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,
3059 fidp->flags |= SMB_FID_MTIMESETDONE;
3062 attribute = *((u_long *)(p->datap + 32));
3063 if (attribute != 0) {
3064 if ((scp->unixModeBits & 0222)
3065 && (attribute & 1) != 0) {
3066 /* make a writable file read-only */
3067 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
3068 attr.unixModeBits = scp->unixModeBits & ~0222;
3070 else if ((scp->unixModeBits & 0222) == 0
3071 && (attribute & 1) == 0) {
3072 /* make a read-only file writable */
3073 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
3074 attr.unixModeBits = scp->unixModeBits | 0222;
3077 lock_ReleaseMutex(&scp->mx);
3081 code = cm_SetAttr(scp, &attr, userp, &req);
3085 else if (infoLevel == SMB_QUERY_FILE_EA_INFO || infoLevel == SMB_QUERY_FILE_NAME_INFO) {
3086 LARGE_INTEGER size = *((LARGE_INTEGER *)(p->datap));
3089 attr.mask = CM_ATTRMASK_LENGTH;
3090 attr.length.LowPart = size.LowPart;
3091 attr.length.HighPart = size.HighPart;
3092 code = cm_SetAttr(scp, &attr, userp, &req);
3094 else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO) {
3095 if (*((char *)(p->datap))) {
3096 code = cm_CheckNTDelete(fidp->NTopen_dscp, scp, userp,
3099 fidp->flags |= SMB_FID_DELONCLOSE;
3103 fidp->flags &= ~SMB_FID_DELONCLOSE;
3108 cm_ReleaseUser(userp);
3109 smb_ReleaseFID(fidp);
3111 smb_SendTran2Packet(vcp, outp, op);
3113 smb_SendTran2Error(vcp, p, op, code);
3114 smb_FreeTran2Packet(outp);
3120 smb_ReceiveTran2FSCTL(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3122 osi_Log0(smb_logp,"ReceiveTran2FSCTL - NOT_SUPPORTED");
3123 return CM_ERROR_BADOP;
3127 smb_ReceiveTran2IOCTL(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3129 osi_Log0(smb_logp,"ReceiveTran2IOCTL - NOT_SUPPORTED");
3130 return CM_ERROR_BADOP;
3134 smb_ReceiveTran2FindNotifyFirst(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3136 osi_Log0(smb_logp,"ReceiveTran2FindNotifyFirst - NOT_SUPPORTED");
3137 return CM_ERROR_BADOP;
3141 smb_ReceiveTran2FindNotifyNext(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3143 osi_Log0(smb_logp,"ReceiveTran2FindNotifyNext - NOT_SUPPORTED");
3144 return CM_ERROR_BADOP;
3148 smb_ReceiveTran2CreateDirectory(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3150 osi_Log0(smb_logp,"ReceiveTran2CreateDirectory - NOT_SUPPORTED");
3151 return CM_ERROR_BADOP;
3155 smb_ReceiveTran2SessionSetup(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3157 osi_Log0(smb_logp,"ReceiveTran2SessionSetup - NOT_SUPPORTED");
3158 return CM_ERROR_BADOP;
3161 struct smb_v2_referral {
3163 USHORT ReferralFlags;
3166 USHORT DfsPathOffset;
3167 USHORT DfsAlternativePathOffset;
3168 USHORT NetworkAddressOffset;
3172 smb_ReceiveTran2GetDFSReferral(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
3174 /* This is a UNICODE only request (bit15 of Flags2) */
3175 /* The TID must be IPC$ */
3177 /* The documentation for the Flags response field is contradictory */
3179 /* Use Version 1 Referral Element Format */
3180 /* ServerType = 0; indicates the next server should be queried for the file */
3181 /* ReferralFlags = 0x01; PathConsumed characters should be stripped */
3182 /* Node = UnicodeString of UNC path of the next share name */
3185 int maxReferralLevel = 0;
3186 char requestFileName[1024] = "";
3187 smb_tran2Packet_t *outp = 0;
3188 cm_user_t *userp = 0;
3191 CPINFO CodePageInfo;
3192 int i, nbnLen, reqLen;
3197 maxReferralLevel = p->parmsp[0];
3199 GetCPInfo(CP_ACP, &CodePageInfo);
3200 WideCharToMultiByte(CP_ACP, 0, (LPCWSTR) &p->parmsp[1], -1,
3201 requestFileName, 1024, NULL, NULL);
3203 osi_Log2(smb_logp,"ReceiveTran2GetDfsReferral [%d][%s]",
3204 maxReferralLevel, osi_LogSaveString(smb_logp, requestFileName));
3206 nbnLen = strlen(cm_NetbiosName);
3207 reqLen = strlen(requestFileName);
3209 if (reqLen == nbnLen + 5 &&
3210 requestFileName[0] == '\\' &&
3211 !_strnicmp(cm_NetbiosName,&requestFileName[1],nbnLen) &&
3212 requestFileName[nbnLen+1] == '\\' &&
3213 !_strnicmp("all",&requestFileName[nbnLen+2],3))
3216 struct smb_v2_referral * v2ref;
3217 outp = smb_GetTran2ResponsePacket(vcp, p, op, 0, 2 * (reqLen + 8));
3219 sp = (USHORT *)outp->datap;
3221 sp[idx++] = reqLen; /* path consumed */
3222 sp[idx++] = 1; /* number of referrals */
3223 sp[idx++] = 0x03; /* flags */
3224 #ifdef DFS_VERSION_1
3225 sp[idx++] = 1; /* Version Number */
3226 sp[idx++] = reqLen + 4; /* Referral Size */
3227 sp[idx++] = 1; /* Type = SMB Server */
3228 sp[idx++] = 0; /* Do not strip path consumed */
3229 for ( i=0;i<=reqLen; i++ )
3230 sp[i+idx] = requestFileName[i];
3231 #else /* DFS_VERSION_2 */
3232 sp[idx++] = 2; /* Version Number */
3233 sp[idx++] = sizeof(struct smb_v2_referral); /* Referral Size */
3234 idx += (sizeof(struct smb_v2_referral) / 2);
3235 v2ref = (struct smb_v2_referral *) &sp[5];
3236 v2ref->ServerType = 1; /* SMB Server */
3237 v2ref->ReferralFlags = 0x03;
3238 v2ref->Proximity = 0; /* closest */
3239 v2ref->TimeToLive = 3600; /* seconds */
3240 v2ref->DfsPathOffset = idx * 2;
3241 v2ref->DfsAlternativePathOffset = idx * 2;
3242 v2ref->NetworkAddressOffset = 0;
3243 for ( i=0;i<=reqLen; i++ )
3244 sp[i+idx] = requestFileName[i];
3247 userp = smb_GetTran2User(vcp, p);
3249 osi_Log1(smb_logp,"ReceiveTran2GetDfsReferral unable to resolve user [%d]", p->uid);
3250 code = CM_ERROR_BADSMB;
3255 code = CM_ERROR_NOSUCHPATH;
3260 cm_ReleaseUser(userp);
3262 smb_SendTran2Packet(vcp, outp, op);
3264 smb_SendTran2Error(vcp, p, op, code);
3266 smb_FreeTran2Packet(outp);
3269 #else /* DFS_SUPPORT */
3270 osi_Log0(smb_logp,"ReceiveTran2GetDfsReferral - NOT_SUPPORTED");
3271 return CM_ERROR_BADOP;
3272 #endif /* DFS_SUPPORT */
3276 smb_ReceiveTran2ReportDFSInconsistency(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3278 /* This is a UNICODE only request (bit15 of Flags2) */
3280 /* There is nothing we can do about this operation. The client is going to
3281 * tell us that there is a Version 1 Referral Element for which there is a DFS Error.
3282 * Unfortunately, there is really nothing we can do about it other then log it
3283 * somewhere. Even then I don't think there is anything for us to do.
3284 * So let's return an error value.
3287 osi_Log0(smb_logp,"ReceiveTran2ReportDFSInconsistency - NOT_SUPPORTED");
3288 return CM_ERROR_BADOP;
3292 smb_ApplyV3DirListPatches(cm_scache_t *dscp,
3293 smb_dirListPatch_t **dirPatchespp, int infoLevel, cm_user_t *userp,
3298 cm_scache_t *targetScp; /* target if scp is a symlink */
3303 unsigned short attr;
3304 unsigned long lattr;
3305 smb_dirListPatch_t *patchp;
3306 smb_dirListPatch_t *npatchp;
3308 for(patchp = *dirPatchespp; patchp; patchp =
3309 (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
3310 code = cm_GetSCache(&patchp->fid, &scp, userp, reqp);
3312 lock_ObtainMutex(&scp->mx);
3313 code = cm_SyncOp(scp, NULL, userp, reqp, 0,
3314 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3316 lock_ReleaseMutex(&scp->mx);
3317 cm_ReleaseSCache(scp);
3319 dptr = patchp->dptr;
3321 /* Plug in fake timestamps. A time stamp of 0 causes 'invalid parameter'
3322 errors in the client. */
3323 if (infoLevel >= 0x101) {
3324 /* 1969-12-31 23:59:59 +00 */
3325 ft.dwHighDateTime = 0x19DB200;
3326 ft.dwLowDateTime = 0x5BB78980;
3328 /* copy to Creation Time */
3329 *((FILETIME *)dptr) = ft;
3332 /* copy to Last Access Time */
3333 *((FILETIME *)dptr) = ft;
3336 /* copy to Last Write Time */
3337 *((FILETIME *)dptr) = ft;
3340 /* copy to Change Time */
3341 *((FILETIME *)dptr) = ft;
3344 /* merge in hidden attribute */
3345 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
3346 *((u_long *)dptr) = SMB_ATTR_HIDDEN;
3350 /* 1969-12-31 23:59:58 +00*/
3351 dosTime = 0xEBBFBF7D;
3353 /* and copy out date */
3354 shortTemp = (dosTime>>16) & 0xffff;
3355 *((u_short *)dptr) = shortTemp;
3358 /* copy out creation time */
3359 shortTemp = dosTime & 0xffff;
3360 *((u_short *)dptr) = shortTemp;
3363 /* and copy out date */
3364 shortTemp = (dosTime>>16) & 0xffff;
3365 *((u_short *)dptr) = shortTemp;
3368 /* copy out access time */
3369 shortTemp = dosTime & 0xffff;
3370 *((u_short *)dptr) = shortTemp;
3373 /* and copy out date */
3374 shortTemp = (dosTime>>16) & 0xffff;
3375 *((u_short *)dptr) = shortTemp;
3378 /* copy out mod time */
3379 shortTemp = dosTime & 0xffff;
3380 *((u_short *)dptr) = shortTemp;
3383 /* merge in hidden (dot file) attribute */
3384 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
3385 attr = SMB_ATTR_HIDDEN;
3386 *dptr++ = attr & 0xff;
3387 *dptr++ = (attr >> 8) & 0xff;
3393 /* now watch for a symlink */
3395 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
3396 lock_ReleaseMutex(&scp->mx);
3397 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, reqp);
3399 /* we have a more accurate file to use (the
3400 * target of the symbolic link). Otherwise,
3401 * we'll just use the symlink anyway.
3403 osi_Log2(smb_logp, "symlink vp %x to vp %x",
3405 cm_ReleaseSCache(scp);
3408 lock_ObtainMutex(&scp->mx);
3411 dptr = patchp->dptr;
3413 if (infoLevel >= 0x101) {
3415 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
3417 /* copy to Creation Time */
3418 *((FILETIME *)dptr) = ft;
3421 /* copy to Last Access Time */
3422 *((FILETIME *)dptr) = ft;
3425 /* copy to Last Write Time */
3426 *((FILETIME *)dptr) = ft;
3429 /* copy to Change Time */
3430 *((FILETIME *)dptr) = ft;
3433 /* Use length for both file length and alloc length */
3434 *((LARGE_INTEGER *)dptr) = scp->length;
3436 *((LARGE_INTEGER *)dptr) = scp->length;
3439 /* Copy attributes */
3440 lattr = smb_ExtAttributes(scp);
3441 if (code == CM_ERROR_NOSUCHPATH && scp->fileType == CM_SCACHETYPE_SYMLINK) {
3442 if (lattr == SMB_ATTR_NORMAL)
3443 lattr = SMB_ATTR_DIRECTORY;
3445 lattr |= SMB_ATTR_DIRECTORY;
3447 /* merge in hidden (dot file) attribute */
3448 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
3449 if (lattr == SMB_ATTR_NORMAL)
3450 lattr = SMB_ATTR_HIDDEN;
3452 lattr |= SMB_ATTR_HIDDEN;
3454 *((u_long *)dptr) = lattr;
3458 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
3460 /* and copy out date */
3461 shortTemp = (dosTime>>16) & 0xffff;
3462 *((u_short *)dptr) = shortTemp;
3465 /* copy out creation time */
3466 shortTemp = dosTime & 0xffff;
3467 *((u_short *)dptr) = shortTemp;
3470 /* and copy out date */
3471 shortTemp = (dosTime>>16) & 0xffff;
3472 *((u_short *)dptr) = shortTemp;
3475 /* copy out access time */
3476 shortTemp = dosTime & 0xffff;
3477 *((u_short *)dptr) = shortTemp;
3480 /* and copy out date */
3481 shortTemp = (dosTime>>16) & 0xffff;
3482 *((u_short *)dptr) = shortTemp;
3485 /* copy out mod time */
3486 shortTemp = dosTime & 0xffff;
3487 *((u_short *)dptr) = shortTemp;
3490 /* copy out file length and alloc length,
3491 * using the same for both
3493 *((u_long *)dptr) = scp->length.LowPart;
3495 *((u_long *)dptr) = scp->length.LowPart;
3498 /* finally copy out attributes as short */
3499 attr = smb_Attributes(scp);
3500 /* merge in hidden (dot file) attribute */
3501 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
3502 if (lattr == SMB_ATTR_NORMAL)
3503 lattr = SMB_ATTR_HIDDEN;
3505 lattr |= SMB_ATTR_HIDDEN;
3507 *dptr++ = attr & 0xff;
3508 *dptr++ = (attr >> 8) & 0xff;
3511 lock_ReleaseMutex(&scp->mx);
3512 cm_ReleaseSCache(scp);
3515 /* now free the patches */
3516 for (patchp = *dirPatchespp; patchp; patchp = npatchp) {
3517 npatchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q);
3521 /* and mark the list as empty */
3522 *dirPatchespp = NULL;
3527 #ifndef USE_OLD_MATCHING
3528 // char table for case insensitive comparison
3529 char mapCaseTable[256];
3531 VOID initUpperCaseTable(VOID)
3534 for (i = 0; i < 256; ++i)
3535 mapCaseTable[i] = toupper(i);
3536 // make '"' match '.'
3537 mapCaseTable[(int)'"'] = toupper('.');
3538 // make '<' match '*'
3539 mapCaseTable[(int)'<'] = toupper('*');
3540 // make '>' match '?'
3541 mapCaseTable[(int)'>'] = toupper('?');
3544 // Compare 'pattern' (containing metacharacters '*' and '?') with the file
3546 // Note : this procedure works recursively calling itself.
3548 // PSZ pattern : string containing metacharacters.
3549 // PSZ name : file name to be compared with 'pattern'.
3551 // BOOL : TRUE/FALSE (match/mistmatch)
3554 szWildCardMatchFileName(PSZ pattern, PSZ name, int casefold)
3556 PSZ pename; // points to the last 'name' character
3558 pename = name + strlen(name) - 1;
3568 if (*pattern == '\0')
3570 for (p = pename; p >= name; --p) {
3571 if ((casefold && (mapCaseTable[*p] == mapCaseTable[*pattern]) ||
3572 !casefold && (*p == *pattern)) &&
3573 szWildCardMatchFileName(pattern + 1, p + 1, casefold))
3578 if ((casefold && mapCaseTable[*name] != mapCaseTable[*pattern]) ||
3579 (!casefold && *name != *pattern))
3586 if (*pattern == '\0' || *pattern == '*' && *(pattern+1) == '\0')
3592 /* do a case-folding search of the star name mask with the name in namep.
3593 * Return 1 if we match, otherwise 0.
3595 int smb_V3MatchMask(char *namep, char *maskp, int flags)
3598 int i, j, star, qmark, casefold, retval;
3600 /* make sure we only match 8.3 names, if requested */
3601 if ((flags & CM_FLAG_8DOT3) && !cm_Is8Dot3(namep))
3604 casefold = (flags & CM_FLAG_CASEFOLD) ? 1 : 0;
3606 /* optimize the pattern:
3607 * if there is a mixture of '?' and '*',
3608 * for example the sequence "*?*?*?*"
3609 * must be turned into the form "*"
3611 newmask = (char *)malloc(strlen(maskp)+1);
3612 for ( i=0, j=0, star=0, qmark=0; maskp[i]; i++) {
3613 switch ( maskp[i] ) {
3625 } else if ( qmark ) {
3629 newmask[j++] = maskp[i];
3636 } else if ( qmark ) {
3640 newmask[j++] = '\0';
3642 retval = szWildCardMatchFileName(newmask, namep, casefold) ? 1:0;
3648 #else /* USE_OLD_MATCHING */
3649 /* do a case-folding search of the star name mask with the name in namep.
3650 * Return 1 if we match, otherwise 0.
3652 int smb_V3MatchMask(char *namep, char *maskp, int flags)
3654 unsigned char tcp1, tcp2; /* Pattern characters */
3655 unsigned char tcn1; /* Name characters */
3656 int sawDot = 0, sawStar = 0, req8dot3 = 0;
3657 char *starNamep, *starMaskp;
3658 static char nullCharp[] = {0};
3659 int casefold = flags & CM_FLAG_CASEFOLD;
3661 /* make sure we only match 8.3 names, if requested */
3662 req8dot3 = (flags & CM_FLAG_8DOT3);
3663 if (req8dot3 && !cm_Is8Dot3(namep))
3668 /* Next pattern character */
3671 /* Next name character */
3675 /* 0 - end of pattern */
3681 else if (tcp1 == '.' || tcp1 == '"') {
3691 * first dot in pattern;
3692 * must match dot or end of name
3697 else if (tcn1 == '.') {
3706 else if (tcp1 == '?') {
3707 if (tcn1 == 0 || tcn1 == '.')
3712 else if (tcp1 == '>') {
3713 if (tcn1 != 0 && tcn1 != '.')
3717 else if (tcp1 == '*' || tcp1 == '<') {
3721 else if ((req8dot3 && tcp2 == '.') || tcp2 == '"') {
3722 while (req8dot3 && tcn1 != '.' && tcn1 != 0)
3737 * pattern character after '*' is not null or
3738 * period. If it is '?' or '>', we are not
3739 * going to understand it. If it is '*' or
3740 * '<', we are going to skip over it. None of
3741 * these are likely, I hope.
3743 /* skip over '*' and '<' */
3744 while (tcp2 == '*' || tcp2 == '<')
3747 /* skip over characters that don't match tcp2 */
3748 while (req8dot3 && tcn1 != '.' && tcn1 != 0 &&
3749 ((casefold && cm_foldUpper[tcn1] != cm_foldUpper[tcp2]) ||
3750 (!casefold && tcn1 != tcp2)))
3754 if ((req8dot3 && tcn1 == '.') || tcn1 == 0)
3757 /* Remember where we are */
3767 /* tcp1 is not a wildcard */
3768 if ((casefold && cm_foldUpper[tcn1] == cm_foldUpper[tcp1]) ||
3769 (!casefold && tcn1 == tcp1)) {
3774 /* if trying to match a star pattern, go back */
3776 maskp = starMaskp - 2;
3777 namep = starNamep + 1;
3786 #endif /* USE_OLD_MATCHING */
3788 long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
3793 long code = 0, code2 = 0;
3797 smb_dirListPatch_t *dirListPatchesp;
3798 smb_dirListPatch_t *curPatchp;
3801 long orbytes; /* # of bytes in this output record */
3802 long ohbytes; /* # of bytes, except file name */
3803 long onbytes; /* # of bytes in name, incl. term. null */
3804 osi_hyper_t dirLength;
3805 osi_hyper_t bufferOffset;
3806 osi_hyper_t curOffset;
3808 smb_dirSearch_t *dsp;
3812 cm_pageHeader_t *pageHeaderp;
3813 cm_user_t *userp = NULL;
3816 long nextEntryCookie;
3817 int numDirChunks; /* # of 32 byte dir chunks in this entry */
3818 char *op; /* output data ptr */
3819 char *origOp; /* original value of op */
3820 cm_space_t *spacep; /* for pathname buffer */
3821 long maxReturnData; /* max # of return data */
3822 long maxReturnParms; /* max # of return parms */
3823 long bytesInBuffer; /* # data bytes in the output buffer */
3825 char *maskp; /* mask part of path */
3829 smb_tran2Packet_t *outp; /* response packet */
3832 char shortName[13]; /* 8.3 name if needed */
3843 if (p->opcode == 1) {
3844 /* find first; obtain basic parameters from request */
3845 attribute = p->parmsp[0];
3846 maxCount = p->parmsp[1];
3847 infoLevel = p->parmsp[3];
3848 searchFlags = p->parmsp[2];
3849 dsp = smb_NewDirSearch(1);
3850 dsp->attribute = attribute;
3851 pathp = ((char *) p->parmsp) + 12; /* points to path */
3852 if (smb_StoreAnsiFilenames)
3853 OemToChar(pathp,pathp);
3855 maskp = strrchr(pathp, '\\');
3859 maskp++; /* skip over backslash */
3860 strcpy(dsp->mask, maskp); /* and save mask */
3861 /* track if this is likely to match a lot of entries */
3862 starPattern = smb_V3IsStarMask(maskp);
3865 osi_assert(p->opcode == 2);
3866 /* find next; obtain basic parameters from request or open dir file */
3867 dsp = smb_FindDirSearch(p->parmsp[0]);
3868 maxCount = p->parmsp[1];
3869 infoLevel = p->parmsp[2];
3870 nextCookie = p->parmsp[3] | (p->parmsp[4] << 16);
3871 searchFlags = p->parmsp[5];
3873 osi_Log2(smb_logp, "T2 search dir bad search ID: id %d nextCookie 0x%x",
3874 p->parmsp[0], nextCookie);
3875 return CM_ERROR_BADFD;
3877 attribute = dsp->attribute;
3880 starPattern = 1; /* assume, since required a Find Next */
3884 "T2 search dir attr 0x%x, info level %d, max count %d, flags 0x%x",
3885 attribute, infoLevel, maxCount, searchFlags);
3887 osi_Log3(smb_logp, "...T2 search op %d, id %d, nextCookie 0x%x",
3888 p->opcode, dsp->cookie, nextCookie);
3890 if (infoLevel >= 0x101)
3891 searchFlags &= ~4; /* no resume keys */
3893 dirListPatchesp = NULL;
3895 maxReturnData = p->maxReturnData;
3896 if (p->opcode == 1) /* find first */
3897 maxReturnParms = 10; /* bytes */
3899 maxReturnParms = 8; /* bytes */
3901 #ifndef CM_CONFIG_MULTITRAN2RESPONSES
3902 if (maxReturnData > 6000)
3903 maxReturnData = 6000;
3904 #endif /* CM_CONFIG_MULTITRAN2RESPONSES */
3906 outp = smb_GetTran2ResponsePacket(vcp, p, opx, maxReturnParms,
3909 osi_Log2(smb_logp, "T2 receive search dir count %d [%s]",
3910 maxCount, osi_LogSaveString(smb_logp, pathp));
3912 /* bail out if request looks bad */
3913 if (p->opcode == 1 && !pathp) {
3914 smb_ReleaseDirSearch(dsp);
3915 smb_FreeTran2Packet(outp);
3916 return CM_ERROR_BADSMB;
3919 osi_Log3(smb_logp, "T2 search dir id %d, nextCookie 0x%x, attr 0x%x",
3920 dsp->cookie, nextCookie, attribute);
3922 userp = smb_GetTran2User(vcp, p);
3924 osi_Log1(smb_logp, "T2 search dir unable to resolve user [%d]", p->uid);
3925 smb_ReleaseDirSearch(dsp);
3926 smb_FreeTran2Packet(outp);
3927 return CM_ERROR_BADSMB;
3930 /* try to get the vnode for the path name next */
3931 lock_ObtainMutex(&dsp->mx);
3937 spacep = cm_GetSpace();
3938 smb_StripLastComponent(spacep->data, NULL, pathp);
3939 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
3941 cm_ReleaseUser(userp);
3942 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOFILES);
3943 smb_FreeTran2Packet(outp);
3944 lock_ReleaseMutex(&dsp->mx);
3945 smb_DeleteDirSearch(dsp);
3946 smb_ReleaseDirSearch(dsp);
3949 code = cm_NameI(cm_data.rootSCachep, spacep->data,
3950 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
3951 userp, tidPathp, &req, &scp);
3952 cm_FreeSpace(spacep);
3955 #ifdef DFS_SUPPORT_BUT_NOT_FIND_FIRST
3956 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
3957 cm_ReleaseSCache(scp);
3958 cm_ReleaseUser(userp);
3959 if ( WANTS_DFS_PATHNAMES(p) )
3960 code = CM_ERROR_PATH_NOT_COVERED;
3962 code = CM_ERROR_BADSHARENAME;
3963 smb_SendTran2Error(vcp, p, opx, code);
3964 smb_FreeTran2Packet(outp);
3965 lock_ReleaseMutex(&dsp->mx);
3966 smb_DeleteDirSearch(dsp);
3967 smb_ReleaseDirSearch(dsp);
3970 #endif /* DFS_SUPPORT */
3972 /* we need one hold for the entry we just stored into,
3973 * and one for our own processing. When we're done
3974 * with this function, we'll drop the one for our own
3975 * processing. We held it once from the namei call,
3976 * and so we do another hold now.
3979 lock_ObtainMutex(&scp->mx);
3980 if ((scp->flags & CM_SCACHEFLAG_BULKSTATTING) == 0 &&
3981 LargeIntegerGreaterOrEqualToZero(scp->bulkStatProgress)) {
3982 scp->flags |= CM_SCACHEFLAG_BULKSTATTING;
3983 dsp->flags |= SMB_DIRSEARCH_BULKST;
3985 lock_ReleaseMutex(&scp->mx);
3988 lock_ReleaseMutex(&dsp->mx);
3990 cm_ReleaseUser(userp);
3991 smb_FreeTran2Packet(outp);
3992 smb_DeleteDirSearch(dsp);
3993 smb_ReleaseDirSearch(dsp);
3997 /* get the directory size */
3998 lock_ObtainMutex(&scp->mx);
3999 code = cm_SyncOp(scp, NULL, userp, &req, 0,
4000 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4002 lock_ReleaseMutex(&scp->mx);
4003 cm_ReleaseSCache(scp);
4004 cm_ReleaseUser(userp);
4005 smb_FreeTran2Packet(outp);
4006 smb_DeleteDirSearch(dsp);
4007 smb_ReleaseDirSearch(dsp);
4012 dirLength = scp->length;
4014 bufferOffset.LowPart = bufferOffset.HighPart = 0;
4015 curOffset.HighPart = 0;
4016 curOffset.LowPart = nextCookie;
4017 origOp = outp->datap;
4025 if (searchFlags & 4)
4026 /* skip over resume key */
4029 /* make sure that curOffset.LowPart doesn't point to the first
4030 * 32 bytes in the 2nd through last dir page, and that it doesn't
4031 * point at the first 13 32-byte chunks in the first dir page,
4032 * since those are dir and page headers, and don't contain useful
4035 temp = curOffset.LowPart & (2048-1);
4036 if (curOffset.HighPart == 0 && curOffset.LowPart < 2048) {
4037 /* we're in the first page */
4038 if (temp < 13*32) temp = 13*32;
4041 /* we're in a later dir page */
4042 if (temp < 32) temp = 32;
4045 /* make sure the low order 5 bits are zero */
4048 /* now put temp bits back ito curOffset.LowPart */
4049 curOffset.LowPart &= ~(2048-1);
4050 curOffset.LowPart |= temp;
4052 /* check if we've passed the dir's EOF */
4053 if (LargeIntegerGreaterThanOrEqualTo(curOffset, dirLength)) {
4054 osi_Log0(smb_logp, "T2 search dir passed eof");
4059 /* check if we've returned all the names that will fit in the
4060 * response packet; we check return count as well as the number
4061 * of bytes requested. We check the # of bytes after we find
4062 * the dir entry, since we'll need to check its size.
4064 if (returnedNames >= maxCount) {
4065 osi_Log2(smb_logp, "T2 search dir returnedNames %d >= maxCount %d",
4066 returnedNames, maxCount);
4070 /* see if we can use the bufferp we have now; compute in which
4071 * page the current offset would be, and check whether that's
4072 * the offset of the buffer we have. If not, get the buffer.
4074 thyper.HighPart = curOffset.HighPart;
4075 thyper.LowPart = curOffset.LowPart & ~(cm_data.buf_blockSize-1);
4076 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
4079 buf_Release(bufferp);
4082 lock_ReleaseMutex(&scp->mx);
4083 lock_ObtainRead(&scp->bufCreateLock);
4084 code = buf_Get(scp, &thyper, &bufferp);
4085 lock_ReleaseRead(&scp->bufCreateLock);
4086 lock_ObtainMutex(&dsp->mx);
4088 /* now, if we're doing a star match, do bulk fetching
4089 * of all of the status info for files in the dir.
4092 smb_ApplyV3DirListPatches(scp, &dirListPatchesp,
4095 lock_ObtainMutex(&scp->mx);
4096 if ((dsp->flags & SMB_DIRSEARCH_BULKST) &&
4097 LargeIntegerGreaterThanOrEqualTo(thyper, scp->bulkStatProgress)) {
4098 /* Don't bulk stat if risking timeout */
4099 int now = GetCurrentTime();
4100 if (now - req.startTime > 5000) {
4101 scp->bulkStatProgress = thyper;
4102 scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
4103 dsp->flags &= ~SMB_DIRSEARCH_BULKST;
4105 cm_TryBulkStat(scp, &thyper, userp, &req);
4108 lock_ObtainMutex(&scp->mx);
4110 lock_ReleaseMutex(&dsp->mx);
4112 osi_Log2(smb_logp, "T2 search dir buf_Get scp %x failed %d", scp, code);
4116 bufferOffset = thyper;
4118 /* now get the data in the cache */
4120 code = cm_SyncOp(scp, bufferp, userp, &req,
4122 CM_SCACHESYNC_NEEDCALLBACK
4123 | CM_SCACHESYNC_READ);
4125 osi_Log2(smb_logp, "T2 search dir cm_SyncOp scp %x failed %d", scp, code);
4129 if (cm_HaveBuffer(scp, bufferp, 0)) {
4130 osi_Log2(smb_logp, "T2 search dir !HaveBuffer scp %x bufferp %x", scp, bufferp);
4134 /* otherwise, load the buffer and try again */
4135 code = cm_GetBuffer(scp, bufferp, NULL, userp,
4138 osi_Log3(smb_logp, "T2 search dir cm_GetBuffer failed scp %x bufferp %x code %d",
4139 scp, bufferp, code);
4144 buf_Release(bufferp);
4148 } /* if (wrong buffer) ... */
4150 /* now we have the buffer containing the entry we're interested
4151 * in; copy it out if it represents a non-deleted entry.
4153 entryInDir = curOffset.LowPart & (2048-1);
4154 entryInBuffer = curOffset.LowPart & (cm_data.buf_blockSize - 1);
4156 /* page header will help tell us which entries are free. Page
4157 * header can change more often than once per buffer, since
4158 * AFS 3 dir page size may be less than (but not more than)
4159 * a buffer package buffer.
4161 /* only look intra-buffer */
4162 temp = curOffset.LowPart & (cm_data.buf_blockSize - 1);
4163 temp &= ~(2048 - 1); /* turn off intra-page bits */
4164 pageHeaderp = (cm_pageHeader_t *) (bufferp->datap + temp);
4166 /* now determine which entry we're looking at in the page.
4167 * If it is free (there's a free bitmap at the start of the
4168 * dir), we should skip these 32 bytes.
4170 slotInPage = (entryInDir & 0x7e0) >> 5;
4171 if (!(pageHeaderp->freeBitmap[slotInPage>>3] &
4172 (1 << (slotInPage & 0x7)))) {
4173 /* this entry is free */
4174 numDirChunks = 1; /* only skip this guy */
4178 tp = bufferp->datap + entryInBuffer;
4179 dep = (cm_dirEntry_t *) tp; /* now points to AFS3 dir entry */
4181 /* while we're here, compute the next entry's location, too,
4182 * since we'll need it when writing out the cookie into the dir
4185 * XXXX Probably should do more sanity checking.
4187 numDirChunks = cm_NameEntries(dep->name, &onbytes);
4189 /* compute offset of cookie representing next entry */
4190 nextEntryCookie = curOffset.LowPart + (CM_DIR_CHUNKSIZE * numDirChunks);
4192 /* Need 8.3 name? */
4194 if (infoLevel == SMB_QUERY_FILE_NAME_INFO
4195 && dep->fid.vnode != 0
4196 && !cm_Is8Dot3(dep->name)) {
4197 cm_Gen8Dot3Name(dep, shortName, &shortNameEnd);
4201 osi_Log3(smb_logp, "T2 search dir vn %u name %s (%s)",
4202 dep->fid.vnode, osi_LogSaveString(smb_logp, dep->name),
4203 NeedShortName ? osi_LogSaveString(smb_logp, shortName) : "");
4205 /* When matching, we are using doing a case fold if we have a wildcard mask.
4206 * If we get a non-wildcard match, it's a lookup for a specific file.
4208 if (dep->fid.vnode != 0 &&
4209 (smb_V3MatchMask(dep->name, maskp, (starPattern? CM_FLAG_CASEFOLD : 0)) ||
4211 smb_V3MatchMask(shortName, maskp, CM_FLAG_CASEFOLD)))) {
4213 /* Eliminate entries that don't match requested attributes */
4214 if (smb_hideDotFiles && !(dsp->attribute & SMB_ATTR_HIDDEN) &&
4215 smb_IsDotFile(dep->name)) {
4216 osi_Log0(smb_logp, "T2 search dir skipping hidden");
4217 goto nextEntry; /* no hidden files */
4219 if (!(dsp->attribute & SMB_ATTR_DIRECTORY)) /* no directories */
4221 /* We have already done the cm_TryBulkStat above */
4222 fid.cell = scp->fid.cell;
4223 fid.volume = scp->fid.volume;
4224 fid.vnode = ntohl(dep->fid.vnode);
4225 fid.unique = ntohl(dep->fid.unique);
4226 fileType = cm_FindFileType(&fid);
4227 /*osi_Log2(smb_logp, "smb_ReceiveTran2SearchDir: file %s "
4228 "has filetype %d", dep->name,
4230 if (fileType == CM_SCACHETYPE_DIRECTORY ||
4231 fileType == CM_SCACHETYPE_DFSLINK ||
4232 fileType == CM_SCACHETYPE_INVALID)
4233 osi_Log0(smb_logp, "T2 search dir skipping directory or bad link");
4237 /* finally check if this name will fit */
4239 /* standard dir entry stuff */
4240 if (infoLevel < 0x101)
4241 ohbytes = 23; /* pre-NT */
4242 else if (infoLevel == SMB_QUERY_FILE_EA_INFO)
4243 ohbytes = 12; /* NT names only */
4245 ohbytes = 64; /* NT */
4247 if (infoLevel == SMB_QUERY_FILE_NAME_INFO)
4248 ohbytes += 26; /* Short name & length */
4250 if (searchFlags & 4) {
4251 ohbytes += 4; /* if resume key required */
4255 && infoLevel != 0x101
4256 && infoLevel != 0x103)
4257 ohbytes += 4; /* EASIZE */
4259 /* add header to name & term. null */
4260 orbytes = onbytes + ohbytes + 1;
4262 /* now, we round up the record to a 4 byte alignment,
4263 * and we make sure that we have enough room here for
4264 * even the aligned version (so we don't have to worry
4265 * about an * overflow when we pad things out below).
4266 * That's the reason for the alignment arithmetic below.
4268 if (infoLevel >= 0x101)
4269 align = (4 - (orbytes & 3)) & 3;
4272 if (orbytes + bytesInBuffer + align > maxReturnData) {
4273 osi_Log1(smb_logp, "T2 dir search exceed max return data %d",
4278 /* this is one of the entries to use: it is not deleted
4279 * and it matches the star pattern we're looking for.
4280 * Put out the name, preceded by its length.
4282 /* First zero everything else */
4283 memset(origOp, 0, ohbytes);
4285 if (infoLevel <= 0x101)
4286 *(origOp + ohbytes - 1) = (unsigned char) onbytes;
4287 else if (infoLevel == SMB_QUERY_FILE_EA_INFO)
4288 *((u_long *)(op + 8)) = onbytes;
4290 *((u_long *)(op + 60)) = onbytes;
4291 strcpy(origOp+ohbytes, dep->name);
4292 if (smb_StoreAnsiFilenames)
4293 CharToOem(origOp+ohbytes, origOp+ohbytes);
4295 /* Short name if requested and needed */
4296 if (infoLevel == SMB_QUERY_FILE_NAME_INFO) {
4297 if (NeedShortName) {
4298 strcpy(op + 70, shortName);
4299 if (smb_StoreAnsiFilenames)
4300 CharToOem(op + 70, op + 70);
4301 *(op + 68) = shortNameEnd - shortName;
4305 /* now, adjust the # of entries copied */
4308 /* NextEntryOffset and FileIndex */
4309 if (infoLevel >= 101) {
4310 int entryOffset = orbytes + align;
4311 *((u_long *)op) = entryOffset;
4312 *((u_long *)(op+4)) = nextEntryCookie;
4315 /* now we emit the attribute. This is tricky, since
4316 * we need to really stat the file to find out what
4317 * type of entry we've got. Right now, we're copying
4318 * out data from a buffer, while holding the scp
4319 * locked, so it isn't really convenient to stat
4320 * something now. We'll put in a place holder
4321 * now, and make a second pass before returning this
4322 * to get the real attributes. So, we just skip the
4323 * data for now, and adjust it later. We allocate a
4324 * patch record to make it easy to find this point
4325 * later. The replay will happen at a time when it is
4326 * safe to unlock the directory.
4328 if (infoLevel != 0x103) {
4329 curPatchp = malloc(sizeof(*curPatchp));
4330 osi_QAdd((osi_queue_t **) &dirListPatchesp,
4332 curPatchp->dptr = op;
4333 if (infoLevel >= 0x101)
4334 curPatchp->dptr += 8;
4336 if (smb_hideDotFiles && smb_IsDotFile(dep->name)) {
4337 curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
4340 curPatchp->flags = 0;
4342 curPatchp->fid.cell = scp->fid.cell;
4343 curPatchp->fid.volume = scp->fid.volume;
4344 curPatchp->fid.vnode = ntohl(dep->fid.vnode);
4345 curPatchp->fid.unique = ntohl(dep->fid.unique);
4348 curPatchp->dep = dep;
4351 if (searchFlags & 4)
4352 /* put out resume key */
4353 *((u_long *)origOp) = nextEntryCookie;
4355 /* Adjust byte ptr and count */
4356 origOp += orbytes; /* skip entire record */
4357 bytesInBuffer += orbytes;
4359 /* and pad the record out */
4360 while (--align >= 0) {
4364 } /* if we're including this name */
4365 else if (!starPattern &&
4367 dep->fid.vnode != 0 &&
4368 smb_V3MatchMask(dep->name, maskp, CM_FLAG_CASEFOLD)) {
4369 /* We were looking for exact matches, but here's an inexact one*/
4374 /* and adjust curOffset to be where the new cookie is */
4375 thyper.HighPart = 0;
4376 thyper.LowPart = CM_DIR_CHUNKSIZE * numDirChunks;
4377 curOffset = LargeIntegerAdd(thyper, curOffset);
4378 } /* while copying data for dir listing */
4380 /* If we didn't get a star pattern, we did an exact match during the first pass.
4381 * If there were no exact matches found, we fail over to inexact matches by
4382 * marking the query as a star pattern (matches all case permutations), and
4383 * re-running the query.
4385 if (returnedNames == 0 && !starPattern && foundInexact) {
4386 osi_Log0(afsd_logp,"T2 Search: No exact matches. Re-running for inexact matches");
4391 /* release the mutex */
4392 lock_ReleaseMutex(&scp->mx);
4394 buf_Release(bufferp);
4396 /* apply and free last set of patches; if not doing a star match, this
4397 * will be empty, but better safe (and freeing everything) than sorry.
4399 code2 = smb_ApplyV3DirListPatches(scp, &dirListPatchesp, infoLevel, userp,
4402 /* now put out the final parameters */
4403 if (returnedNames == 0)
4405 if (p->opcode == 1) {
4407 outp->parmsp[0] = (unsigned short) dsp->cookie;
4408 outp->parmsp[1] = returnedNames;
4409 outp->parmsp[2] = eos;
4410 outp->parmsp[3] = 0; /* nothing wrong with EAS */
4411 outp->parmsp[4] = 0;
4412 /* don't need last name to continue
4413 * search, cookie is enough. Normally,
4414 * this is the offset of the file name
4415 * of the last entry returned.
4417 outp->totalParms = 10; /* in bytes */
4421 outp->parmsp[0] = returnedNames;
4422 outp->parmsp[1] = eos;
4423 outp->parmsp[2] = 0; /* EAS error */
4424 outp->parmsp[3] = 0; /* last name, as above */
4425 outp->totalParms = 8; /* in bytes */
4428 /* return # of bytes in the buffer */
4429 outp->totalData = bytesInBuffer;
4431 /* Return error code if unsuccessful on first request */
4432 if (code == 0 && p->opcode == 1 && returnedNames == 0)
4433 code = CM_ERROR_NOSUCHFILE;
4435 osi_Log4(smb_logp, "T2 search dir done, opcode %d, id %d, %d names, code %d",
4436 p->opcode, dsp->cookie, returnedNames, code);
4438 /* if we're supposed to close the search after this request, or if
4439 * we're supposed to close the search if we're done, and we're done,
4440 * or if something went wrong, close the search.
4442 /* ((searchFlags & 1) || ((searchFlags & 2) && eos) */
4443 if ((searchFlags & 1) || (returnedNames == 0) ||
4444 ((searchFlags & 2) && eos) || code != 0)
4445 smb_DeleteDirSearch(dsp);
4447 smb_SendTran2Error(vcp, p, opx, code);
4449 smb_SendTran2Packet(vcp, outp, opx);
4451 smb_FreeTran2Packet(outp);
4452 smb_ReleaseDirSearch(dsp);
4453 cm_ReleaseSCache(scp);
4454 cm_ReleaseUser(userp);
4458 long smb_ReceiveV3FindClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4461 smb_dirSearch_t *dsp;
4463 dirHandle = smb_GetSMBParm(inp, 0);
4465 osi_Log1(smb_logp, "SMB3 find close handle %d", dirHandle);
4467 dsp = smb_FindDirSearch(dirHandle);
4470 return CM_ERROR_BADFD;
4472 /* otherwise, we have an FD to destroy */
4473 smb_DeleteDirSearch(dsp);
4474 smb_ReleaseDirSearch(dsp);
4476 /* and return results */
4477 smb_SetSMBDataLength(outp, 0);
4482 long smb_ReceiveV3FindNotifyClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4484 smb_SetSMBDataLength(outp, 0);
4488 long smb_ReceiveV3OpenX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4495 cm_scache_t *dscp; /* dir we're dealing with */
4496 cm_scache_t *scp; /* file we're creating */
4498 int initialModeBits;
4508 int parmSlot; /* which parm we're dealing with */
4516 extraInfo = (smb_GetSMBParm(inp, 2) & 1); /* return extra info */
4517 openFun = smb_GetSMBParm(inp, 8); /* open function */
4518 excl = ((openFun & 3) == 0);
4519 trunc = ((openFun & 3) == 2); /* truncate it */
4520 openMode = (smb_GetSMBParm(inp, 3) & 0x7);
4521 openAction = 0; /* tracks what we did */
4523 attributes = smb_GetSMBParm(inp, 5);
4524 dosTime = smb_GetSMBParm(inp, 6) | (smb_GetSMBParm(inp, 7) << 16);
4526 /* compute initial mode bits based on read-only flag in attributes */
4527 initialModeBits = 0666;
4528 if (attributes & 1) initialModeBits &= ~0222;
4530 pathp = smb_GetSMBData(inp, NULL);
4531 if (smb_StoreAnsiFilenames)
4532 OemToChar(pathp,pathp);
4534 spacep = inp->spacep;
4535 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
4537 if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
4538 /* special case magic file name for receiving IOCTL requests
4539 * (since IOCTL calls themselves aren't getting through).
4542 osi_Log0(smb_logp, "IOCTL Open");
4545 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
4546 smb_SetupIoctlFid(fidp, spacep);
4548 /* set inp->fid so that later read calls in same msg can find fid */
4549 inp->fid = fidp->fid;
4551 /* copy out remainder of the parms */
4553 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
4555 smb_SetSMBParm(outp, parmSlot, /* attrs */ 0); parmSlot++;
4556 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* mod time */
4557 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
4558 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* len */
4559 smb_SetSMBParm(outp, parmSlot, 0x7fff); parmSlot++;
4560 smb_SetSMBParm(outp, parmSlot, openMode); parmSlot++;
4561 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* file type 0 ==> normal file or dir */
4562 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* IPC junk */
4564 /* and the final "always present" stuff */
4565 smb_SetSMBParm(outp, parmSlot, /* openAction found existing file */ 1); parmSlot++;
4566 /* next write out the "unique" ID */
4567 smb_SetSMBParm(outp, parmSlot, 0x1234); parmSlot++;
4568 smb_SetSMBParm(outp, parmSlot, 0x5678); parmSlot++;
4569 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
4570 smb_SetSMBDataLength(outp, 0);
4572 /* and clean up fid reference */
4573 smb_ReleaseFID(fidp);
4577 #ifdef DEBUG_VERBOSE
4579 char *hexp, *asciip;
4580 asciip = (lastNamep ? lastNamep : pathp );
4581 hexp = osi_HexifyString(asciip);
4582 DEBUG_EVENT2("AFS", "V3Open H[%s] A[%s]", hexp, asciip );
4586 userp = smb_GetUser(vcp, inp);
4589 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4591 cm_ReleaseUser(userp);
4592 return CM_ERROR_NOSUCHPATH;
4594 code = cm_NameI(cm_data.rootSCachep, pathp,
4595 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
4596 userp, tidPathp, &req, &scp);
4599 if (code == 0 && scp->fileType == CM_SCACHETYPE_DFSLINK) {
4600 cm_ReleaseSCache(scp);
4601 cm_ReleaseUser(userp);
4602 if ( WANTS_DFS_PATHNAMES(inp) )
4603 return CM_ERROR_PATH_NOT_COVERED;
4605 return CM_ERROR_BADSHARENAME;
4607 #endif /* DFS_SUPPORT */
4610 code = cm_NameI(cm_data.rootSCachep, spacep->data,
4611 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
4612 userp, tidPathp, &req, &dscp);
4614 cm_ReleaseUser(userp);
4619 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
4620 cm_ReleaseSCache(dscp);
4621 cm_ReleaseUser(userp);
4622 if ( WANTS_DFS_PATHNAMES(inp) )
4623 return CM_ERROR_PATH_NOT_COVERED;
4625 return CM_ERROR_BADSHARENAME;
4627 #endif /* DFS_SUPPORT */
4629 /* otherwise, scp points to the parent directory. Do a lookup,
4630 * and truncate the file if we find it, otherwise we create the
4637 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD, userp,
4639 if (code && code != CM_ERROR_NOSUCHFILE) {
4640 cm_ReleaseSCache(dscp);
4641 cm_ReleaseUser(userp);
4646 /* if we get here, if code is 0, the file exists and is represented by
4647 * scp. Otherwise, we have to create it. The dir may be represented
4648 * by dscp, or we may have found the file directly. If code is non-zero,
4652 code = cm_CheckOpen(scp, openMode, trunc, userp, &req);
4654 if (dscp) cm_ReleaseSCache(dscp);
4655 cm_ReleaseSCache(scp);
4656 cm_ReleaseUser(userp);
4661 /* oops, file shouldn't be there */
4663 cm_ReleaseSCache(dscp);
4664 cm_ReleaseSCache(scp);
4665 cm_ReleaseUser(userp);
4666 return CM_ERROR_EXISTS;
4670 setAttr.mask = CM_ATTRMASK_LENGTH;
4671 setAttr.length.LowPart = 0;
4672 setAttr.length.HighPart = 0;
4673 code = cm_SetAttr(scp, &setAttr, userp, &req);
4674 openAction = 3; /* truncated existing file */
4676 else openAction = 1; /* found existing file */
4678 else if (!(openFun & SMB_ATTR_DIRECTORY)) {
4679 /* don't create if not found */
4680 if (dscp) cm_ReleaseSCache(dscp);
4681 cm_ReleaseUser(userp);
4682 return CM_ERROR_NOSUCHFILE;
4685 osi_assert(dscp != NULL);
4686 osi_Log1(smb_logp, "smb_ReceiveV3OpenX creating file %s",
4687 osi_LogSaveString(smb_logp, lastNamep));
4688 openAction = 2; /* created file */
4689 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
4690 smb_UnixTimeFromDosUTime(&setAttr.clientModTime, dosTime);
4691 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
4693 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
4694 smb_NotifyChange(FILE_ACTION_ADDED,
4695 FILE_NOTIFY_CHANGE_FILE_NAME,
4696 dscp, lastNamep, NULL, TRUE);
4697 if (!excl && code == CM_ERROR_EXISTS) {
4698 /* not an exclusive create, and someone else tried
4699 * creating it already, then we open it anyway. We
4700 * don't bother retrying after this, since if this next
4701 * fails, that means that the file was deleted after we
4702 * started this call.
4704 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
4708 setAttr.mask = CM_ATTRMASK_LENGTH;
4709 setAttr.length.LowPart = 0;
4710 setAttr.length.HighPart = 0;
4711 code = cm_SetAttr(scp, &setAttr, userp, &req);
4713 } /* lookup succeeded */
4717 /* we don't need this any longer */
4719 cm_ReleaseSCache(dscp);
4722 /* something went wrong creating or truncating the file */
4724 cm_ReleaseSCache(scp);
4725 cm_ReleaseUser(userp);
4729 /* make sure we're about to open a file */
4730 if (scp->fileType != CM_SCACHETYPE_FILE) {
4731 cm_ReleaseSCache(scp);
4732 cm_ReleaseUser(userp);
4733 return CM_ERROR_ISDIR;
4736 /* now all we have to do is open the file itself */
4737 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
4740 /* save a pointer to the vnode */
4743 /* compute open mode */
4745 fidp->flags |= SMB_FID_OPENREAD;
4746 if (openMode == 1 || openMode == 2)
4747 fidp->flags |= SMB_FID_OPENWRITE;
4749 smb_ReleaseFID(fidp);
4751 cm_Open(scp, 0, userp);
4753 /* set inp->fid so that later read calls in same msg can find fid */
4754 inp->fid = fidp->fid;
4756 /* copy out remainder of the parms */
4758 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
4759 lock_ObtainMutex(&scp->mx);
4761 smb_SetSMBParm(outp, parmSlot, smb_Attributes(scp)); parmSlot++;
4762 smb_DosUTimeFromUnixTime(&dosTime, scp->clientModTime);
4763 smb_SetSMBParm(outp, parmSlot, dosTime & 0xffff); parmSlot++;
4764 smb_SetSMBParm(outp, parmSlot, (dosTime>>16) & 0xffff); parmSlot++;
4765 smb_SetSMBParm(outp, parmSlot, scp->length.LowPart & 0xffff); parmSlot++;
4766 smb_SetSMBParm(outp, parmSlot, (scp->length.LowPart >> 16) & 0xffff); parmSlot++;
4767 smb_SetSMBParm(outp, parmSlot, openMode); parmSlot++;
4768 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* file type 0 ==> normal file or dir */
4769 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* IPC junk */
4771 /* and the final "always present" stuff */
4772 smb_SetSMBParm(outp, parmSlot, openAction); parmSlot++;
4773 /* next write out the "unique" ID */
4774 smb_SetSMBParm(outp, parmSlot, scp->fid.vnode & 0xffff); parmSlot++;
4775 smb_SetSMBParm(outp, parmSlot, scp->fid.volume & 0xffff); parmSlot++;
4776 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
4777 lock_ReleaseMutex(&scp->mx);
4778 smb_SetSMBDataLength(outp, 0);
4780 osi_Log1(smb_logp, "SMB OpenX opening fid %d", fidp->fid);
4782 cm_ReleaseUser(userp);
4783 /* leave scp held since we put it in fidp->scp */
4787 long smb_ReceiveV3LockingX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4794 unsigned char LockType;
4795 unsigned short NumberOfUnlocks, NumberOfLocks;
4796 unsigned long Timeout;
4798 LARGE_INTEGER LOffset, LLength;
4799 smb_waitingLock_t *waitingLock;
4806 fid = smb_GetSMBParm(inp, 2);
4807 fid = smb_ChainFID(fid, inp);
4809 fidp = smb_FindFID(vcp, fid, 0);
4810 if (!fidp || (fidp->flags & SMB_FID_IOCTL)) {
4811 return CM_ERROR_BADFD;
4813 /* set inp->fid so that later read calls in same msg can find fid */
4816 userp = smb_GetUser(vcp, inp);
4820 lock_ObtainMutex(&scp->mx);
4821 code = cm_SyncOp(scp, NULL, userp, &req, 0,
4822 CM_SCACHESYNC_NEEDCALLBACK
4823 | CM_SCACHESYNC_GETSTATUS
4824 | CM_SCACHESYNC_LOCK);
4828 LockType = smb_GetSMBParm(inp, 3) & 0xff;
4829 Timeout = (smb_GetSMBParm(inp, 5) << 16) + smb_GetSMBParm(inp, 4);
4830 NumberOfUnlocks = smb_GetSMBParm(inp, 6);
4831 NumberOfLocks = smb_GetSMBParm(inp, 7);
4833 op = smb_GetSMBData(inp, NULL);
4835 for (i=0; i<NumberOfUnlocks; i++) {
4836 if (LockType & 0x10) {
4838 LOffset.HighPart = *((LONG *)(op + 4));
4839 LOffset.LowPart = *((DWORD *)(op + 8));
4840 LLength.HighPart = *((LONG *)(op + 12));
4841 LLength.LowPart = *((DWORD *)(op + 16));
4845 /* Not Large Files */
4846 LOffset.HighPart = 0;
4847 LOffset.LowPart = *((DWORD *)(op + 2));
4848 LLength.HighPart = 0;
4849 LLength.LowPart = *((DWORD *)(op + 6));
4852 if (LargeIntegerNotEqualToZero(LOffset))
4854 /* Do not check length -- length check done in cm_Unlock */
4856 code = cm_Unlock(scp, LockType, LOffset, LLength, userp, &req);
4857 if (code) goto done;
4860 for (i=0; i<NumberOfLocks; i++) {
4861 if (LockType & 0x10) {
4863 LOffset.HighPart = *((LONG *)(op + 4));
4864 LOffset.LowPart = *((DWORD *)(op + 8));
4865 LLength.HighPart = *((LONG *)(op + 12));
4866 LLength.LowPart = *((DWORD *)(op + 16));
4870 /* Not Large Files */
4871 LOffset.HighPart = 0;
4872 LOffset.LowPart = *((DWORD *)(op + 2));
4873 LLength.HighPart = 0;
4874 LLength.LowPart = *((DWORD *)(op + 6));
4877 if (LargeIntegerNotEqualToZero(LOffset))
4879 if (LargeIntegerLessThan(LOffset, scp->length))
4882 code = cm_Lock(scp, LockType, LOffset, LLength, Timeout,
4883 userp, &req, &lockp);
4884 if (code == CM_ERROR_WOULDBLOCK && Timeout != 0) {
4885 /* Put on waiting list */
4886 waitingLock = malloc(sizeof(smb_waitingLock_t));
4887 waitingLock->vcp = vcp;
4889 waitingLock->inp = smb_CopyPacket(inp);
4890 waitingLock->outp = smb_CopyPacket(outp);
4891 waitingLock->timeRemaining = Timeout;
4892 waitingLock->lockp = lockp;
4893 lock_ObtainWrite(&smb_globalLock);
4894 osi_QAdd((osi_queue_t **)&smb_allWaitingLocks,
4896 osi_Wakeup((long) &smb_allWaitingLocks);
4897 lock_ReleaseWrite(&smb_globalLock);
4898 /* don't send reply immediately */
4899 outp->flags |= SMB_PACKETFLAG_NOSEND;
4906 /* release any locks acquired before the failure */
4909 smb_SetSMBDataLength(outp, 0);
4911 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_LOCK);
4913 lock_ReleaseMutex(&scp->mx);
4914 cm_ReleaseUser(userp);
4915 smb_ReleaseFID(fidp);
4920 long smb_ReceiveV3GetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4932 fid = smb_GetSMBParm(inp, 0);
4933 fid = smb_ChainFID(fid, inp);
4935 fidp = smb_FindFID(vcp, fid, 0);
4936 if (!fidp || (fidp->flags & SMB_FID_IOCTL)) {
4937 return CM_ERROR_BADFD;
4940 userp = smb_GetUser(vcp, inp);
4944 /* otherwise, stat the file */
4945 lock_ObtainMutex(&scp->mx);
4946 code = cm_SyncOp(scp, NULL, userp, &req, 0,
4947 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4948 if (code) goto done;
4950 /* decode times. We need a search time, but the response to this
4951 * call provides the date first, not the time, as returned in the
4952 * searchTime variable. So we take the high-order bits first.
4954 smb_SearchTimeFromUnixTime(&searchTime, scp->clientModTime);
4955 smb_SetSMBParm(outp, 0, (searchTime >> 16) & 0xffff); /* ctime */
4956 smb_SetSMBParm(outp, 1, searchTime & 0xffff);
4957 smb_SetSMBParm(outp, 2, (searchTime >> 16) & 0xffff); /* atime */
4958 smb_SetSMBParm(outp, 3, searchTime & 0xffff);
4959 smb_SetSMBParm(outp, 4, (searchTime >> 16) & 0xffff); /* mtime */
4960 smb_SetSMBParm(outp, 5, searchTime & 0xffff);
4962 /* now handle file size and allocation size */
4963 smb_SetSMBParm(outp, 6, scp->length.LowPart & 0xffff); /* file size */
4964 smb_SetSMBParm(outp, 7, (scp->length.LowPart >> 16) & 0xffff);
4965 smb_SetSMBParm(outp, 8, scp->length.LowPart & 0xffff); /* alloc size */
4966 smb_SetSMBParm(outp, 9, (scp->length.LowPart >> 16) & 0xffff);
4968 /* file attribute */
4969 smb_SetSMBParm(outp, 10, smb_Attributes(scp));
4971 /* and finalize stuff */
4972 smb_SetSMBDataLength(outp, 0);
4976 lock_ReleaseMutex(&scp->mx);
4977 cm_ReleaseUser(userp);
4978 smb_ReleaseFID(fidp);
4982 long smb_ReceiveV3SetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4996 fid = smb_GetSMBParm(inp, 0);
4997 fid = smb_ChainFID(fid, inp);
4999 fidp = smb_FindFID(vcp, fid, 0);
5000 if (!fidp || (fidp->flags & SMB_FID_IOCTL)) {
5001 return CM_ERROR_BADFD;
5004 userp = smb_GetUser(vcp, inp);
5008 /* now prepare to call cm_setattr. This message only sets various times,
5009 * and AFS only implements mtime, and we'll set the mtime if that's
5010 * requested. The others we'll ignore.
5012 searchTime = smb_GetSMBParm(inp, 5) | (smb_GetSMBParm(inp, 6) << 16);
5014 if (searchTime != 0) {
5015 smb_UnixTimeFromSearchTime(&unixTime, searchTime);
5017 if ( unixTime != -1 ) {
5018 attrs.mask = CM_ATTRMASK_CLIENTMODTIME;
5019 attrs.clientModTime = unixTime;
5020 code = cm_SetAttr(scp, &attrs, userp, &req);
5022 osi_Log1(smb_logp, "SMB receive V3SetAttributes [fid=%ld]", fid);
5024 osi_Log1(smb_logp, "**smb_UnixTimeFromSearchTime failed searchTime=%ld", searchTime);
5029 cm_ReleaseUser(userp);
5030 smb_ReleaseFID(fidp);
5035 long smb_ReceiveV3ReadX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5038 long count, finalCount;
5045 fd = smb_GetSMBParm(inp, 2);
5046 count = smb_GetSMBParm(inp, 5);
5047 offset.HighPart = 0; /* too bad */
5048 offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
5050 osi_Log3(smb_logp, "smb_ReceiveV3Read fd %d, off 0x%x, size 0x%x",
5051 fd, offset.LowPart, count);
5053 fd = smb_ChainFID(fd, inp);
5054 fidp = smb_FindFID(vcp, fd, 0);
5056 return CM_ERROR_BADFD;
5058 /* set inp->fid so that later read calls in same msg can find fid */
5061 if (fidp->flags & SMB_FID_IOCTL) {
5062 return smb_IoctlV3Read(fidp, vcp, inp, outp);
5065 userp = smb_GetUser(vcp, inp);
5067 /* 0 and 1 are reserved for request chaining, were setup by our caller,
5068 * and will be further filled in after we return.
5070 smb_SetSMBParm(outp, 2, 0); /* remaining bytes, for pipes */
5071 smb_SetSMBParm(outp, 3, 0); /* resvd */
5072 smb_SetSMBParm(outp, 4, 0); /* resvd */
5073 smb_SetSMBParm(outp, 5, count); /* # of bytes we're going to read */
5074 /* fill in #6 when we have all the parameters' space reserved */
5075 smb_SetSMBParm(outp, 7, 0); /* resv'd */
5076 smb_SetSMBParm(outp, 8, 0); /* resv'd */
5077 smb_SetSMBParm(outp, 9, 0); /* resv'd */
5078 smb_SetSMBParm(outp, 10, 0); /* resv'd */
5079 smb_SetSMBParm(outp, 11, 0); /* reserved */
5081 /* get op ptr after putting in the parms, since otherwise we don't
5082 * know where the data really is.
5084 op = smb_GetSMBData(outp, NULL);
5086 /* now fill in offset from start of SMB header to first data byte (to op) */
5087 smb_SetSMBParm(outp, 6, ((int) (op - outp->data)));
5089 /* set the packet data length the count of the # of bytes */
5090 smb_SetSMBDataLength(outp, count);
5093 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount);
5095 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount, FALSE);
5098 /* fix some things up */
5099 smb_SetSMBParm(outp, 5, finalCount);
5100 smb_SetSMBDataLength(outp, finalCount);
5102 smb_ReleaseFID(fidp);
5104 cm_ReleaseUser(userp);
5109 * Values for createDisp, copied from NTDDK.H
5111 #define FILE_SUPERSEDE 0 // (???)
5112 #define FILE_OPEN 1 // (open)
5113 #define FILE_CREATE 2 // (exclusive)
5114 #define FILE_OPEN_IF 3 // (non-exclusive)
5115 #define FILE_OVERWRITE 4 // (open & truncate, but do not create)
5116 #define FILE_OVERWRITE_IF 5 // (open & truncate, or create)
5118 long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5120 char *pathp, *realPathp;
5124 cm_scache_t *dscp; /* parent dir */
5125 cm_scache_t *scp; /* file to create or open */
5126 cm_scache_t *targetScp; /* if scp is a symlink */
5130 unsigned short nameLength;
5132 unsigned int requestOpLock;
5133 unsigned int requestBatchOpLock;
5134 unsigned int mustBeDir;
5135 unsigned int treeCreate;
5137 unsigned int desiredAccess;
5138 unsigned int extAttributes;
5139 unsigned int createDisp;
5140 unsigned int createOptions;
5141 int initialModeBits;
5142 unsigned short baseFid;
5143 smb_fid_t *baseFidp;
5145 cm_scache_t *baseDirp;
5146 unsigned short openAction;
5157 /* This code is very long and has a lot of if-then-else clauses
5158 * scp and dscp get reused frequently and we need to ensure that
5159 * we don't lose a reference. Start by ensuring that they are NULL.
5166 nameLength = smb_GetSMBOffsetParm(inp, 2, 1);
5167 flags = smb_GetSMBOffsetParm(inp, 3, 1)
5168 | (smb_GetSMBOffsetParm(inp, 4, 1) << 16);
5169 requestOpLock = flags & 0x02;
5170 requestBatchOpLock = flags & 0x04;
5171 mustBeDir = flags & 0x08;
5174 * Why all of a sudden 32-bit FID?
5175 * We will reject all bits higher than 16.
5177 if (smb_GetSMBOffsetParm(inp, 6, 1) != 0)
5178 return CM_ERROR_INVAL;
5179 baseFid = smb_GetSMBOffsetParm(inp, 5, 1);
5180 desiredAccess = smb_GetSMBOffsetParm(inp, 7, 1)
5181 | (smb_GetSMBOffsetParm(inp, 8, 1) << 16);
5182 extAttributes = smb_GetSMBOffsetParm(inp, 13, 1)
5183 | (smb_GetSMBOffsetParm(inp, 14, 1) << 16);
5184 createDisp = smb_GetSMBOffsetParm(inp, 17, 1)
5185 | (smb_GetSMBOffsetParm(inp, 18, 1) << 16);
5186 createOptions = smb_GetSMBOffsetParm(inp, 19, 1)
5187 | (smb_GetSMBOffsetParm(inp, 20, 1) << 16);
5189 /* mustBeDir is never set; createOptions directory bit seems to be
5192 if (createOptions & 1)
5194 else if (createOptions & 0x40)
5200 * compute initial mode bits based on read-only flag in
5201 * extended attributes
5203 initialModeBits = 0666;
5204 if (extAttributes & 1)
5205 initialModeBits &= ~0222;
5207 pathp = smb_GetSMBData(inp, NULL);
5208 /* Sometimes path is not null-terminated, so we make a copy. */
5209 realPathp = malloc(nameLength+1);
5210 memcpy(realPathp, pathp, nameLength);
5211 realPathp[nameLength] = 0;
5212 if (smb_StoreAnsiFilenames)
5213 OemToChar(realPathp,realPathp);
5215 spacep = inp->spacep;
5216 smb_StripLastComponent(spacep->data, &lastNamep, realPathp);
5218 osi_Log1(smb_logp,"NTCreateX for [%s]",osi_LogSaveString(smb_logp,realPathp));
5219 osi_Log4(smb_logp,"... da=[%x] ea=[%x] cd=[%x] co=[%x]", desiredAccess, extAttributes, createDisp, createOptions);
5220 osi_Log2(smb_logp,"... flags=[%x] lastNamep=[%s]", flags, osi_LogSaveString(smb_logp,(lastNamep?lastNamep:"null")));
5222 if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
5223 /* special case magic file name for receiving IOCTL requests
5224 * (since IOCTL calls themselves aren't getting through).
5226 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
5227 smb_SetupIoctlFid(fidp, spacep);
5228 osi_Log1(smb_logp,"NTCreateX Setting up IOCTL on fid[%d]",fidp->fid);
5230 /* set inp->fid so that later read calls in same msg can find fid */
5231 inp->fid = fidp->fid;
5235 smb_SetSMBParmByte(outp, parmSlot, 0); /* oplock */
5236 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
5237 smb_SetSMBParmLong(outp, parmSlot, 1); parmSlot += 2; /* Action */
5239 memset(&ft, 0, sizeof(ft));
5240 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
5241 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
5242 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
5243 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
5244 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2; /* attr */
5245 sz.HighPart = 0x7fff; sz.LowPart = 0;
5246 smb_SetSMBParmDouble(outp, parmSlot, (char *)&sz); parmSlot += 4; /* alen */
5247 smb_SetSMBParmDouble(outp, parmSlot, (char *)&sz); parmSlot += 4; /* len */
5248 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* filetype */
5249 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* dev state */
5250 smb_SetSMBParmByte(outp, parmSlot, 0); /* is a dir? */
5251 smb_SetSMBDataLength(outp, 0);
5253 /* clean up fid reference */
5254 smb_ReleaseFID(fidp);
5259 #ifdef DEBUG_VERBOSE
5261 char *hexp, *asciip;
5262 asciip = (lastNamep? lastNamep : realPathp);
5263 hexp = osi_HexifyString( asciip );
5264 DEBUG_EVENT2("AFS", "NTCreateX H[%s] A[%s]", hexp, asciip);
5268 userp = smb_GetUser(vcp, inp);
5270 osi_Log1(smb_logp, "NTCreateX Invalid user [%d]", ((smb_t *) inp)->uid);
5272 return CM_ERROR_INVAL;
5276 baseDirp = cm_data.rootSCachep;
5277 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5278 if (code == CM_ERROR_TIDIPC) {
5279 /* Attempt to use a TID allocated for IPC. The client
5280 * is probably looking for DCE RPC end points which we
5281 * don't support OR it could be looking to make a DFS
5284 osi_Log0(smb_logp, "NTCreateX received IPC TID");
5287 cm_ReleaseUser(userp);
5288 return CM_ERROR_NOSUCHFILE;
5289 #endif /* DFS_SUPPORT */
5292 baseFidp = smb_FindFID(vcp, baseFid, 0);
5294 osi_Log1(smb_logp, "NTCreateX Invalid base fid [%d]", baseFid);
5296 cm_ReleaseUser(userp);
5297 return CM_ERROR_INVAL;
5299 baseDirp = baseFidp->scp;
5303 osi_Log1(smb_logp, "NTCreateX tidPathp=[%s]", (tidPathp==NULL)?"null": osi_LogSaveString(smb_logp,tidPathp));
5305 /* compute open mode */
5307 if (desiredAccess & DELETE)
5308 fidflags |= SMB_FID_OPENDELETE;
5309 if (desiredAccess & AFS_ACCESS_READ)
5310 fidflags |= SMB_FID_OPENREAD;
5311 if (desiredAccess & AFS_ACCESS_WRITE)
5312 fidflags |= SMB_FID_OPENWRITE;
5316 /* For an exclusive create, we want to do a case sensitive match for the last component. */
5317 if ( createDisp == FILE_CREATE ||
5318 createDisp == FILE_OVERWRITE ||
5319 createDisp == FILE_OVERWRITE_IF) {
5320 code = cm_NameI(baseDirp, spacep->data, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
5321 userp, tidPathp, &req, &dscp);
5324 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
5325 cm_ReleaseSCache(dscp);
5326 cm_ReleaseUser(userp);
5328 if ( WANTS_DFS_PATHNAMES(inp) )
5329 return CM_ERROR_PATH_NOT_COVERED;
5331 return CM_ERROR_BADSHARENAME;
5333 #endif /* DFS_SUPPORT */
5334 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp, CM_FLAG_FOLLOW,
5336 if (code == CM_ERROR_NOSUCHFILE) {
5337 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp,
5338 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, &req, &scp);
5339 if (code == 0 && realDirFlag == 1) {
5340 cm_ReleaseSCache(scp);
5341 cm_ReleaseSCache(dscp);
5342 cm_ReleaseUser(userp);
5344 return CM_ERROR_EXISTS;
5348 /* we have both scp and dscp */
5350 code = cm_NameI(baseDirp, realPathp, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
5351 userp, tidPathp, &req, &scp);
5353 if (code == 0 && scp->fileType == CM_SCACHETYPE_DFSLINK) {
5354 cm_ReleaseSCache(scp);
5355 cm_ReleaseUser(userp);
5357 if ( WANTS_DFS_PATHNAMES(inp) )
5358 return CM_ERROR_PATH_NOT_COVERED;
5360 return CM_ERROR_BADSHARENAME;
5362 #endif /* DFS_SUPPORT */
5363 /* we might have scp but not dscp */
5369 if (!foundscp || (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE))) {
5370 /* look up parent directory */
5371 /* If we are trying to create a path (i.e. multiple nested directories), then we don't *need*
5372 * the immediate parent. We have to work our way up realPathp until we hit something that we
5376 /* we might or might not have scp */
5382 code = cm_NameI(baseDirp, spacep->data,
5383 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
5384 userp, tidPathp, &req, &dscp);
5387 if (code == 0 && dscp->fileType == CM_SCACHETYPE_DFSLINK) {
5389 cm_ReleaseSCache(scp);
5390 cm_ReleaseSCache(dscp);
5391 cm_ReleaseUser(userp);
5393 if ( WANTS_DFS_PATHNAMES(inp) )
5394 return CM_ERROR_PATH_NOT_COVERED;
5396 return CM_ERROR_BADSHARENAME;
5398 #endif /* DFS_SUPPORT */
5401 (tp = strrchr(spacep->data,'\\')) &&
5402 (createDisp == FILE_CREATE) &&
5403 (realDirFlag == 1)) {
5406 treeStartp = realPathp + (tp - spacep->data);
5408 if (*tp && !smb_IsLegalFilename(tp)) {
5410 smb_ReleaseFID(baseFidp);
5411 cm_ReleaseUser(userp);
5414 cm_ReleaseSCache(scp);
5415 return CM_ERROR_BADNTFILENAME;
5419 } while (dscp == NULL && code == 0);
5423 /* we might have scp and we might have dscp */
5426 smb_ReleaseFID(baseFidp);
5429 osi_Log0(smb_logp,"NTCreateX parent not found");
5431 cm_ReleaseSCache(scp);
5433 cm_ReleaseSCache(dscp);
5434 cm_ReleaseUser(userp);
5439 if (treeCreate && dscp->fileType == CM_SCACHETYPE_FILE) {
5440 /* A file exists where we want a directory. */
5442 cm_ReleaseSCache(scp);
5443 cm_ReleaseSCache(dscp);
5444 cm_ReleaseUser(userp);
5446 return CM_ERROR_EXISTS;
5450 lastNamep = realPathp;
5454 if (!smb_IsLegalFilename(lastNamep)) {
5456 cm_ReleaseSCache(scp);
5458 cm_ReleaseSCache(dscp);
5459 cm_ReleaseUser(userp);
5461 return CM_ERROR_BADNTFILENAME;
5464 if (!foundscp && !treeCreate) {
5465 if ( createDisp == FILE_CREATE ||
5466 createDisp == FILE_OVERWRITE ||
5467 createDisp == FILE_OVERWRITE_IF)
5469 code = cm_Lookup(dscp, lastNamep,
5470 CM_FLAG_FOLLOW, userp, &req, &scp);
5472 code = cm_Lookup(dscp, lastNamep,
5473 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
5476 if (code && code != CM_ERROR_NOSUCHFILE) {
5477 cm_ReleaseSCache(dscp);
5478 cm_ReleaseUser(userp);
5483 /* we have scp and dscp */
5485 /* we have scp but not dscp */
5487 smb_ReleaseFID(baseFidp);
5490 /* if we get here, if code is 0, the file exists and is represented by
5491 * scp. Otherwise, we have to create it. The dir may be represented
5492 * by dscp, or we may have found the file directly. If code is non-zero,
5495 if (code == 0 && !treeCreate) {
5496 if (createDisp == FILE_CREATE) {
5497 /* oops, file shouldn't be there */
5499 cm_ReleaseSCache(dscp);
5500 cm_ReleaseSCache(scp);
5501 cm_ReleaseUser(userp);
5503 return CM_ERROR_EXISTS;
5506 if ( createDisp == FILE_OVERWRITE ||
5507 createDisp == FILE_OVERWRITE_IF) {
5508 setAttr.mask = CM_ATTRMASK_LENGTH;
5509 setAttr.length.LowPart = 0;
5510 setAttr.length.HighPart = 0;
5511 /* now watch for a symlink */
5513 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
5515 osi_assert(dscp != NULL);
5516 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
5518 /* we have a more accurate file to use (the
5519 * target of the symbolic link). Otherwise,
5520 * we'll just use the symlink anyway.
5522 osi_Log2(smb_logp, "symlink vp %x to vp %x",
5524 cm_ReleaseSCache(scp);
5528 code = cm_SetAttr(scp, &setAttr, userp, &req);
5529 openAction = 3; /* truncated existing file */
5532 openAction = 1; /* found existing file */
5534 code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp, &req);
5537 cm_ReleaseSCache(dscp);
5538 cm_ReleaseSCache(scp);
5539 cm_ReleaseUser(userp);
5543 } else if (createDisp == FILE_OPEN || createDisp == FILE_OVERWRITE) {
5544 /* don't create if not found */
5546 cm_ReleaseSCache(dscp);
5548 cm_ReleaseSCache(scp);
5549 cm_ReleaseUser(userp);
5551 return CM_ERROR_NOSUCHFILE;
5552 } else if (realDirFlag == 0 || realDirFlag == -1) {
5553 osi_assert(dscp != NULL);
5554 osi_Log1(smb_logp, "smb_ReceiveNTCreateX creating file %s",
5555 osi_LogSaveString(smb_logp, lastNamep));
5556 openAction = 2; /* created file */
5557 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
5558 setAttr.clientModTime = time(NULL);
5559 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp, &req);
5560 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
5561 smb_NotifyChange(FILE_ACTION_ADDED,
5562 FILE_NOTIFY_CHANGE_FILE_NAME,
5563 dscp, lastNamep, NULL, TRUE);
5564 if (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE) {
5565 /* Not an exclusive create, and someone else tried
5566 * creating it already, then we open it anyway. We
5567 * don't bother retrying after this, since if this next
5568 * fails, that means that the file was deleted after we
5569 * started this call.
5571 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
5574 if (createDisp == FILE_OVERWRITE_IF) {
5575 setAttr.mask = CM_ATTRMASK_LENGTH;
5576 setAttr.length.LowPart = 0;
5577 setAttr.length.HighPart = 0;
5579 /* now watch for a symlink */
5581 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
5583 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
5585 /* we have a more accurate file to use (the
5586 * target of the symbolic link). Otherwise,
5587 * we'll just use the symlink anyway.
5589 osi_Log2(smb_logp, "symlink vp %x to vp %x",
5591 cm_ReleaseSCache(scp);
5595 code = cm_SetAttr(scp, &setAttr, userp, &req);
5597 } /* lookup succeeded */
5601 char *cp; /* This component */
5602 int clen = 0; /* length of component */
5603 cm_scache_t *tscp1, *tscp2;
5606 /* create directory */
5608 treeStartp = lastNamep;
5609 osi_assert(dscp != NULL);
5610 osi_Log1(smb_logp, "smb_ReceiveNTCreateX creating directory [%s]",
5611 osi_LogSaveString(smb_logp, treeStartp));
5612 openAction = 2; /* created directory */
5614 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
5615 setAttr.clientModTime = time(NULL);
5620 cm_HoldSCache(tscp1);
5624 tp = strchr(pp, '\\');
5628 isLast = 1; /* indicate last component. the supplied path never ends in a slash */
5631 strncpy(cp,pp,clen);
5638 continue; /* the supplied path can't have consecutive slashes either , but */
5640 /* cp is the next component to be created. */
5641 code = cm_MakeDir(tscp1, cp, 0, &setAttr, userp, &req);
5642 if (code == 0 && (tscp1->flags & CM_SCACHEFLAG_ANYWATCH))
5643 smb_NotifyChange(FILE_ACTION_ADDED,
5644 FILE_NOTIFY_CHANGE_DIR_NAME,
5645 tscp1, cp, NULL, TRUE);
5647 (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE)) {
5648 /* Not an exclusive create, and someone else tried
5649 * creating it already, then we open it anyway. We
5650 * don't bother retrying after this, since if this next
5651 * fails, that means that the file was deleted after we
5652 * started this call.
5654 code = cm_Lookup(tscp1, cp, CM_FLAG_CASEFOLD,
5655 userp, &req, &tscp2);
5660 if (!isLast) { /* for anything other than dscp, release it unless it's the last one */
5661 cm_ReleaseSCache(tscp1);
5662 tscp1 = tscp2; /* Newly created directory will be next parent */
5663 /* the hold is transfered to tscp1 from tscp2 */
5668 cm_ReleaseSCache(dscp);
5671 cm_ReleaseSCache(scp);
5674 * if we get here and code == 0, then scp is the last directory created, and dscp is the
5680 /* something went wrong creating or truncating the file */
5682 cm_ReleaseSCache(scp);
5684 cm_ReleaseSCache(dscp);
5685 cm_ReleaseUser(userp);
5690 /* make sure we have file vs. dir right (only applies for single component case) */
5691 if (realDirFlag == 0 && scp->fileType != CM_SCACHETYPE_FILE) {
5692 /* now watch for a symlink */
5694 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
5695 cm_scache_t * targetScp = 0;
5696 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
5698 /* we have a more accurate file to use (the
5699 * target of the symbolic link). Otherwise,
5700 * we'll just use the symlink anyway.
5702 osi_Log2(smb_logp, "symlink vp %x to vp %x", scp, targetScp);
5703 cm_ReleaseSCache(scp);
5708 if (scp->fileType != CM_SCACHETYPE_FILE) {
5710 cm_ReleaseSCache(dscp);
5711 cm_ReleaseSCache(scp);
5712 cm_ReleaseUser(userp);
5714 return CM_ERROR_ISDIR;
5718 /* (only applies to single component case) */
5719 if (realDirFlag == 1 && scp->fileType == CM_SCACHETYPE_FILE) {
5720 cm_ReleaseSCache(scp);
5721 cm_ReleaseSCache(dscp);
5722 cm_ReleaseUser(userp);
5724 return CM_ERROR_NOTDIR;
5727 /* open the file itself */
5728 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
5730 /* save a pointer to the vnode */
5731 fidp->scp = scp; /* Hold transfered to fidp->scp and no longer needed */
5733 fidp->flags = fidflags;
5735 /* save parent dir and pathname for delete or change notification */
5736 if (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE)) {
5737 fidp->flags |= SMB_FID_NTOPEN;
5738 fidp->NTopen_dscp = dscp;
5739 cm_HoldSCache(dscp);
5740 fidp->NTopen_pathp = strdup(lastNamep);
5742 fidp->NTopen_wholepathp = realPathp;
5744 /* we don't need this any longer */
5746 cm_ReleaseSCache(dscp);
5749 cm_Open(scp, 0, userp);
5751 /* set inp->fid so that later read calls in same msg can find fid */
5752 inp->fid = fidp->fid;
5756 lock_ObtainMutex(&scp->mx);
5757 smb_SetSMBParmByte(outp, parmSlot, 0); /* oplock */
5758 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
5759 smb_SetSMBParmLong(outp, parmSlot, openAction); parmSlot += 2;
5760 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
5761 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
5762 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
5763 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
5764 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
5765 smb_SetSMBParmLong(outp, parmSlot, smb_ExtAttributes(scp));
5767 smb_SetSMBParmDouble(outp, parmSlot, (char *)&scp->length); parmSlot += 4;
5768 smb_SetSMBParmDouble(outp, parmSlot, (char *)&scp->length); parmSlot += 4;
5769 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* filetype */
5770 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* dev state */
5771 smb_SetSMBParmByte(outp, parmSlot,
5772 scp->fileType == CM_SCACHETYPE_DIRECTORY); /* is a dir? */
5773 lock_ReleaseMutex(&scp->mx);
5774 smb_SetSMBDataLength(outp, 0);
5776 osi_Log2(smb_logp, "SMB NT CreateX opening fid %d path %s", fidp->fid,
5777 osi_LogSaveString(smb_logp, realPathp));
5779 smb_ReleaseFID(fidp);
5781 cm_ReleaseUser(userp);
5783 /* Can't free realPathp if we get here since fidp->NTopen_wholepathp is pointing there */
5785 /* leave scp held since we put it in fidp->scp */
5790 * A lot of stuff copied verbatim from NT Create&X to NT Tran Create.
5791 * Instead, ultimately, would like to use a subroutine for common code.
5793 long smb_ReceiveNTTranCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5795 char *pathp, *realPathp;
5799 cm_scache_t *dscp; /* parent dir */
5800 cm_scache_t *scp; /* file to create or open */
5801 cm_scache_t *targetScp; /* if scp is a symlink */
5804 unsigned long nameLength;
5806 unsigned int requestOpLock;
5807 unsigned int requestBatchOpLock;
5808 unsigned int mustBeDir;
5809 unsigned int extendedRespRequired;
5811 unsigned int desiredAccess;
5812 #ifdef DEBUG_VERBOSE
5813 unsigned int allocSize;
5814 unsigned int shareAccess;
5816 unsigned int extAttributes;
5817 unsigned int createDisp;
5818 #ifdef DEBUG_VERBOSE
5821 unsigned int createOptions;
5822 int initialModeBits;
5823 unsigned short baseFid;
5824 smb_fid_t *baseFidp;
5826 cm_scache_t *baseDirp;
5827 unsigned short openAction;
5833 int parmOffset, dataOffset;
5844 parmOffset = smb_GetSMBOffsetParm(inp, 11, 1)
5845 | (smb_GetSMBOffsetParm(inp, 12, 1) << 16);
5846 parmp = inp->data + parmOffset;
5847 lparmp = (ULONG *) parmp;
5850 requestOpLock = flags & 0x02;
5851 requestBatchOpLock = flags & 0x04;
5852 mustBeDir = flags & 0x08;
5853 extendedRespRequired = flags & 0x10;
5856 * Why all of a sudden 32-bit FID?
5857 * We will reject all bits higher than 16.
5859 if (lparmp[1] & 0xFFFF0000)
5860 return CM_ERROR_INVAL;
5861 baseFid = (unsigned short)lparmp[1];
5862 desiredAccess = lparmp[2];
5863 #ifdef DEBUG_VERBOSE
5864 allocSize = lparmp[3];
5865 #endif /* DEBUG_VERSOSE */
5866 extAttributes = lparmp[5];
5868 shareAccess = lparmp[6];
5870 createDisp = lparmp[7];
5871 createOptions = lparmp[8];
5872 #ifdef DEBUG_VERBOSE
5875 nameLength = lparmp[11];
5877 #ifdef DEBUG_VERBOSE
5878 osi_Log4(smb_logp,"NTTranCreate with da[%x],ea[%x],sa[%x],cd[%x]",desiredAccess,extAttributes,shareAccess,createDisp);
5879 osi_Log3(smb_logp,"... co[%x],sdl[%x],as[%x]",createOptions,sdLen,allocSize);
5880 osi_Log1(smb_logp,"... flags[%x]",flags);
5883 /* mustBeDir is never set; createOptions directory bit seems to be
5886 if (createOptions & 1)
5888 else if (createOptions & 0x40)
5894 * compute initial mode bits based on read-only flag in
5895 * extended attributes
5897 initialModeBits = 0666;
5898 if (extAttributes & 1)
5899 initialModeBits &= ~0222;
5901 pathp = parmp + (13 * sizeof(ULONG)) + sizeof(UCHAR);
5902 /* Sometimes path is not null-terminated, so we make a copy. */
5903 realPathp = malloc(nameLength+1);
5904 memcpy(realPathp, pathp, nameLength);
5905 realPathp[nameLength] = 0;
5906 if (smb_StoreAnsiFilenames)
5907 OemToChar(realPathp,realPathp);
5909 spacep = cm_GetSpace();
5910 smb_StripLastComponent(spacep->data, &lastNamep, realPathp);
5913 * Nothing here to handle SMB_IOCTL_FILENAME.
5914 * Will add it if necessary.
5917 #ifdef DEBUG_VERBOSE
5919 char *hexp, *asciip;
5920 asciip = (lastNamep? lastNamep : realPathp);
5921 hexp = osi_HexifyString( asciip );
5922 DEBUG_EVENT2("AFS", "NTTranCreate H[%s] A[%s]", hexp, asciip);
5927 userp = smb_GetUser(vcp, inp);
5929 osi_Log1(smb_logp, "NTTranCreate invalid user [%d]", ((smb_t *) inp)->uid);
5931 return CM_ERROR_INVAL;
5935 baseDirp = cm_data.rootSCachep;
5936 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5937 if (code == CM_ERROR_TIDIPC) {
5938 /* Attempt to use a TID allocated for IPC. The client
5939 * is probably looking for DCE RPC end points which we
5940 * don't support OR it could be looking to make a DFS
5943 osi_Log0(smb_logp, "NTTranCreate received IPC TID");
5946 cm_ReleaseUser(userp);
5947 return CM_ERROR_NOSUCHPATH;
5951 baseFidp = smb_FindFID(vcp, baseFid, 0);
5953 osi_Log1(smb_logp, "NTTranCreate Invalid fid [%d]", baseFid);
5955 cm_ReleaseUser(userp);
5956 return CM_ERROR_INVAL;
5958 baseDirp = baseFidp->scp;
5962 /* compute open mode */
5964 if (desiredAccess & DELETE)
5965 fidflags |= SMB_FID_OPENDELETE;
5966 if (desiredAccess & AFS_ACCESS_READ)
5967 fidflags |= SMB_FID_OPENREAD;
5968 if (desiredAccess & AFS_ACCESS_WRITE)
5969 fidflags |= SMB_FID_OPENWRITE;
5973 if ( createDisp == FILE_OPEN ||
5974 createDisp == FILE_OVERWRITE ||
5975 createDisp == FILE_OVERWRITE_IF) {
5976 code = cm_NameI(baseDirp, spacep->data, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
5977 userp, tidPathp, &req, &dscp);
5980 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
5981 cm_ReleaseSCache(dscp);
5982 cm_ReleaseUser(userp);
5984 if ( WANTS_DFS_PATHNAMES(inp) )
5985 return CM_ERROR_PATH_NOT_COVERED;
5987 return CM_ERROR_BADSHARENAME;
5989 #endif /* DFS_SUPPORT */
5990 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp, CM_FLAG_FOLLOW,
5992 if (code == CM_ERROR_NOSUCHFILE) {
5993 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp,
5994 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, &req, &scp);
5995 if (code == 0 && realDirFlag == 1) {
5996 cm_ReleaseSCache(scp);
5997 cm_ReleaseSCache(dscp);
5998 cm_ReleaseUser(userp);
6000 return CM_ERROR_EXISTS;
6006 code = cm_NameI(baseDirp, realPathp, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
6007 userp, tidPathp, &req, &scp);
6009 if (code == 0 && scp->fileType == CM_SCACHETYPE_DFSLINK) {
6010 cm_ReleaseSCache(scp);
6011 cm_ReleaseUser(userp);
6013 if ( WANTS_DFS_PATHNAMES(inp) )
6014 return CM_ERROR_PATH_NOT_COVERED;
6016 return CM_ERROR_BADSHARENAME;
6018 #endif /* DFS_SUPPORT */
6024 if (code != 0 || (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE))) {
6025 /* look up parent directory */
6027 code = cm_NameI(baseDirp, spacep->data,
6028 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
6029 userp, tidPathp, &req, &dscp);
6031 if (code == 0 && dscp->fileType == CM_SCACHETYPE_DFSLINK) {
6032 cm_ReleaseSCache(dscp);
6033 cm_ReleaseUser(userp);
6035 if ( WANTS_DFS_PATHNAMES(inp) )
6036 return CM_ERROR_PATH_NOT_COVERED;
6038 return CM_ERROR_BADSHARENAME;
6040 #endif /* DFS_SUPPORT */
6044 cm_FreeSpace(spacep);
6047 smb_ReleaseFID(baseFidp);
6052 cm_ReleaseUser(userp);
6057 if (!lastNamep) lastNamep = realPathp;
6060 if (!smb_IsLegalFilename(lastNamep))
6061 return CM_ERROR_BADNTFILENAME;
6064 if (createDisp == FILE_CREATE || createDisp == FILE_OVERWRITE_IF) {
6065 code = cm_Lookup(dscp, lastNamep,
6066 CM_FLAG_FOLLOW, userp, &req, &scp);
6068 code = cm_Lookup(dscp, lastNamep,
6069 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
6072 if (code && code != CM_ERROR_NOSUCHFILE) {
6073 cm_ReleaseSCache(dscp);
6074 cm_ReleaseUser(userp);
6081 smb_ReleaseFID(baseFidp);
6084 cm_FreeSpace(spacep);
6087 /* if we get here, if code is 0, the file exists and is represented by
6088 * scp. Otherwise, we have to create it. The dir may be represented
6089 * by dscp, or we may have found the file directly. If code is non-zero,
6093 code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp,
6096 if (dscp) cm_ReleaseSCache(dscp);
6097 cm_ReleaseSCache(scp);
6098 cm_ReleaseUser(userp);
6103 if (createDisp == FILE_CREATE) {
6104 /* oops, file shouldn't be there */
6105 if (dscp) cm_ReleaseSCache(dscp);
6106 cm_ReleaseSCache(scp);
6107 cm_ReleaseUser(userp);
6109 return CM_ERROR_EXISTS;
6112 if (createDisp == FILE_OVERWRITE ||
6113 createDisp == FILE_OVERWRITE_IF) {
6114 setAttr.mask = CM_ATTRMASK_LENGTH;
6115 setAttr.length.LowPart = 0;
6116 setAttr.length.HighPart = 0;
6118 /* now watch for a symlink */
6120 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
6122 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
6124 /* we have a more accurate file to use (the
6125 * target of the symbolic link). Otherwise,
6126 * we'll just use the symlink anyway.
6128 osi_Log2(smb_logp, "symlink vp %x to vp %x",
6130 cm_ReleaseSCache(scp);
6134 code = cm_SetAttr(scp, &setAttr, userp, &req);
6135 openAction = 3; /* truncated existing file */
6137 else openAction = 1; /* found existing file */
6139 else if (createDisp == FILE_OPEN || createDisp == FILE_OVERWRITE) {
6140 /* don't create if not found */
6141 if (dscp) cm_ReleaseSCache(dscp);
6142 cm_ReleaseUser(userp);
6144 return CM_ERROR_NOSUCHFILE;
6146 else if (realDirFlag == 0 || realDirFlag == -1) {
6147 osi_assert(dscp != NULL);
6148 osi_Log1(smb_logp, "smb_ReceiveNTTranCreate creating file %s",
6149 osi_LogSaveString(smb_logp, lastNamep));
6150 openAction = 2; /* created file */
6151 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
6152 setAttr.clientModTime = time(NULL);
6153 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
6155 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
6156 smb_NotifyChange(FILE_ACTION_ADDED,
6157 FILE_NOTIFY_CHANGE_FILE_NAME,
6158 dscp, lastNamep, NULL, TRUE);
6159 if (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE) {
6160 /* Not an exclusive create, and someone else tried
6161 * creating it already, then we open it anyway. We
6162 * don't bother retrying after this, since if this next
6163 * fails, that means that the file was deleted after we
6164 * started this call.
6166 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
6169 if (createDisp == FILE_OVERWRITE_IF) {
6170 setAttr.mask = CM_ATTRMASK_LENGTH;
6171 setAttr.length.LowPart = 0;
6172 setAttr.length.HighPart = 0;
6174 /* now watch for a symlink */
6176 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
6178 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
6180 /* we have a more accurate file to use (the
6181 * target of the symbolic link). Otherwise,
6182 * we'll just use the symlink anyway.
6184 osi_Log2(smb_logp, "symlink vp %x to vp %x",
6186 cm_ReleaseSCache(scp);
6190 code = cm_SetAttr(scp, &setAttr, userp, &req);
6192 } /* lookup succeeded */
6195 /* create directory */
6196 osi_assert(dscp != NULL);
6198 "smb_ReceiveNTTranCreate creating directory %s",
6199 osi_LogSaveString(smb_logp, lastNamep));
6200 openAction = 2; /* created directory */
6201 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
6202 setAttr.clientModTime = time(NULL);
6203 code = cm_MakeDir(dscp, lastNamep, 0, &setAttr, userp, &req);
6204 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
6205 smb_NotifyChange(FILE_ACTION_ADDED,
6206 FILE_NOTIFY_CHANGE_DIR_NAME,
6207 dscp, lastNamep, NULL, TRUE);
6209 (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE)) {
6210 /* Not an exclusive create, and someone else tried
6211 * creating it already, then we open it anyway. We
6212 * don't bother retrying after this, since if this next
6213 * fails, that means that the file was deleted after we
6214 * started this call.
6216 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
6222 /* something went wrong creating or truncating the file */
6223 if (scp) cm_ReleaseSCache(scp);
6224 cm_ReleaseUser(userp);
6229 /* make sure we have file vs. dir right */
6230 if (realDirFlag == 0 && scp->fileType != CM_SCACHETYPE_FILE) {
6231 /* now watch for a symlink */
6233 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
6235 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
6237 /* we have a more accurate file to use (the
6238 * target of the symbolic link). Otherwise,
6239 * we'll just use the symlink anyway.
6241 osi_Log2(smb_logp, "symlink vp %x to vp %x",
6243 cm_ReleaseSCache(scp);
6248 if (scp->fileType != CM_SCACHETYPE_FILE) {
6249 cm_ReleaseSCache(scp);
6250 cm_ReleaseUser(userp);
6252 return CM_ERROR_ISDIR;
6256 if (realDirFlag == 1 && scp->fileType == CM_SCACHETYPE_FILE) {
6257 cm_ReleaseSCache(scp);
6258 cm_ReleaseUser(userp);
6260 return CM_ERROR_NOTDIR;
6263 /* open the file itself */
6264 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
6267 /* save a pointer to the vnode */
6270 fidp->flags = fidflags;
6272 /* save parent dir and pathname for deletion or change notification */
6273 if (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE)) {
6274 fidp->flags |= SMB_FID_NTOPEN;
6275 fidp->NTopen_dscp = dscp;
6276 cm_HoldSCache(dscp);
6277 fidp->NTopen_pathp = strdup(lastNamep);
6279 fidp->NTopen_wholepathp = realPathp;
6281 /* we don't need this any longer */
6282 if (dscp) cm_ReleaseSCache(dscp);
6284 cm_Open(scp, 0, userp);
6286 /* set inp->fid so that later read calls in same msg can find fid */
6287 inp->fid = fidp->fid;
6289 /* check whether we are required to send an extended response */
6290 if (!extendedRespRequired) {
6292 parmOffset = 8*4 + 39;
6293 parmOffset += 1; /* pad to 4 */
6294 dataOffset = parmOffset + 70;
6298 /* Total Parameter Count */
6299 smb_SetSMBParmLong(outp, parmSlot, 70); parmSlot += 2;
6300 /* Total Data Count */
6301 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
6302 /* Parameter Count */
6303 smb_SetSMBParmLong(outp, parmSlot, 70); parmSlot += 2;
6304 /* Parameter Offset */
6305 smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
6306 /* Parameter Displacement */
6307 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
6309 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
6311 smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
6312 /* Data Displacement */
6313 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
6314 smb_SetSMBParmByte(outp, parmSlot, 0); /* Setup Count */
6315 smb_SetSMBDataLength(outp, 70);
6317 lock_ObtainMutex(&scp->mx);
6318 outData = smb_GetSMBData(outp, NULL);
6319 outData++; /* round to get to parmOffset */
6320 *outData = 0; outData++; /* oplock */
6321 *outData = 0; outData++; /* reserved */
6322 *((USHORT *)outData) = fidp->fid; outData += 2; /* fid */
6323 *((ULONG *)outData) = openAction; outData += 4;
6324 *((ULONG *)outData) = 0; outData += 4; /* EA error offset */
6325 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
6326 *((FILETIME *)outData) = ft; outData += 8; /* creation time */
6327 *((FILETIME *)outData) = ft; outData += 8; /* last access time */
6328 *((FILETIME *)outData) = ft; outData += 8; /* last write time */
6329 *((FILETIME *)outData) = ft; outData += 8; /* change time */
6330 *((ULONG *)outData) = smb_ExtAttributes(scp); outData += 4;
6331 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* alloc sz */
6332 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* EOF */
6333 *((USHORT *)outData) = 0; outData += 2; /* filetype */
6334 *((USHORT *)outData) = 0; outData += 2; /* dev state */
6335 *((USHORT *)outData) = (scp->fileType == CM_SCACHETYPE_DIRECTORY);
6336 outData += 2; /* is a dir? */
6337 lock_ReleaseMutex(&scp->mx);
6340 parmOffset = 8*4 + 39;
6341 parmOffset += 1; /* pad to 4 */
6342 dataOffset = parmOffset + 104;
6346 /* Total Parameter Count */
6347 smb_SetSMBParmLong(outp, parmSlot, 101); parmSlot += 2;
6348 /* Total Data Count */
6349 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
6350 /* Parameter Count */
6351 smb_SetSMBParmLong(outp, parmSlot, 101); parmSlot += 2;
6352 /* Parameter Offset */
6353 smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
6354 /* Parameter Displacement */
6355 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
6357 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
6359 smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
6360 /* Data Displacement */
6361 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
6362 smb_SetSMBParmByte(outp, parmSlot, 0); /* Setup Count */
6363 smb_SetSMBDataLength(outp, 105);
6365 lock_ObtainMutex(&scp->mx);
6366 outData = smb_GetSMBData(outp, NULL);
6367 outData++; /* round to get to parmOffset */
6368 *outData = 0; outData++; /* oplock */
6369 *outData = 1; outData++; /* response type */
6370 *((USHORT *)outData) = fidp->fid; outData += 2; /* fid */
6371 *((ULONG *)outData) = openAction; outData += 4;
6372 *((ULONG *)outData) = 0; outData += 4; /* EA error offset */
6373 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
6374 *((FILETIME *)outData) = ft; outData += 8; /* creation time */
6375 *((FILETIME *)outData) = ft; outData += 8; /* last access time */
6376 *((FILETIME *)outData) = ft; outData += 8; /* last write time */
6377 *((FILETIME *)outData) = ft; outData += 8; /* change time */
6378 *((ULONG *)outData) = smb_ExtAttributes(scp); outData += 4;
6379 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* alloc sz */
6380 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* EOF */
6381 *((USHORT *)outData) = 0; outData += 2; /* filetype */
6382 *((USHORT *)outData) = 0; outData += 2; /* dev state */
6383 *((USHORT *)outData) = (scp->fileType == CM_SCACHETYPE_DIRECTORY);
6384 outData += 1; /* is a dir? */
6385 memset(outData,0,24); outData += 24; /* Volume ID and file ID */
6386 *((ULONG *)outData) = 0x001f01ffL; outData += 4; /* Maxmimal access rights */
6387 *((ULONG *)outData) = 0; outData += 4; /* Guest Access rights */
6388 lock_ReleaseMutex(&scp->mx);
6391 osi_Log1(smb_logp, "SMB NTTranCreate opening fid %d", fidp->fid);
6393 smb_ReleaseFID(fidp);
6395 cm_ReleaseUser(userp);
6397 /* free(realPathp); Can't free realPathp here because fidp->NTopen_wholepathp points there */
6398 /* leave scp held since we put it in fidp->scp */
6402 long smb_ReceiveNTTranNotifyChange(smb_vc_t *vcp, smb_packet_t *inp,
6405 smb_packet_t *savedPacketp;
6406 ULONG filter; USHORT fid, watchtree;
6410 filter = smb_GetSMBParm(inp, 19) |
6411 (smb_GetSMBParm(inp, 20) << 16);
6412 fid = smb_GetSMBParm(inp, 21);
6413 watchtree = smb_GetSMBParm(inp, 22) && 0xffff; /* TODO: should this be 0xff ? */
6415 fidp = smb_FindFID(vcp, fid, 0);
6417 osi_Log1(smb_logp, "ERROR: NotifyChange given invalid fid [%d]", fid);
6418 return CM_ERROR_BADFD;
6421 savedPacketp = smb_CopyPacket(inp);
6423 savedPacketp->vcp = vcp;
6424 lock_ObtainMutex(&smb_Dir_Watch_Lock);
6425 savedPacketp->nextp = smb_Directory_Watches;
6426 smb_Directory_Watches = savedPacketp;
6427 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
6429 osi_Log4(smb_logp, "Request for NotifyChange filter 0x%x fid %d wtree %d file %s",
6430 filter, fid, watchtree, osi_LogSaveString(smb_logp, fidp->NTopen_wholepathp));
6433 lock_ObtainMutex(&scp->mx);
6435 scp->flags |= CM_SCACHEFLAG_WATCHEDSUBTREE;
6437 scp->flags |= CM_SCACHEFLAG_WATCHED;
6438 lock_ReleaseMutex(&scp->mx);
6439 smb_ReleaseFID(fidp);
6441 outp->flags |= SMB_PACKETFLAG_NOSEND;
6445 unsigned char nullSecurityDesc[36] = {
6446 0x01, /* security descriptor revision */
6447 0x00, /* reserved, should be zero */
6448 0x00, 0x80, /* security descriptor control;
6449 * 0x8000 : self-relative format */
6450 0x14, 0x00, 0x00, 0x00, /* offset of owner SID */
6451 0x1c, 0x00, 0x00, 0x00, /* offset of group SID */
6452 0x00, 0x00, 0x00, 0x00, /* offset of DACL would go here */
6453 0x00, 0x00, 0x00, 0x00, /* offset of SACL would go here */
6454 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
6455 /* "null SID" owner SID */
6456 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
6457 /* "null SID" group SID */
6460 long smb_ReceiveNTTranQuerySecurityDesc(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6462 int parmOffset, parmCount, dataOffset, dataCount;
6470 ULONG securityInformation;
6472 parmOffset = smb_GetSMBOffsetParm(inp, 11, 1)
6473 | (smb_GetSMBOffsetParm(inp, 12, 1) << 16);
6474 parmp = inp->data + parmOffset;
6475 sparmp = (USHORT *) parmp;
6476 lparmp = (ULONG *) parmp;
6479 securityInformation = lparmp[1];
6481 maxData = smb_GetSMBOffsetParm(inp, 7, 1)
6482 | (smb_GetSMBOffsetParm(inp, 8, 1) << 16);
6490 parmOffset = 8*4 + 39;
6491 parmOffset += 1; /* pad to 4 */
6493 dataOffset = parmOffset + parmCount;
6497 /* Total Parameter Count */
6498 smb_SetSMBParmLong(outp, parmSlot, parmCount); parmSlot += 2;
6499 /* Total Data Count */
6500 smb_SetSMBParmLong(outp, parmSlot, dataCount); parmSlot += 2;
6501 /* Parameter Count */
6502 smb_SetSMBParmLong(outp, parmSlot, parmCount); parmSlot += 2;
6503 /* Parameter Offset */
6504 smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
6505 /* Parameter Displacement */
6506 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
6508 smb_SetSMBParmLong(outp, parmSlot, dataCount); parmSlot += 2;
6510 smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
6511 /* Data Displacement */
6512 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
6513 smb_SetSMBParmByte(outp, parmSlot, 0); /* Setup Count */
6514 smb_SetSMBDataLength(outp, 1 + parmCount + dataCount);
6516 outData = smb_GetSMBData(outp, NULL);
6517 outData++; /* round to get to parmOffset */
6518 *((ULONG *)outData) = 36; outData += 4; /* length */
6520 if (maxData >= 36) {
6521 memcpy(outData, nullSecurityDesc, 36);
6525 return CM_ERROR_BUFFERTOOSMALL;
6528 long smb_ReceiveNTTransact(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6530 unsigned short function;
6532 function = smb_GetSMBParm(inp, 18);
6534 osi_Log1(smb_logp, "SMB NT Transact function %d", function);
6536 /* We can handle long names */
6537 if (vcp->flags & SMB_VCFLAG_USENT)
6538 ((smb_t *)outp)->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
6542 return smb_ReceiveNTTranQuerySecurityDesc(vcp, inp, outp);
6544 return smb_ReceiveNTTranNotifyChange(vcp, inp, outp);
6546 return smb_ReceiveNTTranCreate(vcp, inp, outp);
6548 return CM_ERROR_INVAL;
6553 * smb_NotifyChange -- find relevant change notification messages and
6556 * If we don't know the file name (i.e. a callback break), filename is
6557 * NULL, and we return a zero-length list.
6559 void smb_NotifyChange(DWORD action, DWORD notifyFilter,
6560 cm_scache_t *dscp, char *filename, char *otherFilename,
6561 BOOL isDirectParent)
6563 smb_packet_t *watch, *lastWatch, *nextWatch;
6564 ULONG parmSlot, parmCount, parmOffset, dataOffset, nameLen;
6565 char *outData, *oldOutData;
6569 BOOL twoEntries = FALSE;
6570 ULONG otherNameLen, oldParmCount = 0;
6575 /* Get ready for rename within directory */
6576 if (action == FILE_ACTION_RENAMED_OLD_NAME && otherFilename != NULL) {
6578 otherAction = FILE_ACTION_RENAMED_NEW_NAME;
6581 osi_Log2(smb_logp,"in smb_NotifyChange for file [%s] dscp [%x]",
6582 osi_LogSaveString(smb_logp,filename),dscp);
6584 lock_ObtainMutex(&smb_Dir_Watch_Lock);
6585 watch = smb_Directory_Watches;
6587 filter = smb_GetSMBParm(watch, 19)
6588 | (smb_GetSMBParm(watch, 20) << 16);
6589 fid = smb_GetSMBParm(watch, 21);
6590 wtree = smb_GetSMBParm(watch, 22) & 0xffff; /* TODO: should this be 0xff ? */
6591 maxLen = smb_GetSMBOffsetParm(watch, 5, 1)
6592 | (smb_GetSMBOffsetParm(watch, 6, 1) << 16);
6596 * Strange hack - bug in NT Client and NT Server that we
6599 if (filter == 3 && wtree)
6602 fidp = smb_FindFID(vcp, fid, 0);
6604 osi_Log1(smb_logp," no fidp for fid[%d]",fid);
6606 watch = watch->nextp;
6609 if (fidp->scp != dscp
6610 || (filter & notifyFilter) == 0
6611 || (!isDirectParent && !wtree)) {
6612 osi_Log1(smb_logp," passing fidp->scp[%x]", fidp->scp);
6613 smb_ReleaseFID(fidp);
6615 watch = watch->nextp;
6618 smb_ReleaseFID(fidp);
6621 "Sending Change Notification for fid %d filter 0x%x wtree %d file %s",
6622 fid, filter, wtree, osi_LogSaveString(smb_logp, filename));
6624 nextWatch = watch->nextp;
6625 if (watch == smb_Directory_Watches)
6626 smb_Directory_Watches = nextWatch;
6628 lastWatch->nextp = nextWatch;
6630 /* Turn off WATCHED flag in dscp */
6631 lock_ObtainMutex(&dscp->mx);
6633 dscp->flags &= ~CM_SCACHEFLAG_WATCHEDSUBTREE;
6635 dscp->flags &= ~CM_SCACHEFLAG_WATCHED;
6636 lock_ReleaseMutex(&dscp->mx);
6638 /* Convert to response packet */
6639 ((smb_t *) watch)->reb = SMB_FLAGS_SERVER_TO_CLIENT | SMB_FLAGS_CANONICAL_PATHNAMES;
6640 ((smb_t *) watch)->wct = 0;
6643 if (filename == NULL)
6646 nameLen = strlen(filename);
6647 parmCount = 3*4 + nameLen*2;
6648 parmCount = (parmCount + 3) & ~3; /* pad to 4 */
6650 otherNameLen = strlen(otherFilename);
6651 oldParmCount = parmCount;
6652 parmCount += 3*4 + otherNameLen*2;
6653 parmCount = (parmCount + 3) & ~3; /* pad to 4 */
6655 if (maxLen < parmCount)
6656 parmCount = 0; /* not enough room */
6658 parmOffset = 8*4 + 39;
6659 parmOffset += 1; /* pad to 4 */
6660 dataOffset = parmOffset + parmCount;
6664 /* Total Parameter Count */
6665 smb_SetSMBParmLong(watch, parmSlot, parmCount); parmSlot += 2;
6666 /* Total Data Count */
6667 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
6668 /* Parameter Count */
6669 smb_SetSMBParmLong(watch, parmSlot, parmCount); parmSlot += 2;
6670 /* Parameter Offset */
6671 smb_SetSMBParmLong(watch, parmSlot, parmOffset); parmSlot += 2;
6672 /* Parameter Displacement */
6673 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
6675 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
6677 smb_SetSMBParmLong(watch, parmSlot, dataOffset); parmSlot += 2;
6678 /* Data Displacement */
6679 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
6680 smb_SetSMBParmByte(watch, parmSlot, 0); /* Setup Count */
6681 smb_SetSMBDataLength(watch, parmCount + 1);
6683 if (parmCount != 0) {
6685 outData = smb_GetSMBData(watch, NULL);
6686 outData++; /* round to get to parmOffset */
6687 oldOutData = outData;
6688 *((DWORD *)outData) = oldParmCount; outData += 4;
6689 /* Next Entry Offset */
6690 *((DWORD *)outData) = action; outData += 4;
6692 *((DWORD *)outData) = nameLen*2; outData += 4;
6693 /* File Name Length */
6694 p = strdup(filename);
6695 if (smb_StoreAnsiFilenames)
6697 mbstowcs((WCHAR *)outData, p, nameLen);
6701 outData = oldOutData + oldParmCount;
6702 *((DWORD *)outData) = 0; outData += 4;
6703 /* Next Entry Offset */
6704 *((DWORD *)outData) = otherAction; outData += 4;
6706 *((DWORD *)outData) = otherNameLen*2;
6707 outData += 4; /* File Name Length */
6708 p = strdup(otherFilename);
6709 if (smb_StoreAnsiFilenames)
6711 mbstowcs((WCHAR *)outData, p, otherNameLen); /* File Name */
6717 * If filename is null, we don't know the cause of the
6718 * change notification. We return zero data (see above),
6719 * and set error code to NT_STATUS_NOTIFY_ENUM_DIR
6720 * (= 0x010C). We set the error code here by hand, without
6721 * modifying wct and bcc.
6723 if (filename == NULL) {
6724 ((smb_t *) watch)->rcls = 0x0C;
6725 ((smb_t *) watch)->reh = 0x01;
6726 ((smb_t *) watch)->errLow = 0;
6727 ((smb_t *) watch)->errHigh = 0;
6728 /* Set NT Status codes flag */
6729 ((smb_t *) watch)->flg2 |= SMB_FLAGS2_32BIT_STATUS;
6732 smb_SendPacket(vcp, watch);
6733 smb_FreePacket(watch);
6736 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
6739 long smb_ReceiveNTCancel(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6741 unsigned char *replyWctp;
6742 smb_packet_t *watch, *lastWatch;
6743 USHORT fid, watchtree;
6747 osi_Log0(smb_logp, "SMB3 receive NT cancel");
6749 lock_ObtainMutex(&smb_Dir_Watch_Lock);
6750 watch = smb_Directory_Watches;
6752 if (((smb_t *)watch)->uid == ((smb_t *)inp)->uid
6753 && ((smb_t *)watch)->pid == ((smb_t *)inp)->pid
6754 && ((smb_t *)watch)->mid == ((smb_t *)inp)->mid
6755 && ((smb_t *)watch)->tid == ((smb_t *)inp)->tid) {
6756 if (watch == smb_Directory_Watches)
6757 smb_Directory_Watches = watch->nextp;
6759 lastWatch->nextp = watch->nextp;
6760 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
6762 /* Turn off WATCHED flag in scp */
6763 fid = smb_GetSMBParm(watch, 21);
6764 watchtree = smb_GetSMBParm(watch, 22) & 0xffff;
6766 if (vcp != watch->vcp)
6767 osi_Log2(smb_logp, "smb_ReceiveNTCancel: vcp %x not equal to watch vcp %x",
6770 fidp = smb_FindFID(vcp, fid, 0);
6772 osi_Log3(smb_logp, "Cancelling change notification for fid %d wtree %d file %s",
6774 osi_LogSaveString(smb_logp, (fidp)?fidp->NTopen_wholepathp:""));
6777 lock_ObtainMutex(&scp->mx);
6779 scp->flags &= ~CM_SCACHEFLAG_WATCHEDSUBTREE;
6781 scp->flags &= ~CM_SCACHEFLAG_WATCHED;
6782 lock_ReleaseMutex(&scp->mx);
6783 smb_ReleaseFID(fidp);
6785 osi_Log2(smb_logp,"NTCancel unable to resolve fid [%d] in vcp[%x]", fid,vcp);
6788 /* assume STATUS32; return 0xC0000120 (CANCELED) */
6789 replyWctp = watch->wctp;
6793 ((smb_t *)watch)->rcls = 0x20;
6794 ((smb_t *)watch)->reh = 0x1;
6795 ((smb_t *)watch)->errLow = 0;
6796 ((smb_t *)watch)->errHigh = 0xC0;
6797 ((smb_t *)watch)->flg2 |= SMB_FLAGS2_32BIT_STATUS;
6798 smb_SendPacket(vcp, watch);
6799 smb_FreePacket(watch);
6803 watch = watch->nextp;
6805 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
6811 * NT rename also does hard links.
6814 #define RENAME_FLAG_MOVE_CLUSTER_INFORMATION 0x102
6815 #define RENAME_FLAG_HARD_LINK 0x103
6816 #define RENAME_FLAG_RENAME 0x104
6817 #define RENAME_FLAG_COPY 0x105
6819 long smb_ReceiveNTRename(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6821 char *oldPathp, *newPathp;
6827 attrs = smb_GetSMBParm(inp, 0);
6828 rename_type = smb_GetSMBParm(inp, 1);
6830 if (rename_type != RENAME_FLAG_RENAME && rename_type != RENAME_FLAG_HARD_LINK) {
6831 osi_Log1(smb_logp, "NTRename invalid infolevel [%x]", rename_type);
6832 return CM_ERROR_NOACCESS;
6835 tp = smb_GetSMBData(inp, NULL);
6836 oldPathp = smb_ParseASCIIBlock(tp, &tp);
6837 if (smb_StoreAnsiFilenames)
6838 OemToChar(oldPathp,oldPathp);
6839 newPathp = smb_ParseASCIIBlock(tp, &tp);
6840 if (smb_StoreAnsiFilenames)
6841 OemToChar(newPathp,newPathp);
6843 osi_Log3(smb_logp, "NTRename for [%s]->[%s] type [%s]",
6844 osi_LogSaveString(smb_logp, oldPathp),
6845 osi_LogSaveString(smb_logp, newPathp),
6846 ((rename_type==RENAME_FLAG_RENAME)?"rename":"hardlink"));
6848 if (rename_type == RENAME_FLAG_RENAME) {
6849 code = smb_Rename(vcp,inp,oldPathp,newPathp,attrs);
6850 } else { /* RENAME_FLAG_HARD_LINK */
6851 code = smb_Link(vcp,inp,oldPathp,newPathp);
6858 lock_InitializeMutex(&smb_Dir_Watch_Lock, "Directory Watch List Lock");
6861 cm_user_t *smb_FindCMUserByName(/*smb_vc_t *vcp,*/ char *usern, char *machine)
6864 smb_username_t *unp;
6866 unp = smb_FindUserByName(usern, machine, SMB_FLAG_CREATE);
6868 lock_ObtainMutex(&unp->mx);
6869 unp->userp = cm_NewUser();
6870 lock_ReleaseMutex(&unp->mx);
6871 osi_Log2(smb_logp,"smb_FindCMUserByName New user name[%s] machine[%s]",osi_LogSaveString(smb_logp,usern),osi_LogSaveString(smb_logp,machine));
6872 osi_LogEvent("AFS smb_FindCMUserByName : New User",NULL,"name[%s] machine[%s]",usern,machine);
6874 osi_Log2(smb_logp,"smb_FindCMUserByName Not found name[%s] machine[%s]",osi_LogSaveString(smb_logp,usern),osi_LogSaveString(smb_logp,machine));
6875 osi_LogEvent("AFS smb_FindCMUserByName : Found",NULL,"name[%s] machine[%s]",usern,machine);