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>
15 #define SECURITY_WIN32
26 #include <WINNT\afsreg.h>
30 extern osi_hyper_t hzero;
32 smb_packet_t *smb_Directory_Watches = NULL;
33 osi_mutex_t smb_Dir_Watch_Lock;
35 smb_tran2Dispatch_t smb_tran2DispatchTable[SMB_TRAN2_NOPCODES];
37 smb_tran2Dispatch_t smb_rapDispatchTable[SMB_RAP_NOPCODES];
39 /* protected by the smb_globalLock */
40 smb_tran2Packet_t *smb_tran2AssemblyQueuep;
42 /* retrieve a held reference to a user structure corresponding to an incoming
44 cm_user_t *smb_GetTran2User(smb_vc_t *vcp, smb_tran2Packet_t *inp)
49 uidp = smb_FindUID(vcp, inp->uid, 0);
53 up = smb_GetUserFromUID(uidp);
61 * Return extended attributes.
62 * Right now, we aren't using any of the "new" bits, so this looks exactly
63 * like smb_Attributes() (see smb.c).
65 unsigned long smb_ExtAttributes(cm_scache_t *scp)
69 if (scp->fileType == CM_SCACHETYPE_DIRECTORY ||
70 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
71 scp->fileType == CM_SCACHETYPE_INVALID)
73 attrs = SMB_ATTR_DIRECTORY;
74 #ifdef SPECIAL_FOLDERS
75 attrs |= SMB_ATTR_SYSTEM; /* FILE_ATTRIBUTE_SYSTEM */
76 #endif /* SPECIAL_FOLDERS */
77 } else if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
78 attrs = SMB_ATTR_DIRECTORY | SMB_ATTR_SPARSE_FILE;
82 * We used to mark a file RO if it was in an RO volume, but that
83 * turns out to be impolitic in NT. See defect 10007.
86 if ((scp->unixModeBits & 0222) == 0 || (scp->flags & CM_SCACHEFLAG_RO))
87 attrs |= SMB_ATTR_READONLY; /* Read-only */
89 if ((scp->unixModeBits & 0222) == 0)
90 attrs |= SMB_ATTR_READONLY; /* Read-only */
94 attrs = SMB_ATTR_NORMAL; /* FILE_ATTRIBUTE_NORMAL */
99 int smb_V3IsStarMask(char *maskp)
103 while (tc = *maskp++)
104 if (tc == '?' || tc == '*' || tc == '<' || tc == '>')
109 unsigned char *smb_ParseString(unsigned char *inp, char **chainpp)
112 /* skip over null-terminated string */
113 *chainpp = inp + strlen(inp) + 1;
118 void OutputDebugF(char * format, ...) {
123 va_start( args, format );
124 len = _vscprintf( format, args ) // _vscprintf doesn't count
125 + 3; // terminating '\0' + '\n'
126 buffer = malloc( len * sizeof(char) );
127 vsprintf( buffer, format, args );
128 osi_Log0(smb_logp, osi_LogSaveString(smb_logp, buffer));
129 strcat(buffer, "\n");
130 OutputDebugString(buffer);
134 void OutputDebugHexDump(unsigned char * buffer, int len) {
137 static char tr[16] = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
139 OutputDebugF("Hexdump length [%d]",len);
141 for (i=0;i<len;i++) {
144 osi_Log0(smb_logp, osi_LogSaveString(smb_logp, buf));
146 OutputDebugString(buf);
148 sprintf(buf,"%5x",i);
149 memset(buf+5,' ',80);
154 j = j*3 + 7 + ((j>7)?1:0);
157 buf[j] = tr[k / 16]; buf[j+1] = tr[k % 16];
160 j = j + 56 + ((j>7)?1:0) + pcts;
162 buf[j] = (k>32 && k<127)?k:'.';
169 osi_Log0(smb_logp, osi_LogSaveString(smb_logp, buf));
171 OutputDebugString(buf);
175 #define SMB_EXT_SEC_PACKAGE_NAME "Negotiate"
177 void smb_NegotiateExtendedSecurity(void ** secBlob, int * secBlobLength) {
178 SECURITY_STATUS status, istatus;
179 CredHandle creds = {0,0};
181 SecBufferDesc secOut;
189 OutputDebugF("Negotiating Extended Security");
191 status = AcquireCredentialsHandle( NULL,
192 SMB_EXT_SEC_PACKAGE_NAME,
201 if (status != SEC_E_OK) {
202 /* Really bad. We return an empty security blob */
203 OutputDebugF("AcquireCredentialsHandle failed with %lX", status);
208 secOut.pBuffers = &secTok;
209 secOut.ulVersion = SECBUFFER_VERSION;
211 secTok.BufferType = SECBUFFER_TOKEN;
213 secTok.pvBuffer = NULL;
215 ctx.dwLower = ctx.dwUpper = 0;
217 status = AcceptSecurityContext( &creds,
220 ASC_REQ_CONNECTION | ASC_REQ_EXTENDED_ERROR | ASC_REQ_ALLOCATE_MEMORY,
221 SECURITY_NETWORK_DREP,
228 if (status == SEC_I_COMPLETE_NEEDED || status == SEC_I_COMPLETE_AND_CONTINUE) {
229 OutputDebugF("Completing token...");
230 istatus = CompleteAuthToken(&ctx, &secOut);
231 if ( istatus != SEC_E_OK )
232 OutputDebugF("Token completion failed: %x", istatus);
235 if (status == SEC_I_COMPLETE_AND_CONTINUE || status == SEC_I_CONTINUE_NEEDED) {
236 if (secTok.pvBuffer) {
237 *secBlobLength = secTok.cbBuffer;
238 *secBlob = malloc( secTok.cbBuffer );
239 memcpy(*secBlob, secTok.pvBuffer, secTok.cbBuffer );
242 if ( status != SEC_E_OK )
243 OutputDebugF("AcceptSecurityContext status != CONTINUE %lX", status);
246 /* Discard partial security context */
247 DeleteSecurityContext(&ctx);
249 if (secTok.pvBuffer) FreeContextBuffer( secTok.pvBuffer );
251 /* Discard credentials handle. We'll reacquire one when we get the session setup X */
252 FreeCredentialsHandle(&creds);
258 struct smb_ext_context {
265 long smb_AuthenticateUserExt(smb_vc_t * vcp, char * usern, char * secBlobIn, int secBlobInLength, char ** secBlobOut, int * secBlobOutLength) {
266 SECURITY_STATUS status, istatus;
270 SecBufferDesc secBufIn;
272 SecBufferDesc secBufOut;
275 struct smb_ext_context * secCtx = NULL;
276 struct smb_ext_context * newSecCtx = NULL;
277 void * assembledBlob = NULL;
278 int assembledBlobLength = 0;
281 OutputDebugF("In smb_AuthenticateUserExt");
284 *secBlobOutLength = 0;
286 if (vcp->flags & SMB_VCFLAG_AUTH_IN_PROGRESS) {
287 secCtx = vcp->secCtx;
288 lock_ObtainMutex(&vcp->mx);
289 vcp->flags &= ~SMB_VCFLAG_AUTH_IN_PROGRESS;
291 lock_ReleaseMutex(&vcp->mx);
295 OutputDebugF("Received incoming token:");
296 OutputDebugHexDump(secBlobIn,secBlobInLength);
300 OutputDebugF("Continuing with existing context.");
301 creds = secCtx->creds;
304 if (secCtx->partialToken) {
305 assembledBlobLength = secCtx->partialTokenLen + secBlobInLength;
306 assembledBlob = malloc(assembledBlobLength);
307 memcpy(assembledBlob,secCtx->partialToken, secCtx->partialTokenLen);
308 memcpy(((BYTE *)assembledBlob) + secCtx->partialTokenLen, secBlobIn, secBlobInLength);
311 status = AcquireCredentialsHandle( NULL,
312 SMB_EXT_SEC_PACKAGE_NAME,
321 if (status != SEC_E_OK) {
322 OutputDebugF("Can't acquire Credentials handle [%lX]", status);
323 code = CM_ERROR_BADPASSWORD; /* means "try again when I'm sober" */
331 secBufIn.cBuffers = 1;
332 secBufIn.pBuffers = &secTokIn;
333 secBufIn.ulVersion = SECBUFFER_VERSION;
335 secTokIn.BufferType = SECBUFFER_TOKEN;
337 secTokIn.cbBuffer = assembledBlobLength;
338 secTokIn.pvBuffer = assembledBlob;
340 secTokIn.cbBuffer = secBlobInLength;
341 secTokIn.pvBuffer = secBlobIn;
344 secBufOut.cBuffers = 1;
345 secBufOut.pBuffers = &secTokOut;
346 secBufOut.ulVersion = SECBUFFER_VERSION;
348 secTokOut.BufferType = SECBUFFER_TOKEN;
349 secTokOut.cbBuffer = 0;
350 secTokOut.pvBuffer = NULL;
352 status = AcceptSecurityContext( &creds,
353 ((secCtx)?&ctx:NULL),
355 ASC_REQ_CONNECTION | ASC_REQ_EXTENDED_ERROR | ASC_REQ_ALLOCATE_MEMORY,
356 SECURITY_NETWORK_DREP,
363 if (status == SEC_I_COMPLETE_NEEDED || status == SEC_I_COMPLETE_AND_CONTINUE) {
364 OutputDebugF("Completing token...");
365 istatus = CompleteAuthToken(&ctx, &secBufOut);
366 if ( istatus != SEC_E_OK )
367 OutputDebugF("Token completion failed: %lX", istatus);
370 if (status == SEC_I_COMPLETE_AND_CONTINUE || status == SEC_I_CONTINUE_NEEDED) {
371 OutputDebugF("Continue needed");
373 newSecCtx = malloc(sizeof(*newSecCtx));
375 newSecCtx->creds = creds;
376 newSecCtx->ctx = ctx;
377 newSecCtx->partialToken = NULL;
378 newSecCtx->partialTokenLen = 0;
380 lock_ObtainMutex( &vcp->mx );
381 vcp->flags |= SMB_VCFLAG_AUTH_IN_PROGRESS;
382 vcp->secCtx = newSecCtx;
383 lock_ReleaseMutex( &vcp->mx );
385 code = CM_ERROR_GSSCONTINUE;
388 if ((status == SEC_I_COMPLETE_NEEDED || status == SEC_E_OK ||
389 status == SEC_I_COMPLETE_AND_CONTINUE || status == SEC_I_CONTINUE_NEEDED) &&
390 secTokOut.pvBuffer) {
391 OutputDebugF("Need to send token back to client");
393 *secBlobOutLength = secTokOut.cbBuffer;
394 *secBlobOut = malloc(secTokOut.cbBuffer);
395 memcpy(*secBlobOut, secTokOut.pvBuffer, secTokOut.cbBuffer);
397 OutputDebugF("Outgoing token:");
398 OutputDebugHexDump(*secBlobOut,*secBlobOutLength);
399 } else if (status == SEC_E_INCOMPLETE_MESSAGE) {
400 OutputDebugF("Incomplete message");
402 newSecCtx = malloc(sizeof(*newSecCtx));
404 newSecCtx->creds = creds;
405 newSecCtx->ctx = ctx;
406 newSecCtx->partialToken = malloc(secTokOut.cbBuffer);
407 memcpy(newSecCtx->partialToken, secTokOut.pvBuffer, secTokOut.cbBuffer);
408 newSecCtx->partialTokenLen = secTokOut.cbBuffer;
410 lock_ObtainMutex( &vcp->mx );
411 vcp->flags |= SMB_VCFLAG_AUTH_IN_PROGRESS;
412 vcp->secCtx = newSecCtx;
413 lock_ReleaseMutex( &vcp->mx );
415 code = CM_ERROR_GSSCONTINUE;
418 if (status == SEC_E_OK || status == SEC_I_COMPLETE_NEEDED) {
420 SecPkgContext_Names names;
422 OutputDebugF("Authentication completed");
423 OutputDebugF("Returned flags : [%lX]", flags);
425 if (!QueryContextAttributes(&ctx, SECPKG_ATTR_NAMES, &names)) {
426 OutputDebugF("Received name [%s]", names.sUserName);
427 strcpy(usern, names.sUserName);
428 strlwr(usern); /* in tandem with smb_GetNormalizedUsername */
429 FreeContextBuffer(names.sUserName);
431 /* Force the user to retry if the context is invalid */
432 OutputDebugF("QueryContextAttributes Names failed [%x]", GetLastError());
433 code = CM_ERROR_BADPASSWORD;
437 case SEC_E_INVALID_TOKEN:
438 OutputDebugF("Returning bad password :: INVALID_TOKEN");
440 case SEC_E_INVALID_HANDLE:
441 OutputDebugF("Returning bad password :: INVALID_HANDLE");
443 case SEC_E_LOGON_DENIED:
444 OutputDebugF("Returning bad password :: LOGON_DENIED");
446 case SEC_E_UNKNOWN_CREDENTIALS:
447 OutputDebugF("Returning bad password :: UNKNOWN_CREDENTIALS");
449 case SEC_E_NO_CREDENTIALS:
450 OutputDebugF("Returning bad password :: NO_CREDENTIALS");
452 case SEC_E_CONTEXT_EXPIRED:
453 OutputDebugF("Returning bad password :: CONTEXT_EXPIRED");
455 case SEC_E_INCOMPLETE_CREDENTIALS:
456 OutputDebugF("Returning bad password :: INCOMPLETE_CREDENTIALS");
458 case SEC_E_WRONG_PRINCIPAL:
459 OutputDebugF("Returning bad password :: WRONG_PRINCIPAL");
461 case SEC_E_TIME_SKEW:
462 OutputDebugF("Returning bad password :: TIME_SKEW");
465 OutputDebugF("Returning bad password :: Status == %lX", status);
467 code = CM_ERROR_BADPASSWORD;
471 if (secCtx->partialToken) free(secCtx->partialToken);
479 if (secTokOut.pvBuffer)
480 FreeContextBuffer(secTokOut.pvBuffer);
482 if (code != CM_ERROR_GSSCONTINUE) {
483 DeleteSecurityContext(&ctx);
484 FreeCredentialsHandle(&creds);
492 #define P_RESP_LEN 128
494 /* LsaLogonUser expects input parameters to be in a contiguous block of memory.
495 So put stuff in a struct. */
496 struct Lm20AuthBlob {
497 MSV1_0_LM20_LOGON lmlogon;
498 BYTE ciResponse[P_RESP_LEN]; /* Unicode representation */
499 BYTE csResponse[P_RESP_LEN]; /* ANSI representation */
500 WCHAR accountNameW[P_LEN];
501 WCHAR primaryDomainW[P_LEN];
502 WCHAR workstationW[MAX_COMPUTERNAME_LENGTH + 1];
503 TOKEN_GROUPS tgroups;
504 TOKEN_SOURCE tsource;
507 long smb_AuthenticateUserLM(smb_vc_t *vcp, char * accountName, char * primaryDomain, char * ciPwd, unsigned ciPwdLength, char * csPwd, unsigned csPwdLength)
510 struct Lm20AuthBlob lmAuth;
511 PMSV1_0_LM20_LOGON_PROFILE lmprofilep;
512 QUOTA_LIMITS quotaLimits;
514 ULONG lmprofilepSize;
518 OutputDebugF("In smb_AuthenticateUser for user [%s] domain [%s]", accountName, primaryDomain);
519 OutputDebugF("ciPwdLength is %d and csPwdLength is %d", ciPwdLength, csPwdLength);
521 if (ciPwdLength > P_RESP_LEN || csPwdLength > P_RESP_LEN) {
522 OutputDebugF("ciPwdLength or csPwdLength is too long");
523 return CM_ERROR_BADPASSWORD;
526 memset(&lmAuth,0,sizeof(lmAuth));
528 lmAuth.lmlogon.MessageType = MsV1_0NetworkLogon;
530 lmAuth.lmlogon.LogonDomainName.Buffer = lmAuth.primaryDomainW;
531 mbstowcs(lmAuth.primaryDomainW, primaryDomain, P_LEN);
532 lmAuth.lmlogon.LogonDomainName.Length = (USHORT)(wcslen(lmAuth.primaryDomainW) * sizeof(WCHAR));
533 lmAuth.lmlogon.LogonDomainName.MaximumLength = P_LEN * sizeof(WCHAR);
535 lmAuth.lmlogon.UserName.Buffer = lmAuth.accountNameW;
536 mbstowcs(lmAuth.accountNameW, accountName, P_LEN);
537 lmAuth.lmlogon.UserName.Length = (USHORT)(wcslen(lmAuth.accountNameW) * sizeof(WCHAR));
538 lmAuth.lmlogon.UserName.MaximumLength = P_LEN * sizeof(WCHAR);
540 lmAuth.lmlogon.Workstation.Buffer = lmAuth.workstationW;
541 lmAuth.lmlogon.Workstation.MaximumLength = (MAX_COMPUTERNAME_LENGTH + 1) * sizeof(WCHAR);
542 size = MAX_COMPUTERNAME_LENGTH + 1;
543 GetComputerNameW(lmAuth.workstationW, &size);
544 lmAuth.lmlogon.Workstation.Length = (USHORT)(wcslen(lmAuth.workstationW) * sizeof(WCHAR));
546 memcpy(lmAuth.lmlogon.ChallengeToClient, vcp->encKey, MSV1_0_CHALLENGE_LENGTH);
548 lmAuth.lmlogon.CaseInsensitiveChallengeResponse.Buffer = lmAuth.ciResponse;
549 lmAuth.lmlogon.CaseInsensitiveChallengeResponse.Length = ciPwdLength;
550 lmAuth.lmlogon.CaseInsensitiveChallengeResponse.MaximumLength = P_RESP_LEN;
551 memcpy(lmAuth.ciResponse, ciPwd, ciPwdLength);
553 lmAuth.lmlogon.CaseSensitiveChallengeResponse.Buffer = lmAuth.csResponse;
554 lmAuth.lmlogon.CaseSensitiveChallengeResponse.Length = csPwdLength;
555 lmAuth.lmlogon.CaseSensitiveChallengeResponse.MaximumLength = P_RESP_LEN;
556 memcpy(lmAuth.csResponse, csPwd, csPwdLength);
558 lmAuth.lmlogon.ParameterControl = 0;
560 lmAuth.tgroups.GroupCount = 0;
561 lmAuth.tgroups.Groups[0].Sid = NULL;
562 lmAuth.tgroups.Groups[0].Attributes = 0;
564 lmAuth.tsource.SourceIdentifier.HighPart = (DWORD)((LONG_PTR)vcp << 32);
565 lmAuth.tsource.SourceIdentifier.LowPart = (DWORD)((LONG_PTR)vcp & _UI32_MAX);
566 strcpy(lmAuth.tsource.SourceName,"OpenAFS"); /* 8 char limit */
568 nts = LsaLogonUser( smb_lsaHandle,
583 if (nts != STATUS_SUCCESS || ntsEx != STATUS_SUCCESS)
584 osi_Log2(smb_logp,"LsaLogonUser failure: nts %u ntsEx %u",
587 OutputDebugF("Return from LsaLogonUser is 0x%lX", nts);
588 OutputDebugF("Extended status is 0x%lX", ntsEx);
590 if (nts == ERROR_SUCCESS) {
592 LsaFreeReturnBuffer(lmprofilep);
593 CloseHandle(lmToken);
597 if (nts == 0xC000015BL)
598 return CM_ERROR_BADLOGONTYPE;
599 else /* our catchall is a bad password though we could be more specific */
600 return CM_ERROR_BADPASSWORD;
604 /* The buffer pointed to by usern is assumed to be at least SMB_MAX_USERNAME_LENGTH bytes */
605 long smb_GetNormalizedUsername(char * usern, const char * accountName, const char * domainName)
610 /* check if we have sane input */
611 if ((strlen(accountName) + strlen(domainName) + 1) > SMB_MAX_USERNAME_LENGTH)
614 /* we could get : [accountName][domainName]
620 atsign = strchr(accountName, '@');
622 if (atsign) /* [user@domain][] -> [user@domain][domain] */
627 /* if for some reason the client doesn't know what domain to use,
628 it will either return an empty string or a '?' */
629 if (!domain[0] || domain[0] == '?')
630 /* Empty domains and empty usernames are usually sent from tokenless contexts.
631 This way such logins will get an empty username (easy to check). I don't know
632 when a non-empty username would be supplied with an anonymous domain, but *shrug* */
633 strcpy(usern,accountName);
635 /* TODO: what about WIN.MIT.EDU\user vs. WIN\user? */
636 strcpy(usern,domain);
639 strncat(usern,accountName,atsign - accountName);
641 strcat(usern,accountName);
649 /* When using SMB auth, all SMB sessions have to pass through here
650 * first to authenticate the user.
652 * Caveat: If not using SMB auth, the protocol does not require
653 * sending a session setup packet, which means that we can't rely on a
654 * UID in subsequent packets. Though in practice we get one anyway.
656 long smb_ReceiveV3SessionSetupX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
660 unsigned short newUid;
661 unsigned long caps = 0;
665 char usern[SMB_MAX_USERNAME_LENGTH];
666 char *secBlobOut = NULL;
667 int secBlobOutLength = 0;
669 /* Check for bad conns */
670 if (vcp->flags & SMB_VCFLAG_REMOTECONN)
671 return CM_ERROR_REMOTECONN;
673 if (vcp->flags & SMB_VCFLAG_USENT) {
674 if (smb_authType == SMB_AUTH_EXTENDED) {
675 /* extended authentication */
679 OutputDebugF("NT Session Setup: Extended");
681 if (!(vcp->flags & SMB_VCFLAG_SESSX_RCVD)) {
682 caps = smb_GetSMBParm(inp,10) | (((unsigned long) smb_GetSMBParm(inp,11)) << 16);
685 secBlobInLength = smb_GetSMBParm(inp, 7);
686 secBlobIn = smb_GetSMBData(inp, NULL);
688 code = smb_AuthenticateUserExt(vcp, usern, secBlobIn, secBlobInLength, &secBlobOut, &secBlobOutLength);
690 if (code == CM_ERROR_GSSCONTINUE) {
691 smb_SetSMBParm(outp, 2, 0);
692 smb_SetSMBParm(outp, 3, secBlobOutLength);
693 smb_SetSMBDataLength(outp, secBlobOutLength + smb_ServerOSLength + smb_ServerLanManagerLength + smb_ServerDomainNameLength);
694 tp = smb_GetSMBData(outp, NULL);
695 if (secBlobOutLength) {
696 memcpy(tp, secBlobOut, secBlobOutLength);
698 tp += secBlobOutLength;
700 memcpy(tp,smb_ServerOS,smb_ServerOSLength);
701 tp += smb_ServerOSLength;
702 memcpy(tp,smb_ServerLanManager,smb_ServerLanManagerLength);
703 tp += smb_ServerLanManagerLength;
704 memcpy(tp,smb_ServerDomainName,smb_ServerDomainNameLength);
705 tp += smb_ServerDomainNameLength;
708 /* TODO: handle return code and continue auth. Also free secBlobOut if applicable. */
710 unsigned ciPwdLength, csPwdLength;
716 if (smb_authType == SMB_AUTH_NTLM)
717 OutputDebugF("NT Session Setup: NTLM");
719 OutputDebugF("NT Session Setup: None");
721 /* TODO: parse for extended auth as well */
722 ciPwdLength = smb_GetSMBParm(inp, 7); /* case insensitive password length */
723 csPwdLength = smb_GetSMBParm(inp, 8); /* case sensitive password length */
725 tp = smb_GetSMBData(inp, &datalen);
727 OutputDebugF("Session packet data size [%d]",datalen);
734 accountName = smb_ParseString(tp, &tp);
735 primaryDomain = smb_ParseString(tp, NULL);
737 OutputDebugF("Account Name: %s",accountName);
738 OutputDebugF("Primary Domain: %s", primaryDomain);
739 OutputDebugF("Case Sensitive Password: %s", csPwd && csPwd[0] ? "yes" : "no");
740 OutputDebugF("Case Insensitive Password: %s", ciPwd && ciPwd[0] ? "yes" : "no");
742 if (smb_GetNormalizedUsername(usern, accountName, primaryDomain)) {
743 /* shouldn't happen */
744 code = CM_ERROR_BADSMB;
745 goto after_read_packet;
748 /* capabilities are only valid for first session packet */
749 if (!(vcp->flags & SMB_VCFLAG_SESSX_RCVD)) {
750 caps = smb_GetSMBParm(inp, 11) | (((unsigned long)smb_GetSMBParm(inp, 12)) << 16);
753 if (smb_authType == SMB_AUTH_NTLM) {
754 code = smb_AuthenticateUserLM(vcp, accountName, primaryDomain, ciPwd, ciPwdLength, csPwd, csPwdLength);
756 OutputDebugF("LM authentication failed [%d]", code);
758 OutputDebugF("LM authentication succeeded");
762 unsigned ciPwdLength;
767 switch ( smb_authType ) {
768 case SMB_AUTH_EXTENDED:
769 OutputDebugF("V3 Session Setup: Extended");
772 OutputDebugF("V3 Session Setup: NTLM");
775 OutputDebugF("V3 Session Setup: None");
777 ciPwdLength = smb_GetSMBParm(inp, 7);
778 tp = smb_GetSMBData(inp, NULL);
782 accountName = smb_ParseString(tp, &tp);
783 primaryDomain = smb_ParseString(tp, NULL);
785 OutputDebugF("Account Name: %s",accountName);
786 OutputDebugF("Primary Domain: %s", primaryDomain);
787 OutputDebugF("Case Insensitive Password: %s", ciPwd && ciPwd[0] ? "yes" : "no");
789 if ( smb_GetNormalizedUsername(usern, accountName, primaryDomain)) {
790 /* shouldn't happen */
791 code = CM_ERROR_BADSMB;
792 goto after_read_packet;
795 /* even if we wanted extended auth, if we only negotiated V3, we have to fallback
798 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
799 code = smb_AuthenticateUserLM(vcp,accountName,primaryDomain,ciPwd,ciPwdLength,"",0);
801 OutputDebugF("LM authentication failed [%d]", code);
803 OutputDebugF("LM authentication succeeded");
808 /* note down that we received a session setup X and set the capabilities flag */
809 if (!(vcp->flags & SMB_VCFLAG_SESSX_RCVD)) {
810 lock_ObtainMutex(&vcp->mx);
811 vcp->flags |= SMB_VCFLAG_SESSX_RCVD;
812 /* for the moment we can only deal with NTSTATUS */
813 if (caps & NTNEGOTIATE_CAPABILITY_NTSTATUS) {
814 vcp->flags |= SMB_VCFLAG_STATUS32;
816 lock_ReleaseMutex(&vcp->mx);
819 /* code would be non-zero if there was an authentication failure.
820 Ideally we would like to invalidate the uid for this session or break
821 early to avoid accidently stealing someone else's tokens. */
827 OutputDebugF("Received username=[%s]", usern);
829 /* On Windows 2000, this function appears to be called more often than
830 it is expected to be called. This resulted in multiple smb_user_t
831 records existing all for the same user session which results in all
832 of the users tokens disappearing.
834 To avoid this problem, we look for an existing smb_user_t record
835 based on the users name, and use that one if we find it.
838 uidp = smb_FindUserByNameThisSession(vcp, usern);
839 if (uidp) { /* already there, so don't create a new one */
841 newUid = uidp->userID;
842 osi_Log3(smb_logp,"smb_ReceiveV3SessionSetupX FindUserByName:Lana[%d],lsn[%d],userid[%d]",
843 vcp->lana,vcp->lsn,newUid);
844 smb_ReleaseUID(uidp);
849 /* do a global search for the username/machine name pair */
850 unp = smb_FindUserByName(usern, vcp->rname, SMB_FLAG_CREATE);
851 lock_ObtainMutex(&unp->mx);
852 if (unp->flags & SMB_USERNAMEFLAG_AFSLOGON) {
853 /* clear the afslogon flag so that the tickets can now
854 * be freed when the refCount returns to zero.
856 unp->flags &= ~SMB_USERNAMEFLAG_AFSLOGON;
858 lock_ReleaseMutex(&unp->mx);
860 /* Create a new UID and cm_user_t structure */
863 userp = cm_NewUser();
864 cm_HoldUserVCRef(userp);
865 lock_ObtainMutex(&vcp->mx);
866 if (!vcp->uidCounter)
867 vcp->uidCounter++; /* handle unlikely wraparounds */
868 newUid = (strlen(usern)==0)?0:vcp->uidCounter++;
869 lock_ReleaseMutex(&vcp->mx);
871 /* Create a new smb_user_t structure and connect them up */
872 lock_ObtainMutex(&unp->mx);
874 lock_ReleaseMutex(&unp->mx);
876 uidp = smb_FindUID(vcp, newUid, SMB_FLAG_CREATE);
878 lock_ObtainMutex(&uidp->mx);
880 osi_Log4(smb_logp,"smb_ReceiveV3SessionSetupX MakeNewUser:VCP[%p],Lana[%d],lsn[%d],userid[%d]",vcp,vcp->lana,vcp->lsn,newUid);
881 lock_ReleaseMutex(&uidp->mx);
882 smb_ReleaseUID(uidp);
886 /* Return UID to the client */
887 ((smb_t *)outp)->uid = newUid;
888 /* Also to the next chained message */
889 ((smb_t *)inp)->uid = newUid;
891 osi_Log3(smb_logp, "SMB3 session setup name %s creating ID %d%s",
892 osi_LogSaveString(smb_logp, usern), newUid, osi_LogSaveString(smb_logp, s1));
894 smb_SetSMBParm(outp, 2, 0);
896 if (vcp->flags & SMB_VCFLAG_USENT) {
897 if (smb_authType == SMB_AUTH_EXTENDED) {
898 smb_SetSMBParm(outp, 3, secBlobOutLength);
899 smb_SetSMBDataLength(outp, secBlobOutLength + smb_ServerOSLength + smb_ServerLanManagerLength + smb_ServerDomainNameLength);
900 tp = smb_GetSMBData(outp, NULL);
901 if (secBlobOutLength) {
902 memcpy(tp, secBlobOut, secBlobOutLength);
904 tp += secBlobOutLength;
906 memcpy(tp,smb_ServerOS,smb_ServerOSLength);
907 tp += smb_ServerOSLength;
908 memcpy(tp,smb_ServerLanManager,smb_ServerLanManagerLength);
909 tp += smb_ServerLanManagerLength;
910 memcpy(tp,smb_ServerDomainName,smb_ServerDomainNameLength);
911 tp += smb_ServerDomainNameLength;
913 smb_SetSMBDataLength(outp, 0);
916 if (smb_authType == SMB_AUTH_EXTENDED) {
917 smb_SetSMBDataLength(outp, smb_ServerOSLength + smb_ServerLanManagerLength + smb_ServerDomainNameLength);
918 tp = smb_GetSMBData(outp, NULL);
919 memcpy(tp,smb_ServerOS,smb_ServerOSLength);
920 tp += smb_ServerOSLength;
921 memcpy(tp,smb_ServerLanManager,smb_ServerLanManagerLength);
922 tp += smb_ServerLanManagerLength;
923 memcpy(tp,smb_ServerDomainName,smb_ServerDomainNameLength);
924 tp += smb_ServerDomainNameLength;
926 smb_SetSMBDataLength(outp, 0);
933 long smb_ReceiveV3UserLogoffX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
937 /* find the tree and free it */
938 uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
940 smb_username_t * unp;
942 osi_Log2(smb_logp, "SMB3 user logoffX uid %d name %s", uidp->userID,
943 osi_LogSaveString(smb_logp, (uidp->unp) ? uidp->unp->name: " "));
945 lock_ObtainMutex(&uidp->mx);
946 uidp->flags |= SMB_USERFLAG_DELETE;
948 * it doesn't get deleted right away
949 * because the vcp points to it
952 lock_ReleaseMutex(&uidp->mx);
955 /* we can't do this. we get logoff messages prior to a session
956 * disconnect even though it doesn't mean the user is logging out.
957 * we need to create a new pioctl and EventLogoff handler to set
958 * SMB_USERNAMEFLAG_LOGOFF.
960 if (unp && smb_LogoffTokenTransfer) {
961 lock_ObtainMutex(&unp->mx);
962 unp->flags |= SMB_USERNAMEFLAG_LOGOFF;
963 unp->last_logoff_t = osi_Time() + smb_LogoffTransferTimeout;
964 lock_ReleaseMutex(&unp->mx);
968 smb_ReleaseUID(uidp);
971 osi_Log0(smb_logp, "SMB3 user logoffX");
973 smb_SetSMBDataLength(outp, 0);
977 #define SMB_SUPPORT_SEARCH_BITS 0x0001
978 #define SMB_SHARE_IS_IN_DFS 0x0002
980 long smb_ReceiveV3TreeConnectX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
983 smb_user_t *uidp = NULL;
984 unsigned short newTid;
992 cm_user_t *userp = NULL;
995 osi_Log0(smb_logp, "SMB3 receive tree connect");
997 /* parse input parameters */
998 tp = smb_GetSMBData(inp, NULL);
999 passwordp = smb_ParseString(tp, &tp);
1000 pathp = smb_ParseString(tp, &tp);
1001 if (smb_StoreAnsiFilenames)
1002 OemToChar(pathp,pathp);
1003 servicep = smb_ParseString(tp, &tp);
1005 tp = strrchr(pathp, '\\');
1007 return CM_ERROR_BADSMB;
1009 strcpy(shareName, tp+1);
1011 osi_Log2(smb_logp, "Tree connect pathp[%s] shareName[%s]",
1012 osi_LogSaveString(smb_logp, pathp),
1013 osi_LogSaveString(smb_logp, shareName));
1015 if (strcmp(servicep, "IPC") == 0 || strcmp(shareName, "IPC$") == 0) {
1017 osi_Log0(smb_logp, "TreeConnectX connecting to IPC$");
1020 return CM_ERROR_NOIPC;
1024 uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
1026 userp = smb_GetUserFromUID(uidp);
1028 lock_ObtainMutex(&vcp->mx);
1029 newTid = vcp->tidCounter++;
1030 lock_ReleaseMutex(&vcp->mx);
1032 tidp = smb_FindTID(vcp, newTid, SMB_FLAG_CREATE);
1035 if (!strcmp(shareName, "*."))
1036 strcpy(shareName, "all");
1037 shareFound = smb_FindShare(vcp, uidp, shareName, &sharePath);
1040 smb_ReleaseUID(uidp);
1041 smb_ReleaseTID(tidp);
1042 return CM_ERROR_BADSHARENAME;
1045 if (vcp->flags & SMB_VCFLAG_USENT)
1047 int policy = smb_FindShareCSCPolicy(shareName);
1048 smb_SetSMBParm(outp, 2, SMB_SUPPORT_SEARCH_BITS |
1050 SMB_SHARE_IS_IN_DFS |
1055 smb_SetSMBParm(outp, 2, 0);
1059 smb_ReleaseUID(uidp);
1061 lock_ObtainMutex(&tidp->mx);
1062 tidp->userp = userp;
1063 tidp->pathname = sharePath;
1065 tidp->flags |= SMB_TIDFLAG_IPC;
1066 lock_ReleaseMutex(&tidp->mx);
1067 smb_ReleaseTID(tidp);
1069 ((smb_t *)outp)->tid = newTid;
1070 ((smb_t *)inp)->tid = newTid;
1071 tp = smb_GetSMBData(outp, NULL);
1073 /* XXX - why is this a drive letter? */
1081 smb_SetSMBDataLength(outp, 7);
1084 smb_SetSMBDataLength(outp, 4);
1087 osi_Log1(smb_logp, "SMB3 tree connect created ID %d", newTid);
1091 /* must be called with global tran lock held */
1092 smb_tran2Packet_t *smb_FindTran2Packet(smb_vc_t *vcp, smb_packet_t *inp)
1094 smb_tran2Packet_t *tp;
1097 smbp = (smb_t *) inp->data;
1098 for (tp = smb_tran2AssemblyQueuep; tp; tp = (smb_tran2Packet_t *) osi_QNext(&tp->q)) {
1099 if (tp->vcp == vcp && tp->mid == smbp->mid && tp->tid == smbp->tid)
1105 smb_tran2Packet_t *smb_NewTran2Packet(smb_vc_t *vcp, smb_packet_t *inp,
1106 int totalParms, int totalData)
1108 smb_tran2Packet_t *tp;
1111 smbp = (smb_t *) inp->data;
1112 tp = malloc(sizeof(*tp));
1113 memset(tp, 0, sizeof(*tp));
1116 tp->curData = tp->curParms = 0;
1117 tp->totalData = totalData;
1118 tp->totalParms = totalParms;
1119 tp->tid = smbp->tid;
1120 tp->mid = smbp->mid;
1121 tp->uid = smbp->uid;
1122 tp->pid = smbp->pid;
1123 tp->res[0] = smbp->res[0];
1124 osi_QAdd((osi_queue_t **)&smb_tran2AssemblyQueuep, &tp->q);
1125 if (totalParms != 0)
1126 tp->parmsp = malloc(totalParms);
1128 tp->datap = malloc(totalData);
1129 if (smbp->com == 0x25 || smbp->com == 0x26)
1132 tp->opcode = smb_GetSMBParm(inp, 14);
1135 tp->flags |= SMB_TRAN2PFLAG_ALLOC;
1139 smb_tran2Packet_t *smb_GetTran2ResponsePacket(smb_vc_t *vcp,
1140 smb_tran2Packet_t *inp, smb_packet_t *outp,
1141 int totalParms, int totalData)
1143 smb_tran2Packet_t *tp;
1144 unsigned short parmOffset;
1145 unsigned short dataOffset;
1146 unsigned short dataAlign;
1148 tp = malloc(sizeof(*tp));
1149 memset(tp, 0, sizeof(*tp));
1152 tp->curData = tp->curParms = 0;
1153 tp->totalData = totalData;
1154 tp->totalParms = totalParms;
1155 tp->oldTotalParms = totalParms;
1160 tp->res[0] = inp->res[0];
1161 tp->opcode = inp->opcode;
1165 * We calculate where the parameters and data will start.
1166 * This calculation must parallel the calculation in
1167 * smb_SendTran2Packet.
1170 parmOffset = 10*2 + 35;
1171 parmOffset++; /* round to even */
1172 tp->parmsp = (unsigned short *) (outp->data + parmOffset);
1174 dataOffset = parmOffset + totalParms;
1175 dataAlign = dataOffset & 2; /* quad-align */
1176 dataOffset += dataAlign;
1177 tp->datap = outp->data + dataOffset;
1182 /* free a tran2 packet */
1183 void smb_FreeTran2Packet(smb_tran2Packet_t *t2p)
1186 smb_ReleaseVC(t2p->vcp);
1189 if (t2p->flags & SMB_TRAN2PFLAG_ALLOC) {
1198 /* called with a VC, an input packet to respond to, and an error code.
1199 * sends an error response.
1201 void smb_SendTran2Error(smb_vc_t *vcp, smb_tran2Packet_t *t2p,
1202 smb_packet_t *tp, long code)
1205 unsigned short errCode;
1206 unsigned char errClass;
1207 unsigned long NTStatus;
1209 if (vcp->flags & SMB_VCFLAG_STATUS32)
1210 smb_MapNTError(code, &NTStatus);
1212 smb_MapCoreError(code, vcp, &errCode, &errClass);
1214 smb_FormatResponsePacket(vcp, NULL, tp);
1215 smbp = (smb_t *) tp;
1217 /* We can handle long names */
1218 if (vcp->flags & SMB_VCFLAG_USENT)
1219 smbp->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
1221 /* now copy important fields from the tran 2 packet */
1222 smbp->com = t2p->com;
1223 smbp->tid = t2p->tid;
1224 smbp->mid = t2p->mid;
1225 smbp->pid = t2p->pid;
1226 smbp->uid = t2p->uid;
1227 smbp->res[0] = t2p->res[0];
1228 if (vcp->flags & SMB_VCFLAG_STATUS32) {
1229 smbp->rcls = (unsigned char) (NTStatus & 0xff);
1230 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
1231 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
1232 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
1233 smbp->flg2 |= SMB_FLAGS2_32BIT_STATUS;
1236 smbp->rcls = errClass;
1237 smbp->errLow = (unsigned char) (errCode & 0xff);
1238 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
1242 smb_SendPacket(vcp, tp);
1245 void smb_SendTran2Packet(smb_vc_t *vcp, smb_tran2Packet_t *t2p, smb_packet_t *tp)
1248 unsigned short parmOffset;
1249 unsigned short dataOffset;
1250 unsigned short totalLength;
1251 unsigned short dataAlign;
1254 smb_FormatResponsePacket(vcp, NULL, tp);
1255 smbp = (smb_t *) tp;
1257 /* We can handle long names */
1258 if (vcp->flags & SMB_VCFLAG_USENT)
1259 smbp->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
1261 /* now copy important fields from the tran 2 packet */
1262 smbp->com = t2p->com;
1263 smbp->tid = t2p->tid;
1264 smbp->mid = t2p->mid;
1265 smbp->pid = t2p->pid;
1266 smbp->uid = t2p->uid;
1267 smbp->res[0] = t2p->res[0];
1269 totalLength = 1 + t2p->totalData + t2p->totalParms;
1271 /* now add the core parameters (tran2 info) to the packet */
1272 smb_SetSMBParm(tp, 0, t2p->totalParms); /* parm bytes */
1273 smb_SetSMBParm(tp, 1, t2p->totalData); /* data bytes */
1274 smb_SetSMBParm(tp, 2, 0); /* reserved */
1275 smb_SetSMBParm(tp, 3, t2p->totalParms); /* parm bytes in this packet */
1276 parmOffset = 10*2 + 35; /* parm offset in packet */
1277 parmOffset++; /* round to even */
1278 smb_SetSMBParm(tp, 4, parmOffset); /* 11 parm words plus *
1279 * hdr, bcc and wct */
1280 smb_SetSMBParm(tp, 5, 0); /* parm displacement */
1281 smb_SetSMBParm(tp, 6, t2p->totalData); /* data in this packet */
1282 dataOffset = parmOffset + t2p->oldTotalParms;
1283 dataAlign = dataOffset & 2; /* quad-align */
1284 dataOffset += dataAlign;
1285 smb_SetSMBParm(tp, 7, dataOffset); /* offset of data */
1286 smb_SetSMBParm(tp, 8, 0); /* data displacement */
1287 smb_SetSMBParm(tp, 9, 0); /* low: setup word count *
1290 datap = smb_GetSMBData(tp, NULL);
1291 *datap++ = 0; /* we rounded to even */
1293 totalLength += dataAlign;
1294 smb_SetSMBDataLength(tp, totalLength);
1296 /* next, send the datagram */
1297 smb_SendPacket(vcp, tp);
1300 long smb_ReceiveV3Trans(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
1302 smb_tran2Packet_t *asp;
1315 /* We sometimes see 0 word count. What to do? */
1316 if (*inp->wctp == 0) {
1317 osi_Log0(smb_logp, "Transaction2 word count = 0");
1318 LogEvent(EVENTLOG_WARNING_TYPE, MSG_SMB_ZERO_TRANSACTION_COUNT);
1320 smb_SetSMBDataLength(outp, 0);
1321 smb_SendPacket(vcp, outp);
1325 totalParms = smb_GetSMBParm(inp, 0);
1326 totalData = smb_GetSMBParm(inp, 1);
1328 firstPacket = (inp->inCom == 0x25);
1330 /* find the packet we're reassembling */
1331 lock_ObtainWrite(&smb_globalLock);
1332 asp = smb_FindTran2Packet(vcp, inp);
1334 asp = smb_NewTran2Packet(vcp, inp, totalParms, totalData);
1336 lock_ReleaseWrite(&smb_globalLock);
1338 /* now merge in this latest packet; start by looking up offsets */
1340 parmDisp = dataDisp = 0;
1341 parmOffset = smb_GetSMBParm(inp, 10);
1342 dataOffset = smb_GetSMBParm(inp, 12);
1343 parmCount = smb_GetSMBParm(inp, 9);
1344 dataCount = smb_GetSMBParm(inp, 11);
1345 asp->maxReturnParms = smb_GetSMBParm(inp, 2);
1346 asp->maxReturnData = smb_GetSMBParm(inp, 3);
1348 osi_Log3(smb_logp, "SMB3 received Trans init packet total data %d, cur data %d, max return data %d",
1349 totalData, dataCount, asp->maxReturnData);
1352 parmDisp = smb_GetSMBParm(inp, 4);
1353 parmOffset = smb_GetSMBParm(inp, 3);
1354 dataDisp = smb_GetSMBParm(inp, 7);
1355 dataOffset = smb_GetSMBParm(inp, 6);
1356 parmCount = smb_GetSMBParm(inp, 2);
1357 dataCount = smb_GetSMBParm(inp, 5);
1359 osi_Log2(smb_logp, "SMB3 received Trans aux packet parms %d, data %d",
1360 parmCount, dataCount);
1363 /* now copy the parms and data */
1364 if ( asp->totalParms > 0 && parmCount != 0 )
1366 memcpy(((char *)asp->parmsp) + parmDisp, inp->data + parmOffset, parmCount);
1368 if ( asp->totalData > 0 && dataCount != 0 ) {
1369 memcpy(asp->datap + dataDisp, inp->data + dataOffset, dataCount);
1372 /* account for new bytes */
1373 asp->curData += dataCount;
1374 asp->curParms += parmCount;
1376 /* finally, if we're done, remove the packet from the queue and dispatch it */
1377 if (asp->totalParms > 0 &&
1378 asp->curParms > 0 &&
1379 asp->totalData <= asp->curData &&
1380 asp->totalParms <= asp->curParms) {
1381 /* we've received it all */
1382 lock_ObtainWrite(&smb_globalLock);
1383 osi_QRemove((osi_queue_t **) &smb_tran2AssemblyQueuep, &asp->q);
1384 lock_ReleaseWrite(&smb_globalLock);
1386 /* now dispatch it */
1387 rapOp = asp->parmsp[0];
1389 if ( rapOp >= 0 && rapOp < SMB_RAP_NOPCODES && smb_rapDispatchTable[rapOp].procp) {
1390 osi_Log4(smb_logp,"AFS Server - Dispatch-RAP %s vcp[%p] lana[%d] lsn[%d]",myCrt_RapDispatch(rapOp),vcp,vcp->lana,vcp->lsn);
1391 code = (*smb_rapDispatchTable[rapOp].procp)(vcp, asp, outp);
1392 osi_Log4(smb_logp,"AFS Server - Dispatch-RAP return code 0x%x vcp[%x] lana[%d] lsn[%d]",code,vcp,vcp->lana,vcp->lsn);
1395 osi_Log4(smb_logp,"AFS Server - Dispatch-RAP [INVALID] op[%x] vcp[%p] lana[%d] lsn[%d]", rapOp, vcp, vcp->lana, vcp->lsn);
1396 code = CM_ERROR_BADOP;
1399 /* if an error is returned, we're supposed to send an error packet,
1400 * otherwise the dispatched function already did the data sending.
1401 * We give dispatched proc the responsibility since it knows how much
1402 * space to allocate.
1405 smb_SendTran2Error(vcp, asp, outp, code);
1408 /* free the input tran 2 packet */
1409 smb_FreeTran2Packet(asp);
1411 else if (firstPacket) {
1412 /* the first packet in a multi-packet request, we need to send an
1413 * ack to get more data.
1415 smb_SetSMBDataLength(outp, 0);
1416 smb_SendPacket(vcp, outp);
1422 /* ANSI versions. The unicode versions support arbitrary length
1423 share names, but we don't support unicode yet. */
1425 typedef struct smb_rap_share_info_0 {
1426 char shi0_netname[13];
1427 } smb_rap_share_info_0_t;
1429 typedef struct smb_rap_share_info_1 {
1430 char shi1_netname[13];
1433 DWORD shi1_remark; /* char *shi1_remark; data offset */
1434 } smb_rap_share_info_1_t;
1436 typedef struct smb_rap_share_info_2 {
1437 char shi2_netname[13];
1439 unsigned short shi2_type;
1440 DWORD shi2_remark; /* char *shi2_remark; data offset */
1441 unsigned short shi2_permissions;
1442 unsigned short shi2_max_uses;
1443 unsigned short shi2_current_uses;
1444 DWORD shi2_path; /* char *shi2_path; data offset */
1445 unsigned short shi2_passwd[9];
1446 unsigned short shi2_pad2;
1447 } smb_rap_share_info_2_t;
1449 #define SMB_RAP_MAX_SHARES 512
1451 typedef struct smb_rap_share_list {
1454 smb_rap_share_info_0_t * shares;
1455 } smb_rap_share_list_t;
1457 int smb_rapCollectSharesProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp) {
1458 smb_rap_share_list_t * sp;
1463 if (name[0] == '.' && (!name[1] || (name[1] == '.' && !name[2])))
1464 return 0; /* skip over '.' and '..' */
1466 sp = (smb_rap_share_list_t *) vrockp;
1468 strncpy(sp->shares[sp->cShare].shi0_netname, name, 12);
1469 sp->shares[sp->cShare].shi0_netname[12] = 0;
1473 if (sp->cShare >= sp->maxShares)
1474 return CM_ERROR_STOPNOW;
1479 long smb_ReceiveRAPNetShareEnum(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1481 smb_tran2Packet_t *outp;
1482 unsigned short * tp;
1486 int outParmsTotal; /* total parameter bytes */
1487 int outDataTotal; /* total data bytes */
1490 DWORD allSubmount = 0;
1492 DWORD nRegShares = 0;
1493 DWORD nSharesRet = 0;
1495 HKEY hkSubmount = NULL;
1496 smb_rap_share_info_1_t * shares;
1499 char thisShare[256];
1503 smb_rap_share_list_t rootShares;
1508 tp = p->parmsp + 1; /* skip over function number (always 0) */
1509 (void) smb_ParseString((char *) tp, (char **) &tp); /* skip over parm descriptor */
1510 (void) smb_ParseString((char *) tp, (char **) &tp); /* skip over data descriptor */
1514 if (infoLevel != 1) {
1515 return CM_ERROR_INVAL;
1518 /* first figure out how many shares there are */
1519 rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY, 0,
1520 KEY_QUERY_VALUE, &hkParam);
1521 if (rv == ERROR_SUCCESS) {
1522 len = sizeof(allSubmount);
1523 rv = RegQueryValueEx(hkParam, "AllSubmount", NULL, NULL,
1524 (BYTE *) &allSubmount, &len);
1525 if (rv != ERROR_SUCCESS || allSubmount != 0) {
1528 RegCloseKey (hkParam);
1531 rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_OPENAFS_SUBKEY "\\Submounts",
1532 0, KEY_QUERY_VALUE, &hkSubmount);
1533 if (rv == ERROR_SUCCESS) {
1534 rv = RegQueryInfoKey(hkSubmount, NULL, NULL, NULL, NULL,
1535 NULL, NULL, &nRegShares, NULL, NULL, NULL, NULL);
1536 if (rv != ERROR_SUCCESS)
1542 /* fetch the root shares */
1543 rootShares.maxShares = SMB_RAP_MAX_SHARES;
1544 rootShares.cShare = 0;
1545 rootShares.shares = malloc( sizeof(smb_rap_share_info_0_t) * SMB_RAP_MAX_SHARES );
1549 userp = smb_GetTran2User(vcp,p);
1551 thyper.HighPart = 0;
1554 cm_HoldSCache(cm_data.rootSCachep);
1555 cm_ApplyDir(cm_data.rootSCachep, smb_rapCollectSharesProc, &rootShares, &thyper, userp, &req, NULL);
1556 cm_ReleaseSCache(cm_data.rootSCachep);
1558 cm_ReleaseUser(userp);
1560 nShares = (USHORT)(rootShares.cShare + nRegShares + allSubmount);
1562 #define REMARK_LEN 1
1563 outParmsTotal = 8; /* 4 dwords */
1564 outDataTotal = (sizeof(smb_rap_share_info_1_t) + REMARK_LEN) * nShares ;
1565 if(outDataTotal > bufsize) {
1566 nSharesRet = bufsize / (sizeof(smb_rap_share_info_1_t) + REMARK_LEN);
1567 outDataTotal = (sizeof(smb_rap_share_info_1_t) + REMARK_LEN) * nSharesRet;
1570 nSharesRet = nShares;
1573 outp = smb_GetTran2ResponsePacket(vcp, p, op, outParmsTotal, outDataTotal);
1575 /* now for the submounts */
1576 shares = (smb_rap_share_info_1_t *) outp->datap;
1577 cstrp = outp->datap + sizeof(smb_rap_share_info_1_t) * nSharesRet;
1579 memset(outp->datap, 0, (sizeof(smb_rap_share_info_1_t) + REMARK_LEN) * nSharesRet);
1582 strcpy( shares[cshare].shi1_netname, "all" );
1583 shares[cshare].shi1_remark = (DWORD)(cstrp - outp->datap);
1584 /* type and pad are zero already */
1590 for (dw=0; dw < nRegShares && cshare < nSharesRet; dw++) {
1591 len = sizeof(thisShare);
1592 rv = RegEnumValue(hkSubmount, dw, thisShare, &len, NULL, NULL, NULL, NULL);
1593 if (rv == ERROR_SUCCESS && strlen(thisShare) && (!allSubmount || stricmp(thisShare,"all"))) {
1594 strncpy(shares[cshare].shi1_netname, thisShare, sizeof(shares->shi1_netname)-1);
1595 shares[cshare].shi1_netname[sizeof(shares->shi1_netname)-1] = 0; /* unfortunate truncation */
1596 shares[cshare].shi1_remark = (DWORD)(cstrp - outp->datap);
1601 nShares--; /* uncount key */
1604 RegCloseKey(hkSubmount);
1607 nonrootShares = cshare;
1609 for (i=0; i < rootShares.cShare && cshare < nSharesRet; i++) {
1610 /* in case there are collisions with submounts, submounts have higher priority */
1611 for (j=0; j < nonrootShares; j++)
1612 if (!stricmp(shares[j].shi1_netname, rootShares.shares[i].shi0_netname))
1615 if (j < nonrootShares) {
1616 nShares--; /* uncount */
1620 strcpy(shares[cshare].shi1_netname, rootShares.shares[i].shi0_netname);
1621 shares[cshare].shi1_remark = (DWORD)(cstrp - outp->datap);
1626 outp->parmsp[0] = ((cshare == nShares)? ERROR_SUCCESS : ERROR_MORE_DATA);
1627 outp->parmsp[1] = 0;
1628 outp->parmsp[2] = cshare;
1629 outp->parmsp[3] = nShares;
1631 outp->totalData = (int)(cstrp - outp->datap);
1632 outp->totalParms = outParmsTotal;
1634 smb_SendTran2Packet(vcp, outp, op);
1635 smb_FreeTran2Packet(outp);
1637 free(rootShares.shares);
1642 long smb_ReceiveRAPNetShareGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1644 smb_tran2Packet_t *outp;
1645 unsigned short * tp;
1647 BOOL shareFound = FALSE;
1648 unsigned short infoLevel;
1649 unsigned short bufsize;
1659 tp = p->parmsp + 1; /* skip over function number (always 1) */
1660 (void) smb_ParseString( (char *) tp, (char **) &tp); /* skip over param descriptor */
1661 (void) smb_ParseString( (char *) tp, (char **) &tp); /* skip over data descriptor */
1662 shareName = smb_ParseString( (char *) tp, (char **) &tp);
1669 totalData = sizeof(smb_rap_share_info_0_t);
1670 else if(infoLevel == SMB_INFO_STANDARD)
1671 totalData = sizeof(smb_rap_share_info_1_t) + 1; /* + empty string */
1672 else if(infoLevel == SMB_INFO_QUERY_EA_SIZE)
1673 totalData = sizeof(smb_rap_share_info_2_t) + 2; /* + two empty strings */
1675 return CM_ERROR_INVAL;
1677 outp = smb_GetTran2ResponsePacket(vcp, p, op, totalParam, totalData);
1679 if(!stricmp(shareName,"all") || !strcmp(shareName,"*.")) {
1680 rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY, 0,
1681 KEY_QUERY_VALUE, &hkParam);
1682 if (rv == ERROR_SUCCESS) {
1683 len = sizeof(allSubmount);
1684 rv = RegQueryValueEx(hkParam, "AllSubmount", NULL, NULL,
1685 (BYTE *) &allSubmount, &len);
1686 if (rv != ERROR_SUCCESS || allSubmount != 0) {
1689 RegCloseKey (hkParam);
1696 rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY "\\Submounts", 0,
1697 KEY_QUERY_VALUE, &hkSubmount);
1698 if (rv == ERROR_SUCCESS) {
1699 rv = RegQueryValueEx(hkSubmount, shareName, NULL, NULL, NULL, NULL);
1700 if (rv == ERROR_SUCCESS) {
1703 RegCloseKey(hkSubmount);
1708 smb_FreeTran2Packet(outp);
1709 return CM_ERROR_BADSHARENAME;
1712 memset(outp->datap, 0, totalData);
1714 outp->parmsp[0] = 0;
1715 outp->parmsp[1] = 0;
1716 outp->parmsp[2] = totalData;
1718 if (infoLevel == 0) {
1719 smb_rap_share_info_0_t * info = (smb_rap_share_info_0_t *) outp->datap;
1720 strncpy(info->shi0_netname, shareName, sizeof(info->shi0_netname)-1);
1721 info->shi0_netname[sizeof(info->shi0_netname)-1] = 0;
1722 } else if(infoLevel == SMB_INFO_STANDARD) {
1723 smb_rap_share_info_1_t * info = (smb_rap_share_info_1_t *) outp->datap;
1724 strncpy(info->shi1_netname, shareName, sizeof(info->shi1_netname)-1);
1725 info->shi1_netname[sizeof(info->shi1_netname)-1] = 0;
1726 info->shi1_remark = (DWORD)(((unsigned char *) (info + 1)) - outp->datap);
1727 /* type and pad are already zero */
1728 } else { /* infoLevel==2 */
1729 smb_rap_share_info_2_t * info = (smb_rap_share_info_2_t *) outp->datap;
1730 strncpy(info->shi2_netname, shareName, sizeof(info->shi2_netname)-1);
1731 info->shi2_netname[sizeof(info->shi2_netname)-1] = 0;
1732 info->shi2_remark = (DWORD)(((unsigned char *) (info + 1)) - outp->datap);
1733 info->shi2_permissions = ACCESS_ALL;
1734 info->shi2_max_uses = (unsigned short) -1;
1735 info->shi2_path = (DWORD)(1 + (((unsigned char *) (info + 1)) - outp->datap));
1738 outp->totalData = totalData;
1739 outp->totalParms = totalParam;
1741 smb_SendTran2Packet(vcp, outp, op);
1742 smb_FreeTran2Packet(outp);
1747 typedef struct smb_rap_wksta_info_10 {
1748 DWORD wki10_computername; /*char *wki10_computername;*/
1749 DWORD wki10_username; /* char *wki10_username; */
1750 DWORD wki10_langroup; /* char *wki10_langroup;*/
1751 unsigned char wki10_ver_major;
1752 unsigned char wki10_ver_minor;
1753 DWORD wki10_logon_domain; /*char *wki10_logon_domain;*/
1754 DWORD wki10_oth_domains; /* char *wki10_oth_domains;*/
1755 } smb_rap_wksta_info_10_t;
1758 long smb_ReceiveRAPNetWkstaGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1760 smb_tran2Packet_t *outp;
1764 unsigned short * tp;
1767 smb_rap_wksta_info_10_t * info;
1771 tp = p->parmsp + 1; /* Skip over function number */
1772 (void) smb_ParseString((unsigned char*) tp, (char **) &tp); /* skip over param descriptor */
1773 (void) smb_ParseString((unsigned char*) tp, (char **) &tp); /* skip over data descriptor */
1777 if (infoLevel != 10) {
1778 return CM_ERROR_INVAL;
1784 totalData = sizeof(*info) + /* info */
1785 MAX_COMPUTERNAME_LENGTH + /* wki10_computername */
1786 SMB_MAX_USERNAME_LENGTH + /* wki10_username */
1787 MAX_COMPUTERNAME_LENGTH + /* wki10_langroup */
1788 MAX_COMPUTERNAME_LENGTH + /* wki10_logon_domain */
1789 1; /* wki10_oth_domains (null)*/
1791 outp = smb_GetTran2ResponsePacket(vcp, p, op, totalParams, totalData);
1793 memset(outp->parmsp,0,totalParams);
1794 memset(outp->datap,0,totalData);
1796 info = (smb_rap_wksta_info_10_t *) outp->datap;
1797 cstrp = (char *) (info + 1);
1799 info->wki10_computername = (DWORD) (cstrp - outp->datap);
1800 strcpy(cstrp, smb_localNamep);
1801 cstrp += strlen(cstrp) + 1;
1803 info->wki10_username = (DWORD) (cstrp - outp->datap);
1804 uidp = smb_FindUID(vcp, p->uid, 0);
1806 lock_ObtainMutex(&uidp->mx);
1807 if(uidp->unp && uidp->unp->name)
1808 strcpy(cstrp, uidp->unp->name);
1809 lock_ReleaseMutex(&uidp->mx);
1810 smb_ReleaseUID(uidp);
1812 cstrp += strlen(cstrp) + 1;
1814 info->wki10_langroup = (DWORD) (cstrp - outp->datap);
1815 strcpy(cstrp, "WORKGROUP");
1816 cstrp += strlen(cstrp) + 1;
1818 /* TODO: Not sure what values these should take, but these work */
1819 info->wki10_ver_major = 5;
1820 info->wki10_ver_minor = 1;
1822 info->wki10_logon_domain = (DWORD) (cstrp - outp->datap);
1823 strcpy(cstrp, smb_ServerDomainName);
1824 cstrp += strlen(cstrp) + 1;
1826 info->wki10_oth_domains = (DWORD) (cstrp - outp->datap);
1827 cstrp ++; /* no other domains */
1829 outp->totalData = (unsigned short) (cstrp - outp->datap); /* actual data size */
1830 outp->parmsp[2] = outp->totalData;
1831 outp->totalParms = totalParams;
1833 smb_SendTran2Packet(vcp,outp,op);
1834 smb_FreeTran2Packet(outp);
1839 typedef struct smb_rap_server_info_0 {
1841 } smb_rap_server_info_0_t;
1843 typedef struct smb_rap_server_info_1 {
1845 char sv1_version_major;
1846 char sv1_version_minor;
1847 unsigned long sv1_type;
1848 DWORD *sv1_comment_or_master_browser; /* char *sv1_comment_or_master_browser;*/
1849 } smb_rap_server_info_1_t;
1851 char smb_ServerComment[] = "OpenAFS Client";
1852 int smb_ServerCommentLen = sizeof(smb_ServerComment);
1854 #define SMB_SV_TYPE_SERVER 0x00000002L
1855 #define SMB_SV_TYPE_NT 0x00001000L
1856 #define SMB_SV_TYPE_SERVER_NT 0x00008000L
1858 long smb_ReceiveRAPNetServerGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1860 smb_tran2Packet_t *outp;
1864 unsigned short * tp;
1867 smb_rap_server_info_0_t * info0;
1868 smb_rap_server_info_1_t * info1;
1871 tp = p->parmsp + 1; /* Skip over function number */
1872 (void) smb_ParseString((unsigned char*) tp, (char **) &tp); /* skip over param descriptor */
1873 (void) smb_ParseString((unsigned char*) tp, (char **) &tp); /* skip over data descriptor */
1877 if (infoLevel != 0 && infoLevel != 1) {
1878 return CM_ERROR_INVAL;
1884 (infoLevel == 0) ? sizeof(smb_rap_server_info_0_t)
1885 : (sizeof(smb_rap_server_info_1_t) + smb_ServerCommentLen);
1887 outp = smb_GetTran2ResponsePacket(vcp, p, op, totalParams, totalData);
1889 memset(outp->parmsp,0,totalParams);
1890 memset(outp->datap,0,totalData);
1892 if (infoLevel == 0) {
1893 info0 = (smb_rap_server_info_0_t *) outp->datap;
1894 cstrp = (char *) (info0 + 1);
1895 strcpy(info0->sv0_name, "AFS");
1896 } else { /* infoLevel == SMB_INFO_STANDARD */
1897 info1 = (smb_rap_server_info_1_t *) outp->datap;
1898 cstrp = (char *) (info1 + 1);
1899 strcpy(info1->sv1_name, "AFS");
1902 SMB_SV_TYPE_SERVER |
1904 SMB_SV_TYPE_SERVER_NT;
1906 info1->sv1_version_major = 5;
1907 info1->sv1_version_minor = 1;
1908 info1->sv1_comment_or_master_browser = (DWORD *) (cstrp - outp->datap);
1910 strcpy(cstrp, smb_ServerComment);
1912 cstrp += smb_ServerCommentLen;
1915 totalData = (DWORD)(cstrp - outp->datap);
1916 outp->totalData = min(bufsize,totalData); /* actual data size */
1917 outp->parmsp[0] = (outp->totalData == totalData)? 0 : ERROR_MORE_DATA;
1918 outp->parmsp[2] = totalData;
1919 outp->totalParms = totalParams;
1921 smb_SendTran2Packet(vcp,outp,op);
1922 smb_FreeTran2Packet(outp);
1927 long smb_ReceiveV3Tran2A(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
1929 smb_tran2Packet_t *asp;
1941 /* We sometimes see 0 word count. What to do? */
1942 if (*inp->wctp == 0) {
1943 osi_Log0(smb_logp, "Transaction2 word count = 0");
1944 LogEvent(EVENTLOG_WARNING_TYPE, MSG_SMB_ZERO_TRANSACTION_COUNT);
1946 smb_SetSMBDataLength(outp, 0);
1947 smb_SendPacket(vcp, outp);
1951 totalParms = smb_GetSMBParm(inp, 0);
1952 totalData = smb_GetSMBParm(inp, 1);
1954 firstPacket = (inp->inCom == 0x32);
1956 /* find the packet we're reassembling */
1957 lock_ObtainWrite(&smb_globalLock);
1958 asp = smb_FindTran2Packet(vcp, inp);
1960 asp = smb_NewTran2Packet(vcp, inp, totalParms, totalData);
1962 lock_ReleaseWrite(&smb_globalLock);
1964 /* now merge in this latest packet; start by looking up offsets */
1966 parmDisp = dataDisp = 0;
1967 parmOffset = smb_GetSMBParm(inp, 10);
1968 dataOffset = smb_GetSMBParm(inp, 12);
1969 parmCount = smb_GetSMBParm(inp, 9);
1970 dataCount = smb_GetSMBParm(inp, 11);
1971 asp->maxReturnParms = smb_GetSMBParm(inp, 2);
1972 asp->maxReturnData = smb_GetSMBParm(inp, 3);
1974 osi_Log3(smb_logp, "SMB3 received T2 init packet total data %d, cur data %d, max return data %d",
1975 totalData, dataCount, asp->maxReturnData);
1978 parmDisp = smb_GetSMBParm(inp, 4);
1979 parmOffset = smb_GetSMBParm(inp, 3);
1980 dataDisp = smb_GetSMBParm(inp, 7);
1981 dataOffset = smb_GetSMBParm(inp, 6);
1982 parmCount = smb_GetSMBParm(inp, 2);
1983 dataCount = smb_GetSMBParm(inp, 5);
1985 osi_Log2(smb_logp, "SMB3 received T2 aux packet parms %d, data %d",
1986 parmCount, dataCount);
1989 /* now copy the parms and data */
1990 if ( asp->totalParms > 0 && parmCount != 0 )
1992 memcpy(((char *)asp->parmsp) + parmDisp, inp->data + parmOffset, parmCount);
1994 if ( asp->totalData > 0 && dataCount != 0 ) {
1995 memcpy(asp->datap + dataDisp, inp->data + dataOffset, dataCount);
1998 /* account for new bytes */
1999 asp->curData += dataCount;
2000 asp->curParms += parmCount;
2002 /* finally, if we're done, remove the packet from the queue and dispatch it */
2003 if (asp->totalParms > 0 &&
2004 asp->curParms > 0 &&
2005 asp->totalData <= asp->curData &&
2006 asp->totalParms <= asp->curParms) {
2007 /* we've received it all */
2008 lock_ObtainWrite(&smb_globalLock);
2009 osi_QRemove((osi_queue_t **) &smb_tran2AssemblyQueuep, &asp->q);
2010 lock_ReleaseWrite(&smb_globalLock);
2012 /* now dispatch it */
2013 if ( asp->opcode >= 0 && asp->opcode < 20 && smb_tran2DispatchTable[asp->opcode].procp) {
2014 osi_Log4(smb_logp,"AFS Server - Dispatch-2 %s vcp[%p] lana[%d] lsn[%d]",myCrt_2Dispatch(asp->opcode),vcp,vcp->lana,vcp->lsn);
2015 code = (*smb_tran2DispatchTable[asp->opcode].procp)(vcp, asp, outp);
2018 osi_Log4(smb_logp,"AFS Server - Dispatch-2 [INVALID] op[%x] vcp[%p] lana[%d] lsn[%d]", asp->opcode, vcp, vcp->lana, vcp->lsn);
2019 code = CM_ERROR_BADOP;
2022 /* if an error is returned, we're supposed to send an error packet,
2023 * otherwise the dispatched function already did the data sending.
2024 * We give dispatched proc the responsibility since it knows how much
2025 * space to allocate.
2028 smb_SendTran2Error(vcp, asp, outp, code);
2031 /* free the input tran 2 packet */
2032 smb_FreeTran2Packet(asp);
2034 else if (firstPacket) {
2035 /* the first packet in a multi-packet request, we need to send an
2036 * ack to get more data.
2038 smb_SetSMBDataLength(outp, 0);
2039 smb_SendPacket(vcp, outp);
2045 long smb_ReceiveTran2Open(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
2048 smb_tran2Packet_t *outp;
2053 cm_scache_t *dscp; /* dir we're dealing with */
2054 cm_scache_t *scp; /* file we're creating */
2056 int initialModeBits;
2066 int parmSlot; /* which parm we're dealing with */
2067 long returnEALength;
2076 extraInfo = (p->parmsp[0] & 1); /* return extra info */
2077 returnEALength = (p->parmsp[0] & 8); /* return extended attr length */
2079 openFun = p->parmsp[6]; /* open function */
2080 excl = ((openFun & 3) == 0);
2081 trunc = ((openFun & 3) == 2); /* truncate it */
2082 openMode = (p->parmsp[1] & 0x7);
2083 openAction = 0; /* tracks what we did */
2085 attributes = p->parmsp[3];
2086 dosTime = p->parmsp[4] | (p->parmsp[5] << 16);
2088 /* compute initial mode bits based on read-only flag in attributes */
2089 initialModeBits = 0666;
2090 if (attributes & SMB_ATTR_READONLY)
2091 initialModeBits &= ~0222;
2093 pathp = (char *) (&p->parmsp[14]);
2094 if (smb_StoreAnsiFilenames)
2095 OemToChar(pathp,pathp);
2097 outp = smb_GetTran2ResponsePacket(vcp, p, op, 40, 0);
2099 spacep = cm_GetSpace();
2100 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
2102 if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
2103 /* special case magic file name for receiving IOCTL requests
2104 * (since IOCTL calls themselves aren't getting through).
2106 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
2107 smb_SetupIoctlFid(fidp, spacep);
2109 /* copy out remainder of the parms */
2111 outp->parmsp[parmSlot++] = fidp->fid;
2113 outp->parmsp[parmSlot++] = 0; /* attrs */
2114 outp->parmsp[parmSlot++] = 0; /* mod time */
2115 outp->parmsp[parmSlot++] = 0;
2116 outp->parmsp[parmSlot++] = 0; /* len */
2117 outp->parmsp[parmSlot++] = 0x7fff;
2118 outp->parmsp[parmSlot++] = openMode;
2119 outp->parmsp[parmSlot++] = 0; /* file type 0 ==> normal file or dir */
2120 outp->parmsp[parmSlot++] = 0; /* IPC junk */
2122 /* and the final "always present" stuff */
2123 outp->parmsp[parmSlot++] = 1; /* openAction found existing file */
2124 /* next write out the "unique" ID */
2125 outp->parmsp[parmSlot++] = 0x1234;
2126 outp->parmsp[parmSlot++] = 0x5678;
2127 outp->parmsp[parmSlot++] = 0;
2128 if (returnEALength) {
2129 outp->parmsp[parmSlot++] = 0;
2130 outp->parmsp[parmSlot++] = 0;
2133 outp->totalData = 0;
2134 outp->totalParms = parmSlot * 2;
2136 smb_SendTran2Packet(vcp, outp, op);
2138 smb_FreeTran2Packet(outp);
2140 /* and clean up fid reference */
2141 smb_ReleaseFID(fidp);
2145 #ifdef DEBUG_VERBOSE
2147 char *hexp, *asciip;
2148 asciip = (lastNamep ? lastNamep : pathp);
2149 hexp = osi_HexifyString( asciip );
2150 DEBUG_EVENT2("AFS","T2Open H[%s] A[%s]", hexp, asciip);
2155 userp = smb_GetTran2User(vcp, p);
2156 /* In the off chance that userp is NULL, we log and abandon */
2158 osi_Log1(smb_logp, "ReceiveTran2Open user [%d] not resolvable", p->uid);
2159 smb_FreeTran2Packet(outp);
2160 return CM_ERROR_BADSMB;
2163 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
2164 if (code == CM_ERROR_TIDIPC) {
2165 /* Attempt to use a TID allocated for IPC. The client
2166 * is probably looking for DCE RPC end points which we
2167 * don't support OR it could be looking to make a DFS
2170 osi_Log0(smb_logp, "Tran2Open received IPC TID");
2172 cm_ReleaseUser(userp);
2173 smb_FreeTran2Packet(outp);
2174 return CM_ERROR_NOSUCHPATH;
2179 code = cm_NameI(cm_data.rootSCachep, pathp,
2180 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
2181 userp, tidPathp, &req, &scp);
2183 code = cm_NameI(cm_data.rootSCachep, spacep->data,
2184 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
2185 userp, tidPathp, &req, &dscp);
2186 cm_FreeSpace(spacep);
2189 cm_ReleaseUser(userp);
2190 smb_FreeTran2Packet(outp);
2195 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
2196 cm_ReleaseSCache(dscp);
2197 cm_ReleaseUser(userp);
2198 smb_FreeTran2Packet(outp);
2199 if ( WANTS_DFS_PATHNAMES(p) )
2200 return CM_ERROR_PATH_NOT_COVERED;
2202 return CM_ERROR_BADSHARENAME;
2204 #endif /* DFS_SUPPORT */
2206 /* otherwise, scp points to the parent directory. Do a lookup,
2207 * and truncate the file if we find it, otherwise we create the
2214 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD, userp,
2216 if (code && code != CM_ERROR_NOSUCHFILE) {
2217 cm_ReleaseSCache(dscp);
2218 cm_ReleaseUser(userp);
2219 smb_FreeTran2Packet(outp);
2224 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
2225 cm_ReleaseSCache(scp);
2226 cm_ReleaseUser(userp);
2227 smb_FreeTran2Packet(outp);
2228 if ( WANTS_DFS_PATHNAMES(p) )
2229 return CM_ERROR_PATH_NOT_COVERED;
2231 return CM_ERROR_BADSHARENAME;
2233 #endif /* DFS_SUPPORT */
2235 /* macintosh is expensive to program for it */
2236 cm_FreeSpace(spacep);
2239 /* if we get here, if code is 0, the file exists and is represented by
2240 * scp. Otherwise, we have to create it.
2243 code = cm_CheckOpen(scp, openMode, trunc, userp, &req);
2246 cm_ReleaseSCache(dscp);
2247 cm_ReleaseSCache(scp);
2248 cm_ReleaseUser(userp);
2249 smb_FreeTran2Packet(outp);
2254 /* oops, file shouldn't be there */
2256 cm_ReleaseSCache(dscp);
2257 cm_ReleaseSCache(scp);
2258 cm_ReleaseUser(userp);
2259 smb_FreeTran2Packet(outp);
2260 return CM_ERROR_EXISTS;
2264 setAttr.mask = CM_ATTRMASK_LENGTH;
2265 setAttr.length.LowPart = 0;
2266 setAttr.length.HighPart = 0;
2267 code = cm_SetAttr(scp, &setAttr, userp, &req);
2268 openAction = 3; /* truncated existing file */
2271 openAction = 1; /* found existing file */
2273 else if (!(openFun & 0x10)) {
2274 /* don't create if not found */
2276 cm_ReleaseSCache(dscp);
2277 osi_assert(scp == NULL);
2278 cm_ReleaseUser(userp);
2279 smb_FreeTran2Packet(outp);
2280 return CM_ERROR_NOSUCHFILE;
2283 osi_assert(dscp != NULL && scp == NULL);
2284 openAction = 2; /* created file */
2285 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
2286 smb_UnixTimeFromSearchTime(&setAttr.clientModTime, dosTime);
2287 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
2291 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
2292 smb_NotifyChange(FILE_ACTION_ADDED,
2293 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
2294 dscp, lastNamep, NULL, TRUE);
2295 } else if (!excl && code == CM_ERROR_EXISTS) {
2296 /* not an exclusive create, and someone else tried
2297 * creating it already, then we open it anyway. We
2298 * don't bother retrying after this, since if this next
2299 * fails, that means that the file was deleted after we
2300 * started this call.
2302 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
2306 setAttr.mask = CM_ATTRMASK_LENGTH;
2307 setAttr.length.LowPart = 0;
2308 setAttr.length.HighPart = 0;
2309 code = cm_SetAttr(scp, &setAttr, userp,
2312 } /* lookup succeeded */
2316 /* we don't need this any longer */
2318 cm_ReleaseSCache(dscp);
2321 /* something went wrong creating or truncating the file */
2323 cm_ReleaseSCache(scp);
2324 cm_ReleaseUser(userp);
2325 smb_FreeTran2Packet(outp);
2329 /* make sure we're about to open a file */
2330 if (scp->fileType != CM_SCACHETYPE_FILE) {
2332 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
2333 cm_scache_t * targetScp = 0;
2334 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
2336 /* we have a more accurate file to use (the
2337 * target of the symbolic link). Otherwise,
2338 * we'll just use the symlink anyway.
2340 osi_Log2(smb_logp, "symlink vp %x to vp %x",
2342 cm_ReleaseSCache(scp);
2346 if (scp->fileType != CM_SCACHETYPE_FILE) {
2347 cm_ReleaseSCache(scp);
2348 cm_ReleaseUser(userp);
2349 smb_FreeTran2Packet(outp);
2350 return CM_ERROR_ISDIR;
2354 /* now all we have to do is open the file itself */
2355 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
2359 lock_ObtainMutex(&fidp->mx);
2360 /* save a pointer to the vnode */
2361 osi_Log2(smb_logp,"smb_ReceiveTran2Open fidp 0x%p scp 0x%p", fidp, scp);
2363 lock_ObtainMutex(&scp->mx);
2364 scp->flags |= CM_SCACHEFLAG_SMB_FID;
2365 lock_ReleaseMutex(&scp->mx);
2368 fidp->userp = userp;
2370 /* compute open mode */
2372 fidp->flags |= SMB_FID_OPENREAD_LISTDIR;
2373 if (openMode == 1 || openMode == 2)
2374 fidp->flags |= SMB_FID_OPENWRITE;
2376 /* remember that the file was newly created */
2378 fidp->flags |= SMB_FID_CREATED;
2380 lock_ReleaseMutex(&fidp->mx);
2382 smb_ReleaseFID(fidp);
2384 cm_Open(scp, 0, userp);
2386 /* copy out remainder of the parms */
2388 outp->parmsp[parmSlot++] = fidp->fid;
2389 lock_ObtainMutex(&scp->mx);
2391 outp->parmsp[parmSlot++] = smb_Attributes(scp);
2392 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
2393 outp->parmsp[parmSlot++] = (unsigned short)(dosTime & 0xffff);
2394 outp->parmsp[parmSlot++] = (unsigned short)((dosTime>>16) & 0xffff);
2395 outp->parmsp[parmSlot++] = (unsigned short) (scp->length.LowPart & 0xffff);
2396 outp->parmsp[parmSlot++] = (unsigned short) ((scp->length.LowPart >> 16) & 0xffff);
2397 outp->parmsp[parmSlot++] = openMode;
2398 outp->parmsp[parmSlot++] = 0; /* file type 0 ==> normal file or dir */
2399 outp->parmsp[parmSlot++] = 0; /* IPC junk */
2401 /* and the final "always present" stuff */
2402 outp->parmsp[parmSlot++] = openAction;
2403 /* next write out the "unique" ID */
2404 outp->parmsp[parmSlot++] = (unsigned short) (scp->fid.vnode & 0xffff);
2405 outp->parmsp[parmSlot++] = (unsigned short) (scp->fid.volume & 0xffff);
2406 outp->parmsp[parmSlot++] = 0;
2407 if (returnEALength) {
2408 outp->parmsp[parmSlot++] = 0;
2409 outp->parmsp[parmSlot++] = 0;
2411 lock_ReleaseMutex(&scp->mx);
2412 outp->totalData = 0; /* total # of data bytes */
2413 outp->totalParms = parmSlot * 2; /* shorts are two bytes */
2415 smb_SendTran2Packet(vcp, outp, op);
2417 smb_FreeTran2Packet(outp);
2419 cm_ReleaseUser(userp);
2420 /* leave scp held since we put it in fidp->scp */
2424 long smb_ReceiveTran2QFSInfoFid(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
2427 unsigned short infolevel;
2429 infolevel = p->parmsp[0];
2431 osi_Log2(smb_logp, "T2 QFSInfoFid InfoLevel 0x%x fid 0x%x - NOT_SUPPORTED", infolevel, fid);
2433 return CM_ERROR_BAD_LEVEL;
2436 long smb_ReceiveTran2QFSInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
2438 smb_tran2Packet_t *outp;
2439 smb_tran2QFSInfo_t qi;
2441 static char FSname[8] = {'A', 0, 'F', 0, 'S', 0, 0, 0};
2443 osi_Log1(smb_logp, "T2 QFSInfo type 0x%x", p->parmsp[0]);
2445 switch (p->parmsp[0]) {
2446 case SMB_INFO_ALLOCATION:
2447 responseSize = sizeof(qi.u.allocInfo);
2449 case SMB_INFO_VOLUME:
2450 responseSize = sizeof(qi.u.volumeInfo);
2452 case SMB_QUERY_FS_VOLUME_INFO:
2453 responseSize = sizeof(qi.u.FSvolumeInfo);
2455 case SMB_QUERY_FS_SIZE_INFO:
2456 responseSize = sizeof(qi.u.FSsizeInfo);
2458 case SMB_QUERY_FS_DEVICE_INFO:
2459 responseSize = sizeof(qi.u.FSdeviceInfo);
2461 case SMB_QUERY_FS_ATTRIBUTE_INFO:
2462 responseSize = sizeof(qi.u.FSattributeInfo);
2464 case SMB_INFO_UNIX: /* CIFS Unix Info */
2465 case SMB_INFO_MACOS: /* Mac FS Info */
2467 return CM_ERROR_BADOP;
2470 outp = smb_GetTran2ResponsePacket(vcp, p, op, 0, responseSize);
2471 switch (p->parmsp[0]) {
2472 case SMB_INFO_ALLOCATION:
2474 qi.u.allocInfo.FSID = 0;
2475 qi.u.allocInfo.sectorsPerAllocUnit = 1;
2476 qi.u.allocInfo.totalAllocUnits = 0x7fffffff;
2477 qi.u.allocInfo.availAllocUnits = 0x3fffffff;
2478 qi.u.allocInfo.bytesPerSector = 1024;
2481 case SMB_INFO_VOLUME:
2483 qi.u.volumeInfo.vsn = 1234;
2484 qi.u.volumeInfo.vnCount = 4;
2485 /* we're supposed to pad it out with zeroes to the end */
2486 memset(&qi.u.volumeInfo.label, 0, sizeof(qi.u.volumeInfo.label));
2487 memcpy(qi.u.volumeInfo.label, "AFS", 4);
2490 case SMB_QUERY_FS_VOLUME_INFO:
2491 /* FS volume info */
2492 memset((char *)&qi.u.FSvolumeInfo.vct, 0, 4);
2493 qi.u.FSvolumeInfo.vsn = 1234;
2494 qi.u.FSvolumeInfo.vnCount = 8;
2495 memcpy(qi.u.FSvolumeInfo.label, "A\0F\0S\0\0\0", 8);
2498 case SMB_QUERY_FS_SIZE_INFO:
2500 qi.u.FSsizeInfo.totalAllocUnits.HighPart = 0;
2501 qi.u.FSsizeInfo.totalAllocUnits.LowPart= 0x7fffffff;
2502 qi.u.FSsizeInfo.availAllocUnits.HighPart = 0;
2503 qi.u.FSsizeInfo.availAllocUnits.LowPart= 0x3fffffff;
2504 qi.u.FSsizeInfo.sectorsPerAllocUnit = 1;
2505 qi.u.FSsizeInfo.bytesPerSector = 1024;
2508 case SMB_QUERY_FS_DEVICE_INFO:
2509 /* FS device info */
2510 qi.u.FSdeviceInfo.devType = 0x14; /* network file system */
2511 qi.u.FSdeviceInfo.characteristics = 0x50; /* remote, virtual */
2514 case SMB_QUERY_FS_ATTRIBUTE_INFO:
2515 /* FS attribute info */
2516 /* attributes, defined in WINNT.H:
2517 * FILE_CASE_SENSITIVE_SEARCH 0x1
2518 * FILE_CASE_PRESERVED_NAMES 0x2
2519 * FILE_VOLUME_QUOTAS 0x10
2520 * <no name defined> 0x4000
2521 * If bit 0x4000 is not set, Windows 95 thinks
2522 * we can't handle long (non-8.3) names,
2523 * despite our protestations to the contrary.
2525 qi.u.FSattributeInfo.attributes = 0x4003;
2526 qi.u.FSattributeInfo.maxCompLength = MAX_PATH;
2527 qi.u.FSattributeInfo.FSnameLength = sizeof(FSname);
2528 memcpy(qi.u.FSattributeInfo.FSname, FSname, sizeof(FSname));
2532 /* copy out return data, and set corresponding sizes */
2533 outp->totalParms = 0;
2534 outp->totalData = responseSize;
2535 memcpy(outp->datap, &qi, responseSize);
2537 /* send and free the packets */
2538 smb_SendTran2Packet(vcp, outp, op);
2539 smb_FreeTran2Packet(outp);
2544 long smb_ReceiveTran2SetFSInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
2546 osi_Log0(smb_logp,"ReceiveTran2SetFSInfo - NOT_SUPPORTED");
2547 return CM_ERROR_BADOP;
2550 struct smb_ShortNameRock {
2554 size_t shortNameLen;
2557 int cm_GetShortNameProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *vrockp,
2560 struct smb_ShortNameRock *rockp;
2564 /* compare both names and vnodes, though probably just comparing vnodes
2565 * would be safe enough.
2567 if (cm_stricmp(dep->name, rockp->maskp) != 0)
2569 if (ntohl(dep->fid.vnode) != rockp->vnode)
2571 /* This is the entry */
2572 cm_Gen8Dot3Name(dep, rockp->shortName, &shortNameEnd);
2573 rockp->shortNameLen = shortNameEnd - rockp->shortName;
2574 return CM_ERROR_STOPNOW;
2577 long cm_GetShortName(char *pathp, cm_user_t *userp, cm_req_t *reqp,
2578 char *tidPathp, int vnode, char *shortName, size_t *shortNameLenp)
2580 struct smb_ShortNameRock rock;
2584 int caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
2588 spacep = cm_GetSpace();
2589 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
2591 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold, userp, tidPathp,
2593 cm_FreeSpace(spacep);
2598 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
2599 cm_ReleaseSCache(dscp);
2600 cm_ReleaseUser(userp);
2601 return CM_ERROR_PATH_NOT_COVERED;
2603 #endif /* DFS_SUPPORT */
2605 if (!lastNamep) lastNamep = pathp;
2608 thyper.HighPart = 0;
2609 rock.shortName = shortName;
2611 rock.maskp = lastNamep;
2612 code = cm_ApplyDir(dscp, cm_GetShortNameProc, &rock, &thyper, userp, reqp, NULL);
2614 cm_ReleaseSCache(dscp);
2617 return CM_ERROR_NOSUCHFILE;
2618 if (code == CM_ERROR_STOPNOW) {
2619 *shortNameLenp = rock.shortNameLen;
2625 long smb_ReceiveTran2QPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
2627 smb_tran2Packet_t *outp;
2630 unsigned short infoLevel;
2631 smb_tran2QPathInfo_t qpi;
2633 unsigned short attributes;
2634 unsigned long extAttributes;
2639 cm_scache_t *scp, *dscp;
2640 int scp_mx_held = 0;
2650 infoLevel = p->parmsp[0];
2651 if (infoLevel == SMB_INFO_IS_NAME_VALID)
2653 else if (infoLevel == SMB_INFO_STANDARD)
2654 responseSize = sizeof(qpi.u.QPstandardInfo);
2655 else if (infoLevel == SMB_INFO_QUERY_EA_SIZE)
2656 responseSize = sizeof(qpi.u.QPeaSizeInfo);
2657 else if (infoLevel == SMB_QUERY_FILE_BASIC_INFO)
2658 responseSize = sizeof(qpi.u.QPfileBasicInfo);
2659 else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO)
2660 responseSize = sizeof(qpi.u.QPfileStandardInfo);
2661 else if (infoLevel == SMB_QUERY_FILE_EA_INFO)
2662 responseSize = sizeof(qpi.u.QPfileEaInfo);
2663 else if (infoLevel == SMB_QUERY_FILE_NAME_INFO)
2664 responseSize = sizeof(qpi.u.QPfileNameInfo);
2665 else if (infoLevel == SMB_QUERY_FILE_ALL_INFO)
2666 responseSize = sizeof(qpi.u.QPfileAllInfo);
2667 else if (infoLevel == SMB_QUERY_FILE_ALT_NAME_INFO)
2668 responseSize = sizeof(qpi.u.QPfileAltNameInfo);
2670 osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
2671 p->opcode, infoLevel);
2672 smb_SendTran2Error(vcp, p, opx, CM_ERROR_BAD_LEVEL);
2676 pathp = (char *)(&p->parmsp[3]);
2677 if (smb_StoreAnsiFilenames)
2678 OemToChar(pathp,pathp);
2679 osi_Log2(smb_logp, "T2 QPathInfo type 0x%x path %s", infoLevel,
2680 osi_LogSaveString(smb_logp, pathp));
2682 outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, responseSize);
2684 if (infoLevel > 0x100)
2685 outp->totalParms = 2;
2687 outp->totalParms = 0;
2688 outp->totalData = responseSize;
2690 /* now, if we're at infoLevel 6, we're only being asked to check
2691 * the syntax, so we just OK things now. In particular, we're *not*
2692 * being asked to verify anything about the state of any parent dirs.
2694 if (infoLevel == SMB_INFO_IS_NAME_VALID) {
2695 smb_SendTran2Packet(vcp, outp, opx);
2696 smb_FreeTran2Packet(outp);
2700 userp = smb_GetTran2User(vcp, p);
2702 osi_Log1(smb_logp, "ReceiveTran2QPathInfo unable to resolve user [%d]", p->uid);
2703 smb_FreeTran2Packet(outp);
2704 return CM_ERROR_BADSMB;
2707 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
2709 cm_ReleaseUser(userp);
2710 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOSUCHPATH);
2711 smb_FreeTran2Packet(outp);
2716 * XXX Strange hack XXX
2718 * As of Patch 7 (13 January 98), we are having the following problem:
2719 * In NT Explorer 4.0, whenever we click on a directory, AFS gets
2720 * requests to look up "desktop.ini" in all the subdirectories.
2721 * This can cause zillions of timeouts looking up non-existent cells
2722 * and volumes, especially in the top-level directory.
2724 * We have not found any way to avoid this or work around it except
2725 * to explicitly ignore the requests for mount points that haven't
2726 * yet been evaluated and for directories that haven't yet been
2729 if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
2730 spacep = cm_GetSpace();
2731 smb_StripLastComponent(spacep->data, &lastComp, pathp);
2732 #ifndef SPECIAL_FOLDERS
2733 /* Make sure that lastComp is not NULL */
2735 if (stricmp(lastComp, "\\desktop.ini") == 0) {
2736 code = cm_NameI(cm_data.rootSCachep, spacep->data,
2740 userp, tidPathp, &req, &dscp);
2743 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
2744 if ( WANTS_DFS_PATHNAMES(p) )
2745 code = CM_ERROR_PATH_NOT_COVERED;
2747 code = CM_ERROR_BADSHARENAME;
2749 #endif /* DFS_SUPPORT */
2750 if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT && !dscp->mountRootFid.volume)
2751 code = CM_ERROR_NOSUCHFILE;
2752 else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
2753 cm_buf_t *bp = buf_Find(dscp, &hzero);
2757 code = CM_ERROR_NOSUCHFILE;
2759 cm_ReleaseSCache(dscp);
2761 cm_FreeSpace(spacep);
2762 cm_ReleaseUser(userp);
2763 smb_SendTran2Error(vcp, p, opx, code);
2764 smb_FreeTran2Packet(outp);
2770 #endif /* SPECIAL_FOLDERS */
2772 cm_FreeSpace(spacep);
2775 /* now do namei and stat, and copy out the info */
2776 code = cm_NameI(cm_data.rootSCachep, pathp,
2777 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, tidPathp, &req, &scp);
2780 cm_ReleaseUser(userp);
2781 smb_SendTran2Error(vcp, p, opx, code);
2782 smb_FreeTran2Packet(outp);
2787 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
2788 cm_ReleaseSCache(scp);
2789 cm_ReleaseUser(userp);
2790 if ( WANTS_DFS_PATHNAMES(p) )
2791 code = CM_ERROR_PATH_NOT_COVERED;
2793 code = CM_ERROR_BADSHARENAME;
2794 smb_SendTran2Error(vcp, p, opx, code);
2795 smb_FreeTran2Packet(outp);
2798 #endif /* DFS_SUPPORT */
2800 lock_ObtainMutex(&scp->mx);
2802 code = cm_SyncOp(scp, NULL, userp, &req, 0,
2803 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
2804 if (code) goto done;
2806 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
2808 /* now we have the status in the cache entry, and everything is locked.
2809 * Marshall the output data.
2811 /* for info level 108, figure out short name */
2812 if (infoLevel == SMB_QUERY_FILE_ALT_NAME_INFO) {
2813 code = cm_GetShortName(pathp, userp, &req,
2814 tidPathp, scp->fid.vnode, shortName,
2820 qpi.u.QPfileAltNameInfo.fileNameLength = (len + 1) * 2;
2821 mbstowcs((unsigned short *)qpi.u.QPfileAltNameInfo.fileName, shortName, len + 1);
2825 else if (infoLevel == SMB_QUERY_FILE_NAME_INFO) {
2826 len = strlen(lastComp);
2827 qpi.u.QPfileNameInfo.fileNameLength = (len + 1) * 2;
2828 mbstowcs((unsigned short *)qpi.u.QPfileNameInfo.fileName, lastComp, len + 1);
2832 else if (infoLevel == SMB_INFO_STANDARD || infoLevel == SMB_INFO_QUERY_EA_SIZE) {
2833 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
2834 qpi.u.QPstandardInfo.creationDateTime = dosTime;
2835 qpi.u.QPstandardInfo.lastAccessDateTime = dosTime;
2836 qpi.u.QPstandardInfo.lastWriteDateTime = dosTime;
2837 qpi.u.QPstandardInfo.dataSize = scp->length.LowPart;
2838 qpi.u.QPstandardInfo.allocationSize = scp->length.LowPart;
2839 attributes = smb_Attributes(scp);
2840 qpi.u.QPstandardInfo.attributes = attributes;
2841 qpi.u.QPstandardInfo.eaSize = 0;
2843 else if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
2844 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
2845 qpi.u.QPfileBasicInfo.creationTime = ft;
2846 qpi.u.QPfileBasicInfo.lastAccessTime = ft;
2847 qpi.u.QPfileBasicInfo.lastWriteTime = ft;
2848 qpi.u.QPfileBasicInfo.changeTime = ft;
2849 extAttributes = smb_ExtAttributes(scp);
2850 qpi.u.QPfileBasicInfo.attributes = extAttributes;
2851 qpi.u.QPfileBasicInfo.reserved = 0;
2853 else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO) {
2854 smb_fid_t *fidp = smb_FindFIDByScache(vcp, scp);
2856 qpi.u.QPfileStandardInfo.allocationSize = scp->length;
2857 qpi.u.QPfileStandardInfo.endOfFile = scp->length;
2858 qpi.u.QPfileStandardInfo.numberOfLinks = scp->linkCount;
2859 qpi.u.QPfileStandardInfo.directory =
2860 ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
2861 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
2862 scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0);
2863 qpi.u.QPfileStandardInfo.reserved = 0;
2866 lock_ReleaseMutex(&scp->mx);
2868 lock_ObtainMutex(&fidp->mx);
2869 delonclose = fidp->flags & SMB_FID_DELONCLOSE;
2870 lock_ReleaseMutex(&fidp->mx);
2871 smb_ReleaseFID(fidp);
2873 qpi.u.QPfileStandardInfo.deletePending = (delonclose ? 1 : 0);
2875 else if (infoLevel == SMB_QUERY_FILE_EA_INFO) {
2876 qpi.u.QPfileEaInfo.eaSize = 0;
2878 else if (infoLevel == SMB_QUERY_FILE_ALL_INFO) {
2879 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
2880 qpi.u.QPfileAllInfo.creationTime = ft;
2881 qpi.u.QPfileAllInfo.lastAccessTime = ft;
2882 qpi.u.QPfileAllInfo.lastWriteTime = ft;
2883 qpi.u.QPfileAllInfo.changeTime = ft;
2884 extAttributes = smb_ExtAttributes(scp);
2885 qpi.u.QPfileAllInfo.attributes = extAttributes;
2886 qpi.u.QPfileAllInfo.allocationSize = scp->length;
2887 qpi.u.QPfileAllInfo.endOfFile = scp->length;
2888 qpi.u.QPfileAllInfo.numberOfLinks = scp->linkCount;
2889 qpi.u.QPfileAllInfo.deletePending = 0;
2890 qpi.u.QPfileAllInfo.directory =
2891 ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
2892 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
2893 scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0);
2894 qpi.u.QPfileAllInfo.indexNumber.HighPart = scp->fid.cell;
2895 qpi.u.QPfileAllInfo.indexNumber.LowPart = scp->fid.volume;
2896 qpi.u.QPfileAllInfo.eaSize = 0;
2897 qpi.u.QPfileAllInfo.accessFlags = 0;
2898 qpi.u.QPfileAllInfo.indexNumber2.HighPart = scp->fid.vnode;
2899 qpi.u.QPfileAllInfo.indexNumber2.LowPart = scp->fid.unique;
2900 qpi.u.QPfileAllInfo.currentByteOffset.HighPart = 0;
2901 qpi.u.QPfileAllInfo.currentByteOffset.LowPart = 0;
2902 qpi.u.QPfileAllInfo.mode = 0;
2903 qpi.u.QPfileAllInfo.alignmentRequirement = 0;
2904 len = strlen(lastComp);
2905 qpi.u.QPfileAllInfo.fileNameLength = (len + 1) * 2;
2906 mbstowcs((unsigned short *)qpi.u.QPfileAllInfo.fileName, lastComp, len + 1);
2909 /* send and free the packets */
2912 lock_ReleaseMutex(&scp->mx);
2913 cm_ReleaseSCache(scp);
2914 cm_ReleaseUser(userp);
2916 memcpy(outp->datap, &qpi, responseSize);
2917 smb_SendTran2Packet(vcp, outp, opx);
2919 smb_SendTran2Error(vcp, p, opx, code);
2921 smb_FreeTran2Packet(outp);
2926 long smb_ReceiveTran2SetPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
2929 osi_Log0(smb_logp,"ReceiveTran2SetPathInfo - NOT_SUPPORTED");
2930 return CM_ERROR_BADOP;
2934 unsigned short infoLevel;
2936 smb_tran2Packet_t *outp;
2937 smb_tran2QPathInfo_t *spi;
2939 cm_scache_t *scp, *dscp;
2947 infoLevel = p->parmsp[0];
2948 osi_Log1(smb_logp,"ReceiveTran2SetPathInfo type 0x%x", infoLevel);
2949 if (infoLevel != SMB_INFO_STANDARD &&
2950 infoLevel != SMB_INFO_QUERY_EA_SIZE &&
2951 infoLevel != SMB_INFO_QUERY_ALL_EAS) {
2952 osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
2953 p->opcode, infoLevel);
2954 smb_SendTran2Error(vcp, p, opx, CM_ERROR_BAD_LEVEL);
2958 pathp = (char *)(&p->parmsp[3]);
2959 if (smb_StoreAnsiFilenames)
2960 OemToChar(pathp,pathp);
2961 osi_Log2(smb_logp, "T2 SetPathInfo infolevel 0x%x path %s", infoLevel,
2962 osi_LogSaveString(smb_logp, pathp));
2964 userp = smb_GetTran2User(vcp, p);
2966 osi_Log1(smb_logp,"ReceiveTran2SetPathInfo unable to resolve user [%d]", p->uid);
2967 code = CM_ERROR_BADSMB;
2971 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
2972 if (code == CM_ERROR_TIDIPC) {
2973 /* Attempt to use a TID allocated for IPC. The client
2974 * is probably looking for DCE RPC end points which we
2975 * don't support OR it could be looking to make a DFS
2978 osi_Log0(smb_logp, "Tran2Open received IPC TID");
2979 cm_ReleaseUser(userp);
2980 return CM_ERROR_NOSUCHPATH;
2984 * XXX Strange hack XXX
2986 * As of Patch 7 (13 January 98), we are having the following problem:
2987 * In NT Explorer 4.0, whenever we click on a directory, AFS gets
2988 * requests to look up "desktop.ini" in all the subdirectories.
2989 * This can cause zillions of timeouts looking up non-existent cells
2990 * and volumes, especially in the top-level directory.
2992 * We have not found any way to avoid this or work around it except
2993 * to explicitly ignore the requests for mount points that haven't
2994 * yet been evaluated and for directories that haven't yet been
2997 if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
2998 spacep = cm_GetSpace();
2999 smb_StripLastComponent(spacep->data, &lastComp, pathp);
3000 #ifndef SPECIAL_FOLDERS
3001 /* Make sure that lastComp is not NULL */
3003 if (stricmp(lastComp, "\\desktop.ini") == 0) {
3004 code = cm_NameI(cm_data.rootSCachep, spacep->data,
3008 userp, tidPathp, &req, &dscp);
3011 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
3012 if ( WANTS_DFS_PATHNAMES(p) )
3013 code = CM_ERROR_PATH_NOT_COVERED;
3015 code = CM_ERROR_BADSHARENAME;
3017 #endif /* DFS_SUPPORT */
3018 if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT && !dscp->mountRootFid.volume)
3019 code = CM_ERROR_NOSUCHFILE;
3020 else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
3021 cm_buf_t *bp = buf_Find(dscp, &hzero);
3025 code = CM_ERROR_NOSUCHFILE;
3027 cm_ReleaseSCache(dscp);
3029 cm_FreeSpace(spacep);
3030 cm_ReleaseUser(userp);
3031 smb_SendTran2Error(vcp, p, opx, code);
3037 #endif /* SPECIAL_FOLDERS */
3039 cm_FreeSpace(spacep);
3042 /* now do namei and stat, and copy out the info */
3043 code = cm_NameI(cm_data.rootSCachep, pathp,
3044 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, tidPathp, &req, &scp);
3046 cm_ReleaseUser(userp);
3047 smb_SendTran2Error(vcp, p, opx, code);
3051 fidp = smb_FindFIDByScache(vcp, scp);
3053 cm_ReleaseSCache(scp);
3054 cm_ReleaseUser(userp);
3055 smb_SendTran2Error(vcp, p, opx, code);
3059 lock_ObtainMutex(&fidp->mx);
3060 if (!(fidp->flags & SMB_FID_OPENWRITE)) {
3061 lock_ReleaseMutex(&fidp->mx);
3062 cm_ReleaseSCache(scp);
3063 smb_ReleaseFID(fidp);
3064 cm_ReleaseUser(userp);
3065 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOACCESS);
3068 lock_ReleaseMutex(&fidp->mx);
3070 outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, 0);
3072 outp->totalParms = 2;
3073 outp->totalData = 0;
3075 spi = (smb_tran2QPathInfo_t *)p->datap;
3076 if (infoLevel == SMB_INFO_STANDARD || infoLevel == SMB_INFO_QUERY_EA_SIZE) {
3079 /* lock the vnode with a callback; we need the current status
3080 * to determine what the new status is, in some cases.
3082 lock_ObtainMutex(&scp->mx);
3083 code = cm_SyncOp(scp, NULL, userp, &req, 0,
3084 CM_SCACHESYNC_GETSTATUS
3085 | CM_SCACHESYNC_NEEDCALLBACK);
3087 lock_ReleaseMutex(&scp->mx);
3090 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3092 lock_ReleaseMutex(&scp->mx);
3093 lock_ObtainMutex(&fidp->mx);
3094 lock_ObtainMutex(&scp->mx);
3096 /* prepare for setattr call */
3097 attr.mask = CM_ATTRMASK_LENGTH;
3098 attr.length.LowPart = spi->u.QPstandardInfo.dataSize;
3099 attr.length.HighPart = 0;
3101 if (spi->u.QPstandardInfo.lastWriteDateTime != 0) {
3102 smb_UnixTimeFromSearchTime(&attr.clientModTime, spi->u.QPstandardInfo.lastWriteDateTime);
3103 attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
3104 fidp->flags |= SMB_FID_MTIMESETDONE;
3107 if (spi->u.QPstandardInfo.attributes != 0) {
3108 if ((scp->unixModeBits & 0222)
3109 && (spi->u.QPstandardInfo.attributes & SMB_ATTR_READONLY) != 0) {
3110 /* make a writable file read-only */
3111 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
3112 attr.unixModeBits = scp->unixModeBits & ~0222;
3114 else if ((scp->unixModeBits & 0222) == 0
3115 && (spi->u.QPstandardInfo.attributes & SMB_ATTR_READONLY) == 0) {
3116 /* make a read-only file writable */
3117 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
3118 attr.unixModeBits = scp->unixModeBits | 0222;
3121 lock_ReleaseMutex(&scp->mx);
3122 lock_ReleaseMutex(&fidp->mx);
3126 code = cm_SetAttr(scp, &attr, userp, &req);
3130 else if (infoLevel == SMB_INFO_QUERY_ALL_EAS) {
3131 /* we don't support EAs */
3132 code = CM_ERROR_INVAL;
3136 cm_ReleaseSCache(scp);
3137 cm_ReleaseUser(userp);
3138 smb_ReleaseFID(fidp);
3140 smb_SendTran2Packet(vcp, outp, opx);
3142 smb_SendTran2Error(vcp, p, opx, code);
3143 smb_FreeTran2Packet(outp);
3149 long smb_ReceiveTran2QFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
3151 smb_tran2Packet_t *outp;
3153 unsigned long attributes;
3154 unsigned short infoLevel;
3161 smb_tran2QFileInfo_t qfi;
3168 fidp = smb_FindFID(vcp, fid, 0);
3171 smb_SendTran2Error(vcp, p, opx, CM_ERROR_BADFD);
3175 infoLevel = p->parmsp[1];
3176 if (infoLevel == SMB_QUERY_FILE_BASIC_INFO)
3177 responseSize = sizeof(qfi.u.QFbasicInfo);
3178 else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO)
3179 responseSize = sizeof(qfi.u.QFstandardInfo);
3180 else if (infoLevel == SMB_QUERY_FILE_EA_INFO)
3181 responseSize = sizeof(qfi.u.QFeaInfo);
3182 else if (infoLevel == SMB_QUERY_FILE_NAME_INFO)
3183 responseSize = sizeof(qfi.u.QFfileNameInfo);
3185 osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
3186 p->opcode, infoLevel);
3187 smb_SendTran2Error(vcp, p, opx, CM_ERROR_BAD_LEVEL);
3188 smb_ReleaseFID(fidp);
3191 osi_Log2(smb_logp, "T2 QFileInfo type 0x%x fid %d", infoLevel, fid);
3193 outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, responseSize);
3195 if (infoLevel > 0x100)
3196 outp->totalParms = 2;
3198 outp->totalParms = 0;
3199 outp->totalData = responseSize;
3201 userp = smb_GetTran2User(vcp, p);
3203 osi_Log1(smb_logp, "ReceiveTran2QFileInfo unable to resolve user [%d]", p->uid);
3204 code = CM_ERROR_BADSMB;
3208 lock_ObtainMutex(&fidp->mx);
3209 delonclose = fidp->flags & SMB_FID_DELONCLOSE;
3211 osi_Log2(smb_logp,"smb_ReleaseTran2QFileInfo fidp 0x%p scp 0x%p", fidp, scp);
3213 lock_ReleaseMutex(&fidp->mx);
3214 lock_ObtainMutex(&scp->mx);
3215 code = cm_SyncOp(scp, NULL, userp, &req, 0,
3216 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3220 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3222 /* now we have the status in the cache entry, and everything is locked.
3223 * Marshall the output data.
3225 if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
3226 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
3227 qfi.u.QFbasicInfo.creationTime = ft;
3228 qfi.u.QFbasicInfo.lastAccessTime = ft;
3229 qfi.u.QFbasicInfo.lastWriteTime = ft;
3230 qfi.u.QFbasicInfo.lastChangeTime = ft;
3231 attributes = smb_ExtAttributes(scp);
3232 qfi.u.QFbasicInfo.attributes = attributes;
3234 else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO) {
3235 qfi.u.QFstandardInfo.allocationSize = scp->length;
3236 qfi.u.QFstandardInfo.endOfFile = scp->length;
3237 qfi.u.QFstandardInfo.numberOfLinks = scp->linkCount;
3238 qfi.u.QFstandardInfo.deletePending = (delonclose ? 1 : 0);
3239 qfi.u.QFstandardInfo.directory =
3240 ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
3241 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
3242 scp->fileType == CM_SCACHETYPE_INVALID)? 1 : 0);
3244 else if (infoLevel == SMB_QUERY_FILE_EA_INFO) {
3245 qfi.u.QFeaInfo.eaSize = 0;
3247 else if (infoLevel == SMB_QUERY_FILE_NAME_INFO) {
3251 lock_ReleaseMutex(&scp->mx);
3252 lock_ObtainMutex(&fidp->mx);
3253 lock_ObtainMutex(&scp->mx);
3254 if (fidp->NTopen_wholepathp)
3255 name = fidp->NTopen_wholepathp;
3257 name = "\\"; /* probably can't happen */
3258 lock_ReleaseMutex(&fidp->mx);
3259 len = (unsigned long)strlen(name);
3260 outp->totalData = ((len+1)*2) + 4; /* this is actually what we want to return */
3261 qfi.u.QFfileNameInfo.fileNameLength = (len + 1) * 2;
3262 mbstowcs((unsigned short *)qfi.u.QFfileNameInfo.fileName, name, len + 1);
3265 /* send and free the packets */
3267 lock_ReleaseMutex(&scp->mx);
3268 cm_ReleaseSCache(scp);
3269 cm_ReleaseUser(userp);
3270 smb_ReleaseFID(fidp);
3272 memcpy(outp->datap, &qfi, responseSize);
3273 smb_SendTran2Packet(vcp, outp, opx);
3275 smb_SendTran2Error(vcp, p, opx, code);
3277 smb_FreeTran2Packet(outp);
3282 long smb_ReceiveTran2SetFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
3287 unsigned short infoLevel;
3288 smb_tran2Packet_t *outp;
3289 cm_user_t *userp = NULL;
3290 cm_scache_t *scp = NULL;
3296 fidp = smb_FindFID(vcp, fid, 0);
3299 smb_SendTran2Error(vcp, p, opx, CM_ERROR_BADFD);
3303 infoLevel = p->parmsp[1];
3304 osi_Log2(smb_logp,"ReceiveTran2SetFileInfo type 0x%x fid %d", infoLevel, fid);
3305 if (infoLevel > SMB_SET_FILE_END_OF_FILE_INFO || infoLevel < SMB_SET_FILE_BASIC_INFO) {
3306 osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
3307 p->opcode, infoLevel);
3308 smb_SendTran2Error(vcp, p, opx, CM_ERROR_BAD_LEVEL);
3309 smb_ReleaseFID(fidp);
3313 lock_ObtainMutex(&fidp->mx);
3314 if (infoLevel == SMB_SET_FILE_DISPOSITION_INFO &&
3315 !(fidp->flags & SMB_FID_OPENDELETE)) {
3316 osi_Log3(smb_logp,"smb_ReceiveTran2SetFileInfo !SMB_FID_OPENDELETE fidp 0x%p scp 0x%p fidp->flags 0x%x",
3317 fidp, fidp->scp, fidp->flags);
3318 lock_ReleaseMutex(&fidp->mx);
3319 smb_ReleaseFID(fidp);
3320 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOACCESS);
3323 if ((infoLevel == SMB_SET_FILE_ALLOCATION_INFO ||
3324 infoLevel == SMB_SET_FILE_END_OF_FILE_INFO)
3325 && !(fidp->flags & SMB_FID_OPENWRITE)) {
3326 osi_Log3(smb_logp,"smb_ReceiveTran2SetFileInfo !SMB_FID_OPENWRITE fidp 0x%p scp 0x%p fidp->flags 0x%x",
3327 fidp, fidp->scp, fidp->flags);
3328 lock_ReleaseMutex(&fidp->mx);
3329 smb_ReleaseFID(fidp);
3330 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOACCESS);
3335 osi_Log2(smb_logp,"smb_ReceiveTran2SetFileInfo fidp 0x%p scp 0x%p", fidp, scp);
3337 lock_ReleaseMutex(&fidp->mx);
3339 outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, 0);
3341 outp->totalParms = 2;
3342 outp->totalData = 0;
3344 userp = smb_GetTran2User(vcp, p);
3346 osi_Log1(smb_logp,"ReceiveTran2SetFileInfo unable to resolve user [%d]", p->uid);
3347 code = CM_ERROR_BADSMB;
3351 if (infoLevel == SMB_SET_FILE_BASIC_INFO) {
3353 unsigned int attribute;
3355 smb_tran2QFileInfo_t *sfi;
3357 sfi = (smb_tran2QFileInfo_t *)p->datap;
3359 /* lock the vnode with a callback; we need the current status
3360 * to determine what the new status is, in some cases.
3362 lock_ObtainMutex(&scp->mx);
3363 code = cm_SyncOp(scp, NULL, userp, &req, 0,
3364 CM_SCACHESYNC_GETSTATUS
3365 | CM_SCACHESYNC_NEEDCALLBACK);
3367 lock_ReleaseMutex(&scp->mx);
3371 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3373 lock_ReleaseMutex(&scp->mx);
3374 lock_ObtainMutex(&fidp->mx);
3375 lock_ObtainMutex(&scp->mx);
3377 /* prepare for setattr call */
3380 lastMod = sfi->u.QFbasicInfo.lastWriteTime;
3381 /* when called as result of move a b, lastMod is (-1, -1).
3382 * If the check for -1 is not present, timestamp
3383 * of the resulting file will be 1969 (-1)
3385 if (LargeIntegerNotEqualToZero(*((LARGE_INTEGER *)&lastMod)) &&
3386 lastMod.dwLowDateTime != -1 && lastMod.dwHighDateTime != -1) {
3387 attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
3388 smb_UnixTimeFromLargeSearchTime(&attr.clientModTime, &lastMod);
3389 fidp->flags |= SMB_FID_MTIMESETDONE;
3392 attribute = sfi->u.QFbasicInfo.attributes;
3393 if (attribute != 0) {
3394 if ((scp->unixModeBits & 0222)
3395 && (attribute & SMB_ATTR_READONLY) != 0) {
3396 /* make a writable file read-only */
3397 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
3398 attr.unixModeBits = scp->unixModeBits & ~0222;
3400 else if ((scp->unixModeBits & 0222) == 0
3401 && (attribute & SMB_ATTR_READONLY) == 0) {
3402 /* make a read-only file writable */
3403 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
3404 attr.unixModeBits = scp->unixModeBits | 0222;
3407 lock_ReleaseMutex(&scp->mx);
3408 lock_ReleaseMutex(&fidp->mx);
3412 code = cm_SetAttr(scp, &attr, userp, &req);
3416 else if (infoLevel == SMB_SET_FILE_DISPOSITION_INFO) {
3417 int delflag = *((char *)(p->datap));
3418 osi_Log3(smb_logp,"smb_ReceiveTran2SetFileInfo Delete? %d fidp 0x%p scp 0x%p",
3419 delflag, fidp, scp);
3420 if (*((char *)(p->datap))) { /* File is Deleted */
3421 code = cm_CheckNTDelete(fidp->NTopen_dscp, scp, userp,
3424 lock_ObtainMutex(&fidp->mx);
3425 fidp->flags |= SMB_FID_DELONCLOSE;
3426 lock_ReleaseMutex(&fidp->mx);
3428 osi_Log3(smb_logp,"smb_ReceiveTran2SetFileInfo CheckNTDelete fidp 0x%p scp 0x%p code 0x%x",
3434 lock_ObtainMutex(&fidp->mx);
3435 fidp->flags &= ~SMB_FID_DELONCLOSE;
3436 lock_ReleaseMutex(&fidp->mx);
3439 else if (infoLevel == SMB_SET_FILE_ALLOCATION_INFO ||
3440 infoLevel == SMB_SET_FILE_END_OF_FILE_INFO) {
3441 LARGE_INTEGER size = *((LARGE_INTEGER *)(p->datap));
3444 attr.mask = CM_ATTRMASK_LENGTH;
3445 attr.length.LowPart = size.LowPart;
3446 attr.length.HighPart = size.HighPart;
3447 code = cm_SetAttr(scp, &attr, userp, &req);
3451 cm_ReleaseSCache(scp);
3452 cm_ReleaseUser(userp);
3453 smb_ReleaseFID(fidp);
3455 smb_SendTran2Packet(vcp, outp, opx);
3457 smb_SendTran2Error(vcp, p, opx, code);
3458 smb_FreeTran2Packet(outp);
3464 smb_ReceiveTran2FSCTL(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3466 osi_Log0(smb_logp,"ReceiveTran2FSCTL - NOT_SUPPORTED");
3467 return CM_ERROR_BADOP;
3471 smb_ReceiveTran2IOCTL(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3473 osi_Log0(smb_logp,"ReceiveTran2IOCTL - NOT_SUPPORTED");
3474 return CM_ERROR_BADOP;
3478 smb_ReceiveTran2FindNotifyFirst(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3480 osi_Log0(smb_logp,"ReceiveTran2FindNotifyFirst - NOT_SUPPORTED");
3481 return CM_ERROR_BADOP;
3485 smb_ReceiveTran2FindNotifyNext(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3487 osi_Log0(smb_logp,"ReceiveTran2FindNotifyNext - NOT_SUPPORTED");
3488 return CM_ERROR_BADOP;
3492 smb_ReceiveTran2CreateDirectory(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3494 osi_Log0(smb_logp,"ReceiveTran2CreateDirectory - NOT_SUPPORTED");
3495 return CM_ERROR_BADOP;
3499 smb_ReceiveTran2SessionSetup(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3501 osi_Log0(smb_logp,"ReceiveTran2SessionSetup - NOT_SUPPORTED");
3502 return CM_ERROR_BADOP;
3505 struct smb_v2_referral {
3507 USHORT ReferralFlags;
3510 USHORT DfsPathOffset;
3511 USHORT DfsAlternativePathOffset;
3512 USHORT NetworkAddressOffset;
3516 smb_ReceiveTran2GetDFSReferral(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
3518 /* This is a UNICODE only request (bit15 of Flags2) */
3519 /* The TID must be IPC$ */
3521 /* The documentation for the Flags response field is contradictory */
3523 /* Use Version 1 Referral Element Format */
3524 /* ServerType = 0; indicates the next server should be queried for the file */
3525 /* ReferralFlags = 0x01; PathConsumed characters should be stripped */
3526 /* Node = UnicodeString of UNC path of the next share name */
3529 int maxReferralLevel = 0;
3530 char requestFileName[1024] = "";
3531 smb_tran2Packet_t *outp = 0;
3532 cm_user_t *userp = 0;
3534 CPINFO CodePageInfo;
3535 int i, nbnLen, reqLen;
3540 maxReferralLevel = p->parmsp[0];
3542 GetCPInfo(CP_ACP, &CodePageInfo);
3543 WideCharToMultiByte(CP_ACP, 0, (LPCWSTR) &p->parmsp[1], -1,
3544 requestFileName, 1024, NULL, NULL);
3546 osi_Log2(smb_logp,"ReceiveTran2GetDfsReferral [%d][%s]",
3547 maxReferralLevel, osi_LogSaveString(smb_logp, requestFileName));
3549 nbnLen = strlen(cm_NetbiosName);
3550 reqLen = strlen(requestFileName);
3552 if (reqLen == nbnLen + 5 &&
3553 requestFileName[0] == '\\' &&
3554 !_strnicmp(cm_NetbiosName,&requestFileName[1],nbnLen) &&
3555 requestFileName[nbnLen+1] == '\\' &&
3556 (!_strnicmp("all",&requestFileName[nbnLen+2],3) ||
3557 !_strnicmp("*.",&requestFileName[nbnLen+2],2)))
3560 struct smb_v2_referral * v2ref;
3561 outp = smb_GetTran2ResponsePacket(vcp, p, op, 0, 2 * (reqLen + 8));
3563 sp = (USHORT *)outp->datap;
3565 sp[idx++] = reqLen; /* path consumed */
3566 sp[idx++] = 1; /* number of referrals */
3567 sp[idx++] = 0x03; /* flags */
3568 #ifdef DFS_VERSION_1
3569 sp[idx++] = 1; /* Version Number */
3570 sp[idx++] = reqLen + 4; /* Referral Size */
3571 sp[idx++] = 1; /* Type = SMB Server */
3572 sp[idx++] = 0; /* Do not strip path consumed */
3573 for ( i=0;i<=reqLen; i++ )
3574 sp[i+idx] = requestFileName[i];
3575 #else /* DFS_VERSION_2 */
3576 sp[idx++] = 2; /* Version Number */
3577 sp[idx++] = sizeof(struct smb_v2_referral); /* Referral Size */
3578 idx += (sizeof(struct smb_v2_referral) / 2);
3579 v2ref = (struct smb_v2_referral *) &sp[5];
3580 v2ref->ServerType = 1; /* SMB Server */
3581 v2ref->ReferralFlags = 0x03;
3582 v2ref->Proximity = 0; /* closest */
3583 v2ref->TimeToLive = 3600; /* seconds */
3584 v2ref->DfsPathOffset = idx * 2;
3585 v2ref->DfsAlternativePathOffset = idx * 2;
3586 v2ref->NetworkAddressOffset = 0;
3587 for ( i=0;i<=reqLen; i++ )
3588 sp[i+idx] = requestFileName[i];
3591 userp = smb_GetTran2User(vcp, p);
3593 osi_Log1(smb_logp,"ReceiveTran2GetDfsReferral unable to resolve user [%d]", p->uid);
3594 code = CM_ERROR_BADSMB;
3599 code = CM_ERROR_NOSUCHPATH;
3604 cm_ReleaseUser(userp);
3606 smb_SendTran2Packet(vcp, outp, op);
3608 smb_SendTran2Error(vcp, p, op, code);
3610 smb_FreeTran2Packet(outp);
3613 #else /* DFS_SUPPORT */
3614 osi_Log0(smb_logp,"ReceiveTran2GetDfsReferral - NOT_SUPPORTED");
3615 return CM_ERROR_BADOP;
3616 #endif /* DFS_SUPPORT */
3620 smb_ReceiveTran2ReportDFSInconsistency(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3622 /* This is a UNICODE only request (bit15 of Flags2) */
3624 /* There is nothing we can do about this operation. The client is going to
3625 * tell us that there is a Version 1 Referral Element for which there is a DFS Error.
3626 * Unfortunately, there is really nothing we can do about it other then log it
3627 * somewhere. Even then I don't think there is anything for us to do.
3628 * So let's return an error value.
3631 osi_Log0(smb_logp,"ReceiveTran2ReportDFSInconsistency - NOT_SUPPORTED");
3632 return CM_ERROR_BADOP;
3636 smb_ApplyV3DirListPatches(cm_scache_t *dscp,
3637 smb_dirListPatch_t **dirPatchespp, int infoLevel, cm_user_t *userp,
3642 cm_scache_t *targetScp; /* target if scp is a symlink */
3647 unsigned short attr;
3648 unsigned long lattr;
3649 smb_dirListPatch_t *patchp;
3650 smb_dirListPatch_t *npatchp;
3653 code = cm_FindACLCache(dscp, userp, &rights);
3654 if (code == 0 && !(rights & PRSFS_READ))
3655 code = CM_ERROR_NOACCESS;
3656 else if (code == -1) {
3657 lock_ObtainMutex(&dscp->mx);
3658 code = cm_SyncOp(dscp, NULL, userp, reqp, PRSFS_READ,
3659 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3660 lock_ReleaseMutex(&dscp->mx);
3665 for(patchp = *dirPatchespp; patchp; patchp =
3666 (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
3667 code = cm_GetSCache(&patchp->fid, &scp, userp, reqp);
3671 lock_ObtainMutex(&scp->mx);
3672 code = cm_SyncOp(scp, NULL, userp, reqp, 0,
3673 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3675 lock_ReleaseMutex(&scp->mx);
3676 cm_ReleaseSCache(scp);
3678 dptr = patchp->dptr;
3680 /* Plug in fake timestamps. A time stamp of 0 causes 'invalid parameter'
3681 errors in the client. */
3682 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO) {
3683 /* 1969-12-31 23:59:59 +00 */
3684 ft.dwHighDateTime = 0x19DB200;
3685 ft.dwLowDateTime = 0x5BB78980;
3687 /* copy to Creation Time */
3688 *((FILETIME *)dptr) = ft;
3691 /* copy to Last Access Time */
3692 *((FILETIME *)dptr) = ft;
3695 /* copy to Last Write Time */
3696 *((FILETIME *)dptr) = ft;
3699 /* copy to Change Time */
3700 *((FILETIME *)dptr) = ft;
3703 /* merge in hidden attribute */
3704 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
3705 *((u_long *)dptr) = SMB_ATTR_HIDDEN;
3709 /* 1969-12-31 23:59:58 +00*/
3710 dosTime = 0xEBBFBF7D;
3712 /* and copy out date */
3713 shortTemp = (dosTime>>16) & 0xffff;
3714 *((u_short *)dptr) = shortTemp;
3717 /* copy out creation time */
3718 shortTemp = dosTime & 0xffff;
3719 *((u_short *)dptr) = shortTemp;
3722 /* and copy out date */
3723 shortTemp = (dosTime>>16) & 0xffff;
3724 *((u_short *)dptr) = shortTemp;
3727 /* copy out access time */
3728 shortTemp = dosTime & 0xffff;
3729 *((u_short *)dptr) = shortTemp;
3732 /* and copy out date */
3733 shortTemp = (dosTime>>16) & 0xffff;
3734 *((u_short *)dptr) = shortTemp;
3737 /* copy out mod time */
3738 shortTemp = dosTime & 0xffff;
3739 *((u_short *)dptr) = shortTemp;
3742 /* merge in hidden (dot file) attribute */
3743 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
3744 attr = SMB_ATTR_HIDDEN;
3745 *dptr++ = attr & 0xff;
3746 *dptr++ = (attr >> 8) & 0xff;
3752 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3754 /* now watch for a symlink */
3756 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
3757 lock_ReleaseMutex(&scp->mx);
3758 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, reqp);
3760 /* we have a more accurate file to use (the
3761 * target of the symbolic link). Otherwise,
3762 * we'll just use the symlink anyway.
3764 osi_Log2(smb_logp, "symlink vp %x to vp %x",
3766 cm_ReleaseSCache(scp);
3769 lock_ObtainMutex(&scp->mx);
3772 dptr = patchp->dptr;
3774 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO) {
3776 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
3778 /* copy to Creation Time */
3779 *((FILETIME *)dptr) = ft;
3782 /* copy to Last Access Time */
3783 *((FILETIME *)dptr) = ft;
3786 /* copy to Last Write Time */
3787 *((FILETIME *)dptr) = ft;
3790 /* copy to Change Time */
3791 *((FILETIME *)dptr) = ft;
3794 /* Use length for both file length and alloc length */
3795 *((LARGE_INTEGER *)dptr) = scp->length;
3797 *((LARGE_INTEGER *)dptr) = scp->length;
3800 /* Copy attributes */
3801 lattr = smb_ExtAttributes(scp);
3802 if (code == CM_ERROR_NOSUCHPATH && scp->fileType == CM_SCACHETYPE_SYMLINK) {
3803 if (lattr == SMB_ATTR_NORMAL)
3804 lattr = SMB_ATTR_DIRECTORY;
3806 lattr |= SMB_ATTR_DIRECTORY;
3808 /* merge in hidden (dot file) attribute */
3809 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
3810 if (lattr == SMB_ATTR_NORMAL)
3811 lattr = SMB_ATTR_HIDDEN;
3813 lattr |= SMB_ATTR_HIDDEN;
3815 *((u_long *)dptr) = lattr;
3819 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
3821 /* and copy out date */
3822 shortTemp = (dosTime>>16) & 0xffff;
3823 *((u_short *)dptr) = shortTemp;
3826 /* copy out creation time */
3827 shortTemp = dosTime & 0xffff;
3828 *((u_short *)dptr) = shortTemp;
3831 /* and copy out date */
3832 shortTemp = (dosTime>>16) & 0xffff;
3833 *((u_short *)dptr) = shortTemp;
3836 /* copy out access time */
3837 shortTemp = dosTime & 0xffff;
3838 *((u_short *)dptr) = shortTemp;
3841 /* and copy out date */
3842 shortTemp = (dosTime>>16) & 0xffff;
3843 *((u_short *)dptr) = shortTemp;
3846 /* copy out mod time */
3847 shortTemp = dosTime & 0xffff;
3848 *((u_short *)dptr) = shortTemp;
3851 /* copy out file length and alloc length,
3852 * using the same for both
3854 *((u_long *)dptr) = scp->length.LowPart;
3856 *((u_long *)dptr) = scp->length.LowPart;
3859 /* finally copy out attributes as short */
3860 attr = smb_Attributes(scp);
3861 /* merge in hidden (dot file) attribute */
3862 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
3863 if (lattr == SMB_ATTR_NORMAL)
3864 lattr = SMB_ATTR_HIDDEN;
3866 lattr |= SMB_ATTR_HIDDEN;
3868 *dptr++ = attr & 0xff;
3869 *dptr++ = (attr >> 8) & 0xff;
3872 lock_ReleaseMutex(&scp->mx);
3873 cm_ReleaseSCache(scp);
3876 /* now free the patches */
3877 for (patchp = *dirPatchespp; patchp; patchp = npatchp) {
3878 npatchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q);
3882 /* and mark the list as empty */
3883 *dirPatchespp = NULL;
3888 #ifndef USE_OLD_MATCHING
3889 // char table for case insensitive comparison
3890 char mapCaseTable[256];
3892 VOID initUpperCaseTable(VOID)
3895 for (i = 0; i < 256; ++i)
3896 mapCaseTable[i] = toupper(i);
3897 // make '"' match '.'
3898 mapCaseTable[(int)'"'] = toupper('.');
3899 // make '<' match '*'
3900 mapCaseTable[(int)'<'] = toupper('*');
3901 // make '>' match '?'
3902 mapCaseTable[(int)'>'] = toupper('?');
3905 // Compare 'pattern' (containing metacharacters '*' and '?') with the file
3907 // Note : this procedure works recursively calling itself.
3909 // PSZ pattern : string containing metacharacters.
3910 // PSZ name : file name to be compared with 'pattern'.
3912 // BOOL : TRUE/FALSE (match/mistmatch)
3915 szWildCardMatchFileName(PSZ pattern, PSZ name, int casefold)
3917 PSZ pename; // points to the last 'name' character
3919 pename = name + strlen(name) - 1;
3930 if (*pattern == '\0')
3932 for (p = pename; p >= name; --p) {
3933 if ((casefold && (mapCaseTable[*p] == mapCaseTable[*pattern]) ||
3934 !casefold && (*p == *pattern)) &&
3935 szWildCardMatchFileName(pattern + 1, p + 1, casefold))
3940 if ((casefold && mapCaseTable[*name] != mapCaseTable[*pattern]) ||
3941 (!casefold && *name != *pattern))
3948 /* if all we have left are wildcards, then we match */
3949 for (;*pattern; pattern++) {
3950 if (*pattern != '*' && *pattern != '?')
3956 /* do a case-folding search of the star name mask with the name in namep.
3957 * Return 1 if we match, otherwise 0.
3959 int smb_V3MatchMask(char *namep, char *maskp, int flags)
3962 int i, j, star, qmark, casefold, retval;
3964 /* make sure we only match 8.3 names, if requested */
3965 if ((flags & CM_FLAG_8DOT3) && !cm_Is8Dot3(namep))
3968 casefold = (flags & CM_FLAG_CASEFOLD) ? 1 : 0;
3970 /* optimize the pattern:
3971 * if there is a mixture of '?' and '*',
3972 * for example the sequence "*?*?*?*"
3973 * must be turned into the form "*"
3975 newmask = (char *)malloc(strlen(maskp)+1);
3976 for ( i=0, j=0, star=0, qmark=0; maskp[i]; i++) {
3977 switch ( maskp[i] ) {
3989 } else if ( qmark ) {
3993 newmask[j++] = maskp[i];
4000 } else if ( qmark ) {
4004 newmask[j++] = '\0';
4006 retval = szWildCardMatchFileName(newmask, namep, casefold) ? 1:0;
4012 #else /* USE_OLD_MATCHING */
4013 /* do a case-folding search of the star name mask with the name in namep.
4014 * Return 1 if we match, otherwise 0.
4016 int smb_V3MatchMask(char *namep, char *maskp, int flags)
4018 unsigned char tcp1, tcp2; /* Pattern characters */
4019 unsigned char tcn1; /* Name characters */
4020 int sawDot = 0, sawStar = 0, req8dot3 = 0;
4021 char *starNamep, *starMaskp;
4022 static char nullCharp[] = {0};
4023 int casefold = flags & CM_FLAG_CASEFOLD;
4025 /* make sure we only match 8.3 names, if requested */
4026 req8dot3 = (flags & CM_FLAG_8DOT3);
4027 if (req8dot3 && !cm_Is8Dot3(namep))
4032 /* Next pattern character */
4035 /* Next name character */
4039 /* 0 - end of pattern */
4045 else if (tcp1 == '.' || tcp1 == '"') {
4055 * first dot in pattern;
4056 * must match dot or end of name
4061 else if (tcn1 == '.') {
4070 else if (tcp1 == '?') {
4071 if (tcn1 == 0 || tcn1 == '.')
4076 else if (tcp1 == '>') {
4077 if (tcn1 != 0 && tcn1 != '.')
4081 else if (tcp1 == '*' || tcp1 == '<') {
4085 else if ((req8dot3 && tcp2 == '.') || tcp2 == '"') {
4086 while (req8dot3 && tcn1 != '.' && tcn1 != 0)
4101 * pattern character after '*' is not null or
4102 * period. If it is '?' or '>', we are not
4103 * going to understand it. If it is '*' or
4104 * '<', we are going to skip over it. None of
4105 * these are likely, I hope.
4107 /* skip over '*' and '<' */
4108 while (tcp2 == '*' || tcp2 == '<')
4111 /* skip over characters that don't match tcp2 */
4112 while (req8dot3 && tcn1 != '.' && tcn1 != 0 &&
4113 ((casefold && cm_foldUpper[tcn1] != cm_foldUpper[tcp2]) ||
4114 (!casefold && tcn1 != tcp2)))
4118 if ((req8dot3 && tcn1 == '.') || tcn1 == 0)
4121 /* Remember where we are */
4131 /* tcp1 is not a wildcard */
4132 if ((casefold && cm_foldUpper[tcn1] == cm_foldUpper[tcp1]) ||
4133 (!casefold && tcn1 == tcp1)) {
4138 /* if trying to match a star pattern, go back */
4140 maskp = starMaskp - 2;
4141 namep = starNamep + 1;
4150 #endif /* USE_OLD_MATCHING */
4152 /* smb_ReceiveTran2SearchDir implements both
4153 * Tran2_Find_First and Tran2_Find_Next
4155 #define TRAN2_FIND_FLAG_CLOSE_SEARCH 0x01
4156 #define TRAN2_FIND_FLAG_CLOSE_SEARCH_IF_END 0x02
4157 #define TRAN2_FIND_FLAG_RETURN_RESUME_KEYS 0x04
4158 #define TRAN2_FIND_FLAG_CONTINUE_SEARCH 0x08
4159 #define TRAN2_FIND_FLAG_BACKUP_INTENT 0x10
4161 /* this is an optimized handler for T2SearchDir that handles the case
4162 where there are no wildcards in the search path. I.e. an
4163 application is using FindFirst(Ex) to get information about a
4164 single file or directory. It will attempt to do a single lookup.
4165 If that fails, then smb_ReceiveTran2SearchDir() will fall back to
4166 the usual mechanism.
4168 This function will return either CM_ERROR_NOSUCHFILE or SUCCESS.
4170 long smb_T2SearchDirSingle(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
4174 long code = 0, code2 = 0;
4177 smb_dirListPatch_t *dirListPatchesp;
4178 smb_dirListPatch_t *curPatchp;
4179 long orbytes; /* # of bytes in this output record */
4180 long ohbytes; /* # of bytes, except file name */
4181 long onbytes; /* # of bytes in name, incl. term. null */
4182 cm_scache_t *scp = NULL;
4183 cm_scache_t *targetscp = NULL;
4184 cm_user_t *userp = NULL;
4185 char *op; /* output data ptr */
4186 char *origOp; /* original value of op */
4187 cm_space_t *spacep; /* for pathname buffer */
4188 long maxReturnData; /* max # of return data */
4189 long maxReturnParms; /* max # of return parms */
4190 long bytesInBuffer; /* # data bytes in the output buffer */
4191 char *maskp; /* mask part of path */
4195 smb_tran2Packet_t *outp; /* response packet */
4198 char shortName[13]; /* 8.3 name if needed */
4207 osi_assert(p->opcode == 1);
4209 /* find first; obtain basic parameters from request */
4211 /* note that since we are going to failover to regular
4212 * processing at smb_ReceiveTran2SearchDir(), we shouldn't
4213 * modify any of the input parameters here. */
4214 attribute = p->parmsp[0];
4215 maxCount = p->parmsp[1];
4216 infoLevel = p->parmsp[3];
4217 searchFlags = p->parmsp[2];
4218 pathp = ((char *) p->parmsp) + 12; /* points to path */
4220 maskp = strrchr(pathp, '\\');
4224 maskp++; /* skip over backslash */
4225 /* track if this is likely to match a lot of entries */
4227 osi_Log2(smb_logp, "smb_T2SearchDirSingle : path[%s], mask[%s]",
4228 osi_LogSaveString(smb_logp, pathp),
4229 osi_LogSaveString(smb_logp, maskp));
4231 switch ( infoLevel ) {
4232 case SMB_INFO_STANDARD:
4235 case SMB_INFO_QUERY_EA_SIZE:
4236 s = "InfoQueryEaSize";
4238 case SMB_INFO_QUERY_EAS_FROM_LIST:
4239 s = "InfoQueryEasFromList";
4241 case SMB_FIND_FILE_DIRECTORY_INFO:
4242 s = "FindFileDirectoryInfo";
4244 case SMB_FIND_FILE_FULL_DIRECTORY_INFO:
4245 s = "FindFileFullDirectoryInfo";
4247 case SMB_FIND_FILE_NAMES_INFO:
4248 s = "FindFileNamesInfo";
4250 case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
4251 s = "FindFileBothDirectoryInfo";
4254 s = "unknownInfoLevel";
4257 osi_Log1(smb_logp, "smb_T2SearchDirSingle info level: %s", s);
4260 "smb_T2SearchDirSingle attr 0x%x, info level 0x%x, max count %d, flags 0x%x",
4261 attribute, infoLevel, maxCount, searchFlags);
4263 if (infoLevel > SMB_FIND_FILE_BOTH_DIRECTORY_INFO) {
4264 osi_Log1(smb_logp, "Unsupported InfoLevel 0x%x", infoLevel);
4265 return CM_ERROR_INVAL;
4268 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO)
4269 searchFlags &= ~TRAN2_FIND_FLAG_RETURN_RESUME_KEYS; /* no resume keys */
4271 dirListPatchesp = NULL;
4273 maxReturnData = p->maxReturnData;
4274 maxReturnParms = 10; /* return params for findfirst, which
4275 is the only one we handle.*/
4277 #ifndef CM_CONFIG_MULTITRAN2RESPONSES
4278 if (maxReturnData > 6000)
4279 maxReturnData = 6000;
4280 #endif /* CM_CONFIG_MULTITRAN2RESPONSES */
4282 outp = smb_GetTran2ResponsePacket(vcp, p, opx, maxReturnParms,
4285 osi_Log2(smb_logp, "T2SDSingle search dir count %d [%s]",
4286 maxCount, osi_LogSaveString(smb_logp, pathp));
4288 /* bail out if request looks bad */
4290 smb_FreeTran2Packet(outp);
4291 return CM_ERROR_BADSMB;
4294 userp = smb_GetTran2User(vcp, p);
4296 osi_Log1(smb_logp, "T2 search dir unable to resolve user [%d]", p->uid);
4297 smb_FreeTran2Packet(outp);
4298 return CM_ERROR_BADSMB;
4301 /* try to get the vnode for the path name next */
4302 spacep = cm_GetSpace();
4303 smb_StripLastComponent(spacep->data, NULL, pathp);
4304 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
4306 cm_ReleaseUser(userp);
4307 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOFILES);
4308 smb_FreeTran2Packet(outp);
4312 code = cm_NameI(cm_data.rootSCachep, spacep->data,
4313 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
4314 userp, tidPathp, &req, &scp);
4315 cm_FreeSpace(spacep);
4318 cm_ReleaseUser(userp);
4319 smb_SendTran2Error(vcp, p, opx, code);
4320 smb_FreeTran2Packet(outp);
4324 #ifdef DFS_SUPPORT_BUT_NOT_FIND_FIRST
4325 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
4326 cm_ReleaseSCache(scp);
4327 cm_ReleaseUser(userp);
4328 if ( WANTS_DFS_PATHNAMES(p) )
4329 code = CM_ERROR_PATH_NOT_COVERED;
4331 code = CM_ERROR_BADSHARENAME;
4332 smb_SendTran2Error(vcp, p, opx, code);
4333 smb_FreeTran2Packet(outp);
4336 #endif /* DFS_SUPPORT */
4337 osi_Log1(smb_logp,"smb_ReceiveTran2SearchDir scp 0x%p", scp);
4338 lock_ObtainMutex(&scp->mx);
4339 if ((scp->flags & CM_SCACHEFLAG_BULKSTATTING) == 0 &&
4340 LargeIntegerGreaterOrEqualToZero(scp->bulkStatProgress)) {
4341 scp->flags |= CM_SCACHEFLAG_BULKSTATTING;
4343 lock_ReleaseMutex(&scp->mx);
4345 /* now do a single case sensitive lookup for the file in question */
4346 code = cm_Lookup(scp, maskp, CM_FLAG_NOMOUNTCHASE, userp, &req, &targetscp);
4348 /* if a case sensitive match failed, we try a case insensitive one
4350 if (code == CM_ERROR_NOSUCHFILE) {
4351 code = cm_Lookup(scp, maskp, CM_FLAG_NOMOUNTCHASE | CM_FLAG_CASEFOLD, userp, &req, &targetscp);
4354 if (code == 0 && targetscp->fid.vnode == 0) {
4355 cm_ReleaseSCache(targetscp);
4356 code = CM_ERROR_NOSUCHFILE;
4360 /* if we can't find the directory entry, this block will
4361 return CM_ERROR_NOSUCHFILE, which we will pass on to
4362 smb_ReceiveTran2SearchDir(). */
4363 cm_ReleaseSCache(scp);
4364 cm_ReleaseUser(userp);
4365 if (code != CM_ERROR_NOSUCHFILE) {
4366 smb_SendTran2Error(vcp, p, opx, code);
4369 smb_FreeTran2Packet(outp);
4373 /* now that we have the target in sight, we proceed with filling
4374 up the return data. */
4376 op = origOp = outp->datap;
4379 if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS) {
4380 /* skip over resume key */
4384 if (infoLevel == SMB_FIND_FILE_BOTH_DIRECTORY_INFO
4385 && targetscp->fid.vnode != 0
4386 && !cm_Is8Dot3(maskp)) {
4389 dfid.vnode = htonl(targetscp->fid.vnode);
4390 dfid.unique = htonl(targetscp->fid.unique);
4392 cm_Gen8Dot3NameInt(maskp, &dfid, shortName, &shortNameEnd);
4398 osi_Log4(smb_logp, "T2SDSingle dir vn %u uniq %u name %s (%s)",
4399 htonl(targetscp->fid.vnode),
4400 htonl(targetscp->fid.unique),
4401 osi_LogSaveString(smb_logp, pathp),
4402 NeedShortName ? osi_LogSaveString(smb_logp, shortName) : "");
4404 /* Eliminate entries that don't match requested attributes */
4405 if (smb_hideDotFiles && !(attribute & SMB_ATTR_HIDDEN) &&
4406 smb_IsDotFile(maskp)) {
4408 code = CM_ERROR_NOSUCHFILE;
4409 osi_Log0(smb_logp, "T2SDSingle skipping hidden file");
4414 if (!(attribute & SMB_ATTR_DIRECTORY) &&
4415 (targetscp->fileType == CM_SCACHETYPE_DIRECTORY ||
4416 targetscp->fileType == CM_SCACHETYPE_DFSLINK ||
4417 targetscp->fileType == CM_SCACHETYPE_INVALID)) {
4419 code = CM_ERROR_NOSUCHFILE;
4420 osi_Log0(smb_logp, "T2SDSingle skipping directory or bad link");
4425 /* Check if the name will fit */
4426 if (infoLevel < 0x101)
4427 ohbytes = 23; /* pre-NT */
4428 else if (infoLevel == SMB_FIND_FILE_NAMES_INFO)
4429 ohbytes = 12; /* NT names only */
4431 ohbytes = 64; /* NT */
4433 if (infoLevel == SMB_FIND_FILE_BOTH_DIRECTORY_INFO)
4434 ohbytes += 26; /* Short name & length */
4436 if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS) {
4437 ohbytes += 4; /* if resume key required */
4440 if (infoLevel != SMB_INFO_STANDARD
4441 && infoLevel != SMB_FIND_FILE_DIRECTORY_INFO
4442 && infoLevel != SMB_FIND_FILE_NAMES_INFO)
4443 ohbytes += 4; /* EASIZE */
4445 /* add header to name & term. null */
4446 onbytes = strlen(maskp);
4447 orbytes = ohbytes + onbytes + 1;
4449 /* now, we round up the record to a 4 byte alignment, and we make
4450 * sure that we have enough room here for even the aligned version
4451 * (so we don't have to worry about an * overflow when we pad
4452 * things out below). That's the reason for the alignment
4455 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO)
4456 align = (4 - (orbytes & 3)) & 3;
4460 if (orbytes + align > maxReturnData) {
4462 /* even though this request is unlikely to succeed with a
4463 failover, we do it anyway. */
4464 code = CM_ERROR_NOSUCHFILE;
4465 osi_Log1(smb_logp, "T2 dir search exceed max return data %d",
4470 /* this is one of the entries to use: it is not deleted and it
4471 * matches the star pattern we're looking for. Put out the name,
4472 * preceded by its length.
4474 /* First zero everything else */
4475 memset(origOp, 0, ohbytes);
4477 if (infoLevel <= SMB_FIND_FILE_DIRECTORY_INFO)
4478 *(origOp + ohbytes - 1) = (unsigned char) onbytes;
4479 else if (infoLevel == SMB_FIND_FILE_NAMES_INFO)
4480 *((u_long *)(op + 8)) = onbytes;
4482 *((u_long *)(op + 60)) = onbytes;
4483 strcpy(origOp+ohbytes, maskp);
4484 if (smb_StoreAnsiFilenames)
4485 CharToOem(origOp+ohbytes, origOp+ohbytes);
4487 /* Short name if requested and needed */
4488 if (infoLevel == SMB_FIND_FILE_BOTH_DIRECTORY_INFO) {
4489 if (NeedShortName) {
4490 strcpy(op + 70, shortName);
4491 if (smb_StoreAnsiFilenames)
4492 CharToOem(op + 70, op + 70);
4493 *(op + 68) = (char)(shortNameEnd - shortName);
4497 /* NextEntryOffset and FileIndex */
4498 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO) {
4499 int entryOffset = orbytes + align;
4500 *((u_long *)op) = 0;
4501 *((u_long *)(op+4)) = 0;
4504 if (infoLevel != SMB_FIND_FILE_NAMES_INFO) {
4505 curPatchp = malloc(sizeof(*curPatchp));
4506 osi_QAdd((osi_queue_t **) &dirListPatchesp,
4508 curPatchp->dptr = op;
4509 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO)
4510 curPatchp->dptr += 8;
4512 if (smb_hideDotFiles && smb_IsDotFile(maskp)) {
4513 curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
4515 curPatchp->flags = 0;
4518 curPatchp->fid.cell = targetscp->fid.cell;
4519 curPatchp->fid.volume = targetscp->fid.volume;
4520 curPatchp->fid.vnode = targetscp->fid.vnode;
4521 curPatchp->fid.unique = targetscp->fid.unique;
4524 curPatchp->dep = NULL;
4527 if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS) {
4528 /* put out resume key */
4529 *((u_long *)origOp) = 0;
4532 /* Adjust byte ptr and count */
4533 origOp += orbytes; /* skip entire record */
4534 bytesInBuffer += orbytes;
4536 /* and pad the record out */
4537 while (--align >= 0) {
4542 /* apply the patches */
4543 code2 = smb_ApplyV3DirListPatches(scp, &dirListPatchesp, infoLevel, userp, &req);
4545 outp->parmsp[0] = 0;
4546 outp->parmsp[1] = 1; /* number of names returned */
4547 outp->parmsp[2] = 1; /* end of search */
4548 outp->parmsp[3] = 0; /* nothing wrong with EAS */
4549 outp->parmsp[4] = 0;
4551 outp->totalParms = 10; /* in bytes */
4553 outp->totalData = bytesInBuffer;
4555 osi_Log0(smb_logp, "T2SDSingle done.");
4557 if (code != CM_ERROR_NOSUCHFILE) {
4559 smb_SendTran2Error(vcp, p, opx, code);
4561 smb_SendTran2Packet(vcp, outp, opx);
4566 smb_FreeTran2Packet(outp);
4567 cm_ReleaseSCache(scp);
4568 cm_ReleaseSCache(targetscp);
4569 cm_ReleaseUser(userp);
4575 long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
4580 long code = 0, code2 = 0;
4584 smb_dirListPatch_t *dirListPatchesp;
4585 smb_dirListPatch_t *curPatchp;
4588 long orbytes; /* # of bytes in this output record */
4589 long ohbytes; /* # of bytes, except file name */
4590 long onbytes; /* # of bytes in name, incl. term. null */
4591 osi_hyper_t dirLength;
4592 osi_hyper_t bufferOffset;
4593 osi_hyper_t curOffset;
4595 smb_dirSearch_t *dsp;
4599 cm_pageHeader_t *pageHeaderp;
4600 cm_user_t *userp = NULL;
4603 long nextEntryCookie;
4604 int numDirChunks; /* # of 32 byte dir chunks in this entry */
4605 char *op; /* output data ptr */
4606 char *origOp; /* original value of op */
4607 cm_space_t *spacep; /* for pathname buffer */
4608 long maxReturnData; /* max # of return data */
4609 long maxReturnParms; /* max # of return parms */
4610 long bytesInBuffer; /* # data bytes in the output buffer */
4612 char *maskp; /* mask part of path */
4616 smb_tran2Packet_t *outp; /* response packet */
4619 char shortName[13]; /* 8.3 name if needed */
4631 if (p->opcode == 1) {
4632 /* find first; obtain basic parameters from request */
4633 attribute = p->parmsp[0];
4634 maxCount = p->parmsp[1];
4635 infoLevel = p->parmsp[3];
4636 searchFlags = p->parmsp[2];
4637 pathp = ((char *) p->parmsp) + 12; /* points to path */
4638 if (smb_StoreAnsiFilenames)
4639 OemToChar(pathp,pathp);
4641 maskp = strrchr(pathp, '\\');
4645 maskp++; /* skip over backslash */
4647 /* track if this is likely to match a lot of entries */
4648 starPattern = smb_V3IsStarMask(maskp);
4650 #ifndef NOFINDFIRSTOPTIMIZE
4652 /* if this is for a single directory or file, we let the
4653 optimized routine handle it. The only error it
4654 returns is CM_ERROR_NOSUCHFILE. The */
4655 code = smb_T2SearchDirSingle(vcp, p, opx);
4657 /* we only failover if we see a CM_ERROR_NOSUCHFILE */
4658 if (code != CM_ERROR_NOSUCHFILE) {
4664 dsp = smb_NewDirSearch(1);
4665 dsp->attribute = attribute;
4666 strcpy(dsp->mask, maskp); /* and save mask */
4669 osi_assert(p->opcode == 2);
4670 /* find next; obtain basic parameters from request or open dir file */
4671 dsp = smb_FindDirSearch(p->parmsp[0]);
4672 maxCount = p->parmsp[1];
4673 infoLevel = p->parmsp[2];
4674 nextCookie = p->parmsp[3] | (p->parmsp[4] << 16);
4675 searchFlags = p->parmsp[5];
4677 osi_Log2(smb_logp, "T2 search dir bad search ID: id %d nextCookie 0x%x",
4678 p->parmsp[0], nextCookie);
4679 return CM_ERROR_BADFD;
4681 attribute = dsp->attribute;
4684 starPattern = 1; /* assume, since required a Find Next */
4687 switch ( infoLevel ) {
4688 case SMB_INFO_STANDARD:
4691 case SMB_INFO_QUERY_EA_SIZE:
4692 s = "InfoQueryEaSize";
4694 case SMB_INFO_QUERY_EAS_FROM_LIST:
4695 s = "InfoQueryEasFromList";
4697 case SMB_FIND_FILE_DIRECTORY_INFO:
4698 s = "FindFileDirectoryInfo";
4700 case SMB_FIND_FILE_FULL_DIRECTORY_INFO:
4701 s = "FindFileFullDirectoryInfo";
4703 case SMB_FIND_FILE_NAMES_INFO:
4704 s = "FindFileNamesInfo";
4706 case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
4707 s = "FindFileBothDirectoryInfo";
4710 s = "unknownInfoLevel";
4713 osi_Log1(smb_logp, "T2 search dir info level: %s", s);
4716 "T2 search dir attr 0x%x, info level 0x%x, max count %d, flags 0x%x",
4717 attribute, infoLevel, maxCount, searchFlags);
4719 osi_Log3(smb_logp, "...T2 search op %d, id %d, nextCookie 0x%x",
4720 p->opcode, dsp->cookie, nextCookie);
4722 if (infoLevel > SMB_FIND_FILE_BOTH_DIRECTORY_INFO) {
4723 osi_Log1(smb_logp, "Unsupported InfoLevel 0x%x", infoLevel);
4724 smb_ReleaseDirSearch(dsp);
4725 return CM_ERROR_INVAL;
4728 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO)
4729 searchFlags &= ~TRAN2_FIND_FLAG_RETURN_RESUME_KEYS; /* no resume keys */
4731 dirListPatchesp = NULL;
4733 maxReturnData = p->maxReturnData;
4734 if (p->opcode == 1) /* find first */
4735 maxReturnParms = 10; /* bytes */
4737 maxReturnParms = 8; /* bytes */
4739 #ifndef CM_CONFIG_MULTITRAN2RESPONSES
4740 if (maxReturnData > 6000)
4741 maxReturnData = 6000;
4742 #endif /* CM_CONFIG_MULTITRAN2RESPONSES */
4744 outp = smb_GetTran2ResponsePacket(vcp, p, opx, maxReturnParms,
4747 osi_Log2(smb_logp, "T2 receive search dir count %d [%s]",
4748 maxCount, osi_LogSaveString(smb_logp, pathp));
4750 /* bail out if request looks bad */
4751 if (p->opcode == 1 && !pathp) {
4752 smb_ReleaseDirSearch(dsp);
4753 smb_FreeTran2Packet(outp);
4754 return CM_ERROR_BADSMB;
4757 osi_Log3(smb_logp, "T2 search dir id %d, nextCookie 0x%x, attr 0x%x",
4758 dsp->cookie, nextCookie, attribute);
4760 userp = smb_GetTran2User(vcp, p);
4762 osi_Log1(smb_logp, "T2 search dir unable to resolve user [%d]", p->uid);
4763 smb_ReleaseDirSearch(dsp);
4764 smb_FreeTran2Packet(outp);
4765 return CM_ERROR_BADSMB;
4768 /* try to get the vnode for the path name next */
4769 lock_ObtainMutex(&dsp->mx);
4772 osi_Log2(smb_logp,"smb_ReceiveTran2SearchDir dsp 0x%p scp 0x%p", dsp, scp);
4776 spacep = cm_GetSpace();
4777 smb_StripLastComponent(spacep->data, NULL, pathp);
4778 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
4780 cm_ReleaseUser(userp);
4781 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOFILES);
4782 smb_FreeTran2Packet(outp);
4783 lock_ReleaseMutex(&dsp->mx);
4784 smb_DeleteDirSearch(dsp);
4785 smb_ReleaseDirSearch(dsp);
4788 code = cm_NameI(cm_data.rootSCachep, spacep->data,
4789 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
4790 userp, tidPathp, &req, &scp);
4791 cm_FreeSpace(spacep);
4794 #ifdef DFS_SUPPORT_BUT_NOT_FIND_FIRST
4795 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
4796 cm_ReleaseSCache(scp);
4797 cm_ReleaseUser(userp);
4798 if ( WANTS_DFS_PATHNAMES(p) )
4799 code = CM_ERROR_PATH_NOT_COVERED;
4801 code = CM_ERROR_BADSHARENAME;
4802 smb_SendTran2Error(vcp, p, opx, code);
4803 smb_FreeTran2Packet(outp);
4804 lock_ReleaseMutex(&dsp->mx);
4805 smb_DeleteDirSearch(dsp);
4806 smb_ReleaseDirSearch(dsp);
4809 #endif /* DFS_SUPPORT */
4811 osi_Log2(smb_logp,"smb_ReceiveTran2SearchDir dsp 0x%p scp 0x%p", dsp, scp);
4812 /* we need one hold for the entry we just stored into,
4813 * and one for our own processing. When we're done
4814 * with this function, we'll drop the one for our own
4815 * processing. We held it once from the namei call,
4816 * and so we do another hold now.
4819 lock_ObtainMutex(&scp->mx);
4820 if ((scp->flags & CM_SCACHEFLAG_BULKSTATTING) == 0 &&
4821 LargeIntegerGreaterOrEqualToZero(scp->bulkStatProgress)) {
4822 scp->flags |= CM_SCACHEFLAG_BULKSTATTING;
4823 dsp->flags |= SMB_DIRSEARCH_BULKST;
4825 lock_ReleaseMutex(&scp->mx);
4828 lock_ReleaseMutex(&dsp->mx);
4830 cm_ReleaseUser(userp);
4831 smb_FreeTran2Packet(outp);
4832 smb_DeleteDirSearch(dsp);
4833 smb_ReleaseDirSearch(dsp);
4837 /* get the directory size */
4838 lock_ObtainMutex(&scp->mx);
4839 code = cm_SyncOp(scp, NULL, userp, &req, 0,
4840 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4842 lock_ReleaseMutex(&scp->mx);
4843 cm_ReleaseSCache(scp);
4844 cm_ReleaseUser(userp);
4845 smb_FreeTran2Packet(outp);
4846 smb_DeleteDirSearch(dsp);
4847 smb_ReleaseDirSearch(dsp);
4851 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4854 dirLength = scp->length;
4856 bufferOffset.LowPart = bufferOffset.HighPart = 0;
4857 curOffset.HighPart = 0;
4858 curOffset.LowPart = nextCookie;
4859 origOp = outp->datap;
4867 if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS)
4868 /* skip over resume key */
4871 /* make sure that curOffset.LowPart doesn't point to the first
4872 * 32 bytes in the 2nd through last dir page, and that it doesn't
4873 * point at the first 13 32-byte chunks in the first dir page,
4874 * since those are dir and page headers, and don't contain useful
4877 temp = curOffset.LowPart & (2048-1);
4878 if (curOffset.HighPart == 0 && curOffset.LowPart < 2048) {
4879 /* we're in the first page */
4880 if (temp < 13*32) temp = 13*32;
4883 /* we're in a later dir page */
4884 if (temp < 32) temp = 32;
4887 /* make sure the low order 5 bits are zero */
4890 /* now put temp bits back ito curOffset.LowPart */
4891 curOffset.LowPart &= ~(2048-1);
4892 curOffset.LowPart |= temp;
4894 /* check if we've passed the dir's EOF */
4895 if (LargeIntegerGreaterThanOrEqualTo(curOffset, dirLength)) {
4896 osi_Log0(smb_logp, "T2 search dir passed eof");
4901 /* check if we've returned all the names that will fit in the
4902 * response packet; we check return count as well as the number
4903 * of bytes requested. We check the # of bytes after we find
4904 * the dir entry, since we'll need to check its size.
4906 if (returnedNames >= maxCount) {
4907 osi_Log2(smb_logp, "T2 search dir returnedNames %d >= maxCount %d",
4908 returnedNames, maxCount);
4912 /* see if we can use the bufferp we have now; compute in which
4913 * page the current offset would be, and check whether that's
4914 * the offset of the buffer we have. If not, get the buffer.
4916 thyper.HighPart = curOffset.HighPart;
4917 thyper.LowPart = curOffset.LowPart & ~(cm_data.buf_blockSize-1);
4918 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
4921 buf_Release(bufferp);
4924 lock_ReleaseMutex(&scp->mx);
4925 lock_ObtainRead(&scp->bufCreateLock);
4926 code = buf_Get(scp, &thyper, &bufferp);
4927 lock_ReleaseRead(&scp->bufCreateLock);
4928 lock_ObtainMutex(&dsp->mx);
4930 /* now, if we're doing a star match, do bulk fetching
4931 * of all of the status info for files in the dir.
4934 smb_ApplyV3DirListPatches(scp, &dirListPatchesp,
4937 lock_ObtainMutex(&scp->mx);
4938 if ((dsp->flags & SMB_DIRSEARCH_BULKST) &&
4939 LargeIntegerGreaterThanOrEqualTo(thyper, scp->bulkStatProgress)) {
4940 /* Don't bulk stat if risking timeout */
4941 DWORD now = GetTickCount();
4942 if (now - req.startTime > RDRtimeout) {
4943 scp->bulkStatProgress = thyper;
4944 scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
4945 dsp->flags &= ~SMB_DIRSEARCH_BULKST;
4947 code = cm_TryBulkStat(scp, &thyper, userp, &req);
4950 lock_ObtainMutex(&scp->mx);
4952 lock_ReleaseMutex(&dsp->mx);
4954 osi_Log2(smb_logp, "T2 search dir buf_Get scp %x failed %d", scp, code);
4958 bufferOffset = thyper;
4960 /* now get the data in the cache */
4962 code = cm_SyncOp(scp, bufferp, userp, &req,
4964 CM_SCACHESYNC_NEEDCALLBACK
4965 | CM_SCACHESYNC_READ);
4967 osi_Log2(smb_logp, "T2 search dir cm_SyncOp scp %x failed %d", scp, code);
4971 cm_SyncOpDone(scp, bufferp, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ);
4973 if (cm_HaveBuffer(scp, bufferp, 0)) {
4974 osi_Log2(smb_logp, "T2 search dir !HaveBuffer scp %x bufferp %x", scp, bufferp);
4978 /* otherwise, load the buffer and try again */
4979 code = cm_GetBuffer(scp, bufferp, NULL, userp,
4982 osi_Log3(smb_logp, "T2 search dir cm_GetBuffer failed scp %x bufferp %x code %d",
4983 scp, bufferp, code);
4988 buf_Release(bufferp);
4992 } /* if (wrong buffer) ... */
4994 /* now we have the buffer containing the entry we're interested
4995 * in; copy it out if it represents a non-deleted entry.
4997 entryInDir = curOffset.LowPart & (2048-1);
4998 entryInBuffer = curOffset.LowPart & (cm_data.buf_blockSize - 1);
5000 /* page header will help tell us which entries are free. Page
5001 * header can change more often than once per buffer, since
5002 * AFS 3 dir page size may be less than (but not more than)
5003 * a buffer package buffer.
5005 /* only look intra-buffer */
5006 temp = curOffset.LowPart & (cm_data.buf_blockSize - 1);
5007 temp &= ~(2048 - 1); /* turn off intra-page bits */
5008 pageHeaderp = (cm_pageHeader_t *) (bufferp->datap + temp);
5010 /* now determine which entry we're looking at in the page.
5011 * If it is free (there's a free bitmap at the start of the
5012 * dir), we should skip these 32 bytes.
5014 slotInPage = (entryInDir & 0x7e0) >> 5;
5015 if (!(pageHeaderp->freeBitmap[slotInPage>>3] &
5016 (1 << (slotInPage & 0x7)))) {
5017 /* this entry is free */
5018 numDirChunks = 1; /* only skip this guy */
5022 tp = bufferp->datap + entryInBuffer;
5023 dep = (cm_dirEntry_t *) tp; /* now points to AFS3 dir entry */
5025 /* while we're here, compute the next entry's location, too,
5026 * since we'll need it when writing out the cookie into the dir
5029 * XXXX Probably should do more sanity checking.
5031 numDirChunks = cm_NameEntries(dep->name, &onbytes);
5033 /* compute offset of cookie representing next entry */
5034 nextEntryCookie = curOffset.LowPart + (CM_DIR_CHUNKSIZE * numDirChunks);
5036 /* Need 8.3 name? */
5038 if (infoLevel == SMB_FIND_FILE_BOTH_DIRECTORY_INFO
5039 && dep->fid.vnode != 0
5040 && !cm_Is8Dot3(dep->name)) {
5041 cm_Gen8Dot3Name(dep, shortName, &shortNameEnd);
5045 osi_Log4(smb_logp, "T2 search dir vn %u uniq %u name %s (%s)",
5046 dep->fid.vnode, dep->fid.unique,
5047 osi_LogSaveString(smb_logp, dep->name),
5048 NeedShortName ? osi_LogSaveString(smb_logp, shortName) : "");
5050 /* When matching, we are using doing a case fold if we have a wildcard mask.
5051 * If we get a non-wildcard match, it's a lookup for a specific file.
5053 if (dep->fid.vnode != 0 &&
5054 (smb_V3MatchMask(dep->name, maskp, (starPattern? CM_FLAG_CASEFOLD : 0)) ||
5056 smb_V3MatchMask(shortName, maskp, CM_FLAG_CASEFOLD)))) {
5058 /* Eliminate entries that don't match requested attributes */
5059 if (smb_hideDotFiles && !(dsp->attribute & SMB_ATTR_HIDDEN) &&
5060 smb_IsDotFile(dep->name)) {
5061 osi_Log0(smb_logp, "T2 search dir skipping hidden");
5062 goto nextEntry; /* no hidden files */
5064 if (!(dsp->attribute & SMB_ATTR_DIRECTORY)) /* no directories */
5066 /* We have already done the cm_TryBulkStat above */
5067 fid.cell = scp->fid.cell;
5068 fid.volume = scp->fid.volume;
5069 fid.vnode = ntohl(dep->fid.vnode);
5070 fid.unique = ntohl(dep->fid.unique);
5071 fileType = cm_FindFileType(&fid);
5072 /*osi_Log2(smb_logp, "smb_ReceiveTran2SearchDir: file %s "
5073 "has filetype %d", dep->name,
5075 if (fileType == CM_SCACHETYPE_DIRECTORY ||
5076 fileType == CM_SCACHETYPE_DFSLINK ||
5077 fileType == CM_SCACHETYPE_INVALID)
5078 osi_Log0(smb_logp, "T2 search dir skipping directory or bad link");
5082 /* finally check if this name will fit */
5084 /* standard dir entry stuff */
5085 if (infoLevel < 0x101)
5086 ohbytes = 23; /* pre-NT */
5087 else if (infoLevel == SMB_FIND_FILE_NAMES_INFO)
5088 ohbytes = 12; /* NT names only */
5090 ohbytes = 64; /* NT */
5092 if (infoLevel == SMB_FIND_FILE_BOTH_DIRECTORY_INFO)
5093 ohbytes += 26; /* Short name & length */
5095 if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS) {
5096 ohbytes += 4; /* if resume key required */
5099 if (infoLevel != SMB_INFO_STANDARD
5100 && infoLevel != SMB_FIND_FILE_DIRECTORY_INFO
5101 && infoLevel != SMB_FIND_FILE_NAMES_INFO)
5102 ohbytes += 4; /* EASIZE */
5104 /* add header to name & term. null */
5105 orbytes = onbytes + ohbytes + 1;
5107 /* now, we round up the record to a 4 byte alignment,
5108 * and we make sure that we have enough room here for
5109 * even the aligned version (so we don't have to worry
5110 * about an * overflow when we pad things out below).
5111 * That's the reason for the alignment arithmetic below.
5113 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO)
5114 align = (4 - (orbytes & 3)) & 3;
5117 if (orbytes + bytesInBuffer + align > maxReturnData) {
5118 osi_Log1(smb_logp, "T2 dir search exceed max return data %d",
5123 /* this is one of the entries to use: it is not deleted
5124 * and it matches the star pattern we're looking for.
5125 * Put out the name, preceded by its length.
5127 /* First zero everything else */
5128 memset(origOp, 0, ohbytes);
5130 if (infoLevel <= SMB_FIND_FILE_DIRECTORY_INFO)
5131 *(origOp + ohbytes - 1) = (unsigned char) onbytes;
5132 else if (infoLevel == SMB_FIND_FILE_NAMES_INFO)
5133 *((u_long *)(op + 8)) = onbytes;
5135 *((u_long *)(op + 60)) = onbytes;
5136 strcpy(origOp+ohbytes, dep->name);
5137 if (smb_StoreAnsiFilenames)
5138 CharToOem(origOp+ohbytes, origOp+ohbytes);
5140 /* Short name if requested and needed */
5141 if (infoLevel == SMB_FIND_FILE_BOTH_DIRECTORY_INFO) {
5142 if (NeedShortName) {
5143 strcpy(op + 70, shortName);
5144 if (smb_StoreAnsiFilenames)
5145 CharToOem(op + 70, op + 70);
5146 *(op + 68) = (char)(shortNameEnd - shortName);
5150 /* now, adjust the # of entries copied */
5153 /* NextEntryOffset and FileIndex */
5154 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO) {
5155 int entryOffset = orbytes + align;
5156 *((u_long *)op) = entryOffset;
5157 *((u_long *)(op+4)) = nextEntryCookie;
5160 /* now we emit the attribute. This is tricky, since
5161 * we need to really stat the file to find out what
5162 * type of entry we've got. Right now, we're copying
5163 * out data from a buffer, while holding the scp
5164 * locked, so it isn't really convenient to stat
5165 * something now. We'll put in a place holder
5166 * now, and make a second pass before returning this
5167 * to get the real attributes. So, we just skip the
5168 * data for now, and adjust it later. We allocate a
5169 * patch record to make it easy to find this point
5170 * later. The replay will happen at a time when it is
5171 * safe to unlock the directory.
5173 if (infoLevel != SMB_FIND_FILE_NAMES_INFO) {
5174 curPatchp = malloc(sizeof(*curPatchp));
5175 osi_QAdd((osi_queue_t **) &dirListPatchesp,
5177 curPatchp->dptr = op;
5178 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO)
5179 curPatchp->dptr += 8;
5181 if (smb_hideDotFiles && smb_IsDotFile(dep->name)) {
5182 curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
5185 curPatchp->flags = 0;
5187 curPatchp->fid.cell = scp->fid.cell;
5188 curPatchp->fid.volume = scp->fid.volume;
5189 curPatchp->fid.vnode = ntohl(dep->fid.vnode);
5190 curPatchp->fid.unique = ntohl(dep->fid.unique);
5193 curPatchp->dep = dep;
5196 if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS)
5197 /* put out resume key */
5198 *((u_long *)origOp) = nextEntryCookie;
5200 /* Adjust byte ptr and count */
5201 origOp += orbytes; /* skip entire record */
5202 bytesInBuffer += orbytes;
5204 /* and pad the record out */
5205 while (--align >= 0) {
5209 } /* if we're including this name */
5210 else if (!starPattern &&
5212 dep->fid.vnode != 0 &&
5213 smb_V3MatchMask(dep->name, maskp, CM_FLAG_CASEFOLD)) {
5214 /* We were looking for exact matches, but here's an inexact one*/
5219 /* and adjust curOffset to be where the new cookie is */
5220 thyper.HighPart = 0;
5221 thyper.LowPart = CM_DIR_CHUNKSIZE * numDirChunks;
5222 curOffset = LargeIntegerAdd(thyper, curOffset);
5223 } /* while copying data for dir listing */
5225 /* If we didn't get a star pattern, we did an exact match during the first pass.
5226 * If there were no exact matches found, we fail over to inexact matches by
5227 * marking the query as a star pattern (matches all case permutations), and
5228 * re-running the query.
5230 if (returnedNames == 0 && !starPattern && foundInexact) {
5231 osi_Log0(smb_logp,"T2 Search: No exact matches. Re-running for inexact matches");
5236 /* release the mutex */
5237 lock_ReleaseMutex(&scp->mx);
5239 buf_Release(bufferp);
5243 /* apply and free last set of patches; if not doing a star match, this
5244 * will be empty, but better safe (and freeing everything) than sorry.
5246 code2 = smb_ApplyV3DirListPatches(scp, &dirListPatchesp, infoLevel, userp,
5249 /* now put out the final parameters */
5250 if (returnedNames == 0)
5252 if (p->opcode == 1) {
5254 outp->parmsp[0] = (unsigned short) dsp->cookie;
5255 outp->parmsp[1] = returnedNames;
5256 outp->parmsp[2] = eos;
5257 outp->parmsp[3] = 0; /* nothing wrong with EAS */
5258 outp->parmsp[4] = 0;
5259 /* don't need last name to continue
5260 * search, cookie is enough. Normally,
5261 * this is the offset of the file name
5262 * of the last entry returned.
5264 outp->totalParms = 10; /* in bytes */
5268 outp->parmsp[0] = returnedNames;
5269 outp->parmsp[1] = eos;
5270 outp->parmsp[2] = 0; /* EAS error */
5271 outp->parmsp[3] = 0; /* last name, as above */
5272 outp->totalParms = 8; /* in bytes */
5275 /* return # of bytes in the buffer */
5276 outp->totalData = bytesInBuffer;
5278 /* Return error code if unsuccessful on first request */
5279 if (code == 0 && p->opcode == 1 && returnedNames == 0)
5280 code = CM_ERROR_NOSUCHFILE;
5282 osi_Log4(smb_logp, "T2 search dir done, opcode %d, id %d, %d names, code %d",
5283 p->opcode, dsp->cookie, returnedNames, code);
5285 /* if we're supposed to close the search after this request, or if
5286 * we're supposed to close the search if we're done, and we're done,
5287 * or if something went wrong, close the search.
5289 if ((searchFlags & TRAN2_FIND_FLAG_CLOSE_SEARCH) ||
5290 (returnedNames == 0) ||
5291 ((searchFlags & TRAN2_FIND_FLAG_CLOSE_SEARCH_IF_END) && eos) ||
5293 smb_DeleteDirSearch(dsp);
5296 smb_SendTran2Error(vcp, p, opx, code);
5298 smb_SendTran2Packet(vcp, outp, opx);
5300 smb_FreeTran2Packet(outp);
5301 smb_ReleaseDirSearch(dsp);
5302 cm_ReleaseSCache(scp);
5303 cm_ReleaseUser(userp);
5307 long smb_ReceiveV3FindClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5310 smb_dirSearch_t *dsp;
5312 dirHandle = smb_GetSMBParm(inp, 0);
5314 osi_Log1(smb_logp, "SMB3 find close handle %d", dirHandle);
5316 dsp = smb_FindDirSearch(dirHandle);
5319 return CM_ERROR_BADFD;
5321 /* otherwise, we have an FD to destroy */
5322 smb_DeleteDirSearch(dsp);
5323 smb_ReleaseDirSearch(dsp);
5325 /* and return results */
5326 smb_SetSMBDataLength(outp, 0);
5331 long smb_ReceiveV3FindNotifyClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5333 smb_SetSMBDataLength(outp, 0);
5337 long smb_ReceiveV3OpenX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5344 cm_scache_t *dscp; /* dir we're dealing with */
5345 cm_scache_t *scp; /* file we're creating */
5347 int initialModeBits;
5357 int parmSlot; /* which parm we're dealing with */
5366 extraInfo = (smb_GetSMBParm(inp, 2) & 1); /* return extra info */
5367 openFun = smb_GetSMBParm(inp, 8); /* open function */
5368 excl = ((openFun & 3) == 0);
5369 trunc = ((openFun & 3) == 2); /* truncate it */
5370 openMode = (smb_GetSMBParm(inp, 3) & 0x7);
5371 openAction = 0; /* tracks what we did */
5373 attributes = smb_GetSMBParm(inp, 5);
5374 dosTime = smb_GetSMBParm(inp, 6) | (smb_GetSMBParm(inp, 7) << 16);
5376 /* compute initial mode bits based on read-only flag in attributes */
5377 initialModeBits = 0666;
5378 if (attributes & SMB_ATTR_READONLY)
5379 initialModeBits &= ~0222;
5381 pathp = smb_GetSMBData(inp, NULL);
5382 if (smb_StoreAnsiFilenames)
5383 OemToChar(pathp,pathp);
5385 spacep = inp->spacep;
5386 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
5388 if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
5389 /* special case magic file name for receiving IOCTL requests
5390 * (since IOCTL calls themselves aren't getting through).
5393 osi_Log0(smb_logp, "IOCTL Open");
5396 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
5397 smb_SetupIoctlFid(fidp, spacep);
5399 /* set inp->fid so that later read calls in same msg can find fid */
5400 inp->fid = fidp->fid;
5402 /* copy out remainder of the parms */
5404 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
5406 smb_SetSMBParm(outp, parmSlot, /* attrs */ 0); parmSlot++;
5407 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* mod time */
5408 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
5409 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* len */
5410 smb_SetSMBParm(outp, parmSlot, 0x7fff); parmSlot++;
5411 smb_SetSMBParm(outp, parmSlot, openMode); parmSlot++;
5412 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* file type 0 ==> normal file or dir */
5413 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* IPC junk */
5415 /* and the final "always present" stuff */
5416 smb_SetSMBParm(outp, parmSlot, /* openAction found existing file */ 1); parmSlot++;
5417 /* next write out the "unique" ID */
5418 smb_SetSMBParm(outp, parmSlot, 0x1234); parmSlot++;
5419 smb_SetSMBParm(outp, parmSlot, 0x5678); parmSlot++;
5420 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
5421 smb_SetSMBDataLength(outp, 0);
5423 /* and clean up fid reference */
5424 smb_ReleaseFID(fidp);
5428 #ifdef DEBUG_VERBOSE
5430 char *hexp, *asciip;
5431 asciip = (lastNamep ? lastNamep : pathp );
5432 hexp = osi_HexifyString(asciip);
5433 DEBUG_EVENT2("AFS", "V3Open H[%s] A[%s]", hexp, asciip );
5437 userp = smb_GetUserFromVCP(vcp, inp);
5440 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5442 cm_ReleaseUser(userp);
5443 return CM_ERROR_NOSUCHPATH;
5445 code = cm_NameI(cm_data.rootSCachep, pathp,
5446 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
5447 userp, tidPathp, &req, &scp);
5450 if (code == 0 && scp->fileType == CM_SCACHETYPE_DFSLINK) {
5451 cm_ReleaseSCache(scp);
5452 cm_ReleaseUser(userp);
5453 if ( WANTS_DFS_PATHNAMES(inp) )
5454 return CM_ERROR_PATH_NOT_COVERED;
5456 return CM_ERROR_BADSHARENAME;
5458 #endif /* DFS_SUPPORT */
5461 code = cm_NameI(cm_data.rootSCachep, spacep->data,
5462 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
5463 userp, tidPathp, &req, &dscp);
5465 cm_ReleaseUser(userp);
5470 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
5471 cm_ReleaseSCache(dscp);
5472 cm_ReleaseUser(userp);
5473 if ( WANTS_DFS_PATHNAMES(inp) )
5474 return CM_ERROR_PATH_NOT_COVERED;
5476 return CM_ERROR_BADSHARENAME;
5478 #endif /* DFS_SUPPORT */
5479 /* otherwise, scp points to the parent directory. Do a lookup,
5480 * and truncate the file if we find it, otherwise we create the
5487 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD, userp,
5489 if (code && code != CM_ERROR_NOSUCHFILE) {
5490 cm_ReleaseSCache(dscp);
5491 cm_ReleaseUser(userp);
5496 /* if we get here, if code is 0, the file exists and is represented by
5497 * scp. Otherwise, we have to create it. The dir may be represented
5498 * by dscp, or we may have found the file directly. If code is non-zero,
5502 code = cm_CheckOpen(scp, openMode, trunc, userp, &req);
5504 if (dscp) cm_ReleaseSCache(dscp);
5505 cm_ReleaseSCache(scp);
5506 cm_ReleaseUser(userp);
5511 /* oops, file shouldn't be there */
5513 cm_ReleaseSCache(dscp);
5514 cm_ReleaseSCache(scp);
5515 cm_ReleaseUser(userp);
5516 return CM_ERROR_EXISTS;
5520 setAttr.mask = CM_ATTRMASK_LENGTH;
5521 setAttr.length.LowPart = 0;
5522 setAttr.length.HighPart = 0;
5523 code = cm_SetAttr(scp, &setAttr, userp, &req);
5524 openAction = 3; /* truncated existing file */
5526 else openAction = 1; /* found existing file */
5528 else if (!(openFun & SMB_ATTR_DIRECTORY)) {
5529 /* don't create if not found */
5530 if (dscp) cm_ReleaseSCache(dscp);
5531 cm_ReleaseUser(userp);
5532 return CM_ERROR_NOSUCHFILE;
5535 osi_assert(dscp != NULL);
5536 osi_Log1(smb_logp, "smb_ReceiveV3OpenX creating file %s",
5537 osi_LogSaveString(smb_logp, lastNamep));
5538 openAction = 2; /* created file */
5539 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
5540 smb_UnixTimeFromDosUTime(&setAttr.clientModTime, dosTime);
5541 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
5545 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
5546 smb_NotifyChange(FILE_ACTION_ADDED,
5547 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
5548 dscp, lastNamep, NULL, TRUE);
5549 } else if (!excl && code == CM_ERROR_EXISTS) {
5550 /* not an exclusive create, and someone else tried
5551 * creating it already, then we open it anyway. We
5552 * don't bother retrying after this, since if this next
5553 * fails, that means that the file was deleted after we
5554 * started this call.
5556 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
5560 setAttr.mask = CM_ATTRMASK_LENGTH;
5561 setAttr.length.LowPart = 0;
5562 setAttr.length.HighPart = 0;
5563 code = cm_SetAttr(scp, &setAttr, userp, &req);
5565 } /* lookup succeeded */
5569 /* we don't need this any longer */
5571 cm_ReleaseSCache(dscp);
5574 /* something went wrong creating or truncating the file */
5576 cm_ReleaseSCache(scp);
5577 cm_ReleaseUser(userp);
5581 /* make sure we're about to open a file */
5582 if (scp->fileType != CM_SCACHETYPE_FILE) {
5583 cm_ReleaseSCache(scp);
5584 cm_ReleaseUser(userp);
5585 return CM_ERROR_ISDIR;
5588 /* now all we have to do is open the file itself */
5589 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
5593 lock_ObtainMutex(&fidp->mx);
5594 /* save a pointer to the vnode */
5596 lock_ObtainMutex(&scp->mx);
5597 scp->flags |= CM_SCACHEFLAG_SMB_FID;
5598 lock_ReleaseMutex(&scp->mx);
5599 osi_Log2(smb_logp,"smb_ReceiveV3OpenX fidp 0x%p scp 0x%p", fidp, scp);
5601 fidp->userp = userp;
5603 /* compute open mode */
5605 fidp->flags |= SMB_FID_OPENREAD_LISTDIR;
5606 if (openMode == 1 || openMode == 2)
5607 fidp->flags |= SMB_FID_OPENWRITE;
5609 /* remember if the file was newly created */
5611 fidp->flags |= SMB_FID_CREATED;
5613 lock_ReleaseMutex(&fidp->mx);
5614 smb_ReleaseFID(fidp);
5616 cm_Open(scp, 0, userp);
5618 /* set inp->fid so that later read calls in same msg can find fid */
5619 inp->fid = fidp->fid;
5621 /* copy out remainder of the parms */
5623 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
5624 lock_ObtainMutex(&scp->mx);
5626 smb_SetSMBParm(outp, parmSlot, smb_Attributes(scp)); parmSlot++;
5627 smb_DosUTimeFromUnixTime(&dosTime, scp->clientModTime);
5628 smb_SetSMBParm(outp, parmSlot, dosTime & 0xffff); parmSlot++;
5629 smb_SetSMBParm(outp, parmSlot, (dosTime>>16) & 0xffff); parmSlot++;
5630 smb_SetSMBParm(outp, parmSlot, scp->length.LowPart & 0xffff); parmSlot++;
5631 smb_SetSMBParm(outp, parmSlot, (scp->length.LowPart >> 16) & 0xffff); parmSlot++;
5632 smb_SetSMBParm(outp, parmSlot, openMode); parmSlot++;
5633 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* file type 0 ==> normal file or dir */
5634 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* IPC junk */
5636 /* and the final "always present" stuff */
5637 smb_SetSMBParm(outp, parmSlot, openAction); parmSlot++;
5638 /* next write out the "unique" ID */
5639 smb_SetSMBParm(outp, parmSlot, scp->fid.vnode & 0xffff); parmSlot++;
5640 smb_SetSMBParm(outp, parmSlot, scp->fid.volume & 0xffff); parmSlot++;
5641 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
5642 lock_ReleaseMutex(&scp->mx);
5643 smb_SetSMBDataLength(outp, 0);
5645 osi_Log1(smb_logp, "SMB OpenX opening fid %d", fidp->fid);
5647 cm_ReleaseUser(userp);
5648 /* leave scp held since we put it in fidp->scp */
5652 static void smb_GetLockParams(unsigned char LockType,
5654 unsigned int * ppid,
5655 LARGE_INTEGER * pOffset,
5656 LARGE_INTEGER * pLength)
5658 if (LockType & LOCKING_ANDX_LARGE_FILES) {
5660 *ppid = *((USHORT *) *buf);
5661 pOffset->HighPart = *((LONG *)(*buf + 4));
5662 pOffset->LowPart = *((DWORD *)(*buf + 8));
5663 pLength->HighPart = *((LONG *)(*buf + 12));
5664 pLength->LowPart = *((DWORD *)(*buf + 16));
5668 /* Not Large Files */
5669 *ppid = *((USHORT *) *buf);
5670 pOffset->HighPart = 0;
5671 pOffset->LowPart = *((DWORD *)(*buf + 2));
5672 pLength->HighPart = 0;
5673 pLength->LowPart = *((DWORD *)(*buf + 6));
5678 long smb_ReceiveV3LockingX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5685 unsigned char LockType;
5686 unsigned short NumberOfUnlocks, NumberOfLocks;
5690 LARGE_INTEGER LOffset, LLength;
5691 smb_waitingLockRequest_t *wlRequest = NULL;
5692 cm_file_lock_t *lockp;
5700 fid = smb_GetSMBParm(inp, 2);
5701 fid = smb_ChainFID(fid, inp);
5703 fidp = smb_FindFID(vcp, fid, 0);
5705 return CM_ERROR_BADFD;
5707 lock_ObtainMutex(&fidp->mx);
5708 if (fidp->flags & SMB_FID_IOCTL) {
5709 osi_Log0(smb_logp, "smb_ReceiveV3Locking BadFD");
5710 lock_ReleaseMutex(&fidp->mx);
5711 smb_ReleaseFID(fidp);
5712 return CM_ERROR_BADFD;
5715 osi_Log2(smb_logp,"smb_ReceiveV3LockingX fidp 0x%p scp 0x%p", fidp, scp);
5717 lock_ReleaseMutex(&fidp->mx);
5719 /* set inp->fid so that later read calls in same msg can find fid */
5722 userp = smb_GetUserFromVCP(vcp, inp);
5725 lock_ObtainMutex(&scp->mx);
5726 code = cm_SyncOp(scp, NULL, userp, &req, 0,
5727 CM_SCACHESYNC_NEEDCALLBACK
5728 | CM_SCACHESYNC_GETSTATUS
5729 | CM_SCACHESYNC_LOCK);
5731 osi_Log1(smb_logp, "smb_ReceiveV3Locking SyncOp failure code 0x%x", code);
5735 LockType = smb_GetSMBParm(inp, 3) & 0xff;
5736 Timeout = (smb_GetSMBParm(inp, 5) << 16) + smb_GetSMBParm(inp, 4);
5737 NumberOfUnlocks = smb_GetSMBParm(inp, 6);
5738 NumberOfLocks = smb_GetSMBParm(inp, 7);
5740 if (!(fidp->flags & SMB_FID_OPENWRITE) &&
5741 !(LockType & LOCKING_ANDX_SHARED_LOCK)) {
5742 /* somebody wants exclusive locks on a file that they only
5743 opened for reading. We downgrade this to a shared lock. */
5744 osi_Log0(smb_logp, "smb_ReceiveV3Locking reinterpreting exclusive lock as shared for read-only fid");
5745 LockType |= LOCKING_ANDX_SHARED_LOCK;
5748 if ((LockType & LOCKING_ANDX_CANCEL_LOCK) ||
5749 (LockType & LOCKING_ANDX_CHANGE_LOCKTYPE)) {
5751 /* We don't support these requests. Apparently, we can safely
5752 not deal with them too. */
5753 osi_Log1(smb_logp, "smb_ReceiveV3Locking received unsupported request [%s]",
5754 ((LockType & LOCKING_ANDX_CANCEL_LOCK)?
5755 "LOCKING_ANDX_CANCEL_LOCK":
5756 "LOCKING_ANDX_CHANGE_LOCKTYPE"));
5757 /* No need to call osi_LogSaveString since these are string
5760 code = CM_ERROR_BADOP;
5765 op = smb_GetSMBData(inp, NULL);
5767 for (i=0; i<NumberOfUnlocks; i++) {
5768 smb_GetLockParams(LockType, &op, &pid, &LOffset, &LLength);
5770 key = cm_GenerateKey(vcp->vcID, pid, fidp->fid);
5772 code = cm_Unlock(scp, LockType, LOffset, LLength, key, userp, &req);
5780 for (i=0; i<NumberOfLocks; i++) {
5781 smb_GetLockParams(LockType, &op, &pid, &LOffset, &LLength);
5783 key = cm_GenerateKey(vcp->vcID, pid, fidp->fid);
5785 code = cm_Lock(scp, LockType, LOffset, LLength, key, (Timeout != 0),
5786 userp, &req, &lockp);
5788 if (code == CM_ERROR_NOACCESS && LockType == LockWrite &&
5789 (fidp->flags & (SMB_FID_OPENREAD_LISTDIR | SMB_FID_OPENWRITE)) == SMB_FID_OPENREAD_LISTDIR)
5791 code = cm_Lock(scp, LockRead, LOffset, LLength, key, (Timeout != 0),
5792 userp, &req, &lockp);
5795 if (code == CM_ERROR_WOULDBLOCK && Timeout != 0) {
5796 smb_waitingLock_t * wLock;
5798 /* Put on waiting list */
5799 if(wlRequest == NULL) {
5803 LARGE_INTEGER tOffset, tLength;
5805 wlRequest = malloc(sizeof(smb_waitingLockRequest_t));
5807 osi_assert(wlRequest != NULL);
5809 wlRequest->vcp = vcp;
5811 wlRequest->scp = scp;
5812 osi_Log2(smb_logp,"smb_ReceiveV3LockingX wlRequest 0x%p scp 0x%p", wlRequest, scp);
5814 wlRequest->inp = smb_CopyPacket(inp);
5815 wlRequest->outp = smb_CopyPacket(outp);
5816 wlRequest->lockType = LockType;
5817 wlRequest->timeRemaining = Timeout;
5818 wlRequest->locks = NULL;
5820 /* The waiting lock request needs to have enough
5821 information to undo all the locks in the request.
5822 We do the following to store info about locks that
5823 have already been granted. Sure, we can get most
5824 of the info from the packet, but the packet doesn't
5825 hold the result of cm_Lock call. In practice we
5826 only receive packets with one or two locks, so we
5827 are only wasting a few bytes here and there and
5828 only for a limited period of time until the waiting
5829 lock times out or is freed. */
5831 for(opt = op_locks, j=i; j > 0; j--) {
5832 smb_GetLockParams(LockType, &opt, &pid, &tOffset, &tLength);
5834 tkey = cm_GenerateKey(vcp->vcID, pid, fidp->fid);
5836 wLock = malloc(sizeof(smb_waitingLock_t));
5838 osi_assert(wLock != NULL);
5841 wLock->LOffset = tOffset;
5842 wLock->LLength = tLength;
5843 wLock->lockp = NULL;
5844 wLock->state = SMB_WAITINGLOCKSTATE_DONE;
5845 osi_QAdd((osi_queue_t **) &wlRequest->locks,
5850 wLock = malloc(sizeof(smb_waitingLock_t));
5852 osi_assert(wLock != NULL);
5855 wLock->LOffset = LOffset;
5856 wLock->LLength = LLength;
5857 wLock->lockp = lockp;
5858 wLock->state = SMB_WAITINGLOCKSTATE_WAITING;
5859 osi_QAdd((osi_queue_t **) &wlRequest->locks,
5862 osi_Log1(smb_logp, "smb_ReceiveV3Locking WaitingLock created 0x%p",
5870 osi_Log1(smb_logp, "smb_ReceiveV3Locking cm_Lock failure code 0x%x", code);
5877 /* Since something went wrong with the lock number i, we now
5878 have to go ahead and release any locks acquired before the
5879 failure. All locks before lock number i (of which there
5880 are i of them) have either been successful or are waiting.
5881 Either case requires calling cm_Unlock(). */
5883 /* And purge the waiting lock */
5884 if(wlRequest != NULL) {
5885 smb_waitingLock_t * wl;
5886 smb_waitingLock_t * wlNext;
5889 for(wl = wlRequest->locks; wl; wl = wlNext) {
5891 wlNext = (smb_waitingLock_t *) osi_QNext(&wl->q);
5893 ul_code = cm_Unlock(scp, LockType, wl->LOffset, wl->LLength, wl->key, userp, &req);
5896 osi_Log1(smb_logp, "smb_ReceiveV3Locking cm_Unlock returns code %d", ul_code);
5898 osi_Log0(smb_logp, "smb_ReceiveV3Locking cm_Unlock successful");
5901 osi_QRemove((osi_queue_t **) &wlRequest->locks, &wl->q);
5906 smb_ReleaseVC(wlRequest->vcp);
5907 cm_ReleaseSCache(wlRequest->scp);
5908 smb_FreePacket(wlRequest->inp);
5909 smb_FreePacket(wlRequest->outp);
5918 if (wlRequest != NULL) {
5920 lock_ObtainWrite(&smb_globalLock);
5921 osi_QAdd((osi_queue_t **)&smb_allWaitingLocks,
5923 osi_Wakeup((LONG_PTR)&smb_allWaitingLocks);
5924 lock_ReleaseWrite(&smb_globalLock);
5926 /* don't send reply immediately */
5927 outp->flags |= SMB_PACKETFLAG_NOSEND;
5930 smb_SetSMBDataLength(outp, 0);
5934 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_LOCK);
5937 lock_ReleaseMutex(&scp->mx);
5938 cm_ReleaseSCache(scp);
5939 cm_ReleaseUser(userp);
5940 smb_ReleaseFID(fidp);
5945 long smb_ReceiveV3GetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5951 afs_uint32 searchTime;
5957 fid = smb_GetSMBParm(inp, 0);
5958 fid = smb_ChainFID(fid, inp);
5960 fidp = smb_FindFID(vcp, fid, 0);
5962 return CM_ERROR_BADFD;
5964 lock_ObtainMutex(&fidp->mx);
5965 if (fidp->flags & SMB_FID_IOCTL) {
5966 lock_ReleaseMutex(&fidp->mx);
5967 smb_ReleaseFID(fidp);
5968 return CM_ERROR_BADFD;
5971 osi_Log2(smb_logp,"smb_ReceiveV3GetAttributes fidp 0x%p scp 0x%p", fidp, scp);
5973 lock_ReleaseMutex(&fidp->mx);
5975 userp = smb_GetUserFromVCP(vcp, inp);
5978 /* otherwise, stat the file */
5979 lock_ObtainMutex(&scp->mx);
5980 code = cm_SyncOp(scp, NULL, userp, &req, 0,
5981 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5985 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5987 /* decode times. We need a search time, but the response to this
5988 * call provides the date first, not the time, as returned in the
5989 * searchTime variable. So we take the high-order bits first.
5991 smb_SearchTimeFromUnixTime(&searchTime, scp->clientModTime);
5992 smb_SetSMBParm(outp, 0, (searchTime >> 16) & 0xffff); /* ctime */
5993 smb_SetSMBParm(outp, 1, searchTime & 0xffff);
5994 smb_SetSMBParm(outp, 2, (searchTime >> 16) & 0xffff); /* atime */
5995 smb_SetSMBParm(outp, 3, searchTime & 0xffff);
5996 smb_SetSMBParm(outp, 4, (searchTime >> 16) & 0xffff); /* mtime */
5997 smb_SetSMBParm(outp, 5, searchTime & 0xffff);
5999 /* now handle file size and allocation size */
6000 smb_SetSMBParm(outp, 6, scp->length.LowPart & 0xffff); /* file size */
6001 smb_SetSMBParm(outp, 7, (scp->length.LowPart >> 16) & 0xffff);
6002 smb_SetSMBParm(outp, 8, scp->length.LowPart & 0xffff); /* alloc size */
6003 smb_SetSMBParm(outp, 9, (scp->length.LowPart >> 16) & 0xffff);
6005 /* file attribute */
6006 smb_SetSMBParm(outp, 10, smb_Attributes(scp));
6008 /* and finalize stuff */
6009 smb_SetSMBDataLength(outp, 0);
6013 lock_ReleaseMutex(&scp->mx);
6014 cm_ReleaseSCache(scp);
6015 cm_ReleaseUser(userp);
6016 smb_ReleaseFID(fidp);
6020 long smb_ReceiveV3SetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6026 afs_uint32 searchTime;
6034 fid = smb_GetSMBParm(inp, 0);
6035 fid = smb_ChainFID(fid, inp);
6037 fidp = smb_FindFID(vcp, fid, 0);
6039 return CM_ERROR_BADFD;
6041 lock_ObtainMutex(&fidp->mx);
6042 if (fidp->flags & SMB_FID_IOCTL) {
6043 lock_ReleaseMutex(&fidp->mx);
6044 smb_ReleaseFID(fidp);
6045 return CM_ERROR_BADFD;
6048 osi_Log2(smb_logp,"smb_ReceiveV3SetAttributes fidp 0x%p scp 0x%p", fidp, scp);
6050 lock_ReleaseMutex(&fidp->mx);
6052 userp = smb_GetUserFromVCP(vcp, inp);
6055 /* now prepare to call cm_setattr. This message only sets various times,
6056 * and AFS only implements mtime, and we'll set the mtime if that's
6057 * requested. The others we'll ignore.
6059 searchTime = smb_GetSMBParm(inp, 5) | (smb_GetSMBParm(inp, 6) << 16);
6061 if (searchTime != 0) {
6062 smb_UnixTimeFromSearchTime(&unixTime, searchTime);
6064 if ( unixTime != -1 ) {
6065 attrs.mask = CM_ATTRMASK_CLIENTMODTIME;
6066 attrs.clientModTime = unixTime;
6067 code = cm_SetAttr(scp, &attrs, userp, &req);
6069 osi_Log1(smb_logp, "SMB receive V3SetAttributes [fid=%ld]", fid);
6071 osi_Log1(smb_logp, "**smb_UnixTimeFromSearchTime failed searchTime=%ld", searchTime);
6077 cm_ReleaseSCache(scp);
6078 cm_ReleaseUser(userp);
6079 smb_ReleaseFID(fidp);
6083 long smb_ReceiveV3WriteX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6086 long count, written = 0, total_written = 0;
6093 int inDataBlockCount;
6095 fd = smb_GetSMBParm(inp, 2);
6096 count = smb_GetSMBParm(inp, 10);
6098 offset.HighPart = 0;
6099 offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
6101 if (*inp->wctp == 14) {
6102 /* we have a request with 64-bit file offsets */
6103 #ifdef AFS_LARGEFILES
6104 offset.HighPart = smb_GetSMBParm(inp, 12) | (smb_GetSMBParm(inp, 13) << 16);
6106 if ((smb_GetSMBParm(inp, 12) | (smb_GetSMBParm(inp, 13) << 16)) != 0) {
6108 osi_Log0(smb_logp, "smb_ReceiveV3WriteX offset requires largefile support");
6109 /* we shouldn't have received this op if we didn't specify
6110 largefile support */
6111 return CM_ERROR_BADOP;
6116 op = inp->data + smb_GetSMBParm(inp, 11);
6117 inDataBlockCount = count;
6119 osi_Log4(smb_logp, "smb_ReceiveV3WriteX fid %d, off 0x%x:%08x, size 0x%x",
6120 fd, offset.HighPart, offset.LowPart, count);
6122 fd = smb_ChainFID(fd, inp);
6123 fidp = smb_FindFID(vcp, fd, 0);
6125 return CM_ERROR_BADFD;
6127 lock_ObtainMutex(&fidp->mx);
6128 if (fidp->flags & SMB_FID_IOCTL) {
6129 lock_ReleaseMutex(&fidp->mx);
6130 code = smb_IoctlV3Write(fidp, vcp, inp, outp);
6131 smb_ReleaseFID(fidp);
6134 lock_ReleaseMutex(&fidp->mx);
6135 userp = smb_GetUserFromVCP(vcp, inp);
6137 /* special case: 0 bytes transferred means there is no data
6138 transferred. A slight departure from SMB_COM_WRITE where this
6139 means that we are supposed to truncate the file at this
6144 LARGE_INTEGER LOffset;
6145 LARGE_INTEGER LLength;
6147 pid = ((smb_t *) inp)->pid;
6148 key = cm_GenerateKey(vcp->vcID, pid, fd);
6150 LOffset.HighPart = offset.HighPart;
6151 LOffset.LowPart = offset.LowPart;
6152 LLength.HighPart = 0;
6153 LLength.LowPart = count;
6155 lock_ObtainMutex(&fidp->scp->mx);
6156 code = cm_LockCheckWrite(fidp->scp, LOffset, LLength, key);
6157 lock_ReleaseMutex(&fidp->scp->mx);
6164 * Work around bug in NT client
6166 * When copying a file, the NT client should first copy the data,
6167 * then copy the last write time. But sometimes the NT client does
6168 * these in the wrong order, so the data copies would inadvertently
6169 * cause the last write time to be overwritten. We try to detect this,
6170 * and don't set client mod time if we think that would go against the
6173 lock_ObtainMutex(&fidp->mx);
6174 if ((fidp->flags & SMB_FID_MTIMESETDONE) != SMB_FID_MTIMESETDONE) {
6175 fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
6176 fidp->scp->clientModTime = time(NULL);
6178 lock_ReleaseMutex(&fidp->mx);
6181 while ( code == 0 && count > 0 ) {
6182 code = smb_WriteData(fidp, &offset, count, op, userp, &written);
6183 if (code == 0 && written == 0)
6184 code = CM_ERROR_PARTIALWRITE;
6186 offset = LargeIntegerAdd(offset,
6187 ConvertLongToLargeInteger(written));
6189 total_written += written;
6195 /* slots 0 and 1 are reserved for request chaining and will be
6196 filled in when we return. */
6197 smb_SetSMBParm(outp, 2, total_written);
6198 smb_SetSMBParm(outp, 3, 0); /* reserved */
6199 smb_SetSMBParm(outp, 4, 0); /* reserved */
6200 smb_SetSMBParm(outp, 5, 0); /* reserved */
6201 smb_SetSMBDataLength(outp, 0);
6204 cm_ReleaseUser(userp);
6205 smb_ReleaseFID(fidp);
6210 long smb_ReceiveV3ReadX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6214 long finalCount = 0;
6223 fd = smb_GetSMBParm(inp, 2);
6224 count = smb_GetSMBParm(inp, 5);
6225 offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
6227 if (*inp->wctp == 12) {
6228 /* a request with 64-bit offsets */
6229 #ifdef AFS_LARGEFILES
6230 offset.HighPart = smb_GetSMBParm(inp, 10) | (smb_GetSMBParm(inp, 11) << 16);
6232 if (LargeIntegerLessThanZero(offset)) {
6233 osi_Log2(smb_logp, "smb_ReceiveV3Read offset too large (0x%x:%08x)",
6234 offset.HighPart, offset.LowPart);
6235 return CM_ERROR_BADSMB;
6238 if ((smb_GetSMBParm(inp, 10) | (smb_GetSMBParm(inp, 11) << 16)) != 0) {
6239 osi_Log0(smb_logp, "smb_ReceiveV3Read offset is 64-bit. Dropping");
6240 return CM_ERROR_BADSMB;
6242 offset.HighPart = 0;
6246 offset.HighPart = 0;
6249 osi_Log4(smb_logp, "smb_ReceiveV3Read fd %d, off 0x%x:%08x, size 0x%x",
6250 fd, offset.HighPart, offset.LowPart, count);
6252 fd = smb_ChainFID(fd, inp);
6253 fidp = smb_FindFID(vcp, fd, 0);
6255 return CM_ERROR_BADFD;
6258 pid = ((smb_t *) inp)->pid;
6259 key = cm_GenerateKey(vcp->vcID, pid, fd);
6261 LARGE_INTEGER LOffset, LLength;
6263 LOffset.HighPart = offset.HighPart;
6264 LOffset.LowPart = offset.LowPart;
6265 LLength.HighPart = 0;
6266 LLength.LowPart = count;
6268 lock_ObtainMutex(&fidp->scp->mx);
6269 code = cm_LockCheckRead(fidp->scp, LOffset, LLength, key);
6270 lock_ReleaseMutex(&fidp->scp->mx);
6274 smb_ReleaseFID(fidp);
6278 /* set inp->fid so that later read calls in same msg can find fid */
6281 lock_ObtainMutex(&fidp->mx);
6282 if (fidp->flags & SMB_FID_IOCTL) {
6283 lock_ReleaseMutex(&fidp->mx);
6284 code = smb_IoctlV3Read(fidp, vcp, inp, outp);
6285 smb_ReleaseFID(fidp);
6288 lock_ReleaseMutex(&fidp->mx);
6290 userp = smb_GetUserFromVCP(vcp, inp);
6292 /* 0 and 1 are reserved for request chaining, were setup by our caller,
6293 * and will be further filled in after we return.
6295 smb_SetSMBParm(outp, 2, 0); /* remaining bytes, for pipes */
6296 smb_SetSMBParm(outp, 3, 0); /* resvd */
6297 smb_SetSMBParm(outp, 4, 0); /* resvd */
6298 smb_SetSMBParm(outp, 5, count); /* # of bytes we're going to read */
6299 /* fill in #6 when we have all the parameters' space reserved */
6300 smb_SetSMBParm(outp, 7, 0); /* resv'd */
6301 smb_SetSMBParm(outp, 8, 0); /* resv'd */
6302 smb_SetSMBParm(outp, 9, 0); /* resv'd */
6303 smb_SetSMBParm(outp, 10, 0); /* resv'd */
6304 smb_SetSMBParm(outp, 11, 0); /* reserved */
6306 /* get op ptr after putting in the parms, since otherwise we don't
6307 * know where the data really is.
6309 op = smb_GetSMBData(outp, NULL);
6311 /* now fill in offset from start of SMB header to first data byte (to op) */
6312 smb_SetSMBParm(outp, 6, ((int) (op - outp->data)));
6314 /* set the packet data length the count of the # of bytes */
6315 smb_SetSMBDataLength(outp, count);
6317 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount);
6319 /* fix some things up */
6320 smb_SetSMBParm(outp, 5, finalCount);
6321 smb_SetSMBDataLength(outp, finalCount);
6323 cm_ReleaseUser(userp);
6324 smb_ReleaseFID(fidp);
6329 * Values for createDisp, copied from NTDDK.H
6331 #define FILE_SUPERSEDE 0 // (???)
6332 #define FILE_OPEN 1 // (open)
6333 #define FILE_CREATE 2 // (exclusive)
6334 #define FILE_OPEN_IF 3 // (non-exclusive)
6335 #define FILE_OVERWRITE 4 // (open & truncate, but do not create)
6336 #define FILE_OVERWRITE_IF 5 // (open & truncate, or create)
6339 #define REQUEST_OPLOCK 2
6340 #define REQUEST_BATCH_OPLOCK 4
6341 #define OPEN_DIRECTORY 8
6342 #define EXTENDED_RESPONSE_REQUIRED 0x10
6344 /* CreateOptions field. */
6345 #define FILE_DIRECTORY_FILE 0x0001
6346 #define FILE_WRITE_THROUGH 0x0002
6347 #define FILE_SEQUENTIAL_ONLY 0x0004
6348 #define FILE_NON_DIRECTORY_FILE 0x0040
6349 #define FILE_NO_EA_KNOWLEDGE 0x0200
6350 #define FILE_EIGHT_DOT_THREE_ONLY 0x0400
6351 #define FILE_RANDOM_ACCESS 0x0800
6352 #define FILE_DELETE_ON_CLOSE 0x1000
6353 #define FILE_OPEN_BY_FILE_ID 0x2000
6355 long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6357 char *pathp, *realPathp;
6361 cm_scache_t *dscp; /* parent dir */
6362 cm_scache_t *scp; /* file to create or open */
6363 cm_scache_t *targetScp; /* if scp is a symlink */
6367 unsigned short nameLength;
6369 unsigned int requestOpLock;
6370 unsigned int requestBatchOpLock;
6371 unsigned int mustBeDir;
6372 unsigned int extendedRespRequired;
6373 unsigned int treeCreate;
6375 unsigned int desiredAccess;
6376 unsigned int extAttributes;
6377 unsigned int createDisp;
6378 unsigned int createOptions;
6379 unsigned int shareAccess;
6380 int initialModeBits;
6381 unsigned short baseFid;
6382 smb_fid_t *baseFidp;
6384 cm_scache_t *baseDirp;
6385 unsigned short openAction;
6394 cm_lock_data_t *ldp = NULL;
6398 /* This code is very long and has a lot of if-then-else clauses
6399 * scp and dscp get reused frequently and we need to ensure that
6400 * we don't lose a reference. Start by ensuring that they are NULL.
6407 nameLength = smb_GetSMBOffsetParm(inp, 2, 1);
6408 flags = smb_GetSMBOffsetParm(inp, 3, 1)
6409 | (smb_GetSMBOffsetParm(inp, 4, 1) << 16);
6410 requestOpLock = flags & REQUEST_OPLOCK;
6411 requestBatchOpLock = flags & REQUEST_BATCH_OPLOCK;
6412 mustBeDir = flags & OPEN_DIRECTORY;
6413 extendedRespRequired = flags & EXTENDED_RESPONSE_REQUIRED;
6416 * Why all of a sudden 32-bit FID?
6417 * We will reject all bits higher than 16.
6419 if (smb_GetSMBOffsetParm(inp, 6, 1) != 0)
6420 return CM_ERROR_INVAL;
6421 baseFid = smb_GetSMBOffsetParm(inp, 5, 1);
6422 desiredAccess = smb_GetSMBOffsetParm(inp, 7, 1)
6423 | (smb_GetSMBOffsetParm(inp, 8, 1) << 16);
6424 extAttributes = smb_GetSMBOffsetParm(inp, 13, 1)
6425 | (smb_GetSMBOffsetParm(inp, 14, 1) << 16);
6426 shareAccess = smb_GetSMBOffsetParm(inp, 15, 1)
6427 | (smb_GetSMBOffsetParm(inp, 16, 1) << 16);
6428 createDisp = smb_GetSMBOffsetParm(inp, 17, 1)
6429 | (smb_GetSMBOffsetParm(inp, 18, 1) << 16);
6430 createOptions = smb_GetSMBOffsetParm(inp, 19, 1)
6431 | (smb_GetSMBOffsetParm(inp, 20, 1) << 16);
6433 /* mustBeDir is never set; createOptions directory bit seems to be
6436 if (createOptions & FILE_DIRECTORY_FILE)
6438 else if (createOptions & FILE_NON_DIRECTORY_FILE)
6444 * compute initial mode bits based on read-only flag in
6445 * extended attributes
6447 initialModeBits = 0666;
6448 if (extAttributes & SMB_ATTR_READONLY)
6449 initialModeBits &= ~0222;
6451 pathp = smb_GetSMBData(inp, NULL);
6452 /* Sometimes path is not null-terminated, so we make a copy. */
6453 realPathp = malloc(nameLength+1);
6454 memcpy(realPathp, pathp, nameLength);
6455 realPathp[nameLength] = 0;
6456 if (smb_StoreAnsiFilenames)
6457 OemToChar(realPathp,realPathp);
6459 spacep = inp->spacep;
6460 smb_StripLastComponent(spacep->data, &lastNamep, realPathp);
6462 osi_Log1(smb_logp,"NTCreateX for [%s]",osi_LogSaveString(smb_logp,realPathp));
6463 osi_Log4(smb_logp,"... da=[%x] ea=[%x] cd=[%x] co=[%x]", desiredAccess, extAttributes, createDisp, createOptions);
6464 osi_Log3(smb_logp,"... share=[%x] flags=[%x] lastNamep=[%s]", shareAccess, flags, osi_LogSaveString(smb_logp,(lastNamep?lastNamep:"null")));
6466 if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
6467 /* special case magic file name for receiving IOCTL requests
6468 * (since IOCTL calls themselves aren't getting through).
6470 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
6471 smb_SetupIoctlFid(fidp, spacep);
6472 osi_Log1(smb_logp,"NTCreateX Setting up IOCTL on fid[%d]",fidp->fid);
6474 /* set inp->fid so that later read calls in same msg can find fid */
6475 inp->fid = fidp->fid;
6479 smb_SetSMBParmByte(outp, parmSlot, 0); /* oplock */
6480 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
6481 smb_SetSMBParmLong(outp, parmSlot, 1); parmSlot += 2; /* Action */
6483 memset(&ft, 0, sizeof(ft));
6484 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
6485 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
6486 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
6487 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
6488 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2; /* attr */
6489 sz.HighPart = 0x7fff; sz.LowPart = 0;
6490 smb_SetSMBParmDouble(outp, parmSlot, (char *)&sz); parmSlot += 4; /* alen */
6491 smb_SetSMBParmDouble(outp, parmSlot, (char *)&sz); parmSlot += 4; /* len */
6492 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* filetype */
6493 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* dev state */
6494 smb_SetSMBParmByte(outp, parmSlot, 0); /* is a dir? */
6495 smb_SetSMBDataLength(outp, 0);
6497 /* clean up fid reference */
6498 smb_ReleaseFID(fidp);
6503 #ifdef DEBUG_VERBOSE
6505 char *hexp, *asciip;
6506 asciip = (lastNamep? lastNamep : realPathp);
6507 hexp = osi_HexifyString( asciip );
6508 DEBUG_EVENT2("AFS", "NTCreateX H[%s] A[%s]", hexp, asciip);
6513 userp = smb_GetUserFromVCP(vcp, inp);
6515 osi_Log1(smb_logp, "NTCreateX Invalid user [%d]", ((smb_t *) inp)->uid);
6517 return CM_ERROR_INVAL;
6522 baseDirp = cm_data.rootSCachep;
6523 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
6524 if (code == CM_ERROR_TIDIPC) {
6525 /* Attempt to use a TID allocated for IPC. The client
6526 * is probably looking for DCE RPC end points which we
6527 * don't support OR it could be looking to make a DFS
6530 osi_Log0(smb_logp, "NTCreateX received IPC TID");
6533 cm_ReleaseUser(userp);
6534 return CM_ERROR_NOSUCHFILE;
6535 #endif /* DFS_SUPPORT */
6538 baseFidp = smb_FindFID(vcp, baseFid, 0);
6540 osi_Log1(smb_logp, "NTCreateX Invalid base fid [%d]", baseFid);
6542 cm_ReleaseUser(userp);
6543 return CM_ERROR_INVAL;
6545 baseDirp = baseFidp->scp;
6549 osi_Log1(smb_logp, "NTCreateX tidPathp=[%s]", (tidPathp==NULL)?"null": osi_LogSaveString(smb_logp,tidPathp));
6551 /* compute open mode */
6553 if (desiredAccess & DELETE)
6554 fidflags |= SMB_FID_OPENDELETE;
6555 if (desiredAccess & AFS_ACCESS_READ)
6556 fidflags |= SMB_FID_OPENREAD_LISTDIR;
6557 if (desiredAccess & AFS_ACCESS_WRITE)
6558 fidflags |= SMB_FID_OPENWRITE;
6559 if (createOptions & FILE_DELETE_ON_CLOSE)
6560 fidflags |= SMB_FID_DELONCLOSE;
6561 if (createOptions & FILE_SEQUENTIAL_ONLY && !(createOptions & FILE_RANDOM_ACCESS))
6562 fidflags |= SMB_FID_SEQUENTIAL;
6563 if (createOptions & FILE_RANDOM_ACCESS && !(createOptions & FILE_SEQUENTIAL_ONLY))
6564 fidflags |= SMB_FID_RANDOM;
6566 /* and the share mode */
6567 if (shareAccess & FILE_SHARE_READ)
6568 fidflags |= SMB_FID_SHARE_READ;
6569 if (shareAccess & FILE_SHARE_WRITE)
6570 fidflags |= SMB_FID_SHARE_WRITE;
6572 osi_Log1(smb_logp, "NTCreateX fidflags 0x%x", fidflags);
6575 /* For an exclusive create, we want to do a case sensitive match for the last component. */
6576 if ( createDisp == FILE_CREATE ||
6577 createDisp == FILE_OVERWRITE ||
6578 createDisp == FILE_OVERWRITE_IF) {
6579 code = cm_NameI(baseDirp, spacep->data, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
6580 userp, tidPathp, &req, &dscp);
6583 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
6584 cm_ReleaseSCache(dscp);
6585 cm_ReleaseUser(userp);
6588 smb_ReleaseFID(baseFidp);
6589 if ( WANTS_DFS_PATHNAMES(inp) )
6590 return CM_ERROR_PATH_NOT_COVERED;
6592 return CM_ERROR_BADSHARENAME;
6594 #endif /* DFS_SUPPORT */
6595 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp, CM_FLAG_FOLLOW,
6597 if (code == CM_ERROR_NOSUCHFILE) {
6598 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp,
6599 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, &req, &scp);
6600 if (code == 0 && realDirFlag == 1) {
6601 cm_ReleaseSCache(scp);
6602 cm_ReleaseSCache(dscp);
6603 cm_ReleaseUser(userp);
6606 smb_ReleaseFID(baseFidp);
6607 return CM_ERROR_EXISTS;
6611 /* we have both scp and dscp */
6613 code = cm_NameI(baseDirp, realPathp, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
6614 userp, tidPathp, &req, &scp);
6616 if (code == 0 && scp->fileType == CM_SCACHETYPE_DFSLINK) {
6617 cm_ReleaseSCache(scp);
6618 cm_ReleaseUser(userp);
6621 smb_ReleaseFID(baseFidp);
6622 if ( WANTS_DFS_PATHNAMES(inp) )
6623 return CM_ERROR_PATH_NOT_COVERED;
6625 return CM_ERROR_BADSHARENAME;
6627 #endif /* DFS_SUPPORT */
6628 /* we might have scp but not dscp */
6634 if (!foundscp || (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE))) {
6635 /* look up parent directory */
6636 /* If we are trying to create a path (i.e. multiple nested directories), then we don't *need*
6637 * the immediate parent. We have to work our way up realPathp until we hit something that we
6641 /* we might or might not have scp */
6647 code = cm_NameI(baseDirp, spacep->data,
6648 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
6649 userp, tidPathp, &req, &dscp);
6652 if (code == 0 && dscp->fileType == CM_SCACHETYPE_DFSLINK) {
6654 cm_ReleaseSCache(scp);
6655 cm_ReleaseSCache(dscp);
6656 cm_ReleaseUser(userp);
6659 smb_ReleaseFID(baseFidp);
6660 if ( WANTS_DFS_PATHNAMES(inp) )
6661 return CM_ERROR_PATH_NOT_COVERED;
6663 return CM_ERROR_BADSHARENAME;
6665 #endif /* DFS_SUPPORT */
6668 (tp = strrchr(spacep->data,'\\')) &&
6669 (createDisp == FILE_CREATE) &&
6670 (realDirFlag == 1)) {
6673 treeStartp = realPathp + (tp - spacep->data);
6675 if (*tp && !smb_IsLegalFilename(tp)) {
6676 cm_ReleaseUser(userp);
6678 smb_ReleaseFID(baseFidp);
6681 cm_ReleaseSCache(scp);
6682 return CM_ERROR_BADNTFILENAME;
6686 } while (dscp == NULL && code == 0);
6690 /* we might have scp and we might have dscp */
6693 smb_ReleaseFID(baseFidp);
6696 osi_Log0(smb_logp,"NTCreateX parent not found");
6698 cm_ReleaseSCache(scp);
6700 cm_ReleaseSCache(dscp);
6701 cm_ReleaseUser(userp);
6706 if (treeCreate && dscp->fileType == CM_SCACHETYPE_FILE) {
6707 /* A file exists where we want a directory. */
6709 cm_ReleaseSCache(scp);
6710 cm_ReleaseSCache(dscp);
6711 cm_ReleaseUser(userp);
6713 return CM_ERROR_EXISTS;
6717 lastNamep = realPathp;
6721 if (!smb_IsLegalFilename(lastNamep)) {
6723 cm_ReleaseSCache(scp);
6725 cm_ReleaseSCache(dscp);
6726 cm_ReleaseUser(userp);
6728 return CM_ERROR_BADNTFILENAME;
6731 if (!foundscp && !treeCreate) {
6732 if ( createDisp == FILE_CREATE ||
6733 createDisp == FILE_OVERWRITE ||
6734 createDisp == FILE_OVERWRITE_IF)
6736 code = cm_Lookup(dscp, lastNamep,
6737 CM_FLAG_FOLLOW, userp, &req, &scp);
6739 code = cm_Lookup(dscp, lastNamep,
6740 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
6743 if (code && code != CM_ERROR_NOSUCHFILE) {
6745 cm_ReleaseSCache(dscp);
6746 cm_ReleaseUser(userp);
6751 /* we have scp and dscp */
6753 /* we have scp but not dscp */
6755 smb_ReleaseFID(baseFidp);
6758 /* if we get here, if code is 0, the file exists and is represented by
6759 * scp. Otherwise, we have to create it. The dir may be represented
6760 * by dscp, or we may have found the file directly. If code is non-zero,
6763 if (code == 0 && !treeCreate) {
6764 code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp, &req, &ldp);
6767 cm_ReleaseSCache(dscp);
6769 cm_ReleaseSCache(scp);
6770 cm_ReleaseUser(userp);
6775 if (createDisp == FILE_CREATE) {
6776 /* oops, file shouldn't be there */
6777 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
6779 cm_ReleaseSCache(dscp);
6781 cm_ReleaseSCache(scp);
6782 cm_ReleaseUser(userp);
6784 return CM_ERROR_EXISTS;
6787 if ( createDisp == FILE_OVERWRITE ||
6788 createDisp == FILE_OVERWRITE_IF) {
6790 setAttr.mask = CM_ATTRMASK_LENGTH;
6791 setAttr.length.LowPart = 0;
6792 setAttr.length.HighPart = 0;
6793 /* now watch for a symlink */
6795 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
6797 osi_assert(dscp != NULL);
6798 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
6800 /* we have a more accurate file to use (the
6801 * target of the symbolic link). Otherwise,
6802 * we'll just use the symlink anyway.
6804 osi_Log2(smb_logp, "symlink vp %x to vp %x",
6806 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
6807 cm_ReleaseSCache(scp);
6809 code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp, &req, &ldp);
6812 cm_ReleaseSCache(dscp);
6814 cm_ReleaseSCache(scp);
6815 cm_ReleaseUser(userp);
6821 code = cm_SetAttr(scp, &setAttr, userp, &req);
6822 openAction = 3; /* truncated existing file */
6825 openAction = 1; /* found existing file */
6827 } else if (createDisp == FILE_OPEN || createDisp == FILE_OVERWRITE) {
6828 /* don't create if not found */
6830 cm_ReleaseSCache(dscp);
6832 cm_ReleaseSCache(scp);
6833 cm_ReleaseUser(userp);
6835 return CM_ERROR_NOSUCHFILE;
6836 } else if (realDirFlag == 0 || realDirFlag == -1) {
6837 osi_assert(dscp != NULL);
6838 osi_Log1(smb_logp, "smb_ReceiveNTCreateX creating file %s",
6839 osi_LogSaveString(smb_logp, lastNamep));
6840 openAction = 2; /* created file */
6841 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
6842 setAttr.clientModTime = time(NULL);
6843 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp, &req);
6846 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
6847 smb_NotifyChange(FILE_ACTION_ADDED,
6848 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
6849 dscp, lastNamep, NULL, TRUE);
6850 } else if (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE) {
6851 /* Not an exclusive create, and someone else tried
6852 * creating it already, then we open it anyway. We
6853 * don't bother retrying after this, since if this next
6854 * fails, that means that the file was deleted after we
6855 * started this call.
6857 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
6860 if (createDisp == FILE_OVERWRITE_IF) {
6861 setAttr.mask = CM_ATTRMASK_LENGTH;
6862 setAttr.length.LowPart = 0;
6863 setAttr.length.HighPart = 0;
6865 /* now watch for a symlink */
6867 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
6869 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
6871 /* we have a more accurate file to use (the
6872 * target of the symbolic link). Otherwise,
6873 * we'll just use the symlink anyway.
6875 osi_Log2(smb_logp, "symlink vp %x to vp %x",
6877 cm_ReleaseSCache(scp);
6881 code = cm_SetAttr(scp, &setAttr, userp, &req);
6883 } /* lookup succeeded */
6887 char *cp; /* This component */
6888 int clen = 0; /* length of component */
6889 cm_scache_t *tscp1, *tscp2;
6892 /* create directory */
6894 treeStartp = lastNamep;
6895 osi_assert(dscp != NULL);
6896 osi_Log1(smb_logp, "smb_ReceiveNTCreateX creating directory [%s]",
6897 osi_LogSaveString(smb_logp, treeStartp));
6898 openAction = 2; /* created directory */
6900 /* if the request is to create the root directory
6901 * it will appear as a directory name of the nul-string
6902 * and a code of CM_ERROR_NOSUCHFILE
6904 if ( !*treeStartp && code == CM_ERROR_NOSUCHFILE)
6905 code = CM_ERROR_EXISTS;
6907 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
6908 setAttr.clientModTime = time(NULL);
6913 cm_HoldSCache(tscp1);
6917 tp = strchr(pp, '\\');
6920 clen = (int)strlen(cp);
6921 isLast = 1; /* indicate last component. the supplied path never ends in a slash */
6923 clen = (int)(tp - pp);
6924 strncpy(cp,pp,clen);
6931 continue; /* the supplied path can't have consecutive slashes either , but */
6933 /* cp is the next component to be created. */
6934 code = cm_MakeDir(tscp1, cp, 0, &setAttr, userp, &req);
6935 if (code == 0 && (tscp1->flags & CM_SCACHEFLAG_ANYWATCH))
6936 smb_NotifyChange(FILE_ACTION_ADDED,
6937 FILE_NOTIFY_CHANGE_DIR_NAME,
6938 tscp1, cp, NULL, TRUE);
6940 (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE)) {
6941 /* Not an exclusive create, and someone else tried
6942 * creating it already, then we open it anyway. We
6943 * don't bother retrying after this, since if this next
6944 * fails, that means that the file was deleted after we
6945 * started this call.
6947 code = cm_Lookup(tscp1, cp, CM_FLAG_CASEFOLD,
6948 userp, &req, &tscp2);
6953 if (!isLast) { /* for anything other than dscp, release it unless it's the last one */
6954 cm_ReleaseSCache(tscp1);
6955 tscp1 = tscp2; /* Newly created directory will be next parent */
6956 /* the hold is transfered to tscp1 from tscp2 */
6961 cm_ReleaseSCache(dscp);
6964 cm_ReleaseSCache(scp);
6967 * if we get here and code == 0, then scp is the last directory created, and dscp is the
6973 /* something went wrong creating or truncating the file */
6975 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
6977 cm_ReleaseSCache(scp);
6979 cm_ReleaseSCache(dscp);
6980 cm_ReleaseUser(userp);
6985 /* make sure we have file vs. dir right (only applies for single component case) */
6986 if (realDirFlag == 0 && scp->fileType != CM_SCACHETYPE_FILE) {
6987 /* now watch for a symlink */
6989 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
6990 cm_scache_t * targetScp = 0;
6991 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
6993 /* we have a more accurate file to use (the
6994 * target of the symbolic link). Otherwise,
6995 * we'll just use the symlink anyway.
6997 osi_Log2(smb_logp, "symlink vp %x to vp %x", scp, targetScp);
6999 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7000 cm_ReleaseSCache(scp);
7005 if (scp->fileType != CM_SCACHETYPE_FILE) {
7007 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7009 cm_ReleaseSCache(dscp);
7010 cm_ReleaseSCache(scp);
7011 cm_ReleaseUser(userp);
7013 return CM_ERROR_ISDIR;
7017 /* (only applies to single component case) */
7018 if (realDirFlag == 1 && scp->fileType == CM_SCACHETYPE_FILE) {
7020 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7021 cm_ReleaseSCache(scp);
7023 cm_ReleaseSCache(dscp);
7024 cm_ReleaseUser(userp);
7026 return CM_ERROR_NOTDIR;
7029 /* open the file itself */
7030 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
7033 /* save a reference to the user */
7035 fidp->userp = userp;
7037 /* If we are restricting sharing, we should do so with a suitable
7039 if (scp->fileType == CM_SCACHETYPE_FILE &&
7040 !(fidflags & SMB_FID_SHARE_WRITE)) {
7042 LARGE_INTEGER LOffset, LLength;
7045 LOffset.HighPart = SMB_FID_QLOCK_HIGH;
7046 LOffset.LowPart = SMB_FID_QLOCK_LOW;
7047 LLength.HighPart = 0;
7048 LLength.LowPart = SMB_FID_QLOCK_LENGTH;
7050 /* If we are not opening the file for writing, then we don't
7051 try to get an exclusive lock. Noone else should be able to
7052 get an exclusive lock on the file anyway, although someone
7053 else can get a shared lock. */
7054 if ((fidflags & SMB_FID_SHARE_READ) ||
7055 !(fidflags & SMB_FID_OPENWRITE)) {
7056 sLockType = LOCKING_ANDX_SHARED_LOCK;
7061 key = cm_GenerateKey(vcp->vcID, SMB_FID_QLOCK_PID, fidp->fid);
7063 lock_ObtainMutex(&scp->mx);
7064 code = cm_Lock(scp, sLockType, LOffset, LLength, key, 0, userp, &req, NULL);
7065 lock_ReleaseMutex(&scp->mx);
7069 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7070 cm_ReleaseSCache(scp);
7072 cm_ReleaseSCache(dscp);
7073 cm_ReleaseUser(userp);
7074 /* Shouldn't this be smb_CloseFID()? fidp->flags = SMB_FID_DELETE; */
7075 smb_CloseFID(vcp, fidp, NULL, 0);
7076 smb_ReleaseFID(fidp);
7082 /* Now its safe to release the file server lock obtained by cm_CheckNTOpen() */
7084 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7086 lock_ObtainMutex(&fidp->mx);
7087 /* save a pointer to the vnode */
7088 fidp->scp = scp; /* Hold transfered to fidp->scp and no longer needed */
7089 lock_ObtainMutex(&scp->mx);
7090 scp->flags |= CM_SCACHEFLAG_SMB_FID;
7091 lock_ReleaseMutex(&scp->mx);
7092 osi_Log2(smb_logp,"smb_ReceiveNTCreateX fidp 0x%p scp 0x%p", fidp, scp);
7094 fidp->flags = fidflags;
7096 /* remember if the file was newly created */
7098 fidp->flags |= SMB_FID_CREATED;
7100 /* save parent dir and pathname for delete or change notification */
7101 if (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE)) {
7102 osi_Log2(smb_logp,"smb_ReceiveNTCreateX fidp 0x%p dscp 0x%p", fidp, dscp);
7103 fidp->flags |= SMB_FID_NTOPEN;
7104 fidp->NTopen_dscp = dscp;
7106 fidp->NTopen_pathp = strdup(lastNamep);
7108 fidp->NTopen_wholepathp = realPathp;
7109 lock_ReleaseMutex(&fidp->mx);
7111 /* we don't need this any longer */
7113 cm_ReleaseSCache(dscp);
7117 cm_Open(scp, 0, userp);
7119 /* set inp->fid so that later read calls in same msg can find fid */
7120 inp->fid = fidp->fid;
7124 lock_ObtainMutex(&scp->mx);
7125 smb_SetSMBParmByte(outp, parmSlot, 0); /* oplock */
7126 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
7127 smb_SetSMBParmLong(outp, parmSlot, openAction); parmSlot += 2;
7128 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
7129 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
7130 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
7131 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
7132 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
7133 smb_SetSMBParmLong(outp, parmSlot, smb_ExtAttributes(scp));
7135 smb_SetSMBParmDouble(outp, parmSlot, (char *)&scp->length); parmSlot += 4;
7136 smb_SetSMBParmDouble(outp, parmSlot, (char *)&scp->length); parmSlot += 4;
7137 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* filetype */
7138 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* dev state */
7139 smb_SetSMBParmByte(outp, parmSlot,
7140 (scp->fileType == CM_SCACHETYPE_DIRECTORY ||
7141 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
7142 scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0); /* is a dir? */
7143 lock_ReleaseMutex(&scp->mx);
7144 smb_SetSMBDataLength(outp, 0);
7146 osi_Log2(smb_logp, "SMB NT CreateX opening fid %d path %s", fidp->fid,
7147 osi_LogSaveString(smb_logp, realPathp));
7149 cm_ReleaseUser(userp);
7150 smb_ReleaseFID(fidp);
7152 /* Can't free realPathp if we get here since
7153 fidp->NTopen_wholepathp is pointing there */
7155 /* leave scp held since we put it in fidp->scp */
7160 * A lot of stuff copied verbatim from NT Create&X to NT Tran Create.
7161 * Instead, ultimately, would like to use a subroutine for common code.
7163 long smb_ReceiveNTTranCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7165 char *pathp, *realPathp;
7169 cm_scache_t *dscp; /* parent dir */
7170 cm_scache_t *scp; /* file to create or open */
7171 cm_scache_t *targetScp; /* if scp is a symlink */
7174 unsigned long nameLength;
7176 unsigned int requestOpLock;
7177 unsigned int requestBatchOpLock;
7178 unsigned int mustBeDir;
7179 unsigned int extendedRespRequired;
7181 unsigned int desiredAccess;
7182 #ifdef DEBUG_VERBOSE
7183 unsigned int allocSize;
7185 unsigned int shareAccess;
7186 unsigned int extAttributes;
7187 unsigned int createDisp;
7188 #ifdef DEBUG_VERBOSE
7191 unsigned int createOptions;
7192 int initialModeBits;
7193 unsigned short baseFid;
7194 smb_fid_t *baseFidp;
7196 cm_scache_t *baseDirp;
7197 unsigned short openAction;
7203 int parmOffset, dataOffset;
7209 cm_lock_data_t *ldp = NULL;
7216 parmOffset = smb_GetSMBOffsetParm(inp, 11, 1)
7217 | (smb_GetSMBOffsetParm(inp, 12, 1) << 16);
7218 parmp = inp->data + parmOffset;
7219 lparmp = (ULONG *) parmp;
7222 requestOpLock = flags & REQUEST_OPLOCK;
7223 requestBatchOpLock = flags & REQUEST_BATCH_OPLOCK;
7224 mustBeDir = flags & OPEN_DIRECTORY;
7225 extendedRespRequired = flags & EXTENDED_RESPONSE_REQUIRED;
7228 * Why all of a sudden 32-bit FID?
7229 * We will reject all bits higher than 16.
7231 if (lparmp[1] & 0xFFFF0000)
7232 return CM_ERROR_INVAL;
7233 baseFid = (unsigned short)lparmp[1];
7234 desiredAccess = lparmp[2];
7235 #ifdef DEBUG_VERBOSE
7236 allocSize = lparmp[3];
7237 #endif /* DEBUG_VERSOSE */
7238 extAttributes = lparmp[5];
7239 shareAccess = lparmp[6];
7240 createDisp = lparmp[7];
7241 createOptions = lparmp[8];
7242 #ifdef DEBUG_VERBOSE
7245 nameLength = lparmp[11];
7247 #ifdef DEBUG_VERBOSE
7248 osi_Log4(smb_logp,"NTTranCreate with da[%x],ea[%x],sa[%x],cd[%x]",desiredAccess,extAttributes,shareAccess,createDisp);
7249 osi_Log3(smb_logp,"... co[%x],sdl[%x],as[%x]",createOptions,sdLen,allocSize);
7250 osi_Log1(smb_logp,"... flags[%x]",flags);
7253 /* mustBeDir is never set; createOptions directory bit seems to be
7256 if (createOptions & FILE_DIRECTORY_FILE)
7258 else if (createOptions & FILE_NON_DIRECTORY_FILE)
7264 * compute initial mode bits based on read-only flag in
7265 * extended attributes
7267 initialModeBits = 0666;
7268 if (extAttributes & SMB_ATTR_READONLY)
7269 initialModeBits &= ~0222;
7271 pathp = parmp + (13 * sizeof(ULONG)) + sizeof(UCHAR);
7272 /* Sometimes path is not null-terminated, so we make a copy. */
7273 realPathp = malloc(nameLength+1);
7274 memcpy(realPathp, pathp, nameLength);
7275 realPathp[nameLength] = 0;
7276 if (smb_StoreAnsiFilenames)
7277 OemToChar(realPathp,realPathp);
7279 spacep = cm_GetSpace();
7280 smb_StripLastComponent(spacep->data, &lastNamep, realPathp);
7283 * Nothing here to handle SMB_IOCTL_FILENAME.
7284 * Will add it if necessary.
7287 #ifdef DEBUG_VERBOSE
7289 char *hexp, *asciip;
7290 asciip = (lastNamep? lastNamep : realPathp);
7291 hexp = osi_HexifyString( asciip );
7292 DEBUG_EVENT2("AFS", "NTTranCreate H[%s] A[%s]", hexp, asciip);
7297 userp = smb_GetUserFromVCP(vcp, inp);
7299 osi_Log1(smb_logp, "NTTranCreate invalid user [%d]", ((smb_t *) inp)->uid);
7301 return CM_ERROR_INVAL;
7306 baseDirp = cm_data.rootSCachep;
7307 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
7308 if (code == CM_ERROR_TIDIPC) {
7309 /* Attempt to use a TID allocated for IPC. The client
7310 * is probably looking for DCE RPC end points which we
7311 * don't support OR it could be looking to make a DFS
7314 osi_Log0(smb_logp, "NTTranCreate received IPC TID");
7317 cm_ReleaseUser(userp);
7318 return CM_ERROR_NOSUCHPATH;
7322 baseFidp = smb_FindFID(vcp, baseFid, 0);
7324 osi_Log1(smb_logp, "NTTranCreate Invalid fid [%d]", baseFid);
7326 cm_ReleaseUser(userp);
7327 return CM_ERROR_INVAL;
7329 baseDirp = baseFidp->scp;
7333 /* compute open mode */
7335 if (desiredAccess & DELETE)
7336 fidflags |= SMB_FID_OPENDELETE;
7337 if (desiredAccess & AFS_ACCESS_READ)
7338 fidflags |= SMB_FID_OPENREAD_LISTDIR;
7339 if (desiredAccess & AFS_ACCESS_WRITE)
7340 fidflags |= SMB_FID_OPENWRITE;
7341 if (createOptions & FILE_DELETE_ON_CLOSE)
7342 fidflags |= SMB_FID_DELONCLOSE;
7343 if (createOptions & FILE_SEQUENTIAL_ONLY && !(createOptions & FILE_RANDOM_ACCESS))
7344 fidflags |= SMB_FID_SEQUENTIAL;
7345 if (createOptions & FILE_RANDOM_ACCESS && !(createOptions & FILE_SEQUENTIAL_ONLY))
7346 fidflags |= SMB_FID_RANDOM;
7348 /* And the share mode */
7349 if (shareAccess & FILE_SHARE_READ)
7350 fidflags |= SMB_FID_SHARE_READ;
7351 if (shareAccess & FILE_SHARE_WRITE)
7352 fidflags |= SMB_FID_SHARE_WRITE;
7356 if ( createDisp == FILE_OPEN ||
7357 createDisp == FILE_OVERWRITE ||
7358 createDisp == FILE_OVERWRITE_IF) {
7359 code = cm_NameI(baseDirp, spacep->data, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
7360 userp, tidPathp, &req, &dscp);
7363 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
7364 cm_ReleaseSCache(dscp);
7365 cm_ReleaseUser(userp);
7368 smb_ReleaseFID(baseFidp);
7369 if ( WANTS_DFS_PATHNAMES(inp) )
7370 return CM_ERROR_PATH_NOT_COVERED;
7372 return CM_ERROR_BADSHARENAME;
7374 #endif /* DFS_SUPPORT */
7375 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp, CM_FLAG_FOLLOW,
7377 if (code == CM_ERROR_NOSUCHFILE) {
7378 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp,
7379 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, &req, &scp);
7380 if (code == 0 && realDirFlag == 1) {
7381 cm_ReleaseSCache(scp);
7382 cm_ReleaseSCache(dscp);
7383 cm_ReleaseUser(userp);
7386 smb_ReleaseFID(baseFidp);
7387 return CM_ERROR_EXISTS;
7393 code = cm_NameI(baseDirp, realPathp, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
7394 userp, tidPathp, &req, &scp);
7396 if (code == 0 && scp->fileType == CM_SCACHETYPE_DFSLINK) {
7397 cm_ReleaseSCache(scp);
7398 cm_ReleaseUser(userp);
7401 smb_ReleaseFID(baseFidp);
7402 if ( WANTS_DFS_PATHNAMES(inp) )
7403 return CM_ERROR_PATH_NOT_COVERED;
7405 return CM_ERROR_BADSHARENAME;
7407 #endif /* DFS_SUPPORT */
7413 if (code != 0 || (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE))) {
7414 /* look up parent directory */
7416 code = cm_NameI(baseDirp, spacep->data,
7417 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
7418 userp, tidPathp, &req, &dscp);
7420 if (code == 0 && dscp->fileType == CM_SCACHETYPE_DFSLINK) {
7421 cm_ReleaseSCache(dscp);
7422 cm_ReleaseUser(userp);
7425 smb_ReleaseFID(baseFidp);
7426 if ( WANTS_DFS_PATHNAMES(inp) )
7427 return CM_ERROR_PATH_NOT_COVERED;
7429 return CM_ERROR_BADSHARENAME;
7431 #endif /* DFS_SUPPORT */
7435 cm_FreeSpace(spacep);
7438 smb_ReleaseFID(baseFidp);
7441 cm_ReleaseUser(userp);
7447 lastNamep = realPathp;
7451 if (!smb_IsLegalFilename(lastNamep))
7452 return CM_ERROR_BADNTFILENAME;
7455 if (createDisp == FILE_CREATE || createDisp == FILE_OVERWRITE_IF) {
7456 code = cm_Lookup(dscp, lastNamep,
7457 CM_FLAG_FOLLOW, userp, &req, &scp);
7459 code = cm_Lookup(dscp, lastNamep,
7460 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
7463 if (code && code != CM_ERROR_NOSUCHFILE) {
7464 cm_ReleaseSCache(dscp);
7465 cm_ReleaseUser(userp);
7472 smb_ReleaseFID(baseFidp);
7473 cm_FreeSpace(spacep);
7476 /* if we get here, if code is 0, the file exists and is represented by
7477 * scp. Otherwise, we have to create it. The dir may be represented
7478 * by dscp, or we may have found the file directly. If code is non-zero,
7482 code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp, &req, &ldp);
7485 cm_ReleaseSCache(dscp);
7486 cm_ReleaseSCache(scp);
7487 cm_ReleaseUser(userp);
7492 if (createDisp == FILE_CREATE) {
7493 /* oops, file shouldn't be there */
7494 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7496 cm_ReleaseSCache(dscp);
7497 cm_ReleaseSCache(scp);
7498 cm_ReleaseUser(userp);
7500 return CM_ERROR_EXISTS;
7503 if (createDisp == FILE_OVERWRITE ||
7504 createDisp == FILE_OVERWRITE_IF) {
7505 setAttr.mask = CM_ATTRMASK_LENGTH;
7506 setAttr.length.LowPart = 0;
7507 setAttr.length.HighPart = 0;
7509 /* now watch for a symlink */
7511 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
7513 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
7515 /* we have a more accurate file to use (the
7516 * target of the symbolic link). Otherwise,
7517 * we'll just use the symlink anyway.
7519 osi_Log2(smb_logp, "symlink vp %x to vp %x",
7521 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7522 cm_ReleaseSCache(scp);
7524 code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp, &req, &ldp);
7527 cm_ReleaseSCache(dscp);
7529 cm_ReleaseSCache(scp);
7530 cm_ReleaseUser(userp);
7536 code = cm_SetAttr(scp, &setAttr, userp, &req);
7537 openAction = 3; /* truncated existing file */
7539 else openAction = 1; /* found existing file */
7541 else if (createDisp == FILE_OPEN || createDisp == FILE_OVERWRITE) {
7542 /* don't create if not found */
7544 cm_ReleaseSCache(dscp);
7545 cm_ReleaseUser(userp);
7547 return CM_ERROR_NOSUCHFILE;
7549 else if (realDirFlag == 0 || realDirFlag == -1) {
7550 osi_assert(dscp != NULL);
7551 osi_Log1(smb_logp, "smb_ReceiveNTTranCreate creating file %s",
7552 osi_LogSaveString(smb_logp, lastNamep));
7553 openAction = 2; /* created file */
7554 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
7555 setAttr.clientModTime = time(NULL);
7556 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
7560 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
7561 smb_NotifyChange(FILE_ACTION_ADDED,
7562 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
7563 dscp, lastNamep, NULL, TRUE);
7564 } else if (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE) {
7565 /* Not an exclusive create, and someone else tried
7566 * creating it already, then we open it anyway. We
7567 * don't bother retrying after this, since if this next
7568 * fails, that means that the file was deleted after we
7569 * started this call.
7571 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
7574 if (createDisp == FILE_OVERWRITE_IF) {
7575 setAttr.mask = CM_ATTRMASK_LENGTH;
7576 setAttr.length.LowPart = 0;
7577 setAttr.length.HighPart = 0;
7579 /* now watch for a symlink */
7581 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
7583 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
7585 /* we have a more accurate file to use (the
7586 * target of the symbolic link). Otherwise,
7587 * we'll just use the symlink anyway.
7589 osi_Log2(smb_logp, "symlink vp %x to vp %x",
7591 cm_ReleaseSCache(scp);
7595 code = cm_SetAttr(scp, &setAttr, userp, &req);
7597 } /* lookup succeeded */
7600 /* create directory */
7601 osi_assert(dscp != NULL);
7603 "smb_ReceiveNTTranCreate creating directory %s",
7604 osi_LogSaveString(smb_logp, lastNamep));
7605 openAction = 2; /* created directory */
7606 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
7607 setAttr.clientModTime = time(NULL);
7608 code = cm_MakeDir(dscp, lastNamep, 0, &setAttr, userp, &req);
7609 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
7610 smb_NotifyChange(FILE_ACTION_ADDED,
7611 FILE_NOTIFY_CHANGE_DIR_NAME,
7612 dscp, lastNamep, NULL, TRUE);
7614 (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE)) {
7615 /* Not an exclusive create, and someone else tried
7616 * creating it already, then we open it anyway. We
7617 * don't bother retrying after this, since if this next
7618 * fails, that means that the file was deleted after we
7619 * started this call.
7621 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
7627 /* something went wrong creating or truncating the file */
7629 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7631 cm_ReleaseSCache(scp);
7632 cm_ReleaseUser(userp);
7637 /* make sure we have file vs. dir right */
7638 if (realDirFlag == 0 && scp->fileType != CM_SCACHETYPE_FILE) {
7639 /* now watch for a symlink */
7641 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
7643 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
7645 /* we have a more accurate file to use (the
7646 * target of the symbolic link). Otherwise,
7647 * we'll just use the symlink anyway.
7649 osi_Log2(smb_logp, "symlink vp %x to vp %x",
7652 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7653 cm_ReleaseSCache(scp);
7658 if (scp->fileType != CM_SCACHETYPE_FILE) {
7660 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7661 cm_ReleaseSCache(scp);
7662 cm_ReleaseUser(userp);
7664 return CM_ERROR_ISDIR;
7668 if (realDirFlag == 1 && scp->fileType == CM_SCACHETYPE_FILE) {
7670 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7671 cm_ReleaseSCache(scp);
7672 cm_ReleaseUser(userp);
7674 return CM_ERROR_NOTDIR;
7677 /* open the file itself */
7678 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
7681 /* save a reference to the user */
7683 fidp->userp = userp;
7685 /* If we are restricting sharing, we should do so with a suitable
7687 if (scp->fileType == CM_SCACHETYPE_FILE &&
7688 !(fidflags & SMB_FID_SHARE_WRITE)) {
7690 LARGE_INTEGER LOffset, LLength;
7693 LOffset.HighPart = SMB_FID_QLOCK_HIGH;
7694 LOffset.LowPart = SMB_FID_QLOCK_LOW;
7695 LLength.HighPart = 0;
7696 LLength.LowPart = SMB_FID_QLOCK_LENGTH;
7698 /* Similar to what we do in handling NTCreateX. We get a
7699 shared lock if we are only opening the file for reading. */
7700 if ((fidflags & SMB_FID_SHARE_READ) ||
7701 !(fidflags & SMB_FID_OPENWRITE)) {
7702 sLockType = LOCKING_ANDX_SHARED_LOCK;
7707 key = cm_GenerateKey(vcp->vcID, SMB_FID_QLOCK_PID, fidp->fid);
7709 lock_ObtainMutex(&scp->mx);
7710 code = cm_Lock(scp, sLockType, LOffset, LLength, key, 0, userp, &req, NULL);
7711 lock_ReleaseMutex(&scp->mx);
7715 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7716 cm_ReleaseSCache(scp);
7717 cm_ReleaseUser(userp);
7718 /* Shouldn't this be smb_CloseFID()? fidp->flags = SMB_FID_DELETE; */
7719 smb_CloseFID(vcp, fidp, NULL, 0);
7720 smb_ReleaseFID(fidp);
7722 return CM_ERROR_SHARING_VIOLATION;
7726 /* Now its safe to drop the file server lock obtained by cm_CheckNTOpen() */
7728 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7730 lock_ObtainMutex(&fidp->mx);
7731 /* save a pointer to the vnode */
7733 lock_ObtainMutex(&scp->mx);
7734 scp->flags |= CM_SCACHEFLAG_SMB_FID;
7735 lock_ReleaseMutex(&scp->mx);
7736 osi_Log2(smb_logp,"smb_ReceiveNTTranCreate fidp 0x%p scp 0x%p", fidp, scp);
7738 fidp->flags = fidflags;
7740 /* remember if the file was newly created */
7742 fidp->flags |= SMB_FID_CREATED;
7744 /* save parent dir and pathname for deletion or change notification */
7745 if (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE)) {
7746 fidp->flags |= SMB_FID_NTOPEN;
7747 fidp->NTopen_dscp = dscp;
7748 osi_Log2(smb_logp,"smb_ReceiveNTTranCreate fidp 0x%p dscp 0x%p", fidp, dscp);
7750 fidp->NTopen_pathp = strdup(lastNamep);
7752 fidp->NTopen_wholepathp = realPathp;
7753 lock_ReleaseMutex(&fidp->mx);
7755 /* we don't need this any longer */
7757 cm_ReleaseSCache(dscp);
7759 cm_Open(scp, 0, userp);
7761 /* set inp->fid so that later read calls in same msg can find fid */
7762 inp->fid = fidp->fid;
7764 /* check whether we are required to send an extended response */
7765 if (!extendedRespRequired) {
7767 parmOffset = 8*4 + 39;
7768 parmOffset += 1; /* pad to 4 */
7769 dataOffset = parmOffset + 70;
7773 /* Total Parameter Count */
7774 smb_SetSMBParmLong(outp, parmSlot, 70); parmSlot += 2;
7775 /* Total Data Count */
7776 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
7777 /* Parameter Count */
7778 smb_SetSMBParmLong(outp, parmSlot, 70); parmSlot += 2;
7779 /* Parameter Offset */
7780 smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
7781 /* Parameter Displacement */
7782 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
7784 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
7786 smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
7787 /* Data Displacement */
7788 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
7789 smb_SetSMBParmByte(outp, parmSlot, 0); /* Setup Count */
7790 smb_SetSMBDataLength(outp, 70);
7792 lock_ObtainMutex(&scp->mx);
7793 outData = smb_GetSMBData(outp, NULL);
7794 outData++; /* round to get to parmOffset */
7795 *outData = 0; outData++; /* oplock */
7796 *outData = 0; outData++; /* reserved */
7797 *((USHORT *)outData) = fidp->fid; outData += 2; /* fid */
7798 *((ULONG *)outData) = openAction; outData += 4;
7799 *((ULONG *)outData) = 0; outData += 4; /* EA error offset */
7800 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
7801 *((FILETIME *)outData) = ft; outData += 8; /* creation time */
7802 *((FILETIME *)outData) = ft; outData += 8; /* last access time */
7803 *((FILETIME *)outData) = ft; outData += 8; /* last write time */
7804 *((FILETIME *)outData) = ft; outData += 8; /* change time */
7805 *((ULONG *)outData) = smb_ExtAttributes(scp); outData += 4;
7806 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* alloc sz */
7807 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* EOF */
7808 *((USHORT *)outData) = 0; outData += 2; /* filetype */
7809 *((USHORT *)outData) = 0; outData += 2; /* dev state */
7810 *((USHORT *)outData) = ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
7811 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
7812 scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0);
7813 outData += 2; /* is a dir? */
7814 lock_ReleaseMutex(&scp->mx);
7817 parmOffset = 8*4 + 39;
7818 parmOffset += 1; /* pad to 4 */
7819 dataOffset = parmOffset + 104;
7823 /* Total Parameter Count */
7824 smb_SetSMBParmLong(outp, parmSlot, 101); parmSlot += 2;
7825 /* Total Data Count */
7826 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
7827 /* Parameter Count */
7828 smb_SetSMBParmLong(outp, parmSlot, 101); parmSlot += 2;
7829 /* Parameter Offset */
7830 smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
7831 /* Parameter Displacement */
7832 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
7834 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
7836 smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
7837 /* Data Displacement */
7838 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
7839 smb_SetSMBParmByte(outp, parmSlot, 0); /* Setup Count */
7840 smb_SetSMBDataLength(outp, 105);
7842 lock_ObtainMutex(&scp->mx);
7843 outData = smb_GetSMBData(outp, NULL);
7844 outData++; /* round to get to parmOffset */
7845 *outData = 0; outData++; /* oplock */
7846 *outData = 1; outData++; /* response type */
7847 *((USHORT *)outData) = fidp->fid; outData += 2; /* fid */
7848 *((ULONG *)outData) = openAction; outData += 4;
7849 *((ULONG *)outData) = 0; outData += 4; /* EA error offset */
7850 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
7851 *((FILETIME *)outData) = ft; outData += 8; /* creation time */
7852 *((FILETIME *)outData) = ft; outData += 8; /* last access time */
7853 *((FILETIME *)outData) = ft; outData += 8; /* last write time */
7854 *((FILETIME *)outData) = ft; outData += 8; /* change time */
7855 *((ULONG *)outData) = smb_ExtAttributes(scp); outData += 4;
7856 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* alloc sz */
7857 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* EOF */
7858 *((USHORT *)outData) = 0; outData += 2; /* filetype */
7859 *((USHORT *)outData) = 0; outData += 2; /* dev state */
7860 *((USHORT *)outData) = ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
7861 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
7862 scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0);
7863 outData += 1; /* is a dir? */
7864 memset(outData,0,24); outData += 24; /* Volume ID and file ID */
7865 *((ULONG *)outData) = 0x001f01ffL; outData += 4; /* Maxmimal access rights */
7866 *((ULONG *)outData) = 0; outData += 4; /* Guest Access rights */
7867 lock_ReleaseMutex(&scp->mx);
7870 osi_Log1(smb_logp, "SMB NTTranCreate opening fid %d", fidp->fid);
7872 cm_ReleaseUser(userp);
7873 smb_ReleaseFID(fidp);
7875 /* free(realPathp); Can't free realPathp here because fidp->NTopen_wholepathp points there */
7876 /* leave scp held since we put it in fidp->scp */
7880 long smb_ReceiveNTTranNotifyChange(smb_vc_t *vcp, smb_packet_t *inp,
7883 smb_packet_t *savedPacketp;
7885 USHORT fid, watchtree;
7889 filter = smb_GetSMBParm(inp, 19) |
7890 (smb_GetSMBParm(inp, 20) << 16);
7891 fid = smb_GetSMBParm(inp, 21);
7892 watchtree = (smb_GetSMBParm(inp, 22) & 0xff) ? 1 : 0;
7894 fidp = smb_FindFID(vcp, fid, 0);
7896 osi_Log1(smb_logp, "ERROR: NotifyChange given invalid fid [%d]", fid);
7897 return CM_ERROR_BADFD;
7900 /* Create a copy of the Directory Watch Packet to use when sending the
7901 * notification if in the future a matching change is detected.
7903 savedPacketp = smb_CopyPacket(inp);
7905 if (savedPacketp->vcp)
7906 smb_ReleaseVC(savedPacketp->vcp);
7907 savedPacketp->vcp = vcp;
7909 /* Add the watch to the list of events to send notifications for */
7910 lock_ObtainMutex(&smb_Dir_Watch_Lock);
7911 savedPacketp->nextp = smb_Directory_Watches;
7912 smb_Directory_Watches = savedPacketp;
7913 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
7916 osi_Log3(smb_logp,"smb_ReceiveNTTranNotifyChange fidp 0x%p scp 0x%p file \"%s\"",
7917 fidp, scp, osi_LogSaveString(smb_logp, fidp->NTopen_wholepathp));
7918 osi_Log3(smb_logp, "Request for NotifyChange filter 0x%x fid %d wtree %d",
7919 filter, fid, watchtree);
7920 if (filter & FILE_NOTIFY_CHANGE_FILE_NAME)
7921 osi_Log0(smb_logp, " Notify Change File Name");
7922 if (filter & FILE_NOTIFY_CHANGE_DIR_NAME)
7923 osi_Log0(smb_logp, " Notify Change Directory Name");
7924 if (filter & FILE_NOTIFY_CHANGE_ATTRIBUTES)
7925 osi_Log0(smb_logp, " Notify Change Attributes");
7926 if (filter & FILE_NOTIFY_CHANGE_SIZE)
7927 osi_Log0(smb_logp, " Notify Change Size");
7928 if (filter & FILE_NOTIFY_CHANGE_LAST_WRITE)
7929 osi_Log0(smb_logp, " Notify Change Last Write");
7930 if (filter & FILE_NOTIFY_CHANGE_LAST_ACCESS)
7931 osi_Log0(smb_logp, " Notify Change Last Access");
7932 if (filter & FILE_NOTIFY_CHANGE_CREATION)
7933 osi_Log0(smb_logp, " Notify Change Creation");
7934 if (filter & FILE_NOTIFY_CHANGE_EA)
7935 osi_Log0(smb_logp, " Notify Change Extended Attributes");
7936 if (filter & FILE_NOTIFY_CHANGE_SECURITY)
7937 osi_Log0(smb_logp, " Notify Change Security");
7938 if (filter & FILE_NOTIFY_CHANGE_STREAM_NAME)
7939 osi_Log0(smb_logp, " Notify Change Stream Name");
7940 if (filter & FILE_NOTIFY_CHANGE_STREAM_SIZE)
7941 osi_Log0(smb_logp, " Notify Change Stream Size");
7942 if (filter & FILE_NOTIFY_CHANGE_STREAM_WRITE)
7943 osi_Log0(smb_logp, " Notify Change Stream Write");
7945 lock_ObtainMutex(&scp->mx);
7947 scp->flags |= CM_SCACHEFLAG_WATCHEDSUBTREE;
7949 scp->flags |= CM_SCACHEFLAG_WATCHED;
7950 lock_ReleaseMutex(&scp->mx);
7951 smb_ReleaseFID(fidp);
7953 outp->flags |= SMB_PACKETFLAG_NOSEND;
7957 unsigned char nullSecurityDesc[36] = {
7958 0x01, /* security descriptor revision */
7959 0x00, /* reserved, should be zero */
7960 0x00, 0x80, /* security descriptor control;
7961 * 0x8000 : self-relative format */
7962 0x14, 0x00, 0x00, 0x00, /* offset of owner SID */
7963 0x1c, 0x00, 0x00, 0x00, /* offset of group SID */
7964 0x00, 0x00, 0x00, 0x00, /* offset of DACL would go here */
7965 0x00, 0x00, 0x00, 0x00, /* offset of SACL would go here */
7966 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
7967 /* "null SID" owner SID */
7968 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
7969 /* "null SID" group SID */
7972 long smb_ReceiveNTTranQuerySecurityDesc(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7974 int parmOffset, parmCount, dataOffset, dataCount;
7982 ULONG securityInformation;
7984 parmOffset = smb_GetSMBOffsetParm(inp, 11, 1)
7985 | (smb_GetSMBOffsetParm(inp, 12, 1) << 16);
7986 parmp = inp->data + parmOffset;
7987 sparmp = (USHORT *) parmp;
7988 lparmp = (ULONG *) parmp;
7991 securityInformation = lparmp[1];
7993 maxData = smb_GetSMBOffsetParm(inp, 7, 1)
7994 | (smb_GetSMBOffsetParm(inp, 8, 1) << 16);
8002 parmOffset = 8*4 + 39;
8003 parmOffset += 1; /* pad to 4 */
8005 dataOffset = parmOffset + parmCount;
8009 /* Total Parameter Count */
8010 smb_SetSMBParmLong(outp, parmSlot, parmCount); parmSlot += 2;
8011 /* Total Data Count */
8012 smb_SetSMBParmLong(outp, parmSlot, dataCount); parmSlot += 2;
8013 /* Parameter Count */
8014 smb_SetSMBParmLong(outp, parmSlot, parmCount); parmSlot += 2;
8015 /* Parameter Offset */
8016 smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
8017 /* Parameter Displacement */
8018 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8020 smb_SetSMBParmLong(outp, parmSlot, dataCount); parmSlot += 2;
8022 smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
8023 /* Data Displacement */
8024 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8025 smb_SetSMBParmByte(outp, parmSlot, 0); /* Setup Count */
8026 smb_SetSMBDataLength(outp, 1 + parmCount + dataCount);
8028 outData = smb_GetSMBData(outp, NULL);
8029 outData++; /* round to get to parmOffset */
8030 *((ULONG *)outData) = 36; outData += 4; /* length */
8032 if (maxData >= 36) {
8033 memcpy(outData, nullSecurityDesc, 36);
8037 return CM_ERROR_BUFFERTOOSMALL;
8040 long smb_ReceiveNTTransact(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
8042 unsigned short function;
8044 function = smb_GetSMBParm(inp, 18);
8046 osi_Log1(smb_logp, "SMB NT Transact function %d", function);
8048 /* We can handle long names */
8049 if (vcp->flags & SMB_VCFLAG_USENT)
8050 ((smb_t *)outp)->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
8054 return smb_ReceiveNTTranCreate(vcp, inp, outp);
8056 osi_Log0(smb_logp, "SMB NT Transact Ioctl - not implemented");
8059 osi_Log0(smb_logp, "SMB NT Transact SetSecurityDesc - not implemented");
8062 return smb_ReceiveNTTranNotifyChange(vcp, inp, outp);
8064 osi_Log0(smb_logp, "SMB NT Transact Rename - not implemented");
8067 return smb_ReceiveNTTranQuerySecurityDesc(vcp, inp, outp);
8069 return CM_ERROR_INVAL;
8073 * smb_NotifyChange -- find relevant change notification messages and
8076 * If we don't know the file name (i.e. a callback break), filename is
8077 * NULL, and we return a zero-length list.
8079 * At present there is not a single call to smb_NotifyChange that
8080 * has the isDirectParent parameter set to FALSE.
8082 void smb_NotifyChange(DWORD action, DWORD notifyFilter,
8083 cm_scache_t *dscp, char *filename, char *otherFilename,
8084 BOOL isDirectParent)
8086 smb_packet_t *watch, *lastWatch, *nextWatch;
8087 ULONG parmSlot, parmCount, parmOffset, dataOffset, nameLen;
8088 char *outData, *oldOutData;
8092 BOOL twoEntries = FALSE;
8093 ULONG otherNameLen, oldParmCount = 0;
8097 /* Get ready for rename within directory */
8098 if (action == FILE_ACTION_RENAMED_OLD_NAME && otherFilename != NULL) {
8100 otherAction = FILE_ACTION_RENAMED_NEW_NAME;
8103 osi_Log4(smb_logp,"in smb_NotifyChange for file [%s] dscp [%p] notification 0x%x parent %d",
8104 osi_LogSaveString(smb_logp,filename),dscp, notifyFilter, isDirectParent);
8106 osi_Log0(smb_logp," FILE_ACTION_NONE");
8107 if (action == FILE_ACTION_ADDED)
8108 osi_Log0(smb_logp," FILE_ACTION_ADDED");
8109 if (action == FILE_ACTION_REMOVED)
8110 osi_Log0(smb_logp," FILE_ACTION_REMOVED");
8111 if (action == FILE_ACTION_MODIFIED)
8112 osi_Log0(smb_logp," FILE_ACTION_MODIFIED");
8113 if (action == FILE_ACTION_RENAMED_OLD_NAME)
8114 osi_Log0(smb_logp," FILE_ACTION_RENAMED_OLD_NAME");
8115 if (action == FILE_ACTION_RENAMED_NEW_NAME)
8116 osi_Log0(smb_logp," FILE_ACTION_RENAMED_NEW_NAME");
8118 lock_ObtainMutex(&smb_Dir_Watch_Lock);
8119 watch = smb_Directory_Watches;
8121 filter = smb_GetSMBParm(watch, 19)
8122 | (smb_GetSMBParm(watch, 20) << 16);
8123 fid = smb_GetSMBParm(watch, 21);
8124 wtree = (smb_GetSMBParm(watch, 22) & 0xff) ? 1 : 0;
8126 maxLen = smb_GetSMBOffsetParm(watch, 5, 1)
8127 | (smb_GetSMBOffsetParm(watch, 6, 1) << 16);
8130 * Strange hack - bug in NT Client and NT Server that we must emulate?
8132 if ((filter == (FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME)) && wtree)
8133 filter |= FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_ATTRIBUTES;
8135 fidp = smb_FindFID(watch->vcp, fid, 0);
8137 osi_Log2(smb_logp," no fidp for fid[%d] in vcp 0x%p",fid, watch->vcp);
8139 watch = watch->nextp;
8142 if (fidp->scp != dscp
8143 || (filter & notifyFilter) == 0
8144 || (!isDirectParent && !wtree)) {
8145 osi_Log1(smb_logp," skipping fidp->scp[%x]", fidp->scp);
8146 smb_ReleaseFID(fidp);
8148 watch = watch->nextp;
8151 smb_ReleaseFID(fidp);
8154 "Sending Change Notification for fid %d filter 0x%x wtree %d file %s",
8155 fid, filter, wtree, osi_LogSaveString(smb_logp, filename));
8156 if (filter & FILE_NOTIFY_CHANGE_FILE_NAME)
8157 osi_Log0(smb_logp, " Notify Change File Name");
8158 if (filter & FILE_NOTIFY_CHANGE_DIR_NAME)
8159 osi_Log0(smb_logp, " Notify Change Directory Name");
8160 if (filter & FILE_NOTIFY_CHANGE_ATTRIBUTES)
8161 osi_Log0(smb_logp, " Notify Change Attributes");
8162 if (filter & FILE_NOTIFY_CHANGE_SIZE)
8163 osi_Log0(smb_logp, " Notify Change Size");
8164 if (filter & FILE_NOTIFY_CHANGE_LAST_WRITE)
8165 osi_Log0(smb_logp, " Notify Change Last Write");
8166 if (filter & FILE_NOTIFY_CHANGE_LAST_ACCESS)
8167 osi_Log0(smb_logp, " Notify Change Last Access");
8168 if (filter & FILE_NOTIFY_CHANGE_CREATION)
8169 osi_Log0(smb_logp, " Notify Change Creation");
8170 if (filter & FILE_NOTIFY_CHANGE_EA)
8171 osi_Log0(smb_logp, " Notify Change Extended Attributes");
8172 if (filter & FILE_NOTIFY_CHANGE_SECURITY)
8173 osi_Log0(smb_logp, " Notify Change Security");
8174 if (filter & FILE_NOTIFY_CHANGE_STREAM_NAME)
8175 osi_Log0(smb_logp, " Notify Change Stream Name");
8176 if (filter & FILE_NOTIFY_CHANGE_STREAM_SIZE)
8177 osi_Log0(smb_logp, " Notify Change Stream Size");
8178 if (filter & FILE_NOTIFY_CHANGE_STREAM_WRITE)
8179 osi_Log0(smb_logp, " Notify Change Stream Write");
8181 /* A watch can only be notified once. Remove it from the list */
8182 nextWatch = watch->nextp;
8183 if (watch == smb_Directory_Watches)
8184 smb_Directory_Watches = nextWatch;
8186 lastWatch->nextp = nextWatch;
8188 /* Turn off WATCHED flag in dscp */
8189 lock_ObtainMutex(&dscp->mx);
8191 dscp->flags &= ~CM_SCACHEFLAG_WATCHEDSUBTREE;
8193 dscp->flags &= ~CM_SCACHEFLAG_WATCHED;
8194 lock_ReleaseMutex(&dscp->mx);
8196 /* Convert to response packet */
8197 ((smb_t *) watch)->reb = SMB_FLAGS_SERVER_TO_CLIENT | SMB_FLAGS_CANONICAL_PATHNAMES;
8198 ((smb_t *) watch)->wct = 0;
8201 if (filename == NULL)
8204 nameLen = (ULONG)strlen(filename);
8205 parmCount = 3*4 + nameLen*2;
8206 parmCount = (parmCount + 3) & ~3; /* pad to 4 */
8208 otherNameLen = (ULONG)strlen(otherFilename);
8209 oldParmCount = parmCount;
8210 parmCount += 3*4 + otherNameLen*2;
8211 parmCount = (parmCount + 3) & ~3; /* pad to 4 */
8213 if (maxLen < parmCount)
8214 parmCount = 0; /* not enough room */
8216 parmOffset = 8*4 + 39;
8217 parmOffset += 1; /* pad to 4 */
8218 dataOffset = parmOffset + parmCount;
8222 /* Total Parameter Count */
8223 smb_SetSMBParmLong(watch, parmSlot, parmCount); parmSlot += 2;
8224 /* Total Data Count */
8225 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
8226 /* Parameter Count */
8227 smb_SetSMBParmLong(watch, parmSlot, parmCount); parmSlot += 2;
8228 /* Parameter Offset */
8229 smb_SetSMBParmLong(watch, parmSlot, parmOffset); parmSlot += 2;
8230 /* Parameter Displacement */
8231 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
8233 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
8235 smb_SetSMBParmLong(watch, parmSlot, dataOffset); parmSlot += 2;
8236 /* Data Displacement */
8237 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
8238 smb_SetSMBParmByte(watch, parmSlot, 0); /* Setup Count */
8239 smb_SetSMBDataLength(watch, parmCount + 1);
8241 if (parmCount != 0) {
8243 outData = smb_GetSMBData(watch, NULL);
8244 outData++; /* round to get to parmOffset */
8245 oldOutData = outData;
8246 *((DWORD *)outData) = oldParmCount; outData += 4;
8247 /* Next Entry Offset */
8248 *((DWORD *)outData) = action; outData += 4;
8250 *((DWORD *)outData) = nameLen*2; outData += 4;
8251 /* File Name Length */
8252 p = strdup(filename);
8253 if (smb_StoreAnsiFilenames)
8255 mbstowcs((WCHAR *)outData, p, nameLen);
8259 outData = oldOutData + oldParmCount;
8260 *((DWORD *)outData) = 0; outData += 4;
8261 /* Next Entry Offset */
8262 *((DWORD *)outData) = otherAction; outData += 4;
8264 *((DWORD *)outData) = otherNameLen*2;
8265 outData += 4; /* File Name Length */
8266 p = strdup(otherFilename);
8267 if (smb_StoreAnsiFilenames)
8269 mbstowcs((WCHAR *)outData, p, otherNameLen); /* File Name */
8275 * If filename is null, we don't know the cause of the
8276 * change notification. We return zero data (see above),
8277 * and set error code to NT_STATUS_NOTIFY_ENUM_DIR
8278 * (= 0x010C). We set the error code here by hand, without
8279 * modifying wct and bcc.
8281 if (filename == NULL) {
8282 ((smb_t *) watch)->rcls = 0x0C;
8283 ((smb_t *) watch)->reh = 0x01;
8284 ((smb_t *) watch)->errLow = 0;
8285 ((smb_t *) watch)->errHigh = 0;
8286 /* Set NT Status codes flag */
8287 ((smb_t *) watch)->flg2 |= SMB_FLAGS2_32BIT_STATUS;
8290 smb_SendPacket(watch->vcp, watch);
8291 smb_FreePacket(watch);
8294 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
8297 long smb_ReceiveNTCancel(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
8299 unsigned char *replyWctp;
8300 smb_packet_t *watch, *lastWatch;
8301 USHORT fid, watchtree;
8305 osi_Log0(smb_logp, "SMB3 receive NT cancel");
8307 lock_ObtainMutex(&smb_Dir_Watch_Lock);
8308 watch = smb_Directory_Watches;
8310 if (((smb_t *)watch)->uid == ((smb_t *)inp)->uid
8311 && ((smb_t *)watch)->pid == ((smb_t *)inp)->pid
8312 && ((smb_t *)watch)->mid == ((smb_t *)inp)->mid
8313 && ((smb_t *)watch)->tid == ((smb_t *)inp)->tid) {
8314 if (watch == smb_Directory_Watches)
8315 smb_Directory_Watches = watch->nextp;
8317 lastWatch->nextp = watch->nextp;
8318 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
8320 /* Turn off WATCHED flag in scp */
8321 fid = smb_GetSMBParm(watch, 21);
8322 watchtree = smb_GetSMBParm(watch, 22) & 0xffff;
8324 if (vcp != watch->vcp)
8325 osi_Log2(smb_logp, "smb_ReceiveNTCancel: vcp %x not equal to watch vcp %x",
8328 fidp = smb_FindFID(vcp, fid, 0);
8330 osi_Log3(smb_logp, "Cancelling change notification for fid %d wtree %d file %s",
8332 osi_LogSaveString(smb_logp, (fidp)?fidp->NTopen_wholepathp:""));
8335 osi_Log2(smb_logp,"smb_ReceiveNTCancel fidp 0x%p scp 0x%p", fidp, scp);
8336 lock_ObtainMutex(&scp->mx);
8338 scp->flags &= ~CM_SCACHEFLAG_WATCHEDSUBTREE;
8340 scp->flags &= ~CM_SCACHEFLAG_WATCHED;
8341 lock_ReleaseMutex(&scp->mx);
8342 smb_ReleaseFID(fidp);
8344 osi_Log2(smb_logp,"NTCancel unable to resolve fid [%d] in vcp[%x]", fid,vcp);
8347 /* assume STATUS32; return 0xC0000120 (CANCELED) */
8348 replyWctp = watch->wctp;
8352 ((smb_t *)watch)->rcls = 0x20;
8353 ((smb_t *)watch)->reh = 0x1;
8354 ((smb_t *)watch)->errLow = 0;
8355 ((smb_t *)watch)->errHigh = 0xC0;
8356 ((smb_t *)watch)->flg2 |= SMB_FLAGS2_32BIT_STATUS;
8357 smb_SendPacket(vcp, watch);
8358 smb_FreePacket(watch);
8362 watch = watch->nextp;
8364 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
8370 * NT rename also does hard links.
8373 #define RENAME_FLAG_MOVE_CLUSTER_INFORMATION 0x102
8374 #define RENAME_FLAG_HARD_LINK 0x103
8375 #define RENAME_FLAG_RENAME 0x104
8376 #define RENAME_FLAG_COPY 0x105
8378 long smb_ReceiveNTRename(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
8380 char *oldPathp, *newPathp;
8386 attrs = smb_GetSMBParm(inp, 0);
8387 rename_type = smb_GetSMBParm(inp, 1);
8389 if (rename_type != RENAME_FLAG_RENAME && rename_type != RENAME_FLAG_HARD_LINK) {
8390 osi_Log1(smb_logp, "NTRename invalid rename_type [%x]", rename_type);
8391 return CM_ERROR_NOACCESS;
8394 tp = smb_GetSMBData(inp, NULL);
8395 oldPathp = smb_ParseASCIIBlock(tp, &tp);
8396 if (smb_StoreAnsiFilenames)
8397 OemToChar(oldPathp,oldPathp);
8398 newPathp = smb_ParseASCIIBlock(tp, &tp);
8399 if (smb_StoreAnsiFilenames)
8400 OemToChar(newPathp,newPathp);
8402 osi_Log3(smb_logp, "NTRename for [%s]->[%s] type [%s]",
8403 osi_LogSaveString(smb_logp, oldPathp),
8404 osi_LogSaveString(smb_logp, newPathp),
8405 ((rename_type==RENAME_FLAG_RENAME)?"rename":"hardlink"));
8407 if (rename_type == RENAME_FLAG_RENAME) {
8408 code = smb_Rename(vcp,inp,oldPathp,newPathp,attrs);
8409 } else { /* RENAME_FLAG_HARD_LINK */
8410 code = smb_Link(vcp,inp,oldPathp,newPathp);
8417 lock_InitializeMutex(&smb_Dir_Watch_Lock, "Directory Watch List Lock");
8420 cm_user_t *smb_FindCMUserByName(char *usern, char *machine, afs_uint32 flags)
8422 smb_username_t *unp;
8425 unp = smb_FindUserByName(usern, machine, flags);
8427 lock_ObtainMutex(&unp->mx);
8428 unp->userp = cm_NewUser();
8429 lock_ReleaseMutex(&unp->mx);
8430 osi_Log2(smb_logp,"smb_FindCMUserByName New user name[%s] machine[%s]",osi_LogSaveString(smb_logp,usern),osi_LogSaveString(smb_logp,machine));
8432 osi_Log2(smb_logp,"smb_FindCMUserByName Not found name[%s] machine[%s]",osi_LogSaveString(smb_logp,usern),osi_LogSaveString(smb_logp,machine));
8436 smb_ReleaseUsername(unp);