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 && code != CM_ERROR_BPLUS_NOMATCH) {
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 || code == CM_ERROR_BPLUS_NOMATCH) {
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 && code != CM_ERROR_BPLUS_NOMATCH) {
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 && code != CM_ERROR_BPLUS_NOMATCH) {
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) {
4693 if (code == CM_ERROR_BPLUS_NOMATCH)
4694 code = CM_ERROR_NOSUCHFILE;
4702 dsp = smb_NewDirSearch(1);
4703 dsp->attribute = attribute;
4704 strcpy(dsp->mask, maskp); /* and save mask */
4707 osi_assert(p->opcode == 2);
4708 /* find next; obtain basic parameters from request or open dir file */
4709 dsp = smb_FindDirSearch(p->parmsp[0]);
4710 maxCount = p->parmsp[1];
4711 infoLevel = p->parmsp[2];
4712 nextCookie = p->parmsp[3] | (p->parmsp[4] << 16);
4713 searchFlags = p->parmsp[5];
4715 osi_Log2(smb_logp, "T2 search dir bad search ID: id %d nextCookie 0x%x",
4716 p->parmsp[0], nextCookie);
4717 return CM_ERROR_BADFD;
4719 attribute = dsp->attribute;
4722 starPattern = 1; /* assume, since required a Find Next */
4725 switch ( infoLevel ) {
4726 case SMB_INFO_STANDARD:
4729 case SMB_INFO_QUERY_EA_SIZE:
4730 s = "InfoQueryEaSize";
4732 case SMB_INFO_QUERY_EAS_FROM_LIST:
4733 s = "InfoQueryEasFromList";
4735 case SMB_FIND_FILE_DIRECTORY_INFO:
4736 s = "FindFileDirectoryInfo";
4738 case SMB_FIND_FILE_FULL_DIRECTORY_INFO:
4739 s = "FindFileFullDirectoryInfo";
4741 case SMB_FIND_FILE_NAMES_INFO:
4742 s = "FindFileNamesInfo";
4744 case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
4745 s = "FindFileBothDirectoryInfo";
4748 s = "unknownInfoLevel";
4751 osi_Log1(smb_logp, "T2 search dir info level: %s", s);
4754 "T2 search dir attr 0x%x, info level 0x%x, max count %d, flags 0x%x",
4755 attribute, infoLevel, maxCount, searchFlags);
4757 osi_Log3(smb_logp, "...T2 search op %d, id %d, nextCookie 0x%x",
4758 p->opcode, dsp->cookie, nextCookie);
4760 if (infoLevel > SMB_FIND_FILE_BOTH_DIRECTORY_INFO) {
4761 osi_Log1(smb_logp, "Unsupported InfoLevel 0x%x", infoLevel);
4762 smb_ReleaseDirSearch(dsp);
4763 return CM_ERROR_INVAL;
4766 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO)
4767 searchFlags &= ~TRAN2_FIND_FLAG_RETURN_RESUME_KEYS; /* no resume keys */
4769 dirListPatchesp = NULL;
4771 maxReturnData = p->maxReturnData;
4772 if (p->opcode == 1) /* find first */
4773 maxReturnParms = 10; /* bytes */
4775 maxReturnParms = 8; /* bytes */
4777 #ifndef CM_CONFIG_MULTITRAN2RESPONSES
4778 if (maxReturnData > 6000)
4779 maxReturnData = 6000;
4780 #endif /* CM_CONFIG_MULTITRAN2RESPONSES */
4782 outp = smb_GetTran2ResponsePacket(vcp, p, opx, maxReturnParms,
4785 osi_Log2(smb_logp, "T2 receive search dir count %d [%s]",
4786 maxCount, osi_LogSaveString(smb_logp, pathp));
4788 /* bail out if request looks bad */
4789 if (p->opcode == 1 && !pathp) {
4790 smb_ReleaseDirSearch(dsp);
4791 smb_FreeTran2Packet(outp);
4792 return CM_ERROR_BADSMB;
4795 osi_Log3(smb_logp, "T2 search dir id %d, nextCookie 0x%x, attr 0x%x",
4796 dsp->cookie, nextCookie, attribute);
4798 userp = smb_GetTran2User(vcp, p);
4800 osi_Log1(smb_logp, "T2 search dir unable to resolve user [%d]", p->uid);
4801 smb_ReleaseDirSearch(dsp);
4802 smb_FreeTran2Packet(outp);
4803 return CM_ERROR_BADSMB;
4806 /* try to get the vnode for the path name next */
4807 lock_ObtainMutex(&dsp->mx);
4810 osi_Log2(smb_logp,"smb_ReceiveTran2SearchDir dsp 0x%p scp 0x%p", dsp, scp);
4814 spacep = cm_GetSpace();
4815 smb_StripLastComponent(spacep->data, NULL, pathp);
4816 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
4818 cm_ReleaseUser(userp);
4819 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOFILES);
4820 smb_FreeTran2Packet(outp);
4821 lock_ReleaseMutex(&dsp->mx);
4822 smb_DeleteDirSearch(dsp);
4823 smb_ReleaseDirSearch(dsp);
4826 code = cm_NameI(cm_data.rootSCachep, spacep->data,
4827 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
4828 userp, tidPathp, &req, &scp);
4829 cm_FreeSpace(spacep);
4832 #ifdef DFS_SUPPORT_BUT_NOT_FIND_FIRST
4833 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
4834 cm_ReleaseSCache(scp);
4835 cm_ReleaseUser(userp);
4836 if ( WANTS_DFS_PATHNAMES(p) )
4837 code = CM_ERROR_PATH_NOT_COVERED;
4839 code = CM_ERROR_BADSHARENAME;
4840 smb_SendTran2Error(vcp, p, opx, code);
4841 smb_FreeTran2Packet(outp);
4842 lock_ReleaseMutex(&dsp->mx);
4843 smb_DeleteDirSearch(dsp);
4844 smb_ReleaseDirSearch(dsp);
4847 #endif /* DFS_SUPPORT */
4849 osi_Log2(smb_logp,"smb_ReceiveTran2SearchDir dsp 0x%p scp 0x%p", dsp, scp);
4850 /* we need one hold for the entry we just stored into,
4851 * and one for our own processing. When we're done
4852 * with this function, we'll drop the one for our own
4853 * processing. We held it once from the namei call,
4854 * and so we do another hold now.
4857 lock_ObtainMutex(&scp->mx);
4858 if ((scp->flags & CM_SCACHEFLAG_BULKSTATTING) == 0 &&
4859 LargeIntegerGreaterOrEqualToZero(scp->bulkStatProgress)) {
4860 scp->flags |= CM_SCACHEFLAG_BULKSTATTING;
4861 dsp->flags |= SMB_DIRSEARCH_BULKST;
4863 lock_ReleaseMutex(&scp->mx);
4866 lock_ReleaseMutex(&dsp->mx);
4868 cm_ReleaseUser(userp);
4869 smb_FreeTran2Packet(outp);
4870 smb_DeleteDirSearch(dsp);
4871 smb_ReleaseDirSearch(dsp);
4875 /* get the directory size */
4876 lock_ObtainMutex(&scp->mx);
4877 code = cm_SyncOp(scp, NULL, userp, &req, 0,
4878 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4880 lock_ReleaseMutex(&scp->mx);
4881 cm_ReleaseSCache(scp);
4882 cm_ReleaseUser(userp);
4883 smb_FreeTran2Packet(outp);
4884 smb_DeleteDirSearch(dsp);
4885 smb_ReleaseDirSearch(dsp);
4889 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4892 dirLength = scp->length;
4894 bufferOffset.LowPart = bufferOffset.HighPart = 0;
4895 curOffset.HighPart = 0;
4896 curOffset.LowPart = nextCookie;
4897 origOp = outp->datap;
4905 if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS)
4906 /* skip over resume key */
4909 /* make sure that curOffset.LowPart doesn't point to the first
4910 * 32 bytes in the 2nd through last dir page, and that it doesn't
4911 * point at the first 13 32-byte chunks in the first dir page,
4912 * since those are dir and page headers, and don't contain useful
4915 temp = curOffset.LowPart & (2048-1);
4916 if (curOffset.HighPart == 0 && curOffset.LowPart < 2048) {
4917 /* we're in the first page */
4918 if (temp < 13*32) temp = 13*32;
4921 /* we're in a later dir page */
4922 if (temp < 32) temp = 32;
4925 /* make sure the low order 5 bits are zero */
4928 /* now put temp bits back ito curOffset.LowPart */
4929 curOffset.LowPart &= ~(2048-1);
4930 curOffset.LowPart |= temp;
4932 /* check if we've passed the dir's EOF */
4933 if (LargeIntegerGreaterThanOrEqualTo(curOffset, dirLength)) {
4934 osi_Log0(smb_logp, "T2 search dir passed eof");
4939 /* check if we've returned all the names that will fit in the
4940 * response packet; we check return count as well as the number
4941 * of bytes requested. We check the # of bytes after we find
4942 * the dir entry, since we'll need to check its size.
4944 if (returnedNames >= maxCount) {
4945 osi_Log2(smb_logp, "T2 search dir returnedNames %d >= maxCount %d",
4946 returnedNames, maxCount);
4950 /* see if we can use the bufferp we have now; compute in which
4951 * page the current offset would be, and check whether that's
4952 * the offset of the buffer we have. If not, get the buffer.
4954 thyper.HighPart = curOffset.HighPart;
4955 thyper.LowPart = curOffset.LowPart & ~(cm_data.buf_blockSize-1);
4956 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
4959 buf_Release(bufferp);
4962 lock_ReleaseMutex(&scp->mx);
4963 lock_ObtainRead(&scp->bufCreateLock);
4964 code = buf_Get(scp, &thyper, &bufferp);
4965 lock_ReleaseRead(&scp->bufCreateLock);
4966 lock_ObtainMutex(&dsp->mx);
4968 /* now, if we're doing a star match, do bulk fetching
4969 * of all of the status info for files in the dir.
4972 smb_ApplyV3DirListPatches(scp, &dirListPatchesp,
4975 lock_ObtainMutex(&scp->mx);
4976 if ((dsp->flags & SMB_DIRSEARCH_BULKST) &&
4977 LargeIntegerGreaterThanOrEqualTo(thyper, scp->bulkStatProgress)) {
4978 /* Don't bulk stat if risking timeout */
4979 DWORD now = GetTickCount();
4980 if (now - req.startTime > RDRtimeout * 1000) {
4981 scp->bulkStatProgress = thyper;
4982 scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
4983 dsp->flags &= ~SMB_DIRSEARCH_BULKST;
4985 code = cm_TryBulkStat(scp, &thyper, userp, &req);
4988 lock_ObtainMutex(&scp->mx);
4990 lock_ReleaseMutex(&dsp->mx);
4992 osi_Log2(smb_logp, "T2 search dir buf_Get scp %x failed %d", scp, code);
4996 bufferOffset = thyper;
4998 /* now get the data in the cache */
5000 code = cm_SyncOp(scp, bufferp, userp, &req,
5002 CM_SCACHESYNC_NEEDCALLBACK
5003 | CM_SCACHESYNC_READ);
5005 osi_Log2(smb_logp, "T2 search dir cm_SyncOp scp %x failed %d", scp, code);
5009 cm_SyncOpDone(scp, bufferp, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ);
5011 if (cm_HaveBuffer(scp, bufferp, 0)) {
5012 osi_Log2(smb_logp, "T2 search dir !HaveBuffer scp %x bufferp %x", scp, bufferp);
5016 /* otherwise, load the buffer and try again */
5017 code = cm_GetBuffer(scp, bufferp, NULL, userp,
5020 osi_Log3(smb_logp, "T2 search dir cm_GetBuffer failed scp %x bufferp %x code %d",
5021 scp, bufferp, code);
5026 buf_Release(bufferp);
5030 } /* if (wrong buffer) ... */
5032 /* now we have the buffer containing the entry we're interested
5033 * in; copy it out if it represents a non-deleted entry.
5035 entryInDir = curOffset.LowPart & (2048-1);
5036 entryInBuffer = curOffset.LowPart & (cm_data.buf_blockSize - 1);
5038 /* page header will help tell us which entries are free. Page
5039 * header can change more often than once per buffer, since
5040 * AFS 3 dir page size may be less than (but not more than)
5041 * a buffer package buffer.
5043 /* only look intra-buffer */
5044 temp = curOffset.LowPart & (cm_data.buf_blockSize - 1);
5045 temp &= ~(2048 - 1); /* turn off intra-page bits */
5046 pageHeaderp = (cm_pageHeader_t *) (bufferp->datap + temp);
5048 /* now determine which entry we're looking at in the page.
5049 * If it is free (there's a free bitmap at the start of the
5050 * dir), we should skip these 32 bytes.
5052 slotInPage = (entryInDir & 0x7e0) >> 5;
5053 if (!(pageHeaderp->freeBitmap[slotInPage>>3] &
5054 (1 << (slotInPage & 0x7)))) {
5055 /* this entry is free */
5056 numDirChunks = 1; /* only skip this guy */
5060 tp = bufferp->datap + entryInBuffer;
5061 dep = (cm_dirEntry_t *) tp; /* now points to AFS3 dir entry */
5063 /* while we're here, compute the next entry's location, too,
5064 * since we'll need it when writing out the cookie into the dir
5067 * XXXX Probably should do more sanity checking.
5069 numDirChunks = cm_NameEntries(dep->name, &onbytes);
5071 /* compute offset of cookie representing next entry */
5072 nextEntryCookie = curOffset.LowPart + (CM_DIR_CHUNKSIZE * numDirChunks);
5074 /* Need 8.3 name? */
5076 if (infoLevel == SMB_FIND_FILE_BOTH_DIRECTORY_INFO
5077 && dep->fid.vnode != 0
5078 && !cm_Is8Dot3(dep->name)) {
5079 cm_Gen8Dot3Name(dep, shortName, &shortNameEnd);
5083 osi_Log4(smb_logp, "T2 search dir vn %u uniq %u name %s (%s)",
5084 dep->fid.vnode, dep->fid.unique,
5085 osi_LogSaveString(smb_logp, dep->name),
5086 NeedShortName ? osi_LogSaveString(smb_logp, shortName) : "");
5088 /* When matching, we are using doing a case fold if we have a wildcard mask.
5089 * If we get a non-wildcard match, it's a lookup for a specific file.
5091 if (dep->fid.vnode != 0 &&
5092 (smb_V3MatchMask(dep->name, maskp, (starPattern? CM_FLAG_CASEFOLD : 0)) ||
5094 smb_V3MatchMask(shortName, maskp, CM_FLAG_CASEFOLD)))) {
5096 /* Eliminate entries that don't match requested attributes */
5097 if (smb_hideDotFiles && !(dsp->attribute & SMB_ATTR_HIDDEN) &&
5098 smb_IsDotFile(dep->name)) {
5099 osi_Log0(smb_logp, "T2 search dir skipping hidden");
5100 goto nextEntry; /* no hidden files */
5102 if (!(dsp->attribute & SMB_ATTR_DIRECTORY)) /* no directories */
5104 /* We have already done the cm_TryBulkStat above */
5105 fid.cell = scp->fid.cell;
5106 fid.volume = scp->fid.volume;
5107 fid.vnode = ntohl(dep->fid.vnode);
5108 fid.unique = ntohl(dep->fid.unique);
5109 fileType = cm_FindFileType(&fid);
5110 /*osi_Log2(smb_logp, "smb_ReceiveTran2SearchDir: file %s "
5111 "has filetype %d", dep->name,
5113 if (fileType == CM_SCACHETYPE_DIRECTORY ||
5114 fileType == CM_SCACHETYPE_MOUNTPOINT ||
5115 fileType == CM_SCACHETYPE_DFSLINK ||
5116 fileType == CM_SCACHETYPE_INVALID)
5117 osi_Log0(smb_logp, "T2 search dir skipping directory or bad link");
5121 /* finally check if this name will fit */
5123 /* standard dir entry stuff */
5124 if (infoLevel < 0x101)
5125 ohbytes = 23; /* pre-NT */
5126 else if (infoLevel == SMB_FIND_FILE_NAMES_INFO)
5127 ohbytes = 12; /* NT names only */
5129 ohbytes = 64; /* NT */
5131 if (infoLevel == SMB_FIND_FILE_BOTH_DIRECTORY_INFO)
5132 ohbytes += 26; /* Short name & length */
5134 if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS) {
5135 ohbytes += 4; /* if resume key required */
5138 if (infoLevel != SMB_INFO_STANDARD
5139 && infoLevel != SMB_FIND_FILE_DIRECTORY_INFO
5140 && infoLevel != SMB_FIND_FILE_NAMES_INFO)
5141 ohbytes += 4; /* EASIZE */
5143 /* add header to name & term. null */
5144 orbytes = onbytes + ohbytes + 1;
5146 /* now, we round up the record to a 4 byte alignment,
5147 * and we make sure that we have enough room here for
5148 * even the aligned version (so we don't have to worry
5149 * about an * overflow when we pad things out below).
5150 * That's the reason for the alignment arithmetic below.
5152 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO)
5153 align = (4 - (orbytes & 3)) & 3;
5156 if (orbytes + bytesInBuffer + align > maxReturnData) {
5157 osi_Log1(smb_logp, "T2 dir search exceed max return data %d",
5162 /* this is one of the entries to use: it is not deleted
5163 * and it matches the star pattern we're looking for.
5164 * Put out the name, preceded by its length.
5166 /* First zero everything else */
5167 memset(origOp, 0, ohbytes);
5169 if (infoLevel <= SMB_FIND_FILE_DIRECTORY_INFO)
5170 *(origOp + ohbytes - 1) = (unsigned char) onbytes;
5171 else if (infoLevel == SMB_FIND_FILE_NAMES_INFO)
5172 *((u_long *)(op + 8)) = onbytes;
5174 *((u_long *)(op + 60)) = onbytes;
5175 strcpy(origOp+ohbytes, dep->name);
5176 if (smb_StoreAnsiFilenames)
5177 CharToOem(origOp+ohbytes, origOp+ohbytes);
5179 /* Short name if requested and needed */
5180 if (infoLevel == SMB_FIND_FILE_BOTH_DIRECTORY_INFO) {
5181 if (NeedShortName) {
5182 strcpy(op + 70, shortName);
5183 if (smb_StoreAnsiFilenames)
5184 CharToOem(op + 70, op + 70);
5185 *(op + 68) = (char)(shortNameEnd - shortName);
5189 /* now, adjust the # of entries copied */
5192 /* NextEntryOffset and FileIndex */
5193 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO) {
5194 int entryOffset = orbytes + align;
5195 *((u_long *)op) = entryOffset;
5196 *((u_long *)(op+4)) = nextEntryCookie;
5199 /* now we emit the attribute. This is tricky, since
5200 * we need to really stat the file to find out what
5201 * type of entry we've got. Right now, we're copying
5202 * out data from a buffer, while holding the scp
5203 * locked, so it isn't really convenient to stat
5204 * something now. We'll put in a place holder
5205 * now, and make a second pass before returning this
5206 * to get the real attributes. So, we just skip the
5207 * data for now, and adjust it later. We allocate a
5208 * patch record to make it easy to find this point
5209 * later. The replay will happen at a time when it is
5210 * safe to unlock the directory.
5212 if (infoLevel != SMB_FIND_FILE_NAMES_INFO) {
5213 curPatchp = malloc(sizeof(*curPatchp));
5214 osi_QAdd((osi_queue_t **) &dirListPatchesp,
5216 curPatchp->dptr = op;
5217 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO)
5218 curPatchp->dptr += 8;
5220 if (smb_hideDotFiles && smb_IsDotFile(dep->name)) {
5221 curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
5224 curPatchp->flags = 0;
5226 curPatchp->fid.cell = scp->fid.cell;
5227 curPatchp->fid.volume = scp->fid.volume;
5228 curPatchp->fid.vnode = ntohl(dep->fid.vnode);
5229 curPatchp->fid.unique = ntohl(dep->fid.unique);
5232 curPatchp->dep = dep;
5235 if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS)
5236 /* put out resume key */
5237 *((u_long *)origOp) = nextEntryCookie;
5239 /* Adjust byte ptr and count */
5240 origOp += orbytes; /* skip entire record */
5241 bytesInBuffer += orbytes;
5243 /* and pad the record out */
5244 while (--align >= 0) {
5248 } /* if we're including this name */
5249 else if (!starPattern &&
5251 dep->fid.vnode != 0 &&
5252 smb_V3MatchMask(dep->name, maskp, CM_FLAG_CASEFOLD)) {
5253 /* We were looking for exact matches, but here's an inexact one*/
5258 /* and adjust curOffset to be where the new cookie is */
5259 thyper.HighPart = 0;
5260 thyper.LowPart = CM_DIR_CHUNKSIZE * numDirChunks;
5261 curOffset = LargeIntegerAdd(thyper, curOffset);
5262 } /* while copying data for dir listing */
5264 /* If we didn't get a star pattern, we did an exact match during the first pass.
5265 * If there were no exact matches found, we fail over to inexact matches by
5266 * marking the query as a star pattern (matches all case permutations), and
5267 * re-running the query.
5269 if (returnedNames == 0 && !starPattern && foundInexact) {
5270 osi_Log0(smb_logp,"T2 Search: No exact matches. Re-running for inexact matches");
5275 /* release the mutex */
5276 lock_ReleaseMutex(&scp->mx);
5278 buf_Release(bufferp);
5282 /* apply and free last set of patches; if not doing a star match, this
5283 * will be empty, but better safe (and freeing everything) than sorry.
5285 code2 = smb_ApplyV3DirListPatches(scp, &dirListPatchesp, infoLevel, userp,
5288 /* now put out the final parameters */
5289 if (returnedNames == 0)
5291 if (p->opcode == 1) {
5293 outp->parmsp[0] = (unsigned short) dsp->cookie;
5294 outp->parmsp[1] = returnedNames;
5295 outp->parmsp[2] = eos;
5296 outp->parmsp[3] = 0; /* nothing wrong with EAS */
5297 outp->parmsp[4] = 0;
5298 /* don't need last name to continue
5299 * search, cookie is enough. Normally,
5300 * this is the offset of the file name
5301 * of the last entry returned.
5303 outp->totalParms = 10; /* in bytes */
5307 outp->parmsp[0] = returnedNames;
5308 outp->parmsp[1] = eos;
5309 outp->parmsp[2] = 0; /* EAS error */
5310 outp->parmsp[3] = 0; /* last name, as above */
5311 outp->totalParms = 8; /* in bytes */
5314 /* return # of bytes in the buffer */
5315 outp->totalData = bytesInBuffer;
5317 /* Return error code if unsuccessful on first request */
5318 if (code == 0 && p->opcode == 1 && returnedNames == 0)
5319 code = CM_ERROR_NOSUCHFILE;
5321 osi_Log4(smb_logp, "T2 search dir done, opcode %d, id %d, %d names, code %d",
5322 p->opcode, dsp->cookie, returnedNames, code);
5324 /* if we're supposed to close the search after this request, or if
5325 * we're supposed to close the search if we're done, and we're done,
5326 * or if something went wrong, close the search.
5328 if ((searchFlags & TRAN2_FIND_FLAG_CLOSE_SEARCH) ||
5329 (returnedNames == 0) ||
5330 ((searchFlags & TRAN2_FIND_FLAG_CLOSE_SEARCH_IF_END) && eos) ||
5332 smb_DeleteDirSearch(dsp);
5335 smb_SendTran2Error(vcp, p, opx, code);
5337 smb_SendTran2Packet(vcp, outp, opx);
5339 smb_FreeTran2Packet(outp);
5340 smb_ReleaseDirSearch(dsp);
5341 cm_ReleaseSCache(scp);
5342 cm_ReleaseUser(userp);
5346 long smb_ReceiveV3FindClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5349 smb_dirSearch_t *dsp;
5351 dirHandle = smb_GetSMBParm(inp, 0);
5353 osi_Log1(smb_logp, "SMB3 find close handle %d", dirHandle);
5355 dsp = smb_FindDirSearch(dirHandle);
5358 return CM_ERROR_BADFD;
5360 /* otherwise, we have an FD to destroy */
5361 smb_DeleteDirSearch(dsp);
5362 smb_ReleaseDirSearch(dsp);
5364 /* and return results */
5365 smb_SetSMBDataLength(outp, 0);
5370 long smb_ReceiveV3FindNotifyClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5372 smb_SetSMBDataLength(outp, 0);
5376 long smb_ReceiveV3OpenX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5383 cm_scache_t *dscp; /* dir we're dealing with */
5384 cm_scache_t *scp; /* file we're creating */
5386 int initialModeBits;
5396 int parmSlot; /* which parm we're dealing with */
5405 extraInfo = (smb_GetSMBParm(inp, 2) & 1); /* return extra info */
5406 openFun = smb_GetSMBParm(inp, 8); /* open function */
5407 excl = ((openFun & 3) == 0);
5408 trunc = ((openFun & 3) == 2); /* truncate it */
5409 openMode = (smb_GetSMBParm(inp, 3) & 0x7);
5410 openAction = 0; /* tracks what we did */
5412 attributes = smb_GetSMBParm(inp, 5);
5413 dosTime = smb_GetSMBParm(inp, 6) | (smb_GetSMBParm(inp, 7) << 16);
5415 /* compute initial mode bits based on read-only flag in attributes */
5416 initialModeBits = 0666;
5417 if (attributes & SMB_ATTR_READONLY)
5418 initialModeBits &= ~0222;
5420 pathp = smb_GetSMBData(inp, NULL);
5421 if (smb_StoreAnsiFilenames)
5422 OemToChar(pathp,pathp);
5424 spacep = inp->spacep;
5425 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
5427 if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
5428 /* special case magic file name for receiving IOCTL requests
5429 * (since IOCTL calls themselves aren't getting through).
5432 osi_Log0(smb_logp, "IOCTL Open");
5435 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
5436 smb_SetupIoctlFid(fidp, spacep);
5438 /* set inp->fid so that later read calls in same msg can find fid */
5439 inp->fid = fidp->fid;
5441 /* copy out remainder of the parms */
5443 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
5445 smb_SetSMBParm(outp, parmSlot, /* attrs */ 0); parmSlot++;
5446 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* mod time */
5447 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
5448 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* len */
5449 smb_SetSMBParm(outp, parmSlot, 0x7fff); parmSlot++;
5450 smb_SetSMBParm(outp, parmSlot, openMode); parmSlot++;
5451 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* file type 0 ==> normal file or dir */
5452 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* IPC junk */
5454 /* and the final "always present" stuff */
5455 smb_SetSMBParm(outp, parmSlot, /* openAction found existing file */ 1); parmSlot++;
5456 /* next write out the "unique" ID */
5457 smb_SetSMBParm(outp, parmSlot, 0x1234); parmSlot++;
5458 smb_SetSMBParm(outp, parmSlot, 0x5678); parmSlot++;
5459 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
5460 smb_SetSMBDataLength(outp, 0);
5462 /* and clean up fid reference */
5463 smb_ReleaseFID(fidp);
5467 #ifdef DEBUG_VERBOSE
5469 char *hexp, *asciip;
5470 asciip = (lastNamep ? lastNamep : pathp );
5471 hexp = osi_HexifyString(asciip);
5472 DEBUG_EVENT2("AFS", "V3Open H[%s] A[%s]", hexp, asciip );
5476 userp = smb_GetUserFromVCP(vcp, inp);
5479 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5481 cm_ReleaseUser(userp);
5482 return CM_ERROR_NOSUCHPATH;
5484 code = cm_NameI(cm_data.rootSCachep, pathp,
5485 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
5486 userp, tidPathp, &req, &scp);
5489 if (code == 0 && scp->fileType == CM_SCACHETYPE_DFSLINK) {
5490 cm_ReleaseSCache(scp);
5491 cm_ReleaseUser(userp);
5492 if ( WANTS_DFS_PATHNAMES(inp) )
5493 return CM_ERROR_PATH_NOT_COVERED;
5495 return CM_ERROR_BADSHARENAME;
5497 #endif /* DFS_SUPPORT */
5500 code = cm_NameI(cm_data.rootSCachep, spacep->data,
5501 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
5502 userp, tidPathp, &req, &dscp);
5504 cm_ReleaseUser(userp);
5509 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
5510 cm_ReleaseSCache(dscp);
5511 cm_ReleaseUser(userp);
5512 if ( WANTS_DFS_PATHNAMES(inp) )
5513 return CM_ERROR_PATH_NOT_COVERED;
5515 return CM_ERROR_BADSHARENAME;
5517 #endif /* DFS_SUPPORT */
5518 /* otherwise, scp points to the parent directory. Do a lookup,
5519 * and truncate the file if we find it, otherwise we create the
5526 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD, userp,
5528 if (code && code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
5529 cm_ReleaseSCache(dscp);
5530 cm_ReleaseUser(userp);
5535 /* if we get here, if code is 0, the file exists and is represented by
5536 * scp. Otherwise, we have to create it. The dir may be represented
5537 * by dscp, or we may have found the file directly. If code is non-zero,
5541 code = cm_CheckOpen(scp, openMode, trunc, userp, &req);
5543 if (dscp) cm_ReleaseSCache(dscp);
5544 cm_ReleaseSCache(scp);
5545 cm_ReleaseUser(userp);
5550 /* oops, file shouldn't be there */
5552 cm_ReleaseSCache(dscp);
5553 cm_ReleaseSCache(scp);
5554 cm_ReleaseUser(userp);
5555 return CM_ERROR_EXISTS;
5559 setAttr.mask = CM_ATTRMASK_LENGTH;
5560 setAttr.length.LowPart = 0;
5561 setAttr.length.HighPart = 0;
5562 code = cm_SetAttr(scp, &setAttr, userp, &req);
5563 openAction = 3; /* truncated existing file */
5565 else openAction = 1; /* found existing file */
5567 else if (!(openFun & SMB_ATTR_DIRECTORY)) {
5568 /* don't create if not found */
5569 if (dscp) cm_ReleaseSCache(dscp);
5570 cm_ReleaseUser(userp);
5571 return CM_ERROR_NOSUCHFILE;
5574 osi_assert(dscp != NULL);
5575 osi_Log1(smb_logp, "smb_ReceiveV3OpenX creating file %s",
5576 osi_LogSaveString(smb_logp, lastNamep));
5577 openAction = 2; /* created file */
5578 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
5579 smb_UnixTimeFromDosUTime(&setAttr.clientModTime, dosTime);
5580 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
5584 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
5585 smb_NotifyChange(FILE_ACTION_ADDED,
5586 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
5587 dscp, lastNamep, NULL, TRUE);
5588 } else if (!excl && code == CM_ERROR_EXISTS) {
5589 /* not an exclusive create, and someone else tried
5590 * creating it already, then we open it anyway. We
5591 * don't bother retrying after this, since if this next
5592 * fails, that means that the file was deleted after we
5593 * started this call.
5595 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
5599 setAttr.mask = CM_ATTRMASK_LENGTH;
5600 setAttr.length.LowPart = 0;
5601 setAttr.length.HighPart = 0;
5602 code = cm_SetAttr(scp, &setAttr, userp, &req);
5604 } /* lookup succeeded */
5608 /* we don't need this any longer */
5610 cm_ReleaseSCache(dscp);
5613 /* something went wrong creating or truncating the file */
5615 cm_ReleaseSCache(scp);
5616 cm_ReleaseUser(userp);
5620 /* make sure we're about to open a file */
5621 if (scp->fileType != CM_SCACHETYPE_FILE) {
5622 cm_ReleaseSCache(scp);
5623 cm_ReleaseUser(userp);
5624 return CM_ERROR_ISDIR;
5627 /* now all we have to do is open the file itself */
5628 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
5632 lock_ObtainMutex(&fidp->mx);
5633 /* save a pointer to the vnode */
5635 lock_ObtainMutex(&scp->mx);
5636 scp->flags |= CM_SCACHEFLAG_SMB_FID;
5637 lock_ReleaseMutex(&scp->mx);
5638 osi_Log2(smb_logp,"smb_ReceiveV3OpenX fidp 0x%p scp 0x%p", fidp, scp);
5640 fidp->userp = userp;
5642 /* compute open mode */
5644 fidp->flags |= SMB_FID_OPENREAD_LISTDIR;
5645 if (openMode == 1 || openMode == 2)
5646 fidp->flags |= SMB_FID_OPENWRITE;
5648 /* remember if the file was newly created */
5650 fidp->flags |= SMB_FID_CREATED;
5652 lock_ReleaseMutex(&fidp->mx);
5653 smb_ReleaseFID(fidp);
5655 cm_Open(scp, 0, userp);
5657 /* set inp->fid so that later read calls in same msg can find fid */
5658 inp->fid = fidp->fid;
5660 /* copy out remainder of the parms */
5662 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
5663 lock_ObtainMutex(&scp->mx);
5665 smb_SetSMBParm(outp, parmSlot, smb_Attributes(scp)); parmSlot++;
5666 smb_DosUTimeFromUnixTime(&dosTime, scp->clientModTime);
5667 smb_SetSMBParm(outp, parmSlot, dosTime & 0xffff); parmSlot++;
5668 smb_SetSMBParm(outp, parmSlot, (dosTime>>16) & 0xffff); parmSlot++;
5669 smb_SetSMBParm(outp, parmSlot, scp->length.LowPart & 0xffff); parmSlot++;
5670 smb_SetSMBParm(outp, parmSlot, (scp->length.LowPart >> 16) & 0xffff); parmSlot++;
5671 smb_SetSMBParm(outp, parmSlot, openMode); parmSlot++;
5672 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* file type 0 ==> normal file or dir */
5673 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* IPC junk */
5675 /* and the final "always present" stuff */
5676 smb_SetSMBParm(outp, parmSlot, openAction); parmSlot++;
5677 /* next write out the "unique" ID */
5678 smb_SetSMBParm(outp, parmSlot, scp->fid.vnode & 0xffff); parmSlot++;
5679 smb_SetSMBParm(outp, parmSlot, scp->fid.volume & 0xffff); parmSlot++;
5680 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
5681 lock_ReleaseMutex(&scp->mx);
5682 smb_SetSMBDataLength(outp, 0);
5684 osi_Log1(smb_logp, "SMB OpenX opening fid %d", fidp->fid);
5686 cm_ReleaseUser(userp);
5687 /* leave scp held since we put it in fidp->scp */
5691 static void smb_GetLockParams(unsigned char LockType,
5693 unsigned int * ppid,
5694 LARGE_INTEGER * pOffset,
5695 LARGE_INTEGER * pLength)
5697 if (LockType & LOCKING_ANDX_LARGE_FILES) {
5699 *ppid = *((USHORT *) *buf);
5700 pOffset->HighPart = *((LONG *)(*buf + 4));
5701 pOffset->LowPart = *((DWORD *)(*buf + 8));
5702 pLength->HighPart = *((LONG *)(*buf + 12));
5703 pLength->LowPart = *((DWORD *)(*buf + 16));
5707 /* Not Large Files */
5708 *ppid = *((USHORT *) *buf);
5709 pOffset->HighPart = 0;
5710 pOffset->LowPart = *((DWORD *)(*buf + 2));
5711 pLength->HighPart = 0;
5712 pLength->LowPart = *((DWORD *)(*buf + 6));
5717 long smb_ReceiveV3LockingX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5724 unsigned char LockType;
5725 unsigned short NumberOfUnlocks, NumberOfLocks;
5729 LARGE_INTEGER LOffset, LLength;
5730 smb_waitingLockRequest_t *wlRequest = NULL;
5731 cm_file_lock_t *lockp;
5739 fid = smb_GetSMBParm(inp, 2);
5740 fid = smb_ChainFID(fid, inp);
5742 fidp = smb_FindFID(vcp, fid, 0);
5744 return CM_ERROR_BADFD;
5746 lock_ObtainMutex(&fidp->mx);
5747 if (fidp->flags & SMB_FID_IOCTL) {
5748 osi_Log0(smb_logp, "smb_ReceiveV3Locking BadFD");
5749 lock_ReleaseMutex(&fidp->mx);
5750 smb_ReleaseFID(fidp);
5751 return CM_ERROR_BADFD;
5754 osi_Log2(smb_logp,"smb_ReceiveV3LockingX fidp 0x%p scp 0x%p", fidp, scp);
5756 lock_ReleaseMutex(&fidp->mx);
5758 /* set inp->fid so that later read calls in same msg can find fid */
5761 userp = smb_GetUserFromVCP(vcp, inp);
5764 lock_ObtainMutex(&scp->mx);
5765 code = cm_SyncOp(scp, NULL, userp, &req, 0,
5766 CM_SCACHESYNC_NEEDCALLBACK
5767 | CM_SCACHESYNC_GETSTATUS
5768 | CM_SCACHESYNC_LOCK);
5770 osi_Log1(smb_logp, "smb_ReceiveV3Locking SyncOp failure code 0x%x", code);
5774 LockType = smb_GetSMBParm(inp, 3) & 0xff;
5775 Timeout = (smb_GetSMBParm(inp, 5) << 16) + smb_GetSMBParm(inp, 4);
5776 NumberOfUnlocks = smb_GetSMBParm(inp, 6);
5777 NumberOfLocks = smb_GetSMBParm(inp, 7);
5779 if (!(fidp->flags & SMB_FID_OPENWRITE) &&
5780 !(LockType & LOCKING_ANDX_SHARED_LOCK)) {
5781 /* somebody wants exclusive locks on a file that they only
5782 opened for reading. We downgrade this to a shared lock. */
5783 osi_Log0(smb_logp, "smb_ReceiveV3Locking reinterpreting exclusive lock as shared for read-only fid");
5784 LockType |= LOCKING_ANDX_SHARED_LOCK;
5787 if ((LockType & LOCKING_ANDX_CANCEL_LOCK) ||
5788 (LockType & LOCKING_ANDX_CHANGE_LOCKTYPE)) {
5790 /* We don't support these requests. Apparently, we can safely
5791 not deal with them too. */
5792 osi_Log1(smb_logp, "smb_ReceiveV3Locking received unsupported request [%s]",
5793 ((LockType & LOCKING_ANDX_CANCEL_LOCK)?
5794 "LOCKING_ANDX_CANCEL_LOCK":
5795 "LOCKING_ANDX_CHANGE_LOCKTYPE"));
5796 /* No need to call osi_LogSaveString since these are string
5799 code = CM_ERROR_BADOP;
5804 op = smb_GetSMBData(inp, NULL);
5806 for (i=0; i<NumberOfUnlocks; i++) {
5807 smb_GetLockParams(LockType, &op, &pid, &LOffset, &LLength);
5809 key = cm_GenerateKey(vcp->vcID, pid, fidp->fid);
5811 code = cm_Unlock(scp, LockType, LOffset, LLength, key, userp, &req);
5819 for (i=0; i<NumberOfLocks; i++) {
5820 smb_GetLockParams(LockType, &op, &pid, &LOffset, &LLength);
5822 key = cm_GenerateKey(vcp->vcID, pid, fidp->fid);
5824 code = cm_Lock(scp, LockType, LOffset, LLength, key, (Timeout != 0),
5825 userp, &req, &lockp);
5827 if (code == CM_ERROR_NOACCESS && LockType == LockWrite &&
5828 (fidp->flags & (SMB_FID_OPENREAD_LISTDIR | SMB_FID_OPENWRITE)) == SMB_FID_OPENREAD_LISTDIR)
5830 code = cm_Lock(scp, LockRead, LOffset, LLength, key, (Timeout != 0),
5831 userp, &req, &lockp);
5834 if (code == CM_ERROR_WOULDBLOCK && Timeout != 0) {
5835 smb_waitingLock_t * wLock;
5837 /* Put on waiting list */
5838 if(wlRequest == NULL) {
5842 LARGE_INTEGER tOffset, tLength;
5844 wlRequest = malloc(sizeof(smb_waitingLockRequest_t));
5846 osi_assert(wlRequest != NULL);
5848 wlRequest->vcp = vcp;
5850 wlRequest->scp = scp;
5851 osi_Log2(smb_logp,"smb_ReceiveV3LockingX wlRequest 0x%p scp 0x%p", wlRequest, scp);
5853 wlRequest->inp = smb_CopyPacket(inp);
5854 wlRequest->outp = smb_CopyPacket(outp);
5855 wlRequest->lockType = LockType;
5856 wlRequest->timeRemaining = Timeout;
5857 wlRequest->locks = NULL;
5859 /* The waiting lock request needs to have enough
5860 information to undo all the locks in the request.
5861 We do the following to store info about locks that
5862 have already been granted. Sure, we can get most
5863 of the info from the packet, but the packet doesn't
5864 hold the result of cm_Lock call. In practice we
5865 only receive packets with one or two locks, so we
5866 are only wasting a few bytes here and there and
5867 only for a limited period of time until the waiting
5868 lock times out or is freed. */
5870 for(opt = op_locks, j=i; j > 0; j--) {
5871 smb_GetLockParams(LockType, &opt, &pid, &tOffset, &tLength);
5873 tkey = cm_GenerateKey(vcp->vcID, pid, fidp->fid);
5875 wLock = malloc(sizeof(smb_waitingLock_t));
5877 osi_assert(wLock != NULL);
5880 wLock->LOffset = tOffset;
5881 wLock->LLength = tLength;
5882 wLock->lockp = NULL;
5883 wLock->state = SMB_WAITINGLOCKSTATE_DONE;
5884 osi_QAdd((osi_queue_t **) &wlRequest->locks,
5889 wLock = malloc(sizeof(smb_waitingLock_t));
5891 osi_assert(wLock != NULL);
5894 wLock->LOffset = LOffset;
5895 wLock->LLength = LLength;
5896 wLock->lockp = lockp;
5897 wLock->state = SMB_WAITINGLOCKSTATE_WAITING;
5898 osi_QAdd((osi_queue_t **) &wlRequest->locks,
5901 osi_Log1(smb_logp, "smb_ReceiveV3Locking WaitingLock created 0x%p",
5909 osi_Log1(smb_logp, "smb_ReceiveV3Locking cm_Lock failure code 0x%x", code);
5916 /* Since something went wrong with the lock number i, we now
5917 have to go ahead and release any locks acquired before the
5918 failure. All locks before lock number i (of which there
5919 are i of them) have either been successful or are waiting.
5920 Either case requires calling cm_Unlock(). */
5922 /* And purge the waiting lock */
5923 if(wlRequest != NULL) {
5924 smb_waitingLock_t * wl;
5925 smb_waitingLock_t * wlNext;
5928 for(wl = wlRequest->locks; wl; wl = wlNext) {
5930 wlNext = (smb_waitingLock_t *) osi_QNext(&wl->q);
5932 ul_code = cm_Unlock(scp, LockType, wl->LOffset, wl->LLength, wl->key, userp, &req);
5935 osi_Log1(smb_logp, "smb_ReceiveV3Locking cm_Unlock returns code %d", ul_code);
5937 osi_Log0(smb_logp, "smb_ReceiveV3Locking cm_Unlock successful");
5940 osi_QRemove((osi_queue_t **) &wlRequest->locks, &wl->q);
5945 smb_ReleaseVC(wlRequest->vcp);
5946 cm_ReleaseSCache(wlRequest->scp);
5947 smb_FreePacket(wlRequest->inp);
5948 smb_FreePacket(wlRequest->outp);
5957 if (wlRequest != NULL) {
5959 lock_ObtainWrite(&smb_globalLock);
5960 osi_QAdd((osi_queue_t **)&smb_allWaitingLocks,
5962 osi_Wakeup((LONG_PTR)&smb_allWaitingLocks);
5963 lock_ReleaseWrite(&smb_globalLock);
5965 /* don't send reply immediately */
5966 outp->flags |= SMB_PACKETFLAG_NOSEND;
5969 smb_SetSMBDataLength(outp, 0);
5973 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_LOCK);
5976 lock_ReleaseMutex(&scp->mx);
5977 cm_ReleaseSCache(scp);
5978 cm_ReleaseUser(userp);
5979 smb_ReleaseFID(fidp);
5984 long smb_ReceiveV3GetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5990 afs_uint32 searchTime;
5996 fid = smb_GetSMBParm(inp, 0);
5997 fid = smb_ChainFID(fid, inp);
5999 fidp = smb_FindFID(vcp, fid, 0);
6001 return CM_ERROR_BADFD;
6003 lock_ObtainMutex(&fidp->mx);
6004 if (fidp->flags & SMB_FID_IOCTL) {
6005 lock_ReleaseMutex(&fidp->mx);
6006 smb_ReleaseFID(fidp);
6007 return CM_ERROR_BADFD;
6010 osi_Log2(smb_logp,"smb_ReceiveV3GetAttributes fidp 0x%p scp 0x%p", fidp, scp);
6012 lock_ReleaseMutex(&fidp->mx);
6014 userp = smb_GetUserFromVCP(vcp, inp);
6017 /* otherwise, stat the file */
6018 lock_ObtainMutex(&scp->mx);
6019 code = cm_SyncOp(scp, NULL, userp, &req, 0,
6020 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
6024 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
6026 /* decode times. We need a search time, but the response to this
6027 * call provides the date first, not the time, as returned in the
6028 * searchTime variable. So we take the high-order bits first.
6030 smb_SearchTimeFromUnixTime(&searchTime, scp->clientModTime);
6031 smb_SetSMBParm(outp, 0, (searchTime >> 16) & 0xffff); /* ctime */
6032 smb_SetSMBParm(outp, 1, searchTime & 0xffff);
6033 smb_SetSMBParm(outp, 2, (searchTime >> 16) & 0xffff); /* atime */
6034 smb_SetSMBParm(outp, 3, searchTime & 0xffff);
6035 smb_SetSMBParm(outp, 4, (searchTime >> 16) & 0xffff); /* mtime */
6036 smb_SetSMBParm(outp, 5, searchTime & 0xffff);
6038 /* now handle file size and allocation size */
6039 smb_SetSMBParm(outp, 6, scp->length.LowPart & 0xffff); /* file size */
6040 smb_SetSMBParm(outp, 7, (scp->length.LowPart >> 16) & 0xffff);
6041 smb_SetSMBParm(outp, 8, scp->length.LowPart & 0xffff); /* alloc size */
6042 smb_SetSMBParm(outp, 9, (scp->length.LowPart >> 16) & 0xffff);
6044 /* file attribute */
6045 smb_SetSMBParm(outp, 10, smb_Attributes(scp));
6047 /* and finalize stuff */
6048 smb_SetSMBDataLength(outp, 0);
6052 lock_ReleaseMutex(&scp->mx);
6053 cm_ReleaseSCache(scp);
6054 cm_ReleaseUser(userp);
6055 smb_ReleaseFID(fidp);
6059 long smb_ReceiveV3SetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6065 afs_uint32 searchTime;
6073 fid = smb_GetSMBParm(inp, 0);
6074 fid = smb_ChainFID(fid, inp);
6076 fidp = smb_FindFID(vcp, fid, 0);
6078 return CM_ERROR_BADFD;
6080 lock_ObtainMutex(&fidp->mx);
6081 if (fidp->flags & SMB_FID_IOCTL) {
6082 lock_ReleaseMutex(&fidp->mx);
6083 smb_ReleaseFID(fidp);
6084 return CM_ERROR_BADFD;
6087 osi_Log2(smb_logp,"smb_ReceiveV3SetAttributes fidp 0x%p scp 0x%p", fidp, scp);
6089 lock_ReleaseMutex(&fidp->mx);
6091 userp = smb_GetUserFromVCP(vcp, inp);
6094 /* now prepare to call cm_setattr. This message only sets various times,
6095 * and AFS only implements mtime, and we'll set the mtime if that's
6096 * requested. The others we'll ignore.
6098 searchTime = smb_GetSMBParm(inp, 5) | (smb_GetSMBParm(inp, 6) << 16);
6100 if (searchTime != 0) {
6101 smb_UnixTimeFromSearchTime(&unixTime, searchTime);
6103 if ( unixTime != -1 ) {
6104 attrs.mask = CM_ATTRMASK_CLIENTMODTIME;
6105 attrs.clientModTime = unixTime;
6106 code = cm_SetAttr(scp, &attrs, userp, &req);
6108 osi_Log1(smb_logp, "SMB receive V3SetAttributes [fid=%ld]", fid);
6110 osi_Log1(smb_logp, "**smb_UnixTimeFromSearchTime failed searchTime=%ld", searchTime);
6116 cm_ReleaseSCache(scp);
6117 cm_ReleaseUser(userp);
6118 smb_ReleaseFID(fidp);
6122 long smb_ReceiveV3WriteX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6125 long count, written = 0, total_written = 0;
6132 int inDataBlockCount;
6134 fd = smb_GetSMBParm(inp, 2);
6135 count = smb_GetSMBParm(inp, 10);
6137 offset.HighPart = 0;
6138 offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
6140 if (*inp->wctp == 14) {
6141 /* we have a request with 64-bit file offsets */
6142 #ifdef AFS_LARGEFILES
6143 offset.HighPart = smb_GetSMBParm(inp, 12) | (smb_GetSMBParm(inp, 13) << 16);
6145 if ((smb_GetSMBParm(inp, 12) | (smb_GetSMBParm(inp, 13) << 16)) != 0) {
6147 osi_Log0(smb_logp, "smb_ReceiveV3WriteX offset requires largefile support");
6148 /* we shouldn't have received this op if we didn't specify
6149 largefile support */
6150 return CM_ERROR_BADOP;
6155 op = inp->data + smb_GetSMBParm(inp, 11);
6156 inDataBlockCount = count;
6158 osi_Log4(smb_logp, "smb_ReceiveV3WriteX fid %d, off 0x%x:%08x, size 0x%x",
6159 fd, offset.HighPart, offset.LowPart, count);
6161 fd = smb_ChainFID(fd, inp);
6162 fidp = smb_FindFID(vcp, fd, 0);
6164 return CM_ERROR_BADFD;
6166 lock_ObtainMutex(&fidp->mx);
6167 if (fidp->flags & SMB_FID_IOCTL) {
6168 lock_ReleaseMutex(&fidp->mx);
6169 code = smb_IoctlV3Write(fidp, vcp, inp, outp);
6170 smb_ReleaseFID(fidp);
6173 lock_ReleaseMutex(&fidp->mx);
6174 userp = smb_GetUserFromVCP(vcp, inp);
6176 /* special case: 0 bytes transferred means there is no data
6177 transferred. A slight departure from SMB_COM_WRITE where this
6178 means that we are supposed to truncate the file at this
6183 LARGE_INTEGER LOffset;
6184 LARGE_INTEGER LLength;
6187 pid = ((smb_t *) inp)->pid;
6188 key = cm_GenerateKey(vcp->vcID, pid, fd);
6190 LOffset.HighPart = offset.HighPart;
6191 LOffset.LowPart = offset.LowPart;
6192 LLength.HighPart = 0;
6193 LLength.LowPart = count;
6196 lock_ObtainMutex(&scp->mx);
6197 code = cm_LockCheckWrite(scp, LOffset, LLength, key);
6198 lock_ReleaseMutex(&scp->mx);
6205 * Work around bug in NT client
6207 * When copying a file, the NT client should first copy the data,
6208 * then copy the last write time. But sometimes the NT client does
6209 * these in the wrong order, so the data copies would inadvertently
6210 * cause the last write time to be overwritten. We try to detect this,
6211 * and don't set client mod time if we think that would go against the
6214 lock_ObtainMutex(&fidp->mx);
6215 if ((fidp->flags & SMB_FID_MTIMESETDONE) != SMB_FID_MTIMESETDONE) {
6216 fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
6217 fidp->scp->clientModTime = time(NULL);
6219 lock_ReleaseMutex(&fidp->mx);
6222 while ( code == 0 && count > 0 ) {
6223 code = smb_WriteData(fidp, &offset, count, op, userp, &written);
6224 if (code == 0 && written == 0)
6225 code = CM_ERROR_PARTIALWRITE;
6227 offset = LargeIntegerAdd(offset,
6228 ConvertLongToLargeInteger(written));
6230 total_written += written;
6236 /* slots 0 and 1 are reserved for request chaining and will be
6237 filled in when we return. */
6238 smb_SetSMBParm(outp, 2, total_written);
6239 smb_SetSMBParm(outp, 3, 0); /* reserved */
6240 smb_SetSMBParm(outp, 4, 0); /* reserved */
6241 smb_SetSMBParm(outp, 5, 0); /* reserved */
6242 smb_SetSMBDataLength(outp, 0);
6245 cm_ReleaseUser(userp);
6246 smb_ReleaseFID(fidp);
6251 long smb_ReceiveV3ReadX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6255 long finalCount = 0;
6264 fd = smb_GetSMBParm(inp, 2);
6265 count = smb_GetSMBParm(inp, 5);
6266 offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
6268 if (*inp->wctp == 12) {
6269 /* a request with 64-bit offsets */
6270 #ifdef AFS_LARGEFILES
6271 offset.HighPart = smb_GetSMBParm(inp, 10) | (smb_GetSMBParm(inp, 11) << 16);
6273 if (LargeIntegerLessThanZero(offset)) {
6274 osi_Log2(smb_logp, "smb_ReceiveV3Read offset too large (0x%x:%08x)",
6275 offset.HighPart, offset.LowPart);
6276 return CM_ERROR_BADSMB;
6279 if ((smb_GetSMBParm(inp, 10) | (smb_GetSMBParm(inp, 11) << 16)) != 0) {
6280 osi_Log0(smb_logp, "smb_ReceiveV3Read offset is 64-bit. Dropping");
6281 return CM_ERROR_BADSMB;
6283 offset.HighPart = 0;
6287 offset.HighPart = 0;
6290 osi_Log4(smb_logp, "smb_ReceiveV3Read fd %d, off 0x%x:%08x, size 0x%x",
6291 fd, offset.HighPart, offset.LowPart, count);
6293 fd = smb_ChainFID(fd, inp);
6294 fidp = smb_FindFID(vcp, fd, 0);
6296 return CM_ERROR_BADFD;
6299 pid = ((smb_t *) inp)->pid;
6300 key = cm_GenerateKey(vcp->vcID, pid, fd);
6302 LARGE_INTEGER LOffset, LLength;
6305 LOffset.HighPart = offset.HighPart;
6306 LOffset.LowPart = offset.LowPart;
6307 LLength.HighPart = 0;
6308 LLength.LowPart = count;
6311 lock_ObtainMutex(&scp->mx);
6312 code = cm_LockCheckRead(scp, LOffset, LLength, key);
6313 lock_ReleaseMutex(&scp->mx);
6317 smb_ReleaseFID(fidp);
6321 /* set inp->fid so that later read calls in same msg can find fid */
6324 lock_ObtainMutex(&fidp->mx);
6325 if (fidp->flags & SMB_FID_IOCTL) {
6326 lock_ReleaseMutex(&fidp->mx);
6327 code = smb_IoctlV3Read(fidp, vcp, inp, outp);
6328 smb_ReleaseFID(fidp);
6331 lock_ReleaseMutex(&fidp->mx);
6333 userp = smb_GetUserFromVCP(vcp, inp);
6335 /* 0 and 1 are reserved for request chaining, were setup by our caller,
6336 * and will be further filled in after we return.
6338 smb_SetSMBParm(outp, 2, 0); /* remaining bytes, for pipes */
6339 smb_SetSMBParm(outp, 3, 0); /* resvd */
6340 smb_SetSMBParm(outp, 4, 0); /* resvd */
6341 smb_SetSMBParm(outp, 5, count); /* # of bytes we're going to read */
6342 /* fill in #6 when we have all the parameters' space reserved */
6343 smb_SetSMBParm(outp, 7, 0); /* resv'd */
6344 smb_SetSMBParm(outp, 8, 0); /* resv'd */
6345 smb_SetSMBParm(outp, 9, 0); /* resv'd */
6346 smb_SetSMBParm(outp, 10, 0); /* resv'd */
6347 smb_SetSMBParm(outp, 11, 0); /* reserved */
6349 /* get op ptr after putting in the parms, since otherwise we don't
6350 * know where the data really is.
6352 op = smb_GetSMBData(outp, NULL);
6354 /* now fill in offset from start of SMB header to first data byte (to op) */
6355 smb_SetSMBParm(outp, 6, ((int) (op - outp->data)));
6357 /* set the packet data length the count of the # of bytes */
6358 smb_SetSMBDataLength(outp, count);
6360 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount);
6362 /* fix some things up */
6363 smb_SetSMBParm(outp, 5, finalCount);
6364 smb_SetSMBDataLength(outp, finalCount);
6366 cm_ReleaseUser(userp);
6367 smb_ReleaseFID(fidp);
6372 * Values for createDisp, copied from NTDDK.H
6374 #define FILE_SUPERSEDE 0 // (???)
6375 #define FILE_OPEN 1 // (open)
6376 #define FILE_CREATE 2 // (exclusive)
6377 #define FILE_OPEN_IF 3 // (non-exclusive)
6378 #define FILE_OVERWRITE 4 // (open & truncate, but do not create)
6379 #define FILE_OVERWRITE_IF 5 // (open & truncate, or create)
6382 #define REQUEST_OPLOCK 2
6383 #define REQUEST_BATCH_OPLOCK 4
6384 #define OPEN_DIRECTORY 8
6385 #define EXTENDED_RESPONSE_REQUIRED 0x10
6387 /* CreateOptions field. */
6388 #define FILE_DIRECTORY_FILE 0x0001
6389 #define FILE_WRITE_THROUGH 0x0002
6390 #define FILE_SEQUENTIAL_ONLY 0x0004
6391 #define FILE_NON_DIRECTORY_FILE 0x0040
6392 #define FILE_NO_EA_KNOWLEDGE 0x0200
6393 #define FILE_EIGHT_DOT_THREE_ONLY 0x0400
6394 #define FILE_RANDOM_ACCESS 0x0800
6395 #define FILE_DELETE_ON_CLOSE 0x1000
6396 #define FILE_OPEN_BY_FILE_ID 0x2000
6398 long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6400 char *pathp, *realPathp;
6404 cm_scache_t *dscp; /* parent dir */
6405 cm_scache_t *scp; /* file to create or open */
6406 cm_scache_t *targetScp; /* if scp is a symlink */
6410 unsigned short nameLength;
6412 unsigned int requestOpLock;
6413 unsigned int requestBatchOpLock;
6414 unsigned int mustBeDir;
6415 unsigned int extendedRespRequired;
6416 unsigned int treeCreate;
6418 unsigned int desiredAccess;
6419 unsigned int extAttributes;
6420 unsigned int createDisp;
6421 unsigned int createOptions;
6422 unsigned int shareAccess;
6423 int initialModeBits;
6424 unsigned short baseFid;
6425 smb_fid_t *baseFidp;
6427 cm_scache_t *baseDirp;
6428 unsigned short openAction;
6437 cm_lock_data_t *ldp = NULL;
6441 /* This code is very long and has a lot of if-then-else clauses
6442 * scp and dscp get reused frequently and we need to ensure that
6443 * we don't lose a reference. Start by ensuring that they are NULL.
6450 nameLength = smb_GetSMBOffsetParm(inp, 2, 1);
6451 flags = smb_GetSMBOffsetParm(inp, 3, 1)
6452 | (smb_GetSMBOffsetParm(inp, 4, 1) << 16);
6453 requestOpLock = flags & REQUEST_OPLOCK;
6454 requestBatchOpLock = flags & REQUEST_BATCH_OPLOCK;
6455 mustBeDir = flags & OPEN_DIRECTORY;
6456 extendedRespRequired = flags & EXTENDED_RESPONSE_REQUIRED;
6459 * Why all of a sudden 32-bit FID?
6460 * We will reject all bits higher than 16.
6462 if (smb_GetSMBOffsetParm(inp, 6, 1) != 0)
6463 return CM_ERROR_INVAL;
6464 baseFid = smb_GetSMBOffsetParm(inp, 5, 1);
6465 desiredAccess = smb_GetSMBOffsetParm(inp, 7, 1)
6466 | (smb_GetSMBOffsetParm(inp, 8, 1) << 16);
6467 extAttributes = smb_GetSMBOffsetParm(inp, 13, 1)
6468 | (smb_GetSMBOffsetParm(inp, 14, 1) << 16);
6469 shareAccess = smb_GetSMBOffsetParm(inp, 15, 1)
6470 | (smb_GetSMBOffsetParm(inp, 16, 1) << 16);
6471 createDisp = smb_GetSMBOffsetParm(inp, 17, 1)
6472 | (smb_GetSMBOffsetParm(inp, 18, 1) << 16);
6473 createOptions = smb_GetSMBOffsetParm(inp, 19, 1)
6474 | (smb_GetSMBOffsetParm(inp, 20, 1) << 16);
6476 /* mustBeDir is never set; createOptions directory bit seems to be
6479 if (createOptions & FILE_DIRECTORY_FILE)
6481 else if (createOptions & FILE_NON_DIRECTORY_FILE)
6487 * compute initial mode bits based on read-only flag in
6488 * extended attributes
6490 initialModeBits = 0666;
6491 if (extAttributes & SMB_ATTR_READONLY)
6492 initialModeBits &= ~0222;
6494 pathp = smb_GetSMBData(inp, NULL);
6495 /* Sometimes path is not null-terminated, so we make a copy. */
6496 realPathp = malloc(nameLength+1);
6497 memcpy(realPathp, pathp, nameLength);
6498 realPathp[nameLength] = 0;
6499 if (smb_StoreAnsiFilenames)
6500 OemToChar(realPathp,realPathp);
6502 spacep = inp->spacep;
6503 smb_StripLastComponent(spacep->data, &lastNamep, realPathp);
6505 osi_Log1(smb_logp,"NTCreateX for [%s]",osi_LogSaveString(smb_logp,realPathp));
6506 osi_Log4(smb_logp,"... da=[%x] ea=[%x] cd=[%x] co=[%x]", desiredAccess, extAttributes, createDisp, createOptions);
6507 osi_Log3(smb_logp,"... share=[%x] flags=[%x] lastNamep=[%s]", shareAccess, flags, osi_LogSaveString(smb_logp,(lastNamep?lastNamep:"null")));
6509 if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
6510 /* special case magic file name for receiving IOCTL requests
6511 * (since IOCTL calls themselves aren't getting through).
6513 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
6514 smb_SetupIoctlFid(fidp, spacep);
6515 osi_Log1(smb_logp,"NTCreateX Setting up IOCTL on fid[%d]",fidp->fid);
6517 /* set inp->fid so that later read calls in same msg can find fid */
6518 inp->fid = fidp->fid;
6522 smb_SetSMBParmByte(outp, parmSlot, 0); /* oplock */
6523 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
6524 smb_SetSMBParmLong(outp, parmSlot, 1); parmSlot += 2; /* Action */
6526 memset(&ft, 0, sizeof(ft));
6527 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
6528 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
6529 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
6530 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
6531 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2; /* attr */
6532 sz.HighPart = 0x7fff; sz.LowPart = 0;
6533 smb_SetSMBParmDouble(outp, parmSlot, (char *)&sz); parmSlot += 4; /* alen */
6534 smb_SetSMBParmDouble(outp, parmSlot, (char *)&sz); parmSlot += 4; /* len */
6535 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* filetype */
6536 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* dev state */
6537 smb_SetSMBParmByte(outp, parmSlot, 0); /* is a dir? */
6538 smb_SetSMBDataLength(outp, 0);
6540 /* clean up fid reference */
6541 smb_ReleaseFID(fidp);
6546 #ifdef DEBUG_VERBOSE
6548 char *hexp, *asciip;
6549 asciip = (lastNamep? lastNamep : realPathp);
6550 hexp = osi_HexifyString( asciip );
6551 DEBUG_EVENT2("AFS", "NTCreateX H[%s] A[%s]", hexp, asciip);
6556 userp = smb_GetUserFromVCP(vcp, inp);
6558 osi_Log1(smb_logp, "NTCreateX Invalid user [%d]", ((smb_t *) inp)->uid);
6560 return CM_ERROR_INVAL;
6565 baseDirp = cm_data.rootSCachep;
6566 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
6567 if (code == CM_ERROR_TIDIPC) {
6568 /* Attempt to use a TID allocated for IPC. The client
6569 * is probably looking for DCE RPC end points which we
6570 * don't support OR it could be looking to make a DFS
6573 osi_Log0(smb_logp, "NTCreateX received IPC TID");
6576 cm_ReleaseUser(userp);
6577 return CM_ERROR_NOSUCHFILE;
6578 #endif /* DFS_SUPPORT */
6581 baseFidp = smb_FindFID(vcp, baseFid, 0);
6583 osi_Log1(smb_logp, "NTCreateX Invalid base fid [%d]", baseFid);
6585 cm_ReleaseUser(userp);
6586 return CM_ERROR_INVAL;
6588 baseDirp = baseFidp->scp;
6592 osi_Log1(smb_logp, "NTCreateX tidPathp=[%s]", (tidPathp==NULL)?"null": osi_LogSaveString(smb_logp,tidPathp));
6594 /* compute open mode */
6596 if (desiredAccess & DELETE)
6597 fidflags |= SMB_FID_OPENDELETE;
6598 if (desiredAccess & AFS_ACCESS_READ)
6599 fidflags |= SMB_FID_OPENREAD_LISTDIR;
6600 if (desiredAccess & AFS_ACCESS_WRITE)
6601 fidflags |= SMB_FID_OPENWRITE;
6602 if (createOptions & FILE_DELETE_ON_CLOSE)
6603 fidflags |= SMB_FID_DELONCLOSE;
6604 if (createOptions & FILE_SEQUENTIAL_ONLY && !(createOptions & FILE_RANDOM_ACCESS))
6605 fidflags |= SMB_FID_SEQUENTIAL;
6606 if (createOptions & FILE_RANDOM_ACCESS && !(createOptions & FILE_SEQUENTIAL_ONLY))
6607 fidflags |= SMB_FID_RANDOM;
6609 /* and the share mode */
6610 if (shareAccess & FILE_SHARE_READ)
6611 fidflags |= SMB_FID_SHARE_READ;
6612 if (shareAccess & FILE_SHARE_WRITE)
6613 fidflags |= SMB_FID_SHARE_WRITE;
6615 osi_Log1(smb_logp, "NTCreateX fidflags 0x%x", fidflags);
6618 /* For an exclusive create, we want to do a case sensitive match for the last component. */
6619 if ( createDisp == FILE_CREATE ||
6620 createDisp == FILE_OVERWRITE ||
6621 createDisp == FILE_OVERWRITE_IF) {
6622 code = cm_NameI(baseDirp, spacep->data, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
6623 userp, tidPathp, &req, &dscp);
6626 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
6627 cm_ReleaseSCache(dscp);
6628 cm_ReleaseUser(userp);
6631 smb_ReleaseFID(baseFidp);
6632 if ( WANTS_DFS_PATHNAMES(inp) )
6633 return CM_ERROR_PATH_NOT_COVERED;
6635 return CM_ERROR_BADSHARENAME;
6637 #endif /* DFS_SUPPORT */
6638 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp, CM_FLAG_FOLLOW,
6640 if (code == CM_ERROR_NOSUCHFILE || code == CM_ERROR_BPLUS_NOMATCH) {
6641 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp,
6642 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, &req, &scp);
6643 if (code == 0 && realDirFlag == 1) {
6644 cm_ReleaseSCache(scp);
6645 cm_ReleaseSCache(dscp);
6646 cm_ReleaseUser(userp);
6649 smb_ReleaseFID(baseFidp);
6650 return CM_ERROR_EXISTS;
6654 /* we have both scp and dscp */
6656 code = cm_NameI(baseDirp, realPathp, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
6657 userp, tidPathp, &req, &scp);
6659 if (code == 0 && scp->fileType == CM_SCACHETYPE_DFSLINK) {
6660 cm_ReleaseSCache(scp);
6661 cm_ReleaseUser(userp);
6664 smb_ReleaseFID(baseFidp);
6665 if ( WANTS_DFS_PATHNAMES(inp) )
6666 return CM_ERROR_PATH_NOT_COVERED;
6668 return CM_ERROR_BADSHARENAME;
6670 #endif /* DFS_SUPPORT */
6671 /* we might have scp but not dscp */
6677 if (!foundscp || (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE))) {
6678 /* look up parent directory */
6679 /* If we are trying to create a path (i.e. multiple nested directories), then we don't *need*
6680 * the immediate parent. We have to work our way up realPathp until we hit something that we
6684 /* we might or might not have scp */
6690 code = cm_NameI(baseDirp, spacep->data,
6691 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
6692 userp, tidPathp, &req, &dscp);
6695 if (code == 0 && dscp->fileType == CM_SCACHETYPE_DFSLINK) {
6697 cm_ReleaseSCache(scp);
6698 cm_ReleaseSCache(dscp);
6699 cm_ReleaseUser(userp);
6702 smb_ReleaseFID(baseFidp);
6703 if ( WANTS_DFS_PATHNAMES(inp) )
6704 return CM_ERROR_PATH_NOT_COVERED;
6706 return CM_ERROR_BADSHARENAME;
6708 #endif /* DFS_SUPPORT */
6711 (tp = strrchr(spacep->data,'\\')) &&
6712 (createDisp == FILE_CREATE) &&
6713 (realDirFlag == 1)) {
6716 treeStartp = realPathp + (tp - spacep->data);
6718 if (*tp && !smb_IsLegalFilename(tp)) {
6719 cm_ReleaseUser(userp);
6721 smb_ReleaseFID(baseFidp);
6724 cm_ReleaseSCache(scp);
6725 return CM_ERROR_BADNTFILENAME;
6729 } while (dscp == NULL && code == 0);
6733 /* we might have scp and we might have dscp */
6736 smb_ReleaseFID(baseFidp);
6739 osi_Log0(smb_logp,"NTCreateX parent not found");
6741 cm_ReleaseSCache(scp);
6743 cm_ReleaseSCache(dscp);
6744 cm_ReleaseUser(userp);
6749 if (treeCreate && dscp->fileType == CM_SCACHETYPE_FILE) {
6750 /* A file exists where we want a directory. */
6752 cm_ReleaseSCache(scp);
6753 cm_ReleaseSCache(dscp);
6754 cm_ReleaseUser(userp);
6756 return CM_ERROR_EXISTS;
6760 lastNamep = realPathp;
6764 if (!smb_IsLegalFilename(lastNamep)) {
6766 cm_ReleaseSCache(scp);
6768 cm_ReleaseSCache(dscp);
6769 cm_ReleaseUser(userp);
6771 return CM_ERROR_BADNTFILENAME;
6774 if (!foundscp && !treeCreate) {
6775 if ( createDisp == FILE_CREATE ||
6776 createDisp == FILE_OVERWRITE ||
6777 createDisp == FILE_OVERWRITE_IF)
6779 code = cm_Lookup(dscp, lastNamep,
6780 CM_FLAG_FOLLOW, userp, &req, &scp);
6782 code = cm_Lookup(dscp, lastNamep,
6783 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
6786 if (code && (code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH)) {
6788 cm_ReleaseSCache(dscp);
6789 cm_ReleaseUser(userp);
6794 /* we have scp and dscp */
6796 /* we have scp but not dscp */
6798 smb_ReleaseFID(baseFidp);
6801 /* if we get here, if code is 0, the file exists and is represented by
6802 * scp. Otherwise, we have to create it. The dir may be represented
6803 * by dscp, or we may have found the file directly. If code is non-zero,
6806 if (code == 0 && !treeCreate) {
6807 code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp, &req, &ldp);
6810 cm_ReleaseSCache(dscp);
6812 cm_ReleaseSCache(scp);
6813 cm_ReleaseUser(userp);
6818 if (createDisp == FILE_CREATE) {
6819 /* oops, file shouldn't be there */
6820 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
6822 cm_ReleaseSCache(dscp);
6824 cm_ReleaseSCache(scp);
6825 cm_ReleaseUser(userp);
6827 return CM_ERROR_EXISTS;
6830 if ( createDisp == FILE_OVERWRITE ||
6831 createDisp == FILE_OVERWRITE_IF) {
6833 setAttr.mask = CM_ATTRMASK_LENGTH;
6834 setAttr.length.LowPart = 0;
6835 setAttr.length.HighPart = 0;
6836 /* now watch for a symlink */
6838 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
6840 osi_assert(dscp != NULL);
6841 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
6843 /* we have a more accurate file to use (the
6844 * target of the symbolic link). Otherwise,
6845 * we'll just use the symlink anyway.
6847 osi_Log2(smb_logp, "symlink vp %x to vp %x",
6849 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
6850 cm_ReleaseSCache(scp);
6852 code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp, &req, &ldp);
6855 cm_ReleaseSCache(dscp);
6857 cm_ReleaseSCache(scp);
6858 cm_ReleaseUser(userp);
6864 code = cm_SetAttr(scp, &setAttr, userp, &req);
6865 openAction = 3; /* truncated existing file */
6868 openAction = 1; /* found existing file */
6870 } else if (createDisp == FILE_OPEN || createDisp == FILE_OVERWRITE) {
6871 /* don't create if not found */
6873 cm_ReleaseSCache(dscp);
6875 cm_ReleaseSCache(scp);
6876 cm_ReleaseUser(userp);
6878 return CM_ERROR_NOSUCHFILE;
6879 } else if (realDirFlag == 0 || realDirFlag == -1) {
6880 osi_assert(dscp != NULL);
6881 osi_Log1(smb_logp, "smb_ReceiveNTCreateX creating file %s",
6882 osi_LogSaveString(smb_logp, lastNamep));
6883 openAction = 2; /* created file */
6884 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
6885 setAttr.clientModTime = time(NULL);
6886 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp, &req);
6889 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
6890 smb_NotifyChange(FILE_ACTION_ADDED,
6891 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
6892 dscp, lastNamep, NULL, TRUE);
6893 } else if (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE) {
6894 /* Not an exclusive create, and someone else tried
6895 * creating it already, then we open it anyway. We
6896 * don't bother retrying after this, since if this next
6897 * fails, that means that the file was deleted after we
6898 * started this call.
6900 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
6903 if (createDisp == FILE_OVERWRITE_IF) {
6904 setAttr.mask = CM_ATTRMASK_LENGTH;
6905 setAttr.length.LowPart = 0;
6906 setAttr.length.HighPart = 0;
6908 /* now watch for a symlink */
6910 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
6912 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
6914 /* we have a more accurate file to use (the
6915 * target of the symbolic link). Otherwise,
6916 * we'll just use the symlink anyway.
6918 osi_Log2(smb_logp, "symlink vp %x to vp %x",
6920 cm_ReleaseSCache(scp);
6924 code = cm_SetAttr(scp, &setAttr, userp, &req);
6926 } /* lookup succeeded */
6930 char *cp; /* This component */
6931 int clen = 0; /* length of component */
6932 cm_scache_t *tscp1, *tscp2;
6935 /* create directory */
6937 treeStartp = lastNamep;
6938 osi_assert(dscp != NULL);
6939 osi_Log1(smb_logp, "smb_ReceiveNTCreateX creating directory [%s]",
6940 osi_LogSaveString(smb_logp, treeStartp));
6941 openAction = 2; /* created directory */
6943 /* if the request is to create the root directory
6944 * it will appear as a directory name of the nul-string
6945 * and a code of CM_ERROR_NOSUCHFILE
6947 if ( !*treeStartp && (code == CM_ERROR_NOSUCHFILE || code == CM_ERROR_BPLUS_NOMATCH))
6948 code = CM_ERROR_EXISTS;
6950 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
6951 setAttr.clientModTime = time(NULL);
6956 cm_HoldSCache(tscp1);
6960 tp = strchr(pp, '\\');
6963 clen = (int)strlen(cp);
6964 isLast = 1; /* indicate last component. the supplied path never ends in a slash */
6966 clen = (int)(tp - pp);
6967 strncpy(cp,pp,clen);
6974 continue; /* the supplied path can't have consecutive slashes either , but */
6976 /* cp is the next component to be created. */
6977 code = cm_MakeDir(tscp1, cp, 0, &setAttr, userp, &req);
6978 if (code == 0 && (tscp1->flags & CM_SCACHEFLAG_ANYWATCH))
6979 smb_NotifyChange(FILE_ACTION_ADDED,
6980 FILE_NOTIFY_CHANGE_DIR_NAME,
6981 tscp1, cp, NULL, TRUE);
6983 (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE)) {
6984 /* Not an exclusive create, and someone else tried
6985 * creating it already, then we open it anyway. We
6986 * don't bother retrying after this, since if this next
6987 * fails, that means that the file was deleted after we
6988 * started this call.
6990 code = cm_Lookup(tscp1, cp, CM_FLAG_CASEFOLD,
6991 userp, &req, &tscp2);
6996 if (!isLast) { /* for anything other than dscp, release it unless it's the last one */
6997 cm_ReleaseSCache(tscp1);
6998 tscp1 = tscp2; /* Newly created directory will be next parent */
6999 /* the hold is transfered to tscp1 from tscp2 */
7004 cm_ReleaseSCache(dscp);
7007 cm_ReleaseSCache(scp);
7010 * if we get here and code == 0, then scp is the last directory created, and dscp is the
7016 /* something went wrong creating or truncating the file */
7018 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7020 cm_ReleaseSCache(scp);
7022 cm_ReleaseSCache(dscp);
7023 cm_ReleaseUser(userp);
7028 /* make sure we have file vs. dir right (only applies for single component case) */
7029 if (realDirFlag == 0 && scp->fileType != CM_SCACHETYPE_FILE) {
7030 /* now watch for a symlink */
7032 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
7033 cm_scache_t * targetScp = 0;
7034 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
7036 /* we have a more accurate file to use (the
7037 * target of the symbolic link). Otherwise,
7038 * we'll just use the symlink anyway.
7040 osi_Log2(smb_logp, "symlink vp %x to vp %x", scp, targetScp);
7042 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7043 cm_ReleaseSCache(scp);
7048 if (scp->fileType != CM_SCACHETYPE_FILE) {
7050 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7052 cm_ReleaseSCache(dscp);
7053 cm_ReleaseSCache(scp);
7054 cm_ReleaseUser(userp);
7056 return CM_ERROR_ISDIR;
7060 /* (only applies to single component case) */
7061 if (realDirFlag == 1 && scp->fileType == CM_SCACHETYPE_FILE) {
7063 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7064 cm_ReleaseSCache(scp);
7066 cm_ReleaseSCache(dscp);
7067 cm_ReleaseUser(userp);
7069 return CM_ERROR_NOTDIR;
7072 /* open the file itself */
7073 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
7076 /* save a reference to the user */
7078 fidp->userp = userp;
7080 /* If we are restricting sharing, we should do so with a suitable
7082 if (scp->fileType == CM_SCACHETYPE_FILE &&
7083 !(fidflags & SMB_FID_SHARE_WRITE)) {
7085 LARGE_INTEGER LOffset, LLength;
7088 LOffset.HighPart = SMB_FID_QLOCK_HIGH;
7089 LOffset.LowPart = SMB_FID_QLOCK_LOW;
7090 LLength.HighPart = 0;
7091 LLength.LowPart = SMB_FID_QLOCK_LENGTH;
7093 /* If we are not opening the file for writing, then we don't
7094 try to get an exclusive lock. Noone else should be able to
7095 get an exclusive lock on the file anyway, although someone
7096 else can get a shared lock. */
7097 if ((fidflags & SMB_FID_SHARE_READ) ||
7098 !(fidflags & SMB_FID_OPENWRITE)) {
7099 sLockType = LOCKING_ANDX_SHARED_LOCK;
7104 key = cm_GenerateKey(vcp->vcID, SMB_FID_QLOCK_PID, fidp->fid);
7106 lock_ObtainMutex(&scp->mx);
7107 code = cm_Lock(scp, sLockType, LOffset, LLength, key, 0, userp, &req, NULL);
7108 lock_ReleaseMutex(&scp->mx);
7112 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7113 cm_ReleaseSCache(scp);
7115 cm_ReleaseSCache(dscp);
7116 cm_ReleaseUser(userp);
7117 /* Shouldn't this be smb_CloseFID()? fidp->flags = SMB_FID_DELETE; */
7118 smb_CloseFID(vcp, fidp, NULL, 0);
7119 smb_ReleaseFID(fidp);
7125 /* Now its safe to release the file server lock obtained by cm_CheckNTOpen() */
7127 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7129 lock_ObtainMutex(&fidp->mx);
7130 /* save a pointer to the vnode */
7131 fidp->scp = scp; /* Hold transfered to fidp->scp and no longer needed */
7132 lock_ObtainMutex(&scp->mx);
7133 scp->flags |= CM_SCACHEFLAG_SMB_FID;
7134 lock_ReleaseMutex(&scp->mx);
7135 osi_Log2(smb_logp,"smb_ReceiveNTCreateX fidp 0x%p scp 0x%p", fidp, scp);
7137 fidp->flags = fidflags;
7139 /* remember if the file was newly created */
7141 fidp->flags |= SMB_FID_CREATED;
7143 /* save parent dir and pathname for delete or change notification */
7144 if (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE)) {
7145 osi_Log2(smb_logp,"smb_ReceiveNTCreateX fidp 0x%p dscp 0x%p", fidp, dscp);
7146 fidp->flags |= SMB_FID_NTOPEN;
7147 fidp->NTopen_dscp = dscp;
7149 fidp->NTopen_pathp = strdup(lastNamep);
7151 fidp->NTopen_wholepathp = realPathp;
7152 lock_ReleaseMutex(&fidp->mx);
7154 /* we don't need this any longer */
7156 cm_ReleaseSCache(dscp);
7160 cm_Open(scp, 0, userp);
7162 /* set inp->fid so that later read calls in same msg can find fid */
7163 inp->fid = fidp->fid;
7167 lock_ObtainMutex(&scp->mx);
7168 smb_SetSMBParmByte(outp, parmSlot, 0); /* oplock */
7169 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
7170 smb_SetSMBParmLong(outp, parmSlot, openAction); parmSlot += 2;
7171 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
7172 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
7173 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
7174 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
7175 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
7176 smb_SetSMBParmLong(outp, parmSlot, smb_ExtAttributes(scp));
7178 smb_SetSMBParmDouble(outp, parmSlot, (char *)&scp->length); parmSlot += 4;
7179 smb_SetSMBParmDouble(outp, parmSlot, (char *)&scp->length); parmSlot += 4;
7180 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* filetype */
7181 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* dev state */
7182 smb_SetSMBParmByte(outp, parmSlot,
7183 (scp->fileType == CM_SCACHETYPE_DIRECTORY ||
7184 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
7185 scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0); /* is a dir? */
7186 lock_ReleaseMutex(&scp->mx);
7187 smb_SetSMBDataLength(outp, 0);
7189 osi_Log2(smb_logp, "SMB NT CreateX opening fid %d path %s", fidp->fid,
7190 osi_LogSaveString(smb_logp, realPathp));
7192 cm_ReleaseUser(userp);
7193 smb_ReleaseFID(fidp);
7195 /* Can't free realPathp if we get here since
7196 fidp->NTopen_wholepathp is pointing there */
7198 /* leave scp held since we put it in fidp->scp */
7203 * A lot of stuff copied verbatim from NT Create&X to NT Tran Create.
7204 * Instead, ultimately, would like to use a subroutine for common code.
7206 long smb_ReceiveNTTranCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7208 char *pathp, *realPathp;
7212 cm_scache_t *dscp; /* parent dir */
7213 cm_scache_t *scp; /* file to create or open */
7214 cm_scache_t *targetScp; /* if scp is a symlink */
7217 unsigned long nameLength;
7219 unsigned int requestOpLock;
7220 unsigned int requestBatchOpLock;
7221 unsigned int mustBeDir;
7222 unsigned int extendedRespRequired;
7224 unsigned int desiredAccess;
7225 #ifdef DEBUG_VERBOSE
7226 unsigned int allocSize;
7228 unsigned int shareAccess;
7229 unsigned int extAttributes;
7230 unsigned int createDisp;
7231 #ifdef DEBUG_VERBOSE
7234 unsigned int createOptions;
7235 int initialModeBits;
7236 unsigned short baseFid;
7237 smb_fid_t *baseFidp;
7239 cm_scache_t *baseDirp;
7240 unsigned short openAction;
7246 int parmOffset, dataOffset;
7252 cm_lock_data_t *ldp = NULL;
7259 parmOffset = smb_GetSMBOffsetParm(inp, 11, 1)
7260 | (smb_GetSMBOffsetParm(inp, 12, 1) << 16);
7261 parmp = inp->data + parmOffset;
7262 lparmp = (ULONG *) parmp;
7265 requestOpLock = flags & REQUEST_OPLOCK;
7266 requestBatchOpLock = flags & REQUEST_BATCH_OPLOCK;
7267 mustBeDir = flags & OPEN_DIRECTORY;
7268 extendedRespRequired = flags & EXTENDED_RESPONSE_REQUIRED;
7271 * Why all of a sudden 32-bit FID?
7272 * We will reject all bits higher than 16.
7274 if (lparmp[1] & 0xFFFF0000)
7275 return CM_ERROR_INVAL;
7276 baseFid = (unsigned short)lparmp[1];
7277 desiredAccess = lparmp[2];
7278 #ifdef DEBUG_VERBOSE
7279 allocSize = lparmp[3];
7280 #endif /* DEBUG_VERSOSE */
7281 extAttributes = lparmp[5];
7282 shareAccess = lparmp[6];
7283 createDisp = lparmp[7];
7284 createOptions = lparmp[8];
7285 #ifdef DEBUG_VERBOSE
7288 nameLength = lparmp[11];
7290 #ifdef DEBUG_VERBOSE
7291 osi_Log4(smb_logp,"NTTranCreate with da[%x],ea[%x],sa[%x],cd[%x]",desiredAccess,extAttributes,shareAccess,createDisp);
7292 osi_Log3(smb_logp,"... co[%x],sdl[%x],as[%x]",createOptions,sdLen,allocSize);
7293 osi_Log1(smb_logp,"... flags[%x]",flags);
7296 /* mustBeDir is never set; createOptions directory bit seems to be
7299 if (createOptions & FILE_DIRECTORY_FILE)
7301 else if (createOptions & FILE_NON_DIRECTORY_FILE)
7307 * compute initial mode bits based on read-only flag in
7308 * extended attributes
7310 initialModeBits = 0666;
7311 if (extAttributes & SMB_ATTR_READONLY)
7312 initialModeBits &= ~0222;
7314 pathp = parmp + (13 * sizeof(ULONG)) + sizeof(UCHAR);
7315 /* Sometimes path is not null-terminated, so we make a copy. */
7316 realPathp = malloc(nameLength+1);
7317 memcpy(realPathp, pathp, nameLength);
7318 realPathp[nameLength] = 0;
7319 if (smb_StoreAnsiFilenames)
7320 OemToChar(realPathp,realPathp);
7322 spacep = cm_GetSpace();
7323 smb_StripLastComponent(spacep->data, &lastNamep, realPathp);
7326 * Nothing here to handle SMB_IOCTL_FILENAME.
7327 * Will add it if necessary.
7330 #ifdef DEBUG_VERBOSE
7332 char *hexp, *asciip;
7333 asciip = (lastNamep? lastNamep : realPathp);
7334 hexp = osi_HexifyString( asciip );
7335 DEBUG_EVENT2("AFS", "NTTranCreate H[%s] A[%s]", hexp, asciip);
7340 userp = smb_GetUserFromVCP(vcp, inp);
7342 osi_Log1(smb_logp, "NTTranCreate invalid user [%d]", ((smb_t *) inp)->uid);
7344 return CM_ERROR_INVAL;
7349 baseDirp = cm_data.rootSCachep;
7350 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
7351 if (code == CM_ERROR_TIDIPC) {
7352 /* Attempt to use a TID allocated for IPC. The client
7353 * is probably looking for DCE RPC end points which we
7354 * don't support OR it could be looking to make a DFS
7357 osi_Log0(smb_logp, "NTTranCreate received IPC TID");
7360 cm_ReleaseUser(userp);
7361 return CM_ERROR_NOSUCHPATH;
7365 baseFidp = smb_FindFID(vcp, baseFid, 0);
7367 osi_Log1(smb_logp, "NTTranCreate Invalid fid [%d]", baseFid);
7369 cm_ReleaseUser(userp);
7370 return CM_ERROR_INVAL;
7372 baseDirp = baseFidp->scp;
7376 /* compute open mode */
7378 if (desiredAccess & DELETE)
7379 fidflags |= SMB_FID_OPENDELETE;
7380 if (desiredAccess & AFS_ACCESS_READ)
7381 fidflags |= SMB_FID_OPENREAD_LISTDIR;
7382 if (desiredAccess & AFS_ACCESS_WRITE)
7383 fidflags |= SMB_FID_OPENWRITE;
7384 if (createOptions & FILE_DELETE_ON_CLOSE)
7385 fidflags |= SMB_FID_DELONCLOSE;
7386 if (createOptions & FILE_SEQUENTIAL_ONLY && !(createOptions & FILE_RANDOM_ACCESS))
7387 fidflags |= SMB_FID_SEQUENTIAL;
7388 if (createOptions & FILE_RANDOM_ACCESS && !(createOptions & FILE_SEQUENTIAL_ONLY))
7389 fidflags |= SMB_FID_RANDOM;
7391 /* And the share mode */
7392 if (shareAccess & FILE_SHARE_READ)
7393 fidflags |= SMB_FID_SHARE_READ;
7394 if (shareAccess & FILE_SHARE_WRITE)
7395 fidflags |= SMB_FID_SHARE_WRITE;
7399 if ( createDisp == FILE_OPEN ||
7400 createDisp == FILE_OVERWRITE ||
7401 createDisp == FILE_OVERWRITE_IF) {
7402 code = cm_NameI(baseDirp, spacep->data, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
7403 userp, tidPathp, &req, &dscp);
7406 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
7407 cm_ReleaseSCache(dscp);
7408 cm_ReleaseUser(userp);
7411 smb_ReleaseFID(baseFidp);
7412 if ( WANTS_DFS_PATHNAMES(inp) )
7413 return CM_ERROR_PATH_NOT_COVERED;
7415 return CM_ERROR_BADSHARENAME;
7417 #endif /* DFS_SUPPORT */
7418 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp, CM_FLAG_FOLLOW,
7420 if (code == CM_ERROR_NOSUCHFILE || code == CM_ERROR_BPLUS_NOMATCH) {
7421 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp,
7422 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, &req, &scp);
7423 if (code == 0 && realDirFlag == 1) {
7424 cm_ReleaseSCache(scp);
7425 cm_ReleaseSCache(dscp);
7426 cm_ReleaseUser(userp);
7429 smb_ReleaseFID(baseFidp);
7430 return CM_ERROR_EXISTS;
7436 code = cm_NameI(baseDirp, realPathp, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
7437 userp, tidPathp, &req, &scp);
7439 if (code == 0 && scp->fileType == CM_SCACHETYPE_DFSLINK) {
7440 cm_ReleaseSCache(scp);
7441 cm_ReleaseUser(userp);
7444 smb_ReleaseFID(baseFidp);
7445 if ( WANTS_DFS_PATHNAMES(inp) )
7446 return CM_ERROR_PATH_NOT_COVERED;
7448 return CM_ERROR_BADSHARENAME;
7450 #endif /* DFS_SUPPORT */
7456 if (code != 0 || (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE))) {
7457 /* look up parent directory */
7459 code = cm_NameI(baseDirp, spacep->data,
7460 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
7461 userp, tidPathp, &req, &dscp);
7463 if (code == 0 && dscp->fileType == CM_SCACHETYPE_DFSLINK) {
7464 cm_ReleaseSCache(dscp);
7465 cm_ReleaseUser(userp);
7468 smb_ReleaseFID(baseFidp);
7469 if ( WANTS_DFS_PATHNAMES(inp) )
7470 return CM_ERROR_PATH_NOT_COVERED;
7472 return CM_ERROR_BADSHARENAME;
7474 #endif /* DFS_SUPPORT */
7478 cm_FreeSpace(spacep);
7481 smb_ReleaseFID(baseFidp);
7484 cm_ReleaseUser(userp);
7490 lastNamep = realPathp;
7494 if (!smb_IsLegalFilename(lastNamep))
7495 return CM_ERROR_BADNTFILENAME;
7498 if (createDisp == FILE_CREATE || createDisp == FILE_OVERWRITE_IF) {
7499 code = cm_Lookup(dscp, lastNamep,
7500 CM_FLAG_FOLLOW, userp, &req, &scp);
7502 code = cm_Lookup(dscp, lastNamep,
7503 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
7506 if (code && code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
7507 cm_ReleaseSCache(dscp);
7508 cm_ReleaseUser(userp);
7515 smb_ReleaseFID(baseFidp);
7516 cm_FreeSpace(spacep);
7519 /* if we get here, if code is 0, the file exists and is represented by
7520 * scp. Otherwise, we have to create it. The dir may be represented
7521 * by dscp, or we may have found the file directly. If code is non-zero,
7525 code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp, &req, &ldp);
7528 cm_ReleaseSCache(dscp);
7529 cm_ReleaseSCache(scp);
7530 cm_ReleaseUser(userp);
7535 if (createDisp == FILE_CREATE) {
7536 /* oops, file shouldn't be there */
7537 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7539 cm_ReleaseSCache(dscp);
7540 cm_ReleaseSCache(scp);
7541 cm_ReleaseUser(userp);
7543 return CM_ERROR_EXISTS;
7546 if (createDisp == FILE_OVERWRITE ||
7547 createDisp == FILE_OVERWRITE_IF) {
7548 setAttr.mask = CM_ATTRMASK_LENGTH;
7549 setAttr.length.LowPart = 0;
7550 setAttr.length.HighPart = 0;
7552 /* now watch for a symlink */
7554 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
7556 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
7558 /* we have a more accurate file to use (the
7559 * target of the symbolic link). Otherwise,
7560 * we'll just use the symlink anyway.
7562 osi_Log2(smb_logp, "symlink vp %x to vp %x",
7564 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7565 cm_ReleaseSCache(scp);
7567 code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp, &req, &ldp);
7570 cm_ReleaseSCache(dscp);
7572 cm_ReleaseSCache(scp);
7573 cm_ReleaseUser(userp);
7579 code = cm_SetAttr(scp, &setAttr, userp, &req);
7580 openAction = 3; /* truncated existing file */
7582 else openAction = 1; /* found existing file */
7584 else if (createDisp == FILE_OPEN || createDisp == FILE_OVERWRITE) {
7585 /* don't create if not found */
7587 cm_ReleaseSCache(dscp);
7588 cm_ReleaseUser(userp);
7590 return CM_ERROR_NOSUCHFILE;
7592 else if (realDirFlag == 0 || realDirFlag == -1) {
7593 osi_assert(dscp != NULL);
7594 osi_Log1(smb_logp, "smb_ReceiveNTTranCreate creating file %s",
7595 osi_LogSaveString(smb_logp, lastNamep));
7596 openAction = 2; /* created file */
7597 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
7598 setAttr.clientModTime = time(NULL);
7599 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
7603 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
7604 smb_NotifyChange(FILE_ACTION_ADDED,
7605 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
7606 dscp, lastNamep, NULL, TRUE);
7607 } else if (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE) {
7608 /* Not an exclusive create, and someone else tried
7609 * creating it already, then we open it anyway. We
7610 * don't bother retrying after this, since if this next
7611 * fails, that means that the file was deleted after we
7612 * started this call.
7614 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
7617 if (createDisp == FILE_OVERWRITE_IF) {
7618 setAttr.mask = CM_ATTRMASK_LENGTH;
7619 setAttr.length.LowPart = 0;
7620 setAttr.length.HighPart = 0;
7622 /* now watch for a symlink */
7624 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
7626 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
7628 /* we have a more accurate file to use (the
7629 * target of the symbolic link). Otherwise,
7630 * we'll just use the symlink anyway.
7632 osi_Log2(smb_logp, "symlink vp %x to vp %x",
7634 cm_ReleaseSCache(scp);
7638 code = cm_SetAttr(scp, &setAttr, userp, &req);
7640 } /* lookup succeeded */
7643 /* create directory */
7644 osi_assert(dscp != NULL);
7646 "smb_ReceiveNTTranCreate creating directory %s",
7647 osi_LogSaveString(smb_logp, lastNamep));
7648 openAction = 2; /* created directory */
7649 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
7650 setAttr.clientModTime = time(NULL);
7651 code = cm_MakeDir(dscp, lastNamep, 0, &setAttr, userp, &req);
7652 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
7653 smb_NotifyChange(FILE_ACTION_ADDED,
7654 FILE_NOTIFY_CHANGE_DIR_NAME,
7655 dscp, lastNamep, NULL, TRUE);
7657 (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE)) {
7658 /* Not an exclusive create, and someone else tried
7659 * creating it already, then we open it anyway. We
7660 * don't bother retrying after this, since if this next
7661 * fails, that means that the file was deleted after we
7662 * started this call.
7664 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
7670 /* something went wrong creating or truncating the file */
7672 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7674 cm_ReleaseSCache(scp);
7675 cm_ReleaseUser(userp);
7680 /* make sure we have file vs. dir right */
7681 if (realDirFlag == 0 && scp->fileType != CM_SCACHETYPE_FILE) {
7682 /* now watch for a symlink */
7684 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
7686 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
7688 /* we have a more accurate file to use (the
7689 * target of the symbolic link). Otherwise,
7690 * we'll just use the symlink anyway.
7692 osi_Log2(smb_logp, "symlink vp %x to vp %x",
7695 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7696 cm_ReleaseSCache(scp);
7701 if (scp->fileType != CM_SCACHETYPE_FILE) {
7703 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7704 cm_ReleaseSCache(scp);
7705 cm_ReleaseUser(userp);
7707 return CM_ERROR_ISDIR;
7711 if (realDirFlag == 1 && scp->fileType == CM_SCACHETYPE_FILE) {
7713 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7714 cm_ReleaseSCache(scp);
7715 cm_ReleaseUser(userp);
7717 return CM_ERROR_NOTDIR;
7720 /* open the file itself */
7721 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
7724 /* save a reference to the user */
7726 fidp->userp = userp;
7728 /* If we are restricting sharing, we should do so with a suitable
7730 if (scp->fileType == CM_SCACHETYPE_FILE &&
7731 !(fidflags & SMB_FID_SHARE_WRITE)) {
7733 LARGE_INTEGER LOffset, LLength;
7736 LOffset.HighPart = SMB_FID_QLOCK_HIGH;
7737 LOffset.LowPart = SMB_FID_QLOCK_LOW;
7738 LLength.HighPart = 0;
7739 LLength.LowPart = SMB_FID_QLOCK_LENGTH;
7741 /* Similar to what we do in handling NTCreateX. We get a
7742 shared lock if we are only opening the file for reading. */
7743 if ((fidflags & SMB_FID_SHARE_READ) ||
7744 !(fidflags & SMB_FID_OPENWRITE)) {
7745 sLockType = LOCKING_ANDX_SHARED_LOCK;
7750 key = cm_GenerateKey(vcp->vcID, SMB_FID_QLOCK_PID, fidp->fid);
7752 lock_ObtainMutex(&scp->mx);
7753 code = cm_Lock(scp, sLockType, LOffset, LLength, key, 0, userp, &req, NULL);
7754 lock_ReleaseMutex(&scp->mx);
7758 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7759 cm_ReleaseSCache(scp);
7760 cm_ReleaseUser(userp);
7761 /* Shouldn't this be smb_CloseFID()? fidp->flags = SMB_FID_DELETE; */
7762 smb_CloseFID(vcp, fidp, NULL, 0);
7763 smb_ReleaseFID(fidp);
7765 return CM_ERROR_SHARING_VIOLATION;
7769 /* Now its safe to drop the file server lock obtained by cm_CheckNTOpen() */
7771 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7773 lock_ObtainMutex(&fidp->mx);
7774 /* save a pointer to the vnode */
7776 lock_ObtainMutex(&scp->mx);
7777 scp->flags |= CM_SCACHEFLAG_SMB_FID;
7778 lock_ReleaseMutex(&scp->mx);
7779 osi_Log2(smb_logp,"smb_ReceiveNTTranCreate fidp 0x%p scp 0x%p", fidp, scp);
7781 fidp->flags = fidflags;
7783 /* remember if the file was newly created */
7785 fidp->flags |= SMB_FID_CREATED;
7787 /* save parent dir and pathname for deletion or change notification */
7788 if (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE)) {
7789 fidp->flags |= SMB_FID_NTOPEN;
7790 fidp->NTopen_dscp = dscp;
7791 osi_Log2(smb_logp,"smb_ReceiveNTTranCreate fidp 0x%p dscp 0x%p", fidp, dscp);
7793 fidp->NTopen_pathp = strdup(lastNamep);
7795 fidp->NTopen_wholepathp = realPathp;
7796 lock_ReleaseMutex(&fidp->mx);
7798 /* we don't need this any longer */
7800 cm_ReleaseSCache(dscp);
7802 cm_Open(scp, 0, userp);
7804 /* set inp->fid so that later read calls in same msg can find fid */
7805 inp->fid = fidp->fid;
7807 /* check whether we are required to send an extended response */
7808 if (!extendedRespRequired) {
7810 parmOffset = 8*4 + 39;
7811 parmOffset += 1; /* pad to 4 */
7812 dataOffset = parmOffset + 70;
7816 /* Total Parameter Count */
7817 smb_SetSMBParmLong(outp, parmSlot, 70); parmSlot += 2;
7818 /* Total Data Count */
7819 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
7820 /* Parameter Count */
7821 smb_SetSMBParmLong(outp, parmSlot, 70); parmSlot += 2;
7822 /* Parameter Offset */
7823 smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
7824 /* Parameter Displacement */
7825 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
7827 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
7829 smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
7830 /* Data Displacement */
7831 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
7832 smb_SetSMBParmByte(outp, parmSlot, 0); /* Setup Count */
7833 smb_SetSMBDataLength(outp, 70);
7835 lock_ObtainMutex(&scp->mx);
7836 outData = smb_GetSMBData(outp, NULL);
7837 outData++; /* round to get to parmOffset */
7838 *outData = 0; outData++; /* oplock */
7839 *outData = 0; outData++; /* reserved */
7840 *((USHORT *)outData) = fidp->fid; outData += 2; /* fid */
7841 *((ULONG *)outData) = openAction; outData += 4;
7842 *((ULONG *)outData) = 0; outData += 4; /* EA error offset */
7843 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
7844 *((FILETIME *)outData) = ft; outData += 8; /* creation time */
7845 *((FILETIME *)outData) = ft; outData += 8; /* last access time */
7846 *((FILETIME *)outData) = ft; outData += 8; /* last write time */
7847 *((FILETIME *)outData) = ft; outData += 8; /* change time */
7848 *((ULONG *)outData) = smb_ExtAttributes(scp); outData += 4;
7849 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* alloc sz */
7850 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* EOF */
7851 *((USHORT *)outData) = 0; outData += 2; /* filetype */
7852 *((USHORT *)outData) = 0; outData += 2; /* dev state */
7853 *((USHORT *)outData) = ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
7854 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
7855 scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0);
7856 outData += 2; /* is a dir? */
7857 lock_ReleaseMutex(&scp->mx);
7860 parmOffset = 8*4 + 39;
7861 parmOffset += 1; /* pad to 4 */
7862 dataOffset = parmOffset + 104;
7866 /* Total Parameter Count */
7867 smb_SetSMBParmLong(outp, parmSlot, 101); parmSlot += 2;
7868 /* Total Data Count */
7869 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
7870 /* Parameter Count */
7871 smb_SetSMBParmLong(outp, parmSlot, 101); parmSlot += 2;
7872 /* Parameter Offset */
7873 smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
7874 /* Parameter Displacement */
7875 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
7877 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
7879 smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
7880 /* Data Displacement */
7881 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
7882 smb_SetSMBParmByte(outp, parmSlot, 0); /* Setup Count */
7883 smb_SetSMBDataLength(outp, 105);
7885 lock_ObtainMutex(&scp->mx);
7886 outData = smb_GetSMBData(outp, NULL);
7887 outData++; /* round to get to parmOffset */
7888 *outData = 0; outData++; /* oplock */
7889 *outData = 1; outData++; /* response type */
7890 *((USHORT *)outData) = fidp->fid; outData += 2; /* fid */
7891 *((ULONG *)outData) = openAction; outData += 4;
7892 *((ULONG *)outData) = 0; outData += 4; /* EA error offset */
7893 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
7894 *((FILETIME *)outData) = ft; outData += 8; /* creation time */
7895 *((FILETIME *)outData) = ft; outData += 8; /* last access time */
7896 *((FILETIME *)outData) = ft; outData += 8; /* last write time */
7897 *((FILETIME *)outData) = ft; outData += 8; /* change time */
7898 *((ULONG *)outData) = smb_ExtAttributes(scp); outData += 4;
7899 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* alloc sz */
7900 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* EOF */
7901 *((USHORT *)outData) = 0; outData += 2; /* filetype */
7902 *((USHORT *)outData) = 0; outData += 2; /* dev state */
7903 *((USHORT *)outData) = ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
7904 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
7905 scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0);
7906 outData += 1; /* is a dir? */
7907 memset(outData,0,24); outData += 24; /* Volume ID and file ID */
7908 *((ULONG *)outData) = 0x001f01ffL; outData += 4; /* Maxmimal access rights */
7909 *((ULONG *)outData) = 0; outData += 4; /* Guest Access rights */
7910 lock_ReleaseMutex(&scp->mx);
7913 osi_Log1(smb_logp, "SMB NTTranCreate opening fid %d", fidp->fid);
7915 cm_ReleaseUser(userp);
7916 smb_ReleaseFID(fidp);
7918 /* free(realPathp); Can't free realPathp here because fidp->NTopen_wholepathp points there */
7919 /* leave scp held since we put it in fidp->scp */
7923 long smb_ReceiveNTTranNotifyChange(smb_vc_t *vcp, smb_packet_t *inp,
7926 smb_packet_t *savedPacketp;
7928 USHORT fid, watchtree;
7932 filter = smb_GetSMBParm(inp, 19) |
7933 (smb_GetSMBParm(inp, 20) << 16);
7934 fid = smb_GetSMBParm(inp, 21);
7935 watchtree = (smb_GetSMBParm(inp, 22) & 0xff) ? 1 : 0;
7937 fidp = smb_FindFID(vcp, fid, 0);
7939 osi_Log1(smb_logp, "ERROR: NotifyChange given invalid fid [%d]", fid);
7940 return CM_ERROR_BADFD;
7943 /* Create a copy of the Directory Watch Packet to use when sending the
7944 * notification if in the future a matching change is detected.
7946 savedPacketp = smb_CopyPacket(inp);
7948 if (savedPacketp->vcp)
7949 smb_ReleaseVC(savedPacketp->vcp);
7950 savedPacketp->vcp = vcp;
7952 /* Add the watch to the list of events to send notifications for */
7953 lock_ObtainMutex(&smb_Dir_Watch_Lock);
7954 savedPacketp->nextp = smb_Directory_Watches;
7955 smb_Directory_Watches = savedPacketp;
7956 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
7959 osi_Log3(smb_logp,"smb_ReceiveNTTranNotifyChange fidp 0x%p scp 0x%p file \"%s\"",
7960 fidp, scp, osi_LogSaveString(smb_logp, fidp->NTopen_wholepathp));
7961 osi_Log3(smb_logp, "Request for NotifyChange filter 0x%x fid %d wtree %d",
7962 filter, fid, watchtree);
7963 if (filter & FILE_NOTIFY_CHANGE_FILE_NAME)
7964 osi_Log0(smb_logp, " Notify Change File Name");
7965 if (filter & FILE_NOTIFY_CHANGE_DIR_NAME)
7966 osi_Log0(smb_logp, " Notify Change Directory Name");
7967 if (filter & FILE_NOTIFY_CHANGE_ATTRIBUTES)
7968 osi_Log0(smb_logp, " Notify Change Attributes");
7969 if (filter & FILE_NOTIFY_CHANGE_SIZE)
7970 osi_Log0(smb_logp, " Notify Change Size");
7971 if (filter & FILE_NOTIFY_CHANGE_LAST_WRITE)
7972 osi_Log0(smb_logp, " Notify Change Last Write");
7973 if (filter & FILE_NOTIFY_CHANGE_LAST_ACCESS)
7974 osi_Log0(smb_logp, " Notify Change Last Access");
7975 if (filter & FILE_NOTIFY_CHANGE_CREATION)
7976 osi_Log0(smb_logp, " Notify Change Creation");
7977 if (filter & FILE_NOTIFY_CHANGE_EA)
7978 osi_Log0(smb_logp, " Notify Change Extended Attributes");
7979 if (filter & FILE_NOTIFY_CHANGE_SECURITY)
7980 osi_Log0(smb_logp, " Notify Change Security");
7981 if (filter & FILE_NOTIFY_CHANGE_STREAM_NAME)
7982 osi_Log0(smb_logp, " Notify Change Stream Name");
7983 if (filter & FILE_NOTIFY_CHANGE_STREAM_SIZE)
7984 osi_Log0(smb_logp, " Notify Change Stream Size");
7985 if (filter & FILE_NOTIFY_CHANGE_STREAM_WRITE)
7986 osi_Log0(smb_logp, " Notify Change Stream Write");
7988 lock_ObtainMutex(&scp->mx);
7990 scp->flags |= CM_SCACHEFLAG_WATCHEDSUBTREE;
7992 scp->flags |= CM_SCACHEFLAG_WATCHED;
7993 lock_ReleaseMutex(&scp->mx);
7994 smb_ReleaseFID(fidp);
7996 outp->flags |= SMB_PACKETFLAG_NOSEND;
8000 unsigned char nullSecurityDesc[36] = {
8001 0x01, /* security descriptor revision */
8002 0x00, /* reserved, should be zero */
8003 0x00, 0x80, /* security descriptor control;
8004 * 0x8000 : self-relative format */
8005 0x14, 0x00, 0x00, 0x00, /* offset of owner SID */
8006 0x1c, 0x00, 0x00, 0x00, /* offset of group SID */
8007 0x00, 0x00, 0x00, 0x00, /* offset of DACL would go here */
8008 0x00, 0x00, 0x00, 0x00, /* offset of SACL would go here */
8009 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
8010 /* "null SID" owner SID */
8011 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
8012 /* "null SID" group SID */
8015 long smb_ReceiveNTTranQuerySecurityDesc(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
8017 int parmOffset, parmCount, dataOffset, dataCount;
8025 ULONG securityInformation;
8027 parmOffset = smb_GetSMBOffsetParm(inp, 11, 1)
8028 | (smb_GetSMBOffsetParm(inp, 12, 1) << 16);
8029 parmp = inp->data + parmOffset;
8030 sparmp = (USHORT *) parmp;
8031 lparmp = (ULONG *) parmp;
8034 securityInformation = lparmp[1];
8036 maxData = smb_GetSMBOffsetParm(inp, 7, 1)
8037 | (smb_GetSMBOffsetParm(inp, 8, 1) << 16);
8045 parmOffset = 8*4 + 39;
8046 parmOffset += 1; /* pad to 4 */
8048 dataOffset = parmOffset + parmCount;
8052 /* Total Parameter Count */
8053 smb_SetSMBParmLong(outp, parmSlot, parmCount); parmSlot += 2;
8054 /* Total Data Count */
8055 smb_SetSMBParmLong(outp, parmSlot, dataCount); parmSlot += 2;
8056 /* Parameter Count */
8057 smb_SetSMBParmLong(outp, parmSlot, parmCount); parmSlot += 2;
8058 /* Parameter Offset */
8059 smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
8060 /* Parameter Displacement */
8061 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8063 smb_SetSMBParmLong(outp, parmSlot, dataCount); parmSlot += 2;
8065 smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
8066 /* Data Displacement */
8067 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8068 smb_SetSMBParmByte(outp, parmSlot, 0); /* Setup Count */
8069 smb_SetSMBDataLength(outp, 1 + parmCount + dataCount);
8071 outData = smb_GetSMBData(outp, NULL);
8072 outData++; /* round to get to parmOffset */
8073 *((ULONG *)outData) = 36; outData += 4; /* length */
8075 if (maxData >= 36) {
8076 memcpy(outData, nullSecurityDesc, 36);
8080 return CM_ERROR_BUFFERTOOSMALL;
8083 long smb_ReceiveNTTransact(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
8085 unsigned short function;
8087 function = smb_GetSMBParm(inp, 18);
8089 osi_Log1(smb_logp, "SMB NT Transact function %d", function);
8091 /* We can handle long names */
8092 if (vcp->flags & SMB_VCFLAG_USENT)
8093 ((smb_t *)outp)->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
8097 return smb_ReceiveNTTranCreate(vcp, inp, outp);
8099 osi_Log0(smb_logp, "SMB NT Transact Ioctl - not implemented");
8102 osi_Log0(smb_logp, "SMB NT Transact SetSecurityDesc - not implemented");
8105 return smb_ReceiveNTTranNotifyChange(vcp, inp, outp);
8107 osi_Log0(smb_logp, "SMB NT Transact Rename - not implemented");
8110 return smb_ReceiveNTTranQuerySecurityDesc(vcp, inp, outp);
8112 return CM_ERROR_INVAL;
8116 * smb_NotifyChange -- find relevant change notification messages and
8119 * If we don't know the file name (i.e. a callback break), filename is
8120 * NULL, and we return a zero-length list.
8122 * At present there is not a single call to smb_NotifyChange that
8123 * has the isDirectParent parameter set to FALSE.
8125 void smb_NotifyChange(DWORD action, DWORD notifyFilter,
8126 cm_scache_t *dscp, char *filename, char *otherFilename,
8127 BOOL isDirectParent)
8129 smb_packet_t *watch, *lastWatch, *nextWatch;
8130 ULONG parmSlot, parmCount, parmOffset, dataOffset, nameLen;
8131 char *outData, *oldOutData;
8135 BOOL twoEntries = FALSE;
8136 ULONG otherNameLen, oldParmCount = 0;
8140 /* Get ready for rename within directory */
8141 if (action == FILE_ACTION_RENAMED_OLD_NAME && otherFilename != NULL) {
8143 otherAction = FILE_ACTION_RENAMED_NEW_NAME;
8146 osi_Log4(smb_logp,"in smb_NotifyChange for file [%s] dscp [%p] notification 0x%x parent %d",
8147 osi_LogSaveString(smb_logp,filename),dscp, notifyFilter, isDirectParent);
8149 osi_Log0(smb_logp," FILE_ACTION_NONE");
8150 if (action == FILE_ACTION_ADDED)
8151 osi_Log0(smb_logp," FILE_ACTION_ADDED");
8152 if (action == FILE_ACTION_REMOVED)
8153 osi_Log0(smb_logp," FILE_ACTION_REMOVED");
8154 if (action == FILE_ACTION_MODIFIED)
8155 osi_Log0(smb_logp," FILE_ACTION_MODIFIED");
8156 if (action == FILE_ACTION_RENAMED_OLD_NAME)
8157 osi_Log0(smb_logp," FILE_ACTION_RENAMED_OLD_NAME");
8158 if (action == FILE_ACTION_RENAMED_NEW_NAME)
8159 osi_Log0(smb_logp," FILE_ACTION_RENAMED_NEW_NAME");
8161 lock_ObtainMutex(&smb_Dir_Watch_Lock);
8162 watch = smb_Directory_Watches;
8164 filter = smb_GetSMBParm(watch, 19)
8165 | (smb_GetSMBParm(watch, 20) << 16);
8166 fid = smb_GetSMBParm(watch, 21);
8167 wtree = (smb_GetSMBParm(watch, 22) & 0xff) ? 1 : 0;
8169 maxLen = smb_GetSMBOffsetParm(watch, 5, 1)
8170 | (smb_GetSMBOffsetParm(watch, 6, 1) << 16);
8173 * Strange hack - bug in NT Client and NT Server that we must emulate?
8175 if ((filter == (FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME)) && wtree)
8176 filter |= FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_ATTRIBUTES;
8178 fidp = smb_FindFID(watch->vcp, fid, 0);
8180 osi_Log2(smb_logp," no fidp for fid[%d] in vcp 0x%p",fid, watch->vcp);
8182 watch = watch->nextp;
8185 if (fidp->scp != dscp
8186 || (filter & notifyFilter) == 0
8187 || (!isDirectParent && !wtree)) {
8188 osi_Log1(smb_logp," skipping fidp->scp[%x]", fidp->scp);
8189 smb_ReleaseFID(fidp);
8191 watch = watch->nextp;
8194 smb_ReleaseFID(fidp);
8197 "Sending Change Notification for fid %d filter 0x%x wtree %d file %s",
8198 fid, filter, wtree, osi_LogSaveString(smb_logp, filename));
8199 if (filter & FILE_NOTIFY_CHANGE_FILE_NAME)
8200 osi_Log0(smb_logp, " Notify Change File Name");
8201 if (filter & FILE_NOTIFY_CHANGE_DIR_NAME)
8202 osi_Log0(smb_logp, " Notify Change Directory Name");
8203 if (filter & FILE_NOTIFY_CHANGE_ATTRIBUTES)
8204 osi_Log0(smb_logp, " Notify Change Attributes");
8205 if (filter & FILE_NOTIFY_CHANGE_SIZE)
8206 osi_Log0(smb_logp, " Notify Change Size");
8207 if (filter & FILE_NOTIFY_CHANGE_LAST_WRITE)
8208 osi_Log0(smb_logp, " Notify Change Last Write");
8209 if (filter & FILE_NOTIFY_CHANGE_LAST_ACCESS)
8210 osi_Log0(smb_logp, " Notify Change Last Access");
8211 if (filter & FILE_NOTIFY_CHANGE_CREATION)
8212 osi_Log0(smb_logp, " Notify Change Creation");
8213 if (filter & FILE_NOTIFY_CHANGE_EA)
8214 osi_Log0(smb_logp, " Notify Change Extended Attributes");
8215 if (filter & FILE_NOTIFY_CHANGE_SECURITY)
8216 osi_Log0(smb_logp, " Notify Change Security");
8217 if (filter & FILE_NOTIFY_CHANGE_STREAM_NAME)
8218 osi_Log0(smb_logp, " Notify Change Stream Name");
8219 if (filter & FILE_NOTIFY_CHANGE_STREAM_SIZE)
8220 osi_Log0(smb_logp, " Notify Change Stream Size");
8221 if (filter & FILE_NOTIFY_CHANGE_STREAM_WRITE)
8222 osi_Log0(smb_logp, " Notify Change Stream Write");
8224 /* A watch can only be notified once. Remove it from the list */
8225 nextWatch = watch->nextp;
8226 if (watch == smb_Directory_Watches)
8227 smb_Directory_Watches = nextWatch;
8229 lastWatch->nextp = nextWatch;
8231 /* Turn off WATCHED flag in dscp */
8232 lock_ObtainMutex(&dscp->mx);
8234 dscp->flags &= ~CM_SCACHEFLAG_WATCHEDSUBTREE;
8236 dscp->flags &= ~CM_SCACHEFLAG_WATCHED;
8237 lock_ReleaseMutex(&dscp->mx);
8239 /* Convert to response packet */
8240 ((smb_t *) watch)->reb = SMB_FLAGS_SERVER_TO_CLIENT | SMB_FLAGS_CANONICAL_PATHNAMES;
8241 ((smb_t *) watch)->wct = 0;
8244 if (filename == NULL)
8247 nameLen = (ULONG)strlen(filename);
8248 parmCount = 3*4 + nameLen*2;
8249 parmCount = (parmCount + 3) & ~3; /* pad to 4 */
8251 otherNameLen = (ULONG)strlen(otherFilename);
8252 oldParmCount = parmCount;
8253 parmCount += 3*4 + otherNameLen*2;
8254 parmCount = (parmCount + 3) & ~3; /* pad to 4 */
8256 if (maxLen < parmCount)
8257 parmCount = 0; /* not enough room */
8259 parmOffset = 8*4 + 39;
8260 parmOffset += 1; /* pad to 4 */
8261 dataOffset = parmOffset + parmCount;
8265 /* Total Parameter Count */
8266 smb_SetSMBParmLong(watch, parmSlot, parmCount); parmSlot += 2;
8267 /* Total Data Count */
8268 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
8269 /* Parameter Count */
8270 smb_SetSMBParmLong(watch, parmSlot, parmCount); parmSlot += 2;
8271 /* Parameter Offset */
8272 smb_SetSMBParmLong(watch, parmSlot, parmOffset); parmSlot += 2;
8273 /* Parameter Displacement */
8274 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
8276 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
8278 smb_SetSMBParmLong(watch, parmSlot, dataOffset); parmSlot += 2;
8279 /* Data Displacement */
8280 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
8281 smb_SetSMBParmByte(watch, parmSlot, 0); /* Setup Count */
8282 smb_SetSMBDataLength(watch, parmCount + 1);
8284 if (parmCount != 0) {
8286 outData = smb_GetSMBData(watch, NULL);
8287 outData++; /* round to get to parmOffset */
8288 oldOutData = outData;
8289 *((DWORD *)outData) = oldParmCount; outData += 4;
8290 /* Next Entry Offset */
8291 *((DWORD *)outData) = action; outData += 4;
8293 *((DWORD *)outData) = nameLen*2; outData += 4;
8294 /* File Name Length */
8295 p = strdup(filename);
8296 if (smb_StoreAnsiFilenames)
8298 mbstowcs((WCHAR *)outData, p, nameLen);
8302 outData = oldOutData + oldParmCount;
8303 *((DWORD *)outData) = 0; outData += 4;
8304 /* Next Entry Offset */
8305 *((DWORD *)outData) = otherAction; outData += 4;
8307 *((DWORD *)outData) = otherNameLen*2;
8308 outData += 4; /* File Name Length */
8309 p = strdup(otherFilename);
8310 if (smb_StoreAnsiFilenames)
8312 mbstowcs((WCHAR *)outData, p, otherNameLen); /* File Name */
8318 * If filename is null, we don't know the cause of the
8319 * change notification. We return zero data (see above),
8320 * and set error code to NT_STATUS_NOTIFY_ENUM_DIR
8321 * (= 0x010C). We set the error code here by hand, without
8322 * modifying wct and bcc.
8324 if (filename == NULL) {
8325 ((smb_t *) watch)->rcls = 0x0C;
8326 ((smb_t *) watch)->reh = 0x01;
8327 ((smb_t *) watch)->errLow = 0;
8328 ((smb_t *) watch)->errHigh = 0;
8329 /* Set NT Status codes flag */
8330 ((smb_t *) watch)->flg2 |= SMB_FLAGS2_32BIT_STATUS;
8333 smb_SendPacket(watch->vcp, watch);
8334 smb_FreePacket(watch);
8337 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
8340 long smb_ReceiveNTCancel(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
8342 unsigned char *replyWctp;
8343 smb_packet_t *watch, *lastWatch;
8344 USHORT fid, watchtree;
8348 osi_Log0(smb_logp, "SMB3 receive NT cancel");
8350 lock_ObtainMutex(&smb_Dir_Watch_Lock);
8351 watch = smb_Directory_Watches;
8353 if (((smb_t *)watch)->uid == ((smb_t *)inp)->uid
8354 && ((smb_t *)watch)->pid == ((smb_t *)inp)->pid
8355 && ((smb_t *)watch)->mid == ((smb_t *)inp)->mid
8356 && ((smb_t *)watch)->tid == ((smb_t *)inp)->tid) {
8357 if (watch == smb_Directory_Watches)
8358 smb_Directory_Watches = watch->nextp;
8360 lastWatch->nextp = watch->nextp;
8361 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
8363 /* Turn off WATCHED flag in scp */
8364 fid = smb_GetSMBParm(watch, 21);
8365 watchtree = smb_GetSMBParm(watch, 22) & 0xffff;
8367 if (vcp != watch->vcp)
8368 osi_Log2(smb_logp, "smb_ReceiveNTCancel: vcp %x not equal to watch vcp %x",
8371 fidp = smb_FindFID(vcp, fid, 0);
8373 osi_Log3(smb_logp, "Cancelling change notification for fid %d wtree %d file %s",
8375 osi_LogSaveString(smb_logp, (fidp)?fidp->NTopen_wholepathp:""));
8378 osi_Log2(smb_logp,"smb_ReceiveNTCancel fidp 0x%p scp 0x%p", fidp, scp);
8379 lock_ObtainMutex(&scp->mx);
8381 scp->flags &= ~CM_SCACHEFLAG_WATCHEDSUBTREE;
8383 scp->flags &= ~CM_SCACHEFLAG_WATCHED;
8384 lock_ReleaseMutex(&scp->mx);
8385 smb_ReleaseFID(fidp);
8387 osi_Log2(smb_logp,"NTCancel unable to resolve fid [%d] in vcp[%x]", fid,vcp);
8390 /* assume STATUS32; return 0xC0000120 (CANCELED) */
8391 replyWctp = watch->wctp;
8395 ((smb_t *)watch)->rcls = 0x20;
8396 ((smb_t *)watch)->reh = 0x1;
8397 ((smb_t *)watch)->errLow = 0;
8398 ((smb_t *)watch)->errHigh = 0xC0;
8399 ((smb_t *)watch)->flg2 |= SMB_FLAGS2_32BIT_STATUS;
8400 smb_SendPacket(vcp, watch);
8401 smb_FreePacket(watch);
8405 watch = watch->nextp;
8407 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
8413 * NT rename also does hard links.
8416 #define RENAME_FLAG_MOVE_CLUSTER_INFORMATION 0x102
8417 #define RENAME_FLAG_HARD_LINK 0x103
8418 #define RENAME_FLAG_RENAME 0x104
8419 #define RENAME_FLAG_COPY 0x105
8421 long smb_ReceiveNTRename(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
8423 char *oldPathp, *newPathp;
8429 attrs = smb_GetSMBParm(inp, 0);
8430 rename_type = smb_GetSMBParm(inp, 1);
8432 if (rename_type != RENAME_FLAG_RENAME && rename_type != RENAME_FLAG_HARD_LINK) {
8433 osi_Log1(smb_logp, "NTRename invalid rename_type [%x]", rename_type);
8434 return CM_ERROR_NOACCESS;
8437 tp = smb_GetSMBData(inp, NULL);
8438 oldPathp = smb_ParseASCIIBlock(tp, &tp);
8439 if (smb_StoreAnsiFilenames)
8440 OemToChar(oldPathp,oldPathp);
8441 newPathp = smb_ParseASCIIBlock(tp, &tp);
8442 if (smb_StoreAnsiFilenames)
8443 OemToChar(newPathp,newPathp);
8445 osi_Log3(smb_logp, "NTRename for [%s]->[%s] type [%s]",
8446 osi_LogSaveString(smb_logp, oldPathp),
8447 osi_LogSaveString(smb_logp, newPathp),
8448 ((rename_type==RENAME_FLAG_RENAME)?"rename":"hardlink"));
8450 if (rename_type == RENAME_FLAG_RENAME) {
8451 code = smb_Rename(vcp,inp,oldPathp,newPathp,attrs);
8452 } else { /* RENAME_FLAG_HARD_LINK */
8453 code = smb_Link(vcp,inp,oldPathp,newPathp);
8460 lock_InitializeMutex(&smb_Dir_Watch_Lock, "Directory Watch List Lock");
8463 cm_user_t *smb_FindCMUserByName(char *usern, char *machine, afs_uint32 flags)
8465 smb_username_t *unp;
8468 unp = smb_FindUserByName(usern, machine, flags);
8470 lock_ObtainMutex(&unp->mx);
8471 unp->userp = cm_NewUser();
8472 lock_ReleaseMutex(&unp->mx);
8473 osi_Log2(smb_logp,"smb_FindCMUserByName New user name[%s] machine[%s]",osi_LogSaveString(smb_logp,usern),osi_LogSaveString(smb_logp,machine));
8475 osi_Log2(smb_logp,"smb_FindCMUserByName Not found name[%s] machine[%s]",osi_LogSaveString(smb_logp,usern),osi_LogSaveString(smb_logp,machine));
8479 smb_ReleaseUsername(unp);