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,
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 /* now we have the status in the cache entry, and everything is locked.
2817 * Marshall the output data.
2819 /* for info level 108, figure out short name */
2820 if (infoLevel == SMB_QUERY_FILE_ALT_NAME_INFO) {
2821 code = cm_GetShortName(pathp, userp, &req,
2822 tidPathp, scp->fid.vnode, shortName,
2828 qpi.u.QPfileAltNameInfo.fileNameLength = (len + 1) * 2;
2829 mbstowcs((unsigned short *)qpi.u.QPfileAltNameInfo.fileName, shortName, len + 1);
2833 else if (infoLevel == SMB_QUERY_FILE_NAME_INFO) {
2834 len = strlen(lastComp);
2835 qpi.u.QPfileNameInfo.fileNameLength = (len + 1) * 2;
2836 mbstowcs((unsigned short *)qpi.u.QPfileNameInfo.fileName, lastComp, len + 1);
2840 else if (infoLevel == SMB_INFO_STANDARD || infoLevel == SMB_INFO_QUERY_EA_SIZE) {
2841 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
2842 qpi.u.QPstandardInfo.creationDateTime = dosTime;
2843 qpi.u.QPstandardInfo.lastAccessDateTime = dosTime;
2844 qpi.u.QPstandardInfo.lastWriteDateTime = dosTime;
2845 qpi.u.QPstandardInfo.dataSize = scp->length.LowPart;
2846 qpi.u.QPstandardInfo.allocationSize = scp->length.LowPart;
2847 attributes = smb_Attributes(scp);
2848 qpi.u.QPstandardInfo.attributes = attributes;
2849 qpi.u.QPstandardInfo.eaSize = 0;
2851 else if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
2852 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
2853 qpi.u.QPfileBasicInfo.creationTime = ft;
2854 qpi.u.QPfileBasicInfo.lastAccessTime = ft;
2855 qpi.u.QPfileBasicInfo.lastWriteTime = ft;
2856 qpi.u.QPfileBasicInfo.changeTime = ft;
2857 extAttributes = smb_ExtAttributes(scp);
2858 qpi.u.QPfileBasicInfo.attributes = extAttributes;
2859 qpi.u.QPfileBasicInfo.reserved = 0;
2861 else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO) {
2862 smb_fid_t *fidp = smb_FindFIDByScache(vcp, scp);
2864 lock_ObtainMutex(&fidp->mx);
2865 delonclose = fidp->flags & SMB_FID_DELONCLOSE;
2866 lock_ReleaseMutex(&fidp->mx);
2867 smb_ReleaseFID(fidp);
2870 qpi.u.QPfileStandardInfo.allocationSize = scp->length;
2871 qpi.u.QPfileStandardInfo.endOfFile = scp->length;
2872 qpi.u.QPfileStandardInfo.numberOfLinks = scp->linkCount;
2873 qpi.u.QPfileStandardInfo.deletePending = (delonclose ? 1 : 0);
2874 qpi.u.QPfileStandardInfo.directory =
2875 ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
2876 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
2877 scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0);
2878 qpi.u.QPfileStandardInfo.reserved = 0;
2880 else if (infoLevel == SMB_QUERY_FILE_EA_INFO) {
2881 qpi.u.QPfileEaInfo.eaSize = 0;
2883 else if (infoLevel == SMB_QUERY_FILE_ALL_INFO) {
2884 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
2885 qpi.u.QPfileAllInfo.creationTime = ft;
2886 qpi.u.QPfileAllInfo.lastAccessTime = ft;
2887 qpi.u.QPfileAllInfo.lastWriteTime = ft;
2888 qpi.u.QPfileAllInfo.changeTime = ft;
2889 extAttributes = smb_ExtAttributes(scp);
2890 qpi.u.QPfileAllInfo.attributes = extAttributes;
2891 qpi.u.QPfileAllInfo.allocationSize = scp->length;
2892 qpi.u.QPfileAllInfo.endOfFile = scp->length;
2893 qpi.u.QPfileAllInfo.numberOfLinks = scp->linkCount;
2894 qpi.u.QPfileAllInfo.deletePending = 0;
2895 qpi.u.QPfileAllInfo.directory =
2896 ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
2897 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
2898 scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0);
2899 qpi.u.QPfileAllInfo.indexNumber.HighPart = scp->fid.cell;
2900 qpi.u.QPfileAllInfo.indexNumber.LowPart = scp->fid.volume;
2901 qpi.u.QPfileAllInfo.eaSize = 0;
2902 qpi.u.QPfileAllInfo.accessFlags = 0;
2903 qpi.u.QPfileAllInfo.indexNumber2.HighPart = scp->fid.vnode;
2904 qpi.u.QPfileAllInfo.indexNumber2.LowPart = scp->fid.unique;
2905 qpi.u.QPfileAllInfo.currentByteOffset.HighPart = 0;
2906 qpi.u.QPfileAllInfo.currentByteOffset.LowPart = 0;
2907 qpi.u.QPfileAllInfo.mode = 0;
2908 qpi.u.QPfileAllInfo.alignmentRequirement = 0;
2909 len = strlen(lastComp);
2910 qpi.u.QPfileAllInfo.fileNameLength = (len + 1) * 2;
2911 mbstowcs((unsigned short *)qpi.u.QPfileAllInfo.fileName, lastComp, len + 1);
2914 /* send and free the packets */
2916 lock_ReleaseMutex(&scp->mx);
2917 cm_ReleaseSCache(scp);
2918 cm_ReleaseUser(userp);
2920 memcpy(outp->datap, &qpi, responseSize);
2921 smb_SendTran2Packet(vcp, outp, opx);
2923 smb_SendTran2Error(vcp, p, opx, code);
2925 smb_FreeTran2Packet(outp);
2930 long smb_ReceiveTran2SetPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
2933 osi_Log0(smb_logp,"ReceiveTran2SetPathInfo - NOT_SUPPORTED");
2934 return CM_ERROR_BADOP;
2938 unsigned short infoLevel;
2940 smb_tran2Packet_t *outp;
2941 smb_tran2QPathInfo_t *spi;
2943 cm_scache_t *scp, *dscp;
2951 infoLevel = p->parmsp[0];
2952 osi_Log1(smb_logp,"ReceiveTran2SetPathInfo type 0x%x", infoLevel);
2953 if (infoLevel != SMB_INFO_STANDARD &&
2954 infoLevel != SMB_INFO_QUERY_EA_SIZE &&
2955 infoLevel != SMB_INFO_QUERY_ALL_EAS) {
2956 osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
2957 p->opcode, infoLevel);
2958 smb_SendTran2Error(vcp, p, opx, CM_ERROR_INVAL);
2962 pathp = (char *)(&p->parmsp[3]);
2963 if (smb_StoreAnsiFilenames)
2964 OemToChar(pathp,pathp);
2965 osi_Log2(smb_logp, "T2 SetPathInfo infolevel 0x%x path %s", infoLevel,
2966 osi_LogSaveString(smb_logp, pathp));
2968 userp = smb_GetTran2User(vcp, p);
2970 osi_Log1(smb_logp,"ReceiveTran2SetPathInfo unable to resolve user [%d]", p->uid);
2971 code = CM_ERROR_BADSMB;
2975 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
2976 if (code == CM_ERROR_TIDIPC) {
2977 /* Attempt to use a TID allocated for IPC. The client
2978 * is probably looking for DCE RPC end points which we
2979 * don't support OR it could be looking to make a DFS
2982 osi_Log0(smb_logp, "Tran2Open received IPC TID");
2983 cm_ReleaseUser(userp);
2984 return CM_ERROR_NOSUCHPATH;
2988 * XXX Strange hack XXX
2990 * As of Patch 7 (13 January 98), we are having the following problem:
2991 * In NT Explorer 4.0, whenever we click on a directory, AFS gets
2992 * requests to look up "desktop.ini" in all the subdirectories.
2993 * This can cause zillions of timeouts looking up non-existent cells
2994 * and volumes, especially in the top-level directory.
2996 * We have not found any way to avoid this or work around it except
2997 * to explicitly ignore the requests for mount points that haven't
2998 * yet been evaluated and for directories that haven't yet been
3001 if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
3002 spacep = cm_GetSpace();
3003 smb_StripLastComponent(spacep->data, &lastComp, pathp);
3004 #ifndef SPECIAL_FOLDERS
3005 /* Make sure that lastComp is not NULL */
3007 if (stricmp(lastComp, "\\desktop.ini") == 0) {
3008 code = cm_NameI(cm_data.rootSCachep, spacep->data,
3012 userp, tidPathp, &req, &dscp);
3015 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
3016 if ( WANTS_DFS_PATHNAMES(p) )
3017 code = CM_ERROR_PATH_NOT_COVERED;
3019 code = CM_ERROR_BADSHARENAME;
3021 #endif /* DFS_SUPPORT */
3022 if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT && !dscp->mountRootFid.volume)
3023 code = CM_ERROR_NOSUCHFILE;
3024 else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
3025 cm_buf_t *bp = buf_Find(dscp, &hzero);
3029 code = CM_ERROR_NOSUCHFILE;
3031 cm_ReleaseSCache(dscp);
3033 cm_FreeSpace(spacep);
3034 cm_ReleaseUser(userp);
3035 smb_SendTran2Error(vcp, p, opx, code);
3041 #endif /* SPECIAL_FOLDERS */
3043 cm_FreeSpace(spacep);
3046 /* now do namei and stat, and copy out the info */
3047 code = cm_NameI(cm_data.rootSCachep, pathp,
3048 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, tidPathp, &req, &scp);
3050 cm_ReleaseUser(userp);
3051 smb_SendTran2Error(vcp, p, opx, code);
3055 fidp = smb_FindFIDByScache(vcp, scp);
3057 cm_ReleaseUser(userp);
3058 cm_ReleaseSCache(scp);
3059 smb_SendTran2Error(vcp, p, opx, code);
3063 lock_ObtainMutex(&fidp->mx);
3064 if (!(fidp->flags & SMB_FID_OPENWRITE)) {
3065 lock_ReleaseMutex(&fidp->mx);
3066 smb_ReleaseFID(fidp);
3067 cm_ReleaseUser(userp);
3068 cm_ReleaseSCache(scp);
3069 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOACCESS);
3072 lock_ReleaseMutex(&fidp->mx);
3074 outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, 0);
3076 outp->totalParms = 2;
3077 outp->totalData = 0;
3079 spi = (smb_tran2QPathInfo_t *)p->datap;
3080 if (infoLevel == SMB_INFO_STANDARD || infoLevel == SMB_INFO_QUERY_EA_SIZE) {
3083 /* lock the vnode with a callback; we need the current status
3084 * to determine what the new status is, in some cases.
3086 lock_ObtainMutex(&scp->mx);
3087 code = cm_SyncOp(scp, NULL, userp, &req, 0,
3088 CM_SCACHESYNC_GETSTATUS
3089 | CM_SCACHESYNC_NEEDCALLBACK);
3090 lock_ReleaseMutex(&scp->mx);
3095 lock_ObtainMutex(&fidp->mx);
3096 lock_ObtainMutex(&scp->mx);
3098 /* prepare for setattr call */
3099 attr.mask = CM_ATTRMASK_LENGTH;
3100 attr.length.LowPart = spi->u.QPstandardInfo.dataSize;
3101 attr.length.HighPart = 0;
3103 if (spi->u.QPstandardInfo.lastWriteDateTime != 0) {
3104 smb_UnixTimeFromSearchTime(&attr.clientModTime, spi->u.QPstandardInfo.lastWriteDateTime);
3105 attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
3106 fidp->flags |= SMB_FID_MTIMESETDONE;
3109 if (spi->u.QPstandardInfo.attributes != 0) {
3110 if ((scp->unixModeBits & 0222)
3111 && (spi->u.QPstandardInfo.attributes & SMB_ATTR_READONLY) != 0) {
3112 /* make a writable file read-only */
3113 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
3114 attr.unixModeBits = scp->unixModeBits & ~0222;
3116 else if ((scp->unixModeBits & 0222) == 0
3117 && (spi->u.QPstandardInfo.attributes & SMB_ATTR_READONLY) == 0) {
3118 /* make a read-only file writable */
3119 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
3120 attr.unixModeBits = scp->unixModeBits | 0222;
3123 lock_ReleaseMutex(&scp->mx);
3124 lock_ReleaseMutex(&fidp->mx);
3128 code = cm_SetAttr(scp, &attr, userp, &req);
3132 else if (infoLevel == SMB_INFO_QUERY_ALL_EAS) {
3133 /* we don't support EAs */
3134 code = CM_ERROR_INVAL;
3138 cm_ReleaseSCache(scp);
3139 cm_ReleaseUser(userp);
3140 smb_ReleaseFID(fidp);
3142 smb_SendTran2Packet(vcp, outp, opx);
3144 smb_SendTran2Error(vcp, p, opx, code);
3145 smb_FreeTran2Packet(outp);
3151 long smb_ReceiveTran2QFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
3153 smb_tran2Packet_t *outp;
3155 unsigned long attributes;
3156 unsigned short infoLevel;
3163 smb_tran2QFileInfo_t qfi;
3170 fidp = smb_FindFID(vcp, fid, 0);
3173 smb_SendTran2Error(vcp, p, opx, CM_ERROR_BADFD);
3177 infoLevel = p->parmsp[1];
3178 if (infoLevel == SMB_QUERY_FILE_BASIC_INFO)
3179 responseSize = sizeof(qfi.u.QFbasicInfo);
3180 else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO)
3181 responseSize = sizeof(qfi.u.QFstandardInfo);
3182 else if (infoLevel == SMB_QUERY_FILE_EA_INFO)
3183 responseSize = sizeof(qfi.u.QFeaInfo);
3184 else if (infoLevel == SMB_QUERY_FILE_NAME_INFO)
3185 responseSize = sizeof(qfi.u.QFfileNameInfo);
3187 osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
3188 p->opcode, infoLevel);
3189 smb_SendTran2Error(vcp, p, opx, CM_ERROR_BADOP);
3190 smb_ReleaseFID(fidp);
3193 osi_Log2(smb_logp, "T2 QFileInfo type 0x%x fid %d", infoLevel, fid);
3195 outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, responseSize);
3197 if (infoLevel > 0x100)
3198 outp->totalParms = 2;
3200 outp->totalParms = 0;
3201 outp->totalData = responseSize;
3203 userp = smb_GetTran2User(vcp, p);
3205 osi_Log1(smb_logp, "ReceiveTran2QFileInfo unable to resolve user [%d]", p->uid);
3206 code = CM_ERROR_BADSMB;
3210 lock_ObtainMutex(&fidp->mx);
3211 delonclose = fidp->flags & SMB_FID_DELONCLOSE;
3214 lock_ReleaseMutex(&fidp->mx);
3215 lock_ObtainMutex(&scp->mx);
3216 code = cm_SyncOp(scp, NULL, userp, &req, 0,
3217 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3221 /* now we have the status in the cache entry, and everything is locked.
3222 * Marshall the output data.
3224 if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
3225 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
3226 qfi.u.QFbasicInfo.creationTime = ft;
3227 qfi.u.QFbasicInfo.lastAccessTime = ft;
3228 qfi.u.QFbasicInfo.lastWriteTime = ft;
3229 qfi.u.QFbasicInfo.lastChangeTime = ft;
3230 attributes = smb_ExtAttributes(scp);
3231 qfi.u.QFbasicInfo.attributes = attributes;
3233 else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO) {
3234 qfi.u.QFstandardInfo.allocationSize = scp->length;
3235 qfi.u.QFstandardInfo.endOfFile = scp->length;
3236 qfi.u.QFstandardInfo.numberOfLinks = scp->linkCount;
3237 qfi.u.QFstandardInfo.deletePending = (delonclose ? 1 : 0);
3238 qfi.u.QFstandardInfo.directory =
3239 ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
3240 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
3241 scp->fileType == CM_SCACHETYPE_INVALID)? 1 : 0);
3243 else if (infoLevel == SMB_QUERY_FILE_EA_INFO) {
3244 qfi.u.QFeaInfo.eaSize = 0;
3246 else if (infoLevel == SMB_QUERY_FILE_NAME_INFO) {
3250 lock_ReleaseMutex(&scp->mx);
3251 lock_ObtainMutex(&fidp->mx);
3252 lock_ObtainMutex(&scp->mx);
3253 if (fidp->NTopen_wholepathp)
3254 name = fidp->NTopen_wholepathp;
3256 name = "\\"; /* probably can't happen */
3257 lock_ReleaseMutex(&fidp->mx);
3258 len = (unsigned long)strlen(name);
3259 outp->totalData = ((len+1)*2) + 4; /* this is actually what we want to return */
3260 qfi.u.QFfileNameInfo.fileNameLength = (len + 1) * 2;
3261 mbstowcs((unsigned short *)qfi.u.QFfileNameInfo.fileName, name, len + 1);
3264 /* send and free the packets */
3266 lock_ReleaseMutex(&scp->mx);
3267 cm_ReleaseSCache(scp);
3268 cm_ReleaseUser(userp);
3269 smb_ReleaseFID(fidp);
3271 memcpy(outp->datap, &qfi, responseSize);
3272 smb_SendTran2Packet(vcp, outp, opx);
3274 smb_SendTran2Error(vcp, p, opx, code);
3276 smb_FreeTran2Packet(outp);
3281 long smb_ReceiveTran2SetFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
3286 unsigned short infoLevel;
3287 smb_tran2Packet_t *outp;
3295 fidp = smb_FindFID(vcp, fid, 0);
3298 smb_SendTran2Error(vcp, p, opx, CM_ERROR_BADFD);
3302 infoLevel = p->parmsp[1];
3303 osi_Log2(smb_logp,"ReceiveTran2SetFileInfo type 0x%x fid %d", infoLevel, fid);
3304 if (infoLevel > SMB_SET_FILE_END_OF_FILE_INFO || infoLevel < SMB_SET_FILE_BASIC_INFO) {
3305 osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
3306 p->opcode, infoLevel);
3307 smb_SendTran2Error(vcp, p, opx, CM_ERROR_BADOP);
3308 smb_ReleaseFID(fidp);
3312 lock_ObtainMutex(&fidp->mx);
3313 if (infoLevel == SMB_SET_FILE_DISPOSITION_INFO && !(fidp->flags & SMB_FID_OPENDELETE)) {
3314 lock_ReleaseMutex(&fidp->mx);
3315 smb_ReleaseFID(fidp);
3316 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOACCESS);
3319 if ((infoLevel == SMB_SET_FILE_ALLOCATION_INFO ||
3320 infoLevel == SMB_SET_FILE_END_OF_FILE_INFO)
3321 && !(fidp->flags & SMB_FID_OPENWRITE)) {
3322 lock_ReleaseMutex(&fidp->mx);
3323 smb_ReleaseFID(fidp);
3324 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOACCESS);
3330 lock_ReleaseMutex(&fidp->mx);
3332 outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, 0);
3334 outp->totalParms = 2;
3335 outp->totalData = 0;
3337 userp = smb_GetTran2User(vcp, p);
3339 osi_Log1(smb_logp,"ReceiveTran2SetFileInfo unable to resolve user [%d]", p->uid);
3340 code = CM_ERROR_BADSMB;
3344 if (infoLevel == SMB_SET_FILE_BASIC_INFO) {
3346 unsigned int attribute;
3348 smb_tran2QFileInfo_t *sfi;
3350 sfi = (smb_tran2QFileInfo_t *)p->datap;
3352 /* lock the vnode with a callback; we need the current status
3353 * to determine what the new status is, in some cases.
3355 lock_ObtainMutex(&scp->mx);
3356 code = cm_SyncOp(scp, NULL, userp, &req, 0,
3357 CM_SCACHESYNC_GETSTATUS
3358 | CM_SCACHESYNC_NEEDCALLBACK);
3359 lock_ReleaseMutex(&scp->mx);
3363 lock_ObtainMutex(&fidp->mx);
3364 lock_ObtainMutex(&scp->mx);
3366 /* prepare for setattr call */
3369 lastMod = sfi->u.QFbasicInfo.lastWriteTime;
3370 /* when called as result of move a b, lastMod is (-1, -1).
3371 * If the check for -1 is not present, timestamp
3372 * of the resulting file will be 1969 (-1)
3374 if (LargeIntegerNotEqualToZero(*((LARGE_INTEGER *)&lastMod)) &&
3375 lastMod.dwLowDateTime != -1 && lastMod.dwHighDateTime != -1) {
3376 attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
3377 smb_UnixTimeFromLargeSearchTime(&attr.clientModTime, &lastMod);
3378 fidp->flags |= SMB_FID_MTIMESETDONE;
3381 attribute = sfi->u.QFbasicInfo.attributes;
3382 if (attribute != 0) {
3383 if ((scp->unixModeBits & 0222)
3384 && (attribute & SMB_ATTR_READONLY) != 0) {
3385 /* make a writable file read-only */
3386 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
3387 attr.unixModeBits = scp->unixModeBits & ~0222;
3389 else if ((scp->unixModeBits & 0222) == 0
3390 && (attribute & SMB_ATTR_READONLY) == 0) {
3391 /* make a read-only file writable */
3392 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
3393 attr.unixModeBits = scp->unixModeBits | 0222;
3396 lock_ReleaseMutex(&scp->mx);
3397 lock_ReleaseMutex(&fidp->mx);
3401 code = cm_SetAttr(scp, &attr, userp, &req);
3405 else if (infoLevel == SMB_SET_FILE_DISPOSITION_INFO) {
3406 if (*((char *)(p->datap))) { /* File is Deleted */
3407 code = cm_CheckNTDelete(fidp->NTopen_dscp, scp, userp,
3410 lock_ObtainMutex(&fidp->mx);
3411 fidp->flags |= SMB_FID_DELONCLOSE;
3412 lock_ReleaseMutex(&fidp->mx);
3417 lock_ObtainMutex(&fidp->mx);
3418 fidp->flags &= ~SMB_FID_DELONCLOSE;
3419 lock_ReleaseMutex(&fidp->mx);
3422 else if (infoLevel == SMB_SET_FILE_ALLOCATION_INFO ||
3423 infoLevel == SMB_SET_FILE_END_OF_FILE_INFO) {
3424 LARGE_INTEGER size = *((LARGE_INTEGER *)(p->datap));
3427 attr.mask = CM_ATTRMASK_LENGTH;
3428 attr.length.LowPart = size.LowPart;
3429 attr.length.HighPart = size.HighPart;
3430 code = cm_SetAttr(scp, &attr, userp, &req);
3434 cm_ReleaseSCache(scp);
3435 cm_ReleaseUser(userp);
3436 smb_ReleaseFID(fidp);
3438 smb_SendTran2Packet(vcp, outp, opx);
3440 smb_SendTran2Error(vcp, p, opx, code);
3441 smb_FreeTran2Packet(outp);
3447 smb_ReceiveTran2FSCTL(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3449 osi_Log0(smb_logp,"ReceiveTran2FSCTL - NOT_SUPPORTED");
3450 return CM_ERROR_BADOP;
3454 smb_ReceiveTran2IOCTL(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3456 osi_Log0(smb_logp,"ReceiveTran2IOCTL - NOT_SUPPORTED");
3457 return CM_ERROR_BADOP;
3461 smb_ReceiveTran2FindNotifyFirst(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3463 osi_Log0(smb_logp,"ReceiveTran2FindNotifyFirst - NOT_SUPPORTED");
3464 return CM_ERROR_BADOP;
3468 smb_ReceiveTran2FindNotifyNext(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3470 osi_Log0(smb_logp,"ReceiveTran2FindNotifyNext - NOT_SUPPORTED");
3471 return CM_ERROR_BADOP;
3475 smb_ReceiveTran2CreateDirectory(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3477 osi_Log0(smb_logp,"ReceiveTran2CreateDirectory - NOT_SUPPORTED");
3478 return CM_ERROR_BADOP;
3482 smb_ReceiveTran2SessionSetup(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3484 osi_Log0(smb_logp,"ReceiveTran2SessionSetup - NOT_SUPPORTED");
3485 return CM_ERROR_BADOP;
3488 struct smb_v2_referral {
3490 USHORT ReferralFlags;
3493 USHORT DfsPathOffset;
3494 USHORT DfsAlternativePathOffset;
3495 USHORT NetworkAddressOffset;
3499 smb_ReceiveTran2GetDFSReferral(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
3501 /* This is a UNICODE only request (bit15 of Flags2) */
3502 /* The TID must be IPC$ */
3504 /* The documentation for the Flags response field is contradictory */
3506 /* Use Version 1 Referral Element Format */
3507 /* ServerType = 0; indicates the next server should be queried for the file */
3508 /* ReferralFlags = 0x01; PathConsumed characters should be stripped */
3509 /* Node = UnicodeString of UNC path of the next share name */
3512 int maxReferralLevel = 0;
3513 char requestFileName[1024] = "";
3514 smb_tran2Packet_t *outp = 0;
3515 cm_user_t *userp = 0;
3517 CPINFO CodePageInfo;
3518 int i, nbnLen, reqLen;
3523 maxReferralLevel = p->parmsp[0];
3525 GetCPInfo(CP_ACP, &CodePageInfo);
3526 WideCharToMultiByte(CP_ACP, 0, (LPCWSTR) &p->parmsp[1], -1,
3527 requestFileName, 1024, NULL, NULL);
3529 osi_Log2(smb_logp,"ReceiveTran2GetDfsReferral [%d][%s]",
3530 maxReferralLevel, osi_LogSaveString(smb_logp, requestFileName));
3532 nbnLen = strlen(cm_NetbiosName);
3533 reqLen = strlen(requestFileName);
3535 if (reqLen == nbnLen + 5 &&
3536 requestFileName[0] == '\\' &&
3537 !_strnicmp(cm_NetbiosName,&requestFileName[1],nbnLen) &&
3538 requestFileName[nbnLen+1] == '\\' &&
3539 (!_strnicmp("all",&requestFileName[nbnLen+2],3) ||
3540 !_strnicmp("*.",&requestFileName[nbnLen+2],2)))
3543 struct smb_v2_referral * v2ref;
3544 outp = smb_GetTran2ResponsePacket(vcp, p, op, 0, 2 * (reqLen + 8));
3546 sp = (USHORT *)outp->datap;
3548 sp[idx++] = reqLen; /* path consumed */
3549 sp[idx++] = 1; /* number of referrals */
3550 sp[idx++] = 0x03; /* flags */
3551 #ifdef DFS_VERSION_1
3552 sp[idx++] = 1; /* Version Number */
3553 sp[idx++] = reqLen + 4; /* Referral Size */
3554 sp[idx++] = 1; /* Type = SMB Server */
3555 sp[idx++] = 0; /* Do not strip path consumed */
3556 for ( i=0;i<=reqLen; i++ )
3557 sp[i+idx] = requestFileName[i];
3558 #else /* DFS_VERSION_2 */
3559 sp[idx++] = 2; /* Version Number */
3560 sp[idx++] = sizeof(struct smb_v2_referral); /* Referral Size */
3561 idx += (sizeof(struct smb_v2_referral) / 2);
3562 v2ref = (struct smb_v2_referral *) &sp[5];
3563 v2ref->ServerType = 1; /* SMB Server */
3564 v2ref->ReferralFlags = 0x03;
3565 v2ref->Proximity = 0; /* closest */
3566 v2ref->TimeToLive = 3600; /* seconds */
3567 v2ref->DfsPathOffset = idx * 2;
3568 v2ref->DfsAlternativePathOffset = idx * 2;
3569 v2ref->NetworkAddressOffset = 0;
3570 for ( i=0;i<=reqLen; i++ )
3571 sp[i+idx] = requestFileName[i];
3574 userp = smb_GetTran2User(vcp, p);
3576 osi_Log1(smb_logp,"ReceiveTran2GetDfsReferral unable to resolve user [%d]", p->uid);
3577 code = CM_ERROR_BADSMB;
3582 code = CM_ERROR_NOSUCHPATH;
3587 cm_ReleaseUser(userp);
3589 smb_SendTran2Packet(vcp, outp, op);
3591 smb_SendTran2Error(vcp, p, op, code);
3593 smb_FreeTran2Packet(outp);
3596 #else /* DFS_SUPPORT */
3597 osi_Log0(smb_logp,"ReceiveTran2GetDfsReferral - NOT_SUPPORTED");
3598 return CM_ERROR_BADOP;
3599 #endif /* DFS_SUPPORT */
3603 smb_ReceiveTran2ReportDFSInconsistency(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3605 /* This is a UNICODE only request (bit15 of Flags2) */
3607 /* There is nothing we can do about this operation. The client is going to
3608 * tell us that there is a Version 1 Referral Element for which there is a DFS Error.
3609 * Unfortunately, there is really nothing we can do about it other then log it
3610 * somewhere. Even then I don't think there is anything for us to do.
3611 * So let's return an error value.
3614 osi_Log0(smb_logp,"ReceiveTran2ReportDFSInconsistency - NOT_SUPPORTED");
3615 return CM_ERROR_BADOP;
3619 smb_ApplyV3DirListPatches(cm_scache_t *dscp,
3620 smb_dirListPatch_t **dirPatchespp, int infoLevel, cm_user_t *userp,
3625 cm_scache_t *targetScp; /* target if scp is a symlink */
3630 unsigned short attr;
3631 unsigned long lattr;
3632 smb_dirListPatch_t *patchp;
3633 smb_dirListPatch_t *npatchp;
3635 for(patchp = *dirPatchespp; patchp; patchp =
3636 (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
3637 code = cm_GetSCache(&patchp->fid, &scp, userp, reqp);
3639 lock_ObtainMutex(&scp->mx);
3640 code = cm_SyncOp(scp, NULL, userp, reqp, 0,
3641 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3643 lock_ReleaseMutex(&scp->mx);
3644 cm_ReleaseSCache(scp);
3646 dptr = patchp->dptr;
3648 /* Plug in fake timestamps. A time stamp of 0 causes 'invalid parameter'
3649 errors in the client. */
3650 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO) {
3651 /* 1969-12-31 23:59:59 +00 */
3652 ft.dwHighDateTime = 0x19DB200;
3653 ft.dwLowDateTime = 0x5BB78980;
3655 /* copy to Creation Time */
3656 *((FILETIME *)dptr) = ft;
3659 /* copy to Last Access Time */
3660 *((FILETIME *)dptr) = ft;
3663 /* copy to Last Write Time */
3664 *((FILETIME *)dptr) = ft;
3667 /* copy to Change Time */
3668 *((FILETIME *)dptr) = ft;
3671 /* merge in hidden attribute */
3672 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
3673 *((u_long *)dptr) = SMB_ATTR_HIDDEN;
3677 /* 1969-12-31 23:59:58 +00*/
3678 dosTime = 0xEBBFBF7D;
3680 /* and copy out date */
3681 shortTemp = (dosTime>>16) & 0xffff;
3682 *((u_short *)dptr) = shortTemp;
3685 /* copy out creation time */
3686 shortTemp = dosTime & 0xffff;
3687 *((u_short *)dptr) = shortTemp;
3690 /* and copy out date */
3691 shortTemp = (dosTime>>16) & 0xffff;
3692 *((u_short *)dptr) = shortTemp;
3695 /* copy out access 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 mod time */
3706 shortTemp = dosTime & 0xffff;
3707 *((u_short *)dptr) = shortTemp;
3710 /* merge in hidden (dot file) attribute */
3711 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
3712 attr = SMB_ATTR_HIDDEN;
3713 *dptr++ = attr & 0xff;
3714 *dptr++ = (attr >> 8) & 0xff;
3720 /* now watch for a symlink */
3722 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
3723 lock_ReleaseMutex(&scp->mx);
3724 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, reqp);
3726 /* we have a more accurate file to use (the
3727 * target of the symbolic link). Otherwise,
3728 * we'll just use the symlink anyway.
3730 osi_Log2(smb_logp, "symlink vp %x to vp %x",
3732 cm_ReleaseSCache(scp);
3735 lock_ObtainMutex(&scp->mx);
3738 dptr = patchp->dptr;
3740 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO) {
3742 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
3744 /* copy to Creation Time */
3745 *((FILETIME *)dptr) = ft;
3748 /* copy to Last Access Time */
3749 *((FILETIME *)dptr) = ft;
3752 /* copy to Last Write Time */
3753 *((FILETIME *)dptr) = ft;
3756 /* copy to Change Time */
3757 *((FILETIME *)dptr) = ft;
3760 /* Use length for both file length and alloc length */
3761 *((LARGE_INTEGER *)dptr) = scp->length;
3763 *((LARGE_INTEGER *)dptr) = scp->length;
3766 /* Copy attributes */
3767 lattr = smb_ExtAttributes(scp);
3768 if (code == CM_ERROR_NOSUCHPATH && scp->fileType == CM_SCACHETYPE_SYMLINK) {
3769 if (lattr == SMB_ATTR_NORMAL)
3770 lattr = SMB_ATTR_DIRECTORY;
3772 lattr |= SMB_ATTR_DIRECTORY;
3774 /* merge in hidden (dot file) attribute */
3775 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
3776 if (lattr == SMB_ATTR_NORMAL)
3777 lattr = SMB_ATTR_HIDDEN;
3779 lattr |= SMB_ATTR_HIDDEN;
3781 *((u_long *)dptr) = lattr;
3785 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
3787 /* and copy out date */
3788 shortTemp = (dosTime>>16) & 0xffff;
3789 *((u_short *)dptr) = shortTemp;
3792 /* copy out creation time */
3793 shortTemp = dosTime & 0xffff;
3794 *((u_short *)dptr) = shortTemp;
3797 /* and copy out date */
3798 shortTemp = (dosTime>>16) & 0xffff;
3799 *((u_short *)dptr) = shortTemp;
3802 /* copy out access time */
3803 shortTemp = dosTime & 0xffff;
3804 *((u_short *)dptr) = shortTemp;
3807 /* and copy out date */
3808 shortTemp = (dosTime>>16) & 0xffff;
3809 *((u_short *)dptr) = shortTemp;
3812 /* copy out mod time */
3813 shortTemp = dosTime & 0xffff;
3814 *((u_short *)dptr) = shortTemp;
3817 /* copy out file length and alloc length,
3818 * using the same for both
3820 *((u_long *)dptr) = scp->length.LowPart;
3822 *((u_long *)dptr) = scp->length.LowPart;
3825 /* finally copy out attributes as short */
3826 attr = smb_Attributes(scp);
3827 /* merge in hidden (dot file) attribute */
3828 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
3829 if (lattr == SMB_ATTR_NORMAL)
3830 lattr = SMB_ATTR_HIDDEN;
3832 lattr |= SMB_ATTR_HIDDEN;
3834 *dptr++ = attr & 0xff;
3835 *dptr++ = (attr >> 8) & 0xff;
3838 lock_ReleaseMutex(&scp->mx);
3839 cm_ReleaseSCache(scp);
3842 /* now free the patches */
3843 for (patchp = *dirPatchespp; patchp; patchp = npatchp) {
3844 npatchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q);
3848 /* and mark the list as empty */
3849 *dirPatchespp = NULL;
3854 #ifndef USE_OLD_MATCHING
3855 // char table for case insensitive comparison
3856 char mapCaseTable[256];
3858 VOID initUpperCaseTable(VOID)
3861 for (i = 0; i < 256; ++i)
3862 mapCaseTable[i] = toupper(i);
3863 // make '"' match '.'
3864 mapCaseTable[(int)'"'] = toupper('.');
3865 // make '<' match '*'
3866 mapCaseTable[(int)'<'] = toupper('*');
3867 // make '>' match '?'
3868 mapCaseTable[(int)'>'] = toupper('?');
3871 // Compare 'pattern' (containing metacharacters '*' and '?') with the file
3873 // Note : this procedure works recursively calling itself.
3875 // PSZ pattern : string containing metacharacters.
3876 // PSZ name : file name to be compared with 'pattern'.
3878 // BOOL : TRUE/FALSE (match/mistmatch)
3881 szWildCardMatchFileName(PSZ pattern, PSZ name, int casefold)
3883 PSZ pename; // points to the last 'name' character
3885 pename = name + strlen(name) - 1;
3896 if (*pattern == '\0')
3898 for (p = pename; p >= name; --p) {
3899 if ((casefold && (mapCaseTable[*p] == mapCaseTable[*pattern]) ||
3900 !casefold && (*p == *pattern)) &&
3901 szWildCardMatchFileName(pattern + 1, p + 1, casefold))
3906 if ((casefold && mapCaseTable[*name] != mapCaseTable[*pattern]) ||
3907 (!casefold && *name != *pattern))
3914 /* if all we have left are wildcards, then we match */
3915 for (;*pattern; pattern++) {
3916 if (*pattern != '*' && *pattern != '?')
3922 /* do a case-folding search of the star name mask with the name in namep.
3923 * Return 1 if we match, otherwise 0.
3925 int smb_V3MatchMask(char *namep, char *maskp, int flags)
3928 int i, j, star, qmark, casefold, retval;
3930 /* make sure we only match 8.3 names, if requested */
3931 if ((flags & CM_FLAG_8DOT3) && !cm_Is8Dot3(namep))
3934 casefold = (flags & CM_FLAG_CASEFOLD) ? 1 : 0;
3936 /* optimize the pattern:
3937 * if there is a mixture of '?' and '*',
3938 * for example the sequence "*?*?*?*"
3939 * must be turned into the form "*"
3941 newmask = (char *)malloc(strlen(maskp)+1);
3942 for ( i=0, j=0, star=0, qmark=0; maskp[i]; i++) {
3943 switch ( maskp[i] ) {
3955 } else if ( qmark ) {
3959 newmask[j++] = maskp[i];
3966 } else if ( qmark ) {
3970 newmask[j++] = '\0';
3972 retval = szWildCardMatchFileName(newmask, namep, casefold) ? 1:0;
3978 #else /* USE_OLD_MATCHING */
3979 /* do a case-folding search of the star name mask with the name in namep.
3980 * Return 1 if we match, otherwise 0.
3982 int smb_V3MatchMask(char *namep, char *maskp, int flags)
3984 unsigned char tcp1, tcp2; /* Pattern characters */
3985 unsigned char tcn1; /* Name characters */
3986 int sawDot = 0, sawStar = 0, req8dot3 = 0;
3987 char *starNamep, *starMaskp;
3988 static char nullCharp[] = {0};
3989 int casefold = flags & CM_FLAG_CASEFOLD;
3991 /* make sure we only match 8.3 names, if requested */
3992 req8dot3 = (flags & CM_FLAG_8DOT3);
3993 if (req8dot3 && !cm_Is8Dot3(namep))
3998 /* Next pattern character */
4001 /* Next name character */
4005 /* 0 - end of pattern */
4011 else if (tcp1 == '.' || tcp1 == '"') {
4021 * first dot in pattern;
4022 * must match dot or end of name
4027 else if (tcn1 == '.') {
4036 else if (tcp1 == '?') {
4037 if (tcn1 == 0 || tcn1 == '.')
4042 else if (tcp1 == '>') {
4043 if (tcn1 != 0 && tcn1 != '.')
4047 else if (tcp1 == '*' || tcp1 == '<') {
4051 else if ((req8dot3 && tcp2 == '.') || tcp2 == '"') {
4052 while (req8dot3 && tcn1 != '.' && tcn1 != 0)
4067 * pattern character after '*' is not null or
4068 * period. If it is '?' or '>', we are not
4069 * going to understand it. If it is '*' or
4070 * '<', we are going to skip over it. None of
4071 * these are likely, I hope.
4073 /* skip over '*' and '<' */
4074 while (tcp2 == '*' || tcp2 == '<')
4077 /* skip over characters that don't match tcp2 */
4078 while (req8dot3 && tcn1 != '.' && tcn1 != 0 &&
4079 ((casefold && cm_foldUpper[tcn1] != cm_foldUpper[tcp2]) ||
4080 (!casefold && tcn1 != tcp2)))
4084 if ((req8dot3 && tcn1 == '.') || tcn1 == 0)
4087 /* Remember where we are */
4097 /* tcp1 is not a wildcard */
4098 if ((casefold && cm_foldUpper[tcn1] == cm_foldUpper[tcp1]) ||
4099 (!casefold && tcn1 == tcp1)) {
4104 /* if trying to match a star pattern, go back */
4106 maskp = starMaskp - 2;
4107 namep = starNamep + 1;
4116 #endif /* USE_OLD_MATCHING */
4118 long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
4123 long code = 0, code2 = 0;
4127 smb_dirListPatch_t *dirListPatchesp;
4128 smb_dirListPatch_t *curPatchp;
4131 long orbytes; /* # of bytes in this output record */
4132 long ohbytes; /* # of bytes, except file name */
4133 long onbytes; /* # of bytes in name, incl. term. null */
4134 osi_hyper_t dirLength;
4135 osi_hyper_t bufferOffset;
4136 osi_hyper_t curOffset;
4138 smb_dirSearch_t *dsp;
4142 cm_pageHeader_t *pageHeaderp;
4143 cm_user_t *userp = NULL;
4146 long nextEntryCookie;
4147 int numDirChunks; /* # of 32 byte dir chunks in this entry */
4148 char *op; /* output data ptr */
4149 char *origOp; /* original value of op */
4150 cm_space_t *spacep; /* for pathname buffer */
4151 long maxReturnData; /* max # of return data */
4152 long maxReturnParms; /* max # of return parms */
4153 long bytesInBuffer; /* # data bytes in the output buffer */
4155 char *maskp; /* mask part of path */
4159 smb_tran2Packet_t *outp; /* response packet */
4162 char shortName[13]; /* 8.3 name if needed */
4174 if (p->opcode == 1) {
4175 /* find first; obtain basic parameters from request */
4176 attribute = p->parmsp[0];
4177 maxCount = p->parmsp[1];
4178 infoLevel = p->parmsp[3];
4179 searchFlags = p->parmsp[2];
4180 dsp = smb_NewDirSearch(1);
4181 dsp->attribute = attribute;
4182 pathp = ((char *) p->parmsp) + 12; /* points to path */
4183 if (smb_StoreAnsiFilenames)
4184 OemToChar(pathp,pathp);
4186 maskp = strrchr(pathp, '\\');
4190 maskp++; /* skip over backslash */
4191 strcpy(dsp->mask, maskp); /* and save mask */
4192 /* track if this is likely to match a lot of entries */
4193 starPattern = smb_V3IsStarMask(maskp);
4196 osi_assert(p->opcode == 2);
4197 /* find next; obtain basic parameters from request or open dir file */
4198 dsp = smb_FindDirSearch(p->parmsp[0]);
4199 maxCount = p->parmsp[1];
4200 infoLevel = p->parmsp[2];
4201 nextCookie = p->parmsp[3] | (p->parmsp[4] << 16);
4202 searchFlags = p->parmsp[5];
4204 osi_Log2(smb_logp, "T2 search dir bad search ID: id %d nextCookie 0x%x",
4205 p->parmsp[0], nextCookie);
4206 return CM_ERROR_BADFD;
4208 attribute = dsp->attribute;
4211 starPattern = 1; /* assume, since required a Find Next */
4214 switch ( infoLevel ) {
4215 case SMB_INFO_STANDARD:
4218 case SMB_INFO_QUERY_EA_SIZE:
4219 s = "InfoQueryEaSize";
4221 case SMB_INFO_QUERY_EAS_FROM_LIST:
4222 s = "InfoQueryEasFromList";
4224 case SMB_FIND_FILE_DIRECTORY_INFO:
4225 s = "FindFileDirectoryInfo";
4227 case SMB_FIND_FILE_FULL_DIRECTORY_INFO:
4228 s = "FindFileFullDirectoryInfo";
4230 case SMB_FIND_FILE_NAMES_INFO:
4231 s = "FindFileNamesInfo";
4233 case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
4234 s = "FindFileBothDirectoryInfo";
4237 s = "unknownInfoLevel";
4240 osi_Log1(smb_logp, "T2 search dir info level: %s", s);
4243 "T2 search dir attr 0x%x, info level 0x%x, max count %d, flags 0x%x",
4244 attribute, infoLevel, maxCount, searchFlags);
4246 osi_Log3(smb_logp, "...T2 search op %d, id %d, nextCookie 0x%x",
4247 p->opcode, dsp->cookie, nextCookie);
4249 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO)
4250 searchFlags &= ~4; /* no resume keys */
4252 dirListPatchesp = NULL;
4254 maxReturnData = p->maxReturnData;
4255 if (p->opcode == 1) /* find first */
4256 maxReturnParms = 10; /* bytes */
4258 maxReturnParms = 8; /* bytes */
4260 #ifndef CM_CONFIG_MULTITRAN2RESPONSES
4261 if (maxReturnData > 6000)
4262 maxReturnData = 6000;
4263 #endif /* CM_CONFIG_MULTITRAN2RESPONSES */
4265 outp = smb_GetTran2ResponsePacket(vcp, p, opx, maxReturnParms,
4268 osi_Log2(smb_logp, "T2 receive search dir count %d [%s]",
4269 maxCount, osi_LogSaveString(smb_logp, pathp));
4271 /* bail out if request looks bad */
4272 if (p->opcode == 1 && !pathp) {
4273 smb_ReleaseDirSearch(dsp);
4274 smb_FreeTran2Packet(outp);
4275 return CM_ERROR_BADSMB;
4278 osi_Log3(smb_logp, "T2 search dir id %d, nextCookie 0x%x, attr 0x%x",
4279 dsp->cookie, nextCookie, attribute);
4281 userp = smb_GetTran2User(vcp, p);
4283 osi_Log1(smb_logp, "T2 search dir unable to resolve user [%d]", p->uid);
4284 smb_ReleaseDirSearch(dsp);
4285 smb_FreeTran2Packet(outp);
4286 return CM_ERROR_BADSMB;
4289 /* try to get the vnode for the path name next */
4290 lock_ObtainMutex(&dsp->mx);
4296 spacep = cm_GetSpace();
4297 smb_StripLastComponent(spacep->data, NULL, pathp);
4298 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
4300 cm_ReleaseUser(userp);
4301 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOFILES);
4302 smb_FreeTran2Packet(outp);
4303 lock_ReleaseMutex(&dsp->mx);
4304 smb_DeleteDirSearch(dsp);
4305 smb_ReleaseDirSearch(dsp);
4308 code = cm_NameI(cm_data.rootSCachep, spacep->data,
4309 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
4310 userp, tidPathp, &req, &scp);
4311 cm_FreeSpace(spacep);
4314 #ifdef DFS_SUPPORT_BUT_NOT_FIND_FIRST
4315 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
4316 cm_ReleaseSCache(scp);
4317 cm_ReleaseUser(userp);
4318 if ( WANTS_DFS_PATHNAMES(p) )
4319 code = CM_ERROR_PATH_NOT_COVERED;
4321 code = CM_ERROR_BADSHARENAME;
4322 smb_SendTran2Error(vcp, p, opx, code);
4323 smb_FreeTran2Packet(outp);
4324 lock_ReleaseMutex(&dsp->mx);
4325 smb_DeleteDirSearch(dsp);
4326 smb_ReleaseDirSearch(dsp);
4329 #endif /* DFS_SUPPORT */
4331 /* we need one hold for the entry we just stored into,
4332 * and one for our own processing. When we're done
4333 * with this function, we'll drop the one for our own
4334 * processing. We held it once from the namei call,
4335 * and so we do another hold now.
4338 lock_ObtainMutex(&scp->mx);
4339 if ((scp->flags & CM_SCACHEFLAG_BULKSTATTING) == 0 &&
4340 LargeIntegerGreaterOrEqualToZero(scp->bulkStatProgress)) {
4341 scp->flags |= CM_SCACHEFLAG_BULKSTATTING;
4342 dsp->flags |= SMB_DIRSEARCH_BULKST;
4344 lock_ReleaseMutex(&scp->mx);
4347 lock_ReleaseMutex(&dsp->mx);
4349 cm_ReleaseUser(userp);
4350 smb_FreeTran2Packet(outp);
4351 smb_DeleteDirSearch(dsp);
4352 smb_ReleaseDirSearch(dsp);
4356 /* get the directory size */
4357 lock_ObtainMutex(&scp->mx);
4358 code = cm_SyncOp(scp, NULL, userp, &req, 0,
4359 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4361 lock_ReleaseMutex(&scp->mx);
4362 cm_ReleaseSCache(scp);
4363 cm_ReleaseUser(userp);
4364 smb_FreeTran2Packet(outp);
4365 smb_DeleteDirSearch(dsp);
4366 smb_ReleaseDirSearch(dsp);
4371 dirLength = scp->length;
4373 bufferOffset.LowPart = bufferOffset.HighPart = 0;
4374 curOffset.HighPart = 0;
4375 curOffset.LowPart = nextCookie;
4376 origOp = outp->datap;
4384 if (searchFlags & 4)
4385 /* skip over resume key */
4388 /* make sure that curOffset.LowPart doesn't point to the first
4389 * 32 bytes in the 2nd through last dir page, and that it doesn't
4390 * point at the first 13 32-byte chunks in the first dir page,
4391 * since those are dir and page headers, and don't contain useful
4394 temp = curOffset.LowPart & (2048-1);
4395 if (curOffset.HighPart == 0 && curOffset.LowPart < 2048) {
4396 /* we're in the first page */
4397 if (temp < 13*32) temp = 13*32;
4400 /* we're in a later dir page */
4401 if (temp < 32) temp = 32;
4404 /* make sure the low order 5 bits are zero */
4407 /* now put temp bits back ito curOffset.LowPart */
4408 curOffset.LowPart &= ~(2048-1);
4409 curOffset.LowPart |= temp;
4411 /* check if we've passed the dir's EOF */
4412 if (LargeIntegerGreaterThanOrEqualTo(curOffset, dirLength)) {
4413 osi_Log0(smb_logp, "T2 search dir passed eof");
4418 /* check if we've returned all the names that will fit in the
4419 * response packet; we check return count as well as the number
4420 * of bytes requested. We check the # of bytes after we find
4421 * the dir entry, since we'll need to check its size.
4423 if (returnedNames >= maxCount) {
4424 osi_Log2(smb_logp, "T2 search dir returnedNames %d >= maxCount %d",
4425 returnedNames, maxCount);
4429 /* see if we can use the bufferp we have now; compute in which
4430 * page the current offset would be, and check whether that's
4431 * the offset of the buffer we have. If not, get the buffer.
4433 thyper.HighPart = curOffset.HighPart;
4434 thyper.LowPart = curOffset.LowPart & ~(cm_data.buf_blockSize-1);
4435 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
4438 buf_Release(bufferp);
4441 lock_ReleaseMutex(&scp->mx);
4442 lock_ObtainRead(&scp->bufCreateLock);
4443 code = buf_Get(scp, &thyper, &bufferp);
4444 lock_ReleaseRead(&scp->bufCreateLock);
4445 lock_ObtainMutex(&dsp->mx);
4447 /* now, if we're doing a star match, do bulk fetching
4448 * of all of the status info for files in the dir.
4451 smb_ApplyV3DirListPatches(scp, &dirListPatchesp,
4454 lock_ObtainMutex(&scp->mx);
4455 if ((dsp->flags & SMB_DIRSEARCH_BULKST) &&
4456 LargeIntegerGreaterThanOrEqualTo(thyper, scp->bulkStatProgress)) {
4457 /* Don't bulk stat if risking timeout */
4458 int now = GetTickCount();
4459 if (now - req.startTime > RDRtimeout) {
4460 scp->bulkStatProgress = thyper;
4461 scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
4462 dsp->flags &= ~SMB_DIRSEARCH_BULKST;
4464 code = cm_TryBulkStat(scp, &thyper, userp, &req);
4467 lock_ObtainMutex(&scp->mx);
4469 lock_ReleaseMutex(&dsp->mx);
4471 osi_Log2(smb_logp, "T2 search dir buf_Get scp %x failed %d", scp, code);
4475 bufferOffset = thyper;
4477 /* now get the data in the cache */
4479 code = cm_SyncOp(scp, bufferp, userp, &req,
4481 CM_SCACHESYNC_NEEDCALLBACK
4482 | CM_SCACHESYNC_READ);
4484 osi_Log2(smb_logp, "T2 search dir cm_SyncOp scp %x failed %d", scp, code);
4488 if (cm_HaveBuffer(scp, bufferp, 0)) {
4489 osi_Log2(smb_logp, "T2 search dir !HaveBuffer scp %x bufferp %x", scp, bufferp);
4493 /* otherwise, load the buffer and try again */
4494 code = cm_GetBuffer(scp, bufferp, NULL, userp,
4497 osi_Log3(smb_logp, "T2 search dir cm_GetBuffer failed scp %x bufferp %x code %d",
4498 scp, bufferp, code);
4503 buf_Release(bufferp);
4507 } /* if (wrong buffer) ... */
4509 /* now we have the buffer containing the entry we're interested
4510 * in; copy it out if it represents a non-deleted entry.
4512 entryInDir = curOffset.LowPart & (2048-1);
4513 entryInBuffer = curOffset.LowPart & (cm_data.buf_blockSize - 1);
4515 /* page header will help tell us which entries are free. Page
4516 * header can change more often than once per buffer, since
4517 * AFS 3 dir page size may be less than (but not more than)
4518 * a buffer package buffer.
4520 /* only look intra-buffer */
4521 temp = curOffset.LowPart & (cm_data.buf_blockSize - 1);
4522 temp &= ~(2048 - 1); /* turn off intra-page bits */
4523 pageHeaderp = (cm_pageHeader_t *) (bufferp->datap + temp);
4525 /* now determine which entry we're looking at in the page.
4526 * If it is free (there's a free bitmap at the start of the
4527 * dir), we should skip these 32 bytes.
4529 slotInPage = (entryInDir & 0x7e0) >> 5;
4530 if (!(pageHeaderp->freeBitmap[slotInPage>>3] &
4531 (1 << (slotInPage & 0x7)))) {
4532 /* this entry is free */
4533 numDirChunks = 1; /* only skip this guy */
4537 tp = bufferp->datap + entryInBuffer;
4538 dep = (cm_dirEntry_t *) tp; /* now points to AFS3 dir entry */
4540 /* while we're here, compute the next entry's location, too,
4541 * since we'll need it when writing out the cookie into the dir
4544 * XXXX Probably should do more sanity checking.
4546 numDirChunks = cm_NameEntries(dep->name, &onbytes);
4548 /* compute offset of cookie representing next entry */
4549 nextEntryCookie = curOffset.LowPart + (CM_DIR_CHUNKSIZE * numDirChunks);
4551 /* Need 8.3 name? */
4553 if (infoLevel == SMB_FIND_FILE_BOTH_DIRECTORY_INFO
4554 && dep->fid.vnode != 0
4555 && !cm_Is8Dot3(dep->name)) {
4556 cm_Gen8Dot3Name(dep, shortName, &shortNameEnd);
4560 osi_Log4(smb_logp, "T2 search dir vn %u uniq %u name %s (%s)",
4561 dep->fid.vnode, dep->fid.unique,
4562 osi_LogSaveString(smb_logp, dep->name),
4563 NeedShortName ? osi_LogSaveString(smb_logp, shortName) : "");
4565 /* When matching, we are using doing a case fold if we have a wildcard mask.
4566 * If we get a non-wildcard match, it's a lookup for a specific file.
4568 if (dep->fid.vnode != 0 &&
4569 (smb_V3MatchMask(dep->name, maskp, (starPattern? CM_FLAG_CASEFOLD : 0)) ||
4571 smb_V3MatchMask(shortName, maskp, CM_FLAG_CASEFOLD)))) {
4573 /* Eliminate entries that don't match requested attributes */
4574 if (smb_hideDotFiles && !(dsp->attribute & SMB_ATTR_HIDDEN) &&
4575 smb_IsDotFile(dep->name)) {
4576 osi_Log0(smb_logp, "T2 search dir skipping hidden");
4577 goto nextEntry; /* no hidden files */
4579 if (!(dsp->attribute & SMB_ATTR_DIRECTORY)) /* no directories */
4581 /* We have already done the cm_TryBulkStat above */
4582 fid.cell = scp->fid.cell;
4583 fid.volume = scp->fid.volume;
4584 fid.vnode = ntohl(dep->fid.vnode);
4585 fid.unique = ntohl(dep->fid.unique);
4586 fileType = cm_FindFileType(&fid);
4587 /*osi_Log2(smb_logp, "smb_ReceiveTran2SearchDir: file %s "
4588 "has filetype %d", dep->name,
4590 if (fileType == CM_SCACHETYPE_DIRECTORY ||
4591 fileType == CM_SCACHETYPE_DFSLINK ||
4592 fileType == CM_SCACHETYPE_INVALID)
4593 osi_Log0(smb_logp, "T2 search dir skipping directory or bad link");
4597 /* finally check if this name will fit */
4599 /* standard dir entry stuff */
4600 if (infoLevel < 0x101)
4601 ohbytes = 23; /* pre-NT */
4602 else if (infoLevel == SMB_FIND_FILE_NAMES_INFO)
4603 ohbytes = 12; /* NT names only */
4605 ohbytes = 64; /* NT */
4607 if (infoLevel == SMB_FIND_FILE_BOTH_DIRECTORY_INFO)
4608 ohbytes += 26; /* Short name & length */
4610 if (searchFlags & 4) {
4611 ohbytes += 4; /* if resume key required */
4614 if (infoLevel != SMB_INFO_STANDARD
4615 && infoLevel != SMB_FIND_FILE_DIRECTORY_INFO
4616 && infoLevel != SMB_FIND_FILE_NAMES_INFO)
4617 ohbytes += 4; /* EASIZE */
4619 /* add header to name & term. null */
4620 orbytes = onbytes + ohbytes + 1;
4622 /* now, we round up the record to a 4 byte alignment,
4623 * and we make sure that we have enough room here for
4624 * even the aligned version (so we don't have to worry
4625 * about an * overflow when we pad things out below).
4626 * That's the reason for the alignment arithmetic below.
4628 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO)
4629 align = (4 - (orbytes & 3)) & 3;
4632 if (orbytes + bytesInBuffer + align > maxReturnData) {
4633 osi_Log1(smb_logp, "T2 dir search exceed max return data %d",
4638 /* this is one of the entries to use: it is not deleted
4639 * and it matches the star pattern we're looking for.
4640 * Put out the name, preceded by its length.
4642 /* First zero everything else */
4643 memset(origOp, 0, ohbytes);
4645 if (infoLevel <= SMB_FIND_FILE_DIRECTORY_INFO)
4646 *(origOp + ohbytes - 1) = (unsigned char) onbytes;
4647 else if (infoLevel == SMB_FIND_FILE_NAMES_INFO)
4648 *((u_long *)(op + 8)) = onbytes;
4650 *((u_long *)(op + 60)) = onbytes;
4651 strcpy(origOp+ohbytes, dep->name);
4652 if (smb_StoreAnsiFilenames)
4653 CharToOem(origOp+ohbytes, origOp+ohbytes);
4655 /* Short name if requested and needed */
4656 if (infoLevel == SMB_FIND_FILE_BOTH_DIRECTORY_INFO) {
4657 if (NeedShortName) {
4658 strcpy(op + 70, shortName);
4659 if (smb_StoreAnsiFilenames)
4660 CharToOem(op + 70, op + 70);
4661 *(op + 68) = (char)(shortNameEnd - shortName);
4665 /* now, adjust the # of entries copied */
4668 /* NextEntryOffset and FileIndex */
4669 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO) {
4670 int entryOffset = orbytes + align;
4671 *((u_long *)op) = entryOffset;
4672 *((u_long *)(op+4)) = nextEntryCookie;
4675 /* now we emit the attribute. This is tricky, since
4676 * we need to really stat the file to find out what
4677 * type of entry we've got. Right now, we're copying
4678 * out data from a buffer, while holding the scp
4679 * locked, so it isn't really convenient to stat
4680 * something now. We'll put in a place holder
4681 * now, and make a second pass before returning this
4682 * to get the real attributes. So, we just skip the
4683 * data for now, and adjust it later. We allocate a
4684 * patch record to make it easy to find this point
4685 * later. The replay will happen at a time when it is
4686 * safe to unlock the directory.
4688 if (infoLevel != SMB_FIND_FILE_NAMES_INFO) {
4689 curPatchp = malloc(sizeof(*curPatchp));
4690 osi_QAdd((osi_queue_t **) &dirListPatchesp,
4692 curPatchp->dptr = op;
4693 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO)
4694 curPatchp->dptr += 8;
4696 if (smb_hideDotFiles && smb_IsDotFile(dep->name)) {
4697 curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
4700 curPatchp->flags = 0;
4702 curPatchp->fid.cell = scp->fid.cell;
4703 curPatchp->fid.volume = scp->fid.volume;
4704 curPatchp->fid.vnode = ntohl(dep->fid.vnode);
4705 curPatchp->fid.unique = ntohl(dep->fid.unique);
4708 curPatchp->dep = dep;
4711 if (searchFlags & 4)
4712 /* put out resume key */
4713 *((u_long *)origOp) = nextEntryCookie;
4715 /* Adjust byte ptr and count */
4716 origOp += orbytes; /* skip entire record */
4717 bytesInBuffer += orbytes;
4719 /* and pad the record out */
4720 while (--align >= 0) {
4724 } /* if we're including this name */
4725 else if (!starPattern &&
4727 dep->fid.vnode != 0 &&
4728 smb_V3MatchMask(dep->name, maskp, CM_FLAG_CASEFOLD)) {
4729 /* We were looking for exact matches, but here's an inexact one*/
4734 /* and adjust curOffset to be where the new cookie is */
4735 thyper.HighPart = 0;
4736 thyper.LowPart = CM_DIR_CHUNKSIZE * numDirChunks;
4737 curOffset = LargeIntegerAdd(thyper, curOffset);
4738 } /* while copying data for dir listing */
4740 /* If we didn't get a star pattern, we did an exact match during the first pass.
4741 * If there were no exact matches found, we fail over to inexact matches by
4742 * marking the query as a star pattern (matches all case permutations), and
4743 * re-running the query.
4745 if (returnedNames == 0 && !starPattern && foundInexact) {
4746 osi_Log0(afsd_logp,"T2 Search: No exact matches. Re-running for inexact matches");
4751 /* release the mutex */
4752 lock_ReleaseMutex(&scp->mx);
4754 buf_Release(bufferp);
4756 /* apply and free last set of patches; if not doing a star match, this
4757 * will be empty, but better safe (and freeing everything) than sorry.
4759 code2 = smb_ApplyV3DirListPatches(scp, &dirListPatchesp, infoLevel, userp,
4762 /* now put out the final parameters */
4763 if (returnedNames == 0)
4765 if (p->opcode == 1) {
4767 outp->parmsp[0] = (unsigned short) dsp->cookie;
4768 outp->parmsp[1] = returnedNames;
4769 outp->parmsp[2] = eos;
4770 outp->parmsp[3] = 0; /* nothing wrong with EAS */
4771 outp->parmsp[4] = 0;
4772 /* don't need last name to continue
4773 * search, cookie is enough. Normally,
4774 * this is the offset of the file name
4775 * of the last entry returned.
4777 outp->totalParms = 10; /* in bytes */
4781 outp->parmsp[0] = returnedNames;
4782 outp->parmsp[1] = eos;
4783 outp->parmsp[2] = 0; /* EAS error */
4784 outp->parmsp[3] = 0; /* last name, as above */
4785 outp->totalParms = 8; /* in bytes */
4788 /* return # of bytes in the buffer */
4789 outp->totalData = bytesInBuffer;
4791 /* Return error code if unsuccessful on first request */
4792 if (code == 0 && p->opcode == 1 && returnedNames == 0)
4793 code = CM_ERROR_NOSUCHFILE;
4795 osi_Log4(smb_logp, "T2 search dir done, opcode %d, id %d, %d names, code %d",
4796 p->opcode, dsp->cookie, returnedNames, code);
4798 /* if we're supposed to close the search after this request, or if
4799 * we're supposed to close the search if we're done, and we're done,
4800 * or if something went wrong, close the search.
4802 /* ((searchFlags & 1) || ((searchFlags & 2) && eos) */
4803 if ((searchFlags & 1) || (returnedNames == 0) ||
4804 ((searchFlags & 2) && eos) || code != 0)
4805 smb_DeleteDirSearch(dsp);
4807 smb_SendTran2Error(vcp, p, opx, code);
4809 smb_SendTran2Packet(vcp, outp, opx);
4811 smb_FreeTran2Packet(outp);
4812 smb_ReleaseDirSearch(dsp);
4813 cm_ReleaseSCache(scp);
4814 cm_ReleaseUser(userp);
4818 long smb_ReceiveV3FindClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4821 smb_dirSearch_t *dsp;
4823 dirHandle = smb_GetSMBParm(inp, 0);
4825 osi_Log1(smb_logp, "SMB3 find close handle %d", dirHandle);
4827 dsp = smb_FindDirSearch(dirHandle);
4830 return CM_ERROR_BADFD;
4832 /* otherwise, we have an FD to destroy */
4833 smb_DeleteDirSearch(dsp);
4834 smb_ReleaseDirSearch(dsp);
4836 /* and return results */
4837 smb_SetSMBDataLength(outp, 0);
4842 long smb_ReceiveV3FindNotifyClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4844 smb_SetSMBDataLength(outp, 0);
4848 long smb_ReceiveV3OpenX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4855 cm_scache_t *dscp; /* dir we're dealing with */
4856 cm_scache_t *scp; /* file we're creating */
4858 int initialModeBits;
4868 int parmSlot; /* which parm we're dealing with */
4877 extraInfo = (smb_GetSMBParm(inp, 2) & 1); /* return extra info */
4878 openFun = smb_GetSMBParm(inp, 8); /* open function */
4879 excl = ((openFun & 3) == 0);
4880 trunc = ((openFun & 3) == 2); /* truncate it */
4881 openMode = (smb_GetSMBParm(inp, 3) & 0x7);
4882 openAction = 0; /* tracks what we did */
4884 attributes = smb_GetSMBParm(inp, 5);
4885 dosTime = smb_GetSMBParm(inp, 6) | (smb_GetSMBParm(inp, 7) << 16);
4887 /* compute initial mode bits based on read-only flag in attributes */
4888 initialModeBits = 0666;
4889 if (attributes & SMB_ATTR_READONLY)
4890 initialModeBits &= ~0222;
4892 pathp = smb_GetSMBData(inp, NULL);
4893 if (smb_StoreAnsiFilenames)
4894 OemToChar(pathp,pathp);
4896 spacep = inp->spacep;
4897 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
4899 if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
4900 /* special case magic file name for receiving IOCTL requests
4901 * (since IOCTL calls themselves aren't getting through).
4904 osi_Log0(smb_logp, "IOCTL Open");
4907 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
4908 smb_SetupIoctlFid(fidp, spacep);
4910 /* set inp->fid so that later read calls in same msg can find fid */
4911 inp->fid = fidp->fid;
4913 /* copy out remainder of the parms */
4915 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
4917 smb_SetSMBParm(outp, parmSlot, /* attrs */ 0); parmSlot++;
4918 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* mod time */
4919 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
4920 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* len */
4921 smb_SetSMBParm(outp, parmSlot, 0x7fff); parmSlot++;
4922 smb_SetSMBParm(outp, parmSlot, openMode); parmSlot++;
4923 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* file type 0 ==> normal file or dir */
4924 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* IPC junk */
4926 /* and the final "always present" stuff */
4927 smb_SetSMBParm(outp, parmSlot, /* openAction found existing file */ 1); parmSlot++;
4928 /* next write out the "unique" ID */
4929 smb_SetSMBParm(outp, parmSlot, 0x1234); parmSlot++;
4930 smb_SetSMBParm(outp, parmSlot, 0x5678); parmSlot++;
4931 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
4932 smb_SetSMBDataLength(outp, 0);
4934 /* and clean up fid reference */
4935 smb_ReleaseFID(fidp);
4939 #ifdef DEBUG_VERBOSE
4941 char *hexp, *asciip;
4942 asciip = (lastNamep ? lastNamep : pathp );
4943 hexp = osi_HexifyString(asciip);
4944 DEBUG_EVENT2("AFS", "V3Open H[%s] A[%s]", hexp, asciip );
4948 userp = smb_GetUserFromVCP(vcp, inp);
4951 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4953 cm_ReleaseUser(userp);
4954 return CM_ERROR_NOSUCHPATH;
4956 code = cm_NameI(cm_data.rootSCachep, pathp,
4957 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
4958 userp, tidPathp, &req, &scp);
4961 if (code == 0 && scp->fileType == CM_SCACHETYPE_DFSLINK) {
4962 cm_ReleaseSCache(scp);
4963 cm_ReleaseUser(userp);
4964 if ( WANTS_DFS_PATHNAMES(inp) )
4965 return CM_ERROR_PATH_NOT_COVERED;
4967 return CM_ERROR_BADSHARENAME;
4969 #endif /* DFS_SUPPORT */
4972 code = cm_NameI(cm_data.rootSCachep, spacep->data,
4973 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
4974 userp, tidPathp, &req, &dscp);
4976 cm_ReleaseUser(userp);
4981 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
4982 cm_ReleaseSCache(dscp);
4983 cm_ReleaseUser(userp);
4984 if ( WANTS_DFS_PATHNAMES(inp) )
4985 return CM_ERROR_PATH_NOT_COVERED;
4987 return CM_ERROR_BADSHARENAME;
4989 #endif /* DFS_SUPPORT */
4990 /* otherwise, scp points to the parent directory. Do a lookup,
4991 * and truncate the file if we find it, otherwise we create the
4998 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD, userp,
5000 if (code && code != CM_ERROR_NOSUCHFILE) {
5001 cm_ReleaseSCache(dscp);
5002 cm_ReleaseUser(userp);
5007 /* if we get here, if code is 0, the file exists and is represented by
5008 * scp. Otherwise, we have to create it. The dir may be represented
5009 * by dscp, or we may have found the file directly. If code is non-zero,
5013 code = cm_CheckOpen(scp, openMode, trunc, userp, &req);
5015 if (dscp) cm_ReleaseSCache(dscp);
5016 cm_ReleaseSCache(scp);
5017 cm_ReleaseUser(userp);
5022 /* oops, file shouldn't be there */
5024 cm_ReleaseSCache(dscp);
5025 cm_ReleaseSCache(scp);
5026 cm_ReleaseUser(userp);
5027 return CM_ERROR_EXISTS;
5031 setAttr.mask = CM_ATTRMASK_LENGTH;
5032 setAttr.length.LowPart = 0;
5033 setAttr.length.HighPart = 0;
5034 code = cm_SetAttr(scp, &setAttr, userp, &req);
5035 openAction = 3; /* truncated existing file */
5037 else openAction = 1; /* found existing file */
5039 else if (!(openFun & SMB_ATTR_DIRECTORY)) {
5040 /* don't create if not found */
5041 if (dscp) cm_ReleaseSCache(dscp);
5042 cm_ReleaseUser(userp);
5043 return CM_ERROR_NOSUCHFILE;
5046 osi_assert(dscp != NULL);
5047 osi_Log1(smb_logp, "smb_ReceiveV3OpenX creating file %s",
5048 osi_LogSaveString(smb_logp, lastNamep));
5049 openAction = 2; /* created file */
5050 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
5051 smb_UnixTimeFromDosUTime(&setAttr.clientModTime, dosTime);
5052 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
5056 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
5057 smb_NotifyChange(FILE_ACTION_ADDED,
5058 FILE_NOTIFY_CHANGE_FILE_NAME,
5059 dscp, lastNamep, NULL, TRUE);
5060 } else if (!excl && code == CM_ERROR_EXISTS) {
5061 /* not an exclusive create, and someone else tried
5062 * creating it already, then we open it anyway. We
5063 * don't bother retrying after this, since if this next
5064 * fails, that means that the file was deleted after we
5065 * started this call.
5067 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
5071 setAttr.mask = CM_ATTRMASK_LENGTH;
5072 setAttr.length.LowPart = 0;
5073 setAttr.length.HighPart = 0;
5074 code = cm_SetAttr(scp, &setAttr, userp, &req);
5076 } /* lookup succeeded */
5080 /* we don't need this any longer */
5082 cm_ReleaseSCache(dscp);
5085 /* something went wrong creating or truncating the file */
5087 cm_ReleaseSCache(scp);
5088 cm_ReleaseUser(userp);
5092 /* make sure we're about to open a file */
5093 if (scp->fileType != CM_SCACHETYPE_FILE) {
5094 cm_ReleaseSCache(scp);
5095 cm_ReleaseUser(userp);
5096 return CM_ERROR_ISDIR;
5099 /* now all we have to do is open the file itself */
5100 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
5104 lock_ObtainMutex(&fidp->mx);
5105 /* save a pointer to the vnode */
5108 fidp->userp = userp;
5110 /* compute open mode */
5112 fidp->flags |= SMB_FID_OPENREAD;
5113 if (openMode == 1 || openMode == 2)
5114 fidp->flags |= SMB_FID_OPENWRITE;
5116 /* remember if the file was newly created */
5118 fidp->flags |= SMB_FID_CREATED;
5120 lock_ReleaseMutex(&fidp->mx);
5121 smb_ReleaseFID(fidp);
5123 cm_Open(scp, 0, userp);
5125 /* set inp->fid so that later read calls in same msg can find fid */
5126 inp->fid = fidp->fid;
5128 /* copy out remainder of the parms */
5130 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
5131 lock_ObtainMutex(&scp->mx);
5133 smb_SetSMBParm(outp, parmSlot, smb_Attributes(scp)); parmSlot++;
5134 smb_DosUTimeFromUnixTime(&dosTime, scp->clientModTime);
5135 smb_SetSMBParm(outp, parmSlot, dosTime & 0xffff); parmSlot++;
5136 smb_SetSMBParm(outp, parmSlot, (dosTime>>16) & 0xffff); parmSlot++;
5137 smb_SetSMBParm(outp, parmSlot, scp->length.LowPart & 0xffff); parmSlot++;
5138 smb_SetSMBParm(outp, parmSlot, (scp->length.LowPart >> 16) & 0xffff); parmSlot++;
5139 smb_SetSMBParm(outp, parmSlot, openMode); parmSlot++;
5140 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* file type 0 ==> normal file or dir */
5141 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* IPC junk */
5143 /* and the final "always present" stuff */
5144 smb_SetSMBParm(outp, parmSlot, openAction); parmSlot++;
5145 /* next write out the "unique" ID */
5146 smb_SetSMBParm(outp, parmSlot, scp->fid.vnode & 0xffff); parmSlot++;
5147 smb_SetSMBParm(outp, parmSlot, scp->fid.volume & 0xffff); parmSlot++;
5148 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
5149 lock_ReleaseMutex(&scp->mx);
5150 smb_SetSMBDataLength(outp, 0);
5152 osi_Log1(smb_logp, "SMB OpenX opening fid %d", fidp->fid);
5154 cm_ReleaseUser(userp);
5155 /* leave scp held since we put it in fidp->scp */
5159 static void smb_GetLockParams(unsigned char LockType,
5161 unsigned int * ppid,
5162 LARGE_INTEGER * pOffset,
5163 LARGE_INTEGER * pLength)
5165 if (LockType & LOCKING_ANDX_LARGE_FILES) {
5167 *ppid = *((USHORT *) *buf);
5168 pOffset->HighPart = *((LONG *)(*buf + 4));
5169 pOffset->LowPart = *((DWORD *)(*buf + 8));
5170 pLength->HighPart = *((LONG *)(*buf + 12));
5171 pLength->LowPart = *((DWORD *)(*buf + 16));
5175 /* Not Large Files */
5176 *ppid = *((USHORT *) *buf);
5177 pOffset->HighPart = 0;
5178 pOffset->LowPart = *((DWORD *)(*buf + 2));
5179 pLength->HighPart = 0;
5180 pLength->LowPart = *((DWORD *)(*buf + 6));
5185 long smb_ReceiveV3LockingX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5192 unsigned char LockType;
5193 unsigned short NumberOfUnlocks, NumberOfLocks;
5197 LARGE_INTEGER LOffset, LLength;
5198 smb_waitingLockRequest_t *wlRequest = NULL;
5199 cm_file_lock_t *lockp;
5207 fid = smb_GetSMBParm(inp, 2);
5208 fid = smb_ChainFID(fid, inp);
5210 fidp = smb_FindFID(vcp, fid, 0);
5212 return CM_ERROR_BADFD;
5214 lock_ObtainMutex(&fidp->mx);
5215 if (fidp->flags & SMB_FID_IOCTL) {
5216 osi_Log0(smb_logp, "smb_ReceiveV3Locking BadFD");
5217 lock_ReleaseMutex(&fidp->mx);
5218 smb_ReleaseFID(fidp);
5219 return CM_ERROR_BADFD;
5223 lock_ReleaseMutex(&fidp->mx);
5225 /* set inp->fid so that later read calls in same msg can find fid */
5228 userp = smb_GetUserFromVCP(vcp, inp);
5231 lock_ObtainMutex(&scp->mx);
5232 code = cm_SyncOp(scp, NULL, userp, &req, 0,
5233 CM_SCACHESYNC_NEEDCALLBACK
5234 | CM_SCACHESYNC_GETSTATUS
5235 | CM_SCACHESYNC_LOCK);
5237 osi_Log1(smb_logp, "smb_ReceiveV3Locking SyncOp failure code 0x%x", code);
5241 LockType = smb_GetSMBParm(inp, 3) & 0xff;
5242 Timeout = (smb_GetSMBParm(inp, 5) << 16) + smb_GetSMBParm(inp, 4);
5243 NumberOfUnlocks = smb_GetSMBParm(inp, 6);
5244 NumberOfLocks = smb_GetSMBParm(inp, 7);
5246 if ((LockType & LOCKING_ANDX_CANCEL_LOCK) ||
5247 (LockType & LOCKING_ANDX_CHANGE_LOCKTYPE)) {
5249 /* We don't support these requests. Apparently, we can safely
5250 not deal with them too. */
5251 osi_Log1(smb_logp, "smb_ReceiveV3Locking received unsupported request [%s]",
5252 ((LockType & LOCKING_ANDX_CANCEL_LOCK)?
5253 "LOCKING_ANDX_CANCEL_LOCK":
5254 "LOCKING_ANDX_CHANGE_LOCKTYPE"));
5255 /* No need to call osi_LogSaveString since these are string
5258 code = CM_ERROR_BADOP;
5263 op = smb_GetSMBData(inp, NULL);
5265 for (i=0; i<NumberOfUnlocks; i++) {
5266 smb_GetLockParams(LockType, &op, &pid, &LOffset, &LLength);
5268 key = cm_GenerateKey(vcp->vcID, pid, fidp->fid);
5270 code = cm_Unlock(scp, LockType, LOffset, LLength, key, userp, &req);
5278 for (i=0; i<NumberOfLocks; i++) {
5279 smb_GetLockParams(LockType, &op, &pid, &LOffset, &LLength);
5281 key = cm_GenerateKey(vcp->vcID, pid, fidp->fid);
5283 code = cm_Lock(scp, LockType, LOffset, LLength, key, (Timeout != 0),
5284 userp, &req, &lockp);
5286 if (code == CM_ERROR_WOULDBLOCK && Timeout != 0) {
5287 smb_waitingLock_t * wLock;
5289 /* Put on waiting list */
5290 if(wlRequest == NULL) {
5294 LARGE_INTEGER tOffset, tLength;
5296 wlRequest = malloc(sizeof(smb_waitingLockRequest_t));
5298 osi_assert(wlRequest != NULL);
5300 wlRequest->vcp = vcp;
5302 wlRequest->scp = scp;
5304 wlRequest->inp = smb_CopyPacket(inp);
5305 wlRequest->outp = smb_CopyPacket(outp);
5306 wlRequest->lockType = LockType;
5307 wlRequest->timeRemaining = Timeout;
5308 wlRequest->locks = NULL;
5310 /* The waiting lock request needs to have enough
5311 information to undo all the locks in the request.
5312 We do the following to store info about locks that
5313 have already been granted. Sure, we can get most
5314 of the info from the packet, but the packet doesn't
5315 hold the result of cm_Lock call. In practice we
5316 only receive packets with one or two locks, so we
5317 are only wasting a few bytes here and there and
5318 only for a limited period of time until the waiting
5319 lock times out or is freed. */
5321 for(opt = op_locks, j=i; j > 0; j--) {
5322 smb_GetLockParams(LockType, &opt, &pid, &tOffset, &tLength);
5324 tkey = cm_GenerateKey(vcp->vcID, pid, fidp->fid);
5326 wLock = malloc(sizeof(smb_waitingLock_t));
5328 osi_assert(wLock != NULL);
5331 wLock->LOffset = tOffset;
5332 wLock->LLength = tLength;
5333 wLock->lockp = NULL;
5334 wLock->state = SMB_WAITINGLOCKSTATE_DONE;
5335 osi_QAdd((osi_queue_t **) &wlRequest->locks,
5340 wLock = malloc(sizeof(smb_waitingLock_t));
5342 osi_assert(wLock != NULL);
5345 wLock->LOffset = LOffset;
5346 wLock->LLength = LLength;
5347 wLock->lockp = lockp;
5348 wLock->state = SMB_WAITINGLOCKSTATE_WAITING;
5349 osi_QAdd((osi_queue_t **) &wlRequest->locks,
5352 osi_Log1(smb_logp, "smb_ReceiveV3Locking WaitingLock created 0x%p",
5360 osi_Log1(smb_logp, "smb_ReceiveV3Locking cm_Lock failure code 0x%x", code);
5367 /* Since something went wrong with the lock number i, we now
5368 have to go ahead and release any locks acquired before the
5369 failure. All locks before lock number i (of which there
5370 are i of them) have either been successful or are waiting.
5371 Either case requires calling cm_Unlock(). */
5373 /* And purge the waiting lock */
5374 if(wlRequest != NULL) {
5375 smb_waitingLock_t * wl;
5376 smb_waitingLock_t * wlNext;
5379 for(wl = wlRequest->locks; wl; wl = wlNext) {
5381 wlNext = (smb_waitingLock_t *) osi_QNext(&wl->q);
5383 ul_code = cm_Unlock(scp, LockType, wl->LOffset, wl->LLength, wl->key, userp, &req);
5386 osi_Log1(smb_logp, "smb_ReceiveV3Locking cm_Unlock returns code %d", ul_code);
5388 osi_Log0(smb_logp, "smb_ReceiveV3Locking cm_Unlock successful");
5391 osi_QRemove((osi_queue_t **) &wlRequest->locks, &wl->q);
5396 smb_ReleaseVC(wlRequest->vcp);
5397 cm_ReleaseSCache(wlRequest->scp);
5398 smb_FreePacket(wlRequest->inp);
5399 smb_FreePacket(wlRequest->outp);
5408 if (wlRequest != NULL) {
5410 lock_ObtainWrite(&smb_globalLock);
5411 osi_QAdd((osi_queue_t **)&smb_allWaitingLocks,
5413 osi_Wakeup((LONG_PTR)&smb_allWaitingLocks);
5414 lock_ReleaseWrite(&smb_globalLock);
5416 /* don't send reply immediately */
5417 outp->flags |= SMB_PACKETFLAG_NOSEND;
5420 smb_SetSMBDataLength(outp, 0);
5424 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_LOCK);
5427 lock_ReleaseMutex(&scp->mx);
5428 cm_ReleaseSCache(scp);
5429 cm_ReleaseUser(userp);
5430 smb_ReleaseFID(fidp);
5435 long smb_ReceiveV3GetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5441 afs_uint32 searchTime;
5447 fid = smb_GetSMBParm(inp, 0);
5448 fid = smb_ChainFID(fid, inp);
5450 fidp = smb_FindFID(vcp, fid, 0);
5452 return CM_ERROR_BADFD;
5454 lock_ObtainMutex(&fidp->mx);
5455 if (fidp->flags & SMB_FID_IOCTL) {
5456 lock_ReleaseMutex(&fidp->mx);
5457 smb_ReleaseFID(fidp);
5458 return CM_ERROR_BADFD;
5462 lock_ReleaseMutex(&fidp->mx);
5464 userp = smb_GetUserFromVCP(vcp, inp);
5467 /* otherwise, stat the file */
5468 lock_ObtainMutex(&scp->mx);
5469 code = cm_SyncOp(scp, NULL, userp, &req, 0,
5470 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5474 /* decode times. We need a search time, but the response to this
5475 * call provides the date first, not the time, as returned in the
5476 * searchTime variable. So we take the high-order bits first.
5478 smb_SearchTimeFromUnixTime(&searchTime, scp->clientModTime);
5479 smb_SetSMBParm(outp, 0, (searchTime >> 16) & 0xffff); /* ctime */
5480 smb_SetSMBParm(outp, 1, searchTime & 0xffff);
5481 smb_SetSMBParm(outp, 2, (searchTime >> 16) & 0xffff); /* atime */
5482 smb_SetSMBParm(outp, 3, searchTime & 0xffff);
5483 smb_SetSMBParm(outp, 4, (searchTime >> 16) & 0xffff); /* mtime */
5484 smb_SetSMBParm(outp, 5, searchTime & 0xffff);
5486 /* now handle file size and allocation size */
5487 smb_SetSMBParm(outp, 6, scp->length.LowPart & 0xffff); /* file size */
5488 smb_SetSMBParm(outp, 7, (scp->length.LowPart >> 16) & 0xffff);
5489 smb_SetSMBParm(outp, 8, scp->length.LowPart & 0xffff); /* alloc size */
5490 smb_SetSMBParm(outp, 9, (scp->length.LowPart >> 16) & 0xffff);
5492 /* file attribute */
5493 smb_SetSMBParm(outp, 10, smb_Attributes(scp));
5495 /* and finalize stuff */
5496 smb_SetSMBDataLength(outp, 0);
5500 lock_ReleaseMutex(&scp->mx);
5501 cm_ReleaseSCache(scp);
5502 cm_ReleaseUser(userp);
5503 smb_ReleaseFID(fidp);
5507 long smb_ReceiveV3SetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5513 afs_uint32 searchTime;
5521 fid = smb_GetSMBParm(inp, 0);
5522 fid = smb_ChainFID(fid, inp);
5524 fidp = smb_FindFID(vcp, fid, 0);
5526 return CM_ERROR_BADFD;
5528 lock_ObtainMutex(&fidp->mx);
5529 if (fidp->flags & SMB_FID_IOCTL) {
5530 lock_ReleaseMutex(&fidp->mx);
5531 smb_ReleaseFID(fidp);
5532 return CM_ERROR_BADFD;
5536 lock_ReleaseMutex(&fidp->mx);
5538 userp = smb_GetUserFromVCP(vcp, inp);
5541 /* now prepare to call cm_setattr. This message only sets various times,
5542 * and AFS only implements mtime, and we'll set the mtime if that's
5543 * requested. The others we'll ignore.
5545 searchTime = smb_GetSMBParm(inp, 5) | (smb_GetSMBParm(inp, 6) << 16);
5547 if (searchTime != 0) {
5548 smb_UnixTimeFromSearchTime(&unixTime, searchTime);
5550 if ( unixTime != -1 ) {
5551 attrs.mask = CM_ATTRMASK_CLIENTMODTIME;
5552 attrs.clientModTime = unixTime;
5553 code = cm_SetAttr(scp, &attrs, userp, &req);
5555 osi_Log1(smb_logp, "SMB receive V3SetAttributes [fid=%ld]", fid);
5557 osi_Log1(smb_logp, "**smb_UnixTimeFromSearchTime failed searchTime=%ld", searchTime);
5563 cm_ReleaseSCache(scp);
5564 cm_ReleaseUser(userp);
5565 smb_ReleaseFID(fidp);
5569 long smb_ReceiveV3WriteX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5572 long count, written = 0, total_written = 0;
5579 int inDataBlockCount;
5581 fd = smb_GetSMBParm(inp, 2);
5582 count = smb_GetSMBParm(inp, 10);
5584 offset.HighPart = 0;
5585 offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
5587 if (*inp->wctp == 14) {
5588 /* we have a request with 64-bit file offsets */
5589 #ifdef AFS_LARGEFILES
5590 offset.HighPart = smb_GetSMBParm(inp, 12) | (smb_GetSMBParm(inp, 13) << 16);
5592 if ((smb_GetSMBParm(inp, 12) | (smb_GetSMBParm(inp, 13) << 16)) != 0) {
5594 osi_Log0(smb_logp, "smb_ReceiveV3WriteX offset requires largefile support");
5595 /* we shouldn't have received this op if we didn't specify
5596 largefile support */
5597 return CM_ERROR_BADOP;
5602 op = inp->data + smb_GetSMBParm(inp, 11);
5603 inDataBlockCount = count;
5605 osi_Log4(smb_logp, "smb_ReceiveV3WriteX fid %d, off 0x%x:%08x, size 0x%x",
5606 fd, offset.HighPart, offset.LowPart, count);
5608 fd = smb_ChainFID(fd, inp);
5609 fidp = smb_FindFID(vcp, fd, 0);
5611 return CM_ERROR_BADFD;
5613 lock_ObtainMutex(&fidp->mx);
5614 if (fidp->flags & SMB_FID_IOCTL) {
5615 lock_ReleaseMutex(&fidp->mx);
5616 code = smb_IoctlV3Write(fidp, vcp, inp, outp);
5617 smb_ReleaseFID(fidp);
5620 lock_ReleaseMutex(&fidp->mx);
5621 userp = smb_GetUserFromVCP(vcp, inp);
5623 /* special case: 0 bytes transferred means there is no data
5624 transferred. A slight departure from SMB_COM_WRITE where this
5625 means that we are supposed to truncate the file at this
5630 LARGE_INTEGER LOffset;
5631 LARGE_INTEGER LLength;
5633 pid = ((smb_t *) inp)->pid;
5634 key = cm_GenerateKey(vcp->vcID, pid, fd);
5636 LOffset.HighPart = offset.HighPart;
5637 LOffset.LowPart = offset.LowPart;
5638 LLength.HighPart = 0;
5639 LLength.LowPart = count;
5641 lock_ObtainMutex(&fidp->scp->mx);
5642 code = cm_LockCheckWrite(fidp->scp, LOffset, LLength, key);
5643 lock_ReleaseMutex(&fidp->scp->mx);
5650 * Work around bug in NT client
5652 * When copying a file, the NT client should first copy the data,
5653 * then copy the last write time. But sometimes the NT client does
5654 * these in the wrong order, so the data copies would inadvertently
5655 * cause the last write time to be overwritten. We try to detect this,
5656 * and don't set client mod time if we think that would go against the
5659 lock_ObtainMutex(&fidp->mx);
5660 if ((fidp->flags & SMB_FID_MTIMESETDONE) != SMB_FID_MTIMESETDONE) {
5661 fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
5662 fidp->scp->clientModTime = time(NULL);
5664 lock_ReleaseMutex(&fidp->mx);
5667 while ( code == 0 && count > 0 ) {
5669 code = smb_WriteData(fidp, &offset, count, op, userp, &written);
5671 code = smb_WriteData(fidp, &offset, count, op, userp, &written, FALSE);
5673 if (code == 0 && written == 0)
5674 code = CM_ERROR_PARTIALWRITE;
5676 offset = LargeIntegerAdd(offset,
5677 ConvertLongToLargeInteger(written));
5679 total_written += written;
5685 /* slots 0 and 1 are reserved for request chaining and will be
5686 filled in when we return. */
5687 smb_SetSMBParm(outp, 2, total_written);
5688 smb_SetSMBParm(outp, 3, 0); /* reserved */
5689 smb_SetSMBParm(outp, 4, 0); /* reserved */
5690 smb_SetSMBParm(outp, 5, 0); /* reserved */
5691 smb_SetSMBDataLength(outp, 0);
5694 smb_ReleaseFID(fidp);
5695 cm_ReleaseUser(userp);
5700 long smb_ReceiveV3ReadX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5704 long finalCount = 0;
5713 fd = smb_GetSMBParm(inp, 2);
5714 count = smb_GetSMBParm(inp, 5);
5715 offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
5717 if (*inp->wctp == 12) {
5718 /* a request with 64-bit offsets */
5719 #ifdef AFS_LARGEFILES
5720 offset.HighPart = smb_GetSMBParm(inp, 10) | (smb_GetSMBParm(inp, 11) << 16);
5722 if (LargeIntegerLessThanZero(offset)) {
5723 osi_Log2(smb_logp, "smb_ReceiveV3Read offset too large (0x%x:%08x)",
5724 offset.HighPart, offset.LowPart);
5725 return CM_ERROR_BADSMB;
5728 if ((smb_GetSMBParm(inp, 10) | (smb_GetSMBParm(inp, 11) << 16)) != 0) {
5729 osi_Log0(smb_logp, "smb_ReceiveV3Read offset is 64-bit. Dropping");
5730 return CM_ERROR_BADSMB;
5732 offset.HighPart = 0;
5736 offset.HighPart = 0;
5739 osi_Log4(smb_logp, "smb_ReceiveV3Read fd %d, off 0x%x:%08x, size 0x%x",
5740 fd, offset.HighPart, offset.LowPart, count);
5742 fd = smb_ChainFID(fd, inp);
5743 fidp = smb_FindFID(vcp, fd, 0);
5745 return CM_ERROR_BADFD;
5748 pid = ((smb_t *) inp)->pid;
5749 key = cm_GenerateKey(vcp->vcID, pid, fd);
5751 LARGE_INTEGER LOffset, LLength;
5753 LOffset.HighPart = offset.HighPart;
5754 LOffset.LowPart = offset.LowPart;
5755 LLength.HighPart = 0;
5756 LLength.LowPart = count;
5758 lock_ObtainMutex(&fidp->scp->mx);
5759 code = cm_LockCheckRead(fidp->scp, LOffset, LLength, key);
5760 lock_ReleaseMutex(&fidp->scp->mx);
5764 smb_ReleaseFID(fidp);
5768 /* set inp->fid so that later read calls in same msg can find fid */
5771 lock_ObtainMutex(&fidp->mx);
5772 if (fidp->flags & SMB_FID_IOCTL) {
5773 lock_ReleaseMutex(&fidp->mx);
5774 code = smb_IoctlV3Read(fidp, vcp, inp, outp);
5775 smb_ReleaseFID(fidp);
5778 lock_ReleaseMutex(&fidp->mx);
5780 userp = smb_GetUserFromVCP(vcp, inp);
5782 /* 0 and 1 are reserved for request chaining, were setup by our caller,
5783 * and will be further filled in after we return.
5785 smb_SetSMBParm(outp, 2, 0); /* remaining bytes, for pipes */
5786 smb_SetSMBParm(outp, 3, 0); /* resvd */
5787 smb_SetSMBParm(outp, 4, 0); /* resvd */
5788 smb_SetSMBParm(outp, 5, count); /* # of bytes we're going to read */
5789 /* fill in #6 when we have all the parameters' space reserved */
5790 smb_SetSMBParm(outp, 7, 0); /* resv'd */
5791 smb_SetSMBParm(outp, 8, 0); /* resv'd */
5792 smb_SetSMBParm(outp, 9, 0); /* resv'd */
5793 smb_SetSMBParm(outp, 10, 0); /* resv'd */
5794 smb_SetSMBParm(outp, 11, 0); /* reserved */
5796 /* get op ptr after putting in the parms, since otherwise we don't
5797 * know where the data really is.
5799 op = smb_GetSMBData(outp, NULL);
5801 /* now fill in offset from start of SMB header to first data byte (to op) */
5802 smb_SetSMBParm(outp, 6, ((int) (op - outp->data)));
5804 /* set the packet data length the count of the # of bytes */
5805 smb_SetSMBDataLength(outp, count);
5808 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount);
5810 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount, FALSE);
5813 /* fix some things up */
5814 smb_SetSMBParm(outp, 5, finalCount);
5815 smb_SetSMBDataLength(outp, finalCount);
5817 smb_ReleaseFID(fidp);
5819 cm_ReleaseUser(userp);
5824 * Values for createDisp, copied from NTDDK.H
5826 #define FILE_SUPERSEDE 0 // (???)
5827 #define FILE_OPEN 1 // (open)
5828 #define FILE_CREATE 2 // (exclusive)
5829 #define FILE_OPEN_IF 3 // (non-exclusive)
5830 #define FILE_OVERWRITE 4 // (open & truncate, but do not create)
5831 #define FILE_OVERWRITE_IF 5 // (open & truncate, or create)
5834 #define REQUEST_OPLOCK 2
5835 #define REQUEST_BATCH_OPLOCK 4
5836 #define OPEN_DIRECTORY 8
5837 #define EXTENDED_RESPONSE_REQUIRED 0x10
5839 /* CreateOptions field. */
5840 #define FILE_DIRECTORY_FILE 0x0001
5841 #define FILE_WRITE_THROUGH 0x0002
5842 #define FILE_SEQUENTIAL_ONLY 0x0004
5843 #define FILE_NON_DIRECTORY_FILE 0x0040
5844 #define FILE_NO_EA_KNOWLEDGE 0x0200
5845 #define FILE_EIGHT_DOT_THREE_ONLY 0x0400
5846 #define FILE_RANDOM_ACCESS 0x0800
5847 #define FILE_DELETE_ON_CLOSE 0x1000
5848 #define FILE_OPEN_BY_FILE_ID 0x2000
5850 long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5852 char *pathp, *realPathp;
5856 cm_scache_t *dscp; /* parent dir */
5857 cm_scache_t *scp; /* file to create or open */
5858 cm_scache_t *targetScp; /* if scp is a symlink */
5862 unsigned short nameLength;
5864 unsigned int requestOpLock;
5865 unsigned int requestBatchOpLock;
5866 unsigned int mustBeDir;
5867 unsigned int extendedRespRequired;
5868 unsigned int treeCreate;
5870 unsigned int desiredAccess;
5871 unsigned int extAttributes;
5872 unsigned int createDisp;
5873 unsigned int createOptions;
5874 unsigned int shareAccess;
5875 int initialModeBits;
5876 unsigned short baseFid;
5877 smb_fid_t *baseFidp;
5879 cm_scache_t *baseDirp;
5880 unsigned short openAction;
5892 /* This code is very long and has a lot of if-then-else clauses
5893 * scp and dscp get reused frequently and we need to ensure that
5894 * we don't lose a reference. Start by ensuring that they are NULL.
5901 nameLength = smb_GetSMBOffsetParm(inp, 2, 1);
5902 flags = smb_GetSMBOffsetParm(inp, 3, 1)
5903 | (smb_GetSMBOffsetParm(inp, 4, 1) << 16);
5904 requestOpLock = flags & REQUEST_OPLOCK;
5905 requestBatchOpLock = flags & REQUEST_BATCH_OPLOCK;
5906 mustBeDir = flags & OPEN_DIRECTORY;
5907 extendedRespRequired = flags & EXTENDED_RESPONSE_REQUIRED;
5910 * Why all of a sudden 32-bit FID?
5911 * We will reject all bits higher than 16.
5913 if (smb_GetSMBOffsetParm(inp, 6, 1) != 0)
5914 return CM_ERROR_INVAL;
5915 baseFid = smb_GetSMBOffsetParm(inp, 5, 1);
5916 desiredAccess = smb_GetSMBOffsetParm(inp, 7, 1)
5917 | (smb_GetSMBOffsetParm(inp, 8, 1) << 16);
5918 extAttributes = smb_GetSMBOffsetParm(inp, 13, 1)
5919 | (smb_GetSMBOffsetParm(inp, 14, 1) << 16);
5920 shareAccess = smb_GetSMBOffsetParm(inp, 15, 1)
5921 | (smb_GetSMBOffsetParm(inp, 16, 1) << 16);
5922 createDisp = smb_GetSMBOffsetParm(inp, 17, 1)
5923 | (smb_GetSMBOffsetParm(inp, 18, 1) << 16);
5924 createOptions = smb_GetSMBOffsetParm(inp, 19, 1)
5925 | (smb_GetSMBOffsetParm(inp, 20, 1) << 16);
5927 /* mustBeDir is never set; createOptions directory bit seems to be
5930 if (createOptions & FILE_DIRECTORY_FILE)
5932 else if (createOptions & FILE_NON_DIRECTORY_FILE)
5938 * compute initial mode bits based on read-only flag in
5939 * extended attributes
5941 initialModeBits = 0666;
5942 if (extAttributes & SMB_ATTR_READONLY)
5943 initialModeBits &= ~0222;
5945 pathp = smb_GetSMBData(inp, NULL);
5946 /* Sometimes path is not null-terminated, so we make a copy. */
5947 realPathp = malloc(nameLength+1);
5948 memcpy(realPathp, pathp, nameLength);
5949 realPathp[nameLength] = 0;
5950 if (smb_StoreAnsiFilenames)
5951 OemToChar(realPathp,realPathp);
5953 spacep = inp->spacep;
5954 smb_StripLastComponent(spacep->data, &lastNamep, realPathp);
5956 osi_Log1(smb_logp,"NTCreateX for [%s]",osi_LogSaveString(smb_logp,realPathp));
5957 osi_Log4(smb_logp,"... da=[%x] ea=[%x] cd=[%x] co=[%x]", desiredAccess, extAttributes, createDisp, createOptions);
5958 osi_Log3(smb_logp,"... share=[%x] flags=[%x] lastNamep=[%s]", shareAccess, flags, osi_LogSaveString(smb_logp,(lastNamep?lastNamep:"null")));
5960 if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
5961 /* special case magic file name for receiving IOCTL requests
5962 * (since IOCTL calls themselves aren't getting through).
5964 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
5965 smb_SetupIoctlFid(fidp, spacep);
5966 osi_Log1(smb_logp,"NTCreateX Setting up IOCTL on fid[%d]",fidp->fid);
5968 /* set inp->fid so that later read calls in same msg can find fid */
5969 inp->fid = fidp->fid;
5973 smb_SetSMBParmByte(outp, parmSlot, 0); /* oplock */
5974 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
5975 smb_SetSMBParmLong(outp, parmSlot, 1); parmSlot += 2; /* Action */
5977 memset(&ft, 0, sizeof(ft));
5978 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
5979 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
5980 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
5981 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
5982 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2; /* attr */
5983 sz.HighPart = 0x7fff; sz.LowPart = 0;
5984 smb_SetSMBParmDouble(outp, parmSlot, (char *)&sz); parmSlot += 4; /* alen */
5985 smb_SetSMBParmDouble(outp, parmSlot, (char *)&sz); parmSlot += 4; /* len */
5986 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* filetype */
5987 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* dev state */
5988 smb_SetSMBParmByte(outp, parmSlot, 0); /* is a dir? */
5989 smb_SetSMBDataLength(outp, 0);
5991 /* clean up fid reference */
5992 smb_ReleaseFID(fidp);
5997 #ifdef DEBUG_VERBOSE
5999 char *hexp, *asciip;
6000 asciip = (lastNamep? lastNamep : realPathp);
6001 hexp = osi_HexifyString( asciip );
6002 DEBUG_EVENT2("AFS", "NTCreateX H[%s] A[%s]", hexp, asciip);
6007 userp = smb_GetUserFromVCP(vcp, inp);
6009 osi_Log1(smb_logp, "NTCreateX Invalid user [%d]", ((smb_t *) inp)->uid);
6011 return CM_ERROR_INVAL;
6016 baseDirp = cm_data.rootSCachep;
6017 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
6018 if (code == CM_ERROR_TIDIPC) {
6019 /* Attempt to use a TID allocated for IPC. The client
6020 * is probably looking for DCE RPC end points which we
6021 * don't support OR it could be looking to make a DFS
6024 osi_Log0(smb_logp, "NTCreateX received IPC TID");
6027 cm_ReleaseUser(userp);
6028 return CM_ERROR_NOSUCHFILE;
6029 #endif /* DFS_SUPPORT */
6032 baseFidp = smb_FindFID(vcp, baseFid, 0);
6034 osi_Log1(smb_logp, "NTCreateX Invalid base fid [%d]", baseFid);
6036 cm_ReleaseUser(userp);
6037 return CM_ERROR_INVAL;
6039 baseDirp = baseFidp->scp;
6043 osi_Log1(smb_logp, "NTCreateX tidPathp=[%s]", (tidPathp==NULL)?"null": osi_LogSaveString(smb_logp,tidPathp));
6045 /* compute open mode */
6047 if (desiredAccess & DELETE)
6048 fidflags |= SMB_FID_OPENDELETE;
6049 if (desiredAccess & AFS_ACCESS_READ)
6050 fidflags |= SMB_FID_OPENREAD;
6051 if (desiredAccess & AFS_ACCESS_WRITE)
6052 fidflags |= SMB_FID_OPENWRITE;
6053 if (createOptions & FILE_DELETE_ON_CLOSE)
6054 fidflags |= SMB_FID_DELONCLOSE;
6056 /* and the share mode */
6057 if (shareAccess & FILE_SHARE_READ)
6058 fidflags |= SMB_FID_SHARE_READ;
6059 if (shareAccess & FILE_SHARE_WRITE)
6060 fidflags |= SMB_FID_SHARE_WRITE;
6062 osi_Log1(smb_logp, "NTCreateX fidflags 0x%x", fidflags);
6065 /* For an exclusive create, we want to do a case sensitive match for the last component. */
6066 if ( createDisp == FILE_CREATE ||
6067 createDisp == FILE_OVERWRITE ||
6068 createDisp == FILE_OVERWRITE_IF) {
6069 code = cm_NameI(baseDirp, spacep->data, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
6070 userp, tidPathp, &req, &dscp);
6073 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
6074 cm_ReleaseSCache(dscp);
6075 cm_ReleaseUser(userp);
6078 smb_ReleaseFID(baseFidp);
6079 if ( WANTS_DFS_PATHNAMES(inp) )
6080 return CM_ERROR_PATH_NOT_COVERED;
6082 return CM_ERROR_BADSHARENAME;
6084 #endif /* DFS_SUPPORT */
6085 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp, CM_FLAG_FOLLOW,
6087 if (code == CM_ERROR_NOSUCHFILE) {
6088 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp,
6089 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, &req, &scp);
6090 if (code == 0 && realDirFlag == 1) {
6091 cm_ReleaseSCache(scp);
6092 cm_ReleaseSCache(dscp);
6093 cm_ReleaseUser(userp);
6096 smb_ReleaseFID(baseFidp);
6097 return CM_ERROR_EXISTS;
6101 /* we have both scp and dscp */
6103 code = cm_NameI(baseDirp, realPathp, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
6104 userp, tidPathp, &req, &scp);
6106 if (code == 0 && scp->fileType == CM_SCACHETYPE_DFSLINK) {
6107 cm_ReleaseSCache(scp);
6108 cm_ReleaseUser(userp);
6111 smb_ReleaseFID(baseFidp);
6112 if ( WANTS_DFS_PATHNAMES(inp) )
6113 return CM_ERROR_PATH_NOT_COVERED;
6115 return CM_ERROR_BADSHARENAME;
6117 #endif /* DFS_SUPPORT */
6118 /* we might have scp but not dscp */
6124 if (!foundscp || (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE))) {
6125 /* look up parent directory */
6126 /* If we are trying to create a path (i.e. multiple nested directories), then we don't *need*
6127 * the immediate parent. We have to work our way up realPathp until we hit something that we
6131 /* we might or might not have scp */
6137 code = cm_NameI(baseDirp, spacep->data,
6138 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
6139 userp, tidPathp, &req, &dscp);
6142 if (code == 0 && dscp->fileType == CM_SCACHETYPE_DFSLINK) {
6144 cm_ReleaseSCache(scp);
6145 cm_ReleaseSCache(dscp);
6146 cm_ReleaseUser(userp);
6149 smb_ReleaseFID(baseFidp);
6150 if ( WANTS_DFS_PATHNAMES(inp) )
6151 return CM_ERROR_PATH_NOT_COVERED;
6153 return CM_ERROR_BADSHARENAME;
6155 #endif /* DFS_SUPPORT */
6158 (tp = strrchr(spacep->data,'\\')) &&
6159 (createDisp == FILE_CREATE) &&
6160 (realDirFlag == 1)) {
6163 treeStartp = realPathp + (tp - spacep->data);
6165 if (*tp && !smb_IsLegalFilename(tp)) {
6167 smb_ReleaseFID(baseFidp);
6168 cm_ReleaseUser(userp);
6171 cm_ReleaseSCache(scp);
6172 return CM_ERROR_BADNTFILENAME;
6176 } while (dscp == NULL && code == 0);
6180 /* we might have scp and we might have dscp */
6183 smb_ReleaseFID(baseFidp);
6186 osi_Log0(smb_logp,"NTCreateX parent not found");
6188 cm_ReleaseSCache(scp);
6190 cm_ReleaseSCache(dscp);
6191 cm_ReleaseUser(userp);
6196 if (treeCreate && dscp->fileType == CM_SCACHETYPE_FILE) {
6197 /* A file exists where we want a directory. */
6199 cm_ReleaseSCache(scp);
6200 cm_ReleaseSCache(dscp);
6201 cm_ReleaseUser(userp);
6203 return CM_ERROR_EXISTS;
6207 lastNamep = realPathp;
6211 if (!smb_IsLegalFilename(lastNamep)) {
6213 cm_ReleaseSCache(scp);
6215 cm_ReleaseSCache(dscp);
6216 cm_ReleaseUser(userp);
6218 return CM_ERROR_BADNTFILENAME;
6221 if (!foundscp && !treeCreate) {
6222 if ( createDisp == FILE_CREATE ||
6223 createDisp == FILE_OVERWRITE ||
6224 createDisp == FILE_OVERWRITE_IF)
6226 code = cm_Lookup(dscp, lastNamep,
6227 CM_FLAG_FOLLOW, userp, &req, &scp);
6229 code = cm_Lookup(dscp, lastNamep,
6230 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
6233 if (code && code != CM_ERROR_NOSUCHFILE) {
6235 cm_ReleaseSCache(dscp);
6236 cm_ReleaseUser(userp);
6241 /* we have scp and dscp */
6243 /* we have scp but not dscp */
6245 smb_ReleaseFID(baseFidp);
6248 /* if we get here, if code is 0, the file exists and is represented by
6249 * scp. Otherwise, we have to create it. The dir may be represented
6250 * by dscp, or we may have found the file directly. If code is non-zero,
6253 if (code == 0 && !treeCreate) {
6254 code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp, &req);
6257 cm_ReleaseSCache(dscp);
6259 cm_ReleaseSCache(scp);
6260 cm_ReleaseUser(userp);
6265 if (createDisp == FILE_CREATE) {
6266 /* oops, file shouldn't be there */
6268 cm_ReleaseSCache(dscp);
6270 cm_ReleaseSCache(scp);
6271 cm_ReleaseUser(userp);
6273 return CM_ERROR_EXISTS;
6276 if ( createDisp == FILE_OVERWRITE ||
6277 createDisp == FILE_OVERWRITE_IF) {
6279 setAttr.mask = CM_ATTRMASK_LENGTH;
6280 setAttr.length.LowPart = 0;
6281 setAttr.length.HighPart = 0;
6282 /* now watch for a symlink */
6284 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
6286 osi_assert(dscp != NULL);
6287 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
6289 /* we have a more accurate file to use (the
6290 * target of the symbolic link). Otherwise,
6291 * we'll just use the symlink anyway.
6293 osi_Log2(smb_logp, "symlink vp %x to vp %x",
6295 cm_ReleaseSCache(scp);
6299 code = cm_SetAttr(scp, &setAttr, userp, &req);
6300 openAction = 3; /* truncated existing file */
6303 openAction = 1; /* found existing file */
6305 } else if (createDisp == FILE_OPEN || createDisp == FILE_OVERWRITE) {
6306 /* don't create if not found */
6308 cm_ReleaseSCache(dscp);
6310 cm_ReleaseSCache(scp);
6311 cm_ReleaseUser(userp);
6313 return CM_ERROR_NOSUCHFILE;
6314 } else if (realDirFlag == 0 || realDirFlag == -1) {
6315 osi_assert(dscp != NULL);
6316 osi_Log1(smb_logp, "smb_ReceiveNTCreateX creating file %s",
6317 osi_LogSaveString(smb_logp, lastNamep));
6318 openAction = 2; /* created file */
6319 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
6320 setAttr.clientModTime = time(NULL);
6321 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp, &req);
6324 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
6325 smb_NotifyChange(FILE_ACTION_ADDED,
6326 FILE_NOTIFY_CHANGE_FILE_NAME,
6327 dscp, lastNamep, NULL, TRUE);
6328 } else if (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE) {
6329 /* Not an exclusive create, and someone else tried
6330 * creating it already, then we open it anyway. We
6331 * don't bother retrying after this, since if this next
6332 * fails, that means that the file was deleted after we
6333 * started this call.
6335 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
6338 if (createDisp == FILE_OVERWRITE_IF) {
6339 setAttr.mask = CM_ATTRMASK_LENGTH;
6340 setAttr.length.LowPart = 0;
6341 setAttr.length.HighPart = 0;
6343 /* now watch for a symlink */
6345 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
6347 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
6349 /* we have a more accurate file to use (the
6350 * target of the symbolic link). Otherwise,
6351 * we'll just use the symlink anyway.
6353 osi_Log2(smb_logp, "symlink vp %x to vp %x",
6355 cm_ReleaseSCache(scp);
6359 code = cm_SetAttr(scp, &setAttr, userp, &req);
6361 } /* lookup succeeded */
6365 char *cp; /* This component */
6366 int clen = 0; /* length of component */
6367 cm_scache_t *tscp1, *tscp2;
6370 /* create directory */
6372 treeStartp = lastNamep;
6373 osi_assert(dscp != NULL);
6374 osi_Log1(smb_logp, "smb_ReceiveNTCreateX creating directory [%s]",
6375 osi_LogSaveString(smb_logp, treeStartp));
6376 openAction = 2; /* created directory */
6378 /* if the request is to create the root directory
6379 * it will appear as a directory name of the nul-string
6380 * and a code of CM_ERROR_NOSUCHFILE
6382 if ( !*treeStartp && code == CM_ERROR_NOSUCHFILE)
6383 code = CM_ERROR_EXISTS;
6385 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
6386 setAttr.clientModTime = time(NULL);
6391 cm_HoldSCache(tscp1);
6395 tp = strchr(pp, '\\');
6398 clen = (int)strlen(cp);
6399 isLast = 1; /* indicate last component. the supplied path never ends in a slash */
6401 clen = (int)(tp - pp);
6402 strncpy(cp,pp,clen);
6409 continue; /* the supplied path can't have consecutive slashes either , but */
6411 /* cp is the next component to be created. */
6412 code = cm_MakeDir(tscp1, cp, 0, &setAttr, userp, &req);
6413 if (code == 0 && (tscp1->flags & CM_SCACHEFLAG_ANYWATCH))
6414 smb_NotifyChange(FILE_ACTION_ADDED,
6415 FILE_NOTIFY_CHANGE_DIR_NAME,
6416 tscp1, cp, NULL, TRUE);
6418 (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE)) {
6419 /* Not an exclusive create, and someone else tried
6420 * creating it already, then we open it anyway. We
6421 * don't bother retrying after this, since if this next
6422 * fails, that means that the file was deleted after we
6423 * started this call.
6425 code = cm_Lookup(tscp1, cp, CM_FLAG_CASEFOLD,
6426 userp, &req, &tscp2);
6431 if (!isLast) { /* for anything other than dscp, release it unless it's the last one */
6432 cm_ReleaseSCache(tscp1);
6433 tscp1 = tscp2; /* Newly created directory will be next parent */
6434 /* the hold is transfered to tscp1 from tscp2 */
6439 cm_ReleaseSCache(dscp);
6442 cm_ReleaseSCache(scp);
6445 * if we get here and code == 0, then scp is the last directory created, and dscp is the
6451 /* something went wrong creating or truncating the file */
6453 cm_ReleaseSCache(scp);
6455 cm_ReleaseSCache(dscp);
6456 cm_ReleaseUser(userp);
6461 /* make sure we have file vs. dir right (only applies for single component case) */
6462 if (realDirFlag == 0 && scp->fileType != CM_SCACHETYPE_FILE) {
6463 /* now watch for a symlink */
6465 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
6466 cm_scache_t * targetScp = 0;
6467 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
6469 /* we have a more accurate file to use (the
6470 * target of the symbolic link). Otherwise,
6471 * we'll just use the symlink anyway.
6473 osi_Log2(smb_logp, "symlink vp %x to vp %x", scp, targetScp);
6474 cm_ReleaseSCache(scp);
6479 if (scp->fileType != CM_SCACHETYPE_FILE) {
6481 cm_ReleaseSCache(dscp);
6482 cm_ReleaseSCache(scp);
6483 cm_ReleaseUser(userp);
6485 return CM_ERROR_ISDIR;
6489 /* (only applies to single component case) */
6490 if (realDirFlag == 1 && scp->fileType == CM_SCACHETYPE_FILE) {
6491 cm_ReleaseSCache(scp);
6493 cm_ReleaseSCache(dscp);
6494 cm_ReleaseUser(userp);
6496 return CM_ERROR_NOTDIR;
6499 /* open the file itself */
6500 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
6503 /* save a reference to the user */
6505 fidp->userp = userp;
6507 /* If we are restricting sharing, we should do so with a suitable
6509 if (scp->fileType == CM_SCACHETYPE_FILE &&
6510 !(fidflags & SMB_FID_SHARE_WRITE)) {
6512 LARGE_INTEGER LOffset, LLength;
6515 LOffset.HighPart = SMB_FID_QLOCK_HIGH;
6516 LOffset.LowPart = SMB_FID_QLOCK_LOW;
6517 LLength.HighPart = 0;
6518 LLength.LowPart = SMB_FID_QLOCK_LENGTH;
6520 if (fidflags & SMB_FID_SHARE_READ) {
6521 sLockType = LOCKING_ANDX_SHARED_LOCK;
6526 key = cm_GenerateKey(vcp->vcID, SMB_FID_QLOCK_PID, fidp->fid);
6528 lock_ObtainMutex(&scp->mx);
6529 code = cm_Lock(scp, sLockType, LOffset, LLength, key, 0, userp, &req, NULL);
6530 lock_ReleaseMutex(&scp->mx);
6533 /* shouldn't this be smb_CloseFID() fidp->flags = SMB_FID_DELETE; */
6534 smb_CloseFID(vcp, fidp, NULL, 0);
6535 smb_ReleaseFID(fidp);
6537 cm_ReleaseSCache(scp);
6539 cm_ReleaseSCache(dscp);
6540 cm_ReleaseUser(userp);
6547 lock_ObtainMutex(&fidp->mx);
6548 /* save a pointer to the vnode */
6549 fidp->scp = scp; /* Hold transfered to fidp->scp and no longer needed */
6551 fidp->flags = fidflags;
6553 /* remember if the file was newly created */
6555 fidp->flags |= SMB_FID_CREATED;
6557 /* save parent dir and pathname for delete or change notification */
6558 if (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE)) {
6559 fidp->flags |= SMB_FID_NTOPEN;
6560 fidp->NTopen_dscp = dscp;
6561 cm_HoldSCache(dscp);
6562 fidp->NTopen_pathp = strdup(lastNamep);
6564 fidp->NTopen_wholepathp = realPathp;
6565 lock_ReleaseMutex(&fidp->mx);
6567 /* we don't need this any longer */
6569 cm_ReleaseSCache(dscp);
6573 cm_Open(scp, 0, userp);
6575 /* set inp->fid so that later read calls in same msg can find fid */
6576 inp->fid = fidp->fid;
6580 lock_ObtainMutex(&scp->mx);
6581 smb_SetSMBParmByte(outp, parmSlot, 0); /* oplock */
6582 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
6583 smb_SetSMBParmLong(outp, parmSlot, openAction); parmSlot += 2;
6584 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
6585 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
6586 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
6587 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
6588 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
6589 smb_SetSMBParmLong(outp, parmSlot, smb_ExtAttributes(scp));
6591 smb_SetSMBParmDouble(outp, parmSlot, (char *)&scp->length); parmSlot += 4;
6592 smb_SetSMBParmDouble(outp, parmSlot, (char *)&scp->length); parmSlot += 4;
6593 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* filetype */
6594 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* dev state */
6595 smb_SetSMBParmByte(outp, parmSlot,
6596 (scp->fileType == CM_SCACHETYPE_DIRECTORY ||
6597 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
6598 scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0); /* is a dir? */
6599 lock_ReleaseMutex(&scp->mx);
6600 smb_SetSMBDataLength(outp, 0);
6602 osi_Log2(smb_logp, "SMB NT CreateX opening fid %d path %s", fidp->fid,
6603 osi_LogSaveString(smb_logp, realPathp));
6605 smb_ReleaseFID(fidp);
6607 cm_ReleaseUser(userp);
6609 /* Can't free realPathp if we get here since
6610 fidp->NTopen_wholepathp is pointing there */
6612 /* leave scp held since we put it in fidp->scp */
6617 * A lot of stuff copied verbatim from NT Create&X to NT Tran Create.
6618 * Instead, ultimately, would like to use a subroutine for common code.
6620 long smb_ReceiveNTTranCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6622 char *pathp, *realPathp;
6626 cm_scache_t *dscp; /* parent dir */
6627 cm_scache_t *scp; /* file to create or open */
6628 cm_scache_t *targetScp; /* if scp is a symlink */
6631 unsigned long nameLength;
6633 unsigned int requestOpLock;
6634 unsigned int requestBatchOpLock;
6635 unsigned int mustBeDir;
6636 unsigned int extendedRespRequired;
6638 unsigned int desiredAccess;
6639 #ifdef DEBUG_VERBOSE
6640 unsigned int allocSize;
6642 unsigned int shareAccess;
6643 unsigned int extAttributes;
6644 unsigned int createDisp;
6645 #ifdef DEBUG_VERBOSE
6648 unsigned int createOptions;
6649 int initialModeBits;
6650 unsigned short baseFid;
6651 smb_fid_t *baseFidp;
6653 cm_scache_t *baseDirp;
6654 unsigned short openAction;
6660 int parmOffset, dataOffset;
6672 parmOffset = smb_GetSMBOffsetParm(inp, 11, 1)
6673 | (smb_GetSMBOffsetParm(inp, 12, 1) << 16);
6674 parmp = inp->data + parmOffset;
6675 lparmp = (ULONG *) parmp;
6678 requestOpLock = flags & REQUEST_OPLOCK;
6679 requestBatchOpLock = flags & REQUEST_BATCH_OPLOCK;
6680 mustBeDir = flags & OPEN_DIRECTORY;
6681 extendedRespRequired = flags & EXTENDED_RESPONSE_REQUIRED;
6684 * Why all of a sudden 32-bit FID?
6685 * We will reject all bits higher than 16.
6687 if (lparmp[1] & 0xFFFF0000)
6688 return CM_ERROR_INVAL;
6689 baseFid = (unsigned short)lparmp[1];
6690 desiredAccess = lparmp[2];
6691 #ifdef DEBUG_VERBOSE
6692 allocSize = lparmp[3];
6693 #endif /* DEBUG_VERSOSE */
6694 extAttributes = lparmp[5];
6695 shareAccess = lparmp[6];
6696 createDisp = lparmp[7];
6697 createOptions = lparmp[8];
6698 #ifdef DEBUG_VERBOSE
6701 nameLength = lparmp[11];
6703 #ifdef DEBUG_VERBOSE
6704 osi_Log4(smb_logp,"NTTranCreate with da[%x],ea[%x],sa[%x],cd[%x]",desiredAccess,extAttributes,shareAccess,createDisp);
6705 osi_Log3(smb_logp,"... co[%x],sdl[%x],as[%x]",createOptions,sdLen,allocSize);
6706 osi_Log1(smb_logp,"... flags[%x]",flags);
6709 /* mustBeDir is never set; createOptions directory bit seems to be
6712 if (createOptions & FILE_DIRECTORY_FILE)
6714 else if (createOptions & FILE_NON_DIRECTORY_FILE)
6720 * compute initial mode bits based on read-only flag in
6721 * extended attributes
6723 initialModeBits = 0666;
6724 if (extAttributes & SMB_ATTR_READONLY)
6725 initialModeBits &= ~0222;
6727 pathp = parmp + (13 * sizeof(ULONG)) + sizeof(UCHAR);
6728 /* Sometimes path is not null-terminated, so we make a copy. */
6729 realPathp = malloc(nameLength+1);
6730 memcpy(realPathp, pathp, nameLength);
6731 realPathp[nameLength] = 0;
6732 if (smb_StoreAnsiFilenames)
6733 OemToChar(realPathp,realPathp);
6735 spacep = cm_GetSpace();
6736 smb_StripLastComponent(spacep->data, &lastNamep, realPathp);
6739 * Nothing here to handle SMB_IOCTL_FILENAME.
6740 * Will add it if necessary.
6743 #ifdef DEBUG_VERBOSE
6745 char *hexp, *asciip;
6746 asciip = (lastNamep? lastNamep : realPathp);
6747 hexp = osi_HexifyString( asciip );
6748 DEBUG_EVENT2("AFS", "NTTranCreate H[%s] A[%s]", hexp, asciip);
6753 userp = smb_GetUserFromVCP(vcp, inp);
6755 osi_Log1(smb_logp, "NTTranCreate invalid user [%d]", ((smb_t *) inp)->uid);
6757 return CM_ERROR_INVAL;
6762 baseDirp = cm_data.rootSCachep;
6763 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
6764 if (code == CM_ERROR_TIDIPC) {
6765 /* Attempt to use a TID allocated for IPC. The client
6766 * is probably looking for DCE RPC end points which we
6767 * don't support OR it could be looking to make a DFS
6770 osi_Log0(smb_logp, "NTTranCreate received IPC TID");
6773 cm_ReleaseUser(userp);
6774 return CM_ERROR_NOSUCHPATH;
6778 baseFidp = smb_FindFID(vcp, baseFid, 0);
6780 osi_Log1(smb_logp, "NTTranCreate Invalid fid [%d]", baseFid);
6782 cm_ReleaseUser(userp);
6783 return CM_ERROR_INVAL;
6785 baseDirp = baseFidp->scp;
6789 /* compute open mode */
6791 if (desiredAccess & DELETE)
6792 fidflags |= SMB_FID_OPENDELETE;
6793 if (desiredAccess & AFS_ACCESS_READ)
6794 fidflags |= SMB_FID_OPENREAD;
6795 if (desiredAccess & AFS_ACCESS_WRITE)
6796 fidflags |= SMB_FID_OPENWRITE;
6797 if (createOptions & FILE_DELETE_ON_CLOSE)
6798 fidflags |= SMB_FID_DELONCLOSE;
6800 /* And the share mode */
6801 if (shareAccess & FILE_SHARE_READ)
6802 fidflags |= SMB_FID_SHARE_READ;
6803 if (shareAccess & FILE_SHARE_WRITE)
6804 fidflags |= SMB_FID_SHARE_WRITE;
6808 if ( createDisp == FILE_OPEN ||
6809 createDisp == FILE_OVERWRITE ||
6810 createDisp == FILE_OVERWRITE_IF) {
6811 code = cm_NameI(baseDirp, spacep->data, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
6812 userp, tidPathp, &req, &dscp);
6815 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
6816 cm_ReleaseSCache(dscp);
6817 cm_ReleaseUser(userp);
6820 smb_ReleaseFID(baseFidp);
6821 if ( WANTS_DFS_PATHNAMES(inp) )
6822 return CM_ERROR_PATH_NOT_COVERED;
6824 return CM_ERROR_BADSHARENAME;
6826 #endif /* DFS_SUPPORT */
6827 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp, CM_FLAG_FOLLOW,
6829 if (code == CM_ERROR_NOSUCHFILE) {
6830 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp,
6831 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, &req, &scp);
6832 if (code == 0 && realDirFlag == 1) {
6833 cm_ReleaseSCache(scp);
6834 cm_ReleaseSCache(dscp);
6835 cm_ReleaseUser(userp);
6838 smb_ReleaseFID(baseFidp);
6839 return CM_ERROR_EXISTS;
6845 code = cm_NameI(baseDirp, realPathp, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
6846 userp, tidPathp, &req, &scp);
6848 if (code == 0 && scp->fileType == CM_SCACHETYPE_DFSLINK) {
6849 cm_ReleaseSCache(scp);
6850 cm_ReleaseUser(userp);
6853 smb_ReleaseFID(baseFidp);
6854 if ( WANTS_DFS_PATHNAMES(inp) )
6855 return CM_ERROR_PATH_NOT_COVERED;
6857 return CM_ERROR_BADSHARENAME;
6859 #endif /* DFS_SUPPORT */
6865 if (code != 0 || (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE))) {
6866 /* look up parent directory */
6868 code = cm_NameI(baseDirp, spacep->data,
6869 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
6870 userp, tidPathp, &req, &dscp);
6872 if (code == 0 && dscp->fileType == CM_SCACHETYPE_DFSLINK) {
6873 cm_ReleaseSCache(dscp);
6874 cm_ReleaseUser(userp);
6877 smb_ReleaseFID(baseFidp);
6878 if ( WANTS_DFS_PATHNAMES(inp) )
6879 return CM_ERROR_PATH_NOT_COVERED;
6881 return CM_ERROR_BADSHARENAME;
6883 #endif /* DFS_SUPPORT */
6887 cm_FreeSpace(spacep);
6890 smb_ReleaseFID(baseFidp);
6893 cm_ReleaseUser(userp);
6899 lastNamep = realPathp;
6903 if (!smb_IsLegalFilename(lastNamep))
6904 return CM_ERROR_BADNTFILENAME;
6907 if (createDisp == FILE_CREATE || createDisp == FILE_OVERWRITE_IF) {
6908 code = cm_Lookup(dscp, lastNamep,
6909 CM_FLAG_FOLLOW, userp, &req, &scp);
6911 code = cm_Lookup(dscp, lastNamep,
6912 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
6915 if (code && code != CM_ERROR_NOSUCHFILE) {
6916 cm_ReleaseSCache(dscp);
6917 cm_ReleaseUser(userp);
6924 smb_ReleaseFID(baseFidp);
6925 cm_FreeSpace(spacep);
6928 /* if we get here, if code is 0, the file exists and is represented by
6929 * scp. Otherwise, we have to create it. The dir may be represented
6930 * by dscp, or we may have found the file directly. If code is non-zero,
6934 code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp,
6938 cm_ReleaseSCache(dscp);
6939 cm_ReleaseSCache(scp);
6940 cm_ReleaseUser(userp);
6945 if (createDisp == FILE_CREATE) {
6946 /* oops, file shouldn't be there */
6948 cm_ReleaseSCache(dscp);
6949 cm_ReleaseSCache(scp);
6950 cm_ReleaseUser(userp);
6952 return CM_ERROR_EXISTS;
6955 if (createDisp == FILE_OVERWRITE ||
6956 createDisp == FILE_OVERWRITE_IF) {
6957 setAttr.mask = CM_ATTRMASK_LENGTH;
6958 setAttr.length.LowPart = 0;
6959 setAttr.length.HighPart = 0;
6961 /* now watch for a symlink */
6963 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
6965 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
6967 /* we have a more accurate file to use (the
6968 * target of the symbolic link). Otherwise,
6969 * we'll just use the symlink anyway.
6971 osi_Log2(smb_logp, "symlink vp %x to vp %x",
6973 cm_ReleaseSCache(scp);
6977 code = cm_SetAttr(scp, &setAttr, userp, &req);
6978 openAction = 3; /* truncated existing file */
6980 else openAction = 1; /* found existing file */
6982 else if (createDisp == FILE_OPEN || createDisp == FILE_OVERWRITE) {
6983 /* don't create if not found */
6985 cm_ReleaseSCache(dscp);
6986 cm_ReleaseUser(userp);
6988 return CM_ERROR_NOSUCHFILE;
6990 else if (realDirFlag == 0 || realDirFlag == -1) {
6991 osi_assert(dscp != NULL);
6992 osi_Log1(smb_logp, "smb_ReceiveNTTranCreate creating file %s",
6993 osi_LogSaveString(smb_logp, lastNamep));
6994 openAction = 2; /* created file */
6995 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
6996 setAttr.clientModTime = time(NULL);
6997 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
7001 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
7002 smb_NotifyChange(FILE_ACTION_ADDED,
7003 FILE_NOTIFY_CHANGE_FILE_NAME,
7004 dscp, lastNamep, NULL, TRUE);
7005 } else if (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE) {
7006 /* Not an exclusive create, and someone else tried
7007 * creating it already, then we open it anyway. We
7008 * don't bother retrying after this, since if this next
7009 * fails, that means that the file was deleted after we
7010 * started this call.
7012 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
7015 if (createDisp == FILE_OVERWRITE_IF) {
7016 setAttr.mask = CM_ATTRMASK_LENGTH;
7017 setAttr.length.LowPart = 0;
7018 setAttr.length.HighPart = 0;
7020 /* now watch for a symlink */
7022 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
7024 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
7026 /* we have a more accurate file to use (the
7027 * target of the symbolic link). Otherwise,
7028 * we'll just use the symlink anyway.
7030 osi_Log2(smb_logp, "symlink vp %x to vp %x",
7032 cm_ReleaseSCache(scp);
7036 code = cm_SetAttr(scp, &setAttr, userp, &req);
7038 } /* lookup succeeded */
7041 /* create directory */
7042 osi_assert(dscp != NULL);
7044 "smb_ReceiveNTTranCreate creating directory %s",
7045 osi_LogSaveString(smb_logp, lastNamep));
7046 openAction = 2; /* created directory */
7047 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
7048 setAttr.clientModTime = time(NULL);
7049 code = cm_MakeDir(dscp, lastNamep, 0, &setAttr, userp, &req);
7050 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
7051 smb_NotifyChange(FILE_ACTION_ADDED,
7052 FILE_NOTIFY_CHANGE_DIR_NAME,
7053 dscp, lastNamep, NULL, TRUE);
7055 (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE)) {
7056 /* Not an exclusive create, and someone else tried
7057 * creating it already, then we open it anyway. We
7058 * don't bother retrying after this, since if this next
7059 * fails, that means that the file was deleted after we
7060 * started this call.
7062 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
7068 /* something went wrong creating or truncating the file */
7070 cm_ReleaseSCache(scp);
7071 cm_ReleaseUser(userp);
7076 /* make sure we have file vs. dir right */
7077 if (realDirFlag == 0 && scp->fileType != CM_SCACHETYPE_FILE) {
7078 /* now watch for a symlink */
7080 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
7082 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
7084 /* we have a more accurate file to use (the
7085 * target of the symbolic link). Otherwise,
7086 * we'll just use the symlink anyway.
7088 osi_Log2(smb_logp, "symlink vp %x to vp %x",
7090 cm_ReleaseSCache(scp);
7095 if (scp->fileType != CM_SCACHETYPE_FILE) {
7096 cm_ReleaseSCache(scp);
7097 cm_ReleaseUser(userp);
7099 return CM_ERROR_ISDIR;
7103 if (realDirFlag == 1 && scp->fileType == CM_SCACHETYPE_FILE) {
7104 cm_ReleaseSCache(scp);
7105 cm_ReleaseUser(userp);
7107 return CM_ERROR_NOTDIR;
7110 /* open the file itself */
7111 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
7114 /* save a reference to the user */
7116 fidp->userp = userp;
7118 /* If we are restricting sharing, we should do so with a suitable
7120 if (scp->fileType == CM_SCACHETYPE_FILE &&
7121 !(fidflags & SMB_FID_SHARE_WRITE)) {
7123 LARGE_INTEGER LOffset, LLength;
7126 LOffset.HighPart = SMB_FID_QLOCK_HIGH;
7127 LOffset.LowPart = SMB_FID_QLOCK_LOW;
7128 LLength.HighPart = 0;
7129 LLength.LowPart = SMB_FID_QLOCK_LENGTH;
7131 if (fidflags & SMB_FID_SHARE_READ) {
7132 sLockType = LOCKING_ANDX_SHARED_LOCK;
7137 key = cm_GenerateKey(vcp->vcID, SMB_FID_QLOCK_PID, fidp->fid);
7139 lock_ObtainMutex(&scp->mx);
7140 code = cm_Lock(scp, sLockType, LOffset, LLength, key, 0, userp, &req, NULL);
7141 lock_ReleaseMutex(&scp->mx);
7144 /* Shouldn't this be smb_CloseFID()? fidp->flags = SMB_FID_DELETE; */
7145 smb_CloseFID(vcp, fidp, NULL, 0);
7146 smb_ReleaseFID(fidp);
7148 cm_ReleaseSCache(scp);
7149 cm_ReleaseUser(userp);
7152 return CM_ERROR_SHARING_VIOLATION;
7156 lock_ObtainMutex(&fidp->mx);
7157 /* save a pointer to the vnode */
7160 fidp->flags = fidflags;
7162 /* remember if the file was newly created */
7164 fidp->flags |= SMB_FID_CREATED;
7166 /* save parent dir and pathname for deletion or change notification */
7167 if (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE)) {
7168 fidp->flags |= SMB_FID_NTOPEN;
7169 fidp->NTopen_dscp = dscp;
7170 cm_HoldSCache(dscp);
7171 fidp->NTopen_pathp = strdup(lastNamep);
7173 fidp->NTopen_wholepathp = realPathp;
7174 lock_ReleaseMutex(&fidp->mx);
7176 /* we don't need this any longer */
7178 cm_ReleaseSCache(dscp);
7180 cm_Open(scp, 0, userp);
7182 /* set inp->fid so that later read calls in same msg can find fid */
7183 inp->fid = fidp->fid;
7185 /* check whether we are required to send an extended response */
7186 if (!extendedRespRequired) {
7188 parmOffset = 8*4 + 39;
7189 parmOffset += 1; /* pad to 4 */
7190 dataOffset = parmOffset + 70;
7194 /* Total Parameter Count */
7195 smb_SetSMBParmLong(outp, parmSlot, 70); parmSlot += 2;
7196 /* Total Data Count */
7197 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
7198 /* Parameter Count */
7199 smb_SetSMBParmLong(outp, parmSlot, 70); parmSlot += 2;
7200 /* Parameter Offset */
7201 smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
7202 /* Parameter Displacement */
7203 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
7205 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
7207 smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
7208 /* Data Displacement */
7209 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
7210 smb_SetSMBParmByte(outp, parmSlot, 0); /* Setup Count */
7211 smb_SetSMBDataLength(outp, 70);
7213 lock_ObtainMutex(&scp->mx);
7214 outData = smb_GetSMBData(outp, NULL);
7215 outData++; /* round to get to parmOffset */
7216 *outData = 0; outData++; /* oplock */
7217 *outData = 0; outData++; /* reserved */
7218 *((USHORT *)outData) = fidp->fid; outData += 2; /* fid */
7219 *((ULONG *)outData) = openAction; outData += 4;
7220 *((ULONG *)outData) = 0; outData += 4; /* EA error offset */
7221 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
7222 *((FILETIME *)outData) = ft; outData += 8; /* creation time */
7223 *((FILETIME *)outData) = ft; outData += 8; /* last access time */
7224 *((FILETIME *)outData) = ft; outData += 8; /* last write time */
7225 *((FILETIME *)outData) = ft; outData += 8; /* change time */
7226 *((ULONG *)outData) = smb_ExtAttributes(scp); outData += 4;
7227 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* alloc sz */
7228 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* EOF */
7229 *((USHORT *)outData) = 0; outData += 2; /* filetype */
7230 *((USHORT *)outData) = 0; outData += 2; /* dev state */
7231 *((USHORT *)outData) = ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
7232 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
7233 scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0);
7234 outData += 2; /* is a dir? */
7235 lock_ReleaseMutex(&scp->mx);
7238 parmOffset = 8*4 + 39;
7239 parmOffset += 1; /* pad to 4 */
7240 dataOffset = parmOffset + 104;
7244 /* Total Parameter Count */
7245 smb_SetSMBParmLong(outp, parmSlot, 101); parmSlot += 2;
7246 /* Total Data Count */
7247 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
7248 /* Parameter Count */
7249 smb_SetSMBParmLong(outp, parmSlot, 101); parmSlot += 2;
7250 /* Parameter Offset */
7251 smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
7252 /* Parameter Displacement */
7253 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
7255 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
7257 smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
7258 /* Data Displacement */
7259 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
7260 smb_SetSMBParmByte(outp, parmSlot, 0); /* Setup Count */
7261 smb_SetSMBDataLength(outp, 105);
7263 lock_ObtainMutex(&scp->mx);
7264 outData = smb_GetSMBData(outp, NULL);
7265 outData++; /* round to get to parmOffset */
7266 *outData = 0; outData++; /* oplock */
7267 *outData = 1; outData++; /* response type */
7268 *((USHORT *)outData) = fidp->fid; outData += 2; /* fid */
7269 *((ULONG *)outData) = openAction; outData += 4;
7270 *((ULONG *)outData) = 0; outData += 4; /* EA error offset */
7271 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
7272 *((FILETIME *)outData) = ft; outData += 8; /* creation time */
7273 *((FILETIME *)outData) = ft; outData += 8; /* last access time */
7274 *((FILETIME *)outData) = ft; outData += 8; /* last write time */
7275 *((FILETIME *)outData) = ft; outData += 8; /* change time */
7276 *((ULONG *)outData) = smb_ExtAttributes(scp); outData += 4;
7277 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* alloc sz */
7278 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* EOF */
7279 *((USHORT *)outData) = 0; outData += 2; /* filetype */
7280 *((USHORT *)outData) = 0; outData += 2; /* dev state */
7281 *((USHORT *)outData) = ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
7282 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
7283 scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0);
7284 outData += 1; /* is a dir? */
7285 memset(outData,0,24); outData += 24; /* Volume ID and file ID */
7286 *((ULONG *)outData) = 0x001f01ffL; outData += 4; /* Maxmimal access rights */
7287 *((ULONG *)outData) = 0; outData += 4; /* Guest Access rights */
7288 lock_ReleaseMutex(&scp->mx);
7291 osi_Log1(smb_logp, "SMB NTTranCreate opening fid %d", fidp->fid);
7293 smb_ReleaseFID(fidp);
7295 cm_ReleaseUser(userp);
7297 /* free(realPathp); Can't free realPathp here because fidp->NTopen_wholepathp points there */
7298 /* leave scp held since we put it in fidp->scp */
7302 long smb_ReceiveNTTranNotifyChange(smb_vc_t *vcp, smb_packet_t *inp,
7305 smb_packet_t *savedPacketp;
7306 ULONG filter; USHORT fid, watchtree;
7310 filter = smb_GetSMBParm(inp, 19) |
7311 (smb_GetSMBParm(inp, 20) << 16);
7312 fid = smb_GetSMBParm(inp, 21);
7313 watchtree = smb_GetSMBParm(inp, 22) && 0xffff; /* TODO: should this be 0xff ? */
7315 fidp = smb_FindFID(vcp, fid, 0);
7317 osi_Log1(smb_logp, "ERROR: NotifyChange given invalid fid [%d]", fid);
7318 return CM_ERROR_BADFD;
7321 savedPacketp = smb_CopyPacket(inp);
7323 if (savedPacketp->vcp)
7324 smb_ReleaseVC(savedPacketp->vcp);
7325 savedPacketp->vcp = vcp;
7326 lock_ObtainMutex(&smb_Dir_Watch_Lock);
7327 savedPacketp->nextp = smb_Directory_Watches;
7328 smb_Directory_Watches = savedPacketp;
7329 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
7331 osi_Log4(smb_logp, "Request for NotifyChange filter 0x%x fid %d wtree %d file %s",
7332 filter, fid, watchtree, osi_LogSaveString(smb_logp, fidp->NTopen_wholepathp));
7335 lock_ObtainMutex(&scp->mx);
7337 scp->flags |= CM_SCACHEFLAG_WATCHEDSUBTREE;
7339 scp->flags |= CM_SCACHEFLAG_WATCHED;
7340 lock_ReleaseMutex(&scp->mx);
7341 smb_ReleaseFID(fidp);
7343 outp->flags |= SMB_PACKETFLAG_NOSEND;
7347 unsigned char nullSecurityDesc[36] = {
7348 0x01, /* security descriptor revision */
7349 0x00, /* reserved, should be zero */
7350 0x00, 0x80, /* security descriptor control;
7351 * 0x8000 : self-relative format */
7352 0x14, 0x00, 0x00, 0x00, /* offset of owner SID */
7353 0x1c, 0x00, 0x00, 0x00, /* offset of group SID */
7354 0x00, 0x00, 0x00, 0x00, /* offset of DACL would go here */
7355 0x00, 0x00, 0x00, 0x00, /* offset of SACL would go here */
7356 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
7357 /* "null SID" owner SID */
7358 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
7359 /* "null SID" group SID */
7362 long smb_ReceiveNTTranQuerySecurityDesc(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7364 int parmOffset, parmCount, dataOffset, dataCount;
7372 ULONG securityInformation;
7374 parmOffset = smb_GetSMBOffsetParm(inp, 11, 1)
7375 | (smb_GetSMBOffsetParm(inp, 12, 1) << 16);
7376 parmp = inp->data + parmOffset;
7377 sparmp = (USHORT *) parmp;
7378 lparmp = (ULONG *) parmp;
7381 securityInformation = lparmp[1];
7383 maxData = smb_GetSMBOffsetParm(inp, 7, 1)
7384 | (smb_GetSMBOffsetParm(inp, 8, 1) << 16);
7392 parmOffset = 8*4 + 39;
7393 parmOffset += 1; /* pad to 4 */
7395 dataOffset = parmOffset + parmCount;
7399 /* Total Parameter Count */
7400 smb_SetSMBParmLong(outp, parmSlot, parmCount); parmSlot += 2;
7401 /* Total Data Count */
7402 smb_SetSMBParmLong(outp, parmSlot, dataCount); parmSlot += 2;
7403 /* Parameter Count */
7404 smb_SetSMBParmLong(outp, parmSlot, parmCount); parmSlot += 2;
7405 /* Parameter Offset */
7406 smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
7407 /* Parameter Displacement */
7408 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
7410 smb_SetSMBParmLong(outp, parmSlot, dataCount); parmSlot += 2;
7412 smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
7413 /* Data Displacement */
7414 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
7415 smb_SetSMBParmByte(outp, parmSlot, 0); /* Setup Count */
7416 smb_SetSMBDataLength(outp, 1 + parmCount + dataCount);
7418 outData = smb_GetSMBData(outp, NULL);
7419 outData++; /* round to get to parmOffset */
7420 *((ULONG *)outData) = 36; outData += 4; /* length */
7422 if (maxData >= 36) {
7423 memcpy(outData, nullSecurityDesc, 36);
7427 return CM_ERROR_BUFFERTOOSMALL;
7430 long smb_ReceiveNTTransact(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7432 unsigned short function;
7434 function = smb_GetSMBParm(inp, 18);
7436 osi_Log1(smb_logp, "SMB NT Transact function %d", function);
7438 /* We can handle long names */
7439 if (vcp->flags & SMB_VCFLAG_USENT)
7440 ((smb_t *)outp)->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
7444 return smb_ReceiveNTTranCreate(vcp, inp, outp);
7446 osi_Log0(smb_logp, "SMB NT Transact Ioctl - not implemented");
7449 osi_Log0(smb_logp, "SMB NT Transact SetSecurityDesc - not implemented");
7452 return smb_ReceiveNTTranNotifyChange(vcp, inp, outp);
7454 osi_Log0(smb_logp, "SMB NT Transact Rename - not implemented");
7457 return smb_ReceiveNTTranQuerySecurityDesc(vcp, inp, outp);
7459 return CM_ERROR_INVAL;
7463 * smb_NotifyChange -- find relevant change notification messages and
7466 * If we don't know the file name (i.e. a callback break), filename is
7467 * NULL, and we return a zero-length list.
7469 void smb_NotifyChange(DWORD action, DWORD notifyFilter,
7470 cm_scache_t *dscp, char *filename, char *otherFilename,
7471 BOOL isDirectParent)
7473 smb_packet_t *watch, *lastWatch, *nextWatch;
7474 ULONG parmSlot, parmCount, parmOffset, dataOffset, nameLen;
7475 char *outData, *oldOutData;
7479 BOOL twoEntries = FALSE;
7480 ULONG otherNameLen, oldParmCount = 0;
7484 /* Get ready for rename within directory */
7485 if (action == FILE_ACTION_RENAMED_OLD_NAME && otherFilename != NULL) {
7487 otherAction = FILE_ACTION_RENAMED_NEW_NAME;
7490 osi_Log2(smb_logp,"in smb_NotifyChange for file [%s] dscp [%x]",
7491 osi_LogSaveString(smb_logp,filename),dscp);
7493 lock_ObtainMutex(&smb_Dir_Watch_Lock);
7494 watch = smb_Directory_Watches;
7496 filter = smb_GetSMBParm(watch, 19)
7497 | (smb_GetSMBParm(watch, 20) << 16);
7498 fid = smb_GetSMBParm(watch, 21);
7499 wtree = smb_GetSMBParm(watch, 22) & 0xffff; /* TODO: should this be 0xff ? */
7500 maxLen = smb_GetSMBOffsetParm(watch, 5, 1)
7501 | (smb_GetSMBOffsetParm(watch, 6, 1) << 16);
7504 * Strange hack - bug in NT Client and NT Server that we
7507 if (filter == 3 && wtree)
7510 fidp = smb_FindFID(watch->vcp, fid, 0);
7512 osi_Log1(smb_logp," no fidp for fid[%d]",fid);
7514 watch = watch->nextp;
7517 if (fidp->scp != dscp
7518 || (filter & notifyFilter) == 0
7519 || (!isDirectParent && !wtree)) {
7520 osi_Log1(smb_logp," passing fidp->scp[%x]", fidp->scp);
7521 smb_ReleaseFID(fidp);
7523 watch = watch->nextp;
7526 smb_ReleaseFID(fidp);
7529 "Sending Change Notification for fid %d filter 0x%x wtree %d file %s",
7530 fid, filter, wtree, osi_LogSaveString(smb_logp, filename));
7532 nextWatch = watch->nextp;
7533 if (watch == smb_Directory_Watches)
7534 smb_Directory_Watches = nextWatch;
7536 lastWatch->nextp = nextWatch;
7538 /* Turn off WATCHED flag in dscp */
7539 lock_ObtainMutex(&dscp->mx);
7541 dscp->flags &= ~CM_SCACHEFLAG_WATCHEDSUBTREE;
7543 dscp->flags &= ~CM_SCACHEFLAG_WATCHED;
7544 lock_ReleaseMutex(&dscp->mx);
7546 /* Convert to response packet */
7547 ((smb_t *) watch)->reb = SMB_FLAGS_SERVER_TO_CLIENT | SMB_FLAGS_CANONICAL_PATHNAMES;
7548 ((smb_t *) watch)->wct = 0;
7551 if (filename == NULL)
7554 nameLen = (ULONG)strlen(filename);
7555 parmCount = 3*4 + nameLen*2;
7556 parmCount = (parmCount + 3) & ~3; /* pad to 4 */
7558 otherNameLen = (ULONG)strlen(otherFilename);
7559 oldParmCount = parmCount;
7560 parmCount += 3*4 + otherNameLen*2;
7561 parmCount = (parmCount + 3) & ~3; /* pad to 4 */
7563 if (maxLen < parmCount)
7564 parmCount = 0; /* not enough room */
7566 parmOffset = 8*4 + 39;
7567 parmOffset += 1; /* pad to 4 */
7568 dataOffset = parmOffset + parmCount;
7572 /* Total Parameter Count */
7573 smb_SetSMBParmLong(watch, parmSlot, parmCount); parmSlot += 2;
7574 /* Total Data Count */
7575 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
7576 /* Parameter Count */
7577 smb_SetSMBParmLong(watch, parmSlot, parmCount); parmSlot += 2;
7578 /* Parameter Offset */
7579 smb_SetSMBParmLong(watch, parmSlot, parmOffset); parmSlot += 2;
7580 /* Parameter Displacement */
7581 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
7583 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
7585 smb_SetSMBParmLong(watch, parmSlot, dataOffset); parmSlot += 2;
7586 /* Data Displacement */
7587 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
7588 smb_SetSMBParmByte(watch, parmSlot, 0); /* Setup Count */
7589 smb_SetSMBDataLength(watch, parmCount + 1);
7591 if (parmCount != 0) {
7593 outData = smb_GetSMBData(watch, NULL);
7594 outData++; /* round to get to parmOffset */
7595 oldOutData = outData;
7596 *((DWORD *)outData) = oldParmCount; outData += 4;
7597 /* Next Entry Offset */
7598 *((DWORD *)outData) = action; outData += 4;
7600 *((DWORD *)outData) = nameLen*2; outData += 4;
7601 /* File Name Length */
7602 p = strdup(filename);
7603 if (smb_StoreAnsiFilenames)
7605 mbstowcs((WCHAR *)outData, p, nameLen);
7609 outData = oldOutData + oldParmCount;
7610 *((DWORD *)outData) = 0; outData += 4;
7611 /* Next Entry Offset */
7612 *((DWORD *)outData) = otherAction; outData += 4;
7614 *((DWORD *)outData) = otherNameLen*2;
7615 outData += 4; /* File Name Length */
7616 p = strdup(otherFilename);
7617 if (smb_StoreAnsiFilenames)
7619 mbstowcs((WCHAR *)outData, p, otherNameLen); /* File Name */
7625 * If filename is null, we don't know the cause of the
7626 * change notification. We return zero data (see above),
7627 * and set error code to NT_STATUS_NOTIFY_ENUM_DIR
7628 * (= 0x010C). We set the error code here by hand, without
7629 * modifying wct and bcc.
7631 if (filename == NULL) {
7632 ((smb_t *) watch)->rcls = 0x0C;
7633 ((smb_t *) watch)->reh = 0x01;
7634 ((smb_t *) watch)->errLow = 0;
7635 ((smb_t *) watch)->errHigh = 0;
7636 /* Set NT Status codes flag */
7637 ((smb_t *) watch)->flg2 |= SMB_FLAGS2_32BIT_STATUS;
7640 smb_SendPacket(watch->vcp, watch);
7641 smb_FreePacket(watch);
7644 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
7647 long smb_ReceiveNTCancel(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7649 unsigned char *replyWctp;
7650 smb_packet_t *watch, *lastWatch;
7651 USHORT fid, watchtree;
7655 osi_Log0(smb_logp, "SMB3 receive NT cancel");
7657 lock_ObtainMutex(&smb_Dir_Watch_Lock);
7658 watch = smb_Directory_Watches;
7660 if (((smb_t *)watch)->uid == ((smb_t *)inp)->uid
7661 && ((smb_t *)watch)->pid == ((smb_t *)inp)->pid
7662 && ((smb_t *)watch)->mid == ((smb_t *)inp)->mid
7663 && ((smb_t *)watch)->tid == ((smb_t *)inp)->tid) {
7664 if (watch == smb_Directory_Watches)
7665 smb_Directory_Watches = watch->nextp;
7667 lastWatch->nextp = watch->nextp;
7668 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
7670 /* Turn off WATCHED flag in scp */
7671 fid = smb_GetSMBParm(watch, 21);
7672 watchtree = smb_GetSMBParm(watch, 22) & 0xffff;
7674 if (vcp != watch->vcp)
7675 osi_Log2(smb_logp, "smb_ReceiveNTCancel: vcp %x not equal to watch vcp %x",
7678 fidp = smb_FindFID(vcp, fid, 0);
7680 osi_Log3(smb_logp, "Cancelling change notification for fid %d wtree %d file %s",
7682 osi_LogSaveString(smb_logp, (fidp)?fidp->NTopen_wholepathp:""));
7685 lock_ObtainMutex(&scp->mx);
7687 scp->flags &= ~CM_SCACHEFLAG_WATCHEDSUBTREE;
7689 scp->flags &= ~CM_SCACHEFLAG_WATCHED;
7690 lock_ReleaseMutex(&scp->mx);
7691 smb_ReleaseFID(fidp);
7693 osi_Log2(smb_logp,"NTCancel unable to resolve fid [%d] in vcp[%x]", fid,vcp);
7696 /* assume STATUS32; return 0xC0000120 (CANCELED) */
7697 replyWctp = watch->wctp;
7701 ((smb_t *)watch)->rcls = 0x20;
7702 ((smb_t *)watch)->reh = 0x1;
7703 ((smb_t *)watch)->errLow = 0;
7704 ((smb_t *)watch)->errHigh = 0xC0;
7705 ((smb_t *)watch)->flg2 |= SMB_FLAGS2_32BIT_STATUS;
7706 smb_SendPacket(vcp, watch);
7707 smb_FreePacket(watch);
7711 watch = watch->nextp;
7713 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
7719 * NT rename also does hard links.
7722 #define RENAME_FLAG_MOVE_CLUSTER_INFORMATION 0x102
7723 #define RENAME_FLAG_HARD_LINK 0x103
7724 #define RENAME_FLAG_RENAME 0x104
7725 #define RENAME_FLAG_COPY 0x105
7727 long smb_ReceiveNTRename(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7729 char *oldPathp, *newPathp;
7735 attrs = smb_GetSMBParm(inp, 0);
7736 rename_type = smb_GetSMBParm(inp, 1);
7738 if (rename_type != RENAME_FLAG_RENAME && rename_type != RENAME_FLAG_HARD_LINK) {
7739 osi_Log1(smb_logp, "NTRename invalid infolevel [%x]", rename_type);
7740 return CM_ERROR_NOACCESS;
7743 tp = smb_GetSMBData(inp, NULL);
7744 oldPathp = smb_ParseASCIIBlock(tp, &tp);
7745 if (smb_StoreAnsiFilenames)
7746 OemToChar(oldPathp,oldPathp);
7747 newPathp = smb_ParseASCIIBlock(tp, &tp);
7748 if (smb_StoreAnsiFilenames)
7749 OemToChar(newPathp,newPathp);
7751 osi_Log3(smb_logp, "NTRename for [%s]->[%s] type [%s]",
7752 osi_LogSaveString(smb_logp, oldPathp),
7753 osi_LogSaveString(smb_logp, newPathp),
7754 ((rename_type==RENAME_FLAG_RENAME)?"rename":"hardlink"));
7756 if (rename_type == RENAME_FLAG_RENAME) {
7757 code = smb_Rename(vcp,inp,oldPathp,newPathp,attrs);
7758 } else { /* RENAME_FLAG_HARD_LINK */
7759 code = smb_Link(vcp,inp,oldPathp,newPathp);
7766 lock_InitializeMutex(&smb_Dir_Watch_Lock, "Directory Watch List Lock");
7769 cm_user_t *smb_FindCMUserByName(char *usern, char *machine, afs_uint32 flags)
7771 smb_username_t *unp;
7774 unp = smb_FindUserByName(usern, machine, flags);
7776 lock_ObtainMutex(&unp->mx);
7777 unp->userp = cm_NewUser();
7778 lock_ReleaseMutex(&unp->mx);
7779 osi_Log2(smb_logp,"smb_FindCMUserByName New user name[%s] machine[%s]",osi_LogSaveString(smb_logp,usern),osi_LogSaveString(smb_logp,machine));
7781 osi_Log2(smb_logp,"smb_FindCMUserByName Not found name[%s] machine[%s]",osi_LogSaveString(smb_logp,usern),osi_LogSaveString(smb_logp,machine));
7785 smb_ReleaseUsername(unp);