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;
3652 afs_int32 mustFake = 0;
3654 code = cm_FindACLCache(dscp, userp, &rights);
3655 if (code == 0 && !(rights & PRSFS_READ))
3657 else if (code == -1) {
3658 lock_ObtainMutex(&dscp->mx);
3659 code = cm_SyncOp(dscp, NULL, userp, reqp, PRSFS_READ,
3660 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3661 lock_ReleaseMutex(&dscp->mx);
3662 if (code == CM_ERROR_NOACCESS) {
3670 for(patchp = *dirPatchespp; patchp; patchp =
3671 (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
3672 code = cm_GetSCache(&patchp->fid, &scp, userp, reqp);
3676 lock_ObtainMutex(&scp->mx);
3678 code = cm_SyncOp(scp, NULL, userp, reqp, 0,
3679 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3680 if (mustFake || code) {
3681 lock_ReleaseMutex(&scp->mx);
3683 dptr = patchp->dptr;
3685 /* Plug in fake timestamps. A time stamp of 0 causes 'invalid parameter'
3686 errors in the client. */
3687 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO) {
3688 /* 1969-12-31 23:59:59 +00 */
3689 ft.dwHighDateTime = 0x19DB200;
3690 ft.dwLowDateTime = 0x5BB78980;
3692 /* copy to Creation Time */
3693 *((FILETIME *)dptr) = ft;
3696 /* copy to Last Access Time */
3697 *((FILETIME *)dptr) = ft;
3700 /* copy to Last Write Time */
3701 *((FILETIME *)dptr) = ft;
3704 /* copy to Change Time */
3705 *((FILETIME *)dptr) = ft;
3708 switch (scp->fileType) {
3709 case CM_SCACHETYPE_DIRECTORY:
3710 case CM_SCACHETYPE_MOUNTPOINT:
3711 case CM_SCACHETYPE_SYMLINK:
3712 case CM_SCACHETYPE_INVALID:
3713 *((u_long *)dptr) = SMB_ATTR_DIRECTORY;
3716 /* if we get here we either have a normal file
3717 * or we have a file for which we have never
3718 * received status info. In this case, we can
3719 * check the even/odd value of the entry's vnode.
3720 * even means it is to be treated as a directory
3721 * and odd means it is to be treated as a file.
3723 if (mustFake && (scp->fid.vnode & 0x1))
3724 *((u_long *)dptr) = SMB_ATTR_DIRECTORY;
3726 *((u_long *)dptr) = SMB_ATTR_NORMAL;
3729 /* merge in hidden attribute */
3730 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
3731 *((u_long *)dptr) |= SMB_ATTR_HIDDEN;
3735 /* 1969-12-31 23:59:58 +00*/
3736 dosTime = 0xEBBFBF7D;
3738 /* and copy out date */
3739 shortTemp = (dosTime>>16) & 0xffff;
3740 *((u_short *)dptr) = shortTemp;
3743 /* copy out creation time */
3744 shortTemp = dosTime & 0xffff;
3745 *((u_short *)dptr) = shortTemp;
3748 /* and copy out date */
3749 shortTemp = (dosTime>>16) & 0xffff;
3750 *((u_short *)dptr) = shortTemp;
3753 /* copy out access time */
3754 shortTemp = dosTime & 0xffff;
3755 *((u_short *)dptr) = shortTemp;
3758 /* and copy out date */
3759 shortTemp = (dosTime>>16) & 0xffff;
3760 *((u_short *)dptr) = shortTemp;
3763 /* copy out mod time */
3764 shortTemp = dosTime & 0xffff;
3765 *((u_short *)dptr) = shortTemp;
3768 /* set the attribute */
3769 switch (scp->fileType) {
3770 case CM_SCACHETYPE_DIRECTORY:
3771 case CM_SCACHETYPE_MOUNTPOINT:
3772 case CM_SCACHETYPE_SYMLINK:
3773 case CM_SCACHETYPE_INVALID:
3774 attr = SMB_ATTR_DIRECTORY;
3776 attr = SMB_ATTR_NORMAL;
3778 /* merge in hidden (dot file) attribute */
3779 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
3780 attr |= SMB_ATTR_HIDDEN;
3782 *dptr++ = attr & 0xff;
3783 *dptr++ = (attr >> 8) & 0xff;
3786 cm_ReleaseSCache(scp);
3790 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3792 /* now watch for a symlink */
3794 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
3795 lock_ReleaseMutex(&scp->mx);
3796 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, reqp);
3798 /* we have a more accurate file to use (the
3799 * target of the symbolic link). Otherwise,
3800 * we'll just use the symlink anyway.
3802 osi_Log2(smb_logp, "symlink vp %x to vp %x",
3804 cm_ReleaseSCache(scp);
3807 lock_ObtainMutex(&scp->mx);
3810 dptr = patchp->dptr;
3812 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO) {
3814 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
3816 /* copy to Creation Time */
3817 *((FILETIME *)dptr) = ft;
3820 /* copy to Last Access Time */
3821 *((FILETIME *)dptr) = ft;
3824 /* copy to Last Write Time */
3825 *((FILETIME *)dptr) = ft;
3828 /* copy to Change Time */
3829 *((FILETIME *)dptr) = ft;
3832 /* Use length for both file length and alloc length */
3833 *((LARGE_INTEGER *)dptr) = scp->length;
3835 *((LARGE_INTEGER *)dptr) = scp->length;
3838 /* Copy attributes */
3839 lattr = smb_ExtAttributes(scp);
3840 if (code == CM_ERROR_NOSUCHPATH && scp->fileType == CM_SCACHETYPE_SYMLINK) {
3841 if (lattr == SMB_ATTR_NORMAL)
3842 lattr = SMB_ATTR_DIRECTORY;
3844 lattr |= SMB_ATTR_DIRECTORY;
3846 /* merge in hidden (dot file) attribute */
3847 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
3848 if (lattr == SMB_ATTR_NORMAL)
3849 lattr = SMB_ATTR_HIDDEN;
3851 lattr |= SMB_ATTR_HIDDEN;
3853 *((u_long *)dptr) = lattr;
3857 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
3859 /* and copy out date */
3860 shortTemp = (dosTime>>16) & 0xffff;
3861 *((u_short *)dptr) = shortTemp;
3864 /* copy out creation time */
3865 shortTemp = dosTime & 0xffff;
3866 *((u_short *)dptr) = shortTemp;
3869 /* and copy out date */
3870 shortTemp = (dosTime>>16) & 0xffff;
3871 *((u_short *)dptr) = shortTemp;
3874 /* copy out access time */
3875 shortTemp = dosTime & 0xffff;
3876 *((u_short *)dptr) = shortTemp;
3879 /* and copy out date */
3880 shortTemp = (dosTime>>16) & 0xffff;
3881 *((u_short *)dptr) = shortTemp;
3884 /* copy out mod time */
3885 shortTemp = dosTime & 0xffff;
3886 *((u_short *)dptr) = shortTemp;
3889 /* copy out file length and alloc length,
3890 * using the same for both
3892 *((u_long *)dptr) = scp->length.LowPart;
3894 *((u_long *)dptr) = scp->length.LowPart;
3897 /* finally copy out attributes as short */
3898 attr = smb_Attributes(scp);
3899 /* merge in hidden (dot file) attribute */
3900 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
3901 if (lattr == SMB_ATTR_NORMAL)
3902 lattr = SMB_ATTR_HIDDEN;
3904 lattr |= SMB_ATTR_HIDDEN;
3906 *dptr++ = attr & 0xff;
3907 *dptr++ = (attr >> 8) & 0xff;
3910 lock_ReleaseMutex(&scp->mx);
3911 cm_ReleaseSCache(scp);
3914 /* now free the patches */
3915 for (patchp = *dirPatchespp; patchp; patchp = npatchp) {
3916 npatchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q);
3920 /* and mark the list as empty */
3921 *dirPatchespp = NULL;
3926 #ifndef USE_OLD_MATCHING
3927 // char table for case insensitive comparison
3928 char mapCaseTable[256];
3930 VOID initUpperCaseTable(VOID)
3933 for (i = 0; i < 256; ++i)
3934 mapCaseTable[i] = toupper(i);
3935 // make '"' match '.'
3936 mapCaseTable[(int)'"'] = toupper('.');
3937 // make '<' match '*'
3938 mapCaseTable[(int)'<'] = toupper('*');
3939 // make '>' match '?'
3940 mapCaseTable[(int)'>'] = toupper('?');
3943 // Compare 'pattern' (containing metacharacters '*' and '?') with the file
3945 // Note : this procedure works recursively calling itself.
3947 // PSZ pattern : string containing metacharacters.
3948 // PSZ name : file name to be compared with 'pattern'.
3950 // BOOL : TRUE/FALSE (match/mistmatch)
3953 szWildCardMatchFileName(PSZ pattern, PSZ name, int casefold)
3955 PSZ pename; // points to the last 'name' character
3957 pename = name + strlen(name) - 1;
3968 if (*pattern == '\0')
3970 for (p = pename; p >= name; --p) {
3971 if ((casefold && (mapCaseTable[*p] == mapCaseTable[*pattern]) ||
3972 !casefold && (*p == *pattern)) &&
3973 szWildCardMatchFileName(pattern + 1, p + 1, casefold))
3978 if ((casefold && mapCaseTable[*name] != mapCaseTable[*pattern]) ||
3979 (!casefold && *name != *pattern))
3986 /* if all we have left are wildcards, then we match */
3987 for (;*pattern; pattern++) {
3988 if (*pattern != '*' && *pattern != '?')
3994 /* do a case-folding search of the star name mask with the name in namep.
3995 * Return 1 if we match, otherwise 0.
3997 int smb_V3MatchMask(char *namep, char *maskp, int flags)
4000 int i, j, star, qmark, casefold, retval;
4002 /* make sure we only match 8.3 names, if requested */
4003 if ((flags & CM_FLAG_8DOT3) && !cm_Is8Dot3(namep))
4006 casefold = (flags & CM_FLAG_CASEFOLD) ? 1 : 0;
4008 /* optimize the pattern:
4009 * if there is a mixture of '?' and '*',
4010 * for example the sequence "*?*?*?*"
4011 * must be turned into the form "*"
4013 newmask = (char *)malloc(strlen(maskp)+1);
4014 for ( i=0, j=0, star=0, qmark=0; maskp[i]; i++) {
4015 switch ( maskp[i] ) {
4027 } else if ( qmark ) {
4031 newmask[j++] = maskp[i];
4038 } else if ( qmark ) {
4042 newmask[j++] = '\0';
4044 retval = szWildCardMatchFileName(newmask, namep, casefold) ? 1:0;
4050 #else /* USE_OLD_MATCHING */
4051 /* do a case-folding search of the star name mask with the name in namep.
4052 * Return 1 if we match, otherwise 0.
4054 int smb_V3MatchMask(char *namep, char *maskp, int flags)
4056 unsigned char tcp1, tcp2; /* Pattern characters */
4057 unsigned char tcn1; /* Name characters */
4058 int sawDot = 0, sawStar = 0, req8dot3 = 0;
4059 char *starNamep, *starMaskp;
4060 static char nullCharp[] = {0};
4061 int casefold = flags & CM_FLAG_CASEFOLD;
4063 /* make sure we only match 8.3 names, if requested */
4064 req8dot3 = (flags & CM_FLAG_8DOT3);
4065 if (req8dot3 && !cm_Is8Dot3(namep))
4070 /* Next pattern character */
4073 /* Next name character */
4077 /* 0 - end of pattern */
4083 else if (tcp1 == '.' || tcp1 == '"') {
4093 * first dot in pattern;
4094 * must match dot or end of name
4099 else if (tcn1 == '.') {
4108 else if (tcp1 == '?') {
4109 if (tcn1 == 0 || tcn1 == '.')
4114 else if (tcp1 == '>') {
4115 if (tcn1 != 0 && tcn1 != '.')
4119 else if (tcp1 == '*' || tcp1 == '<') {
4123 else if ((req8dot3 && tcp2 == '.') || tcp2 == '"') {
4124 while (req8dot3 && tcn1 != '.' && tcn1 != 0)
4139 * pattern character after '*' is not null or
4140 * period. If it is '?' or '>', we are not
4141 * going to understand it. If it is '*' or
4142 * '<', we are going to skip over it. None of
4143 * these are likely, I hope.
4145 /* skip over '*' and '<' */
4146 while (tcp2 == '*' || tcp2 == '<')
4149 /* skip over characters that don't match tcp2 */
4150 while (req8dot3 && tcn1 != '.' && tcn1 != 0 &&
4151 ((casefold && cm_foldUpper[tcn1] != cm_foldUpper[tcp2]) ||
4152 (!casefold && tcn1 != tcp2)))
4156 if ((req8dot3 && tcn1 == '.') || tcn1 == 0)
4159 /* Remember where we are */
4169 /* tcp1 is not a wildcard */
4170 if ((casefold && cm_foldUpper[tcn1] == cm_foldUpper[tcp1]) ||
4171 (!casefold && tcn1 == tcp1)) {
4176 /* if trying to match a star pattern, go back */
4178 maskp = starMaskp - 2;
4179 namep = starNamep + 1;
4188 #endif /* USE_OLD_MATCHING */
4190 /* smb_ReceiveTran2SearchDir implements both
4191 * Tran2_Find_First and Tran2_Find_Next
4193 #define TRAN2_FIND_FLAG_CLOSE_SEARCH 0x01
4194 #define TRAN2_FIND_FLAG_CLOSE_SEARCH_IF_END 0x02
4195 #define TRAN2_FIND_FLAG_RETURN_RESUME_KEYS 0x04
4196 #define TRAN2_FIND_FLAG_CONTINUE_SEARCH 0x08
4197 #define TRAN2_FIND_FLAG_BACKUP_INTENT 0x10
4199 /* this is an optimized handler for T2SearchDir that handles the case
4200 where there are no wildcards in the search path. I.e. an
4201 application is using FindFirst(Ex) to get information about a
4202 single file or directory. It will attempt to do a single lookup.
4203 If that fails, then smb_ReceiveTran2SearchDir() will fall back to
4204 the usual mechanism.
4206 This function will return either CM_ERROR_NOSUCHFILE or SUCCESS.
4208 long smb_T2SearchDirSingle(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
4212 long code = 0, code2 = 0;
4215 smb_dirListPatch_t *dirListPatchesp;
4216 smb_dirListPatch_t *curPatchp;
4217 long orbytes; /* # of bytes in this output record */
4218 long ohbytes; /* # of bytes, except file name */
4219 long onbytes; /* # of bytes in name, incl. term. null */
4220 cm_scache_t *scp = NULL;
4221 cm_scache_t *targetscp = NULL;
4222 cm_user_t *userp = NULL;
4223 char *op; /* output data ptr */
4224 char *origOp; /* original value of op */
4225 cm_space_t *spacep; /* for pathname buffer */
4226 long maxReturnData; /* max # of return data */
4227 long maxReturnParms; /* max # of return parms */
4228 long bytesInBuffer; /* # data bytes in the output buffer */
4229 char *maskp; /* mask part of path */
4233 smb_tran2Packet_t *outp; /* response packet */
4236 char shortName[13]; /* 8.3 name if needed */
4245 osi_assert(p->opcode == 1);
4247 /* find first; obtain basic parameters from request */
4249 /* note that since we are going to failover to regular
4250 * processing at smb_ReceiveTran2SearchDir(), we shouldn't
4251 * modify any of the input parameters here. */
4252 attribute = p->parmsp[0];
4253 maxCount = p->parmsp[1];
4254 infoLevel = p->parmsp[3];
4255 searchFlags = p->parmsp[2];
4256 pathp = ((char *) p->parmsp) + 12; /* points to path */
4258 maskp = strrchr(pathp, '\\');
4262 maskp++; /* skip over backslash */
4263 /* track if this is likely to match a lot of entries */
4265 osi_Log2(smb_logp, "smb_T2SearchDirSingle : path[%s], mask[%s]",
4266 osi_LogSaveString(smb_logp, pathp),
4267 osi_LogSaveString(smb_logp, maskp));
4269 switch ( infoLevel ) {
4270 case SMB_INFO_STANDARD:
4273 case SMB_INFO_QUERY_EA_SIZE:
4274 s = "InfoQueryEaSize";
4276 case SMB_INFO_QUERY_EAS_FROM_LIST:
4277 s = "InfoQueryEasFromList";
4279 case SMB_FIND_FILE_DIRECTORY_INFO:
4280 s = "FindFileDirectoryInfo";
4282 case SMB_FIND_FILE_FULL_DIRECTORY_INFO:
4283 s = "FindFileFullDirectoryInfo";
4285 case SMB_FIND_FILE_NAMES_INFO:
4286 s = "FindFileNamesInfo";
4288 case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
4289 s = "FindFileBothDirectoryInfo";
4292 s = "unknownInfoLevel";
4295 osi_Log1(smb_logp, "smb_T2SearchDirSingle info level: %s", s);
4298 "smb_T2SearchDirSingle attr 0x%x, info level 0x%x, max count %d, flags 0x%x",
4299 attribute, infoLevel, maxCount, searchFlags);
4301 if (infoLevel > SMB_FIND_FILE_BOTH_DIRECTORY_INFO) {
4302 osi_Log1(smb_logp, "Unsupported InfoLevel 0x%x", infoLevel);
4303 return CM_ERROR_INVAL;
4306 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO)
4307 searchFlags &= ~TRAN2_FIND_FLAG_RETURN_RESUME_KEYS; /* no resume keys */
4309 dirListPatchesp = NULL;
4311 maxReturnData = p->maxReturnData;
4312 maxReturnParms = 10; /* return params for findfirst, which
4313 is the only one we handle.*/
4315 #ifndef CM_CONFIG_MULTITRAN2RESPONSES
4316 if (maxReturnData > 6000)
4317 maxReturnData = 6000;
4318 #endif /* CM_CONFIG_MULTITRAN2RESPONSES */
4320 outp = smb_GetTran2ResponsePacket(vcp, p, opx, maxReturnParms,
4323 osi_Log2(smb_logp, "T2SDSingle search dir count %d [%s]",
4324 maxCount, osi_LogSaveString(smb_logp, pathp));
4326 /* bail out if request looks bad */
4328 smb_FreeTran2Packet(outp);
4329 return CM_ERROR_BADSMB;
4332 userp = smb_GetTran2User(vcp, p);
4334 osi_Log1(smb_logp, "T2SDSingle search dir unable to resolve user [%d]", p->uid);
4335 smb_FreeTran2Packet(outp);
4336 return CM_ERROR_BADSMB;
4339 /* try to get the vnode for the path name next */
4340 spacep = cm_GetSpace();
4341 smb_StripLastComponent(spacep->data, NULL, pathp);
4342 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
4344 cm_ReleaseUser(userp);
4345 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOFILES);
4346 smb_FreeTran2Packet(outp);
4350 code = cm_NameI(cm_data.rootSCachep, spacep->data,
4351 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
4352 userp, tidPathp, &req, &scp);
4353 cm_FreeSpace(spacep);
4356 cm_ReleaseUser(userp);
4357 smb_SendTran2Error(vcp, p, opx, code);
4358 smb_FreeTran2Packet(outp);
4362 #ifdef DFS_SUPPORT_BUT_NOT_FIND_FIRST
4363 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
4364 cm_ReleaseSCache(scp);
4365 cm_ReleaseUser(userp);
4366 if ( WANTS_DFS_PATHNAMES(p) )
4367 code = CM_ERROR_PATH_NOT_COVERED;
4369 code = CM_ERROR_BADSHARENAME;
4370 smb_SendTran2Error(vcp, p, opx, code);
4371 smb_FreeTran2Packet(outp);
4374 #endif /* DFS_SUPPORT */
4375 osi_Log1(smb_logp,"T2SDSingle scp 0x%p", scp);
4377 /* now do a single case sensitive lookup for the file in question */
4378 code = cm_Lookup(scp, maskp, CM_FLAG_NOMOUNTCHASE, userp, &req, &targetscp);
4380 /* if a case sensitive match failed, we try a case insensitive one
4382 if (code == CM_ERROR_NOSUCHFILE) {
4383 code = cm_Lookup(scp, maskp, CM_FLAG_NOMOUNTCHASE | CM_FLAG_CASEFOLD, userp, &req, &targetscp);
4386 if (code == 0 && targetscp->fid.vnode == 0) {
4387 cm_ReleaseSCache(targetscp);
4388 code = CM_ERROR_NOSUCHFILE;
4392 /* if we can't find the directory entry, this block will
4393 return CM_ERROR_NOSUCHFILE, which we will pass on to
4394 smb_ReceiveTran2SearchDir(). */
4395 cm_ReleaseSCache(scp);
4396 cm_ReleaseUser(userp);
4397 if (code != CM_ERROR_NOSUCHFILE) {
4398 smb_SendTran2Error(vcp, p, opx, code);
4401 smb_FreeTran2Packet(outp);
4405 /* now that we have the target in sight, we proceed with filling
4406 up the return data. */
4408 op = origOp = outp->datap;
4411 if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS) {
4412 /* skip over resume key */
4416 if (infoLevel == SMB_FIND_FILE_BOTH_DIRECTORY_INFO
4417 && targetscp->fid.vnode != 0
4418 && !cm_Is8Dot3(maskp)) {
4421 dfid.vnode = htonl(targetscp->fid.vnode);
4422 dfid.unique = htonl(targetscp->fid.unique);
4424 cm_Gen8Dot3NameInt(maskp, &dfid, shortName, &shortNameEnd);
4430 osi_Log4(smb_logp, "T2SDSingle dir vn %u uniq %u name %s (%s)",
4431 htonl(targetscp->fid.vnode),
4432 htonl(targetscp->fid.unique),
4433 osi_LogSaveString(smb_logp, pathp),
4434 NeedShortName ? osi_LogSaveString(smb_logp, shortName) : "");
4436 /* Eliminate entries that don't match requested attributes */
4437 if (smb_hideDotFiles && !(attribute & SMB_ATTR_HIDDEN) &&
4438 smb_IsDotFile(maskp)) {
4440 code = CM_ERROR_NOSUCHFILE;
4441 osi_Log0(smb_logp, "T2SDSingle skipping hidden file");
4446 if (!(attribute & SMB_ATTR_DIRECTORY) &&
4447 (targetscp->fileType == CM_SCACHETYPE_DIRECTORY ||
4448 targetscp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
4449 targetscp->fileType == CM_SCACHETYPE_DFSLINK ||
4450 targetscp->fileType == CM_SCACHETYPE_INVALID)) {
4452 code = CM_ERROR_NOSUCHFILE;
4453 osi_Log0(smb_logp, "T2SDSingle skipping directory or bad link");
4458 /* Check if the name will fit */
4459 if (infoLevel < 0x101)
4460 ohbytes = 23; /* pre-NT */
4461 else if (infoLevel == SMB_FIND_FILE_NAMES_INFO)
4462 ohbytes = 12; /* NT names only */
4464 ohbytes = 64; /* NT */
4466 if (infoLevel == SMB_FIND_FILE_BOTH_DIRECTORY_INFO)
4467 ohbytes += 26; /* Short name & length */
4469 if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS) {
4470 ohbytes += 4; /* if resume key required */
4473 if (infoLevel != SMB_INFO_STANDARD
4474 && infoLevel != SMB_FIND_FILE_DIRECTORY_INFO
4475 && infoLevel != SMB_FIND_FILE_NAMES_INFO)
4476 ohbytes += 4; /* EASIZE */
4478 /* add header to name & term. null */
4479 onbytes = strlen(maskp);
4480 orbytes = ohbytes + onbytes + 1;
4482 /* now, we round up the record to a 4 byte alignment, and we make
4483 * sure that we have enough room here for even the aligned version
4484 * (so we don't have to worry about an * overflow when we pad
4485 * things out below). That's the reason for the alignment
4488 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO)
4489 align = (4 - (orbytes & 3)) & 3;
4493 if (orbytes + align > maxReturnData) {
4495 /* even though this request is unlikely to succeed with a
4496 failover, we do it anyway. */
4497 code = CM_ERROR_NOSUCHFILE;
4498 osi_Log1(smb_logp, "T2 dir search exceed max return data %d",
4503 /* this is one of the entries to use: it is not deleted and it
4504 * matches the star pattern we're looking for. Put out the name,
4505 * preceded by its length.
4507 /* First zero everything else */
4508 memset(origOp, 0, ohbytes);
4510 if (infoLevel <= SMB_FIND_FILE_DIRECTORY_INFO)
4511 *(origOp + ohbytes - 1) = (unsigned char) onbytes;
4512 else if (infoLevel == SMB_FIND_FILE_NAMES_INFO)
4513 *((u_long *)(op + 8)) = onbytes;
4515 *((u_long *)(op + 60)) = onbytes;
4516 strcpy(origOp+ohbytes, maskp);
4517 if (smb_StoreAnsiFilenames)
4518 CharToOem(origOp+ohbytes, origOp+ohbytes);
4520 /* Short name if requested and needed */
4521 if (infoLevel == SMB_FIND_FILE_BOTH_DIRECTORY_INFO) {
4522 if (NeedShortName) {
4523 strcpy(op + 70, shortName);
4524 if (smb_StoreAnsiFilenames)
4525 CharToOem(op + 70, op + 70);
4526 *(op + 68) = (char)(shortNameEnd - shortName);
4530 /* NextEntryOffset and FileIndex */
4531 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO) {
4532 int entryOffset = orbytes + align;
4533 *((u_long *)op) = 0;
4534 *((u_long *)(op+4)) = 0;
4537 if (infoLevel != SMB_FIND_FILE_NAMES_INFO) {
4538 curPatchp = malloc(sizeof(*curPatchp));
4539 osi_QAdd((osi_queue_t **) &dirListPatchesp,
4541 curPatchp->dptr = op;
4542 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO)
4543 curPatchp->dptr += 8;
4545 if (smb_hideDotFiles && smb_IsDotFile(maskp)) {
4546 curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
4548 curPatchp->flags = 0;
4551 curPatchp->fid.cell = targetscp->fid.cell;
4552 curPatchp->fid.volume = targetscp->fid.volume;
4553 curPatchp->fid.vnode = targetscp->fid.vnode;
4554 curPatchp->fid.unique = targetscp->fid.unique;
4557 curPatchp->dep = NULL;
4560 if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS) {
4561 /* put out resume key */
4562 *((u_long *)origOp) = 0;
4565 /* Adjust byte ptr and count */
4566 origOp += orbytes; /* skip entire record */
4567 bytesInBuffer += orbytes;
4569 /* and pad the record out */
4570 while (--align >= 0) {
4575 /* apply the patches */
4576 code2 = smb_ApplyV3DirListPatches(scp, &dirListPatchesp, infoLevel, userp, &req);
4578 outp->parmsp[0] = 0;
4579 outp->parmsp[1] = 1; /* number of names returned */
4580 outp->parmsp[2] = 1; /* end of search */
4581 outp->parmsp[3] = 0; /* nothing wrong with EAS */
4582 outp->parmsp[4] = 0;
4584 outp->totalParms = 10; /* in bytes */
4586 outp->totalData = bytesInBuffer;
4588 osi_Log0(smb_logp, "T2SDSingle done.");
4590 if (code != CM_ERROR_NOSUCHFILE) {
4592 smb_SendTran2Error(vcp, p, opx, code);
4594 smb_SendTran2Packet(vcp, outp, opx);
4599 smb_FreeTran2Packet(outp);
4600 cm_ReleaseSCache(scp);
4601 cm_ReleaseSCache(targetscp);
4602 cm_ReleaseUser(userp);
4608 long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
4613 long code = 0, code2 = 0;
4617 smb_dirListPatch_t *dirListPatchesp;
4618 smb_dirListPatch_t *curPatchp;
4621 long orbytes; /* # of bytes in this output record */
4622 long ohbytes; /* # of bytes, except file name */
4623 long onbytes; /* # of bytes in name, incl. term. null */
4624 osi_hyper_t dirLength;
4625 osi_hyper_t bufferOffset;
4626 osi_hyper_t curOffset;
4628 smb_dirSearch_t *dsp;
4632 cm_pageHeader_t *pageHeaderp;
4633 cm_user_t *userp = NULL;
4636 long nextEntryCookie;
4637 int numDirChunks; /* # of 32 byte dir chunks in this entry */
4638 char *op; /* output data ptr */
4639 char *origOp; /* original value of op */
4640 cm_space_t *spacep; /* for pathname buffer */
4641 long maxReturnData; /* max # of return data */
4642 long maxReturnParms; /* max # of return parms */
4643 long bytesInBuffer; /* # data bytes in the output buffer */
4645 char *maskp; /* mask part of path */
4649 smb_tran2Packet_t *outp; /* response packet */
4652 char shortName[13]; /* 8.3 name if needed */
4664 if (p->opcode == 1) {
4665 /* find first; obtain basic parameters from request */
4666 attribute = p->parmsp[0];
4667 maxCount = p->parmsp[1];
4668 infoLevel = p->parmsp[3];
4669 searchFlags = p->parmsp[2];
4670 pathp = ((char *) p->parmsp) + 12; /* points to path */
4671 if (smb_StoreAnsiFilenames)
4672 OemToChar(pathp,pathp);
4674 maskp = strrchr(pathp, '\\');
4678 maskp++; /* skip over backslash */
4680 /* track if this is likely to match a lot of entries */
4681 starPattern = smb_V3IsStarMask(maskp);
4683 #ifndef NOFINDFIRSTOPTIMIZE
4685 /* if this is for a single directory or file, we let the
4686 optimized routine handle it. The only error it
4687 returns is CM_ERROR_NOSUCHFILE. The */
4688 code = smb_T2SearchDirSingle(vcp, p, opx);
4690 /* we only failover if we see a CM_ERROR_NOSUCHFILE */
4691 if (code != CM_ERROR_NOSUCHFILE) {
4697 dsp = smb_NewDirSearch(1);
4698 dsp->attribute = attribute;
4699 strcpy(dsp->mask, maskp); /* and save mask */
4702 osi_assert(p->opcode == 2);
4703 /* find next; obtain basic parameters from request or open dir file */
4704 dsp = smb_FindDirSearch(p->parmsp[0]);
4705 maxCount = p->parmsp[1];
4706 infoLevel = p->parmsp[2];
4707 nextCookie = p->parmsp[3] | (p->parmsp[4] << 16);
4708 searchFlags = p->parmsp[5];
4710 osi_Log2(smb_logp, "T2 search dir bad search ID: id %d nextCookie 0x%x",
4711 p->parmsp[0], nextCookie);
4712 return CM_ERROR_BADFD;
4714 attribute = dsp->attribute;
4717 starPattern = 1; /* assume, since required a Find Next */
4720 switch ( infoLevel ) {
4721 case SMB_INFO_STANDARD:
4724 case SMB_INFO_QUERY_EA_SIZE:
4725 s = "InfoQueryEaSize";
4727 case SMB_INFO_QUERY_EAS_FROM_LIST:
4728 s = "InfoQueryEasFromList";
4730 case SMB_FIND_FILE_DIRECTORY_INFO:
4731 s = "FindFileDirectoryInfo";
4733 case SMB_FIND_FILE_FULL_DIRECTORY_INFO:
4734 s = "FindFileFullDirectoryInfo";
4736 case SMB_FIND_FILE_NAMES_INFO:
4737 s = "FindFileNamesInfo";
4739 case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
4740 s = "FindFileBothDirectoryInfo";
4743 s = "unknownInfoLevel";
4746 osi_Log1(smb_logp, "T2 search dir info level: %s", s);
4749 "T2 search dir attr 0x%x, info level 0x%x, max count %d, flags 0x%x",
4750 attribute, infoLevel, maxCount, searchFlags);
4752 osi_Log3(smb_logp, "...T2 search op %d, id %d, nextCookie 0x%x",
4753 p->opcode, dsp->cookie, nextCookie);
4755 if (infoLevel > SMB_FIND_FILE_BOTH_DIRECTORY_INFO) {
4756 osi_Log1(smb_logp, "Unsupported InfoLevel 0x%x", infoLevel);
4757 smb_ReleaseDirSearch(dsp);
4758 return CM_ERROR_INVAL;
4761 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO)
4762 searchFlags &= ~TRAN2_FIND_FLAG_RETURN_RESUME_KEYS; /* no resume keys */
4764 dirListPatchesp = NULL;
4766 maxReturnData = p->maxReturnData;
4767 if (p->opcode == 1) /* find first */
4768 maxReturnParms = 10; /* bytes */
4770 maxReturnParms = 8; /* bytes */
4772 #ifndef CM_CONFIG_MULTITRAN2RESPONSES
4773 if (maxReturnData > 6000)
4774 maxReturnData = 6000;
4775 #endif /* CM_CONFIG_MULTITRAN2RESPONSES */
4777 outp = smb_GetTran2ResponsePacket(vcp, p, opx, maxReturnParms,
4780 osi_Log2(smb_logp, "T2 receive search dir count %d [%s]",
4781 maxCount, osi_LogSaveString(smb_logp, pathp));
4783 /* bail out if request looks bad */
4784 if (p->opcode == 1 && !pathp) {
4785 smb_ReleaseDirSearch(dsp);
4786 smb_FreeTran2Packet(outp);
4787 return CM_ERROR_BADSMB;
4790 osi_Log3(smb_logp, "T2 search dir id %d, nextCookie 0x%x, attr 0x%x",
4791 dsp->cookie, nextCookie, attribute);
4793 userp = smb_GetTran2User(vcp, p);
4795 osi_Log1(smb_logp, "T2 search dir unable to resolve user [%d]", p->uid);
4796 smb_ReleaseDirSearch(dsp);
4797 smb_FreeTran2Packet(outp);
4798 return CM_ERROR_BADSMB;
4801 /* try to get the vnode for the path name next */
4802 lock_ObtainMutex(&dsp->mx);
4805 osi_Log2(smb_logp,"smb_ReceiveTran2SearchDir dsp 0x%p scp 0x%p", dsp, scp);
4809 spacep = cm_GetSpace();
4810 smb_StripLastComponent(spacep->data, NULL, pathp);
4811 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
4813 cm_ReleaseUser(userp);
4814 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOFILES);
4815 smb_FreeTran2Packet(outp);
4816 lock_ReleaseMutex(&dsp->mx);
4817 smb_DeleteDirSearch(dsp);
4818 smb_ReleaseDirSearch(dsp);
4821 code = cm_NameI(cm_data.rootSCachep, spacep->data,
4822 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
4823 userp, tidPathp, &req, &scp);
4824 cm_FreeSpace(spacep);
4827 #ifdef DFS_SUPPORT_BUT_NOT_FIND_FIRST
4828 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
4829 cm_ReleaseSCache(scp);
4830 cm_ReleaseUser(userp);
4831 if ( WANTS_DFS_PATHNAMES(p) )
4832 code = CM_ERROR_PATH_NOT_COVERED;
4834 code = CM_ERROR_BADSHARENAME;
4835 smb_SendTran2Error(vcp, p, opx, code);
4836 smb_FreeTran2Packet(outp);
4837 lock_ReleaseMutex(&dsp->mx);
4838 smb_DeleteDirSearch(dsp);
4839 smb_ReleaseDirSearch(dsp);
4842 #endif /* DFS_SUPPORT */
4844 osi_Log2(smb_logp,"smb_ReceiveTran2SearchDir dsp 0x%p scp 0x%p", dsp, scp);
4845 /* we need one hold for the entry we just stored into,
4846 * and one for our own processing. When we're done
4847 * with this function, we'll drop the one for our own
4848 * processing. We held it once from the namei call,
4849 * and so we do another hold now.
4852 lock_ObtainMutex(&scp->mx);
4853 if ((scp->flags & CM_SCACHEFLAG_BULKSTATTING) == 0 &&
4854 LargeIntegerGreaterOrEqualToZero(scp->bulkStatProgress)) {
4855 scp->flags |= CM_SCACHEFLAG_BULKSTATTING;
4856 dsp->flags |= SMB_DIRSEARCH_BULKST;
4858 lock_ReleaseMutex(&scp->mx);
4861 lock_ReleaseMutex(&dsp->mx);
4863 cm_ReleaseUser(userp);
4864 smb_FreeTran2Packet(outp);
4865 smb_DeleteDirSearch(dsp);
4866 smb_ReleaseDirSearch(dsp);
4870 /* get the directory size */
4871 lock_ObtainMutex(&scp->mx);
4872 code = cm_SyncOp(scp, NULL, userp, &req, 0,
4873 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4875 lock_ReleaseMutex(&scp->mx);
4876 cm_ReleaseSCache(scp);
4877 cm_ReleaseUser(userp);
4878 smb_FreeTran2Packet(outp);
4879 smb_DeleteDirSearch(dsp);
4880 smb_ReleaseDirSearch(dsp);
4884 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4887 dirLength = scp->length;
4889 bufferOffset.LowPart = bufferOffset.HighPart = 0;
4890 curOffset.HighPart = 0;
4891 curOffset.LowPart = nextCookie;
4892 origOp = outp->datap;
4900 if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS)
4901 /* skip over resume key */
4904 /* make sure that curOffset.LowPart doesn't point to the first
4905 * 32 bytes in the 2nd through last dir page, and that it doesn't
4906 * point at the first 13 32-byte chunks in the first dir page,
4907 * since those are dir and page headers, and don't contain useful
4910 temp = curOffset.LowPart & (2048-1);
4911 if (curOffset.HighPart == 0 && curOffset.LowPart < 2048) {
4912 /* we're in the first page */
4913 if (temp < 13*32) temp = 13*32;
4916 /* we're in a later dir page */
4917 if (temp < 32) temp = 32;
4920 /* make sure the low order 5 bits are zero */
4923 /* now put temp bits back ito curOffset.LowPart */
4924 curOffset.LowPart &= ~(2048-1);
4925 curOffset.LowPart |= temp;
4927 /* check if we've passed the dir's EOF */
4928 if (LargeIntegerGreaterThanOrEqualTo(curOffset, dirLength)) {
4929 osi_Log0(smb_logp, "T2 search dir passed eof");
4934 /* check if we've returned all the names that will fit in the
4935 * response packet; we check return count as well as the number
4936 * of bytes requested. We check the # of bytes after we find
4937 * the dir entry, since we'll need to check its size.
4939 if (returnedNames >= maxCount) {
4940 osi_Log2(smb_logp, "T2 search dir returnedNames %d >= maxCount %d",
4941 returnedNames, maxCount);
4945 /* see if we can use the bufferp we have now; compute in which
4946 * page the current offset would be, and check whether that's
4947 * the offset of the buffer we have. If not, get the buffer.
4949 thyper.HighPart = curOffset.HighPart;
4950 thyper.LowPart = curOffset.LowPart & ~(cm_data.buf_blockSize-1);
4951 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
4954 buf_Release(bufferp);
4957 lock_ReleaseMutex(&scp->mx);
4958 lock_ObtainRead(&scp->bufCreateLock);
4959 code = buf_Get(scp, &thyper, &bufferp);
4960 lock_ReleaseRead(&scp->bufCreateLock);
4961 lock_ObtainMutex(&dsp->mx);
4963 /* now, if we're doing a star match, do bulk fetching
4964 * of all of the status info for files in the dir.
4967 smb_ApplyV3DirListPatches(scp, &dirListPatchesp,
4970 lock_ObtainMutex(&scp->mx);
4971 if ((dsp->flags & SMB_DIRSEARCH_BULKST) &&
4972 LargeIntegerGreaterThanOrEqualTo(thyper, scp->bulkStatProgress)) {
4973 /* Don't bulk stat if risking timeout */
4974 DWORD now = GetTickCount();
4975 if (now - req.startTime > RDRtimeout * 1000) {
4976 scp->bulkStatProgress = thyper;
4977 scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
4978 dsp->flags &= ~SMB_DIRSEARCH_BULKST;
4980 code = cm_TryBulkStat(scp, &thyper, userp, &req);
4983 lock_ObtainMutex(&scp->mx);
4985 lock_ReleaseMutex(&dsp->mx);
4987 osi_Log2(smb_logp, "T2 search dir buf_Get scp %x failed %d", scp, code);
4991 bufferOffset = thyper;
4993 /* now get the data in the cache */
4995 code = cm_SyncOp(scp, bufferp, userp, &req,
4997 CM_SCACHESYNC_NEEDCALLBACK
4998 | CM_SCACHESYNC_READ);
5000 osi_Log2(smb_logp, "T2 search dir cm_SyncOp scp %x failed %d", scp, code);
5004 cm_SyncOpDone(scp, bufferp, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ);
5006 if (cm_HaveBuffer(scp, bufferp, 0)) {
5007 osi_Log2(smb_logp, "T2 search dir !HaveBuffer scp %x bufferp %x", scp, bufferp);
5011 /* otherwise, load the buffer and try again */
5012 code = cm_GetBuffer(scp, bufferp, NULL, userp,
5015 osi_Log3(smb_logp, "T2 search dir cm_GetBuffer failed scp %x bufferp %x code %d",
5016 scp, bufferp, code);
5021 buf_Release(bufferp);
5025 } /* if (wrong buffer) ... */
5027 /* now we have the buffer containing the entry we're interested
5028 * in; copy it out if it represents a non-deleted entry.
5030 entryInDir = curOffset.LowPart & (2048-1);
5031 entryInBuffer = curOffset.LowPart & (cm_data.buf_blockSize - 1);
5033 /* page header will help tell us which entries are free. Page
5034 * header can change more often than once per buffer, since
5035 * AFS 3 dir page size may be less than (but not more than)
5036 * a buffer package buffer.
5038 /* only look intra-buffer */
5039 temp = curOffset.LowPart & (cm_data.buf_blockSize - 1);
5040 temp &= ~(2048 - 1); /* turn off intra-page bits */
5041 pageHeaderp = (cm_pageHeader_t *) (bufferp->datap + temp);
5043 /* now determine which entry we're looking at in the page.
5044 * If it is free (there's a free bitmap at the start of the
5045 * dir), we should skip these 32 bytes.
5047 slotInPage = (entryInDir & 0x7e0) >> 5;
5048 if (!(pageHeaderp->freeBitmap[slotInPage>>3] &
5049 (1 << (slotInPage & 0x7)))) {
5050 /* this entry is free */
5051 numDirChunks = 1; /* only skip this guy */
5055 tp = bufferp->datap + entryInBuffer;
5056 dep = (cm_dirEntry_t *) tp; /* now points to AFS3 dir entry */
5058 /* while we're here, compute the next entry's location, too,
5059 * since we'll need it when writing out the cookie into the dir
5062 * XXXX Probably should do more sanity checking.
5064 numDirChunks = cm_NameEntries(dep->name, &onbytes);
5066 /* compute offset of cookie representing next entry */
5067 nextEntryCookie = curOffset.LowPart + (CM_DIR_CHUNKSIZE * numDirChunks);
5069 /* Need 8.3 name? */
5071 if (infoLevel == SMB_FIND_FILE_BOTH_DIRECTORY_INFO
5072 && dep->fid.vnode != 0
5073 && !cm_Is8Dot3(dep->name)) {
5074 cm_Gen8Dot3Name(dep, shortName, &shortNameEnd);
5078 osi_Log4(smb_logp, "T2 search dir vn %u uniq %u name %s (%s)",
5079 dep->fid.vnode, dep->fid.unique,
5080 osi_LogSaveString(smb_logp, dep->name),
5081 NeedShortName ? osi_LogSaveString(smb_logp, shortName) : "");
5083 /* When matching, we are using doing a case fold if we have a wildcard mask.
5084 * If we get a non-wildcard match, it's a lookup for a specific file.
5086 if (dep->fid.vnode != 0 &&
5087 (smb_V3MatchMask(dep->name, maskp, (starPattern? CM_FLAG_CASEFOLD : 0)) ||
5089 smb_V3MatchMask(shortName, maskp, CM_FLAG_CASEFOLD)))) {
5091 /* Eliminate entries that don't match requested attributes */
5092 if (smb_hideDotFiles && !(dsp->attribute & SMB_ATTR_HIDDEN) &&
5093 smb_IsDotFile(dep->name)) {
5094 osi_Log0(smb_logp, "T2 search dir skipping hidden");
5095 goto nextEntry; /* no hidden files */
5097 if (!(dsp->attribute & SMB_ATTR_DIRECTORY)) /* no directories */
5099 /* We have already done the cm_TryBulkStat above */
5100 fid.cell = scp->fid.cell;
5101 fid.volume = scp->fid.volume;
5102 fid.vnode = ntohl(dep->fid.vnode);
5103 fid.unique = ntohl(dep->fid.unique);
5104 fileType = cm_FindFileType(&fid);
5105 /*osi_Log2(smb_logp, "smb_ReceiveTran2SearchDir: file %s "
5106 "has filetype %d", dep->name,
5108 if (fileType == CM_SCACHETYPE_DIRECTORY ||
5109 fileType == CM_SCACHETYPE_MOUNTPOINT ||
5110 fileType == CM_SCACHETYPE_DFSLINK ||
5111 fileType == CM_SCACHETYPE_INVALID)
5112 osi_Log0(smb_logp, "T2 search dir skipping directory or bad link");
5116 /* finally check if this name will fit */
5118 /* standard dir entry stuff */
5119 if (infoLevel < 0x101)
5120 ohbytes = 23; /* pre-NT */
5121 else if (infoLevel == SMB_FIND_FILE_NAMES_INFO)
5122 ohbytes = 12; /* NT names only */
5124 ohbytes = 64; /* NT */
5126 if (infoLevel == SMB_FIND_FILE_BOTH_DIRECTORY_INFO)
5127 ohbytes += 26; /* Short name & length */
5129 if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS) {
5130 ohbytes += 4; /* if resume key required */
5133 if (infoLevel != SMB_INFO_STANDARD
5134 && infoLevel != SMB_FIND_FILE_DIRECTORY_INFO
5135 && infoLevel != SMB_FIND_FILE_NAMES_INFO)
5136 ohbytes += 4; /* EASIZE */
5138 /* add header to name & term. null */
5139 orbytes = onbytes + ohbytes + 1;
5141 /* now, we round up the record to a 4 byte alignment,
5142 * and we make sure that we have enough room here for
5143 * even the aligned version (so we don't have to worry
5144 * about an * overflow when we pad things out below).
5145 * That's the reason for the alignment arithmetic below.
5147 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO)
5148 align = (4 - (orbytes & 3)) & 3;
5151 if (orbytes + bytesInBuffer + align > maxReturnData) {
5152 osi_Log1(smb_logp, "T2 dir search exceed max return data %d",
5157 /* this is one of the entries to use: it is not deleted
5158 * and it matches the star pattern we're looking for.
5159 * Put out the name, preceded by its length.
5161 /* First zero everything else */
5162 memset(origOp, 0, ohbytes);
5164 if (infoLevel <= SMB_FIND_FILE_DIRECTORY_INFO)
5165 *(origOp + ohbytes - 1) = (unsigned char) onbytes;
5166 else if (infoLevel == SMB_FIND_FILE_NAMES_INFO)
5167 *((u_long *)(op + 8)) = onbytes;
5169 *((u_long *)(op + 60)) = onbytes;
5170 strcpy(origOp+ohbytes, dep->name);
5171 if (smb_StoreAnsiFilenames)
5172 CharToOem(origOp+ohbytes, origOp+ohbytes);
5174 /* Short name if requested and needed */
5175 if (infoLevel == SMB_FIND_FILE_BOTH_DIRECTORY_INFO) {
5176 if (NeedShortName) {
5177 strcpy(op + 70, shortName);
5178 if (smb_StoreAnsiFilenames)
5179 CharToOem(op + 70, op + 70);
5180 *(op + 68) = (char)(shortNameEnd - shortName);
5184 /* now, adjust the # of entries copied */
5187 /* NextEntryOffset and FileIndex */
5188 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO) {
5189 int entryOffset = orbytes + align;
5190 *((u_long *)op) = entryOffset;
5191 *((u_long *)(op+4)) = nextEntryCookie;
5194 /* now we emit the attribute. This is tricky, since
5195 * we need to really stat the file to find out what
5196 * type of entry we've got. Right now, we're copying
5197 * out data from a buffer, while holding the scp
5198 * locked, so it isn't really convenient to stat
5199 * something now. We'll put in a place holder
5200 * now, and make a second pass before returning this
5201 * to get the real attributes. So, we just skip the
5202 * data for now, and adjust it later. We allocate a
5203 * patch record to make it easy to find this point
5204 * later. The replay will happen at a time when it is
5205 * safe to unlock the directory.
5207 if (infoLevel != SMB_FIND_FILE_NAMES_INFO) {
5208 curPatchp = malloc(sizeof(*curPatchp));
5209 osi_QAdd((osi_queue_t **) &dirListPatchesp,
5211 curPatchp->dptr = op;
5212 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO)
5213 curPatchp->dptr += 8;
5215 if (smb_hideDotFiles && smb_IsDotFile(dep->name)) {
5216 curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
5219 curPatchp->flags = 0;
5221 curPatchp->fid.cell = scp->fid.cell;
5222 curPatchp->fid.volume = scp->fid.volume;
5223 curPatchp->fid.vnode = ntohl(dep->fid.vnode);
5224 curPatchp->fid.unique = ntohl(dep->fid.unique);
5227 curPatchp->dep = dep;
5230 if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS)
5231 /* put out resume key */
5232 *((u_long *)origOp) = nextEntryCookie;
5234 /* Adjust byte ptr and count */
5235 origOp += orbytes; /* skip entire record */
5236 bytesInBuffer += orbytes;
5238 /* and pad the record out */
5239 while (--align >= 0) {
5243 } /* if we're including this name */
5244 else if (!starPattern &&
5246 dep->fid.vnode != 0 &&
5247 smb_V3MatchMask(dep->name, maskp, CM_FLAG_CASEFOLD)) {
5248 /* We were looking for exact matches, but here's an inexact one*/
5253 /* and adjust curOffset to be where the new cookie is */
5254 thyper.HighPart = 0;
5255 thyper.LowPart = CM_DIR_CHUNKSIZE * numDirChunks;
5256 curOffset = LargeIntegerAdd(thyper, curOffset);
5257 } /* while copying data for dir listing */
5259 /* If we didn't get a star pattern, we did an exact match during the first pass.
5260 * If there were no exact matches found, we fail over to inexact matches by
5261 * marking the query as a star pattern (matches all case permutations), and
5262 * re-running the query.
5264 if (returnedNames == 0 && !starPattern && foundInexact) {
5265 osi_Log0(smb_logp,"T2 Search: No exact matches. Re-running for inexact matches");
5270 /* release the mutex */
5271 lock_ReleaseMutex(&scp->mx);
5273 buf_Release(bufferp);
5277 /* apply and free last set of patches; if not doing a star match, this
5278 * will be empty, but better safe (and freeing everything) than sorry.
5280 code2 = smb_ApplyV3DirListPatches(scp, &dirListPatchesp, infoLevel, userp,
5283 /* now put out the final parameters */
5284 if (returnedNames == 0)
5286 if (p->opcode == 1) {
5288 outp->parmsp[0] = (unsigned short) dsp->cookie;
5289 outp->parmsp[1] = returnedNames;
5290 outp->parmsp[2] = eos;
5291 outp->parmsp[3] = 0; /* nothing wrong with EAS */
5292 outp->parmsp[4] = 0;
5293 /* don't need last name to continue
5294 * search, cookie is enough. Normally,
5295 * this is the offset of the file name
5296 * of the last entry returned.
5298 outp->totalParms = 10; /* in bytes */
5302 outp->parmsp[0] = returnedNames;
5303 outp->parmsp[1] = eos;
5304 outp->parmsp[2] = 0; /* EAS error */
5305 outp->parmsp[3] = 0; /* last name, as above */
5306 outp->totalParms = 8; /* in bytes */
5309 /* return # of bytes in the buffer */
5310 outp->totalData = bytesInBuffer;
5312 /* Return error code if unsuccessful on first request */
5313 if (code == 0 && p->opcode == 1 && returnedNames == 0)
5314 code = CM_ERROR_NOSUCHFILE;
5316 osi_Log4(smb_logp, "T2 search dir done, opcode %d, id %d, %d names, code %d",
5317 p->opcode, dsp->cookie, returnedNames, code);
5319 /* if we're supposed to close the search after this request, or if
5320 * we're supposed to close the search if we're done, and we're done,
5321 * or if something went wrong, close the search.
5323 if ((searchFlags & TRAN2_FIND_FLAG_CLOSE_SEARCH) ||
5324 (returnedNames == 0) ||
5325 ((searchFlags & TRAN2_FIND_FLAG_CLOSE_SEARCH_IF_END) && eos) ||
5327 smb_DeleteDirSearch(dsp);
5330 smb_SendTran2Error(vcp, p, opx, code);
5332 smb_SendTran2Packet(vcp, outp, opx);
5334 smb_FreeTran2Packet(outp);
5335 smb_ReleaseDirSearch(dsp);
5336 cm_ReleaseSCache(scp);
5337 cm_ReleaseUser(userp);
5341 long smb_ReceiveV3FindClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5344 smb_dirSearch_t *dsp;
5346 dirHandle = smb_GetSMBParm(inp, 0);
5348 osi_Log1(smb_logp, "SMB3 find close handle %d", dirHandle);
5350 dsp = smb_FindDirSearch(dirHandle);
5353 return CM_ERROR_BADFD;
5355 /* otherwise, we have an FD to destroy */
5356 smb_DeleteDirSearch(dsp);
5357 smb_ReleaseDirSearch(dsp);
5359 /* and return results */
5360 smb_SetSMBDataLength(outp, 0);
5365 long smb_ReceiveV3FindNotifyClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5367 smb_SetSMBDataLength(outp, 0);
5371 long smb_ReceiveV3OpenX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5378 cm_scache_t *dscp; /* dir we're dealing with */
5379 cm_scache_t *scp; /* file we're creating */
5381 int initialModeBits;
5391 int parmSlot; /* which parm we're dealing with */
5400 extraInfo = (smb_GetSMBParm(inp, 2) & 1); /* return extra info */
5401 openFun = smb_GetSMBParm(inp, 8); /* open function */
5402 excl = ((openFun & 3) == 0);
5403 trunc = ((openFun & 3) == 2); /* truncate it */
5404 openMode = (smb_GetSMBParm(inp, 3) & 0x7);
5405 openAction = 0; /* tracks what we did */
5407 attributes = smb_GetSMBParm(inp, 5);
5408 dosTime = smb_GetSMBParm(inp, 6) | (smb_GetSMBParm(inp, 7) << 16);
5410 /* compute initial mode bits based on read-only flag in attributes */
5411 initialModeBits = 0666;
5412 if (attributes & SMB_ATTR_READONLY)
5413 initialModeBits &= ~0222;
5415 pathp = smb_GetSMBData(inp, NULL);
5416 if (smb_StoreAnsiFilenames)
5417 OemToChar(pathp,pathp);
5419 spacep = inp->spacep;
5420 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
5422 if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
5423 /* special case magic file name for receiving IOCTL requests
5424 * (since IOCTL calls themselves aren't getting through).
5427 osi_Log0(smb_logp, "IOCTL Open");
5430 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
5431 smb_SetupIoctlFid(fidp, spacep);
5433 /* set inp->fid so that later read calls in same msg can find fid */
5434 inp->fid = fidp->fid;
5436 /* copy out remainder of the parms */
5438 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
5440 smb_SetSMBParm(outp, parmSlot, /* attrs */ 0); parmSlot++;
5441 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* mod time */
5442 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
5443 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* len */
5444 smb_SetSMBParm(outp, parmSlot, 0x7fff); parmSlot++;
5445 smb_SetSMBParm(outp, parmSlot, openMode); parmSlot++;
5446 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* file type 0 ==> normal file or dir */
5447 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* IPC junk */
5449 /* and the final "always present" stuff */
5450 smb_SetSMBParm(outp, parmSlot, /* openAction found existing file */ 1); parmSlot++;
5451 /* next write out the "unique" ID */
5452 smb_SetSMBParm(outp, parmSlot, 0x1234); parmSlot++;
5453 smb_SetSMBParm(outp, parmSlot, 0x5678); parmSlot++;
5454 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
5455 smb_SetSMBDataLength(outp, 0);
5457 /* and clean up fid reference */
5458 smb_ReleaseFID(fidp);
5462 #ifdef DEBUG_VERBOSE
5464 char *hexp, *asciip;
5465 asciip = (lastNamep ? lastNamep : pathp );
5466 hexp = osi_HexifyString(asciip);
5467 DEBUG_EVENT2("AFS", "V3Open H[%s] A[%s]", hexp, asciip );
5471 userp = smb_GetUserFromVCP(vcp, inp);
5474 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5476 cm_ReleaseUser(userp);
5477 return CM_ERROR_NOSUCHPATH;
5479 code = cm_NameI(cm_data.rootSCachep, pathp,
5480 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
5481 userp, tidPathp, &req, &scp);
5484 if (code == 0 && scp->fileType == CM_SCACHETYPE_DFSLINK) {
5485 cm_ReleaseSCache(scp);
5486 cm_ReleaseUser(userp);
5487 if ( WANTS_DFS_PATHNAMES(inp) )
5488 return CM_ERROR_PATH_NOT_COVERED;
5490 return CM_ERROR_BADSHARENAME;
5492 #endif /* DFS_SUPPORT */
5495 code = cm_NameI(cm_data.rootSCachep, spacep->data,
5496 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
5497 userp, tidPathp, &req, &dscp);
5499 cm_ReleaseUser(userp);
5504 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
5505 cm_ReleaseSCache(dscp);
5506 cm_ReleaseUser(userp);
5507 if ( WANTS_DFS_PATHNAMES(inp) )
5508 return CM_ERROR_PATH_NOT_COVERED;
5510 return CM_ERROR_BADSHARENAME;
5512 #endif /* DFS_SUPPORT */
5513 /* otherwise, scp points to the parent directory. Do a lookup,
5514 * and truncate the file if we find it, otherwise we create the
5521 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD, userp,
5523 if (code && code != CM_ERROR_NOSUCHFILE) {
5524 cm_ReleaseSCache(dscp);
5525 cm_ReleaseUser(userp);
5530 /* if we get here, if code is 0, the file exists and is represented by
5531 * scp. Otherwise, we have to create it. The dir may be represented
5532 * by dscp, or we may have found the file directly. If code is non-zero,
5536 code = cm_CheckOpen(scp, openMode, trunc, userp, &req);
5538 if (dscp) cm_ReleaseSCache(dscp);
5539 cm_ReleaseSCache(scp);
5540 cm_ReleaseUser(userp);
5545 /* oops, file shouldn't be there */
5547 cm_ReleaseSCache(dscp);
5548 cm_ReleaseSCache(scp);
5549 cm_ReleaseUser(userp);
5550 return CM_ERROR_EXISTS;
5554 setAttr.mask = CM_ATTRMASK_LENGTH;
5555 setAttr.length.LowPart = 0;
5556 setAttr.length.HighPart = 0;
5557 code = cm_SetAttr(scp, &setAttr, userp, &req);
5558 openAction = 3; /* truncated existing file */
5560 else openAction = 1; /* found existing file */
5562 else if (!(openFun & SMB_ATTR_DIRECTORY)) {
5563 /* don't create if not found */
5564 if (dscp) cm_ReleaseSCache(dscp);
5565 cm_ReleaseUser(userp);
5566 return CM_ERROR_NOSUCHFILE;
5569 osi_assert(dscp != NULL);
5570 osi_Log1(smb_logp, "smb_ReceiveV3OpenX creating file %s",
5571 osi_LogSaveString(smb_logp, lastNamep));
5572 openAction = 2; /* created file */
5573 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
5574 smb_UnixTimeFromDosUTime(&setAttr.clientModTime, dosTime);
5575 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
5579 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
5580 smb_NotifyChange(FILE_ACTION_ADDED,
5581 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
5582 dscp, lastNamep, NULL, TRUE);
5583 } else if (!excl && code == CM_ERROR_EXISTS) {
5584 /* not an exclusive create, and someone else tried
5585 * creating it already, then we open it anyway. We
5586 * don't bother retrying after this, since if this next
5587 * fails, that means that the file was deleted after we
5588 * started this call.
5590 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
5594 setAttr.mask = CM_ATTRMASK_LENGTH;
5595 setAttr.length.LowPart = 0;
5596 setAttr.length.HighPart = 0;
5597 code = cm_SetAttr(scp, &setAttr, userp, &req);
5599 } /* lookup succeeded */
5603 /* we don't need this any longer */
5605 cm_ReleaseSCache(dscp);
5608 /* something went wrong creating or truncating the file */
5610 cm_ReleaseSCache(scp);
5611 cm_ReleaseUser(userp);
5615 /* make sure we're about to open a file */
5616 if (scp->fileType != CM_SCACHETYPE_FILE) {
5617 cm_ReleaseSCache(scp);
5618 cm_ReleaseUser(userp);
5619 return CM_ERROR_ISDIR;
5622 /* now all we have to do is open the file itself */
5623 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
5627 lock_ObtainMutex(&fidp->mx);
5628 /* save a pointer to the vnode */
5630 lock_ObtainMutex(&scp->mx);
5631 scp->flags |= CM_SCACHEFLAG_SMB_FID;
5632 lock_ReleaseMutex(&scp->mx);
5633 osi_Log2(smb_logp,"smb_ReceiveV3OpenX fidp 0x%p scp 0x%p", fidp, scp);
5635 fidp->userp = userp;
5637 /* compute open mode */
5639 fidp->flags |= SMB_FID_OPENREAD_LISTDIR;
5640 if (openMode == 1 || openMode == 2)
5641 fidp->flags |= SMB_FID_OPENWRITE;
5643 /* remember if the file was newly created */
5645 fidp->flags |= SMB_FID_CREATED;
5647 lock_ReleaseMutex(&fidp->mx);
5648 smb_ReleaseFID(fidp);
5650 cm_Open(scp, 0, userp);
5652 /* set inp->fid so that later read calls in same msg can find fid */
5653 inp->fid = fidp->fid;
5655 /* copy out remainder of the parms */
5657 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
5658 lock_ObtainMutex(&scp->mx);
5660 smb_SetSMBParm(outp, parmSlot, smb_Attributes(scp)); parmSlot++;
5661 smb_DosUTimeFromUnixTime(&dosTime, scp->clientModTime);
5662 smb_SetSMBParm(outp, parmSlot, dosTime & 0xffff); parmSlot++;
5663 smb_SetSMBParm(outp, parmSlot, (dosTime>>16) & 0xffff); parmSlot++;
5664 smb_SetSMBParm(outp, parmSlot, scp->length.LowPart & 0xffff); parmSlot++;
5665 smb_SetSMBParm(outp, parmSlot, (scp->length.LowPart >> 16) & 0xffff); parmSlot++;
5666 smb_SetSMBParm(outp, parmSlot, openMode); parmSlot++;
5667 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* file type 0 ==> normal file or dir */
5668 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* IPC junk */
5670 /* and the final "always present" stuff */
5671 smb_SetSMBParm(outp, parmSlot, openAction); parmSlot++;
5672 /* next write out the "unique" ID */
5673 smb_SetSMBParm(outp, parmSlot, scp->fid.vnode & 0xffff); parmSlot++;
5674 smb_SetSMBParm(outp, parmSlot, scp->fid.volume & 0xffff); parmSlot++;
5675 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
5676 lock_ReleaseMutex(&scp->mx);
5677 smb_SetSMBDataLength(outp, 0);
5679 osi_Log1(smb_logp, "SMB OpenX opening fid %d", fidp->fid);
5681 cm_ReleaseUser(userp);
5682 /* leave scp held since we put it in fidp->scp */
5686 static void smb_GetLockParams(unsigned char LockType,
5688 unsigned int * ppid,
5689 LARGE_INTEGER * pOffset,
5690 LARGE_INTEGER * pLength)
5692 if (LockType & LOCKING_ANDX_LARGE_FILES) {
5694 *ppid = *((USHORT *) *buf);
5695 pOffset->HighPart = *((LONG *)(*buf + 4));
5696 pOffset->LowPart = *((DWORD *)(*buf + 8));
5697 pLength->HighPart = *((LONG *)(*buf + 12));
5698 pLength->LowPart = *((DWORD *)(*buf + 16));
5702 /* Not Large Files */
5703 *ppid = *((USHORT *) *buf);
5704 pOffset->HighPart = 0;
5705 pOffset->LowPart = *((DWORD *)(*buf + 2));
5706 pLength->HighPart = 0;
5707 pLength->LowPart = *((DWORD *)(*buf + 6));
5712 long smb_ReceiveV3LockingX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5719 unsigned char LockType;
5720 unsigned short NumberOfUnlocks, NumberOfLocks;
5724 LARGE_INTEGER LOffset, LLength;
5725 smb_waitingLockRequest_t *wlRequest = NULL;
5726 cm_file_lock_t *lockp;
5734 fid = smb_GetSMBParm(inp, 2);
5735 fid = smb_ChainFID(fid, inp);
5737 fidp = smb_FindFID(vcp, fid, 0);
5739 return CM_ERROR_BADFD;
5741 lock_ObtainMutex(&fidp->mx);
5742 if (fidp->flags & SMB_FID_IOCTL) {
5743 osi_Log0(smb_logp, "smb_ReceiveV3Locking BadFD");
5744 lock_ReleaseMutex(&fidp->mx);
5745 smb_ReleaseFID(fidp);
5746 return CM_ERROR_BADFD;
5749 osi_Log2(smb_logp,"smb_ReceiveV3LockingX fidp 0x%p scp 0x%p", fidp, scp);
5751 lock_ReleaseMutex(&fidp->mx);
5753 /* set inp->fid so that later read calls in same msg can find fid */
5756 userp = smb_GetUserFromVCP(vcp, inp);
5759 lock_ObtainMutex(&scp->mx);
5760 code = cm_SyncOp(scp, NULL, userp, &req, 0,
5761 CM_SCACHESYNC_NEEDCALLBACK
5762 | CM_SCACHESYNC_GETSTATUS
5763 | CM_SCACHESYNC_LOCK);
5765 osi_Log1(smb_logp, "smb_ReceiveV3Locking SyncOp failure code 0x%x", code);
5769 LockType = smb_GetSMBParm(inp, 3) & 0xff;
5770 Timeout = (smb_GetSMBParm(inp, 5) << 16) + smb_GetSMBParm(inp, 4);
5771 NumberOfUnlocks = smb_GetSMBParm(inp, 6);
5772 NumberOfLocks = smb_GetSMBParm(inp, 7);
5774 if (!(fidp->flags & SMB_FID_OPENWRITE) &&
5775 !(LockType & LOCKING_ANDX_SHARED_LOCK)) {
5776 /* somebody wants exclusive locks on a file that they only
5777 opened for reading. We downgrade this to a shared lock. */
5778 osi_Log0(smb_logp, "smb_ReceiveV3Locking reinterpreting exclusive lock as shared for read-only fid");
5779 LockType |= LOCKING_ANDX_SHARED_LOCK;
5782 if ((LockType & LOCKING_ANDX_CANCEL_LOCK) ||
5783 (LockType & LOCKING_ANDX_CHANGE_LOCKTYPE)) {
5785 /* We don't support these requests. Apparently, we can safely
5786 not deal with them too. */
5787 osi_Log1(smb_logp, "smb_ReceiveV3Locking received unsupported request [%s]",
5788 ((LockType & LOCKING_ANDX_CANCEL_LOCK)?
5789 "LOCKING_ANDX_CANCEL_LOCK":
5790 "LOCKING_ANDX_CHANGE_LOCKTYPE"));
5791 /* No need to call osi_LogSaveString since these are string
5794 code = CM_ERROR_BADOP;
5799 op = smb_GetSMBData(inp, NULL);
5801 for (i=0; i<NumberOfUnlocks; i++) {
5802 smb_GetLockParams(LockType, &op, &pid, &LOffset, &LLength);
5804 key = cm_GenerateKey(vcp->vcID, pid, fidp->fid);
5806 code = cm_Unlock(scp, LockType, LOffset, LLength, key, userp, &req);
5814 for (i=0; i<NumberOfLocks; i++) {
5815 smb_GetLockParams(LockType, &op, &pid, &LOffset, &LLength);
5817 key = cm_GenerateKey(vcp->vcID, pid, fidp->fid);
5819 code = cm_Lock(scp, LockType, LOffset, LLength, key, (Timeout != 0),
5820 userp, &req, &lockp);
5822 if (code == CM_ERROR_NOACCESS && LockType == LockWrite &&
5823 (fidp->flags & (SMB_FID_OPENREAD_LISTDIR | SMB_FID_OPENWRITE)) == SMB_FID_OPENREAD_LISTDIR)
5825 code = cm_Lock(scp, LockRead, LOffset, LLength, key, (Timeout != 0),
5826 userp, &req, &lockp);
5829 if (code == CM_ERROR_WOULDBLOCK && Timeout != 0) {
5830 smb_waitingLock_t * wLock;
5832 /* Put on waiting list */
5833 if(wlRequest == NULL) {
5837 LARGE_INTEGER tOffset, tLength;
5839 wlRequest = malloc(sizeof(smb_waitingLockRequest_t));
5841 osi_assert(wlRequest != NULL);
5843 wlRequest->vcp = vcp;
5845 wlRequest->scp = scp;
5846 osi_Log2(smb_logp,"smb_ReceiveV3LockingX wlRequest 0x%p scp 0x%p", wlRequest, scp);
5848 wlRequest->inp = smb_CopyPacket(inp);
5849 wlRequest->outp = smb_CopyPacket(outp);
5850 wlRequest->lockType = LockType;
5851 wlRequest->timeRemaining = Timeout;
5852 wlRequest->locks = NULL;
5854 /* The waiting lock request needs to have enough
5855 information to undo all the locks in the request.
5856 We do the following to store info about locks that
5857 have already been granted. Sure, we can get most
5858 of the info from the packet, but the packet doesn't
5859 hold the result of cm_Lock call. In practice we
5860 only receive packets with one or two locks, so we
5861 are only wasting a few bytes here and there and
5862 only for a limited period of time until the waiting
5863 lock times out or is freed. */
5865 for(opt = op_locks, j=i; j > 0; j--) {
5866 smb_GetLockParams(LockType, &opt, &pid, &tOffset, &tLength);
5868 tkey = cm_GenerateKey(vcp->vcID, pid, fidp->fid);
5870 wLock = malloc(sizeof(smb_waitingLock_t));
5872 osi_assert(wLock != NULL);
5875 wLock->LOffset = tOffset;
5876 wLock->LLength = tLength;
5877 wLock->lockp = NULL;
5878 wLock->state = SMB_WAITINGLOCKSTATE_DONE;
5879 osi_QAdd((osi_queue_t **) &wlRequest->locks,
5884 wLock = malloc(sizeof(smb_waitingLock_t));
5886 osi_assert(wLock != NULL);
5889 wLock->LOffset = LOffset;
5890 wLock->LLength = LLength;
5891 wLock->lockp = lockp;
5892 wLock->state = SMB_WAITINGLOCKSTATE_WAITING;
5893 osi_QAdd((osi_queue_t **) &wlRequest->locks,
5896 osi_Log1(smb_logp, "smb_ReceiveV3Locking WaitingLock created 0x%p",
5904 osi_Log1(smb_logp, "smb_ReceiveV3Locking cm_Lock failure code 0x%x", code);
5911 /* Since something went wrong with the lock number i, we now
5912 have to go ahead and release any locks acquired before the
5913 failure. All locks before lock number i (of which there
5914 are i of them) have either been successful or are waiting.
5915 Either case requires calling cm_Unlock(). */
5917 /* And purge the waiting lock */
5918 if(wlRequest != NULL) {
5919 smb_waitingLock_t * wl;
5920 smb_waitingLock_t * wlNext;
5923 for(wl = wlRequest->locks; wl; wl = wlNext) {
5925 wlNext = (smb_waitingLock_t *) osi_QNext(&wl->q);
5927 ul_code = cm_Unlock(scp, LockType, wl->LOffset, wl->LLength, wl->key, userp, &req);
5930 osi_Log1(smb_logp, "smb_ReceiveV3Locking cm_Unlock returns code %d", ul_code);
5932 osi_Log0(smb_logp, "smb_ReceiveV3Locking cm_Unlock successful");
5935 osi_QRemove((osi_queue_t **) &wlRequest->locks, &wl->q);
5940 smb_ReleaseVC(wlRequest->vcp);
5941 cm_ReleaseSCache(wlRequest->scp);
5942 smb_FreePacket(wlRequest->inp);
5943 smb_FreePacket(wlRequest->outp);
5952 if (wlRequest != NULL) {
5954 lock_ObtainWrite(&smb_globalLock);
5955 osi_QAdd((osi_queue_t **)&smb_allWaitingLocks,
5957 osi_Wakeup((LONG_PTR)&smb_allWaitingLocks);
5958 lock_ReleaseWrite(&smb_globalLock);
5960 /* don't send reply immediately */
5961 outp->flags |= SMB_PACKETFLAG_NOSEND;
5964 smb_SetSMBDataLength(outp, 0);
5968 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_LOCK);
5971 lock_ReleaseMutex(&scp->mx);
5972 cm_ReleaseSCache(scp);
5973 cm_ReleaseUser(userp);
5974 smb_ReleaseFID(fidp);
5979 long smb_ReceiveV3GetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5985 afs_uint32 searchTime;
5991 fid = smb_GetSMBParm(inp, 0);
5992 fid = smb_ChainFID(fid, inp);
5994 fidp = smb_FindFID(vcp, fid, 0);
5996 return CM_ERROR_BADFD;
5998 lock_ObtainMutex(&fidp->mx);
5999 if (fidp->flags & SMB_FID_IOCTL) {
6000 lock_ReleaseMutex(&fidp->mx);
6001 smb_ReleaseFID(fidp);
6002 return CM_ERROR_BADFD;
6005 osi_Log2(smb_logp,"smb_ReceiveV3GetAttributes fidp 0x%p scp 0x%p", fidp, scp);
6007 lock_ReleaseMutex(&fidp->mx);
6009 userp = smb_GetUserFromVCP(vcp, inp);
6012 /* otherwise, stat the file */
6013 lock_ObtainMutex(&scp->mx);
6014 code = cm_SyncOp(scp, NULL, userp, &req, 0,
6015 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
6019 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
6021 /* decode times. We need a search time, but the response to this
6022 * call provides the date first, not the time, as returned in the
6023 * searchTime variable. So we take the high-order bits first.
6025 smb_SearchTimeFromUnixTime(&searchTime, scp->clientModTime);
6026 smb_SetSMBParm(outp, 0, (searchTime >> 16) & 0xffff); /* ctime */
6027 smb_SetSMBParm(outp, 1, searchTime & 0xffff);
6028 smb_SetSMBParm(outp, 2, (searchTime >> 16) & 0xffff); /* atime */
6029 smb_SetSMBParm(outp, 3, searchTime & 0xffff);
6030 smb_SetSMBParm(outp, 4, (searchTime >> 16) & 0xffff); /* mtime */
6031 smb_SetSMBParm(outp, 5, searchTime & 0xffff);
6033 /* now handle file size and allocation size */
6034 smb_SetSMBParm(outp, 6, scp->length.LowPart & 0xffff); /* file size */
6035 smb_SetSMBParm(outp, 7, (scp->length.LowPart >> 16) & 0xffff);
6036 smb_SetSMBParm(outp, 8, scp->length.LowPart & 0xffff); /* alloc size */
6037 smb_SetSMBParm(outp, 9, (scp->length.LowPart >> 16) & 0xffff);
6039 /* file attribute */
6040 smb_SetSMBParm(outp, 10, smb_Attributes(scp));
6042 /* and finalize stuff */
6043 smb_SetSMBDataLength(outp, 0);
6047 lock_ReleaseMutex(&scp->mx);
6048 cm_ReleaseSCache(scp);
6049 cm_ReleaseUser(userp);
6050 smb_ReleaseFID(fidp);
6054 long smb_ReceiveV3SetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6060 afs_uint32 searchTime;
6068 fid = smb_GetSMBParm(inp, 0);
6069 fid = smb_ChainFID(fid, inp);
6071 fidp = smb_FindFID(vcp, fid, 0);
6073 return CM_ERROR_BADFD;
6075 lock_ObtainMutex(&fidp->mx);
6076 if (fidp->flags & SMB_FID_IOCTL) {
6077 lock_ReleaseMutex(&fidp->mx);
6078 smb_ReleaseFID(fidp);
6079 return CM_ERROR_BADFD;
6082 osi_Log2(smb_logp,"smb_ReceiveV3SetAttributes fidp 0x%p scp 0x%p", fidp, scp);
6084 lock_ReleaseMutex(&fidp->mx);
6086 userp = smb_GetUserFromVCP(vcp, inp);
6089 /* now prepare to call cm_setattr. This message only sets various times,
6090 * and AFS only implements mtime, and we'll set the mtime if that's
6091 * requested. The others we'll ignore.
6093 searchTime = smb_GetSMBParm(inp, 5) | (smb_GetSMBParm(inp, 6) << 16);
6095 if (searchTime != 0) {
6096 smb_UnixTimeFromSearchTime(&unixTime, searchTime);
6098 if ( unixTime != -1 ) {
6099 attrs.mask = CM_ATTRMASK_CLIENTMODTIME;
6100 attrs.clientModTime = unixTime;
6101 code = cm_SetAttr(scp, &attrs, userp, &req);
6103 osi_Log1(smb_logp, "SMB receive V3SetAttributes [fid=%ld]", fid);
6105 osi_Log1(smb_logp, "**smb_UnixTimeFromSearchTime failed searchTime=%ld", searchTime);
6111 cm_ReleaseSCache(scp);
6112 cm_ReleaseUser(userp);
6113 smb_ReleaseFID(fidp);
6117 long smb_ReceiveV3WriteX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6120 long count, written = 0, total_written = 0;
6127 int inDataBlockCount;
6129 fd = smb_GetSMBParm(inp, 2);
6130 count = smb_GetSMBParm(inp, 10);
6132 offset.HighPart = 0;
6133 offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
6135 if (*inp->wctp == 14) {
6136 /* we have a request with 64-bit file offsets */
6137 #ifdef AFS_LARGEFILES
6138 offset.HighPart = smb_GetSMBParm(inp, 12) | (smb_GetSMBParm(inp, 13) << 16);
6140 if ((smb_GetSMBParm(inp, 12) | (smb_GetSMBParm(inp, 13) << 16)) != 0) {
6142 osi_Log0(smb_logp, "smb_ReceiveV3WriteX offset requires largefile support");
6143 /* we shouldn't have received this op if we didn't specify
6144 largefile support */
6145 return CM_ERROR_BADOP;
6150 op = inp->data + smb_GetSMBParm(inp, 11);
6151 inDataBlockCount = count;
6153 osi_Log4(smb_logp, "smb_ReceiveV3WriteX fid %d, off 0x%x:%08x, size 0x%x",
6154 fd, offset.HighPart, offset.LowPart, count);
6156 fd = smb_ChainFID(fd, inp);
6157 fidp = smb_FindFID(vcp, fd, 0);
6159 return CM_ERROR_BADFD;
6161 lock_ObtainMutex(&fidp->mx);
6162 if (fidp->flags & SMB_FID_IOCTL) {
6163 lock_ReleaseMutex(&fidp->mx);
6164 code = smb_IoctlV3Write(fidp, vcp, inp, outp);
6165 smb_ReleaseFID(fidp);
6168 lock_ReleaseMutex(&fidp->mx);
6169 userp = smb_GetUserFromVCP(vcp, inp);
6171 /* special case: 0 bytes transferred means there is no data
6172 transferred. A slight departure from SMB_COM_WRITE where this
6173 means that we are supposed to truncate the file at this
6178 LARGE_INTEGER LOffset;
6179 LARGE_INTEGER LLength;
6182 pid = ((smb_t *) inp)->pid;
6183 key = cm_GenerateKey(vcp->vcID, pid, fd);
6185 LOffset.HighPart = offset.HighPart;
6186 LOffset.LowPart = offset.LowPart;
6187 LLength.HighPart = 0;
6188 LLength.LowPart = count;
6191 lock_ObtainMutex(&scp->mx);
6192 code = cm_LockCheckWrite(scp, LOffset, LLength, key);
6193 lock_ReleaseMutex(&scp->mx);
6200 * Work around bug in NT client
6202 * When copying a file, the NT client should first copy the data,
6203 * then copy the last write time. But sometimes the NT client does
6204 * these in the wrong order, so the data copies would inadvertently
6205 * cause the last write time to be overwritten. We try to detect this,
6206 * and don't set client mod time if we think that would go against the
6209 lock_ObtainMutex(&fidp->mx);
6210 if ((fidp->flags & SMB_FID_MTIMESETDONE) != SMB_FID_MTIMESETDONE) {
6211 fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
6212 fidp->scp->clientModTime = time(NULL);
6214 lock_ReleaseMutex(&fidp->mx);
6217 while ( code == 0 && count > 0 ) {
6218 code = smb_WriteData(fidp, &offset, count, op, userp, &written);
6219 if (code == 0 && written == 0)
6220 code = CM_ERROR_PARTIALWRITE;
6222 offset = LargeIntegerAdd(offset,
6223 ConvertLongToLargeInteger(written));
6225 total_written += written;
6231 /* slots 0 and 1 are reserved for request chaining and will be
6232 filled in when we return. */
6233 smb_SetSMBParm(outp, 2, total_written);
6234 smb_SetSMBParm(outp, 3, 0); /* reserved */
6235 smb_SetSMBParm(outp, 4, 0); /* reserved */
6236 smb_SetSMBParm(outp, 5, 0); /* reserved */
6237 smb_SetSMBDataLength(outp, 0);
6240 cm_ReleaseUser(userp);
6241 smb_ReleaseFID(fidp);
6246 long smb_ReceiveV3ReadX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6250 long finalCount = 0;
6259 fd = smb_GetSMBParm(inp, 2);
6260 count = smb_GetSMBParm(inp, 5);
6261 offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
6263 if (*inp->wctp == 12) {
6264 /* a request with 64-bit offsets */
6265 #ifdef AFS_LARGEFILES
6266 offset.HighPart = smb_GetSMBParm(inp, 10) | (smb_GetSMBParm(inp, 11) << 16);
6268 if (LargeIntegerLessThanZero(offset)) {
6269 osi_Log2(smb_logp, "smb_ReceiveV3Read offset too large (0x%x:%08x)",
6270 offset.HighPart, offset.LowPart);
6271 return CM_ERROR_BADSMB;
6274 if ((smb_GetSMBParm(inp, 10) | (smb_GetSMBParm(inp, 11) << 16)) != 0) {
6275 osi_Log0(smb_logp, "smb_ReceiveV3Read offset is 64-bit. Dropping");
6276 return CM_ERROR_BADSMB;
6278 offset.HighPart = 0;
6282 offset.HighPart = 0;
6285 osi_Log4(smb_logp, "smb_ReceiveV3Read fd %d, off 0x%x:%08x, size 0x%x",
6286 fd, offset.HighPart, offset.LowPart, count);
6288 fd = smb_ChainFID(fd, inp);
6289 fidp = smb_FindFID(vcp, fd, 0);
6291 return CM_ERROR_BADFD;
6294 pid = ((smb_t *) inp)->pid;
6295 key = cm_GenerateKey(vcp->vcID, pid, fd);
6297 LARGE_INTEGER LOffset, LLength;
6300 LOffset.HighPart = offset.HighPart;
6301 LOffset.LowPart = offset.LowPart;
6302 LLength.HighPart = 0;
6303 LLength.LowPart = count;
6306 lock_ObtainMutex(&scp->mx);
6307 code = cm_LockCheckRead(scp, LOffset, LLength, key);
6308 lock_ReleaseMutex(&scp->mx);
6312 smb_ReleaseFID(fidp);
6316 /* set inp->fid so that later read calls in same msg can find fid */
6319 lock_ObtainMutex(&fidp->mx);
6320 if (fidp->flags & SMB_FID_IOCTL) {
6321 lock_ReleaseMutex(&fidp->mx);
6322 code = smb_IoctlV3Read(fidp, vcp, inp, outp);
6323 smb_ReleaseFID(fidp);
6326 lock_ReleaseMutex(&fidp->mx);
6328 userp = smb_GetUserFromVCP(vcp, inp);
6330 /* 0 and 1 are reserved for request chaining, were setup by our caller,
6331 * and will be further filled in after we return.
6333 smb_SetSMBParm(outp, 2, 0); /* remaining bytes, for pipes */
6334 smb_SetSMBParm(outp, 3, 0); /* resvd */
6335 smb_SetSMBParm(outp, 4, 0); /* resvd */
6336 smb_SetSMBParm(outp, 5, count); /* # of bytes we're going to read */
6337 /* fill in #6 when we have all the parameters' space reserved */
6338 smb_SetSMBParm(outp, 7, 0); /* resv'd */
6339 smb_SetSMBParm(outp, 8, 0); /* resv'd */
6340 smb_SetSMBParm(outp, 9, 0); /* resv'd */
6341 smb_SetSMBParm(outp, 10, 0); /* resv'd */
6342 smb_SetSMBParm(outp, 11, 0); /* reserved */
6344 /* get op ptr after putting in the parms, since otherwise we don't
6345 * know where the data really is.
6347 op = smb_GetSMBData(outp, NULL);
6349 /* now fill in offset from start of SMB header to first data byte (to op) */
6350 smb_SetSMBParm(outp, 6, ((int) (op - outp->data)));
6352 /* set the packet data length the count of the # of bytes */
6353 smb_SetSMBDataLength(outp, count);
6355 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount);
6357 /* fix some things up */
6358 smb_SetSMBParm(outp, 5, finalCount);
6359 smb_SetSMBDataLength(outp, finalCount);
6361 cm_ReleaseUser(userp);
6362 smb_ReleaseFID(fidp);
6367 * Values for createDisp, copied from NTDDK.H
6369 #define FILE_SUPERSEDE 0 // (???)
6370 #define FILE_OPEN 1 // (open)
6371 #define FILE_CREATE 2 // (exclusive)
6372 #define FILE_OPEN_IF 3 // (non-exclusive)
6373 #define FILE_OVERWRITE 4 // (open & truncate, but do not create)
6374 #define FILE_OVERWRITE_IF 5 // (open & truncate, or create)
6377 #define REQUEST_OPLOCK 2
6378 #define REQUEST_BATCH_OPLOCK 4
6379 #define OPEN_DIRECTORY 8
6380 #define EXTENDED_RESPONSE_REQUIRED 0x10
6382 /* CreateOptions field. */
6383 #define FILE_DIRECTORY_FILE 0x0001
6384 #define FILE_WRITE_THROUGH 0x0002
6385 #define FILE_SEQUENTIAL_ONLY 0x0004
6386 #define FILE_NON_DIRECTORY_FILE 0x0040
6387 #define FILE_NO_EA_KNOWLEDGE 0x0200
6388 #define FILE_EIGHT_DOT_THREE_ONLY 0x0400
6389 #define FILE_RANDOM_ACCESS 0x0800
6390 #define FILE_DELETE_ON_CLOSE 0x1000
6391 #define FILE_OPEN_BY_FILE_ID 0x2000
6393 long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6395 char *pathp, *realPathp;
6399 cm_scache_t *dscp; /* parent dir */
6400 cm_scache_t *scp; /* file to create or open */
6401 cm_scache_t *targetScp; /* if scp is a symlink */
6405 unsigned short nameLength;
6407 unsigned int requestOpLock;
6408 unsigned int requestBatchOpLock;
6409 unsigned int mustBeDir;
6410 unsigned int extendedRespRequired;
6411 unsigned int treeCreate;
6413 unsigned int desiredAccess;
6414 unsigned int extAttributes;
6415 unsigned int createDisp;
6416 unsigned int createOptions;
6417 unsigned int shareAccess;
6418 int initialModeBits;
6419 unsigned short baseFid;
6420 smb_fid_t *baseFidp;
6422 cm_scache_t *baseDirp;
6423 unsigned short openAction;
6432 cm_lock_data_t *ldp = NULL;
6436 /* This code is very long and has a lot of if-then-else clauses
6437 * scp and dscp get reused frequently and we need to ensure that
6438 * we don't lose a reference. Start by ensuring that they are NULL.
6445 nameLength = smb_GetSMBOffsetParm(inp, 2, 1);
6446 flags = smb_GetSMBOffsetParm(inp, 3, 1)
6447 | (smb_GetSMBOffsetParm(inp, 4, 1) << 16);
6448 requestOpLock = flags & REQUEST_OPLOCK;
6449 requestBatchOpLock = flags & REQUEST_BATCH_OPLOCK;
6450 mustBeDir = flags & OPEN_DIRECTORY;
6451 extendedRespRequired = flags & EXTENDED_RESPONSE_REQUIRED;
6454 * Why all of a sudden 32-bit FID?
6455 * We will reject all bits higher than 16.
6457 if (smb_GetSMBOffsetParm(inp, 6, 1) != 0)
6458 return CM_ERROR_INVAL;
6459 baseFid = smb_GetSMBOffsetParm(inp, 5, 1);
6460 desiredAccess = smb_GetSMBOffsetParm(inp, 7, 1)
6461 | (smb_GetSMBOffsetParm(inp, 8, 1) << 16);
6462 extAttributes = smb_GetSMBOffsetParm(inp, 13, 1)
6463 | (smb_GetSMBOffsetParm(inp, 14, 1) << 16);
6464 shareAccess = smb_GetSMBOffsetParm(inp, 15, 1)
6465 | (smb_GetSMBOffsetParm(inp, 16, 1) << 16);
6466 createDisp = smb_GetSMBOffsetParm(inp, 17, 1)
6467 | (smb_GetSMBOffsetParm(inp, 18, 1) << 16);
6468 createOptions = smb_GetSMBOffsetParm(inp, 19, 1)
6469 | (smb_GetSMBOffsetParm(inp, 20, 1) << 16);
6471 /* mustBeDir is never set; createOptions directory bit seems to be
6474 if (createOptions & FILE_DIRECTORY_FILE)
6476 else if (createOptions & FILE_NON_DIRECTORY_FILE)
6482 * compute initial mode bits based on read-only flag in
6483 * extended attributes
6485 initialModeBits = 0666;
6486 if (extAttributes & SMB_ATTR_READONLY)
6487 initialModeBits &= ~0222;
6489 pathp = smb_GetSMBData(inp, NULL);
6490 /* Sometimes path is not null-terminated, so we make a copy. */
6491 realPathp = malloc(nameLength+1);
6492 memcpy(realPathp, pathp, nameLength);
6493 realPathp[nameLength] = 0;
6494 if (smb_StoreAnsiFilenames)
6495 OemToChar(realPathp,realPathp);
6497 spacep = inp->spacep;
6498 smb_StripLastComponent(spacep->data, &lastNamep, realPathp);
6500 osi_Log1(smb_logp,"NTCreateX for [%s]",osi_LogSaveString(smb_logp,realPathp));
6501 osi_Log4(smb_logp,"... da=[%x] ea=[%x] cd=[%x] co=[%x]", desiredAccess, extAttributes, createDisp, createOptions);
6502 osi_Log3(smb_logp,"... share=[%x] flags=[%x] lastNamep=[%s]", shareAccess, flags, osi_LogSaveString(smb_logp,(lastNamep?lastNamep:"null")));
6504 if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
6505 /* special case magic file name for receiving IOCTL requests
6506 * (since IOCTL calls themselves aren't getting through).
6508 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
6509 smb_SetupIoctlFid(fidp, spacep);
6510 osi_Log1(smb_logp,"NTCreateX Setting up IOCTL on fid[%d]",fidp->fid);
6512 /* set inp->fid so that later read calls in same msg can find fid */
6513 inp->fid = fidp->fid;
6517 smb_SetSMBParmByte(outp, parmSlot, 0); /* oplock */
6518 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
6519 smb_SetSMBParmLong(outp, parmSlot, 1); parmSlot += 2; /* Action */
6521 memset(&ft, 0, sizeof(ft));
6522 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
6523 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
6524 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
6525 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
6526 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2; /* attr */
6527 sz.HighPart = 0x7fff; sz.LowPart = 0;
6528 smb_SetSMBParmDouble(outp, parmSlot, (char *)&sz); parmSlot += 4; /* alen */
6529 smb_SetSMBParmDouble(outp, parmSlot, (char *)&sz); parmSlot += 4; /* len */
6530 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* filetype */
6531 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* dev state */
6532 smb_SetSMBParmByte(outp, parmSlot, 0); /* is a dir? */
6533 smb_SetSMBDataLength(outp, 0);
6535 /* clean up fid reference */
6536 smb_ReleaseFID(fidp);
6541 #ifdef DEBUG_VERBOSE
6543 char *hexp, *asciip;
6544 asciip = (lastNamep? lastNamep : realPathp);
6545 hexp = osi_HexifyString( asciip );
6546 DEBUG_EVENT2("AFS", "NTCreateX H[%s] A[%s]", hexp, asciip);
6551 userp = smb_GetUserFromVCP(vcp, inp);
6553 osi_Log1(smb_logp, "NTCreateX Invalid user [%d]", ((smb_t *) inp)->uid);
6555 return CM_ERROR_INVAL;
6560 baseDirp = cm_data.rootSCachep;
6561 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
6562 if (code == CM_ERROR_TIDIPC) {
6563 /* Attempt to use a TID allocated for IPC. The client
6564 * is probably looking for DCE RPC end points which we
6565 * don't support OR it could be looking to make a DFS
6568 osi_Log0(smb_logp, "NTCreateX received IPC TID");
6571 cm_ReleaseUser(userp);
6572 return CM_ERROR_NOSUCHFILE;
6573 #endif /* DFS_SUPPORT */
6576 baseFidp = smb_FindFID(vcp, baseFid, 0);
6578 osi_Log1(smb_logp, "NTCreateX Invalid base fid [%d]", baseFid);
6580 cm_ReleaseUser(userp);
6581 return CM_ERROR_INVAL;
6583 baseDirp = baseFidp->scp;
6587 osi_Log1(smb_logp, "NTCreateX tidPathp=[%s]", (tidPathp==NULL)?"null": osi_LogSaveString(smb_logp,tidPathp));
6589 /* compute open mode */
6591 if (desiredAccess & DELETE)
6592 fidflags |= SMB_FID_OPENDELETE;
6593 if (desiredAccess & AFS_ACCESS_READ)
6594 fidflags |= SMB_FID_OPENREAD_LISTDIR;
6595 if (desiredAccess & AFS_ACCESS_WRITE)
6596 fidflags |= SMB_FID_OPENWRITE;
6597 if (createOptions & FILE_DELETE_ON_CLOSE)
6598 fidflags |= SMB_FID_DELONCLOSE;
6599 if (createOptions & FILE_SEQUENTIAL_ONLY && !(createOptions & FILE_RANDOM_ACCESS))
6600 fidflags |= SMB_FID_SEQUENTIAL;
6601 if (createOptions & FILE_RANDOM_ACCESS && !(createOptions & FILE_SEQUENTIAL_ONLY))
6602 fidflags |= SMB_FID_RANDOM;
6604 /* and the share mode */
6605 if (shareAccess & FILE_SHARE_READ)
6606 fidflags |= SMB_FID_SHARE_READ;
6607 if (shareAccess & FILE_SHARE_WRITE)
6608 fidflags |= SMB_FID_SHARE_WRITE;
6610 osi_Log1(smb_logp, "NTCreateX fidflags 0x%x", fidflags);
6613 /* For an exclusive create, we want to do a case sensitive match for the last component. */
6614 if ( createDisp == FILE_CREATE ||
6615 createDisp == FILE_OVERWRITE ||
6616 createDisp == FILE_OVERWRITE_IF) {
6617 code = cm_NameI(baseDirp, spacep->data, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
6618 userp, tidPathp, &req, &dscp);
6621 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
6622 cm_ReleaseSCache(dscp);
6623 cm_ReleaseUser(userp);
6626 smb_ReleaseFID(baseFidp);
6627 if ( WANTS_DFS_PATHNAMES(inp) )
6628 return CM_ERROR_PATH_NOT_COVERED;
6630 return CM_ERROR_BADSHARENAME;
6632 #endif /* DFS_SUPPORT */
6633 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp, CM_FLAG_FOLLOW,
6635 if (code == CM_ERROR_NOSUCHFILE) {
6636 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp,
6637 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, &req, &scp);
6638 if (code == 0 && realDirFlag == 1) {
6639 cm_ReleaseSCache(scp);
6640 cm_ReleaseSCache(dscp);
6641 cm_ReleaseUser(userp);
6644 smb_ReleaseFID(baseFidp);
6645 return CM_ERROR_EXISTS;
6649 /* we have both scp and dscp */
6651 code = cm_NameI(baseDirp, realPathp, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
6652 userp, tidPathp, &req, &scp);
6654 if (code == 0 && scp->fileType == CM_SCACHETYPE_DFSLINK) {
6655 cm_ReleaseSCache(scp);
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 */
6666 /* we might have scp but not dscp */
6672 if (!foundscp || (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE))) {
6673 /* look up parent directory */
6674 /* If we are trying to create a path (i.e. multiple nested directories), then we don't *need*
6675 * the immediate parent. We have to work our way up realPathp until we hit something that we
6679 /* we might or might not have scp */
6685 code = cm_NameI(baseDirp, spacep->data,
6686 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
6687 userp, tidPathp, &req, &dscp);
6690 if (code == 0 && dscp->fileType == CM_SCACHETYPE_DFSLINK) {
6692 cm_ReleaseSCache(scp);
6693 cm_ReleaseSCache(dscp);
6694 cm_ReleaseUser(userp);
6697 smb_ReleaseFID(baseFidp);
6698 if ( WANTS_DFS_PATHNAMES(inp) )
6699 return CM_ERROR_PATH_NOT_COVERED;
6701 return CM_ERROR_BADSHARENAME;
6703 #endif /* DFS_SUPPORT */
6706 (tp = strrchr(spacep->data,'\\')) &&
6707 (createDisp == FILE_CREATE) &&
6708 (realDirFlag == 1)) {
6711 treeStartp = realPathp + (tp - spacep->data);
6713 if (*tp && !smb_IsLegalFilename(tp)) {
6714 cm_ReleaseUser(userp);
6716 smb_ReleaseFID(baseFidp);
6719 cm_ReleaseSCache(scp);
6720 return CM_ERROR_BADNTFILENAME;
6724 } while (dscp == NULL && code == 0);
6728 /* we might have scp and we might have dscp */
6731 smb_ReleaseFID(baseFidp);
6734 osi_Log0(smb_logp,"NTCreateX parent not found");
6736 cm_ReleaseSCache(scp);
6738 cm_ReleaseSCache(dscp);
6739 cm_ReleaseUser(userp);
6744 if (treeCreate && dscp->fileType == CM_SCACHETYPE_FILE) {
6745 /* A file exists where we want a directory. */
6747 cm_ReleaseSCache(scp);
6748 cm_ReleaseSCache(dscp);
6749 cm_ReleaseUser(userp);
6751 return CM_ERROR_EXISTS;
6755 lastNamep = realPathp;
6759 if (!smb_IsLegalFilename(lastNamep)) {
6761 cm_ReleaseSCache(scp);
6763 cm_ReleaseSCache(dscp);
6764 cm_ReleaseUser(userp);
6766 return CM_ERROR_BADNTFILENAME;
6769 if (!foundscp && !treeCreate) {
6770 if ( createDisp == FILE_CREATE ||
6771 createDisp == FILE_OVERWRITE ||
6772 createDisp == FILE_OVERWRITE_IF)
6774 code = cm_Lookup(dscp, lastNamep,
6775 CM_FLAG_FOLLOW, userp, &req, &scp);
6777 code = cm_Lookup(dscp, lastNamep,
6778 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
6781 if (code && code != CM_ERROR_NOSUCHFILE) {
6783 cm_ReleaseSCache(dscp);
6784 cm_ReleaseUser(userp);
6789 /* we have scp and dscp */
6791 /* we have scp but not dscp */
6793 smb_ReleaseFID(baseFidp);
6796 /* if we get here, if code is 0, the file exists and is represented by
6797 * scp. Otherwise, we have to create it. The dir may be represented
6798 * by dscp, or we may have found the file directly. If code is non-zero,
6801 if (code == 0 && !treeCreate) {
6802 code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp, &req, &ldp);
6805 cm_ReleaseSCache(dscp);
6807 cm_ReleaseSCache(scp);
6808 cm_ReleaseUser(userp);
6813 if (createDisp == FILE_CREATE) {
6814 /* oops, file shouldn't be there */
6815 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
6817 cm_ReleaseSCache(dscp);
6819 cm_ReleaseSCache(scp);
6820 cm_ReleaseUser(userp);
6822 return CM_ERROR_EXISTS;
6825 if ( createDisp == FILE_OVERWRITE ||
6826 createDisp == FILE_OVERWRITE_IF) {
6828 setAttr.mask = CM_ATTRMASK_LENGTH;
6829 setAttr.length.LowPart = 0;
6830 setAttr.length.HighPart = 0;
6831 /* now watch for a symlink */
6833 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
6835 osi_assert(dscp != NULL);
6836 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
6838 /* we have a more accurate file to use (the
6839 * target of the symbolic link). Otherwise,
6840 * we'll just use the symlink anyway.
6842 osi_Log2(smb_logp, "symlink vp %x to vp %x",
6844 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
6845 cm_ReleaseSCache(scp);
6847 code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp, &req, &ldp);
6850 cm_ReleaseSCache(dscp);
6852 cm_ReleaseSCache(scp);
6853 cm_ReleaseUser(userp);
6859 code = cm_SetAttr(scp, &setAttr, userp, &req);
6860 openAction = 3; /* truncated existing file */
6863 openAction = 1; /* found existing file */
6865 } else if (createDisp == FILE_OPEN || createDisp == FILE_OVERWRITE) {
6866 /* don't create if not found */
6868 cm_ReleaseSCache(dscp);
6870 cm_ReleaseSCache(scp);
6871 cm_ReleaseUser(userp);
6873 return CM_ERROR_NOSUCHFILE;
6874 } else if (realDirFlag == 0 || realDirFlag == -1) {
6875 osi_assert(dscp != NULL);
6876 osi_Log1(smb_logp, "smb_ReceiveNTCreateX creating file %s",
6877 osi_LogSaveString(smb_logp, lastNamep));
6878 openAction = 2; /* created file */
6879 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
6880 setAttr.clientModTime = time(NULL);
6881 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp, &req);
6884 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
6885 smb_NotifyChange(FILE_ACTION_ADDED,
6886 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
6887 dscp, lastNamep, NULL, TRUE);
6888 } else if (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE) {
6889 /* Not an exclusive create, and someone else tried
6890 * creating it already, then we open it anyway. We
6891 * don't bother retrying after this, since if this next
6892 * fails, that means that the file was deleted after we
6893 * started this call.
6895 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
6898 if (createDisp == FILE_OVERWRITE_IF) {
6899 setAttr.mask = CM_ATTRMASK_LENGTH;
6900 setAttr.length.LowPart = 0;
6901 setAttr.length.HighPart = 0;
6903 /* now watch for a symlink */
6905 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
6907 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
6909 /* we have a more accurate file to use (the
6910 * target of the symbolic link). Otherwise,
6911 * we'll just use the symlink anyway.
6913 osi_Log2(smb_logp, "symlink vp %x to vp %x",
6915 cm_ReleaseSCache(scp);
6919 code = cm_SetAttr(scp, &setAttr, userp, &req);
6921 } /* lookup succeeded */
6925 char *cp; /* This component */
6926 int clen = 0; /* length of component */
6927 cm_scache_t *tscp1, *tscp2;
6930 /* create directory */
6932 treeStartp = lastNamep;
6933 osi_assert(dscp != NULL);
6934 osi_Log1(smb_logp, "smb_ReceiveNTCreateX creating directory [%s]",
6935 osi_LogSaveString(smb_logp, treeStartp));
6936 openAction = 2; /* created directory */
6938 /* if the request is to create the root directory
6939 * it will appear as a directory name of the nul-string
6940 * and a code of CM_ERROR_NOSUCHFILE
6942 if ( !*treeStartp && code == CM_ERROR_NOSUCHFILE)
6943 code = CM_ERROR_EXISTS;
6945 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
6946 setAttr.clientModTime = time(NULL);
6951 cm_HoldSCache(tscp1);
6955 tp = strchr(pp, '\\');
6958 clen = (int)strlen(cp);
6959 isLast = 1; /* indicate last component. the supplied path never ends in a slash */
6961 clen = (int)(tp - pp);
6962 strncpy(cp,pp,clen);
6969 continue; /* the supplied path can't have consecutive slashes either , but */
6971 /* cp is the next component to be created. */
6972 code = cm_MakeDir(tscp1, cp, 0, &setAttr, userp, &req);
6973 if (code == 0 && (tscp1->flags & CM_SCACHEFLAG_ANYWATCH))
6974 smb_NotifyChange(FILE_ACTION_ADDED,
6975 FILE_NOTIFY_CHANGE_DIR_NAME,
6976 tscp1, cp, NULL, TRUE);
6978 (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE)) {
6979 /* Not an exclusive create, and someone else tried
6980 * creating it already, then we open it anyway. We
6981 * don't bother retrying after this, since if this next
6982 * fails, that means that the file was deleted after we
6983 * started this call.
6985 code = cm_Lookup(tscp1, cp, CM_FLAG_CASEFOLD,
6986 userp, &req, &tscp2);
6991 if (!isLast) { /* for anything other than dscp, release it unless it's the last one */
6992 cm_ReleaseSCache(tscp1);
6993 tscp1 = tscp2; /* Newly created directory will be next parent */
6994 /* the hold is transfered to tscp1 from tscp2 */
6999 cm_ReleaseSCache(dscp);
7002 cm_ReleaseSCache(scp);
7005 * if we get here and code == 0, then scp is the last directory created, and dscp is the
7011 /* something went wrong creating or truncating the file */
7013 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7015 cm_ReleaseSCache(scp);
7017 cm_ReleaseSCache(dscp);
7018 cm_ReleaseUser(userp);
7023 /* make sure we have file vs. dir right (only applies for single component case) */
7024 if (realDirFlag == 0 && scp->fileType != CM_SCACHETYPE_FILE) {
7025 /* now watch for a symlink */
7027 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
7028 cm_scache_t * targetScp = 0;
7029 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
7031 /* we have a more accurate file to use (the
7032 * target of the symbolic link). Otherwise,
7033 * we'll just use the symlink anyway.
7035 osi_Log2(smb_logp, "symlink vp %x to vp %x", scp, targetScp);
7037 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7038 cm_ReleaseSCache(scp);
7043 if (scp->fileType != CM_SCACHETYPE_FILE) {
7045 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7047 cm_ReleaseSCache(dscp);
7048 cm_ReleaseSCache(scp);
7049 cm_ReleaseUser(userp);
7051 return CM_ERROR_ISDIR;
7055 /* (only applies to single component case) */
7056 if (realDirFlag == 1 && scp->fileType == CM_SCACHETYPE_FILE) {
7058 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7059 cm_ReleaseSCache(scp);
7061 cm_ReleaseSCache(dscp);
7062 cm_ReleaseUser(userp);
7064 return CM_ERROR_NOTDIR;
7067 /* open the file itself */
7068 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
7071 /* save a reference to the user */
7073 fidp->userp = userp;
7075 /* If we are restricting sharing, we should do so with a suitable
7077 if (scp->fileType == CM_SCACHETYPE_FILE &&
7078 !(fidflags & SMB_FID_SHARE_WRITE)) {
7080 LARGE_INTEGER LOffset, LLength;
7083 LOffset.HighPart = SMB_FID_QLOCK_HIGH;
7084 LOffset.LowPart = SMB_FID_QLOCK_LOW;
7085 LLength.HighPart = 0;
7086 LLength.LowPart = SMB_FID_QLOCK_LENGTH;
7088 /* If we are not opening the file for writing, then we don't
7089 try to get an exclusive lock. Noone else should be able to
7090 get an exclusive lock on the file anyway, although someone
7091 else can get a shared lock. */
7092 if ((fidflags & SMB_FID_SHARE_READ) ||
7093 !(fidflags & SMB_FID_OPENWRITE)) {
7094 sLockType = LOCKING_ANDX_SHARED_LOCK;
7099 key = cm_GenerateKey(vcp->vcID, SMB_FID_QLOCK_PID, fidp->fid);
7101 lock_ObtainMutex(&scp->mx);
7102 code = cm_Lock(scp, sLockType, LOffset, LLength, key, 0, userp, &req, NULL);
7103 lock_ReleaseMutex(&scp->mx);
7107 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7108 cm_ReleaseSCache(scp);
7110 cm_ReleaseSCache(dscp);
7111 cm_ReleaseUser(userp);
7112 /* Shouldn't this be smb_CloseFID()? fidp->flags = SMB_FID_DELETE; */
7113 smb_CloseFID(vcp, fidp, NULL, 0);
7114 smb_ReleaseFID(fidp);
7120 /* Now its safe to release the file server lock obtained by cm_CheckNTOpen() */
7122 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7124 lock_ObtainMutex(&fidp->mx);
7125 /* save a pointer to the vnode */
7126 fidp->scp = scp; /* Hold transfered to fidp->scp and no longer needed */
7127 lock_ObtainMutex(&scp->mx);
7128 scp->flags |= CM_SCACHEFLAG_SMB_FID;
7129 lock_ReleaseMutex(&scp->mx);
7130 osi_Log2(smb_logp,"smb_ReceiveNTCreateX fidp 0x%p scp 0x%p", fidp, scp);
7132 fidp->flags = fidflags;
7134 /* remember if the file was newly created */
7136 fidp->flags |= SMB_FID_CREATED;
7138 /* save parent dir and pathname for delete or change notification */
7139 if (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE)) {
7140 osi_Log2(smb_logp,"smb_ReceiveNTCreateX fidp 0x%p dscp 0x%p", fidp, dscp);
7141 fidp->flags |= SMB_FID_NTOPEN;
7142 fidp->NTopen_dscp = dscp;
7144 fidp->NTopen_pathp = strdup(lastNamep);
7146 fidp->NTopen_wholepathp = realPathp;
7147 lock_ReleaseMutex(&fidp->mx);
7149 /* we don't need this any longer */
7151 cm_ReleaseSCache(dscp);
7155 cm_Open(scp, 0, userp);
7157 /* set inp->fid so that later read calls in same msg can find fid */
7158 inp->fid = fidp->fid;
7162 lock_ObtainMutex(&scp->mx);
7163 smb_SetSMBParmByte(outp, parmSlot, 0); /* oplock */
7164 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
7165 smb_SetSMBParmLong(outp, parmSlot, openAction); parmSlot += 2;
7166 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
7167 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
7168 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
7169 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
7170 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
7171 smb_SetSMBParmLong(outp, parmSlot, smb_ExtAttributes(scp));
7173 smb_SetSMBParmDouble(outp, parmSlot, (char *)&scp->length); parmSlot += 4;
7174 smb_SetSMBParmDouble(outp, parmSlot, (char *)&scp->length); parmSlot += 4;
7175 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* filetype */
7176 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* dev state */
7177 smb_SetSMBParmByte(outp, parmSlot,
7178 (scp->fileType == CM_SCACHETYPE_DIRECTORY ||
7179 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
7180 scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0); /* is a dir? */
7181 lock_ReleaseMutex(&scp->mx);
7182 smb_SetSMBDataLength(outp, 0);
7184 osi_Log2(smb_logp, "SMB NT CreateX opening fid %d path %s", fidp->fid,
7185 osi_LogSaveString(smb_logp, realPathp));
7187 cm_ReleaseUser(userp);
7188 smb_ReleaseFID(fidp);
7190 /* Can't free realPathp if we get here since
7191 fidp->NTopen_wholepathp is pointing there */
7193 /* leave scp held since we put it in fidp->scp */
7198 * A lot of stuff copied verbatim from NT Create&X to NT Tran Create.
7199 * Instead, ultimately, would like to use a subroutine for common code.
7201 long smb_ReceiveNTTranCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7203 char *pathp, *realPathp;
7207 cm_scache_t *dscp; /* parent dir */
7208 cm_scache_t *scp; /* file to create or open */
7209 cm_scache_t *targetScp; /* if scp is a symlink */
7212 unsigned long nameLength;
7214 unsigned int requestOpLock;
7215 unsigned int requestBatchOpLock;
7216 unsigned int mustBeDir;
7217 unsigned int extendedRespRequired;
7219 unsigned int desiredAccess;
7220 #ifdef DEBUG_VERBOSE
7221 unsigned int allocSize;
7223 unsigned int shareAccess;
7224 unsigned int extAttributes;
7225 unsigned int createDisp;
7226 #ifdef DEBUG_VERBOSE
7229 unsigned int createOptions;
7230 int initialModeBits;
7231 unsigned short baseFid;
7232 smb_fid_t *baseFidp;
7234 cm_scache_t *baseDirp;
7235 unsigned short openAction;
7241 int parmOffset, dataOffset;
7247 cm_lock_data_t *ldp = NULL;
7254 parmOffset = smb_GetSMBOffsetParm(inp, 11, 1)
7255 | (smb_GetSMBOffsetParm(inp, 12, 1) << 16);
7256 parmp = inp->data + parmOffset;
7257 lparmp = (ULONG *) parmp;
7260 requestOpLock = flags & REQUEST_OPLOCK;
7261 requestBatchOpLock = flags & REQUEST_BATCH_OPLOCK;
7262 mustBeDir = flags & OPEN_DIRECTORY;
7263 extendedRespRequired = flags & EXTENDED_RESPONSE_REQUIRED;
7266 * Why all of a sudden 32-bit FID?
7267 * We will reject all bits higher than 16.
7269 if (lparmp[1] & 0xFFFF0000)
7270 return CM_ERROR_INVAL;
7271 baseFid = (unsigned short)lparmp[1];
7272 desiredAccess = lparmp[2];
7273 #ifdef DEBUG_VERBOSE
7274 allocSize = lparmp[3];
7275 #endif /* DEBUG_VERSOSE */
7276 extAttributes = lparmp[5];
7277 shareAccess = lparmp[6];
7278 createDisp = lparmp[7];
7279 createOptions = lparmp[8];
7280 #ifdef DEBUG_VERBOSE
7283 nameLength = lparmp[11];
7285 #ifdef DEBUG_VERBOSE
7286 osi_Log4(smb_logp,"NTTranCreate with da[%x],ea[%x],sa[%x],cd[%x]",desiredAccess,extAttributes,shareAccess,createDisp);
7287 osi_Log3(smb_logp,"... co[%x],sdl[%x],as[%x]",createOptions,sdLen,allocSize);
7288 osi_Log1(smb_logp,"... flags[%x]",flags);
7291 /* mustBeDir is never set; createOptions directory bit seems to be
7294 if (createOptions & FILE_DIRECTORY_FILE)
7296 else if (createOptions & FILE_NON_DIRECTORY_FILE)
7302 * compute initial mode bits based on read-only flag in
7303 * extended attributes
7305 initialModeBits = 0666;
7306 if (extAttributes & SMB_ATTR_READONLY)
7307 initialModeBits &= ~0222;
7309 pathp = parmp + (13 * sizeof(ULONG)) + sizeof(UCHAR);
7310 /* Sometimes path is not null-terminated, so we make a copy. */
7311 realPathp = malloc(nameLength+1);
7312 memcpy(realPathp, pathp, nameLength);
7313 realPathp[nameLength] = 0;
7314 if (smb_StoreAnsiFilenames)
7315 OemToChar(realPathp,realPathp);
7317 spacep = cm_GetSpace();
7318 smb_StripLastComponent(spacep->data, &lastNamep, realPathp);
7321 * Nothing here to handle SMB_IOCTL_FILENAME.
7322 * Will add it if necessary.
7325 #ifdef DEBUG_VERBOSE
7327 char *hexp, *asciip;
7328 asciip = (lastNamep? lastNamep : realPathp);
7329 hexp = osi_HexifyString( asciip );
7330 DEBUG_EVENT2("AFS", "NTTranCreate H[%s] A[%s]", hexp, asciip);
7335 userp = smb_GetUserFromVCP(vcp, inp);
7337 osi_Log1(smb_logp, "NTTranCreate invalid user [%d]", ((smb_t *) inp)->uid);
7339 return CM_ERROR_INVAL;
7344 baseDirp = cm_data.rootSCachep;
7345 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
7346 if (code == CM_ERROR_TIDIPC) {
7347 /* Attempt to use a TID allocated for IPC. The client
7348 * is probably looking for DCE RPC end points which we
7349 * don't support OR it could be looking to make a DFS
7352 osi_Log0(smb_logp, "NTTranCreate received IPC TID");
7355 cm_ReleaseUser(userp);
7356 return CM_ERROR_NOSUCHPATH;
7360 baseFidp = smb_FindFID(vcp, baseFid, 0);
7362 osi_Log1(smb_logp, "NTTranCreate Invalid fid [%d]", baseFid);
7364 cm_ReleaseUser(userp);
7365 return CM_ERROR_INVAL;
7367 baseDirp = baseFidp->scp;
7371 /* compute open mode */
7373 if (desiredAccess & DELETE)
7374 fidflags |= SMB_FID_OPENDELETE;
7375 if (desiredAccess & AFS_ACCESS_READ)
7376 fidflags |= SMB_FID_OPENREAD_LISTDIR;
7377 if (desiredAccess & AFS_ACCESS_WRITE)
7378 fidflags |= SMB_FID_OPENWRITE;
7379 if (createOptions & FILE_DELETE_ON_CLOSE)
7380 fidflags |= SMB_FID_DELONCLOSE;
7381 if (createOptions & FILE_SEQUENTIAL_ONLY && !(createOptions & FILE_RANDOM_ACCESS))
7382 fidflags |= SMB_FID_SEQUENTIAL;
7383 if (createOptions & FILE_RANDOM_ACCESS && !(createOptions & FILE_SEQUENTIAL_ONLY))
7384 fidflags |= SMB_FID_RANDOM;
7386 /* And the share mode */
7387 if (shareAccess & FILE_SHARE_READ)
7388 fidflags |= SMB_FID_SHARE_READ;
7389 if (shareAccess & FILE_SHARE_WRITE)
7390 fidflags |= SMB_FID_SHARE_WRITE;
7394 if ( createDisp == FILE_OPEN ||
7395 createDisp == FILE_OVERWRITE ||
7396 createDisp == FILE_OVERWRITE_IF) {
7397 code = cm_NameI(baseDirp, spacep->data, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
7398 userp, tidPathp, &req, &dscp);
7401 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
7402 cm_ReleaseSCache(dscp);
7403 cm_ReleaseUser(userp);
7406 smb_ReleaseFID(baseFidp);
7407 if ( WANTS_DFS_PATHNAMES(inp) )
7408 return CM_ERROR_PATH_NOT_COVERED;
7410 return CM_ERROR_BADSHARENAME;
7412 #endif /* DFS_SUPPORT */
7413 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp, CM_FLAG_FOLLOW,
7415 if (code == CM_ERROR_NOSUCHFILE) {
7416 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp,
7417 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, &req, &scp);
7418 if (code == 0 && realDirFlag == 1) {
7419 cm_ReleaseSCache(scp);
7420 cm_ReleaseSCache(dscp);
7421 cm_ReleaseUser(userp);
7424 smb_ReleaseFID(baseFidp);
7425 return CM_ERROR_EXISTS;
7431 code = cm_NameI(baseDirp, realPathp, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
7432 userp, tidPathp, &req, &scp);
7434 if (code == 0 && scp->fileType == CM_SCACHETYPE_DFSLINK) {
7435 cm_ReleaseSCache(scp);
7436 cm_ReleaseUser(userp);
7439 smb_ReleaseFID(baseFidp);
7440 if ( WANTS_DFS_PATHNAMES(inp) )
7441 return CM_ERROR_PATH_NOT_COVERED;
7443 return CM_ERROR_BADSHARENAME;
7445 #endif /* DFS_SUPPORT */
7451 if (code != 0 || (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE))) {
7452 /* look up parent directory */
7454 code = cm_NameI(baseDirp, spacep->data,
7455 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
7456 userp, tidPathp, &req, &dscp);
7458 if (code == 0 && dscp->fileType == CM_SCACHETYPE_DFSLINK) {
7459 cm_ReleaseSCache(dscp);
7460 cm_ReleaseUser(userp);
7463 smb_ReleaseFID(baseFidp);
7464 if ( WANTS_DFS_PATHNAMES(inp) )
7465 return CM_ERROR_PATH_NOT_COVERED;
7467 return CM_ERROR_BADSHARENAME;
7469 #endif /* DFS_SUPPORT */
7473 cm_FreeSpace(spacep);
7476 smb_ReleaseFID(baseFidp);
7479 cm_ReleaseUser(userp);
7485 lastNamep = realPathp;
7489 if (!smb_IsLegalFilename(lastNamep))
7490 return CM_ERROR_BADNTFILENAME;
7493 if (createDisp == FILE_CREATE || createDisp == FILE_OVERWRITE_IF) {
7494 code = cm_Lookup(dscp, lastNamep,
7495 CM_FLAG_FOLLOW, userp, &req, &scp);
7497 code = cm_Lookup(dscp, lastNamep,
7498 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
7501 if (code && code != CM_ERROR_NOSUCHFILE) {
7502 cm_ReleaseSCache(dscp);
7503 cm_ReleaseUser(userp);
7510 smb_ReleaseFID(baseFidp);
7511 cm_FreeSpace(spacep);
7514 /* if we get here, if code is 0, the file exists and is represented by
7515 * scp. Otherwise, we have to create it. The dir may be represented
7516 * by dscp, or we may have found the file directly. If code is non-zero,
7520 code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp, &req, &ldp);
7523 cm_ReleaseSCache(dscp);
7524 cm_ReleaseSCache(scp);
7525 cm_ReleaseUser(userp);
7530 if (createDisp == FILE_CREATE) {
7531 /* oops, file shouldn't be there */
7532 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7534 cm_ReleaseSCache(dscp);
7535 cm_ReleaseSCache(scp);
7536 cm_ReleaseUser(userp);
7538 return CM_ERROR_EXISTS;
7541 if (createDisp == FILE_OVERWRITE ||
7542 createDisp == FILE_OVERWRITE_IF) {
7543 setAttr.mask = CM_ATTRMASK_LENGTH;
7544 setAttr.length.LowPart = 0;
7545 setAttr.length.HighPart = 0;
7547 /* now watch for a symlink */
7549 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
7551 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
7553 /* we have a more accurate file to use (the
7554 * target of the symbolic link). Otherwise,
7555 * we'll just use the symlink anyway.
7557 osi_Log2(smb_logp, "symlink vp %x to vp %x",
7559 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7560 cm_ReleaseSCache(scp);
7562 code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp, &req, &ldp);
7565 cm_ReleaseSCache(dscp);
7567 cm_ReleaseSCache(scp);
7568 cm_ReleaseUser(userp);
7574 code = cm_SetAttr(scp, &setAttr, userp, &req);
7575 openAction = 3; /* truncated existing file */
7577 else openAction = 1; /* found existing file */
7579 else if (createDisp == FILE_OPEN || createDisp == FILE_OVERWRITE) {
7580 /* don't create if not found */
7582 cm_ReleaseSCache(dscp);
7583 cm_ReleaseUser(userp);
7585 return CM_ERROR_NOSUCHFILE;
7587 else if (realDirFlag == 0 || realDirFlag == -1) {
7588 osi_assert(dscp != NULL);
7589 osi_Log1(smb_logp, "smb_ReceiveNTTranCreate creating file %s",
7590 osi_LogSaveString(smb_logp, lastNamep));
7591 openAction = 2; /* created file */
7592 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
7593 setAttr.clientModTime = time(NULL);
7594 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
7598 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
7599 smb_NotifyChange(FILE_ACTION_ADDED,
7600 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
7601 dscp, lastNamep, NULL, TRUE);
7602 } else if (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE) {
7603 /* Not an exclusive create, and someone else tried
7604 * creating it already, then we open it anyway. We
7605 * don't bother retrying after this, since if this next
7606 * fails, that means that the file was deleted after we
7607 * started this call.
7609 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
7612 if (createDisp == FILE_OVERWRITE_IF) {
7613 setAttr.mask = CM_ATTRMASK_LENGTH;
7614 setAttr.length.LowPart = 0;
7615 setAttr.length.HighPart = 0;
7617 /* now watch for a symlink */
7619 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
7621 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
7623 /* we have a more accurate file to use (the
7624 * target of the symbolic link). Otherwise,
7625 * we'll just use the symlink anyway.
7627 osi_Log2(smb_logp, "symlink vp %x to vp %x",
7629 cm_ReleaseSCache(scp);
7633 code = cm_SetAttr(scp, &setAttr, userp, &req);
7635 } /* lookup succeeded */
7638 /* create directory */
7639 osi_assert(dscp != NULL);
7641 "smb_ReceiveNTTranCreate creating directory %s",
7642 osi_LogSaveString(smb_logp, lastNamep));
7643 openAction = 2; /* created directory */
7644 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
7645 setAttr.clientModTime = time(NULL);
7646 code = cm_MakeDir(dscp, lastNamep, 0, &setAttr, userp, &req);
7647 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
7648 smb_NotifyChange(FILE_ACTION_ADDED,
7649 FILE_NOTIFY_CHANGE_DIR_NAME,
7650 dscp, lastNamep, NULL, TRUE);
7652 (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE)) {
7653 /* Not an exclusive create, and someone else tried
7654 * creating it already, then we open it anyway. We
7655 * don't bother retrying after this, since if this next
7656 * fails, that means that the file was deleted after we
7657 * started this call.
7659 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
7665 /* something went wrong creating or truncating the file */
7667 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7669 cm_ReleaseSCache(scp);
7670 cm_ReleaseUser(userp);
7675 /* make sure we have file vs. dir right */
7676 if (realDirFlag == 0 && scp->fileType != CM_SCACHETYPE_FILE) {
7677 /* now watch for a symlink */
7679 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
7681 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
7683 /* we have a more accurate file to use (the
7684 * target of the symbolic link). Otherwise,
7685 * we'll just use the symlink anyway.
7687 osi_Log2(smb_logp, "symlink vp %x to vp %x",
7690 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7691 cm_ReleaseSCache(scp);
7696 if (scp->fileType != CM_SCACHETYPE_FILE) {
7698 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7699 cm_ReleaseSCache(scp);
7700 cm_ReleaseUser(userp);
7702 return CM_ERROR_ISDIR;
7706 if (realDirFlag == 1 && scp->fileType == CM_SCACHETYPE_FILE) {
7708 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7709 cm_ReleaseSCache(scp);
7710 cm_ReleaseUser(userp);
7712 return CM_ERROR_NOTDIR;
7715 /* open the file itself */
7716 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
7719 /* save a reference to the user */
7721 fidp->userp = userp;
7723 /* If we are restricting sharing, we should do so with a suitable
7725 if (scp->fileType == CM_SCACHETYPE_FILE &&
7726 !(fidflags & SMB_FID_SHARE_WRITE)) {
7728 LARGE_INTEGER LOffset, LLength;
7731 LOffset.HighPart = SMB_FID_QLOCK_HIGH;
7732 LOffset.LowPart = SMB_FID_QLOCK_LOW;
7733 LLength.HighPart = 0;
7734 LLength.LowPart = SMB_FID_QLOCK_LENGTH;
7736 /* Similar to what we do in handling NTCreateX. We get a
7737 shared lock if we are only opening the file for reading. */
7738 if ((fidflags & SMB_FID_SHARE_READ) ||
7739 !(fidflags & SMB_FID_OPENWRITE)) {
7740 sLockType = LOCKING_ANDX_SHARED_LOCK;
7745 key = cm_GenerateKey(vcp->vcID, SMB_FID_QLOCK_PID, fidp->fid);
7747 lock_ObtainMutex(&scp->mx);
7748 code = cm_Lock(scp, sLockType, LOffset, LLength, key, 0, userp, &req, NULL);
7749 lock_ReleaseMutex(&scp->mx);
7753 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7754 cm_ReleaseSCache(scp);
7755 cm_ReleaseUser(userp);
7756 /* Shouldn't this be smb_CloseFID()? fidp->flags = SMB_FID_DELETE; */
7757 smb_CloseFID(vcp, fidp, NULL, 0);
7758 smb_ReleaseFID(fidp);
7760 return CM_ERROR_SHARING_VIOLATION;
7764 /* Now its safe to drop the file server lock obtained by cm_CheckNTOpen() */
7766 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7768 lock_ObtainMutex(&fidp->mx);
7769 /* save a pointer to the vnode */
7771 lock_ObtainMutex(&scp->mx);
7772 scp->flags |= CM_SCACHEFLAG_SMB_FID;
7773 lock_ReleaseMutex(&scp->mx);
7774 osi_Log2(smb_logp,"smb_ReceiveNTTranCreate fidp 0x%p scp 0x%p", fidp, scp);
7776 fidp->flags = fidflags;
7778 /* remember if the file was newly created */
7780 fidp->flags |= SMB_FID_CREATED;
7782 /* save parent dir and pathname for deletion or change notification */
7783 if (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE)) {
7784 fidp->flags |= SMB_FID_NTOPEN;
7785 fidp->NTopen_dscp = dscp;
7786 osi_Log2(smb_logp,"smb_ReceiveNTTranCreate fidp 0x%p dscp 0x%p", fidp, dscp);
7788 fidp->NTopen_pathp = strdup(lastNamep);
7790 fidp->NTopen_wholepathp = realPathp;
7791 lock_ReleaseMutex(&fidp->mx);
7793 /* we don't need this any longer */
7795 cm_ReleaseSCache(dscp);
7797 cm_Open(scp, 0, userp);
7799 /* set inp->fid so that later read calls in same msg can find fid */
7800 inp->fid = fidp->fid;
7802 /* check whether we are required to send an extended response */
7803 if (!extendedRespRequired) {
7805 parmOffset = 8*4 + 39;
7806 parmOffset += 1; /* pad to 4 */
7807 dataOffset = parmOffset + 70;
7811 /* Total Parameter Count */
7812 smb_SetSMBParmLong(outp, parmSlot, 70); parmSlot += 2;
7813 /* Total Data Count */
7814 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
7815 /* Parameter Count */
7816 smb_SetSMBParmLong(outp, parmSlot, 70); parmSlot += 2;
7817 /* Parameter Offset */
7818 smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
7819 /* Parameter Displacement */
7820 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
7822 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
7824 smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
7825 /* Data Displacement */
7826 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
7827 smb_SetSMBParmByte(outp, parmSlot, 0); /* Setup Count */
7828 smb_SetSMBDataLength(outp, 70);
7830 lock_ObtainMutex(&scp->mx);
7831 outData = smb_GetSMBData(outp, NULL);
7832 outData++; /* round to get to parmOffset */
7833 *outData = 0; outData++; /* oplock */
7834 *outData = 0; outData++; /* reserved */
7835 *((USHORT *)outData) = fidp->fid; outData += 2; /* fid */
7836 *((ULONG *)outData) = openAction; outData += 4;
7837 *((ULONG *)outData) = 0; outData += 4; /* EA error offset */
7838 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
7839 *((FILETIME *)outData) = ft; outData += 8; /* creation time */
7840 *((FILETIME *)outData) = ft; outData += 8; /* last access time */
7841 *((FILETIME *)outData) = ft; outData += 8; /* last write time */
7842 *((FILETIME *)outData) = ft; outData += 8; /* change time */
7843 *((ULONG *)outData) = smb_ExtAttributes(scp); outData += 4;
7844 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* alloc sz */
7845 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* EOF */
7846 *((USHORT *)outData) = 0; outData += 2; /* filetype */
7847 *((USHORT *)outData) = 0; outData += 2; /* dev state */
7848 *((USHORT *)outData) = ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
7849 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
7850 scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0);
7851 outData += 2; /* is a dir? */
7852 lock_ReleaseMutex(&scp->mx);
7855 parmOffset = 8*4 + 39;
7856 parmOffset += 1; /* pad to 4 */
7857 dataOffset = parmOffset + 104;
7861 /* Total Parameter Count */
7862 smb_SetSMBParmLong(outp, parmSlot, 101); parmSlot += 2;
7863 /* Total Data Count */
7864 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
7865 /* Parameter Count */
7866 smb_SetSMBParmLong(outp, parmSlot, 101); parmSlot += 2;
7867 /* Parameter Offset */
7868 smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
7869 /* Parameter Displacement */
7870 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
7872 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
7874 smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
7875 /* Data Displacement */
7876 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
7877 smb_SetSMBParmByte(outp, parmSlot, 0); /* Setup Count */
7878 smb_SetSMBDataLength(outp, 105);
7880 lock_ObtainMutex(&scp->mx);
7881 outData = smb_GetSMBData(outp, NULL);
7882 outData++; /* round to get to parmOffset */
7883 *outData = 0; outData++; /* oplock */
7884 *outData = 1; outData++; /* response type */
7885 *((USHORT *)outData) = fidp->fid; outData += 2; /* fid */
7886 *((ULONG *)outData) = openAction; outData += 4;
7887 *((ULONG *)outData) = 0; outData += 4; /* EA error offset */
7888 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
7889 *((FILETIME *)outData) = ft; outData += 8; /* creation time */
7890 *((FILETIME *)outData) = ft; outData += 8; /* last access time */
7891 *((FILETIME *)outData) = ft; outData += 8; /* last write time */
7892 *((FILETIME *)outData) = ft; outData += 8; /* change time */
7893 *((ULONG *)outData) = smb_ExtAttributes(scp); outData += 4;
7894 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* alloc sz */
7895 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* EOF */
7896 *((USHORT *)outData) = 0; outData += 2; /* filetype */
7897 *((USHORT *)outData) = 0; outData += 2; /* dev state */
7898 *((USHORT *)outData) = ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
7899 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
7900 scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0);
7901 outData += 1; /* is a dir? */
7902 memset(outData,0,24); outData += 24; /* Volume ID and file ID */
7903 *((ULONG *)outData) = 0x001f01ffL; outData += 4; /* Maxmimal access rights */
7904 *((ULONG *)outData) = 0; outData += 4; /* Guest Access rights */
7905 lock_ReleaseMutex(&scp->mx);
7908 osi_Log1(smb_logp, "SMB NTTranCreate opening fid %d", fidp->fid);
7910 cm_ReleaseUser(userp);
7911 smb_ReleaseFID(fidp);
7913 /* free(realPathp); Can't free realPathp here because fidp->NTopen_wholepathp points there */
7914 /* leave scp held since we put it in fidp->scp */
7918 long smb_ReceiveNTTranNotifyChange(smb_vc_t *vcp, smb_packet_t *inp,
7921 smb_packet_t *savedPacketp;
7923 USHORT fid, watchtree;
7927 filter = smb_GetSMBParm(inp, 19) |
7928 (smb_GetSMBParm(inp, 20) << 16);
7929 fid = smb_GetSMBParm(inp, 21);
7930 watchtree = (smb_GetSMBParm(inp, 22) & 0xff) ? 1 : 0;
7932 fidp = smb_FindFID(vcp, fid, 0);
7934 osi_Log1(smb_logp, "ERROR: NotifyChange given invalid fid [%d]", fid);
7935 return CM_ERROR_BADFD;
7938 /* Create a copy of the Directory Watch Packet to use when sending the
7939 * notification if in the future a matching change is detected.
7941 savedPacketp = smb_CopyPacket(inp);
7943 if (savedPacketp->vcp)
7944 smb_ReleaseVC(savedPacketp->vcp);
7945 savedPacketp->vcp = vcp;
7947 /* Add the watch to the list of events to send notifications for */
7948 lock_ObtainMutex(&smb_Dir_Watch_Lock);
7949 savedPacketp->nextp = smb_Directory_Watches;
7950 smb_Directory_Watches = savedPacketp;
7951 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
7954 osi_Log3(smb_logp,"smb_ReceiveNTTranNotifyChange fidp 0x%p scp 0x%p file \"%s\"",
7955 fidp, scp, osi_LogSaveString(smb_logp, fidp->NTopen_wholepathp));
7956 osi_Log3(smb_logp, "Request for NotifyChange filter 0x%x fid %d wtree %d",
7957 filter, fid, watchtree);
7958 if (filter & FILE_NOTIFY_CHANGE_FILE_NAME)
7959 osi_Log0(smb_logp, " Notify Change File Name");
7960 if (filter & FILE_NOTIFY_CHANGE_DIR_NAME)
7961 osi_Log0(smb_logp, " Notify Change Directory Name");
7962 if (filter & FILE_NOTIFY_CHANGE_ATTRIBUTES)
7963 osi_Log0(smb_logp, " Notify Change Attributes");
7964 if (filter & FILE_NOTIFY_CHANGE_SIZE)
7965 osi_Log0(smb_logp, " Notify Change Size");
7966 if (filter & FILE_NOTIFY_CHANGE_LAST_WRITE)
7967 osi_Log0(smb_logp, " Notify Change Last Write");
7968 if (filter & FILE_NOTIFY_CHANGE_LAST_ACCESS)
7969 osi_Log0(smb_logp, " Notify Change Last Access");
7970 if (filter & FILE_NOTIFY_CHANGE_CREATION)
7971 osi_Log0(smb_logp, " Notify Change Creation");
7972 if (filter & FILE_NOTIFY_CHANGE_EA)
7973 osi_Log0(smb_logp, " Notify Change Extended Attributes");
7974 if (filter & FILE_NOTIFY_CHANGE_SECURITY)
7975 osi_Log0(smb_logp, " Notify Change Security");
7976 if (filter & FILE_NOTIFY_CHANGE_STREAM_NAME)
7977 osi_Log0(smb_logp, " Notify Change Stream Name");
7978 if (filter & FILE_NOTIFY_CHANGE_STREAM_SIZE)
7979 osi_Log0(smb_logp, " Notify Change Stream Size");
7980 if (filter & FILE_NOTIFY_CHANGE_STREAM_WRITE)
7981 osi_Log0(smb_logp, " Notify Change Stream Write");
7983 lock_ObtainMutex(&scp->mx);
7985 scp->flags |= CM_SCACHEFLAG_WATCHEDSUBTREE;
7987 scp->flags |= CM_SCACHEFLAG_WATCHED;
7988 lock_ReleaseMutex(&scp->mx);
7989 smb_ReleaseFID(fidp);
7991 outp->flags |= SMB_PACKETFLAG_NOSEND;
7995 unsigned char nullSecurityDesc[36] = {
7996 0x01, /* security descriptor revision */
7997 0x00, /* reserved, should be zero */
7998 0x00, 0x80, /* security descriptor control;
7999 * 0x8000 : self-relative format */
8000 0x14, 0x00, 0x00, 0x00, /* offset of owner SID */
8001 0x1c, 0x00, 0x00, 0x00, /* offset of group SID */
8002 0x00, 0x00, 0x00, 0x00, /* offset of DACL would go here */
8003 0x00, 0x00, 0x00, 0x00, /* offset of SACL would go here */
8004 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
8005 /* "null SID" owner SID */
8006 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
8007 /* "null SID" group SID */
8010 long smb_ReceiveNTTranQuerySecurityDesc(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
8012 int parmOffset, parmCount, dataOffset, dataCount;
8020 ULONG securityInformation;
8022 parmOffset = smb_GetSMBOffsetParm(inp, 11, 1)
8023 | (smb_GetSMBOffsetParm(inp, 12, 1) << 16);
8024 parmp = inp->data + parmOffset;
8025 sparmp = (USHORT *) parmp;
8026 lparmp = (ULONG *) parmp;
8029 securityInformation = lparmp[1];
8031 maxData = smb_GetSMBOffsetParm(inp, 7, 1)
8032 | (smb_GetSMBOffsetParm(inp, 8, 1) << 16);
8040 parmOffset = 8*4 + 39;
8041 parmOffset += 1; /* pad to 4 */
8043 dataOffset = parmOffset + parmCount;
8047 /* Total Parameter Count */
8048 smb_SetSMBParmLong(outp, parmSlot, parmCount); parmSlot += 2;
8049 /* Total Data Count */
8050 smb_SetSMBParmLong(outp, parmSlot, dataCount); parmSlot += 2;
8051 /* Parameter Count */
8052 smb_SetSMBParmLong(outp, parmSlot, parmCount); parmSlot += 2;
8053 /* Parameter Offset */
8054 smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
8055 /* Parameter Displacement */
8056 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8058 smb_SetSMBParmLong(outp, parmSlot, dataCount); parmSlot += 2;
8060 smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
8061 /* Data Displacement */
8062 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8063 smb_SetSMBParmByte(outp, parmSlot, 0); /* Setup Count */
8064 smb_SetSMBDataLength(outp, 1 + parmCount + dataCount);
8066 outData = smb_GetSMBData(outp, NULL);
8067 outData++; /* round to get to parmOffset */
8068 *((ULONG *)outData) = 36; outData += 4; /* length */
8070 if (maxData >= 36) {
8071 memcpy(outData, nullSecurityDesc, 36);
8075 return CM_ERROR_BUFFERTOOSMALL;
8078 long smb_ReceiveNTTransact(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
8080 unsigned short function;
8082 function = smb_GetSMBParm(inp, 18);
8084 osi_Log1(smb_logp, "SMB NT Transact function %d", function);
8086 /* We can handle long names */
8087 if (vcp->flags & SMB_VCFLAG_USENT)
8088 ((smb_t *)outp)->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
8092 return smb_ReceiveNTTranCreate(vcp, inp, outp);
8094 osi_Log0(smb_logp, "SMB NT Transact Ioctl - not implemented");
8097 osi_Log0(smb_logp, "SMB NT Transact SetSecurityDesc - not implemented");
8100 return smb_ReceiveNTTranNotifyChange(vcp, inp, outp);
8102 osi_Log0(smb_logp, "SMB NT Transact Rename - not implemented");
8105 return smb_ReceiveNTTranQuerySecurityDesc(vcp, inp, outp);
8107 return CM_ERROR_INVAL;
8111 * smb_NotifyChange -- find relevant change notification messages and
8114 * If we don't know the file name (i.e. a callback break), filename is
8115 * NULL, and we return a zero-length list.
8117 * At present there is not a single call to smb_NotifyChange that
8118 * has the isDirectParent parameter set to FALSE.
8120 void smb_NotifyChange(DWORD action, DWORD notifyFilter,
8121 cm_scache_t *dscp, char *filename, char *otherFilename,
8122 BOOL isDirectParent)
8124 smb_packet_t *watch, *lastWatch, *nextWatch;
8125 ULONG parmSlot, parmCount, parmOffset, dataOffset, nameLen;
8126 char *outData, *oldOutData;
8130 BOOL twoEntries = FALSE;
8131 ULONG otherNameLen, oldParmCount = 0;
8135 /* Get ready for rename within directory */
8136 if (action == FILE_ACTION_RENAMED_OLD_NAME && otherFilename != NULL) {
8138 otherAction = FILE_ACTION_RENAMED_NEW_NAME;
8141 osi_Log4(smb_logp,"in smb_NotifyChange for file [%s] dscp [%p] notification 0x%x parent %d",
8142 osi_LogSaveString(smb_logp,filename),dscp, notifyFilter, isDirectParent);
8144 osi_Log0(smb_logp," FILE_ACTION_NONE");
8145 if (action == FILE_ACTION_ADDED)
8146 osi_Log0(smb_logp," FILE_ACTION_ADDED");
8147 if (action == FILE_ACTION_REMOVED)
8148 osi_Log0(smb_logp," FILE_ACTION_REMOVED");
8149 if (action == FILE_ACTION_MODIFIED)
8150 osi_Log0(smb_logp," FILE_ACTION_MODIFIED");
8151 if (action == FILE_ACTION_RENAMED_OLD_NAME)
8152 osi_Log0(smb_logp," FILE_ACTION_RENAMED_OLD_NAME");
8153 if (action == FILE_ACTION_RENAMED_NEW_NAME)
8154 osi_Log0(smb_logp," FILE_ACTION_RENAMED_NEW_NAME");
8156 lock_ObtainMutex(&smb_Dir_Watch_Lock);
8157 watch = smb_Directory_Watches;
8159 filter = smb_GetSMBParm(watch, 19)
8160 | (smb_GetSMBParm(watch, 20) << 16);
8161 fid = smb_GetSMBParm(watch, 21);
8162 wtree = (smb_GetSMBParm(watch, 22) & 0xff) ? 1 : 0;
8164 maxLen = smb_GetSMBOffsetParm(watch, 5, 1)
8165 | (smb_GetSMBOffsetParm(watch, 6, 1) << 16);
8168 * Strange hack - bug in NT Client and NT Server that we must emulate?
8170 if ((filter == (FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME)) && wtree)
8171 filter |= FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_ATTRIBUTES;
8173 fidp = smb_FindFID(watch->vcp, fid, 0);
8175 osi_Log2(smb_logp," no fidp for fid[%d] in vcp 0x%p",fid, watch->vcp);
8177 watch = watch->nextp;
8180 if (fidp->scp != dscp
8181 || (filter & notifyFilter) == 0
8182 || (!isDirectParent && !wtree)) {
8183 osi_Log1(smb_logp," skipping fidp->scp[%x]", fidp->scp);
8184 smb_ReleaseFID(fidp);
8186 watch = watch->nextp;
8189 smb_ReleaseFID(fidp);
8192 "Sending Change Notification for fid %d filter 0x%x wtree %d file %s",
8193 fid, filter, wtree, osi_LogSaveString(smb_logp, filename));
8194 if (filter & FILE_NOTIFY_CHANGE_FILE_NAME)
8195 osi_Log0(smb_logp, " Notify Change File Name");
8196 if (filter & FILE_NOTIFY_CHANGE_DIR_NAME)
8197 osi_Log0(smb_logp, " Notify Change Directory Name");
8198 if (filter & FILE_NOTIFY_CHANGE_ATTRIBUTES)
8199 osi_Log0(smb_logp, " Notify Change Attributes");
8200 if (filter & FILE_NOTIFY_CHANGE_SIZE)
8201 osi_Log0(smb_logp, " Notify Change Size");
8202 if (filter & FILE_NOTIFY_CHANGE_LAST_WRITE)
8203 osi_Log0(smb_logp, " Notify Change Last Write");
8204 if (filter & FILE_NOTIFY_CHANGE_LAST_ACCESS)
8205 osi_Log0(smb_logp, " Notify Change Last Access");
8206 if (filter & FILE_NOTIFY_CHANGE_CREATION)
8207 osi_Log0(smb_logp, " Notify Change Creation");
8208 if (filter & FILE_NOTIFY_CHANGE_EA)
8209 osi_Log0(smb_logp, " Notify Change Extended Attributes");
8210 if (filter & FILE_NOTIFY_CHANGE_SECURITY)
8211 osi_Log0(smb_logp, " Notify Change Security");
8212 if (filter & FILE_NOTIFY_CHANGE_STREAM_NAME)
8213 osi_Log0(smb_logp, " Notify Change Stream Name");
8214 if (filter & FILE_NOTIFY_CHANGE_STREAM_SIZE)
8215 osi_Log0(smb_logp, " Notify Change Stream Size");
8216 if (filter & FILE_NOTIFY_CHANGE_STREAM_WRITE)
8217 osi_Log0(smb_logp, " Notify Change Stream Write");
8219 /* A watch can only be notified once. Remove it from the list */
8220 nextWatch = watch->nextp;
8221 if (watch == smb_Directory_Watches)
8222 smb_Directory_Watches = nextWatch;
8224 lastWatch->nextp = nextWatch;
8226 /* Turn off WATCHED flag in dscp */
8227 lock_ObtainMutex(&dscp->mx);
8229 dscp->flags &= ~CM_SCACHEFLAG_WATCHEDSUBTREE;
8231 dscp->flags &= ~CM_SCACHEFLAG_WATCHED;
8232 lock_ReleaseMutex(&dscp->mx);
8234 /* Convert to response packet */
8235 ((smb_t *) watch)->reb = SMB_FLAGS_SERVER_TO_CLIENT | SMB_FLAGS_CANONICAL_PATHNAMES;
8236 ((smb_t *) watch)->wct = 0;
8239 if (filename == NULL)
8242 nameLen = (ULONG)strlen(filename);
8243 parmCount = 3*4 + nameLen*2;
8244 parmCount = (parmCount + 3) & ~3; /* pad to 4 */
8246 otherNameLen = (ULONG)strlen(otherFilename);
8247 oldParmCount = parmCount;
8248 parmCount += 3*4 + otherNameLen*2;
8249 parmCount = (parmCount + 3) & ~3; /* pad to 4 */
8251 if (maxLen < parmCount)
8252 parmCount = 0; /* not enough room */
8254 parmOffset = 8*4 + 39;
8255 parmOffset += 1; /* pad to 4 */
8256 dataOffset = parmOffset + parmCount;
8260 /* Total Parameter Count */
8261 smb_SetSMBParmLong(watch, parmSlot, parmCount); parmSlot += 2;
8262 /* Total Data Count */
8263 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
8264 /* Parameter Count */
8265 smb_SetSMBParmLong(watch, parmSlot, parmCount); parmSlot += 2;
8266 /* Parameter Offset */
8267 smb_SetSMBParmLong(watch, parmSlot, parmOffset); parmSlot += 2;
8268 /* Parameter Displacement */
8269 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
8271 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
8273 smb_SetSMBParmLong(watch, parmSlot, dataOffset); parmSlot += 2;
8274 /* Data Displacement */
8275 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
8276 smb_SetSMBParmByte(watch, parmSlot, 0); /* Setup Count */
8277 smb_SetSMBDataLength(watch, parmCount + 1);
8279 if (parmCount != 0) {
8281 outData = smb_GetSMBData(watch, NULL);
8282 outData++; /* round to get to parmOffset */
8283 oldOutData = outData;
8284 *((DWORD *)outData) = oldParmCount; outData += 4;
8285 /* Next Entry Offset */
8286 *((DWORD *)outData) = action; outData += 4;
8288 *((DWORD *)outData) = nameLen*2; outData += 4;
8289 /* File Name Length */
8290 p = strdup(filename);
8291 if (smb_StoreAnsiFilenames)
8293 mbstowcs((WCHAR *)outData, p, nameLen);
8297 outData = oldOutData + oldParmCount;
8298 *((DWORD *)outData) = 0; outData += 4;
8299 /* Next Entry Offset */
8300 *((DWORD *)outData) = otherAction; outData += 4;
8302 *((DWORD *)outData) = otherNameLen*2;
8303 outData += 4; /* File Name Length */
8304 p = strdup(otherFilename);
8305 if (smb_StoreAnsiFilenames)
8307 mbstowcs((WCHAR *)outData, p, otherNameLen); /* File Name */
8313 * If filename is null, we don't know the cause of the
8314 * change notification. We return zero data (see above),
8315 * and set error code to NT_STATUS_NOTIFY_ENUM_DIR
8316 * (= 0x010C). We set the error code here by hand, without
8317 * modifying wct and bcc.
8319 if (filename == NULL) {
8320 ((smb_t *) watch)->rcls = 0x0C;
8321 ((smb_t *) watch)->reh = 0x01;
8322 ((smb_t *) watch)->errLow = 0;
8323 ((smb_t *) watch)->errHigh = 0;
8324 /* Set NT Status codes flag */
8325 ((smb_t *) watch)->flg2 |= SMB_FLAGS2_32BIT_STATUS;
8328 smb_SendPacket(watch->vcp, watch);
8329 smb_FreePacket(watch);
8332 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
8335 long smb_ReceiveNTCancel(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
8337 unsigned char *replyWctp;
8338 smb_packet_t *watch, *lastWatch;
8339 USHORT fid, watchtree;
8343 osi_Log0(smb_logp, "SMB3 receive NT cancel");
8345 lock_ObtainMutex(&smb_Dir_Watch_Lock);
8346 watch = smb_Directory_Watches;
8348 if (((smb_t *)watch)->uid == ((smb_t *)inp)->uid
8349 && ((smb_t *)watch)->pid == ((smb_t *)inp)->pid
8350 && ((smb_t *)watch)->mid == ((smb_t *)inp)->mid
8351 && ((smb_t *)watch)->tid == ((smb_t *)inp)->tid) {
8352 if (watch == smb_Directory_Watches)
8353 smb_Directory_Watches = watch->nextp;
8355 lastWatch->nextp = watch->nextp;
8356 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
8358 /* Turn off WATCHED flag in scp */
8359 fid = smb_GetSMBParm(watch, 21);
8360 watchtree = smb_GetSMBParm(watch, 22) & 0xffff;
8362 if (vcp != watch->vcp)
8363 osi_Log2(smb_logp, "smb_ReceiveNTCancel: vcp %x not equal to watch vcp %x",
8366 fidp = smb_FindFID(vcp, fid, 0);
8368 osi_Log3(smb_logp, "Cancelling change notification for fid %d wtree %d file %s",
8370 osi_LogSaveString(smb_logp, (fidp)?fidp->NTopen_wholepathp:""));
8373 osi_Log2(smb_logp,"smb_ReceiveNTCancel fidp 0x%p scp 0x%p", fidp, scp);
8374 lock_ObtainMutex(&scp->mx);
8376 scp->flags &= ~CM_SCACHEFLAG_WATCHEDSUBTREE;
8378 scp->flags &= ~CM_SCACHEFLAG_WATCHED;
8379 lock_ReleaseMutex(&scp->mx);
8380 smb_ReleaseFID(fidp);
8382 osi_Log2(smb_logp,"NTCancel unable to resolve fid [%d] in vcp[%x]", fid,vcp);
8385 /* assume STATUS32; return 0xC0000120 (CANCELED) */
8386 replyWctp = watch->wctp;
8390 ((smb_t *)watch)->rcls = 0x20;
8391 ((smb_t *)watch)->reh = 0x1;
8392 ((smb_t *)watch)->errLow = 0;
8393 ((smb_t *)watch)->errHigh = 0xC0;
8394 ((smb_t *)watch)->flg2 |= SMB_FLAGS2_32BIT_STATUS;
8395 smb_SendPacket(vcp, watch);
8396 smb_FreePacket(watch);
8400 watch = watch->nextp;
8402 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
8408 * NT rename also does hard links.
8411 #define RENAME_FLAG_MOVE_CLUSTER_INFORMATION 0x102
8412 #define RENAME_FLAG_HARD_LINK 0x103
8413 #define RENAME_FLAG_RENAME 0x104
8414 #define RENAME_FLAG_COPY 0x105
8416 long smb_ReceiveNTRename(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
8418 char *oldPathp, *newPathp;
8424 attrs = smb_GetSMBParm(inp, 0);
8425 rename_type = smb_GetSMBParm(inp, 1);
8427 if (rename_type != RENAME_FLAG_RENAME && rename_type != RENAME_FLAG_HARD_LINK) {
8428 osi_Log1(smb_logp, "NTRename invalid rename_type [%x]", rename_type);
8429 return CM_ERROR_NOACCESS;
8432 tp = smb_GetSMBData(inp, NULL);
8433 oldPathp = smb_ParseASCIIBlock(tp, &tp);
8434 if (smb_StoreAnsiFilenames)
8435 OemToChar(oldPathp,oldPathp);
8436 newPathp = smb_ParseASCIIBlock(tp, &tp);
8437 if (smb_StoreAnsiFilenames)
8438 OemToChar(newPathp,newPathp);
8440 osi_Log3(smb_logp, "NTRename for [%s]->[%s] type [%s]",
8441 osi_LogSaveString(smb_logp, oldPathp),
8442 osi_LogSaveString(smb_logp, newPathp),
8443 ((rename_type==RENAME_FLAG_RENAME)?"rename":"hardlink"));
8445 if (rename_type == RENAME_FLAG_RENAME) {
8446 code = smb_Rename(vcp,inp,oldPathp,newPathp,attrs);
8447 } else { /* RENAME_FLAG_HARD_LINK */
8448 code = smb_Link(vcp,inp,oldPathp,newPathp);
8455 lock_InitializeMutex(&smb_Dir_Watch_Lock, "Directory Watch List Lock");
8458 cm_user_t *smb_FindCMUserByName(char *usern, char *machine, afs_uint32 flags)
8460 smb_username_t *unp;
8463 unp = smb_FindUserByName(usern, machine, flags);
8465 lock_ObtainMutex(&unp->mx);
8466 unp->userp = cm_NewUser();
8467 lock_ReleaseMutex(&unp->mx);
8468 osi_Log2(smb_logp,"smb_FindCMUserByName New user name[%s] machine[%s]",osi_LogSaveString(smb_logp,usern),osi_LogSaveString(smb_logp,machine));
8470 osi_Log2(smb_logp,"smb_FindCMUserByName Not found name[%s] machine[%s]",osi_LogSaveString(smb_logp,usern),osi_LogSaveString(smb_logp,machine));
8474 smb_ReleaseUsername(unp);