2 * Copyright 2000, International Business Machines Corporation and others.
5 * This software has been released under the terms of the IBM Public
6 * License. For details, see the LICENSE file in the top-level source
7 * directory or online at http://www.openafs.org/dl/license10.html
10 #include <afs/param.h>
16 #define SECURITY_WIN32
28 #include <WINNT\afsreg.h>
32 extern osi_hyper_t hzero;
34 smb_packet_t *smb_Directory_Watches = NULL;
35 osi_mutex_t smb_Dir_Watch_Lock;
37 smb_tran2Dispatch_t smb_tran2DispatchTable[SMB_TRAN2_NOPCODES];
39 smb_tran2Dispatch_t smb_rapDispatchTable[SMB_RAP_NOPCODES];
41 /* protected by the smb_globalLock */
42 smb_tran2Packet_t *smb_tran2AssemblyQueuep;
44 /* retrieve a held reference to a user structure corresponding to an incoming
46 cm_user_t *smb_GetTran2User(smb_vc_t *vcp, smb_tran2Packet_t *inp)
51 uidp = smb_FindUID(vcp, inp->uid, 0);
55 up = smb_GetUserFromUID(uidp);
63 * Return extended attributes.
64 * Right now, we aren't using any of the "new" bits, so this looks exactly
65 * like smb_Attributes() (see smb.c).
67 unsigned long smb_ExtAttributes(cm_scache_t *scp)
71 if (scp->fileType == CM_SCACHETYPE_DIRECTORY ||
72 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
73 scp->fileType == CM_SCACHETYPE_INVALID)
75 attrs = SMB_ATTR_DIRECTORY;
76 #ifdef SPECIAL_FOLDERS
77 attrs |= SMB_ATTR_SYSTEM; /* FILE_ATTRIBUTE_SYSTEM */
78 #endif /* SPECIAL_FOLDERS */
79 } else if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
80 attrs = SMB_ATTR_DIRECTORY | SMB_ATTR_SPARSE_FILE;
84 * We used to mark a file RO if it was in an RO volume, but that
85 * turns out to be impolitic in NT. See defect 10007.
88 if ((scp->unixModeBits & 0222) == 0 || (scp->flags & CM_SCACHEFLAG_RO))
89 attrs |= SMB_ATTR_READONLY; /* Read-only */
91 if ((scp->unixModeBits & 0222) == 0)
92 attrs |= SMB_ATTR_READONLY; /* Read-only */
96 attrs = SMB_ATTR_NORMAL; /* FILE_ATTRIBUTE_NORMAL */
101 int smb_V3IsStarMask(char *maskp)
105 while (tc = *maskp++)
106 if (tc == '?' || tc == '*' || tc == '<' || tc == '>')
111 unsigned char *smb_ParseString(unsigned char *inp, char **chainpp)
114 /* skip over null-terminated string */
115 *chainpp = inp + strlen(inp) + 1;
120 void OutputDebugF(char * format, ...) {
125 va_start( args, format );
126 len = _vscprintf( format, args ) // _vscprintf doesn't count
127 + 3; // terminating '\0' + '\n'
128 buffer = malloc( len * sizeof(char) );
129 vsprintf( buffer, format, args );
130 osi_Log0(smb_logp, osi_LogSaveString(smb_logp, buffer));
131 strcat(buffer, "\n");
132 OutputDebugString(buffer);
136 void OutputDebugHexDump(unsigned char * buffer, int len) {
139 static char tr[16] = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
141 OutputDebugF("Hexdump length [%d]",len);
143 for (i=0;i<len;i++) {
146 osi_Log0(smb_logp, osi_LogSaveString(smb_logp, buf));
148 OutputDebugString(buf);
150 sprintf(buf,"%5x",i);
151 memset(buf+5,' ',80);
156 j = j*3 + 7 + ((j>7)?1:0);
159 buf[j] = tr[k / 16]; buf[j+1] = tr[k % 16];
162 j = j + 56 + ((j>7)?1:0) + pcts;
164 buf[j] = (k>32 && k<127)?k:'.';
171 osi_Log0(smb_logp, osi_LogSaveString(smb_logp, buf));
173 OutputDebugString(buf);
177 #define SMB_EXT_SEC_PACKAGE_NAME "Negotiate"
179 void smb_NegotiateExtendedSecurity(void ** secBlob, int * secBlobLength) {
180 SECURITY_STATUS status, istatus;
181 CredHandle creds = {0,0};
183 SecBufferDesc secOut;
191 OutputDebugF("Negotiating Extended Security");
193 status = AcquireCredentialsHandle( NULL,
194 SMB_EXT_SEC_PACKAGE_NAME,
203 if (status != SEC_E_OK) {
204 /* Really bad. We return an empty security blob */
205 OutputDebugF("AcquireCredentialsHandle failed with %lX", status);
210 secOut.pBuffers = &secTok;
211 secOut.ulVersion = SECBUFFER_VERSION;
213 secTok.BufferType = SECBUFFER_TOKEN;
215 secTok.pvBuffer = NULL;
217 ctx.dwLower = ctx.dwUpper = 0;
219 status = AcceptSecurityContext( &creds,
222 ASC_REQ_CONNECTION | ASC_REQ_EXTENDED_ERROR | ASC_REQ_ALLOCATE_MEMORY,
223 SECURITY_NETWORK_DREP,
230 if (status == SEC_I_COMPLETE_NEEDED || status == SEC_I_COMPLETE_AND_CONTINUE) {
231 OutputDebugF("Completing token...");
232 istatus = CompleteAuthToken(&ctx, &secOut);
233 if ( istatus != SEC_E_OK )
234 OutputDebugF("Token completion failed: %x", istatus);
237 if (status == SEC_I_COMPLETE_AND_CONTINUE || status == SEC_I_CONTINUE_NEEDED) {
238 if (secTok.pvBuffer) {
239 *secBlobLength = secTok.cbBuffer;
240 *secBlob = malloc( secTok.cbBuffer );
241 memcpy(*secBlob, secTok.pvBuffer, secTok.cbBuffer );
244 if ( status != SEC_E_OK )
245 OutputDebugF("AcceptSecurityContext status != CONTINUE %lX", status);
248 /* Discard partial security context */
249 DeleteSecurityContext(&ctx);
251 if (secTok.pvBuffer) FreeContextBuffer( secTok.pvBuffer );
253 /* Discard credentials handle. We'll reacquire one when we get the session setup X */
254 FreeCredentialsHandle(&creds);
260 struct smb_ext_context {
267 long smb_AuthenticateUserExt(smb_vc_t * vcp, char * usern, char * secBlobIn, int secBlobInLength, char ** secBlobOut, int * secBlobOutLength) {
268 SECURITY_STATUS status, istatus;
272 SecBufferDesc secBufIn;
274 SecBufferDesc secBufOut;
277 struct smb_ext_context * secCtx = NULL;
278 struct smb_ext_context * newSecCtx = NULL;
279 void * assembledBlob = NULL;
280 int assembledBlobLength = 0;
283 OutputDebugF("In smb_AuthenticateUserExt");
286 *secBlobOutLength = 0;
288 if (vcp->flags & SMB_VCFLAG_AUTH_IN_PROGRESS) {
289 secCtx = vcp->secCtx;
290 lock_ObtainMutex(&vcp->mx);
291 vcp->flags &= ~SMB_VCFLAG_AUTH_IN_PROGRESS;
293 lock_ReleaseMutex(&vcp->mx);
297 OutputDebugF("Received incoming token:");
298 OutputDebugHexDump(secBlobIn,secBlobInLength);
302 OutputDebugF("Continuing with existing context.");
303 creds = secCtx->creds;
306 if (secCtx->partialToken) {
307 assembledBlobLength = secCtx->partialTokenLen + secBlobInLength;
308 assembledBlob = malloc(assembledBlobLength);
309 memcpy(assembledBlob,secCtx->partialToken, secCtx->partialTokenLen);
310 memcpy(((BYTE *)assembledBlob) + secCtx->partialTokenLen, secBlobIn, secBlobInLength);
313 status = AcquireCredentialsHandle( NULL,
314 SMB_EXT_SEC_PACKAGE_NAME,
323 if (status != SEC_E_OK) {
324 OutputDebugF("Can't acquire Credentials handle [%lX]", status);
325 code = CM_ERROR_BADPASSWORD; /* means "try again when I'm sober" */
333 secBufIn.cBuffers = 1;
334 secBufIn.pBuffers = &secTokIn;
335 secBufIn.ulVersion = SECBUFFER_VERSION;
337 secTokIn.BufferType = SECBUFFER_TOKEN;
339 secTokIn.cbBuffer = assembledBlobLength;
340 secTokIn.pvBuffer = assembledBlob;
342 secTokIn.cbBuffer = secBlobInLength;
343 secTokIn.pvBuffer = secBlobIn;
346 secBufOut.cBuffers = 1;
347 secBufOut.pBuffers = &secTokOut;
348 secBufOut.ulVersion = SECBUFFER_VERSION;
350 secTokOut.BufferType = SECBUFFER_TOKEN;
351 secTokOut.cbBuffer = 0;
352 secTokOut.pvBuffer = NULL;
354 status = AcceptSecurityContext( &creds,
355 ((secCtx)?&ctx:NULL),
357 ASC_REQ_CONNECTION | ASC_REQ_EXTENDED_ERROR | ASC_REQ_ALLOCATE_MEMORY,
358 SECURITY_NETWORK_DREP,
365 if (status == SEC_I_COMPLETE_NEEDED || status == SEC_I_COMPLETE_AND_CONTINUE) {
366 OutputDebugF("Completing token...");
367 istatus = CompleteAuthToken(&ctx, &secBufOut);
368 if ( istatus != SEC_E_OK )
369 OutputDebugF("Token completion failed: %lX", istatus);
372 if (status == SEC_I_COMPLETE_AND_CONTINUE || status == SEC_I_CONTINUE_NEEDED) {
373 OutputDebugF("Continue needed");
375 newSecCtx = malloc(sizeof(*newSecCtx));
377 newSecCtx->creds = creds;
378 newSecCtx->ctx = ctx;
379 newSecCtx->partialToken = NULL;
380 newSecCtx->partialTokenLen = 0;
382 lock_ObtainMutex( &vcp->mx );
383 vcp->flags |= SMB_VCFLAG_AUTH_IN_PROGRESS;
384 vcp->secCtx = newSecCtx;
385 lock_ReleaseMutex( &vcp->mx );
387 code = CM_ERROR_GSSCONTINUE;
390 if ((status == SEC_I_COMPLETE_NEEDED || status == SEC_E_OK ||
391 status == SEC_I_COMPLETE_AND_CONTINUE || status == SEC_I_CONTINUE_NEEDED) &&
392 secTokOut.pvBuffer) {
393 OutputDebugF("Need to send token back to client");
395 *secBlobOutLength = secTokOut.cbBuffer;
396 *secBlobOut = malloc(secTokOut.cbBuffer);
397 memcpy(*secBlobOut, secTokOut.pvBuffer, secTokOut.cbBuffer);
399 OutputDebugF("Outgoing token:");
400 OutputDebugHexDump(*secBlobOut,*secBlobOutLength);
401 } else if (status == SEC_E_INCOMPLETE_MESSAGE) {
402 OutputDebugF("Incomplete message");
404 newSecCtx = malloc(sizeof(*newSecCtx));
406 newSecCtx->creds = creds;
407 newSecCtx->ctx = ctx;
408 newSecCtx->partialToken = malloc(secTokOut.cbBuffer);
409 memcpy(newSecCtx->partialToken, secTokOut.pvBuffer, secTokOut.cbBuffer);
410 newSecCtx->partialTokenLen = secTokOut.cbBuffer;
412 lock_ObtainMutex( &vcp->mx );
413 vcp->flags |= SMB_VCFLAG_AUTH_IN_PROGRESS;
414 vcp->secCtx = newSecCtx;
415 lock_ReleaseMutex( &vcp->mx );
417 code = CM_ERROR_GSSCONTINUE;
420 if (status == SEC_E_OK || status == SEC_I_COMPLETE_NEEDED) {
422 SecPkgContext_Names names;
424 OutputDebugF("Authentication completed");
425 OutputDebugF("Returned flags : [%lX]", flags);
427 if (!QueryContextAttributes(&ctx, SECPKG_ATTR_NAMES, &names)) {
428 OutputDebugF("Received name [%s]", names.sUserName);
429 strcpy(usern, names.sUserName);
430 strlwr(usern); /* in tandem with smb_GetNormalizedUsername */
431 FreeContextBuffer(names.sUserName);
433 /* Force the user to retry if the context is invalid */
434 OutputDebugF("QueryContextAttributes Names failed [%x]", GetLastError());
435 code = CM_ERROR_BADPASSWORD;
439 case SEC_E_INVALID_TOKEN:
440 OutputDebugF("Returning bad password :: INVALID_TOKEN");
442 case SEC_E_INVALID_HANDLE:
443 OutputDebugF("Returning bad password :: INVALID_HANDLE");
445 case SEC_E_LOGON_DENIED:
446 OutputDebugF("Returning bad password :: LOGON_DENIED");
448 case SEC_E_UNKNOWN_CREDENTIALS:
449 OutputDebugF("Returning bad password :: UNKNOWN_CREDENTIALS");
451 case SEC_E_NO_CREDENTIALS:
452 OutputDebugF("Returning bad password :: NO_CREDENTIALS");
454 case SEC_E_CONTEXT_EXPIRED:
455 OutputDebugF("Returning bad password :: CONTEXT_EXPIRED");
457 case SEC_E_INCOMPLETE_CREDENTIALS:
458 OutputDebugF("Returning bad password :: INCOMPLETE_CREDENTIALS");
460 case SEC_E_WRONG_PRINCIPAL:
461 OutputDebugF("Returning bad password :: WRONG_PRINCIPAL");
463 case SEC_E_TIME_SKEW:
464 OutputDebugF("Returning bad password :: TIME_SKEW");
467 OutputDebugF("Returning bad password :: Status == %lX", status);
469 code = CM_ERROR_BADPASSWORD;
473 if (secCtx->partialToken) free(secCtx->partialToken);
481 if (secTokOut.pvBuffer)
482 FreeContextBuffer(secTokOut.pvBuffer);
484 if (code != CM_ERROR_GSSCONTINUE) {
485 DeleteSecurityContext(&ctx);
486 FreeCredentialsHandle(&creds);
494 #define P_RESP_LEN 128
496 /* LsaLogonUser expects input parameters to be in a contiguous block of memory.
497 So put stuff in a struct. */
498 struct Lm20AuthBlob {
499 MSV1_0_LM20_LOGON lmlogon;
500 BYTE ciResponse[P_RESP_LEN]; /* Unicode representation */
501 BYTE csResponse[P_RESP_LEN]; /* ANSI representation */
502 WCHAR accountNameW[P_LEN];
503 WCHAR primaryDomainW[P_LEN];
504 WCHAR workstationW[MAX_COMPUTERNAME_LENGTH + 1];
505 TOKEN_GROUPS tgroups;
506 TOKEN_SOURCE tsource;
509 long smb_AuthenticateUserLM(smb_vc_t *vcp, char * accountName, char * primaryDomain, char * ciPwd, unsigned ciPwdLength, char * csPwd, unsigned csPwdLength)
512 struct Lm20AuthBlob lmAuth;
513 PMSV1_0_LM20_LOGON_PROFILE lmprofilep;
514 QUOTA_LIMITS quotaLimits;
516 ULONG lmprofilepSize;
520 OutputDebugF("In smb_AuthenticateUser for user [%s] domain [%s]", accountName, primaryDomain);
521 OutputDebugF("ciPwdLength is %d and csPwdLength is %d", ciPwdLength, csPwdLength);
523 if (ciPwdLength > P_RESP_LEN || csPwdLength > P_RESP_LEN) {
524 OutputDebugF("ciPwdLength or csPwdLength is too long");
525 return CM_ERROR_BADPASSWORD;
528 memset(&lmAuth,0,sizeof(lmAuth));
530 lmAuth.lmlogon.MessageType = MsV1_0NetworkLogon;
532 lmAuth.lmlogon.LogonDomainName.Buffer = lmAuth.primaryDomainW;
533 mbstowcs(lmAuth.primaryDomainW, primaryDomain, P_LEN);
534 lmAuth.lmlogon.LogonDomainName.Length = (USHORT)(wcslen(lmAuth.primaryDomainW) * sizeof(WCHAR));
535 lmAuth.lmlogon.LogonDomainName.MaximumLength = P_LEN * sizeof(WCHAR);
537 lmAuth.lmlogon.UserName.Buffer = lmAuth.accountNameW;
538 mbstowcs(lmAuth.accountNameW, accountName, P_LEN);
539 lmAuth.lmlogon.UserName.Length = (USHORT)(wcslen(lmAuth.accountNameW) * sizeof(WCHAR));
540 lmAuth.lmlogon.UserName.MaximumLength = P_LEN * sizeof(WCHAR);
542 lmAuth.lmlogon.Workstation.Buffer = lmAuth.workstationW;
543 lmAuth.lmlogon.Workstation.MaximumLength = (MAX_COMPUTERNAME_LENGTH + 1) * sizeof(WCHAR);
544 size = MAX_COMPUTERNAME_LENGTH + 1;
545 GetComputerNameW(lmAuth.workstationW, &size);
546 lmAuth.lmlogon.Workstation.Length = (USHORT)(wcslen(lmAuth.workstationW) * sizeof(WCHAR));
548 memcpy(lmAuth.lmlogon.ChallengeToClient, vcp->encKey, MSV1_0_CHALLENGE_LENGTH);
550 lmAuth.lmlogon.CaseInsensitiveChallengeResponse.Buffer = lmAuth.ciResponse;
551 lmAuth.lmlogon.CaseInsensitiveChallengeResponse.Length = ciPwdLength;
552 lmAuth.lmlogon.CaseInsensitiveChallengeResponse.MaximumLength = P_RESP_LEN;
553 memcpy(lmAuth.ciResponse, ciPwd, ciPwdLength);
555 lmAuth.lmlogon.CaseSensitiveChallengeResponse.Buffer = lmAuth.csResponse;
556 lmAuth.lmlogon.CaseSensitiveChallengeResponse.Length = csPwdLength;
557 lmAuth.lmlogon.CaseSensitiveChallengeResponse.MaximumLength = P_RESP_LEN;
558 memcpy(lmAuth.csResponse, csPwd, csPwdLength);
560 lmAuth.lmlogon.ParameterControl = 0;
562 lmAuth.tgroups.GroupCount = 0;
563 lmAuth.tgroups.Groups[0].Sid = NULL;
564 lmAuth.tgroups.Groups[0].Attributes = 0;
566 lmAuth.tsource.SourceIdentifier.HighPart = (DWORD)((LONG_PTR)vcp << 32);
567 lmAuth.tsource.SourceIdentifier.LowPart = (DWORD)((LONG_PTR)vcp & _UI32_MAX);
568 strcpy(lmAuth.tsource.SourceName,"OpenAFS"); /* 8 char limit */
570 nts = LsaLogonUser( smb_lsaHandle,
585 if (nts != STATUS_SUCCESS || ntsEx != STATUS_SUCCESS)
586 osi_Log2(smb_logp,"LsaLogonUser failure: nts %u ntsEx %u",
589 OutputDebugF("Return from LsaLogonUser is 0x%lX", nts);
590 OutputDebugF("Extended status is 0x%lX", ntsEx);
592 if (nts == ERROR_SUCCESS) {
594 LsaFreeReturnBuffer(lmprofilep);
595 CloseHandle(lmToken);
599 if (nts == 0xC000015BL)
600 return CM_ERROR_BADLOGONTYPE;
601 else /* our catchall is a bad password though we could be more specific */
602 return CM_ERROR_BADPASSWORD;
606 /* The buffer pointed to by usern is assumed to be at least SMB_MAX_USERNAME_LENGTH bytes */
607 long smb_GetNormalizedUsername(char * usern, const char * accountName, const char * domainName)
612 /* check if we have sane input */
613 if ((strlen(accountName) + strlen(domainName) + 1) > SMB_MAX_USERNAME_LENGTH)
616 /* we could get : [accountName][domainName]
622 atsign = strchr(accountName, '@');
624 if (atsign) /* [user@domain][] -> [user@domain][domain] */
629 /* if for some reason the client doesn't know what domain to use,
630 it will either return an empty string or a '?' */
631 if (!domain[0] || domain[0] == '?')
632 /* Empty domains and empty usernames are usually sent from tokenless contexts.
633 This way such logins will get an empty username (easy to check). I don't know
634 when a non-empty username would be supplied with an anonymous domain, but *shrug* */
635 strcpy(usern,accountName);
637 /* TODO: what about WIN.MIT.EDU\user vs. WIN\user? */
638 strcpy(usern,domain);
641 strncat(usern,accountName,atsign - accountName);
643 strcat(usern,accountName);
651 /* When using SMB auth, all SMB sessions have to pass through here
652 * first to authenticate the user.
654 * Caveat: If not using SMB auth, the protocol does not require
655 * sending a session setup packet, which means that we can't rely on a
656 * UID in subsequent packets. Though in practice we get one anyway.
658 long smb_ReceiveV3SessionSetupX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
662 unsigned short newUid;
663 unsigned long caps = 0;
667 char usern[SMB_MAX_USERNAME_LENGTH];
668 char *secBlobOut = NULL;
669 int secBlobOutLength = 0;
671 /* Check for bad conns */
672 if (vcp->flags & SMB_VCFLAG_REMOTECONN)
673 return CM_ERROR_REMOTECONN;
675 if (vcp->flags & SMB_VCFLAG_USENT) {
676 if (smb_authType == SMB_AUTH_EXTENDED) {
677 /* extended authentication */
681 OutputDebugF("NT Session Setup: Extended");
683 if (!(vcp->flags & SMB_VCFLAG_SESSX_RCVD)) {
684 caps = smb_GetSMBParm(inp,10) | (((unsigned long) smb_GetSMBParm(inp,11)) << 16);
687 secBlobInLength = smb_GetSMBParm(inp, 7);
688 secBlobIn = smb_GetSMBData(inp, NULL);
690 code = smb_AuthenticateUserExt(vcp, usern, secBlobIn, secBlobInLength, &secBlobOut, &secBlobOutLength);
692 if (code == CM_ERROR_GSSCONTINUE) {
693 smb_SetSMBParm(outp, 2, 0);
694 smb_SetSMBParm(outp, 3, secBlobOutLength);
695 smb_SetSMBDataLength(outp, secBlobOutLength + smb_ServerOSLength + smb_ServerLanManagerLength + smb_ServerDomainNameLength);
696 tp = smb_GetSMBData(outp, NULL);
697 if (secBlobOutLength) {
698 memcpy(tp, secBlobOut, secBlobOutLength);
700 tp += secBlobOutLength;
702 memcpy(tp,smb_ServerOS,smb_ServerOSLength);
703 tp += smb_ServerOSLength;
704 memcpy(tp,smb_ServerLanManager,smb_ServerLanManagerLength);
705 tp += smb_ServerLanManagerLength;
706 memcpy(tp,smb_ServerDomainName,smb_ServerDomainNameLength);
707 tp += smb_ServerDomainNameLength;
710 /* TODO: handle return code and continue auth. Also free secBlobOut if applicable. */
712 unsigned ciPwdLength, csPwdLength;
718 if (smb_authType == SMB_AUTH_NTLM)
719 OutputDebugF("NT Session Setup: NTLM");
721 OutputDebugF("NT Session Setup: None");
723 /* TODO: parse for extended auth as well */
724 ciPwdLength = smb_GetSMBParm(inp, 7); /* case insensitive password length */
725 csPwdLength = smb_GetSMBParm(inp, 8); /* case sensitive password length */
727 tp = smb_GetSMBData(inp, &datalen);
729 OutputDebugF("Session packet data size [%d]",datalen);
736 accountName = smb_ParseString(tp, &tp);
737 primaryDomain = smb_ParseString(tp, NULL);
739 OutputDebugF("Account Name: %s",accountName);
740 OutputDebugF("Primary Domain: %s", primaryDomain);
741 OutputDebugF("Case Sensitive Password: %s", csPwd && csPwd[0] ? "yes" : "no");
742 OutputDebugF("Case Insensitive Password: %s", ciPwd && ciPwd[0] ? "yes" : "no");
744 if (smb_GetNormalizedUsername(usern, accountName, primaryDomain)) {
745 /* shouldn't happen */
746 code = CM_ERROR_BADSMB;
747 goto after_read_packet;
750 /* capabilities are only valid for first session packet */
751 if (!(vcp->flags & SMB_VCFLAG_SESSX_RCVD)) {
752 caps = smb_GetSMBParm(inp, 11) | (((unsigned long)smb_GetSMBParm(inp, 12)) << 16);
755 if (smb_authType == SMB_AUTH_NTLM) {
756 code = smb_AuthenticateUserLM(vcp, accountName, primaryDomain, ciPwd, ciPwdLength, csPwd, csPwdLength);
758 OutputDebugF("LM authentication failed [%d]", code);
760 OutputDebugF("LM authentication succeeded");
764 unsigned ciPwdLength;
769 switch ( smb_authType ) {
770 case SMB_AUTH_EXTENDED:
771 OutputDebugF("V3 Session Setup: Extended");
774 OutputDebugF("V3 Session Setup: NTLM");
777 OutputDebugF("V3 Session Setup: None");
779 ciPwdLength = smb_GetSMBParm(inp, 7);
780 tp = smb_GetSMBData(inp, NULL);
784 accountName = smb_ParseString(tp, &tp);
785 primaryDomain = smb_ParseString(tp, NULL);
787 OutputDebugF("Account Name: %s",accountName);
788 OutputDebugF("Primary Domain: %s", primaryDomain);
789 OutputDebugF("Case Insensitive Password: %s", ciPwd && ciPwd[0] ? "yes" : "no");
791 if ( smb_GetNormalizedUsername(usern, accountName, primaryDomain)) {
792 /* shouldn't happen */
793 code = CM_ERROR_BADSMB;
794 goto after_read_packet;
797 /* even if we wanted extended auth, if we only negotiated V3, we have to fallback
800 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
801 code = smb_AuthenticateUserLM(vcp,accountName,primaryDomain,ciPwd,ciPwdLength,"",0);
803 OutputDebugF("LM authentication failed [%d]", code);
805 OutputDebugF("LM authentication succeeded");
810 /* note down that we received a session setup X and set the capabilities flag */
811 if (!(vcp->flags & SMB_VCFLAG_SESSX_RCVD)) {
812 lock_ObtainMutex(&vcp->mx);
813 vcp->flags |= SMB_VCFLAG_SESSX_RCVD;
814 /* for the moment we can only deal with NTSTATUS */
815 if (caps & NTNEGOTIATE_CAPABILITY_NTSTATUS) {
816 vcp->flags |= SMB_VCFLAG_STATUS32;
818 lock_ReleaseMutex(&vcp->mx);
821 /* code would be non-zero if there was an authentication failure.
822 Ideally we would like to invalidate the uid for this session or break
823 early to avoid accidently stealing someone else's tokens. */
829 OutputDebugF("Received username=[%s]", usern);
831 /* On Windows 2000, this function appears to be called more often than
832 it is expected to be called. This resulted in multiple smb_user_t
833 records existing all for the same user session which results in all
834 of the users tokens disappearing.
836 To avoid this problem, we look for an existing smb_user_t record
837 based on the users name, and use that one if we find it.
840 uidp = smb_FindUserByNameThisSession(vcp, usern);
841 if (uidp) { /* already there, so don't create a new one */
843 newUid = uidp->userID;
844 osi_Log3(smb_logp,"smb_ReceiveV3SessionSetupX FindUserByName:Lana[%d],lsn[%d],userid[%d]",
845 vcp->lana,vcp->lsn,newUid);
846 smb_ReleaseUID(uidp);
851 /* do a global search for the username/machine name pair */
852 unp = smb_FindUserByName(usern, vcp->rname, SMB_FLAG_CREATE);
853 lock_ObtainMutex(&unp->mx);
854 if (unp->flags & SMB_USERNAMEFLAG_AFSLOGON) {
855 /* clear the afslogon flag so that the tickets can now
856 * be freed when the refCount returns to zero.
858 unp->flags &= ~SMB_USERNAMEFLAG_AFSLOGON;
860 lock_ReleaseMutex(&unp->mx);
862 /* Create a new UID and cm_user_t structure */
865 userp = cm_NewUser();
866 cm_HoldUserVCRef(userp);
867 lock_ObtainMutex(&vcp->mx);
868 if (!vcp->uidCounter)
869 vcp->uidCounter++; /* handle unlikely wraparounds */
870 newUid = (strlen(usern)==0)?0:vcp->uidCounter++;
871 lock_ReleaseMutex(&vcp->mx);
873 /* Create a new smb_user_t structure and connect them up */
874 lock_ObtainMutex(&unp->mx);
876 lock_ReleaseMutex(&unp->mx);
878 uidp = smb_FindUID(vcp, newUid, SMB_FLAG_CREATE);
880 lock_ObtainMutex(&uidp->mx);
882 osi_Log4(smb_logp,"smb_ReceiveV3SessionSetupX MakeNewUser:VCP[%p],Lana[%d],lsn[%d],userid[%d]",vcp,vcp->lana,vcp->lsn,newUid);
883 lock_ReleaseMutex(&uidp->mx);
884 smb_ReleaseUID(uidp);
888 /* Return UID to the client */
889 ((smb_t *)outp)->uid = newUid;
890 /* Also to the next chained message */
891 ((smb_t *)inp)->uid = newUid;
893 osi_Log3(smb_logp, "SMB3 session setup name %s creating ID %d%s",
894 osi_LogSaveString(smb_logp, usern), newUid, osi_LogSaveString(smb_logp, s1));
896 smb_SetSMBParm(outp, 2, 0);
898 if (vcp->flags & SMB_VCFLAG_USENT) {
899 if (smb_authType == SMB_AUTH_EXTENDED) {
900 smb_SetSMBParm(outp, 3, secBlobOutLength);
901 smb_SetSMBDataLength(outp, secBlobOutLength + smb_ServerOSLength + smb_ServerLanManagerLength + smb_ServerDomainNameLength);
902 tp = smb_GetSMBData(outp, NULL);
903 if (secBlobOutLength) {
904 memcpy(tp, secBlobOut, secBlobOutLength);
906 tp += secBlobOutLength;
908 memcpy(tp,smb_ServerOS,smb_ServerOSLength);
909 tp += smb_ServerOSLength;
910 memcpy(tp,smb_ServerLanManager,smb_ServerLanManagerLength);
911 tp += smb_ServerLanManagerLength;
912 memcpy(tp,smb_ServerDomainName,smb_ServerDomainNameLength);
913 tp += smb_ServerDomainNameLength;
915 smb_SetSMBDataLength(outp, 0);
918 if (smb_authType == SMB_AUTH_EXTENDED) {
919 smb_SetSMBDataLength(outp, smb_ServerOSLength + smb_ServerLanManagerLength + smb_ServerDomainNameLength);
920 tp = smb_GetSMBData(outp, NULL);
921 memcpy(tp,smb_ServerOS,smb_ServerOSLength);
922 tp += smb_ServerOSLength;
923 memcpy(tp,smb_ServerLanManager,smb_ServerLanManagerLength);
924 tp += smb_ServerLanManagerLength;
925 memcpy(tp,smb_ServerDomainName,smb_ServerDomainNameLength);
926 tp += smb_ServerDomainNameLength;
928 smb_SetSMBDataLength(outp, 0);
935 long smb_ReceiveV3UserLogoffX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
939 /* find the tree and free it */
940 uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
942 smb_username_t * unp;
944 osi_Log2(smb_logp, "SMB3 user logoffX uid %d name %s", uidp->userID,
945 osi_LogSaveString(smb_logp, (uidp->unp) ? uidp->unp->name: " "));
947 lock_ObtainMutex(&uidp->mx);
948 uidp->flags |= SMB_USERFLAG_DELETE;
950 * it doesn't get deleted right away
951 * because the vcp points to it
954 lock_ReleaseMutex(&uidp->mx);
957 /* we can't do this. we get logoff messages prior to a session
958 * disconnect even though it doesn't mean the user is logging out.
959 * we need to create a new pioctl and EventLogoff handler to set
960 * SMB_USERNAMEFLAG_LOGOFF.
962 if (unp && smb_LogoffTokenTransfer) {
963 lock_ObtainMutex(&unp->mx);
964 unp->flags |= SMB_USERNAMEFLAG_LOGOFF;
965 unp->last_logoff_t = osi_Time() + smb_LogoffTransferTimeout;
966 lock_ReleaseMutex(&unp->mx);
970 smb_ReleaseUID(uidp);
973 osi_Log0(smb_logp, "SMB3 user logoffX");
975 smb_SetSMBDataLength(outp, 0);
979 #define SMB_SUPPORT_SEARCH_BITS 0x0001
980 #define SMB_SHARE_IS_IN_DFS 0x0002
982 long smb_ReceiveV3TreeConnectX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
985 smb_user_t *uidp = NULL;
986 unsigned short newTid;
994 cm_user_t *userp = NULL;
997 osi_Log0(smb_logp, "SMB3 receive tree connect");
999 /* parse input parameters */
1000 tp = smb_GetSMBData(inp, NULL);
1001 passwordp = smb_ParseString(tp, &tp);
1002 pathp = smb_ParseString(tp, &tp);
1003 if (smb_StoreAnsiFilenames)
1004 OemToChar(pathp,pathp);
1005 servicep = smb_ParseString(tp, &tp);
1007 tp = strrchr(pathp, '\\');
1009 return CM_ERROR_BADSMB;
1011 strcpy(shareName, tp+1);
1013 osi_Log2(smb_logp, "Tree connect pathp[%s] shareName[%s]",
1014 osi_LogSaveString(smb_logp, pathp),
1015 osi_LogSaveString(smb_logp, shareName));
1017 if (strcmp(servicep, "IPC") == 0 || strcmp(shareName, "IPC$") == 0) {
1019 osi_Log0(smb_logp, "TreeConnectX connecting to IPC$");
1022 return CM_ERROR_NOIPC;
1026 uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
1028 userp = smb_GetUserFromUID(uidp);
1030 lock_ObtainMutex(&vcp->mx);
1031 newTid = vcp->tidCounter++;
1032 lock_ReleaseMutex(&vcp->mx);
1034 tidp = smb_FindTID(vcp, newTid, SMB_FLAG_CREATE);
1037 if (!strcmp(shareName, "*."))
1038 strcpy(shareName, "all");
1039 shareFound = smb_FindShare(vcp, uidp, shareName, &sharePath);
1042 smb_ReleaseUID(uidp);
1043 smb_ReleaseTID(tidp);
1044 return CM_ERROR_BADSHARENAME;
1047 if (vcp->flags & SMB_VCFLAG_USENT)
1049 int policy = smb_FindShareCSCPolicy(shareName);
1050 smb_SetSMBParm(outp, 2, SMB_SUPPORT_SEARCH_BITS |
1052 SMB_SHARE_IS_IN_DFS |
1057 smb_SetSMBParm(outp, 2, 0);
1061 smb_ReleaseUID(uidp);
1063 lock_ObtainMutex(&tidp->mx);
1064 tidp->userp = userp;
1065 tidp->pathname = sharePath;
1067 tidp->flags |= SMB_TIDFLAG_IPC;
1068 lock_ReleaseMutex(&tidp->mx);
1069 smb_ReleaseTID(tidp);
1071 ((smb_t *)outp)->tid = newTid;
1072 ((smb_t *)inp)->tid = newTid;
1073 tp = smb_GetSMBData(outp, NULL);
1075 /* XXX - why is this a drive letter? */
1083 smb_SetSMBDataLength(outp, 7);
1086 smb_SetSMBDataLength(outp, 4);
1089 osi_Log1(smb_logp, "SMB3 tree connect created ID %d", newTid);
1093 /* must be called with global tran lock held */
1094 smb_tran2Packet_t *smb_FindTran2Packet(smb_vc_t *vcp, smb_packet_t *inp)
1096 smb_tran2Packet_t *tp;
1099 smbp = (smb_t *) inp->data;
1100 for (tp = smb_tran2AssemblyQueuep; tp; tp = (smb_tran2Packet_t *) osi_QNext(&tp->q)) {
1101 if (tp->vcp == vcp && tp->mid == smbp->mid && tp->tid == smbp->tid)
1107 smb_tran2Packet_t *smb_NewTran2Packet(smb_vc_t *vcp, smb_packet_t *inp,
1108 int totalParms, int totalData)
1110 smb_tran2Packet_t *tp;
1113 smbp = (smb_t *) inp->data;
1114 tp = malloc(sizeof(*tp));
1115 memset(tp, 0, sizeof(*tp));
1118 tp->curData = tp->curParms = 0;
1119 tp->totalData = totalData;
1120 tp->totalParms = totalParms;
1121 tp->tid = smbp->tid;
1122 tp->mid = smbp->mid;
1123 tp->uid = smbp->uid;
1124 tp->pid = smbp->pid;
1125 tp->res[0] = smbp->res[0];
1126 osi_QAdd((osi_queue_t **)&smb_tran2AssemblyQueuep, &tp->q);
1127 if (totalParms != 0)
1128 tp->parmsp = malloc(totalParms);
1130 tp->datap = malloc(totalData);
1131 if (smbp->com == 0x25 || smbp->com == 0x26)
1134 tp->opcode = smb_GetSMBParm(inp, 14);
1137 tp->flags |= SMB_TRAN2PFLAG_ALLOC;
1141 smb_tran2Packet_t *smb_GetTran2ResponsePacket(smb_vc_t *vcp,
1142 smb_tran2Packet_t *inp, smb_packet_t *outp,
1143 int totalParms, int totalData)
1145 smb_tran2Packet_t *tp;
1146 unsigned short parmOffset;
1147 unsigned short dataOffset;
1148 unsigned short dataAlign;
1150 tp = malloc(sizeof(*tp));
1151 memset(tp, 0, sizeof(*tp));
1154 tp->curData = tp->curParms = 0;
1155 tp->totalData = totalData;
1156 tp->totalParms = totalParms;
1157 tp->oldTotalParms = totalParms;
1162 tp->res[0] = inp->res[0];
1163 tp->opcode = inp->opcode;
1167 * We calculate where the parameters and data will start.
1168 * This calculation must parallel the calculation in
1169 * smb_SendTran2Packet.
1172 parmOffset = 10*2 + 35;
1173 parmOffset++; /* round to even */
1174 tp->parmsp = (unsigned short *) (outp->data + parmOffset);
1176 dataOffset = parmOffset + totalParms;
1177 dataAlign = dataOffset & 2; /* quad-align */
1178 dataOffset += dataAlign;
1179 tp->datap = outp->data + dataOffset;
1184 /* free a tran2 packet */
1185 void smb_FreeTran2Packet(smb_tran2Packet_t *t2p)
1188 smb_ReleaseVC(t2p->vcp);
1191 if (t2p->flags & SMB_TRAN2PFLAG_ALLOC) {
1200 /* called with a VC, an input packet to respond to, and an error code.
1201 * sends an error response.
1203 void smb_SendTran2Error(smb_vc_t *vcp, smb_tran2Packet_t *t2p,
1204 smb_packet_t *tp, long code)
1207 unsigned short errCode;
1208 unsigned char errClass;
1209 unsigned long NTStatus;
1211 if (vcp->flags & SMB_VCFLAG_STATUS32)
1212 smb_MapNTError(code, &NTStatus);
1214 smb_MapCoreError(code, vcp, &errCode, &errClass);
1216 smb_FormatResponsePacket(vcp, NULL, tp);
1217 smbp = (smb_t *) tp;
1219 /* We can handle long names */
1220 if (vcp->flags & SMB_VCFLAG_USENT)
1221 smbp->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
1223 /* now copy important fields from the tran 2 packet */
1224 smbp->com = t2p->com;
1225 smbp->tid = t2p->tid;
1226 smbp->mid = t2p->mid;
1227 smbp->pid = t2p->pid;
1228 smbp->uid = t2p->uid;
1229 smbp->res[0] = t2p->res[0];
1230 if (vcp->flags & SMB_VCFLAG_STATUS32) {
1231 smbp->rcls = (unsigned char) (NTStatus & 0xff);
1232 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
1233 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
1234 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
1235 smbp->flg2 |= SMB_FLAGS2_32BIT_STATUS;
1238 smbp->rcls = errClass;
1239 smbp->errLow = (unsigned char) (errCode & 0xff);
1240 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
1244 smb_SendPacket(vcp, tp);
1247 void smb_SendTran2Packet(smb_vc_t *vcp, smb_tran2Packet_t *t2p, smb_packet_t *tp)
1250 unsigned short parmOffset;
1251 unsigned short dataOffset;
1252 unsigned short totalLength;
1253 unsigned short dataAlign;
1256 smb_FormatResponsePacket(vcp, NULL, tp);
1257 smbp = (smb_t *) tp;
1259 /* We can handle long names */
1260 if (vcp->flags & SMB_VCFLAG_USENT)
1261 smbp->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
1263 /* now copy important fields from the tran 2 packet */
1264 smbp->com = t2p->com;
1265 smbp->tid = t2p->tid;
1266 smbp->mid = t2p->mid;
1267 smbp->pid = t2p->pid;
1268 smbp->uid = t2p->uid;
1269 smbp->res[0] = t2p->res[0];
1271 totalLength = 1 + t2p->totalData + t2p->totalParms;
1273 /* now add the core parameters (tran2 info) to the packet */
1274 smb_SetSMBParm(tp, 0, t2p->totalParms); /* parm bytes */
1275 smb_SetSMBParm(tp, 1, t2p->totalData); /* data bytes */
1276 smb_SetSMBParm(tp, 2, 0); /* reserved */
1277 smb_SetSMBParm(tp, 3, t2p->totalParms); /* parm bytes in this packet */
1278 parmOffset = 10*2 + 35; /* parm offset in packet */
1279 parmOffset++; /* round to even */
1280 smb_SetSMBParm(tp, 4, parmOffset); /* 11 parm words plus *
1281 * hdr, bcc and wct */
1282 smb_SetSMBParm(tp, 5, 0); /* parm displacement */
1283 smb_SetSMBParm(tp, 6, t2p->totalData); /* data in this packet */
1284 dataOffset = parmOffset + t2p->oldTotalParms;
1285 dataAlign = dataOffset & 2; /* quad-align */
1286 dataOffset += dataAlign;
1287 smb_SetSMBParm(tp, 7, dataOffset); /* offset of data */
1288 smb_SetSMBParm(tp, 8, 0); /* data displacement */
1289 smb_SetSMBParm(tp, 9, 0); /* low: setup word count *
1292 datap = smb_GetSMBData(tp, NULL);
1293 *datap++ = 0; /* we rounded to even */
1295 totalLength += dataAlign;
1296 smb_SetSMBDataLength(tp, totalLength);
1298 /* next, send the datagram */
1299 smb_SendPacket(vcp, tp);
1302 long smb_ReceiveV3Trans(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
1304 smb_tran2Packet_t *asp;
1317 /* We sometimes see 0 word count. What to do? */
1318 if (*inp->wctp == 0) {
1319 osi_Log0(smb_logp, "Transaction2 word count = 0");
1321 LogEvent(EVENTLOG_WARNING_TYPE, MSG_SMB_ZERO_TRANSACTION_COUNT);
1324 smb_SetSMBDataLength(outp, 0);
1325 smb_SendPacket(vcp, outp);
1329 totalParms = smb_GetSMBParm(inp, 0);
1330 totalData = smb_GetSMBParm(inp, 1);
1332 firstPacket = (inp->inCom == 0x25);
1334 /* find the packet we're reassembling */
1335 lock_ObtainWrite(&smb_globalLock);
1336 asp = smb_FindTran2Packet(vcp, inp);
1338 asp = smb_NewTran2Packet(vcp, inp, totalParms, totalData);
1340 lock_ReleaseWrite(&smb_globalLock);
1342 /* now merge in this latest packet; start by looking up offsets */
1344 parmDisp = dataDisp = 0;
1345 parmOffset = smb_GetSMBParm(inp, 10);
1346 dataOffset = smb_GetSMBParm(inp, 12);
1347 parmCount = smb_GetSMBParm(inp, 9);
1348 dataCount = smb_GetSMBParm(inp, 11);
1349 asp->maxReturnParms = smb_GetSMBParm(inp, 2);
1350 asp->maxReturnData = smb_GetSMBParm(inp, 3);
1352 osi_Log3(smb_logp, "SMB3 received Trans init packet total data %d, cur data %d, max return data %d",
1353 totalData, dataCount, asp->maxReturnData);
1356 parmDisp = smb_GetSMBParm(inp, 4);
1357 parmOffset = smb_GetSMBParm(inp, 3);
1358 dataDisp = smb_GetSMBParm(inp, 7);
1359 dataOffset = smb_GetSMBParm(inp, 6);
1360 parmCount = smb_GetSMBParm(inp, 2);
1361 dataCount = smb_GetSMBParm(inp, 5);
1363 osi_Log2(smb_logp, "SMB3 received Trans aux packet parms %d, data %d",
1364 parmCount, dataCount);
1367 /* now copy the parms and data */
1368 if ( asp->totalParms > 0 && parmCount != 0 )
1370 memcpy(((char *)asp->parmsp) + parmDisp, inp->data + parmOffset, parmCount);
1372 if ( asp->totalData > 0 && dataCount != 0 ) {
1373 memcpy(asp->datap + dataDisp, inp->data + dataOffset, dataCount);
1376 /* account for new bytes */
1377 asp->curData += dataCount;
1378 asp->curParms += parmCount;
1380 /* finally, if we're done, remove the packet from the queue and dispatch it */
1381 if (asp->totalParms > 0 &&
1382 asp->curParms > 0 &&
1383 asp->totalData <= asp->curData &&
1384 asp->totalParms <= asp->curParms) {
1385 /* we've received it all */
1386 lock_ObtainWrite(&smb_globalLock);
1387 osi_QRemove((osi_queue_t **) &smb_tran2AssemblyQueuep, &asp->q);
1388 lock_ReleaseWrite(&smb_globalLock);
1390 /* now dispatch it */
1391 rapOp = asp->parmsp[0];
1393 if ( rapOp >= 0 && rapOp < SMB_RAP_NOPCODES && smb_rapDispatchTable[rapOp].procp) {
1394 osi_Log4(smb_logp,"AFS Server - Dispatch-RAP %s vcp[%p] lana[%d] lsn[%d]",myCrt_RapDispatch(rapOp),vcp,vcp->lana,vcp->lsn);
1395 code = (*smb_rapDispatchTable[rapOp].procp)(vcp, asp, outp);
1396 osi_Log4(smb_logp,"AFS Server - Dispatch-RAP return code 0x%x vcp[%x] lana[%d] lsn[%d]",code,vcp,vcp->lana,vcp->lsn);
1399 osi_Log4(smb_logp,"AFS Server - Dispatch-RAP [INVALID] op[%x] vcp[%p] lana[%d] lsn[%d]", rapOp, vcp, vcp->lana, vcp->lsn);
1400 code = CM_ERROR_BADOP;
1403 /* if an error is returned, we're supposed to send an error packet,
1404 * otherwise the dispatched function already did the data sending.
1405 * We give dispatched proc the responsibility since it knows how much
1406 * space to allocate.
1409 smb_SendTran2Error(vcp, asp, outp, code);
1412 /* free the input tran 2 packet */
1413 smb_FreeTran2Packet(asp);
1415 else if (firstPacket) {
1416 /* the first packet in a multi-packet request, we need to send an
1417 * ack to get more data.
1419 smb_SetSMBDataLength(outp, 0);
1420 smb_SendPacket(vcp, outp);
1426 /* ANSI versions. The unicode versions support arbitrary length
1427 share names, but we don't support unicode yet. */
1429 typedef struct smb_rap_share_info_0 {
1430 char shi0_netname[13];
1431 } smb_rap_share_info_0_t;
1433 typedef struct smb_rap_share_info_1 {
1434 char shi1_netname[13];
1437 DWORD shi1_remark; /* char *shi1_remark; data offset */
1438 } smb_rap_share_info_1_t;
1440 typedef struct smb_rap_share_info_2 {
1441 char shi2_netname[13];
1443 unsigned short shi2_type;
1444 DWORD shi2_remark; /* char *shi2_remark; data offset */
1445 unsigned short shi2_permissions;
1446 unsigned short shi2_max_uses;
1447 unsigned short shi2_current_uses;
1448 DWORD shi2_path; /* char *shi2_path; data offset */
1449 unsigned short shi2_passwd[9];
1450 unsigned short shi2_pad2;
1451 } smb_rap_share_info_2_t;
1453 #define SMB_RAP_MAX_SHARES 512
1455 typedef struct smb_rap_share_list {
1458 smb_rap_share_info_0_t * shares;
1459 } smb_rap_share_list_t;
1461 int smb_rapCollectSharesProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp) {
1462 smb_rap_share_list_t * sp;
1467 if (name[0] == '.' && (!name[1] || (name[1] == '.' && !name[2])))
1468 return 0; /* skip over '.' and '..' */
1470 sp = (smb_rap_share_list_t *) vrockp;
1472 strncpy(sp->shares[sp->cShare].shi0_netname, name, 12);
1473 sp->shares[sp->cShare].shi0_netname[12] = 0;
1477 if (sp->cShare >= sp->maxShares)
1478 return CM_ERROR_STOPNOW;
1483 long smb_ReceiveRAPNetShareEnum(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1485 smb_tran2Packet_t *outp;
1486 unsigned short * tp;
1490 int outParmsTotal; /* total parameter bytes */
1491 int outDataTotal; /* total data bytes */
1494 DWORD allSubmount = 0;
1496 DWORD nRegShares = 0;
1497 DWORD nSharesRet = 0;
1499 HKEY hkSubmount = NULL;
1500 smb_rap_share_info_1_t * shares;
1503 char thisShare[256];
1506 smb_rap_share_list_t rootShares;
1511 tp = p->parmsp + 1; /* skip over function number (always 0) */
1512 (void) smb_ParseString((char *) tp, (char **) &tp); /* skip over parm descriptor */
1513 (void) smb_ParseString((char *) tp, (char **) &tp); /* skip over data descriptor */
1517 if (infoLevel != 1) {
1518 return CM_ERROR_INVAL;
1521 /* first figure out how many shares there are */
1522 rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY, 0,
1523 KEY_QUERY_VALUE, &hkParam);
1524 if (rv == ERROR_SUCCESS) {
1525 len = sizeof(allSubmount);
1526 rv = RegQueryValueEx(hkParam, "AllSubmount", NULL, NULL,
1527 (BYTE *) &allSubmount, &len);
1528 if (rv != ERROR_SUCCESS || allSubmount != 0) {
1531 RegCloseKey (hkParam);
1534 rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_OPENAFS_SUBKEY "\\Submounts",
1535 0, KEY_QUERY_VALUE, &hkSubmount);
1536 if (rv == ERROR_SUCCESS) {
1537 rv = RegQueryInfoKey(hkSubmount, NULL, NULL, NULL, NULL,
1538 NULL, NULL, &nRegShares, NULL, NULL, NULL, NULL);
1539 if (rv != ERROR_SUCCESS)
1545 /* fetch the root shares */
1546 rootShares.maxShares = SMB_RAP_MAX_SHARES;
1547 rootShares.cShare = 0;
1548 rootShares.shares = malloc( sizeof(smb_rap_share_info_0_t) * SMB_RAP_MAX_SHARES );
1552 userp = smb_GetTran2User(vcp,p);
1554 thyper.HighPart = 0;
1557 cm_HoldSCache(cm_data.rootSCachep);
1558 cm_ApplyDir(cm_data.rootSCachep, smb_rapCollectSharesProc, &rootShares, &thyper, userp, &req, NULL);
1559 cm_ReleaseSCache(cm_data.rootSCachep);
1561 cm_ReleaseUser(userp);
1563 nShares = (USHORT)(rootShares.cShare + nRegShares + allSubmount);
1565 #define REMARK_LEN 1
1566 outParmsTotal = 8; /* 4 dwords */
1567 outDataTotal = (sizeof(smb_rap_share_info_1_t) + REMARK_LEN) * nShares ;
1568 if(outDataTotal > bufsize) {
1569 nSharesRet = bufsize / (sizeof(smb_rap_share_info_1_t) + REMARK_LEN);
1570 outDataTotal = (sizeof(smb_rap_share_info_1_t) + REMARK_LEN) * nSharesRet;
1573 nSharesRet = nShares;
1576 outp = smb_GetTran2ResponsePacket(vcp, p, op, outParmsTotal, outDataTotal);
1578 /* now for the submounts */
1579 shares = (smb_rap_share_info_1_t *) outp->datap;
1580 cstrp = outp->datap + sizeof(smb_rap_share_info_1_t) * nSharesRet;
1582 memset(outp->datap, 0, (sizeof(smb_rap_share_info_1_t) + REMARK_LEN) * nSharesRet);
1585 strcpy( shares[cshare].shi1_netname, "all" );
1586 shares[cshare].shi1_remark = (DWORD)(cstrp - outp->datap);
1587 /* type and pad are zero already */
1593 for (i=0; i < nRegShares && cshare < nSharesRet; i++) {
1594 len = sizeof(thisShare);
1595 rv = RegEnumValue(hkSubmount, i, thisShare, &len, NULL, NULL, NULL, NULL);
1596 if (rv == ERROR_SUCCESS && strlen(thisShare) && (!allSubmount || stricmp(thisShare,"all"))) {
1597 strncpy(shares[cshare].shi1_netname, thisShare, sizeof(shares->shi1_netname)-1);
1598 shares[cshare].shi1_netname[sizeof(shares->shi1_netname)-1] = 0; /* unfortunate truncation */
1599 shares[cshare].shi1_remark = (DWORD)(cstrp - outp->datap);
1604 nShares--; /* uncount key */
1607 RegCloseKey(hkSubmount);
1610 nonrootShares = cshare;
1612 for (i=0; i < rootShares.cShare && cshare < nSharesRet; i++) {
1613 /* in case there are collisions with submounts, submounts have higher priority */
1614 for (j=0; j < nonrootShares; j++)
1615 if (!stricmp(shares[j].shi1_netname, rootShares.shares[i].shi0_netname))
1618 if (j < nonrootShares) {
1619 nShares--; /* uncount */
1623 strcpy(shares[cshare].shi1_netname, rootShares.shares[i].shi0_netname);
1624 shares[cshare].shi1_remark = (DWORD)(cstrp - outp->datap);
1629 outp->parmsp[0] = ((cshare == nShares)? ERROR_SUCCESS : ERROR_MORE_DATA);
1630 outp->parmsp[1] = 0;
1631 outp->parmsp[2] = cshare;
1632 outp->parmsp[3] = nShares;
1634 outp->totalData = (int)(cstrp - outp->datap);
1635 outp->totalParms = outParmsTotal;
1637 smb_SendTran2Packet(vcp, outp, op);
1638 smb_FreeTran2Packet(outp);
1640 free(rootShares.shares);
1645 long smb_ReceiveRAPNetShareGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1647 smb_tran2Packet_t *outp;
1648 unsigned short * tp;
1650 BOOL shareFound = FALSE;
1651 unsigned short infoLevel;
1652 unsigned short bufsize;
1662 tp = p->parmsp + 1; /* skip over function number (always 1) */
1663 (void) smb_ParseString( (char *) tp, (char **) &tp); /* skip over param descriptor */
1664 (void) smb_ParseString( (char *) tp, (char **) &tp); /* skip over data descriptor */
1665 shareName = smb_ParseString( (char *) tp, (char **) &tp);
1672 totalData = sizeof(smb_rap_share_info_0_t);
1673 else if(infoLevel == SMB_INFO_STANDARD)
1674 totalData = sizeof(smb_rap_share_info_1_t) + 1; /* + empty string */
1675 else if(infoLevel == SMB_INFO_QUERY_EA_SIZE)
1676 totalData = sizeof(smb_rap_share_info_2_t) + 2; /* + two empty strings */
1678 return CM_ERROR_INVAL;
1680 outp = smb_GetTran2ResponsePacket(vcp, p, op, totalParam, totalData);
1682 if(!stricmp(shareName,"all") || !strcmp(shareName,"*.")) {
1683 rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY, 0,
1684 KEY_QUERY_VALUE, &hkParam);
1685 if (rv == ERROR_SUCCESS) {
1686 len = sizeof(allSubmount);
1687 rv = RegQueryValueEx(hkParam, "AllSubmount", NULL, NULL,
1688 (BYTE *) &allSubmount, &len);
1689 if (rv != ERROR_SUCCESS || allSubmount != 0) {
1692 RegCloseKey (hkParam);
1699 rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY "\\Submounts", 0,
1700 KEY_QUERY_VALUE, &hkSubmount);
1701 if (rv == ERROR_SUCCESS) {
1702 rv = RegQueryValueEx(hkSubmount, shareName, NULL, NULL, NULL, NULL);
1703 if (rv == ERROR_SUCCESS) {
1706 RegCloseKey(hkSubmount);
1711 smb_FreeTran2Packet(outp);
1712 return CM_ERROR_BADSHARENAME;
1715 memset(outp->datap, 0, totalData);
1717 outp->parmsp[0] = 0;
1718 outp->parmsp[1] = 0;
1719 outp->parmsp[2] = totalData;
1721 if (infoLevel == 0) {
1722 smb_rap_share_info_0_t * info = (smb_rap_share_info_0_t *) outp->datap;
1723 strncpy(info->shi0_netname, shareName, sizeof(info->shi0_netname)-1);
1724 info->shi0_netname[sizeof(info->shi0_netname)-1] = 0;
1725 } else if(infoLevel == SMB_INFO_STANDARD) {
1726 smb_rap_share_info_1_t * info = (smb_rap_share_info_1_t *) outp->datap;
1727 strncpy(info->shi1_netname, shareName, sizeof(info->shi1_netname)-1);
1728 info->shi1_netname[sizeof(info->shi1_netname)-1] = 0;
1729 info->shi1_remark = (DWORD)(((unsigned char *) (info + 1)) - outp->datap);
1730 /* type and pad are already zero */
1731 } else { /* infoLevel==2 */
1732 smb_rap_share_info_2_t * info = (smb_rap_share_info_2_t *) outp->datap;
1733 strncpy(info->shi2_netname, shareName, sizeof(info->shi2_netname)-1);
1734 info->shi2_netname[sizeof(info->shi2_netname)-1] = 0;
1735 info->shi2_remark = (DWORD)(((unsigned char *) (info + 1)) - outp->datap);
1736 info->shi2_permissions = ACCESS_ALL;
1737 info->shi2_max_uses = (unsigned short) -1;
1738 info->shi2_path = (DWORD)(1 + (((unsigned char *) (info + 1)) - outp->datap));
1741 outp->totalData = totalData;
1742 outp->totalParms = totalParam;
1744 smb_SendTran2Packet(vcp, outp, op);
1745 smb_FreeTran2Packet(outp);
1750 typedef struct smb_rap_wksta_info_10 {
1751 DWORD wki10_computername; /*char *wki10_computername;*/
1752 DWORD wki10_username; /* char *wki10_username; */
1753 DWORD wki10_langroup; /* char *wki10_langroup;*/
1754 unsigned char wki10_ver_major;
1755 unsigned char wki10_ver_minor;
1756 DWORD wki10_logon_domain; /*char *wki10_logon_domain;*/
1757 DWORD wki10_oth_domains; /* char *wki10_oth_domains;*/
1758 } smb_rap_wksta_info_10_t;
1761 long smb_ReceiveRAPNetWkstaGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1763 smb_tran2Packet_t *outp;
1767 unsigned short * tp;
1770 smb_rap_wksta_info_10_t * info;
1774 tp = p->parmsp + 1; /* Skip over function number */
1775 (void) smb_ParseString((unsigned char*) tp, (char **) &tp); /* skip over param descriptor */
1776 (void) smb_ParseString((unsigned char*) tp, (char **) &tp); /* skip over data descriptor */
1780 if (infoLevel != 10) {
1781 return CM_ERROR_INVAL;
1787 totalData = sizeof(*info) + /* info */
1788 MAX_COMPUTERNAME_LENGTH + /* wki10_computername */
1789 SMB_MAX_USERNAME_LENGTH + /* wki10_username */
1790 MAX_COMPUTERNAME_LENGTH + /* wki10_langroup */
1791 MAX_COMPUTERNAME_LENGTH + /* wki10_logon_domain */
1792 1; /* wki10_oth_domains (null)*/
1794 outp = smb_GetTran2ResponsePacket(vcp, p, op, totalParams, totalData);
1796 memset(outp->parmsp,0,totalParams);
1797 memset(outp->datap,0,totalData);
1799 info = (smb_rap_wksta_info_10_t *) outp->datap;
1800 cstrp = (char *) (info + 1);
1802 info->wki10_computername = (DWORD) (cstrp - outp->datap);
1803 strcpy(cstrp, smb_localNamep);
1804 cstrp += strlen(cstrp) + 1;
1806 info->wki10_username = (DWORD) (cstrp - outp->datap);
1807 uidp = smb_FindUID(vcp, p->uid, 0);
1809 lock_ObtainMutex(&uidp->mx);
1810 if(uidp->unp && uidp->unp->name)
1811 strcpy(cstrp, uidp->unp->name);
1812 lock_ReleaseMutex(&uidp->mx);
1813 smb_ReleaseUID(uidp);
1815 cstrp += strlen(cstrp) + 1;
1817 info->wki10_langroup = (DWORD) (cstrp - outp->datap);
1818 strcpy(cstrp, "WORKGROUP");
1819 cstrp += strlen(cstrp) + 1;
1821 /* TODO: Not sure what values these should take, but these work */
1822 info->wki10_ver_major = 5;
1823 info->wki10_ver_minor = 1;
1825 info->wki10_logon_domain = (DWORD) (cstrp - outp->datap);
1826 strcpy(cstrp, smb_ServerDomainName);
1827 cstrp += strlen(cstrp) + 1;
1829 info->wki10_oth_domains = (DWORD) (cstrp - outp->datap);
1830 cstrp ++; /* no other domains */
1832 outp->totalData = (unsigned short) (cstrp - outp->datap); /* actual data size */
1833 outp->parmsp[2] = outp->totalData;
1834 outp->totalParms = totalParams;
1836 smb_SendTran2Packet(vcp,outp,op);
1837 smb_FreeTran2Packet(outp);
1842 typedef struct smb_rap_server_info_0 {
1844 } smb_rap_server_info_0_t;
1846 typedef struct smb_rap_server_info_1 {
1848 char sv1_version_major;
1849 char sv1_version_minor;
1850 unsigned long sv1_type;
1851 DWORD *sv1_comment_or_master_browser; /* char *sv1_comment_or_master_browser;*/
1852 } smb_rap_server_info_1_t;
1854 char smb_ServerComment[] = "OpenAFS Client";
1855 int smb_ServerCommentLen = sizeof(smb_ServerComment);
1857 #define SMB_SV_TYPE_SERVER 0x00000002L
1858 #define SMB_SV_TYPE_NT 0x00001000L
1859 #define SMB_SV_TYPE_SERVER_NT 0x00008000L
1861 long smb_ReceiveRAPNetServerGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1863 smb_tran2Packet_t *outp;
1867 unsigned short * tp;
1870 smb_rap_server_info_0_t * info0;
1871 smb_rap_server_info_1_t * info1;
1874 tp = p->parmsp + 1; /* Skip over function number */
1875 (void) smb_ParseString((unsigned char*) tp, (char **) &tp); /* skip over param descriptor */
1876 (void) smb_ParseString((unsigned char*) tp, (char **) &tp); /* skip over data descriptor */
1880 if (infoLevel != 0 && infoLevel != 1) {
1881 return CM_ERROR_INVAL;
1887 (infoLevel == 0) ? sizeof(smb_rap_server_info_0_t)
1888 : (sizeof(smb_rap_server_info_1_t) + smb_ServerCommentLen);
1890 outp = smb_GetTran2ResponsePacket(vcp, p, op, totalParams, totalData);
1892 memset(outp->parmsp,0,totalParams);
1893 memset(outp->datap,0,totalData);
1895 if (infoLevel == 0) {
1896 info0 = (smb_rap_server_info_0_t *) outp->datap;
1897 cstrp = (char *) (info0 + 1);
1898 strcpy(info0->sv0_name, "AFS");
1899 } else { /* infoLevel == SMB_INFO_STANDARD */
1900 info1 = (smb_rap_server_info_1_t *) outp->datap;
1901 cstrp = (char *) (info1 + 1);
1902 strcpy(info1->sv1_name, "AFS");
1905 SMB_SV_TYPE_SERVER |
1907 SMB_SV_TYPE_SERVER_NT;
1909 info1->sv1_version_major = 5;
1910 info1->sv1_version_minor = 1;
1911 info1->sv1_comment_or_master_browser = (DWORD *) (cstrp - outp->datap);
1913 strcpy(cstrp, smb_ServerComment);
1915 cstrp += smb_ServerCommentLen;
1918 totalData = (DWORD)(cstrp - outp->datap);
1919 outp->totalData = min(bufsize,totalData); /* actual data size */
1920 outp->parmsp[0] = (outp->totalData == totalData)? 0 : ERROR_MORE_DATA;
1921 outp->parmsp[2] = totalData;
1922 outp->totalParms = totalParams;
1924 smb_SendTran2Packet(vcp,outp,op);
1925 smb_FreeTran2Packet(outp);
1930 long smb_ReceiveV3Tran2A(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
1932 smb_tran2Packet_t *asp;
1944 /* We sometimes see 0 word count. What to do? */
1945 if (*inp->wctp == 0) {
1946 osi_Log0(smb_logp, "Transaction2 word count = 0");
1948 LogEvent(EVENTLOG_WARNING_TYPE, MSG_SMB_ZERO_TRANSACTION_COUNT);
1951 smb_SetSMBDataLength(outp, 0);
1952 smb_SendPacket(vcp, outp);
1956 totalParms = smb_GetSMBParm(inp, 0);
1957 totalData = smb_GetSMBParm(inp, 1);
1959 firstPacket = (inp->inCom == 0x32);
1961 /* find the packet we're reassembling */
1962 lock_ObtainWrite(&smb_globalLock);
1963 asp = smb_FindTran2Packet(vcp, inp);
1965 asp = smb_NewTran2Packet(vcp, inp, totalParms, totalData);
1967 lock_ReleaseWrite(&smb_globalLock);
1969 /* now merge in this latest packet; start by looking up offsets */
1971 parmDisp = dataDisp = 0;
1972 parmOffset = smb_GetSMBParm(inp, 10);
1973 dataOffset = smb_GetSMBParm(inp, 12);
1974 parmCount = smb_GetSMBParm(inp, 9);
1975 dataCount = smb_GetSMBParm(inp, 11);
1976 asp->maxReturnParms = smb_GetSMBParm(inp, 2);
1977 asp->maxReturnData = smb_GetSMBParm(inp, 3);
1979 osi_Log3(smb_logp, "SMB3 received T2 init packet total data %d, cur data %d, max return data %d",
1980 totalData, dataCount, asp->maxReturnData);
1983 parmDisp = smb_GetSMBParm(inp, 4);
1984 parmOffset = smb_GetSMBParm(inp, 3);
1985 dataDisp = smb_GetSMBParm(inp, 7);
1986 dataOffset = smb_GetSMBParm(inp, 6);
1987 parmCount = smb_GetSMBParm(inp, 2);
1988 dataCount = smb_GetSMBParm(inp, 5);
1990 osi_Log2(smb_logp, "SMB3 received T2 aux packet parms %d, data %d",
1991 parmCount, dataCount);
1994 /* now copy the parms and data */
1995 if ( asp->totalParms > 0 && parmCount != 0 )
1997 memcpy(((char *)asp->parmsp) + parmDisp, inp->data + parmOffset, parmCount);
1999 if ( asp->totalData > 0 && dataCount != 0 ) {
2000 memcpy(asp->datap + dataDisp, inp->data + dataOffset, dataCount);
2003 /* account for new bytes */
2004 asp->curData += dataCount;
2005 asp->curParms += parmCount;
2007 /* finally, if we're done, remove the packet from the queue and dispatch it */
2008 if (asp->totalParms > 0 &&
2009 asp->curParms > 0 &&
2010 asp->totalData <= asp->curData &&
2011 asp->totalParms <= asp->curParms) {
2012 /* we've received it all */
2013 lock_ObtainWrite(&smb_globalLock);
2014 osi_QRemove((osi_queue_t **) &smb_tran2AssemblyQueuep, &asp->q);
2015 lock_ReleaseWrite(&smb_globalLock);
2017 /* now dispatch it */
2018 if ( asp->opcode >= 0 && asp->opcode < 20 && smb_tran2DispatchTable[asp->opcode].procp) {
2019 osi_Log4(smb_logp,"AFS Server - Dispatch-2 %s vcp[%p] lana[%d] lsn[%d]",myCrt_2Dispatch(asp->opcode),vcp,vcp->lana,vcp->lsn);
2020 code = (*smb_tran2DispatchTable[asp->opcode].procp)(vcp, asp, outp);
2023 osi_Log4(smb_logp,"AFS Server - Dispatch-2 [INVALID] op[%x] vcp[%p] lana[%d] lsn[%d]", asp->opcode, vcp, vcp->lana, vcp->lsn);
2024 code = CM_ERROR_BADOP;
2027 /* if an error is returned, we're supposed to send an error packet,
2028 * otherwise the dispatched function already did the data sending.
2029 * We give dispatched proc the responsibility since it knows how much
2030 * space to allocate.
2033 smb_SendTran2Error(vcp, asp, outp, code);
2036 /* free the input tran 2 packet */
2037 smb_FreeTran2Packet(asp);
2039 else if (firstPacket) {
2040 /* the first packet in a multi-packet request, we need to send an
2041 * ack to get more data.
2043 smb_SetSMBDataLength(outp, 0);
2044 smb_SendPacket(vcp, outp);
2050 long smb_ReceiveTran2Open(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
2053 smb_tran2Packet_t *outp;
2058 cm_scache_t *dscp; /* dir we're dealing with */
2059 cm_scache_t *scp; /* file we're creating */
2061 int initialModeBits;
2071 int parmSlot; /* which parm we're dealing with */
2072 long returnEALength;
2081 extraInfo = (p->parmsp[0] & 1); /* return extra info */
2082 returnEALength = (p->parmsp[0] & 8); /* return extended attr length */
2084 openFun = p->parmsp[6]; /* open function */
2085 excl = ((openFun & 3) == 0);
2086 trunc = ((openFun & 3) == 2); /* truncate it */
2087 openMode = (p->parmsp[1] & 0x7);
2088 openAction = 0; /* tracks what we did */
2090 attributes = p->parmsp[3];
2091 dosTime = p->parmsp[4] | (p->parmsp[5] << 16);
2093 /* compute initial mode bits based on read-only flag in attributes */
2094 initialModeBits = 0666;
2095 if (attributes & SMB_ATTR_READONLY)
2096 initialModeBits &= ~0222;
2098 pathp = (char *) (&p->parmsp[14]);
2099 if (smb_StoreAnsiFilenames)
2100 OemToChar(pathp,pathp);
2102 outp = smb_GetTran2ResponsePacket(vcp, p, op, 40, 0);
2104 spacep = cm_GetSpace();
2105 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
2107 if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
2108 /* special case magic file name for receiving IOCTL requests
2109 * (since IOCTL calls themselves aren't getting through).
2111 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
2112 smb_SetupIoctlFid(fidp, spacep);
2114 /* copy out remainder of the parms */
2116 outp->parmsp[parmSlot++] = fidp->fid;
2118 outp->parmsp[parmSlot++] = 0; /* attrs */
2119 outp->parmsp[parmSlot++] = 0; /* mod time */
2120 outp->parmsp[parmSlot++] = 0;
2121 outp->parmsp[parmSlot++] = 0; /* len */
2122 outp->parmsp[parmSlot++] = 0x7fff;
2123 outp->parmsp[parmSlot++] = openMode;
2124 outp->parmsp[parmSlot++] = 0; /* file type 0 ==> normal file or dir */
2125 outp->parmsp[parmSlot++] = 0; /* IPC junk */
2127 /* and the final "always present" stuff */
2128 outp->parmsp[parmSlot++] = 1; /* openAction found existing file */
2129 /* next write out the "unique" ID */
2130 outp->parmsp[parmSlot++] = 0x1234;
2131 outp->parmsp[parmSlot++] = 0x5678;
2132 outp->parmsp[parmSlot++] = 0;
2133 if (returnEALength) {
2134 outp->parmsp[parmSlot++] = 0;
2135 outp->parmsp[parmSlot++] = 0;
2138 outp->totalData = 0;
2139 outp->totalParms = parmSlot * 2;
2141 smb_SendTran2Packet(vcp, outp, op);
2143 smb_FreeTran2Packet(outp);
2145 /* and clean up fid reference */
2146 smb_ReleaseFID(fidp);
2150 #ifdef DEBUG_VERBOSE
2152 char *hexp, *asciip;
2153 asciip = (lastNamep ? lastNamep : pathp);
2154 hexp = osi_HexifyString( asciip );
2155 DEBUG_EVENT2("AFS","T2Open H[%s] A[%s]", hexp, asciip);
2160 userp = smb_GetTran2User(vcp, p);
2161 /* In the off chance that userp is NULL, we log and abandon */
2163 osi_Log1(smb_logp, "ReceiveTran2Open user [%d] not resolvable", p->uid);
2164 smb_FreeTran2Packet(outp);
2165 return CM_ERROR_BADSMB;
2168 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
2169 if (code == CM_ERROR_TIDIPC) {
2170 /* Attempt to use a TID allocated for IPC. The client
2171 * is probably looking for DCE RPC end points which we
2172 * don't support OR it could be looking to make a DFS
2175 osi_Log0(smb_logp, "Tran2Open received IPC TID");
2177 cm_ReleaseUser(userp);
2178 smb_FreeTran2Packet(outp);
2179 return CM_ERROR_NOSUCHPATH;
2184 code = cm_NameI(cm_data.rootSCachep, pathp,
2185 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
2186 userp, tidPathp, &req, &scp);
2188 code = cm_NameI(cm_data.rootSCachep, spacep->data,
2189 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
2190 userp, tidPathp, &req, &dscp);
2191 cm_FreeSpace(spacep);
2194 cm_ReleaseUser(userp);
2195 smb_FreeTran2Packet(outp);
2200 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
2201 cm_ReleaseSCache(dscp);
2202 cm_ReleaseUser(userp);
2203 smb_FreeTran2Packet(outp);
2204 if ( WANTS_DFS_PATHNAMES(p) )
2205 return CM_ERROR_PATH_NOT_COVERED;
2207 return CM_ERROR_BADSHARENAME;
2209 #endif /* DFS_SUPPORT */
2211 /* otherwise, scp points to the parent directory. Do a lookup,
2212 * and truncate the file if we find it, otherwise we create the
2219 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD, userp,
2221 if (code && code != CM_ERROR_NOSUCHFILE) {
2222 cm_ReleaseSCache(dscp);
2223 cm_ReleaseUser(userp);
2224 smb_FreeTran2Packet(outp);
2229 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
2230 cm_ReleaseSCache(scp);
2231 cm_ReleaseUser(userp);
2232 smb_FreeTran2Packet(outp);
2233 if ( WANTS_DFS_PATHNAMES(p) )
2234 return CM_ERROR_PATH_NOT_COVERED;
2236 return CM_ERROR_BADSHARENAME;
2238 #endif /* DFS_SUPPORT */
2240 /* macintosh is expensive to program for it */
2241 cm_FreeSpace(spacep);
2244 /* if we get here, if code is 0, the file exists and is represented by
2245 * scp. Otherwise, we have to create it.
2248 code = cm_CheckOpen(scp, openMode, trunc, userp, &req);
2251 cm_ReleaseSCache(dscp);
2252 cm_ReleaseSCache(scp);
2253 cm_ReleaseUser(userp);
2254 smb_FreeTran2Packet(outp);
2259 /* oops, file shouldn't be there */
2261 cm_ReleaseSCache(dscp);
2262 cm_ReleaseSCache(scp);
2263 cm_ReleaseUser(userp);
2264 smb_FreeTran2Packet(outp);
2265 return CM_ERROR_EXISTS;
2269 setAttr.mask = CM_ATTRMASK_LENGTH;
2270 setAttr.length.LowPart = 0;
2271 setAttr.length.HighPart = 0;
2272 code = cm_SetAttr(scp, &setAttr, userp, &req);
2273 openAction = 3; /* truncated existing file */
2276 openAction = 1; /* found existing file */
2278 else if (!(openFun & 0x10)) {
2279 /* don't create if not found */
2281 cm_ReleaseSCache(dscp);
2282 osi_assert(scp == NULL);
2283 cm_ReleaseUser(userp);
2284 smb_FreeTran2Packet(outp);
2285 return CM_ERROR_NOSUCHFILE;
2288 osi_assert(dscp != NULL && scp == NULL);
2289 openAction = 2; /* created file */
2290 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
2291 smb_UnixTimeFromSearchTime(&setAttr.clientModTime, dosTime);
2292 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
2296 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
2297 smb_NotifyChange(FILE_ACTION_ADDED,
2298 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
2299 dscp, lastNamep, NULL, TRUE);
2300 } else if (!excl && code == CM_ERROR_EXISTS) {
2301 /* not an exclusive create, and someone else tried
2302 * creating it already, then we open it anyway. We
2303 * don't bother retrying after this, since if this next
2304 * fails, that means that the file was deleted after we
2305 * started this call.
2307 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
2311 setAttr.mask = CM_ATTRMASK_LENGTH;
2312 setAttr.length.LowPart = 0;
2313 setAttr.length.HighPart = 0;
2314 code = cm_SetAttr(scp, &setAttr, userp,
2317 } /* lookup succeeded */
2321 /* we don't need this any longer */
2323 cm_ReleaseSCache(dscp);
2326 /* something went wrong creating or truncating the file */
2328 cm_ReleaseSCache(scp);
2329 cm_ReleaseUser(userp);
2330 smb_FreeTran2Packet(outp);
2334 /* make sure we're about to open a file */
2335 if (scp->fileType != CM_SCACHETYPE_FILE) {
2337 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
2338 cm_scache_t * targetScp = 0;
2339 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
2341 /* we have a more accurate file to use (the
2342 * target of the symbolic link). Otherwise,
2343 * we'll just use the symlink anyway.
2345 osi_Log2(smb_logp, "symlink vp %x to vp %x",
2347 cm_ReleaseSCache(scp);
2351 if (scp->fileType != CM_SCACHETYPE_FILE) {
2352 cm_ReleaseSCache(scp);
2353 cm_ReleaseUser(userp);
2354 smb_FreeTran2Packet(outp);
2355 return CM_ERROR_ISDIR;
2359 /* now all we have to do is open the file itself */
2360 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
2364 lock_ObtainMutex(&fidp->mx);
2365 /* save a pointer to the vnode */
2368 fidp->userp = userp;
2370 /* compute open mode */
2372 fidp->flags |= SMB_FID_OPENREAD;
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_ReceiveTran2FindFirst(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
2426 osi_Log0(smb_logp,"ReceiveTran2FindFirst - NOT_SUPPORTED");
2427 return CM_ERROR_BADOP;
2430 long smb_ReceiveTran2FindNext(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
2432 osi_Log0(smb_logp,"ReceiveTran2FindNext - NOT_SUPPORTED");
2433 return CM_ERROR_BADOP;
2436 long smb_ReceiveTran2QFSInfoFid(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
2439 unsigned short infolevel;
2441 infolevel = p->parmsp[0];
2443 osi_Log2(smb_logp, "T2 QFSInfoFid InfoLevel 0x%x fid 0x%x - NOT_SUPPORTED", infolevel, fid);
2445 return CM_ERROR_BADOP;
2448 long smb_ReceiveTran2QFSInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
2450 smb_tran2Packet_t *outp;
2451 smb_tran2QFSInfo_t qi;
2453 static char FSname[8] = {'A', 0, 'F', 0, 'S', 0, 0, 0};
2455 osi_Log1(smb_logp, "T2 QFSInfo type 0x%x", p->parmsp[0]);
2457 switch (p->parmsp[0]) {
2458 case SMB_INFO_ALLOCATION:
2459 responseSize = sizeof(qi.u.allocInfo);
2461 case SMB_INFO_VOLUME:
2462 responseSize = sizeof(qi.u.volumeInfo);
2464 case SMB_QUERY_FS_VOLUME_INFO:
2465 responseSize = sizeof(qi.u.FSvolumeInfo);
2467 case SMB_QUERY_FS_SIZE_INFO:
2468 responseSize = sizeof(qi.u.FSsizeInfo);
2470 case SMB_QUERY_FS_DEVICE_INFO:
2471 responseSize = sizeof(qi.u.FSdeviceInfo);
2473 case SMB_QUERY_FS_ATTRIBUTE_INFO:
2474 responseSize = sizeof(qi.u.FSattributeInfo);
2476 case SMB_INFO_UNIX: /* CIFS Unix Info */
2477 case SMB_INFO_MACOS: /* Mac FS Info */
2479 return CM_ERROR_BADOP;
2482 outp = smb_GetTran2ResponsePacket(vcp, p, op, 0, responseSize);
2483 switch (p->parmsp[0]) {
2484 case SMB_INFO_ALLOCATION:
2486 qi.u.allocInfo.FSID = 0;
2487 qi.u.allocInfo.sectorsPerAllocUnit = 1;
2488 qi.u.allocInfo.totalAllocUnits = 0x7fffffff;
2489 qi.u.allocInfo.availAllocUnits = 0x3fffffff;
2490 qi.u.allocInfo.bytesPerSector = 1024;
2493 case SMB_INFO_VOLUME:
2495 qi.u.volumeInfo.vsn = 1234;
2496 qi.u.volumeInfo.vnCount = 4;
2497 /* we're supposed to pad it out with zeroes to the end */
2498 memset(&qi.u.volumeInfo.label, 0, sizeof(qi.u.volumeInfo.label));
2499 memcpy(qi.u.volumeInfo.label, "AFS", 4);
2502 case SMB_QUERY_FS_VOLUME_INFO:
2503 /* FS volume info */
2504 memset((char *)&qi.u.FSvolumeInfo.vct, 0, 4);
2505 qi.u.FSvolumeInfo.vsn = 1234;
2506 qi.u.FSvolumeInfo.vnCount = 8;
2507 memcpy(qi.u.FSvolumeInfo.label, "A\0F\0S\0\0\0", 8);
2510 case SMB_QUERY_FS_SIZE_INFO:
2512 qi.u.FSsizeInfo.totalAllocUnits.HighPart = 0;
2513 qi.u.FSsizeInfo.totalAllocUnits.LowPart= 0x7fffffff;
2514 qi.u.FSsizeInfo.availAllocUnits.HighPart = 0;
2515 qi.u.FSsizeInfo.availAllocUnits.LowPart= 0x3fffffff;
2516 qi.u.FSsizeInfo.sectorsPerAllocUnit = 1;
2517 qi.u.FSsizeInfo.bytesPerSector = 1024;
2520 case SMB_QUERY_FS_DEVICE_INFO:
2521 /* FS device info */
2522 qi.u.FSdeviceInfo.devType = 0x14; /* network file system */
2523 qi.u.FSdeviceInfo.characteristics = 0x50; /* remote, virtual */
2526 case SMB_QUERY_FS_ATTRIBUTE_INFO:
2527 /* FS attribute info */
2528 /* attributes, defined in WINNT.H:
2529 * FILE_CASE_SENSITIVE_SEARCH 0x1
2530 * FILE_CASE_PRESERVED_NAMES 0x2
2531 * FILE_VOLUME_QUOTAS 0x10
2532 * <no name defined> 0x4000
2533 * If bit 0x4000 is not set, Windows 95 thinks
2534 * we can't handle long (non-8.3) names,
2535 * despite our protestations to the contrary.
2537 qi.u.FSattributeInfo.attributes = 0x4003;
2538 qi.u.FSattributeInfo.maxCompLength = MAX_PATH;
2539 qi.u.FSattributeInfo.FSnameLength = sizeof(FSname);
2540 memcpy(qi.u.FSattributeInfo.FSname, FSname, sizeof(FSname));
2544 /* copy out return data, and set corresponding sizes */
2545 outp->totalParms = 0;
2546 outp->totalData = responseSize;
2547 memcpy(outp->datap, &qi, responseSize);
2549 /* send and free the packets */
2550 smb_SendTran2Packet(vcp, outp, op);
2551 smb_FreeTran2Packet(outp);
2556 long smb_ReceiveTran2SetFSInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
2558 osi_Log0(smb_logp,"ReceiveTran2SetFSInfo - NOT_SUPPORTED");
2559 return CM_ERROR_BADOP;
2562 struct smb_ShortNameRock {
2566 size_t shortNameLen;
2569 int cm_GetShortNameProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *vrockp,
2572 struct smb_ShortNameRock *rockp;
2576 /* compare both names and vnodes, though probably just comparing vnodes
2577 * would be safe enough.
2579 if (cm_stricmp(dep->name, rockp->maskp) != 0)
2581 if (ntohl(dep->fid.vnode) != rockp->vnode)
2583 /* This is the entry */
2584 cm_Gen8Dot3Name(dep, rockp->shortName, &shortNameEnd);
2585 rockp->shortNameLen = shortNameEnd - rockp->shortName;
2586 return CM_ERROR_STOPNOW;
2589 long cm_GetShortName(char *pathp, cm_user_t *userp, cm_req_t *reqp,
2590 char *tidPathp, int vnode, char *shortName, size_t *shortNameLenp)
2592 struct smb_ShortNameRock rock;
2596 int caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
2600 spacep = cm_GetSpace();
2601 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
2603 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold, userp, tidPathp,
2605 cm_FreeSpace(spacep);
2610 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
2611 cm_ReleaseSCache(dscp);
2612 cm_ReleaseUser(userp);
2613 return CM_ERROR_PATH_NOT_COVERED;
2615 #endif /* DFS_SUPPORT */
2617 if (!lastNamep) lastNamep = pathp;
2620 thyper.HighPart = 0;
2621 rock.shortName = shortName;
2623 rock.maskp = lastNamep;
2624 code = cm_ApplyDir(dscp, cm_GetShortNameProc, &rock, &thyper, userp, reqp, NULL);
2626 cm_ReleaseSCache(dscp);
2629 return CM_ERROR_NOSUCHFILE;
2630 if (code == CM_ERROR_STOPNOW) {
2631 *shortNameLenp = rock.shortNameLen;
2637 long smb_ReceiveTran2QPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
2639 smb_tran2Packet_t *outp;
2642 unsigned short infoLevel;
2643 smb_tran2QPathInfo_t qpi;
2645 unsigned short attributes;
2646 unsigned long extAttributes;
2651 cm_scache_t *scp, *dscp;
2661 infoLevel = p->parmsp[0];
2662 if (infoLevel == SMB_INFO_IS_NAME_VALID)
2664 else if (infoLevel == SMB_INFO_STANDARD)
2665 responseSize = sizeof(qpi.u.QPstandardInfo);
2666 else if (infoLevel == SMB_INFO_QUERY_EA_SIZE)
2667 responseSize = sizeof(qpi.u.QPeaSizeInfo);
2668 else if (infoLevel == SMB_QUERY_FILE_BASIC_INFO)
2669 responseSize = sizeof(qpi.u.QPfileBasicInfo);
2670 else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO)
2671 responseSize = sizeof(qpi.u.QPfileStandardInfo);
2672 else if (infoLevel == SMB_QUERY_FILE_EA_INFO)
2673 responseSize = sizeof(qpi.u.QPfileEaInfo);
2674 else if (infoLevel == SMB_QUERY_FILE_NAME_INFO)
2675 responseSize = sizeof(qpi.u.QPfileNameInfo);
2676 else if (infoLevel == SMB_QUERY_FILE_ALL_INFO)
2677 responseSize = sizeof(qpi.u.QPfileAllInfo);
2678 else if (infoLevel == SMB_QUERY_FILE_ALT_NAME_INFO)
2679 responseSize = sizeof(qpi.u.QPfileAltNameInfo);
2681 osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
2682 p->opcode, infoLevel);
2683 smb_SendTran2Error(vcp, p, opx, CM_ERROR_BADOP);
2687 pathp = (char *)(&p->parmsp[3]);
2688 if (smb_StoreAnsiFilenames)
2689 OemToChar(pathp,pathp);
2690 osi_Log2(smb_logp, "T2 QPathInfo type 0x%x path %s", infoLevel,
2691 osi_LogSaveString(smb_logp, pathp));
2693 outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, responseSize);
2695 if (infoLevel > 0x100)
2696 outp->totalParms = 2;
2698 outp->totalParms = 0;
2699 outp->totalData = responseSize;
2701 /* now, if we're at infoLevel 6, we're only being asked to check
2702 * the syntax, so we just OK things now. In particular, we're *not*
2703 * being asked to verify anything about the state of any parent dirs.
2705 if (infoLevel == SMB_INFO_IS_NAME_VALID) {
2706 smb_SendTran2Packet(vcp, outp, opx);
2707 smb_FreeTran2Packet(outp);
2711 userp = smb_GetTran2User(vcp, p);
2713 osi_Log1(smb_logp, "ReceiveTran2QPathInfo unable to resolve user [%d]", p->uid);
2714 smb_FreeTran2Packet(outp);
2715 return CM_ERROR_BADSMB;
2718 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
2720 cm_ReleaseUser(userp);
2721 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOSUCHPATH);
2722 smb_FreeTran2Packet(outp);
2727 * XXX Strange hack XXX
2729 * As of Patch 7 (13 January 98), we are having the following problem:
2730 * In NT Explorer 4.0, whenever we click on a directory, AFS gets
2731 * requests to look up "desktop.ini" in all the subdirectories.
2732 * This can cause zillions of timeouts looking up non-existent cells
2733 * and volumes, especially in the top-level directory.
2735 * We have not found any way to avoid this or work around it except
2736 * to explicitly ignore the requests for mount points that haven't
2737 * yet been evaluated and for directories that haven't yet been
2740 if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
2741 spacep = cm_GetSpace();
2742 smb_StripLastComponent(spacep->data, &lastComp, pathp);
2743 #ifndef SPECIAL_FOLDERS
2744 /* Make sure that lastComp is not NULL */
2746 if (stricmp(lastComp, "\\desktop.ini") == 0) {
2747 code = cm_NameI(cm_data.rootSCachep, spacep->data,
2751 userp, tidPathp, &req, &dscp);
2754 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
2755 if ( WANTS_DFS_PATHNAMES(p) )
2756 code = CM_ERROR_PATH_NOT_COVERED;
2758 code = CM_ERROR_BADSHARENAME;
2760 #endif /* DFS_SUPPORT */
2761 if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT && !dscp->mountRootFid.volume)
2762 code = CM_ERROR_NOSUCHFILE;
2763 else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
2764 cm_buf_t *bp = buf_Find(dscp, &hzero);
2768 code = CM_ERROR_NOSUCHFILE;
2770 cm_ReleaseSCache(dscp);
2772 cm_FreeSpace(spacep);
2773 cm_ReleaseUser(userp);
2774 smb_SendTran2Error(vcp, p, opx, code);
2775 smb_FreeTran2Packet(outp);
2781 #endif /* SPECIAL_FOLDERS */
2783 cm_FreeSpace(spacep);
2786 /* now do namei and stat, and copy out the info */
2787 code = cm_NameI(cm_data.rootSCachep, pathp,
2788 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, tidPathp, &req, &scp);
2791 cm_ReleaseUser(userp);
2792 smb_SendTran2Error(vcp, p, opx, code);
2793 smb_FreeTran2Packet(outp);
2798 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
2799 cm_ReleaseSCache(scp);
2800 cm_ReleaseUser(userp);
2801 if ( WANTS_DFS_PATHNAMES(p) )
2802 code = CM_ERROR_PATH_NOT_COVERED;
2804 code = CM_ERROR_BADSHARENAME;
2805 smb_SendTran2Error(vcp, p, opx, code);
2806 smb_FreeTran2Packet(outp);
2809 #endif /* DFS_SUPPORT */
2811 lock_ObtainMutex(&scp->mx);
2812 code = cm_SyncOp(scp, NULL, userp, &req, 0,
2813 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
2814 if (code) goto done;
2816 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
2818 /* now we have the status in the cache entry, and everything is locked.
2819 * Marshall the output data.
2821 /* for info level 108, figure out short name */
2822 if (infoLevel == SMB_QUERY_FILE_ALT_NAME_INFO) {
2823 code = cm_GetShortName(pathp, userp, &req,
2824 tidPathp, scp->fid.vnode, shortName,
2830 qpi.u.QPfileAltNameInfo.fileNameLength = (len + 1) * 2;
2831 mbstowcs((unsigned short *)qpi.u.QPfileAltNameInfo.fileName, shortName, len + 1);
2835 else if (infoLevel == SMB_QUERY_FILE_NAME_INFO) {
2836 len = strlen(lastComp);
2837 qpi.u.QPfileNameInfo.fileNameLength = (len + 1) * 2;
2838 mbstowcs((unsigned short *)qpi.u.QPfileNameInfo.fileName, lastComp, len + 1);
2842 else if (infoLevel == SMB_INFO_STANDARD || infoLevel == SMB_INFO_QUERY_EA_SIZE) {
2843 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
2844 qpi.u.QPstandardInfo.creationDateTime = dosTime;
2845 qpi.u.QPstandardInfo.lastAccessDateTime = dosTime;
2846 qpi.u.QPstandardInfo.lastWriteDateTime = dosTime;
2847 qpi.u.QPstandardInfo.dataSize = scp->length.LowPart;
2848 qpi.u.QPstandardInfo.allocationSize = scp->length.LowPart;
2849 attributes = smb_Attributes(scp);
2850 qpi.u.QPstandardInfo.attributes = attributes;
2851 qpi.u.QPstandardInfo.eaSize = 0;
2853 else if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
2854 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
2855 qpi.u.QPfileBasicInfo.creationTime = ft;
2856 qpi.u.QPfileBasicInfo.lastAccessTime = ft;
2857 qpi.u.QPfileBasicInfo.lastWriteTime = ft;
2858 qpi.u.QPfileBasicInfo.changeTime = ft;
2859 extAttributes = smb_ExtAttributes(scp);
2860 qpi.u.QPfileBasicInfo.attributes = extAttributes;
2861 qpi.u.QPfileBasicInfo.reserved = 0;
2863 else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO) {
2864 smb_fid_t *fidp = smb_FindFIDByScache(vcp, scp);
2866 lock_ObtainMutex(&fidp->mx);
2867 delonclose = fidp->flags & SMB_FID_DELONCLOSE;
2868 lock_ReleaseMutex(&fidp->mx);
2869 smb_ReleaseFID(fidp);
2872 qpi.u.QPfileStandardInfo.allocationSize = scp->length;
2873 qpi.u.QPfileStandardInfo.endOfFile = scp->length;
2874 qpi.u.QPfileStandardInfo.numberOfLinks = scp->linkCount;
2875 qpi.u.QPfileStandardInfo.deletePending = (delonclose ? 1 : 0);
2876 qpi.u.QPfileStandardInfo.directory =
2877 ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
2878 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
2879 scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0);
2880 qpi.u.QPfileStandardInfo.reserved = 0;
2882 else if (infoLevel == SMB_QUERY_FILE_EA_INFO) {
2883 qpi.u.QPfileEaInfo.eaSize = 0;
2885 else if (infoLevel == SMB_QUERY_FILE_ALL_INFO) {
2886 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
2887 qpi.u.QPfileAllInfo.creationTime = ft;
2888 qpi.u.QPfileAllInfo.lastAccessTime = ft;
2889 qpi.u.QPfileAllInfo.lastWriteTime = ft;
2890 qpi.u.QPfileAllInfo.changeTime = ft;
2891 extAttributes = smb_ExtAttributes(scp);
2892 qpi.u.QPfileAllInfo.attributes = extAttributes;
2893 qpi.u.QPfileAllInfo.allocationSize = scp->length;
2894 qpi.u.QPfileAllInfo.endOfFile = scp->length;
2895 qpi.u.QPfileAllInfo.numberOfLinks = scp->linkCount;
2896 qpi.u.QPfileAllInfo.deletePending = 0;
2897 qpi.u.QPfileAllInfo.directory =
2898 ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
2899 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
2900 scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0);
2901 qpi.u.QPfileAllInfo.indexNumber.HighPart = scp->fid.cell;
2902 qpi.u.QPfileAllInfo.indexNumber.LowPart = scp->fid.volume;
2903 qpi.u.QPfileAllInfo.eaSize = 0;
2904 qpi.u.QPfileAllInfo.accessFlags = 0;
2905 qpi.u.QPfileAllInfo.indexNumber2.HighPart = scp->fid.vnode;
2906 qpi.u.QPfileAllInfo.indexNumber2.LowPart = scp->fid.unique;
2907 qpi.u.QPfileAllInfo.currentByteOffset.HighPart = 0;
2908 qpi.u.QPfileAllInfo.currentByteOffset.LowPart = 0;
2909 qpi.u.QPfileAllInfo.mode = 0;
2910 qpi.u.QPfileAllInfo.alignmentRequirement = 0;
2911 len = strlen(lastComp);
2912 qpi.u.QPfileAllInfo.fileNameLength = (len + 1) * 2;
2913 mbstowcs((unsigned short *)qpi.u.QPfileAllInfo.fileName, lastComp, len + 1);
2916 /* send and free the packets */
2918 lock_ReleaseMutex(&scp->mx);
2919 cm_ReleaseSCache(scp);
2920 cm_ReleaseUser(userp);
2922 memcpy(outp->datap, &qpi, responseSize);
2923 smb_SendTran2Packet(vcp, outp, opx);
2925 smb_SendTran2Error(vcp, p, opx, code);
2927 smb_FreeTran2Packet(outp);
2932 long smb_ReceiveTran2SetPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
2935 osi_Log0(smb_logp,"ReceiveTran2SetPathInfo - NOT_SUPPORTED");
2936 return CM_ERROR_BADOP;
2940 unsigned short infoLevel;
2942 smb_tran2Packet_t *outp;
2943 smb_tran2QPathInfo_t *spi;
2945 cm_scache_t *scp, *dscp;
2953 infoLevel = p->parmsp[0];
2954 osi_Log1(smb_logp,"ReceiveTran2SetPathInfo type 0x%x", infoLevel);
2955 if (infoLevel != SMB_INFO_STANDARD &&
2956 infoLevel != SMB_INFO_QUERY_EA_SIZE &&
2957 infoLevel != SMB_INFO_QUERY_ALL_EAS) {
2958 osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
2959 p->opcode, infoLevel);
2960 smb_SendTran2Error(vcp, p, opx, CM_ERROR_INVAL);
2964 pathp = (char *)(&p->parmsp[3]);
2965 if (smb_StoreAnsiFilenames)
2966 OemToChar(pathp,pathp);
2967 osi_Log2(smb_logp, "T2 SetPathInfo infolevel 0x%x path %s", infoLevel,
2968 osi_LogSaveString(smb_logp, pathp));
2970 userp = smb_GetTran2User(vcp, p);
2972 osi_Log1(smb_logp,"ReceiveTran2SetPathInfo unable to resolve user [%d]", p->uid);
2973 code = CM_ERROR_BADSMB;
2977 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
2978 if (code == CM_ERROR_TIDIPC) {
2979 /* Attempt to use a TID allocated for IPC. The client
2980 * is probably looking for DCE RPC end points which we
2981 * don't support OR it could be looking to make a DFS
2984 osi_Log0(smb_logp, "Tran2Open received IPC TID");
2985 cm_ReleaseUser(userp);
2986 return CM_ERROR_NOSUCHPATH;
2990 * XXX Strange hack XXX
2992 * As of Patch 7 (13 January 98), we are having the following problem:
2993 * In NT Explorer 4.0, whenever we click on a directory, AFS gets
2994 * requests to look up "desktop.ini" in all the subdirectories.
2995 * This can cause zillions of timeouts looking up non-existent cells
2996 * and volumes, especially in the top-level directory.
2998 * We have not found any way to avoid this or work around it except
2999 * to explicitly ignore the requests for mount points that haven't
3000 * yet been evaluated and for directories that haven't yet been
3003 if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
3004 spacep = cm_GetSpace();
3005 smb_StripLastComponent(spacep->data, &lastComp, pathp);
3006 #ifndef SPECIAL_FOLDERS
3007 /* Make sure that lastComp is not NULL */
3009 if (stricmp(lastComp, "\\desktop.ini") == 0) {
3010 code = cm_NameI(cm_data.rootSCachep, spacep->data,
3014 userp, tidPathp, &req, &dscp);
3017 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
3018 if ( WANTS_DFS_PATHNAMES(p) )
3019 code = CM_ERROR_PATH_NOT_COVERED;
3021 code = CM_ERROR_BADSHARENAME;
3023 #endif /* DFS_SUPPORT */
3024 if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT && !dscp->mountRootFid.volume)
3025 code = CM_ERROR_NOSUCHFILE;
3026 else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
3027 cm_buf_t *bp = buf_Find(dscp, &hzero);
3031 code = CM_ERROR_NOSUCHFILE;
3033 cm_ReleaseSCache(dscp);
3035 cm_FreeSpace(spacep);
3036 cm_ReleaseUser(userp);
3037 smb_SendTran2Error(vcp, p, opx, code);
3043 #endif /* SPECIAL_FOLDERS */
3045 cm_FreeSpace(spacep);
3048 /* now do namei and stat, and copy out the info */
3049 code = cm_NameI(cm_data.rootSCachep, pathp,
3050 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, tidPathp, &req, &scp);
3052 cm_ReleaseUser(userp);
3053 smb_SendTran2Error(vcp, p, opx, code);
3057 fidp = smb_FindFIDByScache(vcp, scp);
3059 cm_ReleaseUser(userp);
3060 cm_ReleaseSCache(scp);
3061 smb_SendTran2Error(vcp, p, opx, code);
3065 lock_ObtainMutex(&fidp->mx);
3066 if (!(fidp->flags & SMB_FID_OPENWRITE)) {
3067 lock_ReleaseMutex(&fidp->mx);
3068 smb_ReleaseFID(fidp);
3069 cm_ReleaseUser(userp);
3070 cm_ReleaseSCache(scp);
3071 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOACCESS);
3074 lock_ReleaseMutex(&fidp->mx);
3076 outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, 0);
3078 outp->totalParms = 2;
3079 outp->totalData = 0;
3081 spi = (smb_tran2QPathInfo_t *)p->datap;
3082 if (infoLevel == SMB_INFO_STANDARD || infoLevel == SMB_INFO_QUERY_EA_SIZE) {
3085 /* lock the vnode with a callback; we need the current status
3086 * to determine what the new status is, in some cases.
3088 lock_ObtainMutex(&scp->mx);
3089 code = cm_SyncOp(scp, NULL, userp, &req, 0,
3090 CM_SCACHESYNC_GETSTATUS
3091 | CM_SCACHESYNC_NEEDCALLBACK);
3093 lock_ReleaseMutex(&scp->mx);
3096 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3098 lock_ReleaseMutex(&scp->mx);
3099 lock_ObtainMutex(&fidp->mx);
3100 lock_ObtainMutex(&scp->mx);
3102 /* prepare for setattr call */
3103 attr.mask = CM_ATTRMASK_LENGTH;
3104 attr.length.LowPart = spi->u.QPstandardInfo.dataSize;
3105 attr.length.HighPart = 0;
3107 if (spi->u.QPstandardInfo.lastWriteDateTime != 0) {
3108 smb_UnixTimeFromSearchTime(&attr.clientModTime, spi->u.QPstandardInfo.lastWriteDateTime);
3109 attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
3110 fidp->flags |= SMB_FID_MTIMESETDONE;
3113 if (spi->u.QPstandardInfo.attributes != 0) {
3114 if ((scp->unixModeBits & 0222)
3115 && (spi->u.QPstandardInfo.attributes & SMB_ATTR_READONLY) != 0) {
3116 /* make a writable file read-only */
3117 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
3118 attr.unixModeBits = scp->unixModeBits & ~0222;
3120 else if ((scp->unixModeBits & 0222) == 0
3121 && (spi->u.QPstandardInfo.attributes & SMB_ATTR_READONLY) == 0) {
3122 /* make a read-only file writable */
3123 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
3124 attr.unixModeBits = scp->unixModeBits | 0222;
3127 lock_ReleaseMutex(&scp->mx);
3128 lock_ReleaseMutex(&fidp->mx);
3132 code = cm_SetAttr(scp, &attr, userp, &req);
3136 else if (infoLevel == SMB_INFO_QUERY_ALL_EAS) {
3137 /* we don't support EAs */
3138 code = CM_ERROR_INVAL;
3142 cm_ReleaseSCache(scp);
3143 cm_ReleaseUser(userp);
3144 smb_ReleaseFID(fidp);
3146 smb_SendTran2Packet(vcp, outp, opx);
3148 smb_SendTran2Error(vcp, p, opx, code);
3149 smb_FreeTran2Packet(outp);
3155 long smb_ReceiveTran2QFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
3157 smb_tran2Packet_t *outp;
3159 unsigned long attributes;
3160 unsigned short infoLevel;
3167 smb_tran2QFileInfo_t qfi;
3174 fidp = smb_FindFID(vcp, fid, 0);
3177 smb_SendTran2Error(vcp, p, opx, CM_ERROR_BADFD);
3181 infoLevel = p->parmsp[1];
3182 if (infoLevel == SMB_QUERY_FILE_BASIC_INFO)
3183 responseSize = sizeof(qfi.u.QFbasicInfo);
3184 else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO)
3185 responseSize = sizeof(qfi.u.QFstandardInfo);
3186 else if (infoLevel == SMB_QUERY_FILE_EA_INFO)
3187 responseSize = sizeof(qfi.u.QFeaInfo);
3188 else if (infoLevel == SMB_QUERY_FILE_NAME_INFO)
3189 responseSize = sizeof(qfi.u.QFfileNameInfo);
3191 osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
3192 p->opcode, infoLevel);
3193 smb_SendTran2Error(vcp, p, opx, CM_ERROR_BADOP);
3194 smb_ReleaseFID(fidp);
3197 osi_Log2(smb_logp, "T2 QFileInfo type 0x%x fid %d", infoLevel, fid);
3199 outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, responseSize);
3201 if (infoLevel > 0x100)
3202 outp->totalParms = 2;
3204 outp->totalParms = 0;
3205 outp->totalData = responseSize;
3207 userp = smb_GetTran2User(vcp, p);
3209 osi_Log1(smb_logp, "ReceiveTran2QFileInfo unable to resolve user [%d]", p->uid);
3210 code = CM_ERROR_BADSMB;
3214 lock_ObtainMutex(&fidp->mx);
3215 delonclose = fidp->flags & SMB_FID_DELONCLOSE;
3218 lock_ReleaseMutex(&fidp->mx);
3219 lock_ObtainMutex(&scp->mx);
3220 code = cm_SyncOp(scp, NULL, userp, &req, 0,
3221 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3225 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3227 /* now we have the status in the cache entry, and everything is locked.
3228 * Marshall the output data.
3230 if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
3231 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
3232 qfi.u.QFbasicInfo.creationTime = ft;
3233 qfi.u.QFbasicInfo.lastAccessTime = ft;
3234 qfi.u.QFbasicInfo.lastWriteTime = ft;
3235 qfi.u.QFbasicInfo.lastChangeTime = ft;
3236 attributes = smb_ExtAttributes(scp);
3237 qfi.u.QFbasicInfo.attributes = attributes;
3239 else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO) {
3240 qfi.u.QFstandardInfo.allocationSize = scp->length;
3241 qfi.u.QFstandardInfo.endOfFile = scp->length;
3242 qfi.u.QFstandardInfo.numberOfLinks = scp->linkCount;
3243 qfi.u.QFstandardInfo.deletePending = (delonclose ? 1 : 0);
3244 qfi.u.QFstandardInfo.directory =
3245 ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
3246 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
3247 scp->fileType == CM_SCACHETYPE_INVALID)? 1 : 0);
3249 else if (infoLevel == SMB_QUERY_FILE_EA_INFO) {
3250 qfi.u.QFeaInfo.eaSize = 0;
3252 else if (infoLevel == SMB_QUERY_FILE_NAME_INFO) {
3256 lock_ReleaseMutex(&scp->mx);
3257 lock_ObtainMutex(&fidp->mx);
3258 lock_ObtainMutex(&scp->mx);
3259 if (fidp->NTopen_wholepathp)
3260 name = fidp->NTopen_wholepathp;
3262 name = "\\"; /* probably can't happen */
3263 lock_ReleaseMutex(&fidp->mx);
3264 len = (unsigned long)strlen(name);
3265 outp->totalData = ((len+1)*2) + 4; /* this is actually what we want to return */
3266 qfi.u.QFfileNameInfo.fileNameLength = (len + 1) * 2;
3267 mbstowcs((unsigned short *)qfi.u.QFfileNameInfo.fileName, name, len + 1);
3270 /* send and free the packets */
3272 lock_ReleaseMutex(&scp->mx);
3273 cm_ReleaseSCache(scp);
3274 cm_ReleaseUser(userp);
3275 smb_ReleaseFID(fidp);
3277 memcpy(outp->datap, &qfi, responseSize);
3278 smb_SendTran2Packet(vcp, outp, opx);
3280 smb_SendTran2Error(vcp, p, opx, code);
3282 smb_FreeTran2Packet(outp);
3287 long smb_ReceiveTran2SetFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
3292 unsigned short infoLevel;
3293 smb_tran2Packet_t *outp;
3301 fidp = smb_FindFID(vcp, fid, 0);
3304 smb_SendTran2Error(vcp, p, opx, CM_ERROR_BADFD);
3308 infoLevel = p->parmsp[1];
3309 osi_Log2(smb_logp,"ReceiveTran2SetFileInfo type 0x%x fid %d", infoLevel, fid);
3310 if (infoLevel > SMB_SET_FILE_END_OF_FILE_INFO || infoLevel < SMB_SET_FILE_BASIC_INFO) {
3311 osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
3312 p->opcode, infoLevel);
3313 smb_SendTran2Error(vcp, p, opx, CM_ERROR_BADOP);
3314 smb_ReleaseFID(fidp);
3318 lock_ObtainMutex(&fidp->mx);
3319 if (infoLevel == SMB_SET_FILE_DISPOSITION_INFO && !(fidp->flags & SMB_FID_OPENDELETE)) {
3320 lock_ReleaseMutex(&fidp->mx);
3321 smb_ReleaseFID(fidp);
3322 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOACCESS);
3325 if ((infoLevel == SMB_SET_FILE_ALLOCATION_INFO ||
3326 infoLevel == SMB_SET_FILE_END_OF_FILE_INFO)
3327 && !(fidp->flags & SMB_FID_OPENWRITE)) {
3328 lock_ReleaseMutex(&fidp->mx);
3329 smb_ReleaseFID(fidp);
3330 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOACCESS);
3336 lock_ReleaseMutex(&fidp->mx);
3338 outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, 0);
3340 outp->totalParms = 2;
3341 outp->totalData = 0;
3343 userp = smb_GetTran2User(vcp, p);
3345 osi_Log1(smb_logp,"ReceiveTran2SetFileInfo unable to resolve user [%d]", p->uid);
3346 code = CM_ERROR_BADSMB;
3350 if (infoLevel == SMB_SET_FILE_BASIC_INFO) {
3352 unsigned int attribute;
3354 smb_tran2QFileInfo_t *sfi;
3356 sfi = (smb_tran2QFileInfo_t *)p->datap;
3358 /* lock the vnode with a callback; we need the current status
3359 * to determine what the new status is, in some cases.
3361 lock_ObtainMutex(&scp->mx);
3362 code = cm_SyncOp(scp, NULL, userp, &req, 0,
3363 CM_SCACHESYNC_GETSTATUS
3364 | CM_SCACHESYNC_NEEDCALLBACK);
3366 lock_ReleaseMutex(&scp->mx);
3370 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3372 lock_ReleaseMutex(&scp->mx);
3373 lock_ObtainMutex(&fidp->mx);
3374 lock_ObtainMutex(&scp->mx);
3376 /* prepare for setattr call */
3379 lastMod = sfi->u.QFbasicInfo.lastWriteTime;
3380 /* when called as result of move a b, lastMod is (-1, -1).
3381 * If the check for -1 is not present, timestamp
3382 * of the resulting file will be 1969 (-1)
3384 if (LargeIntegerNotEqualToZero(*((LARGE_INTEGER *)&lastMod)) &&
3385 lastMod.dwLowDateTime != -1 && lastMod.dwHighDateTime != -1) {
3386 attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
3387 smb_UnixTimeFromLargeSearchTime(&attr.clientModTime, &lastMod);
3388 fidp->flags |= SMB_FID_MTIMESETDONE;
3391 attribute = sfi->u.QFbasicInfo.attributes;
3392 if (attribute != 0) {
3393 if ((scp->unixModeBits & 0222)
3394 && (attribute & SMB_ATTR_READONLY) != 0) {
3395 /* make a writable file read-only */
3396 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
3397 attr.unixModeBits = scp->unixModeBits & ~0222;
3399 else if ((scp->unixModeBits & 0222) == 0
3400 && (attribute & SMB_ATTR_READONLY) == 0) {
3401 /* make a read-only file writable */
3402 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
3403 attr.unixModeBits = scp->unixModeBits | 0222;
3406 lock_ReleaseMutex(&scp->mx);
3407 lock_ReleaseMutex(&fidp->mx);
3411 code = cm_SetAttr(scp, &attr, userp, &req);
3415 else if (infoLevel == SMB_SET_FILE_DISPOSITION_INFO) {
3416 if (*((char *)(p->datap))) { /* File is Deleted */
3417 code = cm_CheckNTDelete(fidp->NTopen_dscp, scp, userp,
3420 lock_ObtainMutex(&fidp->mx);
3421 fidp->flags |= SMB_FID_DELONCLOSE;
3422 lock_ReleaseMutex(&fidp->mx);
3427 lock_ObtainMutex(&fidp->mx);
3428 fidp->flags &= ~SMB_FID_DELONCLOSE;
3429 lock_ReleaseMutex(&fidp->mx);
3432 else if (infoLevel == SMB_SET_FILE_ALLOCATION_INFO ||
3433 infoLevel == SMB_SET_FILE_END_OF_FILE_INFO) {
3434 LARGE_INTEGER size = *((LARGE_INTEGER *)(p->datap));
3437 attr.mask = CM_ATTRMASK_LENGTH;
3438 attr.length.LowPart = size.LowPart;
3439 attr.length.HighPart = size.HighPart;
3440 code = cm_SetAttr(scp, &attr, userp, &req);
3444 cm_ReleaseSCache(scp);
3445 cm_ReleaseUser(userp);
3446 smb_ReleaseFID(fidp);
3448 smb_SendTran2Packet(vcp, outp, opx);
3450 smb_SendTran2Error(vcp, p, opx, code);
3451 smb_FreeTran2Packet(outp);
3457 smb_ReceiveTran2FSCTL(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3459 osi_Log0(smb_logp,"ReceiveTran2FSCTL - NOT_SUPPORTED");
3460 return CM_ERROR_BADOP;
3464 smb_ReceiveTran2IOCTL(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3466 osi_Log0(smb_logp,"ReceiveTran2IOCTL - NOT_SUPPORTED");
3467 return CM_ERROR_BADOP;
3471 smb_ReceiveTran2FindNotifyFirst(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3473 osi_Log0(smb_logp,"ReceiveTran2FindNotifyFirst - NOT_SUPPORTED");
3474 return CM_ERROR_BADOP;
3478 smb_ReceiveTran2FindNotifyNext(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3480 osi_Log0(smb_logp,"ReceiveTran2FindNotifyNext - NOT_SUPPORTED");
3481 return CM_ERROR_BADOP;
3485 smb_ReceiveTran2CreateDirectory(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3487 osi_Log0(smb_logp,"ReceiveTran2CreateDirectory - NOT_SUPPORTED");
3488 return CM_ERROR_BADOP;
3492 smb_ReceiveTran2SessionSetup(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3494 osi_Log0(smb_logp,"ReceiveTran2SessionSetup - NOT_SUPPORTED");
3495 return CM_ERROR_BADOP;
3498 struct smb_v2_referral {
3500 USHORT ReferralFlags;
3503 USHORT DfsPathOffset;
3504 USHORT DfsAlternativePathOffset;
3505 USHORT NetworkAddressOffset;
3509 smb_ReceiveTran2GetDFSReferral(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
3511 /* This is a UNICODE only request (bit15 of Flags2) */
3512 /* The TID must be IPC$ */
3514 /* The documentation for the Flags response field is contradictory */
3516 /* Use Version 1 Referral Element Format */
3517 /* ServerType = 0; indicates the next server should be queried for the file */
3518 /* ReferralFlags = 0x01; PathConsumed characters should be stripped */
3519 /* Node = UnicodeString of UNC path of the next share name */
3522 int maxReferralLevel = 0;
3523 char requestFileName[1024] = "";
3524 smb_tran2Packet_t *outp = 0;
3525 cm_user_t *userp = 0;
3527 CPINFO CodePageInfo;
3528 int i, nbnLen, reqLen;
3533 maxReferralLevel = p->parmsp[0];
3535 GetCPInfo(CP_ACP, &CodePageInfo);
3536 WideCharToMultiByte(CP_ACP, 0, (LPCWSTR) &p->parmsp[1], -1,
3537 requestFileName, 1024, NULL, NULL);
3539 osi_Log2(smb_logp,"ReceiveTran2GetDfsReferral [%d][%s]",
3540 maxReferralLevel, osi_LogSaveString(smb_logp, requestFileName));
3542 nbnLen = strlen(cm_NetbiosName);
3543 reqLen = strlen(requestFileName);
3545 if (reqLen == nbnLen + 5 &&
3546 requestFileName[0] == '\\' &&
3547 !_strnicmp(cm_NetbiosName,&requestFileName[1],nbnLen) &&
3548 requestFileName[nbnLen+1] == '\\' &&
3549 (!_strnicmp("all",&requestFileName[nbnLen+2],3) ||
3550 !_strnicmp("*.",&requestFileName[nbnLen+2],2)))
3553 struct smb_v2_referral * v2ref;
3554 outp = smb_GetTran2ResponsePacket(vcp, p, op, 0, 2 * (reqLen + 8));
3556 sp = (USHORT *)outp->datap;
3558 sp[idx++] = reqLen; /* path consumed */
3559 sp[idx++] = 1; /* number of referrals */
3560 sp[idx++] = 0x03; /* flags */
3561 #ifdef DFS_VERSION_1
3562 sp[idx++] = 1; /* Version Number */
3563 sp[idx++] = reqLen + 4; /* Referral Size */
3564 sp[idx++] = 1; /* Type = SMB Server */
3565 sp[idx++] = 0; /* Do not strip path consumed */
3566 for ( i=0;i<=reqLen; i++ )
3567 sp[i+idx] = requestFileName[i];
3568 #else /* DFS_VERSION_2 */
3569 sp[idx++] = 2; /* Version Number */
3570 sp[idx++] = sizeof(struct smb_v2_referral); /* Referral Size */
3571 idx += (sizeof(struct smb_v2_referral) / 2);
3572 v2ref = (struct smb_v2_referral *) &sp[5];
3573 v2ref->ServerType = 1; /* SMB Server */
3574 v2ref->ReferralFlags = 0x03;
3575 v2ref->Proximity = 0; /* closest */
3576 v2ref->TimeToLive = 3600; /* seconds */
3577 v2ref->DfsPathOffset = idx * 2;
3578 v2ref->DfsAlternativePathOffset = idx * 2;
3579 v2ref->NetworkAddressOffset = 0;
3580 for ( i=0;i<=reqLen; i++ )
3581 sp[i+idx] = requestFileName[i];
3584 userp = smb_GetTran2User(vcp, p);
3586 osi_Log1(smb_logp,"ReceiveTran2GetDfsReferral unable to resolve user [%d]", p->uid);
3587 code = CM_ERROR_BADSMB;
3592 code = CM_ERROR_NOSUCHPATH;
3597 cm_ReleaseUser(userp);
3599 smb_SendTran2Packet(vcp, outp, op);
3601 smb_SendTran2Error(vcp, p, op, code);
3603 smb_FreeTran2Packet(outp);
3606 #else /* DFS_SUPPORT */
3607 osi_Log0(smb_logp,"ReceiveTran2GetDfsReferral - NOT_SUPPORTED");
3608 return CM_ERROR_BADOP;
3609 #endif /* DFS_SUPPORT */
3613 smb_ReceiveTran2ReportDFSInconsistency(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3615 /* This is a UNICODE only request (bit15 of Flags2) */
3617 /* There is nothing we can do about this operation. The client is going to
3618 * tell us that there is a Version 1 Referral Element for which there is a DFS Error.
3619 * Unfortunately, there is really nothing we can do about it other then log it
3620 * somewhere. Even then I don't think there is anything for us to do.
3621 * So let's return an error value.
3624 osi_Log0(smb_logp,"ReceiveTran2ReportDFSInconsistency - NOT_SUPPORTED");
3625 return CM_ERROR_BADOP;
3629 smb_ApplyV3DirListPatches(cm_scache_t *dscp,
3630 smb_dirListPatch_t **dirPatchespp, int infoLevel, cm_user_t *userp,
3635 cm_scache_t *targetScp; /* target if scp is a symlink */
3640 unsigned short attr;
3641 unsigned long lattr;
3642 smb_dirListPatch_t *patchp;
3643 smb_dirListPatch_t *npatchp;
3645 for(patchp = *dirPatchespp; patchp; patchp =
3646 (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
3647 code = cm_GetSCache(&patchp->fid, &scp, userp, reqp);
3649 lock_ObtainMutex(&scp->mx);
3650 code = cm_SyncOp(scp, NULL, userp, reqp, 0,
3651 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3653 lock_ReleaseMutex(&scp->mx);
3654 cm_ReleaseSCache(scp);
3656 dptr = patchp->dptr;
3658 /* Plug in fake timestamps. A time stamp of 0 causes 'invalid parameter'
3659 errors in the client. */
3660 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO) {
3661 /* 1969-12-31 23:59:59 +00 */
3662 ft.dwHighDateTime = 0x19DB200;
3663 ft.dwLowDateTime = 0x5BB78980;
3665 /* copy to Creation Time */
3666 *((FILETIME *)dptr) = ft;
3669 /* copy to Last Access Time */
3670 *((FILETIME *)dptr) = ft;
3673 /* copy to Last Write Time */
3674 *((FILETIME *)dptr) = ft;
3677 /* copy to Change Time */
3678 *((FILETIME *)dptr) = ft;
3681 /* merge in hidden attribute */
3682 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
3683 *((u_long *)dptr) = SMB_ATTR_HIDDEN;
3687 /* 1969-12-31 23:59:58 +00*/
3688 dosTime = 0xEBBFBF7D;
3690 /* and copy out date */
3691 shortTemp = (dosTime>>16) & 0xffff;
3692 *((u_short *)dptr) = shortTemp;
3695 /* copy out creation time */
3696 shortTemp = dosTime & 0xffff;
3697 *((u_short *)dptr) = shortTemp;
3700 /* and copy out date */
3701 shortTemp = (dosTime>>16) & 0xffff;
3702 *((u_short *)dptr) = shortTemp;
3705 /* copy out access time */
3706 shortTemp = dosTime & 0xffff;
3707 *((u_short *)dptr) = shortTemp;
3710 /* and copy out date */
3711 shortTemp = (dosTime>>16) & 0xffff;
3712 *((u_short *)dptr) = shortTemp;
3715 /* copy out mod time */
3716 shortTemp = dosTime & 0xffff;
3717 *((u_short *)dptr) = shortTemp;
3720 /* merge in hidden (dot file) attribute */
3721 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
3722 attr = SMB_ATTR_HIDDEN;
3723 *dptr++ = attr & 0xff;
3724 *dptr++ = (attr >> 8) & 0xff;
3730 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3732 /* now watch for a symlink */
3734 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
3735 lock_ReleaseMutex(&scp->mx);
3736 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, reqp);
3738 /* we have a more accurate file to use (the
3739 * target of the symbolic link). Otherwise,
3740 * we'll just use the symlink anyway.
3742 osi_Log2(smb_logp, "symlink vp %x to vp %x",
3744 cm_ReleaseSCache(scp);
3747 lock_ObtainMutex(&scp->mx);
3750 dptr = patchp->dptr;
3752 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO) {
3754 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
3756 /* copy to Creation Time */
3757 *((FILETIME *)dptr) = ft;
3760 /* copy to Last Access Time */
3761 *((FILETIME *)dptr) = ft;
3764 /* copy to Last Write Time */
3765 *((FILETIME *)dptr) = ft;
3768 /* copy to Change Time */
3769 *((FILETIME *)dptr) = ft;
3772 /* Use length for both file length and alloc length */
3773 *((LARGE_INTEGER *)dptr) = scp->length;
3775 *((LARGE_INTEGER *)dptr) = scp->length;
3778 /* Copy attributes */
3779 lattr = smb_ExtAttributes(scp);
3780 if (code == CM_ERROR_NOSUCHPATH && scp->fileType == CM_SCACHETYPE_SYMLINK) {
3781 if (lattr == SMB_ATTR_NORMAL)
3782 lattr = SMB_ATTR_DIRECTORY;
3784 lattr |= SMB_ATTR_DIRECTORY;
3786 /* merge in hidden (dot file) attribute */
3787 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
3788 if (lattr == SMB_ATTR_NORMAL)
3789 lattr = SMB_ATTR_HIDDEN;
3791 lattr |= SMB_ATTR_HIDDEN;
3793 *((u_long *)dptr) = lattr;
3797 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
3799 /* and copy out date */
3800 shortTemp = (dosTime>>16) & 0xffff;
3801 *((u_short *)dptr) = shortTemp;
3804 /* copy out creation time */
3805 shortTemp = dosTime & 0xffff;
3806 *((u_short *)dptr) = shortTemp;
3809 /* and copy out date */
3810 shortTemp = (dosTime>>16) & 0xffff;
3811 *((u_short *)dptr) = shortTemp;
3814 /* copy out access time */
3815 shortTemp = dosTime & 0xffff;
3816 *((u_short *)dptr) = shortTemp;
3819 /* and copy out date */
3820 shortTemp = (dosTime>>16) & 0xffff;
3821 *((u_short *)dptr) = shortTemp;
3824 /* copy out mod time */
3825 shortTemp = dosTime & 0xffff;
3826 *((u_short *)dptr) = shortTemp;
3829 /* copy out file length and alloc length,
3830 * using the same for both
3832 *((u_long *)dptr) = scp->length.LowPart;
3834 *((u_long *)dptr) = scp->length.LowPart;
3837 /* finally copy out attributes as short */
3838 attr = smb_Attributes(scp);
3839 /* merge in hidden (dot file) attribute */
3840 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
3841 if (lattr == SMB_ATTR_NORMAL)
3842 lattr = SMB_ATTR_HIDDEN;
3844 lattr |= SMB_ATTR_HIDDEN;
3846 *dptr++ = attr & 0xff;
3847 *dptr++ = (attr >> 8) & 0xff;
3850 lock_ReleaseMutex(&scp->mx);
3851 cm_ReleaseSCache(scp);
3854 /* now free the patches */
3855 for (patchp = *dirPatchespp; patchp; patchp = npatchp) {
3856 npatchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q);
3860 /* and mark the list as empty */
3861 *dirPatchespp = NULL;
3866 #ifndef USE_OLD_MATCHING
3867 // char table for case insensitive comparison
3868 char mapCaseTable[256];
3870 VOID initUpperCaseTable(VOID)
3873 for (i = 0; i < 256; ++i)
3874 mapCaseTable[i] = toupper(i);
3875 // make '"' match '.'
3876 mapCaseTable[(int)'"'] = toupper('.');
3877 // make '<' match '*'
3878 mapCaseTable[(int)'<'] = toupper('*');
3879 // make '>' match '?'
3880 mapCaseTable[(int)'>'] = toupper('?');
3883 // Compare 'pattern' (containing metacharacters '*' and '?') with the file
3885 // Note : this procedure works recursively calling itself.
3887 // PSZ pattern : string containing metacharacters.
3888 // PSZ name : file name to be compared with 'pattern'.
3890 // BOOL : TRUE/FALSE (match/mistmatch)
3893 szWildCardMatchFileName(PSZ pattern, PSZ name, int casefold)
3895 PSZ pename; // points to the last 'name' character
3897 pename = name + strlen(name) - 1;
3908 if (*pattern == '\0')
3910 for (p = pename; p >= name; --p) {
3911 if ((casefold && (mapCaseTable[*p] == mapCaseTable[*pattern]) ||
3912 !casefold && (*p == *pattern)) &&
3913 szWildCardMatchFileName(pattern + 1, p + 1, casefold))
3918 if ((casefold && mapCaseTable[*name] != mapCaseTable[*pattern]) ||
3919 (!casefold && *name != *pattern))
3926 /* if all we have left are wildcards, then we match */
3927 for (;*pattern; pattern++) {
3928 if (*pattern != '*' && *pattern != '?')
3934 /* do a case-folding search of the star name mask with the name in namep.
3935 * Return 1 if we match, otherwise 0.
3937 int smb_V3MatchMask(char *namep, char *maskp, int flags)
3940 int i, j, star, qmark, casefold, retval;
3942 /* make sure we only match 8.3 names, if requested */
3943 if ((flags & CM_FLAG_8DOT3) && !cm_Is8Dot3(namep))
3946 casefold = (flags & CM_FLAG_CASEFOLD) ? 1 : 0;
3948 /* optimize the pattern:
3949 * if there is a mixture of '?' and '*',
3950 * for example the sequence "*?*?*?*"
3951 * must be turned into the form "*"
3953 newmask = (char *)malloc(strlen(maskp)+1);
3954 for ( i=0, j=0, star=0, qmark=0; maskp[i]; i++) {
3955 switch ( maskp[i] ) {
3967 } else if ( qmark ) {
3971 newmask[j++] = maskp[i];
3978 } else if ( qmark ) {
3982 newmask[j++] = '\0';
3984 retval = szWildCardMatchFileName(newmask, namep, casefold) ? 1:0;
3990 #else /* USE_OLD_MATCHING */
3991 /* do a case-folding search of the star name mask with the name in namep.
3992 * Return 1 if we match, otherwise 0.
3994 int smb_V3MatchMask(char *namep, char *maskp, int flags)
3996 unsigned char tcp1, tcp2; /* Pattern characters */
3997 unsigned char tcn1; /* Name characters */
3998 int sawDot = 0, sawStar = 0, req8dot3 = 0;
3999 char *starNamep, *starMaskp;
4000 static char nullCharp[] = {0};
4001 int casefold = flags & CM_FLAG_CASEFOLD;
4003 /* make sure we only match 8.3 names, if requested */
4004 req8dot3 = (flags & CM_FLAG_8DOT3);
4005 if (req8dot3 && !cm_Is8Dot3(namep))
4010 /* Next pattern character */
4013 /* Next name character */
4017 /* 0 - end of pattern */
4023 else if (tcp1 == '.' || tcp1 == '"') {
4033 * first dot in pattern;
4034 * must match dot or end of name
4039 else if (tcn1 == '.') {
4048 else if (tcp1 == '?') {
4049 if (tcn1 == 0 || tcn1 == '.')
4054 else if (tcp1 == '>') {
4055 if (tcn1 != 0 && tcn1 != '.')
4059 else if (tcp1 == '*' || tcp1 == '<') {
4063 else if ((req8dot3 && tcp2 == '.') || tcp2 == '"') {
4064 while (req8dot3 && tcn1 != '.' && tcn1 != 0)
4079 * pattern character after '*' is not null or
4080 * period. If it is '?' or '>', we are not
4081 * going to understand it. If it is '*' or
4082 * '<', we are going to skip over it. None of
4083 * these are likely, I hope.
4085 /* skip over '*' and '<' */
4086 while (tcp2 == '*' || tcp2 == '<')
4089 /* skip over characters that don't match tcp2 */
4090 while (req8dot3 && tcn1 != '.' && tcn1 != 0 &&
4091 ((casefold && cm_foldUpper[tcn1] != cm_foldUpper[tcp2]) ||
4092 (!casefold && tcn1 != tcp2)))
4096 if ((req8dot3 && tcn1 == '.') || tcn1 == 0)
4099 /* Remember where we are */
4109 /* tcp1 is not a wildcard */
4110 if ((casefold && cm_foldUpper[tcn1] == cm_foldUpper[tcp1]) ||
4111 (!casefold && tcn1 == tcp1)) {
4116 /* if trying to match a star pattern, go back */
4118 maskp = starMaskp - 2;
4119 namep = starNamep + 1;
4128 #endif /* USE_OLD_MATCHING */
4130 long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
4135 long code = 0, code2 = 0;
4139 smb_dirListPatch_t *dirListPatchesp;
4140 smb_dirListPatch_t *curPatchp;
4143 long orbytes; /* # of bytes in this output record */
4144 long ohbytes; /* # of bytes, except file name */
4145 long onbytes; /* # of bytes in name, incl. term. null */
4146 osi_hyper_t dirLength;
4147 osi_hyper_t bufferOffset;
4148 osi_hyper_t curOffset;
4150 smb_dirSearch_t *dsp;
4154 cm_pageHeader_t *pageHeaderp;
4155 cm_user_t *userp = NULL;
4158 long nextEntryCookie;
4159 int numDirChunks; /* # of 32 byte dir chunks in this entry */
4160 char *op; /* output data ptr */
4161 char *origOp; /* original value of op */
4162 cm_space_t *spacep; /* for pathname buffer */
4163 long maxReturnData; /* max # of return data */
4164 long maxReturnParms; /* max # of return parms */
4165 long bytesInBuffer; /* # data bytes in the output buffer */
4167 char *maskp; /* mask part of path */
4171 smb_tran2Packet_t *outp; /* response packet */
4174 char shortName[13]; /* 8.3 name if needed */
4186 if (p->opcode == 1) {
4187 /* find first; obtain basic parameters from request */
4188 attribute = p->parmsp[0];
4189 maxCount = p->parmsp[1];
4190 infoLevel = p->parmsp[3];
4191 searchFlags = p->parmsp[2];
4192 dsp = smb_NewDirSearch(1);
4193 dsp->attribute = attribute;
4194 pathp = ((char *) p->parmsp) + 12; /* points to path */
4195 if (smb_StoreAnsiFilenames)
4196 OemToChar(pathp,pathp);
4198 maskp = strrchr(pathp, '\\');
4202 maskp++; /* skip over backslash */
4203 strcpy(dsp->mask, maskp); /* and save mask */
4204 /* track if this is likely to match a lot of entries */
4205 starPattern = smb_V3IsStarMask(maskp);
4208 osi_assert(p->opcode == 2);
4209 /* find next; obtain basic parameters from request or open dir file */
4210 dsp = smb_FindDirSearch(p->parmsp[0]);
4211 maxCount = p->parmsp[1];
4212 infoLevel = p->parmsp[2];
4213 nextCookie = p->parmsp[3] | (p->parmsp[4] << 16);
4214 searchFlags = p->parmsp[5];
4216 osi_Log2(smb_logp, "T2 search dir bad search ID: id %d nextCookie 0x%x",
4217 p->parmsp[0], nextCookie);
4218 return CM_ERROR_BADFD;
4220 attribute = dsp->attribute;
4223 starPattern = 1; /* assume, since required a Find Next */
4226 switch ( infoLevel ) {
4227 case SMB_INFO_STANDARD:
4230 case SMB_INFO_QUERY_EA_SIZE:
4231 s = "InfoQueryEaSize";
4233 case SMB_INFO_QUERY_EAS_FROM_LIST:
4234 s = "InfoQueryEasFromList";
4236 case SMB_FIND_FILE_DIRECTORY_INFO:
4237 s = "FindFileDirectoryInfo";
4239 case SMB_FIND_FILE_FULL_DIRECTORY_INFO:
4240 s = "FindFileFullDirectoryInfo";
4242 case SMB_FIND_FILE_NAMES_INFO:
4243 s = "FindFileNamesInfo";
4245 case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
4246 s = "FindFileBothDirectoryInfo";
4249 s = "unknownInfoLevel";
4252 osi_Log1(smb_logp, "T2 search dir info level: %s", s);
4255 "T2 search dir attr 0x%x, info level 0x%x, max count %d, flags 0x%x",
4256 attribute, infoLevel, maxCount, searchFlags);
4258 osi_Log3(smb_logp, "...T2 search op %d, id %d, nextCookie 0x%x",
4259 p->opcode, dsp->cookie, nextCookie);
4261 if (infoLevel > SMB_FIND_FILE_BOTH_DIRECTORY_INFO) {
4262 osi_Log1(smb_logp, "Unsupported InfoLevel 0x%x", infoLevel);
4263 smb_ReleaseDirSearch(dsp);
4264 return CM_ERROR_INVAL;
4267 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO)
4268 searchFlags &= ~4; /* no resume keys */
4270 dirListPatchesp = NULL;
4272 maxReturnData = p->maxReturnData;
4273 if (p->opcode == 1) /* find first */
4274 maxReturnParms = 10; /* bytes */
4276 maxReturnParms = 8; /* bytes */
4278 #ifndef CM_CONFIG_MULTITRAN2RESPONSES
4279 if (maxReturnData > 6000)
4280 maxReturnData = 6000;
4281 #endif /* CM_CONFIG_MULTITRAN2RESPONSES */
4283 outp = smb_GetTran2ResponsePacket(vcp, p, opx, maxReturnParms,
4286 osi_Log2(smb_logp, "T2 receive search dir count %d [%s]",
4287 maxCount, osi_LogSaveString(smb_logp, pathp));
4289 /* bail out if request looks bad */
4290 if (p->opcode == 1 && !pathp) {
4291 smb_ReleaseDirSearch(dsp);
4292 smb_FreeTran2Packet(outp);
4293 return CM_ERROR_BADSMB;
4296 osi_Log3(smb_logp, "T2 search dir id %d, nextCookie 0x%x, attr 0x%x",
4297 dsp->cookie, nextCookie, attribute);
4299 userp = smb_GetTran2User(vcp, p);
4301 osi_Log1(smb_logp, "T2 search dir unable to resolve user [%d]", p->uid);
4302 smb_ReleaseDirSearch(dsp);
4303 smb_FreeTran2Packet(outp);
4304 return CM_ERROR_BADSMB;
4307 /* try to get the vnode for the path name next */
4308 lock_ObtainMutex(&dsp->mx);
4314 spacep = cm_GetSpace();
4315 smb_StripLastComponent(spacep->data, NULL, pathp);
4316 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
4318 cm_ReleaseUser(userp);
4319 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOFILES);
4320 smb_FreeTran2Packet(outp);
4321 lock_ReleaseMutex(&dsp->mx);
4322 smb_DeleteDirSearch(dsp);
4323 smb_ReleaseDirSearch(dsp);
4326 code = cm_NameI(cm_data.rootSCachep, spacep->data,
4327 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
4328 userp, tidPathp, &req, &scp);
4329 cm_FreeSpace(spacep);
4332 #ifdef DFS_SUPPORT_BUT_NOT_FIND_FIRST
4333 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
4334 cm_ReleaseSCache(scp);
4335 cm_ReleaseUser(userp);
4336 if ( WANTS_DFS_PATHNAMES(p) )
4337 code = CM_ERROR_PATH_NOT_COVERED;
4339 code = CM_ERROR_BADSHARENAME;
4340 smb_SendTran2Error(vcp, p, opx, code);
4341 smb_FreeTran2Packet(outp);
4342 lock_ReleaseMutex(&dsp->mx);
4343 smb_DeleteDirSearch(dsp);
4344 smb_ReleaseDirSearch(dsp);
4347 #endif /* DFS_SUPPORT */
4349 /* we need one hold for the entry we just stored into,
4350 * and one for our own processing. When we're done
4351 * with this function, we'll drop the one for our own
4352 * processing. We held it once from the namei call,
4353 * and so we do another hold now.
4356 lock_ObtainMutex(&scp->mx);
4357 if ((scp->flags & CM_SCACHEFLAG_BULKSTATTING) == 0 &&
4358 LargeIntegerGreaterOrEqualToZero(scp->bulkStatProgress)) {
4359 scp->flags |= CM_SCACHEFLAG_BULKSTATTING;
4360 dsp->flags |= SMB_DIRSEARCH_BULKST;
4362 lock_ReleaseMutex(&scp->mx);
4365 lock_ReleaseMutex(&dsp->mx);
4367 cm_ReleaseUser(userp);
4368 smb_FreeTran2Packet(outp);
4369 smb_DeleteDirSearch(dsp);
4370 smb_ReleaseDirSearch(dsp);
4374 /* get the directory size */
4375 lock_ObtainMutex(&scp->mx);
4376 code = cm_SyncOp(scp, NULL, userp, &req, 0,
4377 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4379 lock_ReleaseMutex(&scp->mx);
4380 cm_ReleaseSCache(scp);
4381 cm_ReleaseUser(userp);
4382 smb_FreeTran2Packet(outp);
4383 smb_DeleteDirSearch(dsp);
4384 smb_ReleaseDirSearch(dsp);
4388 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4391 dirLength = scp->length;
4393 bufferOffset.LowPart = bufferOffset.HighPart = 0;
4394 curOffset.HighPart = 0;
4395 curOffset.LowPart = nextCookie;
4396 origOp = outp->datap;
4404 if (searchFlags & 4)
4405 /* skip over resume key */
4408 /* make sure that curOffset.LowPart doesn't point to the first
4409 * 32 bytes in the 2nd through last dir page, and that it doesn't
4410 * point at the first 13 32-byte chunks in the first dir page,
4411 * since those are dir and page headers, and don't contain useful
4414 temp = curOffset.LowPart & (2048-1);
4415 if (curOffset.HighPart == 0 && curOffset.LowPart < 2048) {
4416 /* we're in the first page */
4417 if (temp < 13*32) temp = 13*32;
4420 /* we're in a later dir page */
4421 if (temp < 32) temp = 32;
4424 /* make sure the low order 5 bits are zero */
4427 /* now put temp bits back ito curOffset.LowPart */
4428 curOffset.LowPart &= ~(2048-1);
4429 curOffset.LowPart |= temp;
4431 /* check if we've passed the dir's EOF */
4432 if (LargeIntegerGreaterThanOrEqualTo(curOffset, dirLength)) {
4433 osi_Log0(smb_logp, "T2 search dir passed eof");
4438 /* check if we've returned all the names that will fit in the
4439 * response packet; we check return count as well as the number
4440 * of bytes requested. We check the # of bytes after we find
4441 * the dir entry, since we'll need to check its size.
4443 if (returnedNames >= maxCount) {
4444 osi_Log2(smb_logp, "T2 search dir returnedNames %d >= maxCount %d",
4445 returnedNames, maxCount);
4449 /* see if we can use the bufferp we have now; compute in which
4450 * page the current offset would be, and check whether that's
4451 * the offset of the buffer we have. If not, get the buffer.
4453 thyper.HighPart = curOffset.HighPart;
4454 thyper.LowPart = curOffset.LowPart & ~(cm_data.buf_blockSize-1);
4455 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
4458 buf_Release(bufferp);
4461 lock_ReleaseMutex(&scp->mx);
4462 lock_ObtainRead(&scp->bufCreateLock);
4463 code = buf_Get(scp, &thyper, &bufferp);
4464 lock_ReleaseRead(&scp->bufCreateLock);
4465 lock_ObtainMutex(&dsp->mx);
4467 /* now, if we're doing a star match, do bulk fetching
4468 * of all of the status info for files in the dir.
4471 smb_ApplyV3DirListPatches(scp, &dirListPatchesp,
4474 lock_ObtainMutex(&scp->mx);
4475 if ((dsp->flags & SMB_DIRSEARCH_BULKST) &&
4476 LargeIntegerGreaterThanOrEqualTo(thyper, scp->bulkStatProgress)) {
4477 /* Don't bulk stat if risking timeout */
4478 int now = GetTickCount();
4479 if (now - req.startTime > RDRtimeout) {
4480 scp->bulkStatProgress = thyper;
4481 scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
4482 dsp->flags &= ~SMB_DIRSEARCH_BULKST;
4484 code = cm_TryBulkStat(scp, &thyper, userp, &req);
4487 lock_ObtainMutex(&scp->mx);
4489 lock_ReleaseMutex(&dsp->mx);
4491 osi_Log2(smb_logp, "T2 search dir buf_Get scp %x failed %d", scp, code);
4495 bufferOffset = thyper;
4497 /* now get the data in the cache */
4499 code = cm_SyncOp(scp, bufferp, userp, &req,
4501 CM_SCACHESYNC_NEEDCALLBACK
4502 | CM_SCACHESYNC_READ);
4504 osi_Log2(smb_logp, "T2 search dir cm_SyncOp scp %x failed %d", scp, code);
4508 cm_SyncOpDone(scp, bufferp, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ);
4510 if (cm_HaveBuffer(scp, bufferp, 0)) {
4511 osi_Log2(smb_logp, "T2 search dir !HaveBuffer scp %x bufferp %x", scp, bufferp);
4515 /* otherwise, load the buffer and try again */
4516 code = cm_GetBuffer(scp, bufferp, NULL, userp,
4519 osi_Log3(smb_logp, "T2 search dir cm_GetBuffer failed scp %x bufferp %x code %d",
4520 scp, bufferp, code);
4525 buf_Release(bufferp);
4529 } /* if (wrong buffer) ... */
4531 /* now we have the buffer containing the entry we're interested
4532 * in; copy it out if it represents a non-deleted entry.
4534 entryInDir = curOffset.LowPart & (2048-1);
4535 entryInBuffer = curOffset.LowPart & (cm_data.buf_blockSize - 1);
4537 /* page header will help tell us which entries are free. Page
4538 * header can change more often than once per buffer, since
4539 * AFS 3 dir page size may be less than (but not more than)
4540 * a buffer package buffer.
4542 /* only look intra-buffer */
4543 temp = curOffset.LowPart & (cm_data.buf_blockSize - 1);
4544 temp &= ~(2048 - 1); /* turn off intra-page bits */
4545 pageHeaderp = (cm_pageHeader_t *) (bufferp->datap + temp);
4547 /* now determine which entry we're looking at in the page.
4548 * If it is free (there's a free bitmap at the start of the
4549 * dir), we should skip these 32 bytes.
4551 slotInPage = (entryInDir & 0x7e0) >> 5;
4552 if (!(pageHeaderp->freeBitmap[slotInPage>>3] &
4553 (1 << (slotInPage & 0x7)))) {
4554 /* this entry is free */
4555 numDirChunks = 1; /* only skip this guy */
4559 tp = bufferp->datap + entryInBuffer;
4560 dep = (cm_dirEntry_t *) tp; /* now points to AFS3 dir entry */
4562 /* while we're here, compute the next entry's location, too,
4563 * since we'll need it when writing out the cookie into the dir
4566 * XXXX Probably should do more sanity checking.
4568 numDirChunks = cm_NameEntries(dep->name, &onbytes);
4570 /* compute offset of cookie representing next entry */
4571 nextEntryCookie = curOffset.LowPart + (CM_DIR_CHUNKSIZE * numDirChunks);
4573 /* Need 8.3 name? */
4575 if (infoLevel == SMB_FIND_FILE_BOTH_DIRECTORY_INFO
4576 && dep->fid.vnode != 0
4577 && !cm_Is8Dot3(dep->name)) {
4578 cm_Gen8Dot3Name(dep, shortName, &shortNameEnd);
4582 osi_Log4(smb_logp, "T2 search dir vn %u uniq %u name %s (%s)",
4583 dep->fid.vnode, dep->fid.unique,
4584 osi_LogSaveString(smb_logp, dep->name),
4585 NeedShortName ? osi_LogSaveString(smb_logp, shortName) : "");
4587 /* When matching, we are using doing a case fold if we have a wildcard mask.
4588 * If we get a non-wildcard match, it's a lookup for a specific file.
4590 if (dep->fid.vnode != 0 &&
4591 (smb_V3MatchMask(dep->name, maskp, (starPattern? CM_FLAG_CASEFOLD : 0)) ||
4593 smb_V3MatchMask(shortName, maskp, CM_FLAG_CASEFOLD)))) {
4595 /* Eliminate entries that don't match requested attributes */
4596 if (smb_hideDotFiles && !(dsp->attribute & SMB_ATTR_HIDDEN) &&
4597 smb_IsDotFile(dep->name)) {
4598 osi_Log0(smb_logp, "T2 search dir skipping hidden");
4599 goto nextEntry; /* no hidden files */
4601 if (!(dsp->attribute & SMB_ATTR_DIRECTORY)) /* no directories */
4603 /* We have already done the cm_TryBulkStat above */
4604 fid.cell = scp->fid.cell;
4605 fid.volume = scp->fid.volume;
4606 fid.vnode = ntohl(dep->fid.vnode);
4607 fid.unique = ntohl(dep->fid.unique);
4608 fileType = cm_FindFileType(&fid);
4609 /*osi_Log2(smb_logp, "smb_ReceiveTran2SearchDir: file %s "
4610 "has filetype %d", dep->name,
4612 if (fileType == CM_SCACHETYPE_DIRECTORY ||
4613 fileType == CM_SCACHETYPE_DFSLINK ||
4614 fileType == CM_SCACHETYPE_INVALID)
4615 osi_Log0(smb_logp, "T2 search dir skipping directory or bad link");
4619 /* finally check if this name will fit */
4621 /* standard dir entry stuff */
4622 if (infoLevel < 0x101)
4623 ohbytes = 23; /* pre-NT */
4624 else if (infoLevel == SMB_FIND_FILE_NAMES_INFO)
4625 ohbytes = 12; /* NT names only */
4627 ohbytes = 64; /* NT */
4629 if (infoLevel == SMB_FIND_FILE_BOTH_DIRECTORY_INFO)
4630 ohbytes += 26; /* Short name & length */
4632 if (searchFlags & 4) {
4633 ohbytes += 4; /* if resume key required */
4636 if (infoLevel != SMB_INFO_STANDARD
4637 && infoLevel != SMB_FIND_FILE_DIRECTORY_INFO
4638 && infoLevel != SMB_FIND_FILE_NAMES_INFO)
4639 ohbytes += 4; /* EASIZE */
4641 /* add header to name & term. null */
4642 orbytes = onbytes + ohbytes + 1;
4644 /* now, we round up the record to a 4 byte alignment,
4645 * and we make sure that we have enough room here for
4646 * even the aligned version (so we don't have to worry
4647 * about an * overflow when we pad things out below).
4648 * That's the reason for the alignment arithmetic below.
4650 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO)
4651 align = (4 - (orbytes & 3)) & 3;
4654 if (orbytes + bytesInBuffer + align > maxReturnData) {
4655 osi_Log1(smb_logp, "T2 dir search exceed max return data %d",
4660 /* this is one of the entries to use: it is not deleted
4661 * and it matches the star pattern we're looking for.
4662 * Put out the name, preceded by its length.
4664 /* First zero everything else */
4665 memset(origOp, 0, ohbytes);
4667 if (infoLevel <= SMB_FIND_FILE_DIRECTORY_INFO)
4668 *(origOp + ohbytes - 1) = (unsigned char) onbytes;
4669 else if (infoLevel == SMB_FIND_FILE_NAMES_INFO)
4670 *((u_long *)(op + 8)) = onbytes;
4672 *((u_long *)(op + 60)) = onbytes;
4673 strcpy(origOp+ohbytes, dep->name);
4674 if (smb_StoreAnsiFilenames)
4675 CharToOem(origOp+ohbytes, origOp+ohbytes);
4677 /* Short name if requested and needed */
4678 if (infoLevel == SMB_FIND_FILE_BOTH_DIRECTORY_INFO) {
4679 if (NeedShortName) {
4680 strcpy(op + 70, shortName);
4681 if (smb_StoreAnsiFilenames)
4682 CharToOem(op + 70, op + 70);
4683 *(op + 68) = (char)(shortNameEnd - shortName);
4687 /* now, adjust the # of entries copied */
4690 /* NextEntryOffset and FileIndex */
4691 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO) {
4692 int entryOffset = orbytes + align;
4693 *((u_long *)op) = entryOffset;
4694 *((u_long *)(op+4)) = nextEntryCookie;
4697 /* now we emit the attribute. This is tricky, since
4698 * we need to really stat the file to find out what
4699 * type of entry we've got. Right now, we're copying
4700 * out data from a buffer, while holding the scp
4701 * locked, so it isn't really convenient to stat
4702 * something now. We'll put in a place holder
4703 * now, and make a second pass before returning this
4704 * to get the real attributes. So, we just skip the
4705 * data for now, and adjust it later. We allocate a
4706 * patch record to make it easy to find this point
4707 * later. The replay will happen at a time when it is
4708 * safe to unlock the directory.
4710 if (infoLevel != SMB_FIND_FILE_NAMES_INFO) {
4711 curPatchp = malloc(sizeof(*curPatchp));
4712 osi_QAdd((osi_queue_t **) &dirListPatchesp,
4714 curPatchp->dptr = op;
4715 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO)
4716 curPatchp->dptr += 8;
4718 if (smb_hideDotFiles && smb_IsDotFile(dep->name)) {
4719 curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
4722 curPatchp->flags = 0;
4724 curPatchp->fid.cell = scp->fid.cell;
4725 curPatchp->fid.volume = scp->fid.volume;
4726 curPatchp->fid.vnode = ntohl(dep->fid.vnode);
4727 curPatchp->fid.unique = ntohl(dep->fid.unique);
4730 curPatchp->dep = dep;
4733 if (searchFlags & 4)
4734 /* put out resume key */
4735 *((u_long *)origOp) = nextEntryCookie;
4737 /* Adjust byte ptr and count */
4738 origOp += orbytes; /* skip entire record */
4739 bytesInBuffer += orbytes;
4741 /* and pad the record out */
4742 while (--align >= 0) {
4746 } /* if we're including this name */
4747 else if (!starPattern &&
4749 dep->fid.vnode != 0 &&
4750 smb_V3MatchMask(dep->name, maskp, CM_FLAG_CASEFOLD)) {
4751 /* We were looking for exact matches, but here's an inexact one*/
4756 /* and adjust curOffset to be where the new cookie is */
4757 thyper.HighPart = 0;
4758 thyper.LowPart = CM_DIR_CHUNKSIZE * numDirChunks;
4759 curOffset = LargeIntegerAdd(thyper, curOffset);
4760 } /* while copying data for dir listing */
4762 /* If we didn't get a star pattern, we did an exact match during the first pass.
4763 * If there were no exact matches found, we fail over to inexact matches by
4764 * marking the query as a star pattern (matches all case permutations), and
4765 * re-running the query.
4767 if (returnedNames == 0 && !starPattern && foundInexact) {
4768 osi_Log0(afsd_logp,"T2 Search: No exact matches. Re-running for inexact matches");
4773 /* release the mutex */
4774 lock_ReleaseMutex(&scp->mx);
4776 buf_Release(bufferp);
4780 /* apply and free last set of patches; if not doing a star match, this
4781 * will be empty, but better safe (and freeing everything) than sorry.
4783 code2 = smb_ApplyV3DirListPatches(scp, &dirListPatchesp, infoLevel, userp,
4786 /* now put out the final parameters */
4787 if (returnedNames == 0)
4789 if (p->opcode == 1) {
4791 outp->parmsp[0] = (unsigned short) dsp->cookie;
4792 outp->parmsp[1] = returnedNames;
4793 outp->parmsp[2] = eos;
4794 outp->parmsp[3] = 0; /* nothing wrong with EAS */
4795 outp->parmsp[4] = 0;
4796 /* don't need last name to continue
4797 * search, cookie is enough. Normally,
4798 * this is the offset of the file name
4799 * of the last entry returned.
4801 outp->totalParms = 10; /* in bytes */
4805 outp->parmsp[0] = returnedNames;
4806 outp->parmsp[1] = eos;
4807 outp->parmsp[2] = 0; /* EAS error */
4808 outp->parmsp[3] = 0; /* last name, as above */
4809 outp->totalParms = 8; /* in bytes */
4812 /* return # of bytes in the buffer */
4813 outp->totalData = bytesInBuffer;
4815 /* Return error code if unsuccessful on first request */
4816 if (code == 0 && p->opcode == 1 && returnedNames == 0)
4817 code = CM_ERROR_NOSUCHFILE;
4819 osi_Log4(smb_logp, "T2 search dir done, opcode %d, id %d, %d names, code %d",
4820 p->opcode, dsp->cookie, returnedNames, code);
4822 /* if we're supposed to close the search after this request, or if
4823 * we're supposed to close the search if we're done, and we're done,
4824 * or if something went wrong, close the search.
4826 /* ((searchFlags & 1) || ((searchFlags & 2) && eos) */
4827 if ((searchFlags & 1) || (returnedNames == 0) ||
4828 ((searchFlags & 2) && eos) || code != 0)
4829 smb_DeleteDirSearch(dsp);
4831 smb_SendTran2Error(vcp, p, opx, code);
4833 smb_SendTran2Packet(vcp, outp, opx);
4835 smb_FreeTran2Packet(outp);
4836 smb_ReleaseDirSearch(dsp);
4837 cm_ReleaseSCache(scp);
4838 cm_ReleaseUser(userp);
4842 long smb_ReceiveV3FindClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4845 smb_dirSearch_t *dsp;
4847 dirHandle = smb_GetSMBParm(inp, 0);
4849 osi_Log1(smb_logp, "SMB3 find close handle %d", dirHandle);
4851 dsp = smb_FindDirSearch(dirHandle);
4854 return CM_ERROR_BADFD;
4856 /* otherwise, we have an FD to destroy */
4857 smb_DeleteDirSearch(dsp);
4858 smb_ReleaseDirSearch(dsp);
4860 /* and return results */
4861 smb_SetSMBDataLength(outp, 0);
4866 long smb_ReceiveV3FindNotifyClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4868 smb_SetSMBDataLength(outp, 0);
4872 long smb_ReceiveV3OpenX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4879 cm_scache_t *dscp; /* dir we're dealing with */
4880 cm_scache_t *scp; /* file we're creating */
4882 int initialModeBits;
4892 int parmSlot; /* which parm we're dealing with */
4901 extraInfo = (smb_GetSMBParm(inp, 2) & 1); /* return extra info */
4902 openFun = smb_GetSMBParm(inp, 8); /* open function */
4903 excl = ((openFun & 3) == 0);
4904 trunc = ((openFun & 3) == 2); /* truncate it */
4905 openMode = (smb_GetSMBParm(inp, 3) & 0x7);
4906 openAction = 0; /* tracks what we did */
4908 attributes = smb_GetSMBParm(inp, 5);
4909 dosTime = smb_GetSMBParm(inp, 6) | (smb_GetSMBParm(inp, 7) << 16);
4911 /* compute initial mode bits based on read-only flag in attributes */
4912 initialModeBits = 0666;
4913 if (attributes & SMB_ATTR_READONLY)
4914 initialModeBits &= ~0222;
4916 pathp = smb_GetSMBData(inp, NULL);
4917 if (smb_StoreAnsiFilenames)
4918 OemToChar(pathp,pathp);
4920 spacep = inp->spacep;
4921 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
4923 if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
4924 /* special case magic file name for receiving IOCTL requests
4925 * (since IOCTL calls themselves aren't getting through).
4928 osi_Log0(smb_logp, "IOCTL Open");
4931 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
4932 smb_SetupIoctlFid(fidp, spacep);
4934 /* set inp->fid so that later read calls in same msg can find fid */
4935 inp->fid = fidp->fid;
4937 /* copy out remainder of the parms */
4939 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
4941 smb_SetSMBParm(outp, parmSlot, /* attrs */ 0); parmSlot++;
4942 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* mod time */
4943 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
4944 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* len */
4945 smb_SetSMBParm(outp, parmSlot, 0x7fff); parmSlot++;
4946 smb_SetSMBParm(outp, parmSlot, openMode); parmSlot++;
4947 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* file type 0 ==> normal file or dir */
4948 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* IPC junk */
4950 /* and the final "always present" stuff */
4951 smb_SetSMBParm(outp, parmSlot, /* openAction found existing file */ 1); parmSlot++;
4952 /* next write out the "unique" ID */
4953 smb_SetSMBParm(outp, parmSlot, 0x1234); parmSlot++;
4954 smb_SetSMBParm(outp, parmSlot, 0x5678); parmSlot++;
4955 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
4956 smb_SetSMBDataLength(outp, 0);
4958 /* and clean up fid reference */
4959 smb_ReleaseFID(fidp);
4963 #ifdef DEBUG_VERBOSE
4965 char *hexp, *asciip;
4966 asciip = (lastNamep ? lastNamep : pathp );
4967 hexp = osi_HexifyString(asciip);
4968 DEBUG_EVENT2("AFS", "V3Open H[%s] A[%s]", hexp, asciip );
4972 userp = smb_GetUserFromVCP(vcp, inp);
4975 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4977 cm_ReleaseUser(userp);
4978 return CM_ERROR_NOSUCHPATH;
4980 code = cm_NameI(cm_data.rootSCachep, pathp,
4981 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
4982 userp, tidPathp, &req, &scp);
4985 if (code == 0 && scp->fileType == CM_SCACHETYPE_DFSLINK) {
4986 cm_ReleaseSCache(scp);
4987 cm_ReleaseUser(userp);
4988 if ( WANTS_DFS_PATHNAMES(inp) )
4989 return CM_ERROR_PATH_NOT_COVERED;
4991 return CM_ERROR_BADSHARENAME;
4993 #endif /* DFS_SUPPORT */
4996 code = cm_NameI(cm_data.rootSCachep, spacep->data,
4997 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
4998 userp, tidPathp, &req, &dscp);
5000 cm_ReleaseUser(userp);
5005 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
5006 cm_ReleaseSCache(dscp);
5007 cm_ReleaseUser(userp);
5008 if ( WANTS_DFS_PATHNAMES(inp) )
5009 return CM_ERROR_PATH_NOT_COVERED;
5011 return CM_ERROR_BADSHARENAME;
5013 #endif /* DFS_SUPPORT */
5014 /* otherwise, scp points to the parent directory. Do a lookup,
5015 * and truncate the file if we find it, otherwise we create the
5022 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD, userp,
5024 if (code && code != CM_ERROR_NOSUCHFILE) {
5025 cm_ReleaseSCache(dscp);
5026 cm_ReleaseUser(userp);
5031 /* if we get here, if code is 0, the file exists and is represented by
5032 * scp. Otherwise, we have to create it. The dir may be represented
5033 * by dscp, or we may have found the file directly. If code is non-zero,
5037 code = cm_CheckOpen(scp, openMode, trunc, userp, &req);
5039 if (dscp) cm_ReleaseSCache(dscp);
5040 cm_ReleaseSCache(scp);
5041 cm_ReleaseUser(userp);
5046 /* oops, file shouldn't be there */
5048 cm_ReleaseSCache(dscp);
5049 cm_ReleaseSCache(scp);
5050 cm_ReleaseUser(userp);
5051 return CM_ERROR_EXISTS;
5055 setAttr.mask = CM_ATTRMASK_LENGTH;
5056 setAttr.length.LowPart = 0;
5057 setAttr.length.HighPart = 0;
5058 code = cm_SetAttr(scp, &setAttr, userp, &req);
5059 openAction = 3; /* truncated existing file */
5061 else openAction = 1; /* found existing file */
5063 else if (!(openFun & SMB_ATTR_DIRECTORY)) {
5064 /* don't create if not found */
5065 if (dscp) cm_ReleaseSCache(dscp);
5066 cm_ReleaseUser(userp);
5067 return CM_ERROR_NOSUCHFILE;
5070 osi_assert(dscp != NULL);
5071 osi_Log1(smb_logp, "smb_ReceiveV3OpenX creating file %s",
5072 osi_LogSaveString(smb_logp, lastNamep));
5073 openAction = 2; /* created file */
5074 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
5075 smb_UnixTimeFromDosUTime(&setAttr.clientModTime, dosTime);
5076 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
5080 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
5081 smb_NotifyChange(FILE_ACTION_ADDED,
5082 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
5083 dscp, lastNamep, NULL, TRUE);
5084 } else if (!excl && code == CM_ERROR_EXISTS) {
5085 /* not an exclusive create, and someone else tried
5086 * creating it already, then we open it anyway. We
5087 * don't bother retrying after this, since if this next
5088 * fails, that means that the file was deleted after we
5089 * started this call.
5091 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
5095 setAttr.mask = CM_ATTRMASK_LENGTH;
5096 setAttr.length.LowPart = 0;
5097 setAttr.length.HighPart = 0;
5098 code = cm_SetAttr(scp, &setAttr, userp, &req);
5100 } /* lookup succeeded */
5104 /* we don't need this any longer */
5106 cm_ReleaseSCache(dscp);
5109 /* something went wrong creating or truncating the file */
5111 cm_ReleaseSCache(scp);
5112 cm_ReleaseUser(userp);
5116 /* make sure we're about to open a file */
5117 if (scp->fileType != CM_SCACHETYPE_FILE) {
5118 cm_ReleaseSCache(scp);
5119 cm_ReleaseUser(userp);
5120 return CM_ERROR_ISDIR;
5123 /* now all we have to do is open the file itself */
5124 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
5128 lock_ObtainMutex(&fidp->mx);
5129 /* save a pointer to the vnode */
5132 fidp->userp = userp;
5134 /* compute open mode */
5136 fidp->flags |= SMB_FID_OPENREAD;
5137 if (openMode == 1 || openMode == 2)
5138 fidp->flags |= SMB_FID_OPENWRITE;
5140 /* remember if the file was newly created */
5142 fidp->flags |= SMB_FID_CREATED;
5144 lock_ReleaseMutex(&fidp->mx);
5145 smb_ReleaseFID(fidp);
5147 cm_Open(scp, 0, userp);
5149 /* set inp->fid so that later read calls in same msg can find fid */
5150 inp->fid = fidp->fid;
5152 /* copy out remainder of the parms */
5154 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
5155 lock_ObtainMutex(&scp->mx);
5157 smb_SetSMBParm(outp, parmSlot, smb_Attributes(scp)); parmSlot++;
5158 smb_DosUTimeFromUnixTime(&dosTime, scp->clientModTime);
5159 smb_SetSMBParm(outp, parmSlot, dosTime & 0xffff); parmSlot++;
5160 smb_SetSMBParm(outp, parmSlot, (dosTime>>16) & 0xffff); parmSlot++;
5161 smb_SetSMBParm(outp, parmSlot, scp->length.LowPart & 0xffff); parmSlot++;
5162 smb_SetSMBParm(outp, parmSlot, (scp->length.LowPart >> 16) & 0xffff); parmSlot++;
5163 smb_SetSMBParm(outp, parmSlot, openMode); parmSlot++;
5164 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* file type 0 ==> normal file or dir */
5165 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* IPC junk */
5167 /* and the final "always present" stuff */
5168 smb_SetSMBParm(outp, parmSlot, openAction); parmSlot++;
5169 /* next write out the "unique" ID */
5170 smb_SetSMBParm(outp, parmSlot, scp->fid.vnode & 0xffff); parmSlot++;
5171 smb_SetSMBParm(outp, parmSlot, scp->fid.volume & 0xffff); parmSlot++;
5172 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
5173 lock_ReleaseMutex(&scp->mx);
5174 smb_SetSMBDataLength(outp, 0);
5176 osi_Log1(smb_logp, "SMB OpenX opening fid %d", fidp->fid);
5178 cm_ReleaseUser(userp);
5179 /* leave scp held since we put it in fidp->scp */
5183 static void smb_GetLockParams(unsigned char LockType,
5185 unsigned int * ppid,
5186 LARGE_INTEGER * pOffset,
5187 LARGE_INTEGER * pLength)
5189 if (LockType & LOCKING_ANDX_LARGE_FILES) {
5191 *ppid = *((USHORT *) *buf);
5192 pOffset->HighPart = *((LONG *)(*buf + 4));
5193 pOffset->LowPart = *((DWORD *)(*buf + 8));
5194 pLength->HighPart = *((LONG *)(*buf + 12));
5195 pLength->LowPart = *((DWORD *)(*buf + 16));
5199 /* Not Large Files */
5200 *ppid = *((USHORT *) *buf);
5201 pOffset->HighPart = 0;
5202 pOffset->LowPart = *((DWORD *)(*buf + 2));
5203 pLength->HighPart = 0;
5204 pLength->LowPart = *((DWORD *)(*buf + 6));
5209 long smb_ReceiveV3LockingX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5216 unsigned char LockType;
5217 unsigned short NumberOfUnlocks, NumberOfLocks;
5221 LARGE_INTEGER LOffset, LLength;
5222 smb_waitingLockRequest_t *wlRequest = NULL;
5223 cm_file_lock_t *lockp;
5231 fid = smb_GetSMBParm(inp, 2);
5232 fid = smb_ChainFID(fid, inp);
5234 fidp = smb_FindFID(vcp, fid, 0);
5236 return CM_ERROR_BADFD;
5238 lock_ObtainMutex(&fidp->mx);
5239 if (fidp->flags & SMB_FID_IOCTL) {
5240 osi_Log0(smb_logp, "smb_ReceiveV3Locking BadFD");
5241 lock_ReleaseMutex(&fidp->mx);
5242 smb_ReleaseFID(fidp);
5243 return CM_ERROR_BADFD;
5247 lock_ReleaseMutex(&fidp->mx);
5249 /* set inp->fid so that later read calls in same msg can find fid */
5252 userp = smb_GetUserFromVCP(vcp, inp);
5255 lock_ObtainMutex(&scp->mx);
5256 code = cm_SyncOp(scp, NULL, userp, &req, 0,
5257 CM_SCACHESYNC_NEEDCALLBACK
5258 | CM_SCACHESYNC_GETSTATUS
5259 | CM_SCACHESYNC_LOCK);
5261 osi_Log1(smb_logp, "smb_ReceiveV3Locking SyncOp failure code 0x%x", code);
5265 LockType = smb_GetSMBParm(inp, 3) & 0xff;
5266 Timeout = (smb_GetSMBParm(inp, 5) << 16) + smb_GetSMBParm(inp, 4);
5267 NumberOfUnlocks = smb_GetSMBParm(inp, 6);
5268 NumberOfLocks = smb_GetSMBParm(inp, 7);
5270 if ((LockType & LOCKING_ANDX_CANCEL_LOCK) ||
5271 (LockType & LOCKING_ANDX_CHANGE_LOCKTYPE)) {
5273 /* We don't support these requests. Apparently, we can safely
5274 not deal with them too. */
5275 osi_Log1(smb_logp, "smb_ReceiveV3Locking received unsupported request [%s]",
5276 ((LockType & LOCKING_ANDX_CANCEL_LOCK)?
5277 "LOCKING_ANDX_CANCEL_LOCK":
5278 "LOCKING_ANDX_CHANGE_LOCKTYPE"));
5279 /* No need to call osi_LogSaveString since these are string
5282 code = CM_ERROR_BADOP;
5287 op = smb_GetSMBData(inp, NULL);
5289 for (i=0; i<NumberOfUnlocks; i++) {
5290 smb_GetLockParams(LockType, &op, &pid, &LOffset, &LLength);
5292 key = cm_GenerateKey(vcp->vcID, pid, fidp->fid);
5294 code = cm_Unlock(scp, LockType, LOffset, LLength, key, userp, &req);
5302 for (i=0; i<NumberOfLocks; i++) {
5303 smb_GetLockParams(LockType, &op, &pid, &LOffset, &LLength);
5305 key = cm_GenerateKey(vcp->vcID, pid, fidp->fid);
5307 code = cm_Lock(scp, LockType, LOffset, LLength, key, (Timeout != 0),
5308 userp, &req, &lockp);
5310 if (code == CM_ERROR_WOULDBLOCK && Timeout != 0) {
5311 smb_waitingLock_t * wLock;
5313 /* Put on waiting list */
5314 if(wlRequest == NULL) {
5318 LARGE_INTEGER tOffset, tLength;
5320 wlRequest = malloc(sizeof(smb_waitingLockRequest_t));
5322 osi_assert(wlRequest != NULL);
5324 wlRequest->vcp = vcp;
5326 wlRequest->scp = scp;
5328 wlRequest->inp = smb_CopyPacket(inp);
5329 wlRequest->outp = smb_CopyPacket(outp);
5330 wlRequest->lockType = LockType;
5331 wlRequest->timeRemaining = Timeout;
5332 wlRequest->locks = NULL;
5334 /* The waiting lock request needs to have enough
5335 information to undo all the locks in the request.
5336 We do the following to store info about locks that
5337 have already been granted. Sure, we can get most
5338 of the info from the packet, but the packet doesn't
5339 hold the result of cm_Lock call. In practice we
5340 only receive packets with one or two locks, so we
5341 are only wasting a few bytes here and there and
5342 only for a limited period of time until the waiting
5343 lock times out or is freed. */
5345 for(opt = op_locks, j=i; j > 0; j--) {
5346 smb_GetLockParams(LockType, &opt, &pid, &tOffset, &tLength);
5348 tkey = cm_GenerateKey(vcp->vcID, pid, fidp->fid);
5350 wLock = malloc(sizeof(smb_waitingLock_t));
5352 osi_assert(wLock != NULL);
5355 wLock->LOffset = tOffset;
5356 wLock->LLength = tLength;
5357 wLock->lockp = NULL;
5358 wLock->state = SMB_WAITINGLOCKSTATE_DONE;
5359 osi_QAdd((osi_queue_t **) &wlRequest->locks,
5364 wLock = malloc(sizeof(smb_waitingLock_t));
5366 osi_assert(wLock != NULL);
5369 wLock->LOffset = LOffset;
5370 wLock->LLength = LLength;
5371 wLock->lockp = lockp;
5372 wLock->state = SMB_WAITINGLOCKSTATE_WAITING;
5373 osi_QAdd((osi_queue_t **) &wlRequest->locks,
5376 osi_Log1(smb_logp, "smb_ReceiveV3Locking WaitingLock created 0x%p",
5384 osi_Log1(smb_logp, "smb_ReceiveV3Locking cm_Lock failure code 0x%x", code);
5391 /* Since something went wrong with the lock number i, we now
5392 have to go ahead and release any locks acquired before the
5393 failure. All locks before lock number i (of which there
5394 are i of them) have either been successful or are waiting.
5395 Either case requires calling cm_Unlock(). */
5397 /* And purge the waiting lock */
5398 if(wlRequest != NULL) {
5399 smb_waitingLock_t * wl;
5400 smb_waitingLock_t * wlNext;
5403 for(wl = wlRequest->locks; wl; wl = wlNext) {
5405 wlNext = (smb_waitingLock_t *) osi_QNext(&wl->q);
5407 ul_code = cm_Unlock(scp, LockType, wl->LOffset, wl->LLength, wl->key, userp, &req);
5410 osi_Log1(smb_logp, "smb_ReceiveV3Locking cm_Unlock returns code %d", ul_code);
5412 osi_Log0(smb_logp, "smb_ReceiveV3Locking cm_Unlock successful");
5415 osi_QRemove((osi_queue_t **) &wlRequest->locks, &wl->q);
5420 smb_ReleaseVC(wlRequest->vcp);
5421 cm_ReleaseSCache(wlRequest->scp);
5422 smb_FreePacket(wlRequest->inp);
5423 smb_FreePacket(wlRequest->outp);
5432 if (wlRequest != NULL) {
5434 lock_ObtainWrite(&smb_globalLock);
5435 osi_QAdd((osi_queue_t **)&smb_allWaitingLocks,
5437 osi_Wakeup((LONG_PTR)&smb_allWaitingLocks);
5438 lock_ReleaseWrite(&smb_globalLock);
5440 /* don't send reply immediately */
5441 outp->flags |= SMB_PACKETFLAG_NOSEND;
5444 smb_SetSMBDataLength(outp, 0);
5448 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_LOCK);
5451 lock_ReleaseMutex(&scp->mx);
5452 cm_ReleaseSCache(scp);
5453 cm_ReleaseUser(userp);
5454 smb_ReleaseFID(fidp);
5459 long smb_ReceiveV3GetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5465 afs_uint32 searchTime;
5471 fid = smb_GetSMBParm(inp, 0);
5472 fid = smb_ChainFID(fid, inp);
5474 fidp = smb_FindFID(vcp, fid, 0);
5476 return CM_ERROR_BADFD;
5478 lock_ObtainMutex(&fidp->mx);
5479 if (fidp->flags & SMB_FID_IOCTL) {
5480 lock_ReleaseMutex(&fidp->mx);
5481 smb_ReleaseFID(fidp);
5482 return CM_ERROR_BADFD;
5486 lock_ReleaseMutex(&fidp->mx);
5488 userp = smb_GetUserFromVCP(vcp, inp);
5491 /* otherwise, stat the file */
5492 lock_ObtainMutex(&scp->mx);
5493 code = cm_SyncOp(scp, NULL, userp, &req, 0,
5494 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5498 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5500 /* decode times. We need a search time, but the response to this
5501 * call provides the date first, not the time, as returned in the
5502 * searchTime variable. So we take the high-order bits first.
5504 smb_SearchTimeFromUnixTime(&searchTime, scp->clientModTime);
5505 smb_SetSMBParm(outp, 0, (searchTime >> 16) & 0xffff); /* ctime */
5506 smb_SetSMBParm(outp, 1, searchTime & 0xffff);
5507 smb_SetSMBParm(outp, 2, (searchTime >> 16) & 0xffff); /* atime */
5508 smb_SetSMBParm(outp, 3, searchTime & 0xffff);
5509 smb_SetSMBParm(outp, 4, (searchTime >> 16) & 0xffff); /* mtime */
5510 smb_SetSMBParm(outp, 5, searchTime & 0xffff);
5512 /* now handle file size and allocation size */
5513 smb_SetSMBParm(outp, 6, scp->length.LowPart & 0xffff); /* file size */
5514 smb_SetSMBParm(outp, 7, (scp->length.LowPart >> 16) & 0xffff);
5515 smb_SetSMBParm(outp, 8, scp->length.LowPart & 0xffff); /* alloc size */
5516 smb_SetSMBParm(outp, 9, (scp->length.LowPart >> 16) & 0xffff);
5518 /* file attribute */
5519 smb_SetSMBParm(outp, 10, smb_Attributes(scp));
5521 /* and finalize stuff */
5522 smb_SetSMBDataLength(outp, 0);
5526 lock_ReleaseMutex(&scp->mx);
5527 cm_ReleaseSCache(scp);
5528 cm_ReleaseUser(userp);
5529 smb_ReleaseFID(fidp);
5533 long smb_ReceiveV3SetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5539 afs_uint32 searchTime;
5547 fid = smb_GetSMBParm(inp, 0);
5548 fid = smb_ChainFID(fid, inp);
5550 fidp = smb_FindFID(vcp, fid, 0);
5552 return CM_ERROR_BADFD;
5554 lock_ObtainMutex(&fidp->mx);
5555 if (fidp->flags & SMB_FID_IOCTL) {
5556 lock_ReleaseMutex(&fidp->mx);
5557 smb_ReleaseFID(fidp);
5558 return CM_ERROR_BADFD;
5562 lock_ReleaseMutex(&fidp->mx);
5564 userp = smb_GetUserFromVCP(vcp, inp);
5567 /* now prepare to call cm_setattr. This message only sets various times,
5568 * and AFS only implements mtime, and we'll set the mtime if that's
5569 * requested. The others we'll ignore.
5571 searchTime = smb_GetSMBParm(inp, 5) | (smb_GetSMBParm(inp, 6) << 16);
5573 if (searchTime != 0) {
5574 smb_UnixTimeFromSearchTime(&unixTime, searchTime);
5576 if ( unixTime != -1 ) {
5577 attrs.mask = CM_ATTRMASK_CLIENTMODTIME;
5578 attrs.clientModTime = unixTime;
5579 code = cm_SetAttr(scp, &attrs, userp, &req);
5581 osi_Log1(smb_logp, "SMB receive V3SetAttributes [fid=%ld]", fid);
5583 osi_Log1(smb_logp, "**smb_UnixTimeFromSearchTime failed searchTime=%ld", searchTime);
5589 cm_ReleaseSCache(scp);
5590 cm_ReleaseUser(userp);
5591 smb_ReleaseFID(fidp);
5595 long smb_ReceiveV3WriteX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5598 long count, written = 0, total_written = 0;
5605 int inDataBlockCount;
5607 fd = smb_GetSMBParm(inp, 2);
5608 count = smb_GetSMBParm(inp, 10);
5610 offset.HighPart = 0;
5611 offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
5613 if (*inp->wctp == 14) {
5614 /* we have a request with 64-bit file offsets */
5615 #ifdef AFS_LARGEFILES
5616 offset.HighPart = smb_GetSMBParm(inp, 12) | (smb_GetSMBParm(inp, 13) << 16);
5618 if ((smb_GetSMBParm(inp, 12) | (smb_GetSMBParm(inp, 13) << 16)) != 0) {
5620 osi_Log0(smb_logp, "smb_ReceiveV3WriteX offset requires largefile support");
5621 /* we shouldn't have received this op if we didn't specify
5622 largefile support */
5623 return CM_ERROR_BADOP;
5628 op = inp->data + smb_GetSMBParm(inp, 11);
5629 inDataBlockCount = count;
5631 osi_Log4(smb_logp, "smb_ReceiveV3WriteX fid %d, off 0x%x:%08x, size 0x%x",
5632 fd, offset.HighPart, offset.LowPart, count);
5634 fd = smb_ChainFID(fd, inp);
5635 fidp = smb_FindFID(vcp, fd, 0);
5637 return CM_ERROR_BADFD;
5639 lock_ObtainMutex(&fidp->mx);
5640 if (fidp->flags & SMB_FID_IOCTL) {
5641 lock_ReleaseMutex(&fidp->mx);
5642 code = smb_IoctlV3Write(fidp, vcp, inp, outp);
5643 smb_ReleaseFID(fidp);
5646 lock_ReleaseMutex(&fidp->mx);
5647 userp = smb_GetUserFromVCP(vcp, inp);
5649 /* special case: 0 bytes transferred means there is no data
5650 transferred. A slight departure from SMB_COM_WRITE where this
5651 means that we are supposed to truncate the file at this
5656 LARGE_INTEGER LOffset;
5657 LARGE_INTEGER LLength;
5659 pid = ((smb_t *) inp)->pid;
5660 key = cm_GenerateKey(vcp->vcID, pid, fd);
5662 LOffset.HighPart = offset.HighPart;
5663 LOffset.LowPart = offset.LowPart;
5664 LLength.HighPart = 0;
5665 LLength.LowPart = count;
5667 lock_ObtainMutex(&fidp->scp->mx);
5668 code = cm_LockCheckWrite(fidp->scp, LOffset, LLength, key);
5669 lock_ReleaseMutex(&fidp->scp->mx);
5676 * Work around bug in NT client
5678 * When copying a file, the NT client should first copy the data,
5679 * then copy the last write time. But sometimes the NT client does
5680 * these in the wrong order, so the data copies would inadvertently
5681 * cause the last write time to be overwritten. We try to detect this,
5682 * and don't set client mod time if we think that would go against the
5685 lock_ObtainMutex(&fidp->mx);
5686 if ((fidp->flags & SMB_FID_MTIMESETDONE) != SMB_FID_MTIMESETDONE) {
5687 fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
5688 fidp->scp->clientModTime = time(NULL);
5690 lock_ReleaseMutex(&fidp->mx);
5693 while ( code == 0 && count > 0 ) {
5695 code = smb_WriteData(fidp, &offset, count, op, userp, &written);
5697 code = smb_WriteData(fidp, &offset, count, op, userp, &written, FALSE);
5699 if (code == 0 && written == 0)
5700 code = CM_ERROR_PARTIALWRITE;
5702 offset = LargeIntegerAdd(offset,
5703 ConvertLongToLargeInteger(written));
5705 total_written += written;
5711 /* slots 0 and 1 are reserved for request chaining and will be
5712 filled in when we return. */
5713 smb_SetSMBParm(outp, 2, total_written);
5714 smb_SetSMBParm(outp, 3, 0); /* reserved */
5715 smb_SetSMBParm(outp, 4, 0); /* reserved */
5716 smb_SetSMBParm(outp, 5, 0); /* reserved */
5717 smb_SetSMBDataLength(outp, 0);
5720 smb_ReleaseFID(fidp);
5721 cm_ReleaseUser(userp);
5726 long smb_ReceiveV3ReadX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5730 long finalCount = 0;
5739 fd = smb_GetSMBParm(inp, 2);
5740 count = smb_GetSMBParm(inp, 5);
5741 offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
5743 if (*inp->wctp == 12) {
5744 /* a request with 64-bit offsets */
5745 #ifdef AFS_LARGEFILES
5746 offset.HighPart = smb_GetSMBParm(inp, 10) | (smb_GetSMBParm(inp, 11) << 16);
5748 if (LargeIntegerLessThanZero(offset)) {
5749 osi_Log2(smb_logp, "smb_ReceiveV3Read offset too large (0x%x:%08x)",
5750 offset.HighPart, offset.LowPart);
5751 return CM_ERROR_BADSMB;
5754 if ((smb_GetSMBParm(inp, 10) | (smb_GetSMBParm(inp, 11) << 16)) != 0) {
5755 osi_Log0(smb_logp, "smb_ReceiveV3Read offset is 64-bit. Dropping");
5756 return CM_ERROR_BADSMB;
5758 offset.HighPart = 0;
5762 offset.HighPart = 0;
5765 osi_Log4(smb_logp, "smb_ReceiveV3Read fd %d, off 0x%x:%08x, size 0x%x",
5766 fd, offset.HighPart, offset.LowPart, count);
5768 fd = smb_ChainFID(fd, inp);
5769 fidp = smb_FindFID(vcp, fd, 0);
5771 return CM_ERROR_BADFD;
5774 pid = ((smb_t *) inp)->pid;
5775 key = cm_GenerateKey(vcp->vcID, pid, fd);
5777 LARGE_INTEGER LOffset, LLength;
5779 LOffset.HighPart = offset.HighPart;
5780 LOffset.LowPart = offset.LowPart;
5781 LLength.HighPart = 0;
5782 LLength.LowPart = count;
5784 lock_ObtainMutex(&fidp->scp->mx);
5785 code = cm_LockCheckRead(fidp->scp, LOffset, LLength, key);
5786 lock_ReleaseMutex(&fidp->scp->mx);
5790 smb_ReleaseFID(fidp);
5794 /* set inp->fid so that later read calls in same msg can find fid */
5797 lock_ObtainMutex(&fidp->mx);
5798 if (fidp->flags & SMB_FID_IOCTL) {
5799 lock_ReleaseMutex(&fidp->mx);
5800 code = smb_IoctlV3Read(fidp, vcp, inp, outp);
5801 smb_ReleaseFID(fidp);
5804 lock_ReleaseMutex(&fidp->mx);
5806 userp = smb_GetUserFromVCP(vcp, inp);
5808 /* 0 and 1 are reserved for request chaining, were setup by our caller,
5809 * and will be further filled in after we return.
5811 smb_SetSMBParm(outp, 2, 0); /* remaining bytes, for pipes */
5812 smb_SetSMBParm(outp, 3, 0); /* resvd */
5813 smb_SetSMBParm(outp, 4, 0); /* resvd */
5814 smb_SetSMBParm(outp, 5, count); /* # of bytes we're going to read */
5815 /* fill in #6 when we have all the parameters' space reserved */
5816 smb_SetSMBParm(outp, 7, 0); /* resv'd */
5817 smb_SetSMBParm(outp, 8, 0); /* resv'd */
5818 smb_SetSMBParm(outp, 9, 0); /* resv'd */
5819 smb_SetSMBParm(outp, 10, 0); /* resv'd */
5820 smb_SetSMBParm(outp, 11, 0); /* reserved */
5822 /* get op ptr after putting in the parms, since otherwise we don't
5823 * know where the data really is.
5825 op = smb_GetSMBData(outp, NULL);
5827 /* now fill in offset from start of SMB header to first data byte (to op) */
5828 smb_SetSMBParm(outp, 6, ((int) (op - outp->data)));
5830 /* set the packet data length the count of the # of bytes */
5831 smb_SetSMBDataLength(outp, count);
5834 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount);
5836 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount, FALSE);
5839 /* fix some things up */
5840 smb_SetSMBParm(outp, 5, finalCount);
5841 smb_SetSMBDataLength(outp, finalCount);
5843 smb_ReleaseFID(fidp);
5845 cm_ReleaseUser(userp);
5850 * Values for createDisp, copied from NTDDK.H
5852 #define FILE_SUPERSEDE 0 // (???)
5853 #define FILE_OPEN 1 // (open)
5854 #define FILE_CREATE 2 // (exclusive)
5855 #define FILE_OPEN_IF 3 // (non-exclusive)
5856 #define FILE_OVERWRITE 4 // (open & truncate, but do not create)
5857 #define FILE_OVERWRITE_IF 5 // (open & truncate, or create)
5860 #define REQUEST_OPLOCK 2
5861 #define REQUEST_BATCH_OPLOCK 4
5862 #define OPEN_DIRECTORY 8
5863 #define EXTENDED_RESPONSE_REQUIRED 0x10
5865 /* CreateOptions field. */
5866 #define FILE_DIRECTORY_FILE 0x0001
5867 #define FILE_WRITE_THROUGH 0x0002
5868 #define FILE_SEQUENTIAL_ONLY 0x0004
5869 #define FILE_NON_DIRECTORY_FILE 0x0040
5870 #define FILE_NO_EA_KNOWLEDGE 0x0200
5871 #define FILE_EIGHT_DOT_THREE_ONLY 0x0400
5872 #define FILE_RANDOM_ACCESS 0x0800
5873 #define FILE_DELETE_ON_CLOSE 0x1000
5874 #define FILE_OPEN_BY_FILE_ID 0x2000
5876 long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5878 char *pathp, *realPathp;
5882 cm_scache_t *dscp; /* parent dir */
5883 cm_scache_t *scp; /* file to create or open */
5884 cm_scache_t *targetScp; /* if scp is a symlink */
5888 unsigned short nameLength;
5890 unsigned int requestOpLock;
5891 unsigned int requestBatchOpLock;
5892 unsigned int mustBeDir;
5893 unsigned int extendedRespRequired;
5894 unsigned int treeCreate;
5896 unsigned int desiredAccess;
5897 unsigned int extAttributes;
5898 unsigned int createDisp;
5899 unsigned int createOptions;
5900 unsigned int shareAccess;
5901 int initialModeBits;
5902 unsigned short baseFid;
5903 smb_fid_t *baseFidp;
5905 cm_scache_t *baseDirp;
5906 unsigned short openAction;
5918 /* This code is very long and has a lot of if-then-else clauses
5919 * scp and dscp get reused frequently and we need to ensure that
5920 * we don't lose a reference. Start by ensuring that they are NULL.
5927 nameLength = smb_GetSMBOffsetParm(inp, 2, 1);
5928 flags = smb_GetSMBOffsetParm(inp, 3, 1)
5929 | (smb_GetSMBOffsetParm(inp, 4, 1) << 16);
5930 requestOpLock = flags & REQUEST_OPLOCK;
5931 requestBatchOpLock = flags & REQUEST_BATCH_OPLOCK;
5932 mustBeDir = flags & OPEN_DIRECTORY;
5933 extendedRespRequired = flags & EXTENDED_RESPONSE_REQUIRED;
5936 * Why all of a sudden 32-bit FID?
5937 * We will reject all bits higher than 16.
5939 if (smb_GetSMBOffsetParm(inp, 6, 1) != 0)
5940 return CM_ERROR_INVAL;
5941 baseFid = smb_GetSMBOffsetParm(inp, 5, 1);
5942 desiredAccess = smb_GetSMBOffsetParm(inp, 7, 1)
5943 | (smb_GetSMBOffsetParm(inp, 8, 1) << 16);
5944 extAttributes = smb_GetSMBOffsetParm(inp, 13, 1)
5945 | (smb_GetSMBOffsetParm(inp, 14, 1) << 16);
5946 shareAccess = smb_GetSMBOffsetParm(inp, 15, 1)
5947 | (smb_GetSMBOffsetParm(inp, 16, 1) << 16);
5948 createDisp = smb_GetSMBOffsetParm(inp, 17, 1)
5949 | (smb_GetSMBOffsetParm(inp, 18, 1) << 16);
5950 createOptions = smb_GetSMBOffsetParm(inp, 19, 1)
5951 | (smb_GetSMBOffsetParm(inp, 20, 1) << 16);
5953 /* mustBeDir is never set; createOptions directory bit seems to be
5956 if (createOptions & FILE_DIRECTORY_FILE)
5958 else if (createOptions & FILE_NON_DIRECTORY_FILE)
5964 * compute initial mode bits based on read-only flag in
5965 * extended attributes
5967 initialModeBits = 0666;
5968 if (extAttributes & SMB_ATTR_READONLY)
5969 initialModeBits &= ~0222;
5971 pathp = smb_GetSMBData(inp, NULL);
5972 /* Sometimes path is not null-terminated, so we make a copy. */
5973 realPathp = malloc(nameLength+1);
5974 memcpy(realPathp, pathp, nameLength);
5975 realPathp[nameLength] = 0;
5976 if (smb_StoreAnsiFilenames)
5977 OemToChar(realPathp,realPathp);
5979 spacep = inp->spacep;
5980 smb_StripLastComponent(spacep->data, &lastNamep, realPathp);
5982 osi_Log1(smb_logp,"NTCreateX for [%s]",osi_LogSaveString(smb_logp,realPathp));
5983 osi_Log4(smb_logp,"... da=[%x] ea=[%x] cd=[%x] co=[%x]", desiredAccess, extAttributes, createDisp, createOptions);
5984 osi_Log3(smb_logp,"... share=[%x] flags=[%x] lastNamep=[%s]", shareAccess, flags, osi_LogSaveString(smb_logp,(lastNamep?lastNamep:"null")));
5986 if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
5987 /* special case magic file name for receiving IOCTL requests
5988 * (since IOCTL calls themselves aren't getting through).
5990 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
5991 smb_SetupIoctlFid(fidp, spacep);
5992 osi_Log1(smb_logp,"NTCreateX Setting up IOCTL on fid[%d]",fidp->fid);
5994 /* set inp->fid so that later read calls in same msg can find fid */
5995 inp->fid = fidp->fid;
5999 smb_SetSMBParmByte(outp, parmSlot, 0); /* oplock */
6000 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
6001 smb_SetSMBParmLong(outp, parmSlot, 1); parmSlot += 2; /* Action */
6003 memset(&ft, 0, sizeof(ft));
6004 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
6005 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
6006 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
6007 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
6008 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2; /* attr */
6009 sz.HighPart = 0x7fff; sz.LowPart = 0;
6010 smb_SetSMBParmDouble(outp, parmSlot, (char *)&sz); parmSlot += 4; /* alen */
6011 smb_SetSMBParmDouble(outp, parmSlot, (char *)&sz); parmSlot += 4; /* len */
6012 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* filetype */
6013 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* dev state */
6014 smb_SetSMBParmByte(outp, parmSlot, 0); /* is a dir? */
6015 smb_SetSMBDataLength(outp, 0);
6017 /* clean up fid reference */
6018 smb_ReleaseFID(fidp);
6023 #ifdef DEBUG_VERBOSE
6025 char *hexp, *asciip;
6026 asciip = (lastNamep? lastNamep : realPathp);
6027 hexp = osi_HexifyString( asciip );
6028 DEBUG_EVENT2("AFS", "NTCreateX H[%s] A[%s]", hexp, asciip);
6033 userp = smb_GetUserFromVCP(vcp, inp);
6035 osi_Log1(smb_logp, "NTCreateX Invalid user [%d]", ((smb_t *) inp)->uid);
6037 return CM_ERROR_INVAL;
6042 baseDirp = cm_data.rootSCachep;
6043 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
6044 if (code == CM_ERROR_TIDIPC) {
6045 /* Attempt to use a TID allocated for IPC. The client
6046 * is probably looking for DCE RPC end points which we
6047 * don't support OR it could be looking to make a DFS
6050 osi_Log0(smb_logp, "NTCreateX received IPC TID");
6053 cm_ReleaseUser(userp);
6054 return CM_ERROR_NOSUCHFILE;
6055 #endif /* DFS_SUPPORT */
6058 baseFidp = smb_FindFID(vcp, baseFid, 0);
6060 osi_Log1(smb_logp, "NTCreateX Invalid base fid [%d]", baseFid);
6062 cm_ReleaseUser(userp);
6063 return CM_ERROR_INVAL;
6065 baseDirp = baseFidp->scp;
6069 osi_Log1(smb_logp, "NTCreateX tidPathp=[%s]", (tidPathp==NULL)?"null": osi_LogSaveString(smb_logp,tidPathp));
6071 /* compute open mode */
6073 if (desiredAccess & DELETE)
6074 fidflags |= SMB_FID_OPENDELETE;
6075 if (desiredAccess & AFS_ACCESS_READ)
6076 fidflags |= SMB_FID_OPENREAD;
6077 if (desiredAccess & AFS_ACCESS_WRITE)
6078 fidflags |= SMB_FID_OPENWRITE;
6079 if (createOptions & FILE_DELETE_ON_CLOSE)
6080 fidflags |= SMB_FID_DELONCLOSE;
6081 if (createOptions & FILE_SEQUENTIAL_ONLY && !(createOptions & FILE_RANDOM_ACCESS))
6082 fidflags |= SMB_FID_SEQUENTIAL;
6083 if (createOptions & FILE_RANDOM_ACCESS && !(createOptions & FILE_SEQUENTIAL_ONLY))
6084 fidflags |= SMB_FID_RANDOM;
6086 /* and the share mode */
6087 if (shareAccess & FILE_SHARE_READ)
6088 fidflags |= SMB_FID_SHARE_READ;
6089 if (shareAccess & FILE_SHARE_WRITE)
6090 fidflags |= SMB_FID_SHARE_WRITE;
6092 osi_Log1(smb_logp, "NTCreateX fidflags 0x%x", fidflags);
6095 /* For an exclusive create, we want to do a case sensitive match for the last component. */
6096 if ( createDisp == FILE_CREATE ||
6097 createDisp == FILE_OVERWRITE ||
6098 createDisp == FILE_OVERWRITE_IF) {
6099 code = cm_NameI(baseDirp, spacep->data, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
6100 userp, tidPathp, &req, &dscp);
6103 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
6104 cm_ReleaseSCache(dscp);
6105 cm_ReleaseUser(userp);
6108 smb_ReleaseFID(baseFidp);
6109 if ( WANTS_DFS_PATHNAMES(inp) )
6110 return CM_ERROR_PATH_NOT_COVERED;
6112 return CM_ERROR_BADSHARENAME;
6114 #endif /* DFS_SUPPORT */
6115 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp, CM_FLAG_FOLLOW,
6117 if (code == CM_ERROR_NOSUCHFILE) {
6118 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp,
6119 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, &req, &scp);
6120 if (code == 0 && realDirFlag == 1) {
6121 cm_ReleaseSCache(scp);
6122 cm_ReleaseSCache(dscp);
6123 cm_ReleaseUser(userp);
6126 smb_ReleaseFID(baseFidp);
6127 return CM_ERROR_EXISTS;
6131 /* we have both scp and dscp */
6133 code = cm_NameI(baseDirp, realPathp, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
6134 userp, tidPathp, &req, &scp);
6136 if (code == 0 && scp->fileType == CM_SCACHETYPE_DFSLINK) {
6137 cm_ReleaseSCache(scp);
6138 cm_ReleaseUser(userp);
6141 smb_ReleaseFID(baseFidp);
6142 if ( WANTS_DFS_PATHNAMES(inp) )
6143 return CM_ERROR_PATH_NOT_COVERED;
6145 return CM_ERROR_BADSHARENAME;
6147 #endif /* DFS_SUPPORT */
6148 /* we might have scp but not dscp */
6154 if (!foundscp || (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE))) {
6155 /* look up parent directory */
6156 /* If we are trying to create a path (i.e. multiple nested directories), then we don't *need*
6157 * the immediate parent. We have to work our way up realPathp until we hit something that we
6161 /* we might or might not have scp */
6167 code = cm_NameI(baseDirp, spacep->data,
6168 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
6169 userp, tidPathp, &req, &dscp);
6172 if (code == 0 && dscp->fileType == CM_SCACHETYPE_DFSLINK) {
6174 cm_ReleaseSCache(scp);
6175 cm_ReleaseSCache(dscp);
6176 cm_ReleaseUser(userp);
6179 smb_ReleaseFID(baseFidp);
6180 if ( WANTS_DFS_PATHNAMES(inp) )
6181 return CM_ERROR_PATH_NOT_COVERED;
6183 return CM_ERROR_BADSHARENAME;
6185 #endif /* DFS_SUPPORT */
6188 (tp = strrchr(spacep->data,'\\')) &&
6189 (createDisp == FILE_CREATE) &&
6190 (realDirFlag == 1)) {
6193 treeStartp = realPathp + (tp - spacep->data);
6195 if (*tp && !smb_IsLegalFilename(tp)) {
6197 smb_ReleaseFID(baseFidp);
6198 cm_ReleaseUser(userp);
6201 cm_ReleaseSCache(scp);
6202 return CM_ERROR_BADNTFILENAME;
6206 } while (dscp == NULL && code == 0);
6210 /* we might have scp and we might have dscp */
6213 smb_ReleaseFID(baseFidp);
6216 osi_Log0(smb_logp,"NTCreateX parent not found");
6218 cm_ReleaseSCache(scp);
6220 cm_ReleaseSCache(dscp);
6221 cm_ReleaseUser(userp);
6226 if (treeCreate && dscp->fileType == CM_SCACHETYPE_FILE) {
6227 /* A file exists where we want a directory. */
6229 cm_ReleaseSCache(scp);
6230 cm_ReleaseSCache(dscp);
6231 cm_ReleaseUser(userp);
6233 return CM_ERROR_EXISTS;
6237 lastNamep = realPathp;
6241 if (!smb_IsLegalFilename(lastNamep)) {
6243 cm_ReleaseSCache(scp);
6245 cm_ReleaseSCache(dscp);
6246 cm_ReleaseUser(userp);
6248 return CM_ERROR_BADNTFILENAME;
6251 if (!foundscp && !treeCreate) {
6252 if ( createDisp == FILE_CREATE ||
6253 createDisp == FILE_OVERWRITE ||
6254 createDisp == FILE_OVERWRITE_IF)
6256 code = cm_Lookup(dscp, lastNamep,
6257 CM_FLAG_FOLLOW, userp, &req, &scp);
6259 code = cm_Lookup(dscp, lastNamep,
6260 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
6263 if (code && code != CM_ERROR_NOSUCHFILE) {
6265 cm_ReleaseSCache(dscp);
6266 cm_ReleaseUser(userp);
6271 /* we have scp and dscp */
6273 /* we have scp but not dscp */
6275 smb_ReleaseFID(baseFidp);
6278 /* if we get here, if code is 0, the file exists and is represented by
6279 * scp. Otherwise, we have to create it. The dir may be represented
6280 * by dscp, or we may have found the file directly. If code is non-zero,
6283 if (code == 0 && !treeCreate) {
6284 code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp, &req);
6287 cm_ReleaseSCache(dscp);
6289 cm_ReleaseSCache(scp);
6290 cm_ReleaseUser(userp);
6295 if (createDisp == FILE_CREATE) {
6296 /* oops, file shouldn't be there */
6298 cm_ReleaseSCache(dscp);
6300 cm_ReleaseSCache(scp);
6301 cm_ReleaseUser(userp);
6303 return CM_ERROR_EXISTS;
6306 if ( createDisp == FILE_OVERWRITE ||
6307 createDisp == FILE_OVERWRITE_IF) {
6309 setAttr.mask = CM_ATTRMASK_LENGTH;
6310 setAttr.length.LowPart = 0;
6311 setAttr.length.HighPart = 0;
6312 /* now watch for a symlink */
6314 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
6316 osi_assert(dscp != NULL);
6317 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
6319 /* we have a more accurate file to use (the
6320 * target of the symbolic link). Otherwise,
6321 * we'll just use the symlink anyway.
6323 osi_Log2(smb_logp, "symlink vp %x to vp %x",
6325 cm_ReleaseSCache(scp);
6329 code = cm_SetAttr(scp, &setAttr, userp, &req);
6330 openAction = 3; /* truncated existing file */
6333 openAction = 1; /* found existing file */
6335 } else if (createDisp == FILE_OPEN || createDisp == FILE_OVERWRITE) {
6336 /* don't create if not found */
6338 cm_ReleaseSCache(dscp);
6340 cm_ReleaseSCache(scp);
6341 cm_ReleaseUser(userp);
6343 return CM_ERROR_NOSUCHFILE;
6344 } else if (realDirFlag == 0 || realDirFlag == -1) {
6345 osi_assert(dscp != NULL);
6346 osi_Log1(smb_logp, "smb_ReceiveNTCreateX creating file %s",
6347 osi_LogSaveString(smb_logp, lastNamep));
6348 openAction = 2; /* created file */
6349 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
6350 setAttr.clientModTime = time(NULL);
6351 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp, &req);
6354 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
6355 smb_NotifyChange(FILE_ACTION_ADDED,
6356 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
6357 dscp, lastNamep, NULL, TRUE);
6358 } else if (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE) {
6359 /* Not an exclusive create, and someone else tried
6360 * creating it already, then we open it anyway. We
6361 * don't bother retrying after this, since if this next
6362 * fails, that means that the file was deleted after we
6363 * started this call.
6365 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
6368 if (createDisp == FILE_OVERWRITE_IF) {
6369 setAttr.mask = CM_ATTRMASK_LENGTH;
6370 setAttr.length.LowPart = 0;
6371 setAttr.length.HighPart = 0;
6373 /* now watch for a symlink */
6375 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
6377 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
6379 /* we have a more accurate file to use (the
6380 * target of the symbolic link). Otherwise,
6381 * we'll just use the symlink anyway.
6383 osi_Log2(smb_logp, "symlink vp %x to vp %x",
6385 cm_ReleaseSCache(scp);
6389 code = cm_SetAttr(scp, &setAttr, userp, &req);
6391 } /* lookup succeeded */
6395 char *cp; /* This component */
6396 int clen = 0; /* length of component */
6397 cm_scache_t *tscp1, *tscp2;
6400 /* create directory */
6402 treeStartp = lastNamep;
6403 osi_assert(dscp != NULL);
6404 osi_Log1(smb_logp, "smb_ReceiveNTCreateX creating directory [%s]",
6405 osi_LogSaveString(smb_logp, treeStartp));
6406 openAction = 2; /* created directory */
6408 /* if the request is to create the root directory
6409 * it will appear as a directory name of the nul-string
6410 * and a code of CM_ERROR_NOSUCHFILE
6412 if ( !*treeStartp && code == CM_ERROR_NOSUCHFILE)
6413 code = CM_ERROR_EXISTS;
6415 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
6416 setAttr.clientModTime = time(NULL);
6421 cm_HoldSCache(tscp1);
6425 tp = strchr(pp, '\\');
6428 clen = (int)strlen(cp);
6429 isLast = 1; /* indicate last component. the supplied path never ends in a slash */
6431 clen = (int)(tp - pp);
6432 strncpy(cp,pp,clen);
6439 continue; /* the supplied path can't have consecutive slashes either , but */
6441 /* cp is the next component to be created. */
6442 code = cm_MakeDir(tscp1, cp, 0, &setAttr, userp, &req);
6443 if (code == 0 && (tscp1->flags & CM_SCACHEFLAG_ANYWATCH))
6444 smb_NotifyChange(FILE_ACTION_ADDED,
6445 FILE_NOTIFY_CHANGE_DIR_NAME,
6446 tscp1, cp, NULL, TRUE);
6448 (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE)) {
6449 /* Not an exclusive create, and someone else tried
6450 * creating it already, then we open it anyway. We
6451 * don't bother retrying after this, since if this next
6452 * fails, that means that the file was deleted after we
6453 * started this call.
6455 code = cm_Lookup(tscp1, cp, CM_FLAG_CASEFOLD,
6456 userp, &req, &tscp2);
6461 if (!isLast) { /* for anything other than dscp, release it unless it's the last one */
6462 cm_ReleaseSCache(tscp1);
6463 tscp1 = tscp2; /* Newly created directory will be next parent */
6464 /* the hold is transfered to tscp1 from tscp2 */
6469 cm_ReleaseSCache(dscp);
6472 cm_ReleaseSCache(scp);
6475 * if we get here and code == 0, then scp is the last directory created, and dscp is the
6481 /* something went wrong creating or truncating the file */
6483 cm_ReleaseSCache(scp);
6485 cm_ReleaseSCache(dscp);
6486 cm_ReleaseUser(userp);
6491 /* make sure we have file vs. dir right (only applies for single component case) */
6492 if (realDirFlag == 0 && scp->fileType != CM_SCACHETYPE_FILE) {
6493 /* now watch for a symlink */
6495 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
6496 cm_scache_t * targetScp = 0;
6497 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
6499 /* we have a more accurate file to use (the
6500 * target of the symbolic link). Otherwise,
6501 * we'll just use the symlink anyway.
6503 osi_Log2(smb_logp, "symlink vp %x to vp %x", scp, targetScp);
6504 cm_ReleaseSCache(scp);
6509 if (scp->fileType != CM_SCACHETYPE_FILE) {
6511 cm_ReleaseSCache(dscp);
6512 cm_ReleaseSCache(scp);
6513 cm_ReleaseUser(userp);
6515 return CM_ERROR_ISDIR;
6519 /* (only applies to single component case) */
6520 if (realDirFlag == 1 && scp->fileType == CM_SCACHETYPE_FILE) {
6521 cm_ReleaseSCache(scp);
6523 cm_ReleaseSCache(dscp);
6524 cm_ReleaseUser(userp);
6526 return CM_ERROR_NOTDIR;
6529 /* open the file itself */
6530 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
6533 /* save a reference to the user */
6535 fidp->userp = userp;
6537 /* If we are restricting sharing, we should do so with a suitable
6539 if (scp->fileType == CM_SCACHETYPE_FILE &&
6540 !(fidflags & SMB_FID_SHARE_WRITE)) {
6542 LARGE_INTEGER LOffset, LLength;
6545 LOffset.HighPart = SMB_FID_QLOCK_HIGH;
6546 LOffset.LowPart = SMB_FID_QLOCK_LOW;
6547 LLength.HighPart = 0;
6548 LLength.LowPart = SMB_FID_QLOCK_LENGTH;
6550 if (fidflags & SMB_FID_SHARE_READ) {
6551 sLockType = LOCKING_ANDX_SHARED_LOCK;
6556 key = cm_GenerateKey(vcp->vcID, SMB_FID_QLOCK_PID, fidp->fid);
6558 lock_ObtainMutex(&scp->mx);
6559 code = cm_Lock(scp, sLockType, LOffset, LLength, key, 0, userp, &req, NULL);
6560 lock_ReleaseMutex(&scp->mx);
6563 /* shouldn't this be smb_CloseFID() fidp->flags = SMB_FID_DELETE; */
6564 smb_CloseFID(vcp, fidp, NULL, 0);
6565 smb_ReleaseFID(fidp);
6567 cm_ReleaseSCache(scp);
6569 cm_ReleaseSCache(dscp);
6570 cm_ReleaseUser(userp);
6577 lock_ObtainMutex(&fidp->mx);
6578 /* save a pointer to the vnode */
6579 fidp->scp = scp; /* Hold transfered to fidp->scp and no longer needed */
6581 fidp->flags = fidflags;
6583 /* remember if the file was newly created */
6585 fidp->flags |= SMB_FID_CREATED;
6587 /* save parent dir and pathname for delete or change notification */
6588 if (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE)) {
6589 fidp->flags |= SMB_FID_NTOPEN;
6590 fidp->NTopen_dscp = dscp;
6591 cm_HoldSCache(dscp);
6592 fidp->NTopen_pathp = strdup(lastNamep);
6594 fidp->NTopen_wholepathp = realPathp;
6595 lock_ReleaseMutex(&fidp->mx);
6597 /* we don't need this any longer */
6599 cm_ReleaseSCache(dscp);
6603 cm_Open(scp, 0, userp);
6605 /* set inp->fid so that later read calls in same msg can find fid */
6606 inp->fid = fidp->fid;
6610 lock_ObtainMutex(&scp->mx);
6611 smb_SetSMBParmByte(outp, parmSlot, 0); /* oplock */
6612 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
6613 smb_SetSMBParmLong(outp, parmSlot, openAction); parmSlot += 2;
6614 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
6615 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
6616 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
6617 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
6618 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
6619 smb_SetSMBParmLong(outp, parmSlot, smb_ExtAttributes(scp));
6621 smb_SetSMBParmDouble(outp, parmSlot, (char *)&scp->length); parmSlot += 4;
6622 smb_SetSMBParmDouble(outp, parmSlot, (char *)&scp->length); parmSlot += 4;
6623 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* filetype */
6624 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* dev state */
6625 smb_SetSMBParmByte(outp, parmSlot,
6626 (scp->fileType == CM_SCACHETYPE_DIRECTORY ||
6627 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
6628 scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0); /* is a dir? */
6629 lock_ReleaseMutex(&scp->mx);
6630 smb_SetSMBDataLength(outp, 0);
6632 osi_Log2(smb_logp, "SMB NT CreateX opening fid %d path %s", fidp->fid,
6633 osi_LogSaveString(smb_logp, realPathp));
6635 smb_ReleaseFID(fidp);
6637 cm_ReleaseUser(userp);
6639 /* Can't free realPathp if we get here since
6640 fidp->NTopen_wholepathp is pointing there */
6642 /* leave scp held since we put it in fidp->scp */
6647 * A lot of stuff copied verbatim from NT Create&X to NT Tran Create.
6648 * Instead, ultimately, would like to use a subroutine for common code.
6650 long smb_ReceiveNTTranCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6652 char *pathp, *realPathp;
6656 cm_scache_t *dscp; /* parent dir */
6657 cm_scache_t *scp; /* file to create or open */
6658 cm_scache_t *targetScp; /* if scp is a symlink */
6661 unsigned long nameLength;
6663 unsigned int requestOpLock;
6664 unsigned int requestBatchOpLock;
6665 unsigned int mustBeDir;
6666 unsigned int extendedRespRequired;
6668 unsigned int desiredAccess;
6669 #ifdef DEBUG_VERBOSE
6670 unsigned int allocSize;
6672 unsigned int shareAccess;
6673 unsigned int extAttributes;
6674 unsigned int createDisp;
6675 #ifdef DEBUG_VERBOSE
6678 unsigned int createOptions;
6679 int initialModeBits;
6680 unsigned short baseFid;
6681 smb_fid_t *baseFidp;
6683 cm_scache_t *baseDirp;
6684 unsigned short openAction;
6690 int parmOffset, dataOffset;
6702 parmOffset = smb_GetSMBOffsetParm(inp, 11, 1)
6703 | (smb_GetSMBOffsetParm(inp, 12, 1) << 16);
6704 parmp = inp->data + parmOffset;
6705 lparmp = (ULONG *) parmp;
6708 requestOpLock = flags & REQUEST_OPLOCK;
6709 requestBatchOpLock = flags & REQUEST_BATCH_OPLOCK;
6710 mustBeDir = flags & OPEN_DIRECTORY;
6711 extendedRespRequired = flags & EXTENDED_RESPONSE_REQUIRED;
6714 * Why all of a sudden 32-bit FID?
6715 * We will reject all bits higher than 16.
6717 if (lparmp[1] & 0xFFFF0000)
6718 return CM_ERROR_INVAL;
6719 baseFid = (unsigned short)lparmp[1];
6720 desiredAccess = lparmp[2];
6721 #ifdef DEBUG_VERBOSE
6722 allocSize = lparmp[3];
6723 #endif /* DEBUG_VERSOSE */
6724 extAttributes = lparmp[5];
6725 shareAccess = lparmp[6];
6726 createDisp = lparmp[7];
6727 createOptions = lparmp[8];
6728 #ifdef DEBUG_VERBOSE
6731 nameLength = lparmp[11];
6733 #ifdef DEBUG_VERBOSE
6734 osi_Log4(smb_logp,"NTTranCreate with da[%x],ea[%x],sa[%x],cd[%x]",desiredAccess,extAttributes,shareAccess,createDisp);
6735 osi_Log3(smb_logp,"... co[%x],sdl[%x],as[%x]",createOptions,sdLen,allocSize);
6736 osi_Log1(smb_logp,"... flags[%x]",flags);
6739 /* mustBeDir is never set; createOptions directory bit seems to be
6742 if (createOptions & FILE_DIRECTORY_FILE)
6744 else if (createOptions & FILE_NON_DIRECTORY_FILE)
6750 * compute initial mode bits based on read-only flag in
6751 * extended attributes
6753 initialModeBits = 0666;
6754 if (extAttributes & SMB_ATTR_READONLY)
6755 initialModeBits &= ~0222;
6757 pathp = parmp + (13 * sizeof(ULONG)) + sizeof(UCHAR);
6758 /* Sometimes path is not null-terminated, so we make a copy. */
6759 realPathp = malloc(nameLength+1);
6760 memcpy(realPathp, pathp, nameLength);
6761 realPathp[nameLength] = 0;
6762 if (smb_StoreAnsiFilenames)
6763 OemToChar(realPathp,realPathp);
6765 spacep = cm_GetSpace();
6766 smb_StripLastComponent(spacep->data, &lastNamep, realPathp);
6769 * Nothing here to handle SMB_IOCTL_FILENAME.
6770 * Will add it if necessary.
6773 #ifdef DEBUG_VERBOSE
6775 char *hexp, *asciip;
6776 asciip = (lastNamep? lastNamep : realPathp);
6777 hexp = osi_HexifyString( asciip );
6778 DEBUG_EVENT2("AFS", "NTTranCreate H[%s] A[%s]", hexp, asciip);
6783 userp = smb_GetUserFromVCP(vcp, inp);
6785 osi_Log1(smb_logp, "NTTranCreate invalid user [%d]", ((smb_t *) inp)->uid);
6787 return CM_ERROR_INVAL;
6792 baseDirp = cm_data.rootSCachep;
6793 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
6794 if (code == CM_ERROR_TIDIPC) {
6795 /* Attempt to use a TID allocated for IPC. The client
6796 * is probably looking for DCE RPC end points which we
6797 * don't support OR it could be looking to make a DFS
6800 osi_Log0(smb_logp, "NTTranCreate received IPC TID");
6803 cm_ReleaseUser(userp);
6804 return CM_ERROR_NOSUCHPATH;
6808 baseFidp = smb_FindFID(vcp, baseFid, 0);
6810 osi_Log1(smb_logp, "NTTranCreate Invalid fid [%d]", baseFid);
6812 cm_ReleaseUser(userp);
6813 return CM_ERROR_INVAL;
6815 baseDirp = baseFidp->scp;
6819 /* compute open mode */
6821 if (desiredAccess & DELETE)
6822 fidflags |= SMB_FID_OPENDELETE;
6823 if (desiredAccess & AFS_ACCESS_READ)
6824 fidflags |= SMB_FID_OPENREAD;
6825 if (desiredAccess & AFS_ACCESS_WRITE)
6826 fidflags |= SMB_FID_OPENWRITE;
6827 if (createOptions & FILE_DELETE_ON_CLOSE)
6828 fidflags |= SMB_FID_DELONCLOSE;
6829 if (createOptions & FILE_SEQUENTIAL_ONLY && !(createOptions & FILE_RANDOM_ACCESS))
6830 fidflags |= SMB_FID_SEQUENTIAL;
6831 if (createOptions & FILE_RANDOM_ACCESS && !(createOptions & FILE_SEQUENTIAL_ONLY))
6832 fidflags |= SMB_FID_RANDOM;
6834 /* And the share mode */
6835 if (shareAccess & FILE_SHARE_READ)
6836 fidflags |= SMB_FID_SHARE_READ;
6837 if (shareAccess & FILE_SHARE_WRITE)
6838 fidflags |= SMB_FID_SHARE_WRITE;
6842 if ( createDisp == FILE_OPEN ||
6843 createDisp == FILE_OVERWRITE ||
6844 createDisp == FILE_OVERWRITE_IF) {
6845 code = cm_NameI(baseDirp, spacep->data, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
6846 userp, tidPathp, &req, &dscp);
6849 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
6850 cm_ReleaseSCache(dscp);
6851 cm_ReleaseUser(userp);
6854 smb_ReleaseFID(baseFidp);
6855 if ( WANTS_DFS_PATHNAMES(inp) )
6856 return CM_ERROR_PATH_NOT_COVERED;
6858 return CM_ERROR_BADSHARENAME;
6860 #endif /* DFS_SUPPORT */
6861 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp, CM_FLAG_FOLLOW,
6863 if (code == CM_ERROR_NOSUCHFILE) {
6864 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp,
6865 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, &req, &scp);
6866 if (code == 0 && realDirFlag == 1) {
6867 cm_ReleaseSCache(scp);
6868 cm_ReleaseSCache(dscp);
6869 cm_ReleaseUser(userp);
6872 smb_ReleaseFID(baseFidp);
6873 return CM_ERROR_EXISTS;
6879 code = cm_NameI(baseDirp, realPathp, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
6880 userp, tidPathp, &req, &scp);
6882 if (code == 0 && scp->fileType == CM_SCACHETYPE_DFSLINK) {
6883 cm_ReleaseSCache(scp);
6884 cm_ReleaseUser(userp);
6887 smb_ReleaseFID(baseFidp);
6888 if ( WANTS_DFS_PATHNAMES(inp) )
6889 return CM_ERROR_PATH_NOT_COVERED;
6891 return CM_ERROR_BADSHARENAME;
6893 #endif /* DFS_SUPPORT */
6899 if (code != 0 || (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE))) {
6900 /* look up parent directory */
6902 code = cm_NameI(baseDirp, spacep->data,
6903 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
6904 userp, tidPathp, &req, &dscp);
6906 if (code == 0 && dscp->fileType == CM_SCACHETYPE_DFSLINK) {
6907 cm_ReleaseSCache(dscp);
6908 cm_ReleaseUser(userp);
6911 smb_ReleaseFID(baseFidp);
6912 if ( WANTS_DFS_PATHNAMES(inp) )
6913 return CM_ERROR_PATH_NOT_COVERED;
6915 return CM_ERROR_BADSHARENAME;
6917 #endif /* DFS_SUPPORT */
6921 cm_FreeSpace(spacep);
6924 smb_ReleaseFID(baseFidp);
6927 cm_ReleaseUser(userp);
6933 lastNamep = realPathp;
6937 if (!smb_IsLegalFilename(lastNamep))
6938 return CM_ERROR_BADNTFILENAME;
6941 if (createDisp == FILE_CREATE || createDisp == FILE_OVERWRITE_IF) {
6942 code = cm_Lookup(dscp, lastNamep,
6943 CM_FLAG_FOLLOW, userp, &req, &scp);
6945 code = cm_Lookup(dscp, lastNamep,
6946 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
6949 if (code && code != CM_ERROR_NOSUCHFILE) {
6950 cm_ReleaseSCache(dscp);
6951 cm_ReleaseUser(userp);
6958 smb_ReleaseFID(baseFidp);
6959 cm_FreeSpace(spacep);
6962 /* if we get here, if code is 0, the file exists and is represented by
6963 * scp. Otherwise, we have to create it. The dir may be represented
6964 * by dscp, or we may have found the file directly. If code is non-zero,
6968 code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp,
6972 cm_ReleaseSCache(dscp);
6973 cm_ReleaseSCache(scp);
6974 cm_ReleaseUser(userp);
6979 if (createDisp == FILE_CREATE) {
6980 /* oops, file shouldn't be there */
6982 cm_ReleaseSCache(dscp);
6983 cm_ReleaseSCache(scp);
6984 cm_ReleaseUser(userp);
6986 return CM_ERROR_EXISTS;
6989 if (createDisp == FILE_OVERWRITE ||
6990 createDisp == FILE_OVERWRITE_IF) {
6991 setAttr.mask = CM_ATTRMASK_LENGTH;
6992 setAttr.length.LowPart = 0;
6993 setAttr.length.HighPart = 0;
6995 /* now watch for a symlink */
6997 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
6999 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
7001 /* we have a more accurate file to use (the
7002 * target of the symbolic link). Otherwise,
7003 * we'll just use the symlink anyway.
7005 osi_Log2(smb_logp, "symlink vp %x to vp %x",
7007 cm_ReleaseSCache(scp);
7011 code = cm_SetAttr(scp, &setAttr, userp, &req);
7012 openAction = 3; /* truncated existing file */
7014 else openAction = 1; /* found existing file */
7016 else if (createDisp == FILE_OPEN || createDisp == FILE_OVERWRITE) {
7017 /* don't create if not found */
7019 cm_ReleaseSCache(dscp);
7020 cm_ReleaseUser(userp);
7022 return CM_ERROR_NOSUCHFILE;
7024 else if (realDirFlag == 0 || realDirFlag == -1) {
7025 osi_assert(dscp != NULL);
7026 osi_Log1(smb_logp, "smb_ReceiveNTTranCreate creating file %s",
7027 osi_LogSaveString(smb_logp, lastNamep));
7028 openAction = 2; /* created file */
7029 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
7030 setAttr.clientModTime = time(NULL);
7031 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
7035 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
7036 smb_NotifyChange(FILE_ACTION_ADDED,
7037 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
7038 dscp, lastNamep, NULL, TRUE);
7039 } else if (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE) {
7040 /* Not an exclusive create, and someone else tried
7041 * creating it already, then we open it anyway. We
7042 * don't bother retrying after this, since if this next
7043 * fails, that means that the file was deleted after we
7044 * started this call.
7046 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
7049 if (createDisp == FILE_OVERWRITE_IF) {
7050 setAttr.mask = CM_ATTRMASK_LENGTH;
7051 setAttr.length.LowPart = 0;
7052 setAttr.length.HighPart = 0;
7054 /* now watch for a symlink */
7056 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
7058 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
7060 /* we have a more accurate file to use (the
7061 * target of the symbolic link). Otherwise,
7062 * we'll just use the symlink anyway.
7064 osi_Log2(smb_logp, "symlink vp %x to vp %x",
7066 cm_ReleaseSCache(scp);
7070 code = cm_SetAttr(scp, &setAttr, userp, &req);
7072 } /* lookup succeeded */
7075 /* create directory */
7076 osi_assert(dscp != NULL);
7078 "smb_ReceiveNTTranCreate creating directory %s",
7079 osi_LogSaveString(smb_logp, lastNamep));
7080 openAction = 2; /* created directory */
7081 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
7082 setAttr.clientModTime = time(NULL);
7083 code = cm_MakeDir(dscp, lastNamep, 0, &setAttr, userp, &req);
7084 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
7085 smb_NotifyChange(FILE_ACTION_ADDED,
7086 FILE_NOTIFY_CHANGE_DIR_NAME,
7087 dscp, lastNamep, NULL, TRUE);
7089 (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE)) {
7090 /* Not an exclusive create, and someone else tried
7091 * creating it already, then we open it anyway. We
7092 * don't bother retrying after this, since if this next
7093 * fails, that means that the file was deleted after we
7094 * started this call.
7096 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
7102 /* something went wrong creating or truncating the file */
7104 cm_ReleaseSCache(scp);
7105 cm_ReleaseUser(userp);
7110 /* make sure we have file vs. dir right */
7111 if (realDirFlag == 0 && scp->fileType != CM_SCACHETYPE_FILE) {
7112 /* now watch for a symlink */
7114 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
7116 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
7118 /* we have a more accurate file to use (the
7119 * target of the symbolic link). Otherwise,
7120 * we'll just use the symlink anyway.
7122 osi_Log2(smb_logp, "symlink vp %x to vp %x",
7124 cm_ReleaseSCache(scp);
7129 if (scp->fileType != CM_SCACHETYPE_FILE) {
7130 cm_ReleaseSCache(scp);
7131 cm_ReleaseUser(userp);
7133 return CM_ERROR_ISDIR;
7137 if (realDirFlag == 1 && scp->fileType == CM_SCACHETYPE_FILE) {
7138 cm_ReleaseSCache(scp);
7139 cm_ReleaseUser(userp);
7141 return CM_ERROR_NOTDIR;
7144 /* open the file itself */
7145 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
7148 /* save a reference to the user */
7150 fidp->userp = userp;
7152 /* If we are restricting sharing, we should do so with a suitable
7154 if (scp->fileType == CM_SCACHETYPE_FILE &&
7155 !(fidflags & SMB_FID_SHARE_WRITE)) {
7157 LARGE_INTEGER LOffset, LLength;
7160 LOffset.HighPart = SMB_FID_QLOCK_HIGH;
7161 LOffset.LowPart = SMB_FID_QLOCK_LOW;
7162 LLength.HighPart = 0;
7163 LLength.LowPart = SMB_FID_QLOCK_LENGTH;
7165 if (fidflags & SMB_FID_SHARE_READ) {
7166 sLockType = LOCKING_ANDX_SHARED_LOCK;
7171 key = cm_GenerateKey(vcp->vcID, SMB_FID_QLOCK_PID, fidp->fid);
7173 lock_ObtainMutex(&scp->mx);
7174 code = cm_Lock(scp, sLockType, LOffset, LLength, key, 0, userp, &req, NULL);
7175 lock_ReleaseMutex(&scp->mx);
7178 /* Shouldn't this be smb_CloseFID()? fidp->flags = SMB_FID_DELETE; */
7179 smb_CloseFID(vcp, fidp, NULL, 0);
7180 smb_ReleaseFID(fidp);
7182 cm_ReleaseSCache(scp);
7183 cm_ReleaseUser(userp);
7186 return CM_ERROR_SHARING_VIOLATION;
7190 lock_ObtainMutex(&fidp->mx);
7191 /* save a pointer to the vnode */
7194 fidp->flags = fidflags;
7196 /* remember if the file was newly created */
7198 fidp->flags |= SMB_FID_CREATED;
7200 /* save parent dir and pathname for deletion or change notification */
7201 if (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE)) {
7202 fidp->flags |= SMB_FID_NTOPEN;
7203 fidp->NTopen_dscp = dscp;
7204 cm_HoldSCache(dscp);
7205 fidp->NTopen_pathp = strdup(lastNamep);
7207 fidp->NTopen_wholepathp = realPathp;
7208 lock_ReleaseMutex(&fidp->mx);
7210 /* we don't need this any longer */
7212 cm_ReleaseSCache(dscp);
7214 cm_Open(scp, 0, userp);
7216 /* set inp->fid so that later read calls in same msg can find fid */
7217 inp->fid = fidp->fid;
7219 /* check whether we are required to send an extended response */
7220 if (!extendedRespRequired) {
7222 parmOffset = 8*4 + 39;
7223 parmOffset += 1; /* pad to 4 */
7224 dataOffset = parmOffset + 70;
7228 /* Total Parameter Count */
7229 smb_SetSMBParmLong(outp, parmSlot, 70); parmSlot += 2;
7230 /* Total Data Count */
7231 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
7232 /* Parameter Count */
7233 smb_SetSMBParmLong(outp, parmSlot, 70); parmSlot += 2;
7234 /* Parameter Offset */
7235 smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
7236 /* Parameter Displacement */
7237 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
7239 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
7241 smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
7242 /* Data Displacement */
7243 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
7244 smb_SetSMBParmByte(outp, parmSlot, 0); /* Setup Count */
7245 smb_SetSMBDataLength(outp, 70);
7247 lock_ObtainMutex(&scp->mx);
7248 outData = smb_GetSMBData(outp, NULL);
7249 outData++; /* round to get to parmOffset */
7250 *outData = 0; outData++; /* oplock */
7251 *outData = 0; outData++; /* reserved */
7252 *((USHORT *)outData) = fidp->fid; outData += 2; /* fid */
7253 *((ULONG *)outData) = openAction; outData += 4;
7254 *((ULONG *)outData) = 0; outData += 4; /* EA error offset */
7255 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
7256 *((FILETIME *)outData) = ft; outData += 8; /* creation time */
7257 *((FILETIME *)outData) = ft; outData += 8; /* last access time */
7258 *((FILETIME *)outData) = ft; outData += 8; /* last write time */
7259 *((FILETIME *)outData) = ft; outData += 8; /* change time */
7260 *((ULONG *)outData) = smb_ExtAttributes(scp); outData += 4;
7261 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* alloc sz */
7262 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* EOF */
7263 *((USHORT *)outData) = 0; outData += 2; /* filetype */
7264 *((USHORT *)outData) = 0; outData += 2; /* dev state */
7265 *((USHORT *)outData) = ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
7266 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
7267 scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0);
7268 outData += 2; /* is a dir? */
7269 lock_ReleaseMutex(&scp->mx);
7272 parmOffset = 8*4 + 39;
7273 parmOffset += 1; /* pad to 4 */
7274 dataOffset = parmOffset + 104;
7278 /* Total Parameter Count */
7279 smb_SetSMBParmLong(outp, parmSlot, 101); parmSlot += 2;
7280 /* Total Data Count */
7281 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
7282 /* Parameter Count */
7283 smb_SetSMBParmLong(outp, parmSlot, 101); parmSlot += 2;
7284 /* Parameter Offset */
7285 smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
7286 /* Parameter Displacement */
7287 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
7289 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
7291 smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
7292 /* Data Displacement */
7293 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
7294 smb_SetSMBParmByte(outp, parmSlot, 0); /* Setup Count */
7295 smb_SetSMBDataLength(outp, 105);
7297 lock_ObtainMutex(&scp->mx);
7298 outData = smb_GetSMBData(outp, NULL);
7299 outData++; /* round to get to parmOffset */
7300 *outData = 0; outData++; /* oplock */
7301 *outData = 1; outData++; /* response type */
7302 *((USHORT *)outData) = fidp->fid; outData += 2; /* fid */
7303 *((ULONG *)outData) = openAction; outData += 4;
7304 *((ULONG *)outData) = 0; outData += 4; /* EA error offset */
7305 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
7306 *((FILETIME *)outData) = ft; outData += 8; /* creation time */
7307 *((FILETIME *)outData) = ft; outData += 8; /* last access time */
7308 *((FILETIME *)outData) = ft; outData += 8; /* last write time */
7309 *((FILETIME *)outData) = ft; outData += 8; /* change time */
7310 *((ULONG *)outData) = smb_ExtAttributes(scp); outData += 4;
7311 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* alloc sz */
7312 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* EOF */
7313 *((USHORT *)outData) = 0; outData += 2; /* filetype */
7314 *((USHORT *)outData) = 0; outData += 2; /* dev state */
7315 *((USHORT *)outData) = ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
7316 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
7317 scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0);
7318 outData += 1; /* is a dir? */
7319 memset(outData,0,24); outData += 24; /* Volume ID and file ID */
7320 *((ULONG *)outData) = 0x001f01ffL; outData += 4; /* Maxmimal access rights */
7321 *((ULONG *)outData) = 0; outData += 4; /* Guest Access rights */
7322 lock_ReleaseMutex(&scp->mx);
7325 osi_Log1(smb_logp, "SMB NTTranCreate opening fid %d", fidp->fid);
7327 smb_ReleaseFID(fidp);
7329 cm_ReleaseUser(userp);
7331 /* free(realPathp); Can't free realPathp here because fidp->NTopen_wholepathp points there */
7332 /* leave scp held since we put it in fidp->scp */
7336 long smb_ReceiveNTTranNotifyChange(smb_vc_t *vcp, smb_packet_t *inp,
7339 smb_packet_t *savedPacketp;
7340 ULONG filter; USHORT fid, watchtree;
7344 filter = smb_GetSMBParm(inp, 19) |
7345 (smb_GetSMBParm(inp, 20) << 16);
7346 fid = smb_GetSMBParm(inp, 21);
7347 watchtree = smb_GetSMBParm(inp, 22) && 0xffff; /* TODO: should this be 0xff ? */
7349 fidp = smb_FindFID(vcp, fid, 0);
7351 osi_Log1(smb_logp, "ERROR: NotifyChange given invalid fid [%d]", fid);
7352 return CM_ERROR_BADFD;
7355 savedPacketp = smb_CopyPacket(inp);
7357 if (savedPacketp->vcp)
7358 smb_ReleaseVC(savedPacketp->vcp);
7359 savedPacketp->vcp = vcp;
7360 lock_ObtainMutex(&smb_Dir_Watch_Lock);
7361 savedPacketp->nextp = smb_Directory_Watches;
7362 smb_Directory_Watches = savedPacketp;
7363 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
7365 osi_Log4(smb_logp, "Request for NotifyChange filter 0x%x fid %d wtree %d file %s",
7366 filter, fid, watchtree, osi_LogSaveString(smb_logp, fidp->NTopen_wholepathp));
7369 lock_ObtainMutex(&scp->mx);
7371 scp->flags |= CM_SCACHEFLAG_WATCHEDSUBTREE;
7373 scp->flags |= CM_SCACHEFLAG_WATCHED;
7374 lock_ReleaseMutex(&scp->mx);
7375 smb_ReleaseFID(fidp);
7377 outp->flags |= SMB_PACKETFLAG_NOSEND;
7381 unsigned char nullSecurityDesc[36] = {
7382 0x01, /* security descriptor revision */
7383 0x00, /* reserved, should be zero */
7384 0x00, 0x80, /* security descriptor control;
7385 * 0x8000 : self-relative format */
7386 0x14, 0x00, 0x00, 0x00, /* offset of owner SID */
7387 0x1c, 0x00, 0x00, 0x00, /* offset of group SID */
7388 0x00, 0x00, 0x00, 0x00, /* offset of DACL would go here */
7389 0x00, 0x00, 0x00, 0x00, /* offset of SACL would go here */
7390 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
7391 /* "null SID" owner SID */
7392 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
7393 /* "null SID" group SID */
7396 long smb_ReceiveNTTranQuerySecurityDesc(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7398 int parmOffset, parmCount, dataOffset, dataCount;
7406 ULONG securityInformation;
7408 parmOffset = smb_GetSMBOffsetParm(inp, 11, 1)
7409 | (smb_GetSMBOffsetParm(inp, 12, 1) << 16);
7410 parmp = inp->data + parmOffset;
7411 sparmp = (USHORT *) parmp;
7412 lparmp = (ULONG *) parmp;
7415 securityInformation = lparmp[1];
7417 maxData = smb_GetSMBOffsetParm(inp, 7, 1)
7418 | (smb_GetSMBOffsetParm(inp, 8, 1) << 16);
7426 parmOffset = 8*4 + 39;
7427 parmOffset += 1; /* pad to 4 */
7429 dataOffset = parmOffset + parmCount;
7433 /* Total Parameter Count */
7434 smb_SetSMBParmLong(outp, parmSlot, parmCount); parmSlot += 2;
7435 /* Total Data Count */
7436 smb_SetSMBParmLong(outp, parmSlot, dataCount); parmSlot += 2;
7437 /* Parameter Count */
7438 smb_SetSMBParmLong(outp, parmSlot, parmCount); parmSlot += 2;
7439 /* Parameter Offset */
7440 smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
7441 /* Parameter Displacement */
7442 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
7444 smb_SetSMBParmLong(outp, parmSlot, dataCount); parmSlot += 2;
7446 smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
7447 /* Data Displacement */
7448 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
7449 smb_SetSMBParmByte(outp, parmSlot, 0); /* Setup Count */
7450 smb_SetSMBDataLength(outp, 1 + parmCount + dataCount);
7452 outData = smb_GetSMBData(outp, NULL);
7453 outData++; /* round to get to parmOffset */
7454 *((ULONG *)outData) = 36; outData += 4; /* length */
7456 if (maxData >= 36) {
7457 memcpy(outData, nullSecurityDesc, 36);
7461 return CM_ERROR_BUFFERTOOSMALL;
7464 long smb_ReceiveNTTransact(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7466 unsigned short function;
7468 function = smb_GetSMBParm(inp, 18);
7470 osi_Log1(smb_logp, "SMB NT Transact function %d", function);
7472 /* We can handle long names */
7473 if (vcp->flags & SMB_VCFLAG_USENT)
7474 ((smb_t *)outp)->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
7478 return smb_ReceiveNTTranCreate(vcp, inp, outp);
7480 osi_Log0(smb_logp, "SMB NT Transact Ioctl - not implemented");
7483 osi_Log0(smb_logp, "SMB NT Transact SetSecurityDesc - not implemented");
7486 return smb_ReceiveNTTranNotifyChange(vcp, inp, outp);
7488 osi_Log0(smb_logp, "SMB NT Transact Rename - not implemented");
7491 return smb_ReceiveNTTranQuerySecurityDesc(vcp, inp, outp);
7493 return CM_ERROR_INVAL;
7497 * smb_NotifyChange -- find relevant change notification messages and
7500 * If we don't know the file name (i.e. a callback break), filename is
7501 * NULL, and we return a zero-length list.
7503 void smb_NotifyChange(DWORD action, DWORD notifyFilter,
7504 cm_scache_t *dscp, char *filename, char *otherFilename,
7505 BOOL isDirectParent)
7507 smb_packet_t *watch, *lastWatch, *nextWatch;
7508 ULONG parmSlot, parmCount, parmOffset, dataOffset, nameLen;
7509 char *outData, *oldOutData;
7513 BOOL twoEntries = FALSE;
7514 ULONG otherNameLen, oldParmCount = 0;
7518 /* Get ready for rename within directory */
7519 if (action == FILE_ACTION_RENAMED_OLD_NAME && otherFilename != NULL) {
7521 otherAction = FILE_ACTION_RENAMED_NEW_NAME;
7524 osi_Log2(smb_logp,"in smb_NotifyChange for file [%s] dscp [%x]",
7525 osi_LogSaveString(smb_logp,filename),dscp);
7527 lock_ObtainMutex(&smb_Dir_Watch_Lock);
7528 watch = smb_Directory_Watches;
7530 filter = smb_GetSMBParm(watch, 19)
7531 | (smb_GetSMBParm(watch, 20) << 16);
7532 fid = smb_GetSMBParm(watch, 21);
7533 wtree = smb_GetSMBParm(watch, 22) & 0xffff; /* TODO: should this be 0xff ? */
7534 maxLen = smb_GetSMBOffsetParm(watch, 5, 1)
7535 | (smb_GetSMBOffsetParm(watch, 6, 1) << 16);
7538 * Strange hack - bug in NT Client and NT Server that we
7541 if (filter == 3 && wtree)
7544 fidp = smb_FindFID(watch->vcp, fid, 0);
7546 osi_Log1(smb_logp," no fidp for fid[%d]",fid);
7548 watch = watch->nextp;
7551 if (fidp->scp != dscp
7552 || (filter & notifyFilter) == 0
7553 || (!isDirectParent && !wtree)) {
7554 osi_Log1(smb_logp," passing fidp->scp[%x]", fidp->scp);
7555 smb_ReleaseFID(fidp);
7557 watch = watch->nextp;
7560 smb_ReleaseFID(fidp);
7563 "Sending Change Notification for fid %d filter 0x%x wtree %d file %s",
7564 fid, filter, wtree, osi_LogSaveString(smb_logp, filename));
7566 nextWatch = watch->nextp;
7567 if (watch == smb_Directory_Watches)
7568 smb_Directory_Watches = nextWatch;
7570 lastWatch->nextp = nextWatch;
7572 /* Turn off WATCHED flag in dscp */
7573 lock_ObtainMutex(&dscp->mx);
7575 dscp->flags &= ~CM_SCACHEFLAG_WATCHEDSUBTREE;
7577 dscp->flags &= ~CM_SCACHEFLAG_WATCHED;
7578 lock_ReleaseMutex(&dscp->mx);
7580 /* Convert to response packet */
7581 ((smb_t *) watch)->reb = SMB_FLAGS_SERVER_TO_CLIENT | SMB_FLAGS_CANONICAL_PATHNAMES;
7582 ((smb_t *) watch)->wct = 0;
7585 if (filename == NULL)
7588 nameLen = (ULONG)strlen(filename);
7589 parmCount = 3*4 + nameLen*2;
7590 parmCount = (parmCount + 3) & ~3; /* pad to 4 */
7592 otherNameLen = (ULONG)strlen(otherFilename);
7593 oldParmCount = parmCount;
7594 parmCount += 3*4 + otherNameLen*2;
7595 parmCount = (parmCount + 3) & ~3; /* pad to 4 */
7597 if (maxLen < parmCount)
7598 parmCount = 0; /* not enough room */
7600 parmOffset = 8*4 + 39;
7601 parmOffset += 1; /* pad to 4 */
7602 dataOffset = parmOffset + parmCount;
7606 /* Total Parameter Count */
7607 smb_SetSMBParmLong(watch, parmSlot, parmCount); parmSlot += 2;
7608 /* Total Data Count */
7609 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
7610 /* Parameter Count */
7611 smb_SetSMBParmLong(watch, parmSlot, parmCount); parmSlot += 2;
7612 /* Parameter Offset */
7613 smb_SetSMBParmLong(watch, parmSlot, parmOffset); parmSlot += 2;
7614 /* Parameter Displacement */
7615 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
7617 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
7619 smb_SetSMBParmLong(watch, parmSlot, dataOffset); parmSlot += 2;
7620 /* Data Displacement */
7621 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
7622 smb_SetSMBParmByte(watch, parmSlot, 0); /* Setup Count */
7623 smb_SetSMBDataLength(watch, parmCount + 1);
7625 if (parmCount != 0) {
7627 outData = smb_GetSMBData(watch, NULL);
7628 outData++; /* round to get to parmOffset */
7629 oldOutData = outData;
7630 *((DWORD *)outData) = oldParmCount; outData += 4;
7631 /* Next Entry Offset */
7632 *((DWORD *)outData) = action; outData += 4;
7634 *((DWORD *)outData) = nameLen*2; outData += 4;
7635 /* File Name Length */
7636 p = strdup(filename);
7637 if (smb_StoreAnsiFilenames)
7639 mbstowcs((WCHAR *)outData, p, nameLen);
7643 outData = oldOutData + oldParmCount;
7644 *((DWORD *)outData) = 0; outData += 4;
7645 /* Next Entry Offset */
7646 *((DWORD *)outData) = otherAction; outData += 4;
7648 *((DWORD *)outData) = otherNameLen*2;
7649 outData += 4; /* File Name Length */
7650 p = strdup(otherFilename);
7651 if (smb_StoreAnsiFilenames)
7653 mbstowcs((WCHAR *)outData, p, otherNameLen); /* File Name */
7659 * If filename is null, we don't know the cause of the
7660 * change notification. We return zero data (see above),
7661 * and set error code to NT_STATUS_NOTIFY_ENUM_DIR
7662 * (= 0x010C). We set the error code here by hand, without
7663 * modifying wct and bcc.
7665 if (filename == NULL) {
7666 ((smb_t *) watch)->rcls = 0x0C;
7667 ((smb_t *) watch)->reh = 0x01;
7668 ((smb_t *) watch)->errLow = 0;
7669 ((smb_t *) watch)->errHigh = 0;
7670 /* Set NT Status codes flag */
7671 ((smb_t *) watch)->flg2 |= SMB_FLAGS2_32BIT_STATUS;
7674 smb_SendPacket(watch->vcp, watch);
7675 smb_FreePacket(watch);
7678 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
7681 long smb_ReceiveNTCancel(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7683 unsigned char *replyWctp;
7684 smb_packet_t *watch, *lastWatch;
7685 USHORT fid, watchtree;
7689 osi_Log0(smb_logp, "SMB3 receive NT cancel");
7691 lock_ObtainMutex(&smb_Dir_Watch_Lock);
7692 watch = smb_Directory_Watches;
7694 if (((smb_t *)watch)->uid == ((smb_t *)inp)->uid
7695 && ((smb_t *)watch)->pid == ((smb_t *)inp)->pid
7696 && ((smb_t *)watch)->mid == ((smb_t *)inp)->mid
7697 && ((smb_t *)watch)->tid == ((smb_t *)inp)->tid) {
7698 if (watch == smb_Directory_Watches)
7699 smb_Directory_Watches = watch->nextp;
7701 lastWatch->nextp = watch->nextp;
7702 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
7704 /* Turn off WATCHED flag in scp */
7705 fid = smb_GetSMBParm(watch, 21);
7706 watchtree = smb_GetSMBParm(watch, 22) & 0xffff;
7708 if (vcp != watch->vcp)
7709 osi_Log2(smb_logp, "smb_ReceiveNTCancel: vcp %x not equal to watch vcp %x",
7712 fidp = smb_FindFID(vcp, fid, 0);
7714 osi_Log3(smb_logp, "Cancelling change notification for fid %d wtree %d file %s",
7716 osi_LogSaveString(smb_logp, (fidp)?fidp->NTopen_wholepathp:""));
7719 lock_ObtainMutex(&scp->mx);
7721 scp->flags &= ~CM_SCACHEFLAG_WATCHEDSUBTREE;
7723 scp->flags &= ~CM_SCACHEFLAG_WATCHED;
7724 lock_ReleaseMutex(&scp->mx);
7725 smb_ReleaseFID(fidp);
7727 osi_Log2(smb_logp,"NTCancel unable to resolve fid [%d] in vcp[%x]", fid,vcp);
7730 /* assume STATUS32; return 0xC0000120 (CANCELED) */
7731 replyWctp = watch->wctp;
7735 ((smb_t *)watch)->rcls = 0x20;
7736 ((smb_t *)watch)->reh = 0x1;
7737 ((smb_t *)watch)->errLow = 0;
7738 ((smb_t *)watch)->errHigh = 0xC0;
7739 ((smb_t *)watch)->flg2 |= SMB_FLAGS2_32BIT_STATUS;
7740 smb_SendPacket(vcp, watch);
7741 smb_FreePacket(watch);
7745 watch = watch->nextp;
7747 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
7753 * NT rename also does hard links.
7756 #define RENAME_FLAG_MOVE_CLUSTER_INFORMATION 0x102
7757 #define RENAME_FLAG_HARD_LINK 0x103
7758 #define RENAME_FLAG_RENAME 0x104
7759 #define RENAME_FLAG_COPY 0x105
7761 long smb_ReceiveNTRename(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7763 char *oldPathp, *newPathp;
7769 attrs = smb_GetSMBParm(inp, 0);
7770 rename_type = smb_GetSMBParm(inp, 1);
7772 if (rename_type != RENAME_FLAG_RENAME && rename_type != RENAME_FLAG_HARD_LINK) {
7773 osi_Log1(smb_logp, "NTRename invalid infolevel [%x]", rename_type);
7774 return CM_ERROR_NOACCESS;
7777 tp = smb_GetSMBData(inp, NULL);
7778 oldPathp = smb_ParseASCIIBlock(tp, &tp);
7779 if (smb_StoreAnsiFilenames)
7780 OemToChar(oldPathp,oldPathp);
7781 newPathp = smb_ParseASCIIBlock(tp, &tp);
7782 if (smb_StoreAnsiFilenames)
7783 OemToChar(newPathp,newPathp);
7785 osi_Log3(smb_logp, "NTRename for [%s]->[%s] type [%s]",
7786 osi_LogSaveString(smb_logp, oldPathp),
7787 osi_LogSaveString(smb_logp, newPathp),
7788 ((rename_type==RENAME_FLAG_RENAME)?"rename":"hardlink"));
7790 if (rename_type == RENAME_FLAG_RENAME) {
7791 code = smb_Rename(vcp,inp,oldPathp,newPathp,attrs);
7792 } else { /* RENAME_FLAG_HARD_LINK */
7793 code = smb_Link(vcp,inp,oldPathp,newPathp);
7800 lock_InitializeMutex(&smb_Dir_Watch_Lock, "Directory Watch List Lock");
7803 cm_user_t *smb_FindCMUserByName(char *usern, char *machine, afs_uint32 flags)
7805 smb_username_t *unp;
7808 unp = smb_FindUserByName(usern, machine, flags);
7810 lock_ObtainMutex(&unp->mx);
7811 unp->userp = cm_NewUser();
7812 lock_ReleaseMutex(&unp->mx);
7813 osi_Log2(smb_logp,"smb_FindCMUserByName New user name[%s] machine[%s]",osi_LogSaveString(smb_logp,usern),osi_LogSaveString(smb_logp,machine));
7815 osi_Log2(smb_logp,"smb_FindCMUserByName Not found name[%s] machine[%s]",osi_LogSaveString(smb_logp,usern),osi_LogSaveString(smb_logp,machine));
7819 smb_ReleaseUsername(unp);