2 * Copyright 2000, International Business Machines Corporation and others.
5 * This software has been released under the terms of the IBM Public
6 * License. For details, see the LICENSE file in the top-level source
7 * directory or online at http://www.openafs.org/dl/license10.html
10 #include <afs/param.h>
15 #define SECURITY_WIN32
26 #include <WINNT\afsreg.h>
30 extern osi_hyper_t hzero;
32 smb_packet_t *smb_Directory_Watches = NULL;
33 osi_mutex_t smb_Dir_Watch_Lock;
35 smb_tran2Dispatch_t smb_tran2DispatchTable[SMB_TRAN2_NOPCODES];
37 smb_tran2Dispatch_t smb_rapDispatchTable[SMB_RAP_NOPCODES];
39 /* protected by the smb_globalLock */
40 smb_tran2Packet_t *smb_tran2AssemblyQueuep;
42 /* retrieve a held reference to a user structure corresponding to an incoming
44 cm_user_t *smb_GetTran2User(smb_vc_t *vcp, smb_tran2Packet_t *inp)
49 uidp = smb_FindUID(vcp, inp->uid, 0);
53 up = smb_GetUserFromUID(uidp);
61 * Return extended attributes.
62 * Right now, we aren't using any of the "new" bits, so this looks exactly
63 * like smb_Attributes() (see smb.c).
65 unsigned long smb_ExtAttributes(cm_scache_t *scp)
69 if (scp->fileType == CM_SCACHETYPE_DIRECTORY ||
70 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
71 scp->fileType == CM_SCACHETYPE_INVALID)
73 attrs = SMB_ATTR_DIRECTORY;
74 #ifdef SPECIAL_FOLDERS
75 attrs |= SMB_ATTR_SYSTEM; /* FILE_ATTRIBUTE_SYSTEM */
76 #endif /* SPECIAL_FOLDERS */
77 } else if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
78 attrs = SMB_ATTR_DIRECTORY | SMB_ATTR_SPARSE_FILE;
82 * We used to mark a file RO if it was in an RO volume, but that
83 * turns out to be impolitic in NT. See defect 10007.
86 if ((scp->unixModeBits & 0222) == 0 || (scp->flags & CM_SCACHEFLAG_RO))
87 attrs |= SMB_ATTR_READONLY; /* Read-only */
89 if ((scp->unixModeBits & 0222) == 0)
90 attrs |= SMB_ATTR_READONLY; /* Read-only */
94 attrs = SMB_ATTR_NORMAL; /* FILE_ATTRIBUTE_NORMAL */
99 int smb_V3IsStarMask(char *maskp)
103 while (tc = *maskp++)
104 if (tc == '?' || tc == '*' || tc == '<' || tc == '>')
109 unsigned char *smb_ParseString(unsigned char *inp, char **chainpp)
112 /* skip over null-terminated string */
113 *chainpp = inp + strlen(inp) + 1;
118 void OutputDebugF(char * format, ...) {
123 va_start( args, format );
124 len = _vscprintf( format, args ) // _vscprintf doesn't count
125 + 3; // terminating '\0' + '\n'
126 buffer = malloc( len * sizeof(char) );
127 vsprintf( buffer, format, args );
128 osi_Log0(smb_logp, osi_LogSaveString(smb_logp, buffer));
129 strcat(buffer, "\n");
130 OutputDebugString(buffer);
134 void OutputDebugHexDump(unsigned char * buffer, int len) {
137 static char tr[16] = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
139 OutputDebugF("Hexdump length [%d]",len);
141 for (i=0;i<len;i++) {
144 osi_Log0(smb_logp, osi_LogSaveString(smb_logp, buf));
146 OutputDebugString(buf);
148 sprintf(buf,"%5x",i);
149 memset(buf+5,' ',80);
154 j = j*3 + 7 + ((j>7)?1:0);
157 buf[j] = tr[k / 16]; buf[j+1] = tr[k % 16];
160 j = j + 56 + ((j>7)?1:0) + pcts;
162 buf[j] = (k>32 && k<127)?k:'.';
169 osi_Log0(smb_logp, osi_LogSaveString(smb_logp, buf));
171 OutputDebugString(buf);
175 #define SMB_EXT_SEC_PACKAGE_NAME "Negotiate"
177 void smb_NegotiateExtendedSecurity(void ** secBlob, int * secBlobLength) {
178 SECURITY_STATUS status, istatus;
179 CredHandle creds = {0,0};
181 SecBufferDesc secOut;
189 OutputDebugF("Negotiating Extended Security");
191 status = AcquireCredentialsHandle( NULL,
192 SMB_EXT_SEC_PACKAGE_NAME,
201 if (status != SEC_E_OK) {
202 /* Really bad. We return an empty security blob */
203 OutputDebugF("AcquireCredentialsHandle failed with %lX", status);
208 secOut.pBuffers = &secTok;
209 secOut.ulVersion = SECBUFFER_VERSION;
211 secTok.BufferType = SECBUFFER_TOKEN;
213 secTok.pvBuffer = NULL;
215 ctx.dwLower = ctx.dwUpper = 0;
217 status = AcceptSecurityContext( &creds,
220 ASC_REQ_CONNECTION | ASC_REQ_EXTENDED_ERROR | ASC_REQ_ALLOCATE_MEMORY,
221 SECURITY_NETWORK_DREP,
228 if (status == SEC_I_COMPLETE_NEEDED || status == SEC_I_COMPLETE_AND_CONTINUE) {
229 OutputDebugF("Completing token...");
230 istatus = CompleteAuthToken(&ctx, &secOut);
231 if ( istatus != SEC_E_OK )
232 OutputDebugF("Token completion failed: %x", istatus);
235 if (status == SEC_I_COMPLETE_AND_CONTINUE || status == SEC_I_CONTINUE_NEEDED) {
236 if (secTok.pvBuffer) {
237 *secBlobLength = secTok.cbBuffer;
238 *secBlob = malloc( secTok.cbBuffer );
239 memcpy(*secBlob, secTok.pvBuffer, secTok.cbBuffer );
242 if ( status != SEC_E_OK )
243 OutputDebugF("AcceptSecurityContext status != CONTINUE %lX", status);
246 /* Discard partial security context */
247 DeleteSecurityContext(&ctx);
249 if (secTok.pvBuffer) FreeContextBuffer( secTok.pvBuffer );
251 /* Discard credentials handle. We'll reacquire one when we get the session setup X */
252 FreeCredentialsHandle(&creds);
258 struct smb_ext_context {
265 long smb_AuthenticateUserExt(smb_vc_t * vcp, char * usern, char * secBlobIn, int secBlobInLength, char ** secBlobOut, int * secBlobOutLength) {
266 SECURITY_STATUS status, istatus;
270 SecBufferDesc secBufIn;
272 SecBufferDesc secBufOut;
275 struct smb_ext_context * secCtx = NULL;
276 struct smb_ext_context * newSecCtx = NULL;
277 void * assembledBlob = NULL;
278 int assembledBlobLength = 0;
281 OutputDebugF("In smb_AuthenticateUserExt");
284 *secBlobOutLength = 0;
286 if (vcp->flags & SMB_VCFLAG_AUTH_IN_PROGRESS) {
287 secCtx = vcp->secCtx;
288 lock_ObtainMutex(&vcp->mx);
289 vcp->flags &= ~SMB_VCFLAG_AUTH_IN_PROGRESS;
291 lock_ReleaseMutex(&vcp->mx);
295 OutputDebugF("Received incoming token:");
296 OutputDebugHexDump(secBlobIn,secBlobInLength);
300 OutputDebugF("Continuing with existing context.");
301 creds = secCtx->creds;
304 if (secCtx->partialToken) {
305 assembledBlobLength = secCtx->partialTokenLen + secBlobInLength;
306 assembledBlob = malloc(assembledBlobLength);
307 memcpy(assembledBlob,secCtx->partialToken, secCtx->partialTokenLen);
308 memcpy(((BYTE *)assembledBlob) + secCtx->partialTokenLen, secBlobIn, secBlobInLength);
311 status = AcquireCredentialsHandle( NULL,
312 SMB_EXT_SEC_PACKAGE_NAME,
321 if (status != SEC_E_OK) {
322 OutputDebugF("Can't acquire Credentials handle [%lX]", status);
323 code = CM_ERROR_BADPASSWORD; /* means "try again when I'm sober" */
331 secBufIn.cBuffers = 1;
332 secBufIn.pBuffers = &secTokIn;
333 secBufIn.ulVersion = SECBUFFER_VERSION;
335 secTokIn.BufferType = SECBUFFER_TOKEN;
337 secTokIn.cbBuffer = assembledBlobLength;
338 secTokIn.pvBuffer = assembledBlob;
340 secTokIn.cbBuffer = secBlobInLength;
341 secTokIn.pvBuffer = secBlobIn;
344 secBufOut.cBuffers = 1;
345 secBufOut.pBuffers = &secTokOut;
346 secBufOut.ulVersion = SECBUFFER_VERSION;
348 secTokOut.BufferType = SECBUFFER_TOKEN;
349 secTokOut.cbBuffer = 0;
350 secTokOut.pvBuffer = NULL;
352 status = AcceptSecurityContext( &creds,
353 ((secCtx)?&ctx:NULL),
355 ASC_REQ_CONNECTION | ASC_REQ_EXTENDED_ERROR | ASC_REQ_ALLOCATE_MEMORY,
356 SECURITY_NETWORK_DREP,
363 if (status == SEC_I_COMPLETE_NEEDED || status == SEC_I_COMPLETE_AND_CONTINUE) {
364 OutputDebugF("Completing token...");
365 istatus = CompleteAuthToken(&ctx, &secBufOut);
366 if ( istatus != SEC_E_OK )
367 OutputDebugF("Token completion failed: %lX", istatus);
370 if (status == SEC_I_COMPLETE_AND_CONTINUE || status == SEC_I_CONTINUE_NEEDED) {
371 OutputDebugF("Continue needed");
373 newSecCtx = malloc(sizeof(*newSecCtx));
375 newSecCtx->creds = creds;
376 newSecCtx->ctx = ctx;
377 newSecCtx->partialToken = NULL;
378 newSecCtx->partialTokenLen = 0;
380 lock_ObtainMutex( &vcp->mx );
381 vcp->flags |= SMB_VCFLAG_AUTH_IN_PROGRESS;
382 vcp->secCtx = newSecCtx;
383 lock_ReleaseMutex( &vcp->mx );
385 code = CM_ERROR_GSSCONTINUE;
388 if ((status == SEC_I_COMPLETE_NEEDED || status == SEC_E_OK ||
389 status == SEC_I_COMPLETE_AND_CONTINUE || status == SEC_I_CONTINUE_NEEDED) &&
390 secTokOut.pvBuffer) {
391 OutputDebugF("Need to send token back to client");
393 *secBlobOutLength = secTokOut.cbBuffer;
394 *secBlobOut = malloc(secTokOut.cbBuffer);
395 memcpy(*secBlobOut, secTokOut.pvBuffer, secTokOut.cbBuffer);
397 OutputDebugF("Outgoing token:");
398 OutputDebugHexDump(*secBlobOut,*secBlobOutLength);
399 } else if (status == SEC_E_INCOMPLETE_MESSAGE) {
400 OutputDebugF("Incomplete message");
402 newSecCtx = malloc(sizeof(*newSecCtx));
404 newSecCtx->creds = creds;
405 newSecCtx->ctx = ctx;
406 newSecCtx->partialToken = malloc(secTokOut.cbBuffer);
407 memcpy(newSecCtx->partialToken, secTokOut.pvBuffer, secTokOut.cbBuffer);
408 newSecCtx->partialTokenLen = secTokOut.cbBuffer;
410 lock_ObtainMutex( &vcp->mx );
411 vcp->flags |= SMB_VCFLAG_AUTH_IN_PROGRESS;
412 vcp->secCtx = newSecCtx;
413 lock_ReleaseMutex( &vcp->mx );
415 code = CM_ERROR_GSSCONTINUE;
418 if (status == SEC_E_OK || status == SEC_I_COMPLETE_NEEDED) {
420 SecPkgContext_Names names;
422 OutputDebugF("Authentication completed");
423 OutputDebugF("Returned flags : [%lX]", flags);
425 if (!QueryContextAttributes(&ctx, SECPKG_ATTR_NAMES, &names)) {
426 OutputDebugF("Received name [%s]", names.sUserName);
427 strcpy(usern, names.sUserName);
428 strlwr(usern); /* in tandem with smb_GetNormalizedUsername */
429 FreeContextBuffer(names.sUserName);
431 /* Force the user to retry if the context is invalid */
432 OutputDebugF("QueryContextAttributes Names failed [%x]", GetLastError());
433 code = CM_ERROR_BADPASSWORD;
437 case SEC_E_INVALID_TOKEN:
438 OutputDebugF("Returning bad password :: INVALID_TOKEN");
440 case SEC_E_INVALID_HANDLE:
441 OutputDebugF("Returning bad password :: INVALID_HANDLE");
443 case SEC_E_LOGON_DENIED:
444 OutputDebugF("Returning bad password :: LOGON_DENIED");
446 case SEC_E_UNKNOWN_CREDENTIALS:
447 OutputDebugF("Returning bad password :: UNKNOWN_CREDENTIALS");
449 case SEC_E_NO_CREDENTIALS:
450 OutputDebugF("Returning bad password :: NO_CREDENTIALS");
452 case SEC_E_CONTEXT_EXPIRED:
453 OutputDebugF("Returning bad password :: CONTEXT_EXPIRED");
455 case SEC_E_INCOMPLETE_CREDENTIALS:
456 OutputDebugF("Returning bad password :: INCOMPLETE_CREDENTIALS");
458 case SEC_E_WRONG_PRINCIPAL:
459 OutputDebugF("Returning bad password :: WRONG_PRINCIPAL");
461 case SEC_E_TIME_SKEW:
462 OutputDebugF("Returning bad password :: TIME_SKEW");
465 OutputDebugF("Returning bad password :: Status == %lX", status);
467 code = CM_ERROR_BADPASSWORD;
471 if (secCtx->partialToken) free(secCtx->partialToken);
479 if (secTokOut.pvBuffer)
480 FreeContextBuffer(secTokOut.pvBuffer);
482 if (code != CM_ERROR_GSSCONTINUE) {
483 DeleteSecurityContext(&ctx);
484 FreeCredentialsHandle(&creds);
492 #define P_RESP_LEN 128
494 /* LsaLogonUser expects input parameters to be in a contiguous block of memory.
495 So put stuff in a struct. */
496 struct Lm20AuthBlob {
497 MSV1_0_LM20_LOGON lmlogon;
498 BYTE ciResponse[P_RESP_LEN]; /* Unicode representation */
499 BYTE csResponse[P_RESP_LEN]; /* ANSI representation */
500 WCHAR accountNameW[P_LEN];
501 WCHAR primaryDomainW[P_LEN];
502 WCHAR workstationW[MAX_COMPUTERNAME_LENGTH + 1];
503 TOKEN_GROUPS tgroups;
504 TOKEN_SOURCE tsource;
507 long smb_AuthenticateUserLM(smb_vc_t *vcp, char * accountName, char * primaryDomain, char * ciPwd, unsigned ciPwdLength, char * csPwd, unsigned csPwdLength)
510 struct Lm20AuthBlob lmAuth;
511 PMSV1_0_LM20_LOGON_PROFILE lmprofilep;
512 QUOTA_LIMITS quotaLimits;
514 ULONG lmprofilepSize;
518 OutputDebugF("In smb_AuthenticateUser for user [%s] domain [%s]", accountName, primaryDomain);
519 OutputDebugF("ciPwdLength is %d and csPwdLength is %d", ciPwdLength, csPwdLength);
521 if (ciPwdLength > P_RESP_LEN || csPwdLength > P_RESP_LEN) {
522 OutputDebugF("ciPwdLength or csPwdLength is too long");
523 return CM_ERROR_BADPASSWORD;
526 memset(&lmAuth,0,sizeof(lmAuth));
528 lmAuth.lmlogon.MessageType = MsV1_0NetworkLogon;
530 lmAuth.lmlogon.LogonDomainName.Buffer = lmAuth.primaryDomainW;
531 mbstowcs(lmAuth.primaryDomainW, primaryDomain, P_LEN);
532 lmAuth.lmlogon.LogonDomainName.Length = (USHORT)(wcslen(lmAuth.primaryDomainW) * sizeof(WCHAR));
533 lmAuth.lmlogon.LogonDomainName.MaximumLength = P_LEN * sizeof(WCHAR);
535 lmAuth.lmlogon.UserName.Buffer = lmAuth.accountNameW;
536 mbstowcs(lmAuth.accountNameW, accountName, P_LEN);
537 lmAuth.lmlogon.UserName.Length = (USHORT)(wcslen(lmAuth.accountNameW) * sizeof(WCHAR));
538 lmAuth.lmlogon.UserName.MaximumLength = P_LEN * sizeof(WCHAR);
540 lmAuth.lmlogon.Workstation.Buffer = lmAuth.workstationW;
541 lmAuth.lmlogon.Workstation.MaximumLength = (MAX_COMPUTERNAME_LENGTH + 1) * sizeof(WCHAR);
542 size = MAX_COMPUTERNAME_LENGTH + 1;
543 GetComputerNameW(lmAuth.workstationW, &size);
544 lmAuth.lmlogon.Workstation.Length = (USHORT)(wcslen(lmAuth.workstationW) * sizeof(WCHAR));
546 memcpy(lmAuth.lmlogon.ChallengeToClient, vcp->encKey, MSV1_0_CHALLENGE_LENGTH);
548 lmAuth.lmlogon.CaseInsensitiveChallengeResponse.Buffer = lmAuth.ciResponse;
549 lmAuth.lmlogon.CaseInsensitiveChallengeResponse.Length = ciPwdLength;
550 lmAuth.lmlogon.CaseInsensitiveChallengeResponse.MaximumLength = P_RESP_LEN;
551 memcpy(lmAuth.ciResponse, ciPwd, ciPwdLength);
553 lmAuth.lmlogon.CaseSensitiveChallengeResponse.Buffer = lmAuth.csResponse;
554 lmAuth.lmlogon.CaseSensitiveChallengeResponse.Length = csPwdLength;
555 lmAuth.lmlogon.CaseSensitiveChallengeResponse.MaximumLength = P_RESP_LEN;
556 memcpy(lmAuth.csResponse, csPwd, csPwdLength);
558 lmAuth.lmlogon.ParameterControl = 0;
560 lmAuth.tgroups.GroupCount = 0;
561 lmAuth.tgroups.Groups[0].Sid = NULL;
562 lmAuth.tgroups.Groups[0].Attributes = 0;
564 lmAuth.tsource.SourceIdentifier.HighPart = (DWORD)((LONG_PTR)vcp << 32);
565 lmAuth.tsource.SourceIdentifier.LowPart = (DWORD)((LONG_PTR)vcp & _UI32_MAX);
566 strcpy(lmAuth.tsource.SourceName,"OpenAFS"); /* 8 char limit */
568 nts = LsaLogonUser( smb_lsaHandle,
583 if (nts != STATUS_SUCCESS || ntsEx != STATUS_SUCCESS)
584 osi_Log2(smb_logp,"LsaLogonUser failure: nts %u ntsEx %u",
587 OutputDebugF("Return from LsaLogonUser is 0x%lX", nts);
588 OutputDebugF("Extended status is 0x%lX", ntsEx);
590 if (nts == ERROR_SUCCESS) {
592 LsaFreeReturnBuffer(lmprofilep);
593 CloseHandle(lmToken);
597 if (nts == 0xC000015BL)
598 return CM_ERROR_BADLOGONTYPE;
599 else /* our catchall is a bad password though we could be more specific */
600 return CM_ERROR_BADPASSWORD;
604 /* The buffer pointed to by usern is assumed to be at least SMB_MAX_USERNAME_LENGTH bytes */
605 long smb_GetNormalizedUsername(char * usern, const char * accountName, const char * domainName)
610 /* check if we have sane input */
611 if ((strlen(accountName) + strlen(domainName) + 1) > SMB_MAX_USERNAME_LENGTH)
614 /* we could get : [accountName][domainName]
620 atsign = strchr(accountName, '@');
622 if (atsign) /* [user@domain][] -> [user@domain][domain] */
627 /* if for some reason the client doesn't know what domain to use,
628 it will either return an empty string or a '?' */
629 if (!domain[0] || domain[0] == '?')
630 /* Empty domains and empty usernames are usually sent from tokenless contexts.
631 This way such logins will get an empty username (easy to check). I don't know
632 when a non-empty username would be supplied with an anonymous domain, but *shrug* */
633 strcpy(usern,accountName);
635 /* TODO: what about WIN.MIT.EDU\user vs. WIN\user? */
636 strcpy(usern,domain);
639 strncat(usern,accountName,atsign - accountName);
641 strcat(usern,accountName);
649 /* When using SMB auth, all SMB sessions have to pass through here
650 * first to authenticate the user.
652 * Caveat: If not using SMB auth, the protocol does not require
653 * sending a session setup packet, which means that we can't rely on a
654 * UID in subsequent packets. Though in practice we get one anyway.
656 long smb_ReceiveV3SessionSetupX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
660 unsigned short newUid;
661 unsigned long caps = 0;
665 char usern[SMB_MAX_USERNAME_LENGTH];
666 char *secBlobOut = NULL;
667 int secBlobOutLength = 0;
669 /* Check for bad conns */
670 if (vcp->flags & SMB_VCFLAG_REMOTECONN)
671 return CM_ERROR_REMOTECONN;
673 if (vcp->flags & SMB_VCFLAG_USENT) {
674 if (smb_authType == SMB_AUTH_EXTENDED) {
675 /* extended authentication */
679 OutputDebugF("NT Session Setup: Extended");
681 if (!(vcp->flags & SMB_VCFLAG_SESSX_RCVD)) {
682 caps = smb_GetSMBParm(inp,10) | (((unsigned long) smb_GetSMBParm(inp,11)) << 16);
685 secBlobInLength = smb_GetSMBParm(inp, 7);
686 secBlobIn = smb_GetSMBData(inp, NULL);
688 code = smb_AuthenticateUserExt(vcp, usern, secBlobIn, secBlobInLength, &secBlobOut, &secBlobOutLength);
690 if (code == CM_ERROR_GSSCONTINUE) {
691 smb_SetSMBParm(outp, 2, 0);
692 smb_SetSMBParm(outp, 3, secBlobOutLength);
693 smb_SetSMBDataLength(outp, secBlobOutLength + smb_ServerOSLength + smb_ServerLanManagerLength + smb_ServerDomainNameLength);
694 tp = smb_GetSMBData(outp, NULL);
695 if (secBlobOutLength) {
696 memcpy(tp, secBlobOut, secBlobOutLength);
698 tp += secBlobOutLength;
700 memcpy(tp,smb_ServerOS,smb_ServerOSLength);
701 tp += smb_ServerOSLength;
702 memcpy(tp,smb_ServerLanManager,smb_ServerLanManagerLength);
703 tp += smb_ServerLanManagerLength;
704 memcpy(tp,smb_ServerDomainName,smb_ServerDomainNameLength);
705 tp += smb_ServerDomainNameLength;
708 /* TODO: handle return code and continue auth. Also free secBlobOut if applicable. */
710 unsigned ciPwdLength, csPwdLength;
716 if (smb_authType == SMB_AUTH_NTLM)
717 OutputDebugF("NT Session Setup: NTLM");
719 OutputDebugF("NT Session Setup: None");
721 /* TODO: parse for extended auth as well */
722 ciPwdLength = smb_GetSMBParm(inp, 7); /* case insensitive password length */
723 csPwdLength = smb_GetSMBParm(inp, 8); /* case sensitive password length */
725 tp = smb_GetSMBData(inp, &datalen);
727 OutputDebugF("Session packet data size [%d]",datalen);
734 accountName = smb_ParseString(tp, &tp);
735 primaryDomain = smb_ParseString(tp, NULL);
737 OutputDebugF("Account Name: %s",accountName);
738 OutputDebugF("Primary Domain: %s", primaryDomain);
739 OutputDebugF("Case Sensitive Password: %s", csPwd && csPwd[0] ? "yes" : "no");
740 OutputDebugF("Case Insensitive Password: %s", ciPwd && ciPwd[0] ? "yes" : "no");
742 if (smb_GetNormalizedUsername(usern, accountName, primaryDomain)) {
743 /* shouldn't happen */
744 code = CM_ERROR_BADSMB;
745 goto after_read_packet;
748 /* capabilities are only valid for first session packet */
749 if (!(vcp->flags & SMB_VCFLAG_SESSX_RCVD)) {
750 caps = smb_GetSMBParm(inp, 11) | (((unsigned long)smb_GetSMBParm(inp, 12)) << 16);
753 if (smb_authType == SMB_AUTH_NTLM) {
754 code = smb_AuthenticateUserLM(vcp, accountName, primaryDomain, ciPwd, ciPwdLength, csPwd, csPwdLength);
756 OutputDebugF("LM authentication failed [%d]", code);
758 OutputDebugF("LM authentication succeeded");
762 unsigned ciPwdLength;
767 switch ( smb_authType ) {
768 case SMB_AUTH_EXTENDED:
769 OutputDebugF("V3 Session Setup: Extended");
772 OutputDebugF("V3 Session Setup: NTLM");
775 OutputDebugF("V3 Session Setup: None");
777 ciPwdLength = smb_GetSMBParm(inp, 7);
778 tp = smb_GetSMBData(inp, NULL);
782 accountName = smb_ParseString(tp, &tp);
783 primaryDomain = smb_ParseString(tp, NULL);
785 OutputDebugF("Account Name: %s",accountName);
786 OutputDebugF("Primary Domain: %s", primaryDomain);
787 OutputDebugF("Case Insensitive Password: %s", ciPwd && ciPwd[0] ? "yes" : "no");
789 if ( smb_GetNormalizedUsername(usern, accountName, primaryDomain)) {
790 /* shouldn't happen */
791 code = CM_ERROR_BADSMB;
792 goto after_read_packet;
795 /* even if we wanted extended auth, if we only negotiated V3, we have to fallback
798 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
799 code = smb_AuthenticateUserLM(vcp,accountName,primaryDomain,ciPwd,ciPwdLength,"",0);
801 OutputDebugF("LM authentication failed [%d]", code);
803 OutputDebugF("LM authentication succeeded");
808 /* note down that we received a session setup X and set the capabilities flag */
809 if (!(vcp->flags & SMB_VCFLAG_SESSX_RCVD)) {
810 lock_ObtainMutex(&vcp->mx);
811 vcp->flags |= SMB_VCFLAG_SESSX_RCVD;
812 /* for the moment we can only deal with NTSTATUS */
813 if (caps & NTNEGOTIATE_CAPABILITY_NTSTATUS) {
814 vcp->flags |= SMB_VCFLAG_STATUS32;
816 lock_ReleaseMutex(&vcp->mx);
819 /* code would be non-zero if there was an authentication failure.
820 Ideally we would like to invalidate the uid for this session or break
821 early to avoid accidently stealing someone else's tokens. */
827 OutputDebugF("Received username=[%s]", usern);
829 /* On Windows 2000, this function appears to be called more often than
830 it is expected to be called. This resulted in multiple smb_user_t
831 records existing all for the same user session which results in all
832 of the users tokens disappearing.
834 To avoid this problem, we look for an existing smb_user_t record
835 based on the users name, and use that one if we find it.
838 uidp = smb_FindUserByNameThisSession(vcp, usern);
839 if (uidp) { /* already there, so don't create a new one */
841 newUid = uidp->userID;
842 osi_Log3(smb_logp,"smb_ReceiveV3SessionSetupX FindUserByName:Lana[%d],lsn[%d],userid[%d]",
843 vcp->lana,vcp->lsn,newUid);
844 smb_ReleaseUID(uidp);
849 /* do a global search for the username/machine name pair */
850 unp = smb_FindUserByName(usern, vcp->rname, SMB_FLAG_CREATE);
851 lock_ObtainMutex(&unp->mx);
852 if (unp->flags & SMB_USERNAMEFLAG_AFSLOGON) {
853 /* clear the afslogon flag so that the tickets can now
854 * be freed when the refCount returns to zero.
856 unp->flags &= ~SMB_USERNAMEFLAG_AFSLOGON;
858 lock_ReleaseMutex(&unp->mx);
860 /* Create a new UID and cm_user_t structure */
863 userp = cm_NewUser();
864 cm_HoldUserVCRef(userp);
865 lock_ObtainMutex(&vcp->mx);
866 if (!vcp->uidCounter)
867 vcp->uidCounter++; /* handle unlikely wraparounds */
868 newUid = (strlen(usern)==0)?0:vcp->uidCounter++;
869 lock_ReleaseMutex(&vcp->mx);
871 /* Create a new smb_user_t structure and connect them up */
872 lock_ObtainMutex(&unp->mx);
874 lock_ReleaseMutex(&unp->mx);
876 uidp = smb_FindUID(vcp, newUid, SMB_FLAG_CREATE);
878 lock_ObtainMutex(&uidp->mx);
880 osi_Log4(smb_logp,"smb_ReceiveV3SessionSetupX MakeNewUser:VCP[%p],Lana[%d],lsn[%d],userid[%d]",vcp,vcp->lana,vcp->lsn,newUid);
881 lock_ReleaseMutex(&uidp->mx);
882 smb_ReleaseUID(uidp);
886 /* Return UID to the client */
887 ((smb_t *)outp)->uid = newUid;
888 /* Also to the next chained message */
889 ((smb_t *)inp)->uid = newUid;
891 osi_Log3(smb_logp, "SMB3 session setup name %s creating ID %d%s",
892 osi_LogSaveString(smb_logp, usern), newUid, osi_LogSaveString(smb_logp, s1));
894 smb_SetSMBParm(outp, 2, 0);
896 if (vcp->flags & SMB_VCFLAG_USENT) {
897 if (smb_authType == SMB_AUTH_EXTENDED) {
898 smb_SetSMBParm(outp, 3, secBlobOutLength);
899 smb_SetSMBDataLength(outp, secBlobOutLength + smb_ServerOSLength + smb_ServerLanManagerLength + smb_ServerDomainNameLength);
900 tp = smb_GetSMBData(outp, NULL);
901 if (secBlobOutLength) {
902 memcpy(tp, secBlobOut, secBlobOutLength);
904 tp += secBlobOutLength;
906 memcpy(tp,smb_ServerOS,smb_ServerOSLength);
907 tp += smb_ServerOSLength;
908 memcpy(tp,smb_ServerLanManager,smb_ServerLanManagerLength);
909 tp += smb_ServerLanManagerLength;
910 memcpy(tp,smb_ServerDomainName,smb_ServerDomainNameLength);
911 tp += smb_ServerDomainNameLength;
913 smb_SetSMBDataLength(outp, 0);
916 if (smb_authType == SMB_AUTH_EXTENDED) {
917 smb_SetSMBDataLength(outp, smb_ServerOSLength + smb_ServerLanManagerLength + smb_ServerDomainNameLength);
918 tp = smb_GetSMBData(outp, NULL);
919 memcpy(tp,smb_ServerOS,smb_ServerOSLength);
920 tp += smb_ServerOSLength;
921 memcpy(tp,smb_ServerLanManager,smb_ServerLanManagerLength);
922 tp += smb_ServerLanManagerLength;
923 memcpy(tp,smb_ServerDomainName,smb_ServerDomainNameLength);
924 tp += smb_ServerDomainNameLength;
926 smb_SetSMBDataLength(outp, 0);
933 long smb_ReceiveV3UserLogoffX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
937 /* find the tree and free it */
938 uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
940 smb_username_t * unp;
942 osi_Log2(smb_logp, "SMB3 user logoffX uid %d name %s", uidp->userID,
943 osi_LogSaveString(smb_logp, (uidp->unp) ? uidp->unp->name: " "));
945 lock_ObtainMutex(&uidp->mx);
946 uidp->flags |= SMB_USERFLAG_DELETE;
948 * it doesn't get deleted right away
949 * because the vcp points to it
952 lock_ReleaseMutex(&uidp->mx);
955 /* we can't do this. we get logoff messages prior to a session
956 * disconnect even though it doesn't mean the user is logging out.
957 * we need to create a new pioctl and EventLogoff handler to set
958 * SMB_USERNAMEFLAG_LOGOFF.
960 if (unp && smb_LogoffTokenTransfer) {
961 lock_ObtainMutex(&unp->mx);
962 unp->flags |= SMB_USERNAMEFLAG_LOGOFF;
963 unp->last_logoff_t = osi_Time() + smb_LogoffTransferTimeout;
964 lock_ReleaseMutex(&unp->mx);
968 smb_ReleaseUID(uidp);
971 osi_Log0(smb_logp, "SMB3 user logoffX");
973 smb_SetSMBDataLength(outp, 0);
977 #define SMB_SUPPORT_SEARCH_BITS 0x0001
978 #define SMB_SHARE_IS_IN_DFS 0x0002
980 long smb_ReceiveV3TreeConnectX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
983 smb_user_t *uidp = NULL;
984 unsigned short newTid;
992 cm_user_t *userp = NULL;
995 osi_Log0(smb_logp, "SMB3 receive tree connect");
997 /* parse input parameters */
998 tp = smb_GetSMBData(inp, NULL);
999 passwordp = smb_ParseString(tp, &tp);
1000 pathp = smb_ParseString(tp, &tp);
1001 if (smb_StoreAnsiFilenames)
1002 OemToChar(pathp,pathp);
1003 servicep = smb_ParseString(tp, &tp);
1005 tp = strrchr(pathp, '\\');
1007 return CM_ERROR_BADSMB;
1009 strcpy(shareName, tp+1);
1011 osi_Log2(smb_logp, "Tree connect pathp[%s] shareName[%s]",
1012 osi_LogSaveString(smb_logp, pathp),
1013 osi_LogSaveString(smb_logp, shareName));
1015 if (strcmp(servicep, "IPC") == 0 || strcmp(shareName, "IPC$") == 0) {
1017 osi_Log0(smb_logp, "TreeConnectX connecting to IPC$");
1020 return CM_ERROR_NOIPC;
1024 uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
1026 userp = smb_GetUserFromUID(uidp);
1028 lock_ObtainMutex(&vcp->mx);
1029 newTid = vcp->tidCounter++;
1030 lock_ReleaseMutex(&vcp->mx);
1032 tidp = smb_FindTID(vcp, newTid, SMB_FLAG_CREATE);
1035 if (!strcmp(shareName, "*."))
1036 strcpy(shareName, "all");
1037 shareFound = smb_FindShare(vcp, uidp, shareName, &sharePath);
1040 smb_ReleaseUID(uidp);
1041 smb_ReleaseTID(tidp);
1042 return CM_ERROR_BADSHARENAME;
1045 if (vcp->flags & SMB_VCFLAG_USENT)
1047 int policy = smb_FindShareCSCPolicy(shareName);
1048 smb_SetSMBParm(outp, 2, SMB_SUPPORT_SEARCH_BITS |
1050 SMB_SHARE_IS_IN_DFS |
1055 smb_SetSMBParm(outp, 2, 0);
1059 smb_ReleaseUID(uidp);
1061 lock_ObtainMutex(&tidp->mx);
1062 tidp->userp = userp;
1063 tidp->pathname = sharePath;
1065 tidp->flags |= SMB_TIDFLAG_IPC;
1066 lock_ReleaseMutex(&tidp->mx);
1067 smb_ReleaseTID(tidp);
1069 ((smb_t *)outp)->tid = newTid;
1070 ((smb_t *)inp)->tid = newTid;
1071 tp = smb_GetSMBData(outp, NULL);
1073 /* XXX - why is this a drive letter? */
1081 smb_SetSMBDataLength(outp, 7);
1084 smb_SetSMBDataLength(outp, 4);
1087 osi_Log1(smb_logp, "SMB3 tree connect created ID %d", newTid);
1091 /* must be called with global tran lock held */
1092 smb_tran2Packet_t *smb_FindTran2Packet(smb_vc_t *vcp, smb_packet_t *inp)
1094 smb_tran2Packet_t *tp;
1097 smbp = (smb_t *) inp->data;
1098 for (tp = smb_tran2AssemblyQueuep; tp; tp = (smb_tran2Packet_t *) osi_QNext(&tp->q)) {
1099 if (tp->vcp == vcp && tp->mid == smbp->mid && tp->tid == smbp->tid)
1105 smb_tran2Packet_t *smb_NewTran2Packet(smb_vc_t *vcp, smb_packet_t *inp,
1106 int totalParms, int totalData)
1108 smb_tran2Packet_t *tp;
1111 smbp = (smb_t *) inp->data;
1112 tp = malloc(sizeof(*tp));
1113 memset(tp, 0, sizeof(*tp));
1116 tp->curData = tp->curParms = 0;
1117 tp->totalData = totalData;
1118 tp->totalParms = totalParms;
1119 tp->tid = smbp->tid;
1120 tp->mid = smbp->mid;
1121 tp->uid = smbp->uid;
1122 tp->pid = smbp->pid;
1123 tp->res[0] = smbp->res[0];
1124 osi_QAdd((osi_queue_t **)&smb_tran2AssemblyQueuep, &tp->q);
1125 if (totalParms != 0)
1126 tp->parmsp = malloc(totalParms);
1128 tp->datap = malloc(totalData);
1129 if (smbp->com == 0x25 || smbp->com == 0x26)
1132 tp->opcode = smb_GetSMBParm(inp, 14);
1135 tp->flags |= SMB_TRAN2PFLAG_ALLOC;
1139 smb_tran2Packet_t *smb_GetTran2ResponsePacket(smb_vc_t *vcp,
1140 smb_tran2Packet_t *inp, smb_packet_t *outp,
1141 int totalParms, int totalData)
1143 smb_tran2Packet_t *tp;
1144 unsigned short parmOffset;
1145 unsigned short dataOffset;
1146 unsigned short dataAlign;
1148 tp = malloc(sizeof(*tp));
1149 memset(tp, 0, sizeof(*tp));
1152 tp->curData = tp->curParms = 0;
1153 tp->totalData = totalData;
1154 tp->totalParms = totalParms;
1155 tp->oldTotalParms = totalParms;
1160 tp->res[0] = inp->res[0];
1161 tp->opcode = inp->opcode;
1165 * We calculate where the parameters and data will start.
1166 * This calculation must parallel the calculation in
1167 * smb_SendTran2Packet.
1170 parmOffset = 10*2 + 35;
1171 parmOffset++; /* round to even */
1172 tp->parmsp = (unsigned short *) (outp->data + parmOffset);
1174 dataOffset = parmOffset + totalParms;
1175 dataAlign = dataOffset & 2; /* quad-align */
1176 dataOffset += dataAlign;
1177 tp->datap = outp->data + dataOffset;
1182 /* free a tran2 packet */
1183 void smb_FreeTran2Packet(smb_tran2Packet_t *t2p)
1186 smb_ReleaseVC(t2p->vcp);
1189 if (t2p->flags & SMB_TRAN2PFLAG_ALLOC) {
1198 /* called with a VC, an input packet to respond to, and an error code.
1199 * sends an error response.
1201 void smb_SendTran2Error(smb_vc_t *vcp, smb_tran2Packet_t *t2p,
1202 smb_packet_t *tp, long code)
1205 unsigned short errCode;
1206 unsigned char errClass;
1207 unsigned long NTStatus;
1209 if (vcp->flags & SMB_VCFLAG_STATUS32)
1210 smb_MapNTError(code, &NTStatus);
1212 smb_MapCoreError(code, vcp, &errCode, &errClass);
1214 smb_FormatResponsePacket(vcp, NULL, tp);
1215 smbp = (smb_t *) tp;
1217 /* We can handle long names */
1218 if (vcp->flags & SMB_VCFLAG_USENT)
1219 smbp->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
1221 /* now copy important fields from the tran 2 packet */
1222 smbp->com = t2p->com;
1223 smbp->tid = t2p->tid;
1224 smbp->mid = t2p->mid;
1225 smbp->pid = t2p->pid;
1226 smbp->uid = t2p->uid;
1227 smbp->res[0] = t2p->res[0];
1228 if (vcp->flags & SMB_VCFLAG_STATUS32) {
1229 smbp->rcls = (unsigned char) (NTStatus & 0xff);
1230 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
1231 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
1232 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
1233 smbp->flg2 |= SMB_FLAGS2_32BIT_STATUS;
1236 smbp->rcls = errClass;
1237 smbp->errLow = (unsigned char) (errCode & 0xff);
1238 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
1242 smb_SendPacket(vcp, tp);
1245 void smb_SendTran2Packet(smb_vc_t *vcp, smb_tran2Packet_t *t2p, smb_packet_t *tp)
1248 unsigned short parmOffset;
1249 unsigned short dataOffset;
1250 unsigned short totalLength;
1251 unsigned short dataAlign;
1254 smb_FormatResponsePacket(vcp, NULL, tp);
1255 smbp = (smb_t *) tp;
1257 /* We can handle long names */
1258 if (vcp->flags & SMB_VCFLAG_USENT)
1259 smbp->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
1261 /* now copy important fields from the tran 2 packet */
1262 smbp->com = t2p->com;
1263 smbp->tid = t2p->tid;
1264 smbp->mid = t2p->mid;
1265 smbp->pid = t2p->pid;
1266 smbp->uid = t2p->uid;
1267 smbp->res[0] = t2p->res[0];
1269 totalLength = 1 + t2p->totalData + t2p->totalParms;
1271 /* now add the core parameters (tran2 info) to the packet */
1272 smb_SetSMBParm(tp, 0, t2p->totalParms); /* parm bytes */
1273 smb_SetSMBParm(tp, 1, t2p->totalData); /* data bytes */
1274 smb_SetSMBParm(tp, 2, 0); /* reserved */
1275 smb_SetSMBParm(tp, 3, t2p->totalParms); /* parm bytes in this packet */
1276 parmOffset = 10*2 + 35; /* parm offset in packet */
1277 parmOffset++; /* round to even */
1278 smb_SetSMBParm(tp, 4, parmOffset); /* 11 parm words plus *
1279 * hdr, bcc and wct */
1280 smb_SetSMBParm(tp, 5, 0); /* parm displacement */
1281 smb_SetSMBParm(tp, 6, t2p->totalData); /* data in this packet */
1282 dataOffset = parmOffset + t2p->oldTotalParms;
1283 dataAlign = dataOffset & 2; /* quad-align */
1284 dataOffset += dataAlign;
1285 smb_SetSMBParm(tp, 7, dataOffset); /* offset of data */
1286 smb_SetSMBParm(tp, 8, 0); /* data displacement */
1287 smb_SetSMBParm(tp, 9, 0); /* low: setup word count *
1290 datap = smb_GetSMBData(tp, NULL);
1291 *datap++ = 0; /* we rounded to even */
1293 totalLength += dataAlign;
1294 smb_SetSMBDataLength(tp, totalLength);
1296 /* next, send the datagram */
1297 smb_SendPacket(vcp, tp);
1300 long smb_ReceiveV3Trans(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
1302 smb_tran2Packet_t *asp;
1315 /* We sometimes see 0 word count. What to do? */
1316 if (*inp->wctp == 0) {
1317 osi_Log0(smb_logp, "Transaction2 word count = 0");
1318 LogEvent(EVENTLOG_WARNING_TYPE, MSG_SMB_ZERO_TRANSACTION_COUNT);
1320 smb_SetSMBDataLength(outp, 0);
1321 smb_SendPacket(vcp, outp);
1325 totalParms = smb_GetSMBParm(inp, 0);
1326 totalData = smb_GetSMBParm(inp, 1);
1328 firstPacket = (inp->inCom == 0x25);
1330 /* find the packet we're reassembling */
1331 lock_ObtainWrite(&smb_globalLock);
1332 asp = smb_FindTran2Packet(vcp, inp);
1334 asp = smb_NewTran2Packet(vcp, inp, totalParms, totalData);
1336 lock_ReleaseWrite(&smb_globalLock);
1338 /* now merge in this latest packet; start by looking up offsets */
1340 parmDisp = dataDisp = 0;
1341 parmOffset = smb_GetSMBParm(inp, 10);
1342 dataOffset = smb_GetSMBParm(inp, 12);
1343 parmCount = smb_GetSMBParm(inp, 9);
1344 dataCount = smb_GetSMBParm(inp, 11);
1345 asp->maxReturnParms = smb_GetSMBParm(inp, 2);
1346 asp->maxReturnData = smb_GetSMBParm(inp, 3);
1348 osi_Log3(smb_logp, "SMB3 received Trans init packet total data %d, cur data %d, max return data %d",
1349 totalData, dataCount, asp->maxReturnData);
1352 parmDisp = smb_GetSMBParm(inp, 4);
1353 parmOffset = smb_GetSMBParm(inp, 3);
1354 dataDisp = smb_GetSMBParm(inp, 7);
1355 dataOffset = smb_GetSMBParm(inp, 6);
1356 parmCount = smb_GetSMBParm(inp, 2);
1357 dataCount = smb_GetSMBParm(inp, 5);
1359 osi_Log2(smb_logp, "SMB3 received Trans aux packet parms %d, data %d",
1360 parmCount, dataCount);
1363 /* now copy the parms and data */
1364 if ( asp->totalParms > 0 && parmCount != 0 )
1366 memcpy(((char *)asp->parmsp) + parmDisp, inp->data + parmOffset, parmCount);
1368 if ( asp->totalData > 0 && dataCount != 0 ) {
1369 memcpy(asp->datap + dataDisp, inp->data + dataOffset, dataCount);
1372 /* account for new bytes */
1373 asp->curData += dataCount;
1374 asp->curParms += parmCount;
1376 /* finally, if we're done, remove the packet from the queue and dispatch it */
1377 if (asp->totalParms > 0 &&
1378 asp->curParms > 0 &&
1379 asp->totalData <= asp->curData &&
1380 asp->totalParms <= asp->curParms) {
1381 /* we've received it all */
1382 lock_ObtainWrite(&smb_globalLock);
1383 osi_QRemove((osi_queue_t **) &smb_tran2AssemblyQueuep, &asp->q);
1384 lock_ReleaseWrite(&smb_globalLock);
1386 /* now dispatch it */
1387 rapOp = asp->parmsp[0];
1389 if ( rapOp >= 0 && rapOp < SMB_RAP_NOPCODES && smb_rapDispatchTable[rapOp].procp) {
1390 osi_Log4(smb_logp,"AFS Server - Dispatch-RAP %s vcp[%p] lana[%d] lsn[%d]",myCrt_RapDispatch(rapOp),vcp,vcp->lana,vcp->lsn);
1391 code = (*smb_rapDispatchTable[rapOp].procp)(vcp, asp, outp);
1392 osi_Log4(smb_logp,"AFS Server - Dispatch-RAP return code 0x%x vcp[%x] lana[%d] lsn[%d]",code,vcp,vcp->lana,vcp->lsn);
1395 osi_Log4(smb_logp,"AFS Server - Dispatch-RAP [INVALID] op[%x] vcp[%p] lana[%d] lsn[%d]", rapOp, vcp, vcp->lana, vcp->lsn);
1396 code = CM_ERROR_BADOP;
1399 /* if an error is returned, we're supposed to send an error packet,
1400 * otherwise the dispatched function already did the data sending.
1401 * We give dispatched proc the responsibility since it knows how much
1402 * space to allocate.
1405 smb_SendTran2Error(vcp, asp, outp, code);
1408 /* free the input tran 2 packet */
1409 smb_FreeTran2Packet(asp);
1411 else if (firstPacket) {
1412 /* the first packet in a multi-packet request, we need to send an
1413 * ack to get more data.
1415 smb_SetSMBDataLength(outp, 0);
1416 smb_SendPacket(vcp, outp);
1422 /* ANSI versions. The unicode versions support arbitrary length
1423 share names, but we don't support unicode yet. */
1425 typedef struct smb_rap_share_info_0 {
1426 char shi0_netname[13];
1427 } smb_rap_share_info_0_t;
1429 typedef struct smb_rap_share_info_1 {
1430 char shi1_netname[13];
1433 DWORD shi1_remark; /* char *shi1_remark; data offset */
1434 } smb_rap_share_info_1_t;
1436 typedef struct smb_rap_share_info_2 {
1437 char shi2_netname[13];
1439 unsigned short shi2_type;
1440 DWORD shi2_remark; /* char *shi2_remark; data offset */
1441 unsigned short shi2_permissions;
1442 unsigned short shi2_max_uses;
1443 unsigned short shi2_current_uses;
1444 DWORD shi2_path; /* char *shi2_path; data offset */
1445 unsigned short shi2_passwd[9];
1446 unsigned short shi2_pad2;
1447 } smb_rap_share_info_2_t;
1449 #define SMB_RAP_MAX_SHARES 512
1451 typedef struct smb_rap_share_list {
1454 smb_rap_share_info_0_t * shares;
1455 } smb_rap_share_list_t;
1457 int smb_rapCollectSharesProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp) {
1458 smb_rap_share_list_t * sp;
1463 if (name[0] == '.' && (!name[1] || (name[1] == '.' && !name[2])))
1464 return 0; /* skip over '.' and '..' */
1466 sp = (smb_rap_share_list_t *) vrockp;
1468 strncpy(sp->shares[sp->cShare].shi0_netname, name, 12);
1469 sp->shares[sp->cShare].shi0_netname[12] = 0;
1473 if (sp->cShare >= sp->maxShares)
1474 return CM_ERROR_STOPNOW;
1479 long smb_ReceiveRAPNetShareEnum(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1481 smb_tran2Packet_t *outp;
1482 unsigned short * tp;
1486 int outParmsTotal; /* total parameter bytes */
1487 int outDataTotal; /* total data bytes */
1490 DWORD allSubmount = 0;
1492 DWORD nRegShares = 0;
1493 DWORD nSharesRet = 0;
1495 HKEY hkSubmount = NULL;
1496 smb_rap_share_info_1_t * shares;
1499 char thisShare[256];
1502 smb_rap_share_list_t rootShares;
1507 tp = p->parmsp + 1; /* skip over function number (always 0) */
1508 (void) smb_ParseString((char *) tp, (char **) &tp); /* skip over parm descriptor */
1509 (void) smb_ParseString((char *) tp, (char **) &tp); /* skip over data descriptor */
1513 if (infoLevel != 1) {
1514 return CM_ERROR_INVAL;
1517 /* first figure out how many shares there are */
1518 rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY, 0,
1519 KEY_QUERY_VALUE, &hkParam);
1520 if (rv == ERROR_SUCCESS) {
1521 len = sizeof(allSubmount);
1522 rv = RegQueryValueEx(hkParam, "AllSubmount", NULL, NULL,
1523 (BYTE *) &allSubmount, &len);
1524 if (rv != ERROR_SUCCESS || allSubmount != 0) {
1527 RegCloseKey (hkParam);
1530 rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_OPENAFS_SUBKEY "\\Submounts",
1531 0, KEY_QUERY_VALUE, &hkSubmount);
1532 if (rv == ERROR_SUCCESS) {
1533 rv = RegQueryInfoKey(hkSubmount, NULL, NULL, NULL, NULL,
1534 NULL, NULL, &nRegShares, NULL, NULL, NULL, NULL);
1535 if (rv != ERROR_SUCCESS)
1541 /* fetch the root shares */
1542 rootShares.maxShares = SMB_RAP_MAX_SHARES;
1543 rootShares.cShare = 0;
1544 rootShares.shares = malloc( sizeof(smb_rap_share_info_0_t) * SMB_RAP_MAX_SHARES );
1548 userp = smb_GetTran2User(vcp,p);
1550 thyper.HighPart = 0;
1553 cm_HoldSCache(cm_data.rootSCachep);
1554 cm_ApplyDir(cm_data.rootSCachep, smb_rapCollectSharesProc, &rootShares, &thyper, userp, &req, NULL);
1555 cm_ReleaseSCache(cm_data.rootSCachep);
1557 cm_ReleaseUser(userp);
1559 nShares = (USHORT)(rootShares.cShare + nRegShares + allSubmount);
1561 #define REMARK_LEN 1
1562 outParmsTotal = 8; /* 4 dwords */
1563 outDataTotal = (sizeof(smb_rap_share_info_1_t) + REMARK_LEN) * nShares ;
1564 if(outDataTotal > bufsize) {
1565 nSharesRet = bufsize / (sizeof(smb_rap_share_info_1_t) + REMARK_LEN);
1566 outDataTotal = (sizeof(smb_rap_share_info_1_t) + REMARK_LEN) * nSharesRet;
1569 nSharesRet = nShares;
1572 outp = smb_GetTran2ResponsePacket(vcp, p, op, outParmsTotal, outDataTotal);
1574 /* now for the submounts */
1575 shares = (smb_rap_share_info_1_t *) outp->datap;
1576 cstrp = outp->datap + sizeof(smb_rap_share_info_1_t) * nSharesRet;
1578 memset(outp->datap, 0, (sizeof(smb_rap_share_info_1_t) + REMARK_LEN) * nSharesRet);
1581 strcpy( shares[cshare].shi1_netname, "all" );
1582 shares[cshare].shi1_remark = (DWORD)(cstrp - outp->datap);
1583 /* type and pad are zero already */
1589 for (i=0; i < nRegShares && cshare < nSharesRet; i++) {
1590 len = sizeof(thisShare);
1591 rv = RegEnumValue(hkSubmount, i, thisShare, &len, NULL, NULL, NULL, NULL);
1592 if (rv == ERROR_SUCCESS && strlen(thisShare) && (!allSubmount || stricmp(thisShare,"all"))) {
1593 strncpy(shares[cshare].shi1_netname, thisShare, sizeof(shares->shi1_netname)-1);
1594 shares[cshare].shi1_netname[sizeof(shares->shi1_netname)-1] = 0; /* unfortunate truncation */
1595 shares[cshare].shi1_remark = (DWORD)(cstrp - outp->datap);
1600 nShares--; /* uncount key */
1603 RegCloseKey(hkSubmount);
1606 nonrootShares = cshare;
1608 for (i=0; i < rootShares.cShare && cshare < nSharesRet; i++) {
1609 /* in case there are collisions with submounts, submounts have higher priority */
1610 for (j=0; j < nonrootShares; j++)
1611 if (!stricmp(shares[j].shi1_netname, rootShares.shares[i].shi0_netname))
1614 if (j < nonrootShares) {
1615 nShares--; /* uncount */
1619 strcpy(shares[cshare].shi1_netname, rootShares.shares[i].shi0_netname);
1620 shares[cshare].shi1_remark = (DWORD)(cstrp - outp->datap);
1625 outp->parmsp[0] = ((cshare == nShares)? ERROR_SUCCESS : ERROR_MORE_DATA);
1626 outp->parmsp[1] = 0;
1627 outp->parmsp[2] = cshare;
1628 outp->parmsp[3] = nShares;
1630 outp->totalData = (int)(cstrp - outp->datap);
1631 outp->totalParms = outParmsTotal;
1633 smb_SendTran2Packet(vcp, outp, op);
1634 smb_FreeTran2Packet(outp);
1636 free(rootShares.shares);
1641 long smb_ReceiveRAPNetShareGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1643 smb_tran2Packet_t *outp;
1644 unsigned short * tp;
1646 BOOL shareFound = FALSE;
1647 unsigned short infoLevel;
1648 unsigned short bufsize;
1658 tp = p->parmsp + 1; /* skip over function number (always 1) */
1659 (void) smb_ParseString( (char *) tp, (char **) &tp); /* skip over param descriptor */
1660 (void) smb_ParseString( (char *) tp, (char **) &tp); /* skip over data descriptor */
1661 shareName = smb_ParseString( (char *) tp, (char **) &tp);
1668 totalData = sizeof(smb_rap_share_info_0_t);
1669 else if(infoLevel == SMB_INFO_STANDARD)
1670 totalData = sizeof(smb_rap_share_info_1_t) + 1; /* + empty string */
1671 else if(infoLevel == SMB_INFO_QUERY_EA_SIZE)
1672 totalData = sizeof(smb_rap_share_info_2_t) + 2; /* + two empty strings */
1674 return CM_ERROR_INVAL;
1676 outp = smb_GetTran2ResponsePacket(vcp, p, op, totalParam, totalData);
1678 if(!stricmp(shareName,"all") || !strcmp(shareName,"*.")) {
1679 rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY, 0,
1680 KEY_QUERY_VALUE, &hkParam);
1681 if (rv == ERROR_SUCCESS) {
1682 len = sizeof(allSubmount);
1683 rv = RegQueryValueEx(hkParam, "AllSubmount", NULL, NULL,
1684 (BYTE *) &allSubmount, &len);
1685 if (rv != ERROR_SUCCESS || allSubmount != 0) {
1688 RegCloseKey (hkParam);
1695 rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY "\\Submounts", 0,
1696 KEY_QUERY_VALUE, &hkSubmount);
1697 if (rv == ERROR_SUCCESS) {
1698 rv = RegQueryValueEx(hkSubmount, shareName, NULL, NULL, NULL, NULL);
1699 if (rv == ERROR_SUCCESS) {
1702 RegCloseKey(hkSubmount);
1707 smb_FreeTran2Packet(outp);
1708 return CM_ERROR_BADSHARENAME;
1711 memset(outp->datap, 0, totalData);
1713 outp->parmsp[0] = 0;
1714 outp->parmsp[1] = 0;
1715 outp->parmsp[2] = totalData;
1717 if (infoLevel == 0) {
1718 smb_rap_share_info_0_t * info = (smb_rap_share_info_0_t *) outp->datap;
1719 strncpy(info->shi0_netname, shareName, sizeof(info->shi0_netname)-1);
1720 info->shi0_netname[sizeof(info->shi0_netname)-1] = 0;
1721 } else if(infoLevel == SMB_INFO_STANDARD) {
1722 smb_rap_share_info_1_t * info = (smb_rap_share_info_1_t *) outp->datap;
1723 strncpy(info->shi1_netname, shareName, sizeof(info->shi1_netname)-1);
1724 info->shi1_netname[sizeof(info->shi1_netname)-1] = 0;
1725 info->shi1_remark = (DWORD)(((unsigned char *) (info + 1)) - outp->datap);
1726 /* type and pad are already zero */
1727 } else { /* infoLevel==2 */
1728 smb_rap_share_info_2_t * info = (smb_rap_share_info_2_t *) outp->datap;
1729 strncpy(info->shi2_netname, shareName, sizeof(info->shi2_netname)-1);
1730 info->shi2_netname[sizeof(info->shi2_netname)-1] = 0;
1731 info->shi2_remark = (DWORD)(((unsigned char *) (info + 1)) - outp->datap);
1732 info->shi2_permissions = ACCESS_ALL;
1733 info->shi2_max_uses = (unsigned short) -1;
1734 info->shi2_path = (DWORD)(1 + (((unsigned char *) (info + 1)) - outp->datap));
1737 outp->totalData = totalData;
1738 outp->totalParms = totalParam;
1740 smb_SendTran2Packet(vcp, outp, op);
1741 smb_FreeTran2Packet(outp);
1746 typedef struct smb_rap_wksta_info_10 {
1747 DWORD wki10_computername; /*char *wki10_computername;*/
1748 DWORD wki10_username; /* char *wki10_username; */
1749 DWORD wki10_langroup; /* char *wki10_langroup;*/
1750 unsigned char wki10_ver_major;
1751 unsigned char wki10_ver_minor;
1752 DWORD wki10_logon_domain; /*char *wki10_logon_domain;*/
1753 DWORD wki10_oth_domains; /* char *wki10_oth_domains;*/
1754 } smb_rap_wksta_info_10_t;
1757 long smb_ReceiveRAPNetWkstaGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1759 smb_tran2Packet_t *outp;
1763 unsigned short * tp;
1766 smb_rap_wksta_info_10_t * info;
1770 tp = p->parmsp + 1; /* Skip over function number */
1771 (void) smb_ParseString((unsigned char*) tp, (char **) &tp); /* skip over param descriptor */
1772 (void) smb_ParseString((unsigned char*) tp, (char **) &tp); /* skip over data descriptor */
1776 if (infoLevel != 10) {
1777 return CM_ERROR_INVAL;
1783 totalData = sizeof(*info) + /* info */
1784 MAX_COMPUTERNAME_LENGTH + /* wki10_computername */
1785 SMB_MAX_USERNAME_LENGTH + /* wki10_username */
1786 MAX_COMPUTERNAME_LENGTH + /* wki10_langroup */
1787 MAX_COMPUTERNAME_LENGTH + /* wki10_logon_domain */
1788 1; /* wki10_oth_domains (null)*/
1790 outp = smb_GetTran2ResponsePacket(vcp, p, op, totalParams, totalData);
1792 memset(outp->parmsp,0,totalParams);
1793 memset(outp->datap,0,totalData);
1795 info = (smb_rap_wksta_info_10_t *) outp->datap;
1796 cstrp = (char *) (info + 1);
1798 info->wki10_computername = (DWORD) (cstrp - outp->datap);
1799 strcpy(cstrp, smb_localNamep);
1800 cstrp += strlen(cstrp) + 1;
1802 info->wki10_username = (DWORD) (cstrp - outp->datap);
1803 uidp = smb_FindUID(vcp, p->uid, 0);
1805 lock_ObtainMutex(&uidp->mx);
1806 if(uidp->unp && uidp->unp->name)
1807 strcpy(cstrp, uidp->unp->name);
1808 lock_ReleaseMutex(&uidp->mx);
1809 smb_ReleaseUID(uidp);
1811 cstrp += strlen(cstrp) + 1;
1813 info->wki10_langroup = (DWORD) (cstrp - outp->datap);
1814 strcpy(cstrp, "WORKGROUP");
1815 cstrp += strlen(cstrp) + 1;
1817 /* TODO: Not sure what values these should take, but these work */
1818 info->wki10_ver_major = 5;
1819 info->wki10_ver_minor = 1;
1821 info->wki10_logon_domain = (DWORD) (cstrp - outp->datap);
1822 strcpy(cstrp, smb_ServerDomainName);
1823 cstrp += strlen(cstrp) + 1;
1825 info->wki10_oth_domains = (DWORD) (cstrp - outp->datap);
1826 cstrp ++; /* no other domains */
1828 outp->totalData = (unsigned short) (cstrp - outp->datap); /* actual data size */
1829 outp->parmsp[2] = outp->totalData;
1830 outp->totalParms = totalParams;
1832 smb_SendTran2Packet(vcp,outp,op);
1833 smb_FreeTran2Packet(outp);
1838 typedef struct smb_rap_server_info_0 {
1840 } smb_rap_server_info_0_t;
1842 typedef struct smb_rap_server_info_1 {
1844 char sv1_version_major;
1845 char sv1_version_minor;
1846 unsigned long sv1_type;
1847 DWORD *sv1_comment_or_master_browser; /* char *sv1_comment_or_master_browser;*/
1848 } smb_rap_server_info_1_t;
1850 char smb_ServerComment[] = "OpenAFS Client";
1851 int smb_ServerCommentLen = sizeof(smb_ServerComment);
1853 #define SMB_SV_TYPE_SERVER 0x00000002L
1854 #define SMB_SV_TYPE_NT 0x00001000L
1855 #define SMB_SV_TYPE_SERVER_NT 0x00008000L
1857 long smb_ReceiveRAPNetServerGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1859 smb_tran2Packet_t *outp;
1863 unsigned short * tp;
1866 smb_rap_server_info_0_t * info0;
1867 smb_rap_server_info_1_t * info1;
1870 tp = p->parmsp + 1; /* Skip over function number */
1871 (void) smb_ParseString((unsigned char*) tp, (char **) &tp); /* skip over param descriptor */
1872 (void) smb_ParseString((unsigned char*) tp, (char **) &tp); /* skip over data descriptor */
1876 if (infoLevel != 0 && infoLevel != 1) {
1877 return CM_ERROR_INVAL;
1883 (infoLevel == 0) ? sizeof(smb_rap_server_info_0_t)
1884 : (sizeof(smb_rap_server_info_1_t) + smb_ServerCommentLen);
1886 outp = smb_GetTran2ResponsePacket(vcp, p, op, totalParams, totalData);
1888 memset(outp->parmsp,0,totalParams);
1889 memset(outp->datap,0,totalData);
1891 if (infoLevel == 0) {
1892 info0 = (smb_rap_server_info_0_t *) outp->datap;
1893 cstrp = (char *) (info0 + 1);
1894 strcpy(info0->sv0_name, "AFS");
1895 } else { /* infoLevel == SMB_INFO_STANDARD */
1896 info1 = (smb_rap_server_info_1_t *) outp->datap;
1897 cstrp = (char *) (info1 + 1);
1898 strcpy(info1->sv1_name, "AFS");
1901 SMB_SV_TYPE_SERVER |
1903 SMB_SV_TYPE_SERVER_NT;
1905 info1->sv1_version_major = 5;
1906 info1->sv1_version_minor = 1;
1907 info1->sv1_comment_or_master_browser = (DWORD *) (cstrp - outp->datap);
1909 strcpy(cstrp, smb_ServerComment);
1911 cstrp += smb_ServerCommentLen;
1914 totalData = (DWORD)(cstrp - outp->datap);
1915 outp->totalData = min(bufsize,totalData); /* actual data size */
1916 outp->parmsp[0] = (outp->totalData == totalData)? 0 : ERROR_MORE_DATA;
1917 outp->parmsp[2] = totalData;
1918 outp->totalParms = totalParams;
1920 smb_SendTran2Packet(vcp,outp,op);
1921 smb_FreeTran2Packet(outp);
1926 long smb_ReceiveV3Tran2A(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
1928 smb_tran2Packet_t *asp;
1940 /* We sometimes see 0 word count. What to do? */
1941 if (*inp->wctp == 0) {
1942 osi_Log0(smb_logp, "Transaction2 word count = 0");
1943 LogEvent(EVENTLOG_WARNING_TYPE, MSG_SMB_ZERO_TRANSACTION_COUNT);
1945 smb_SetSMBDataLength(outp, 0);
1946 smb_SendPacket(vcp, outp);
1950 totalParms = smb_GetSMBParm(inp, 0);
1951 totalData = smb_GetSMBParm(inp, 1);
1953 firstPacket = (inp->inCom == 0x32);
1955 /* find the packet we're reassembling */
1956 lock_ObtainWrite(&smb_globalLock);
1957 asp = smb_FindTran2Packet(vcp, inp);
1959 asp = smb_NewTran2Packet(vcp, inp, totalParms, totalData);
1961 lock_ReleaseWrite(&smb_globalLock);
1963 /* now merge in this latest packet; start by looking up offsets */
1965 parmDisp = dataDisp = 0;
1966 parmOffset = smb_GetSMBParm(inp, 10);
1967 dataOffset = smb_GetSMBParm(inp, 12);
1968 parmCount = smb_GetSMBParm(inp, 9);
1969 dataCount = smb_GetSMBParm(inp, 11);
1970 asp->maxReturnParms = smb_GetSMBParm(inp, 2);
1971 asp->maxReturnData = smb_GetSMBParm(inp, 3);
1973 osi_Log3(smb_logp, "SMB3 received T2 init packet total data %d, cur data %d, max return data %d",
1974 totalData, dataCount, asp->maxReturnData);
1977 parmDisp = smb_GetSMBParm(inp, 4);
1978 parmOffset = smb_GetSMBParm(inp, 3);
1979 dataDisp = smb_GetSMBParm(inp, 7);
1980 dataOffset = smb_GetSMBParm(inp, 6);
1981 parmCount = smb_GetSMBParm(inp, 2);
1982 dataCount = smb_GetSMBParm(inp, 5);
1984 osi_Log2(smb_logp, "SMB3 received T2 aux packet parms %d, data %d",
1985 parmCount, dataCount);
1988 /* now copy the parms and data */
1989 if ( asp->totalParms > 0 && parmCount != 0 )
1991 memcpy(((char *)asp->parmsp) + parmDisp, inp->data + parmOffset, parmCount);
1993 if ( asp->totalData > 0 && dataCount != 0 ) {
1994 memcpy(asp->datap + dataDisp, inp->data + dataOffset, dataCount);
1997 /* account for new bytes */
1998 asp->curData += dataCount;
1999 asp->curParms += parmCount;
2001 /* finally, if we're done, remove the packet from the queue and dispatch it */
2002 if (asp->totalParms > 0 &&
2003 asp->curParms > 0 &&
2004 asp->totalData <= asp->curData &&
2005 asp->totalParms <= asp->curParms) {
2006 /* we've received it all */
2007 lock_ObtainWrite(&smb_globalLock);
2008 osi_QRemove((osi_queue_t **) &smb_tran2AssemblyQueuep, &asp->q);
2009 lock_ReleaseWrite(&smb_globalLock);
2011 /* now dispatch it */
2012 if ( asp->opcode >= 0 && asp->opcode < 20 && smb_tran2DispatchTable[asp->opcode].procp) {
2013 osi_Log4(smb_logp,"AFS Server - Dispatch-2 %s vcp[%p] lana[%d] lsn[%d]",myCrt_2Dispatch(asp->opcode),vcp,vcp->lana,vcp->lsn);
2014 code = (*smb_tran2DispatchTable[asp->opcode].procp)(vcp, asp, outp);
2017 osi_Log4(smb_logp,"AFS Server - Dispatch-2 [INVALID] op[%x] vcp[%p] lana[%d] lsn[%d]", asp->opcode, vcp, vcp->lana, vcp->lsn);
2018 code = CM_ERROR_BADOP;
2021 /* if an error is returned, we're supposed to send an error packet,
2022 * otherwise the dispatched function already did the data sending.
2023 * We give dispatched proc the responsibility since it knows how much
2024 * space to allocate.
2027 smb_SendTran2Error(vcp, asp, outp, code);
2030 /* free the input tran 2 packet */
2031 smb_FreeTran2Packet(asp);
2033 else if (firstPacket) {
2034 /* the first packet in a multi-packet request, we need to send an
2035 * ack to get more data.
2037 smb_SetSMBDataLength(outp, 0);
2038 smb_SendPacket(vcp, outp);
2044 long smb_ReceiveTran2Open(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
2047 smb_tran2Packet_t *outp;
2052 cm_scache_t *dscp; /* dir we're dealing with */
2053 cm_scache_t *scp; /* file we're creating */
2055 int initialModeBits;
2065 int parmSlot; /* which parm we're dealing with */
2066 long returnEALength;
2075 extraInfo = (p->parmsp[0] & 1); /* return extra info */
2076 returnEALength = (p->parmsp[0] & 8); /* return extended attr length */
2078 openFun = p->parmsp[6]; /* open function */
2079 excl = ((openFun & 3) == 0);
2080 trunc = ((openFun & 3) == 2); /* truncate it */
2081 openMode = (p->parmsp[1] & 0x7);
2082 openAction = 0; /* tracks what we did */
2084 attributes = p->parmsp[3];
2085 dosTime = p->parmsp[4] | (p->parmsp[5] << 16);
2087 /* compute initial mode bits based on read-only flag in attributes */
2088 initialModeBits = 0666;
2089 if (attributes & SMB_ATTR_READONLY)
2090 initialModeBits &= ~0222;
2092 pathp = (char *) (&p->parmsp[14]);
2093 if (smb_StoreAnsiFilenames)
2094 OemToChar(pathp,pathp);
2096 outp = smb_GetTran2ResponsePacket(vcp, p, op, 40, 0);
2098 spacep = cm_GetSpace();
2099 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
2101 if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
2102 /* special case magic file name for receiving IOCTL requests
2103 * (since IOCTL calls themselves aren't getting through).
2105 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
2106 smb_SetupIoctlFid(fidp, spacep);
2108 /* copy out remainder of the parms */
2110 outp->parmsp[parmSlot++] = fidp->fid;
2112 outp->parmsp[parmSlot++] = 0; /* attrs */
2113 outp->parmsp[parmSlot++] = 0; /* mod time */
2114 outp->parmsp[parmSlot++] = 0;
2115 outp->parmsp[parmSlot++] = 0; /* len */
2116 outp->parmsp[parmSlot++] = 0x7fff;
2117 outp->parmsp[parmSlot++] = openMode;
2118 outp->parmsp[parmSlot++] = 0; /* file type 0 ==> normal file or dir */
2119 outp->parmsp[parmSlot++] = 0; /* IPC junk */
2121 /* and the final "always present" stuff */
2122 outp->parmsp[parmSlot++] = 1; /* openAction found existing file */
2123 /* next write out the "unique" ID */
2124 outp->parmsp[parmSlot++] = 0x1234;
2125 outp->parmsp[parmSlot++] = 0x5678;
2126 outp->parmsp[parmSlot++] = 0;
2127 if (returnEALength) {
2128 outp->parmsp[parmSlot++] = 0;
2129 outp->parmsp[parmSlot++] = 0;
2132 outp->totalData = 0;
2133 outp->totalParms = parmSlot * 2;
2135 smb_SendTran2Packet(vcp, outp, op);
2137 smb_FreeTran2Packet(outp);
2139 /* and clean up fid reference */
2140 smb_ReleaseFID(fidp);
2144 #ifdef DEBUG_VERBOSE
2146 char *hexp, *asciip;
2147 asciip = (lastNamep ? lastNamep : pathp);
2148 hexp = osi_HexifyString( asciip );
2149 DEBUG_EVENT2("AFS","T2Open H[%s] A[%s]", hexp, asciip);
2154 userp = smb_GetTran2User(vcp, p);
2155 /* In the off chance that userp is NULL, we log and abandon */
2157 osi_Log1(smb_logp, "ReceiveTran2Open user [%d] not resolvable", p->uid);
2158 smb_FreeTran2Packet(outp);
2159 return CM_ERROR_BADSMB;
2162 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
2163 if (code == CM_ERROR_TIDIPC) {
2164 /* Attempt to use a TID allocated for IPC. The client
2165 * is probably looking for DCE RPC end points which we
2166 * don't support OR it could be looking to make a DFS
2169 osi_Log0(smb_logp, "Tran2Open received IPC TID");
2171 cm_ReleaseUser(userp);
2172 smb_FreeTran2Packet(outp);
2173 return CM_ERROR_NOSUCHPATH;
2178 code = cm_NameI(cm_data.rootSCachep, pathp,
2179 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
2180 userp, tidPathp, &req, &scp);
2182 code = cm_NameI(cm_data.rootSCachep, spacep->data,
2183 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
2184 userp, tidPathp, &req, &dscp);
2185 cm_FreeSpace(spacep);
2188 cm_ReleaseUser(userp);
2189 smb_FreeTran2Packet(outp);
2194 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
2195 cm_ReleaseSCache(dscp);
2196 cm_ReleaseUser(userp);
2197 smb_FreeTran2Packet(outp);
2198 if ( WANTS_DFS_PATHNAMES(p) )
2199 return CM_ERROR_PATH_NOT_COVERED;
2201 return CM_ERROR_BADSHARENAME;
2203 #endif /* DFS_SUPPORT */
2205 /* otherwise, scp points to the parent directory. Do a lookup,
2206 * and truncate the file if we find it, otherwise we create the
2213 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD, userp,
2215 if (code && code != CM_ERROR_NOSUCHFILE) {
2216 cm_ReleaseSCache(dscp);
2217 cm_ReleaseUser(userp);
2218 smb_FreeTran2Packet(outp);
2223 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
2224 cm_ReleaseSCache(scp);
2225 cm_ReleaseUser(userp);
2226 smb_FreeTran2Packet(outp);
2227 if ( WANTS_DFS_PATHNAMES(p) )
2228 return CM_ERROR_PATH_NOT_COVERED;
2230 return CM_ERROR_BADSHARENAME;
2232 #endif /* DFS_SUPPORT */
2234 /* macintosh is expensive to program for it */
2235 cm_FreeSpace(spacep);
2238 /* if we get here, if code is 0, the file exists and is represented by
2239 * scp. Otherwise, we have to create it.
2242 code = cm_CheckOpen(scp, openMode, trunc, userp, &req);
2245 cm_ReleaseSCache(dscp);
2246 cm_ReleaseSCache(scp);
2247 cm_ReleaseUser(userp);
2248 smb_FreeTran2Packet(outp);
2253 /* oops, file shouldn't be there */
2255 cm_ReleaseSCache(dscp);
2256 cm_ReleaseSCache(scp);
2257 cm_ReleaseUser(userp);
2258 smb_FreeTran2Packet(outp);
2259 return CM_ERROR_EXISTS;
2263 setAttr.mask = CM_ATTRMASK_LENGTH;
2264 setAttr.length.LowPart = 0;
2265 setAttr.length.HighPart = 0;
2266 code = cm_SetAttr(scp, &setAttr, userp, &req);
2267 openAction = 3; /* truncated existing file */
2270 openAction = 1; /* found existing file */
2272 else if (!(openFun & 0x10)) {
2273 /* don't create if not found */
2275 cm_ReleaseSCache(dscp);
2276 osi_assert(scp == NULL);
2277 cm_ReleaseUser(userp);
2278 smb_FreeTran2Packet(outp);
2279 return CM_ERROR_NOSUCHFILE;
2282 osi_assert(dscp != NULL && scp == NULL);
2283 openAction = 2; /* created file */
2284 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
2285 smb_UnixTimeFromSearchTime(&setAttr.clientModTime, dosTime);
2286 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
2290 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
2291 smb_NotifyChange(FILE_ACTION_ADDED,
2292 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
2293 dscp, lastNamep, NULL, TRUE);
2294 } else if (!excl && code == CM_ERROR_EXISTS) {
2295 /* not an exclusive create, and someone else tried
2296 * creating it already, then we open it anyway. We
2297 * don't bother retrying after this, since if this next
2298 * fails, that means that the file was deleted after we
2299 * started this call.
2301 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
2305 setAttr.mask = CM_ATTRMASK_LENGTH;
2306 setAttr.length.LowPart = 0;
2307 setAttr.length.HighPart = 0;
2308 code = cm_SetAttr(scp, &setAttr, userp,
2311 } /* lookup succeeded */
2315 /* we don't need this any longer */
2317 cm_ReleaseSCache(dscp);
2320 /* something went wrong creating or truncating the file */
2322 cm_ReleaseSCache(scp);
2323 cm_ReleaseUser(userp);
2324 smb_FreeTran2Packet(outp);
2328 /* make sure we're about to open a file */
2329 if (scp->fileType != CM_SCACHETYPE_FILE) {
2331 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
2332 cm_scache_t * targetScp = 0;
2333 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
2335 /* we have a more accurate file to use (the
2336 * target of the symbolic link). Otherwise,
2337 * we'll just use the symlink anyway.
2339 osi_Log2(smb_logp, "symlink vp %x to vp %x",
2341 cm_ReleaseSCache(scp);
2345 if (scp->fileType != CM_SCACHETYPE_FILE) {
2346 cm_ReleaseSCache(scp);
2347 cm_ReleaseUser(userp);
2348 smb_FreeTran2Packet(outp);
2349 return CM_ERROR_ISDIR;
2353 /* now all we have to do is open the file itself */
2354 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
2358 lock_ObtainMutex(&fidp->mx);
2359 /* save a pointer to the vnode */
2360 osi_Log2(afsd_logp,"smb_ReceiveTran2Open fidp 0x%p scp 0x%p", fidp, scp);
2362 lock_ObtainMutex(&scp->mx);
2363 scp->flags |= CM_SCACHEFLAG_SMB_FID;
2364 lock_ReleaseMutex(&scp->mx);
2367 fidp->userp = userp;
2369 /* compute open mode */
2371 fidp->flags |= SMB_FID_OPENREAD;
2372 if (openMode == 1 || openMode == 2)
2373 fidp->flags |= SMB_FID_OPENWRITE;
2375 /* remember that the file was newly created */
2377 fidp->flags |= SMB_FID_CREATED;
2379 lock_ReleaseMutex(&fidp->mx);
2381 smb_ReleaseFID(fidp);
2383 cm_Open(scp, 0, userp);
2385 /* copy out remainder of the parms */
2387 outp->parmsp[parmSlot++] = fidp->fid;
2388 lock_ObtainMutex(&scp->mx);
2390 outp->parmsp[parmSlot++] = smb_Attributes(scp);
2391 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
2392 outp->parmsp[parmSlot++] = (unsigned short)(dosTime & 0xffff);
2393 outp->parmsp[parmSlot++] = (unsigned short)((dosTime>>16) & 0xffff);
2394 outp->parmsp[parmSlot++] = (unsigned short) (scp->length.LowPart & 0xffff);
2395 outp->parmsp[parmSlot++] = (unsigned short) ((scp->length.LowPart >> 16) & 0xffff);
2396 outp->parmsp[parmSlot++] = openMode;
2397 outp->parmsp[parmSlot++] = 0; /* file type 0 ==> normal file or dir */
2398 outp->parmsp[parmSlot++] = 0; /* IPC junk */
2400 /* and the final "always present" stuff */
2401 outp->parmsp[parmSlot++] = openAction;
2402 /* next write out the "unique" ID */
2403 outp->parmsp[parmSlot++] = (unsigned short) (scp->fid.vnode & 0xffff);
2404 outp->parmsp[parmSlot++] = (unsigned short) (scp->fid.volume & 0xffff);
2405 outp->parmsp[parmSlot++] = 0;
2406 if (returnEALength) {
2407 outp->parmsp[parmSlot++] = 0;
2408 outp->parmsp[parmSlot++] = 0;
2410 lock_ReleaseMutex(&scp->mx);
2411 outp->totalData = 0; /* total # of data bytes */
2412 outp->totalParms = parmSlot * 2; /* shorts are two bytes */
2414 smb_SendTran2Packet(vcp, outp, op);
2416 smb_FreeTran2Packet(outp);
2418 cm_ReleaseUser(userp);
2419 /* leave scp held since we put it in fidp->scp */
2423 long smb_ReceiveTran2FindFirst(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
2425 osi_Log0(smb_logp,"ReceiveTran2FindFirst - NOT_SUPPORTED");
2426 return CM_ERROR_BADOP;
2429 long smb_ReceiveTran2FindNext(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
2431 osi_Log0(smb_logp,"ReceiveTran2FindNext - NOT_SUPPORTED");
2432 return CM_ERROR_BADOP;
2435 long smb_ReceiveTran2QFSInfoFid(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
2438 unsigned short infolevel;
2440 infolevel = p->parmsp[0];
2442 osi_Log2(smb_logp, "T2 QFSInfoFid InfoLevel 0x%x fid 0x%x - NOT_SUPPORTED", infolevel, fid);
2444 return CM_ERROR_BADOP;
2447 long smb_ReceiveTran2QFSInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
2449 smb_tran2Packet_t *outp;
2450 smb_tran2QFSInfo_t qi;
2452 static char FSname[8] = {'A', 0, 'F', 0, 'S', 0, 0, 0};
2454 osi_Log1(smb_logp, "T2 QFSInfo type 0x%x", p->parmsp[0]);
2456 switch (p->parmsp[0]) {
2457 case SMB_INFO_ALLOCATION:
2458 responseSize = sizeof(qi.u.allocInfo);
2460 case SMB_INFO_VOLUME:
2461 responseSize = sizeof(qi.u.volumeInfo);
2463 case SMB_QUERY_FS_VOLUME_INFO:
2464 responseSize = sizeof(qi.u.FSvolumeInfo);
2466 case SMB_QUERY_FS_SIZE_INFO:
2467 responseSize = sizeof(qi.u.FSsizeInfo);
2469 case SMB_QUERY_FS_DEVICE_INFO:
2470 responseSize = sizeof(qi.u.FSdeviceInfo);
2472 case SMB_QUERY_FS_ATTRIBUTE_INFO:
2473 responseSize = sizeof(qi.u.FSattributeInfo);
2475 case SMB_INFO_UNIX: /* CIFS Unix Info */
2476 case SMB_INFO_MACOS: /* Mac FS Info */
2478 return CM_ERROR_BADOP;
2481 outp = smb_GetTran2ResponsePacket(vcp, p, op, 0, responseSize);
2482 switch (p->parmsp[0]) {
2483 case SMB_INFO_ALLOCATION:
2485 qi.u.allocInfo.FSID = 0;
2486 qi.u.allocInfo.sectorsPerAllocUnit = 1;
2487 qi.u.allocInfo.totalAllocUnits = 0x7fffffff;
2488 qi.u.allocInfo.availAllocUnits = 0x3fffffff;
2489 qi.u.allocInfo.bytesPerSector = 1024;
2492 case SMB_INFO_VOLUME:
2494 qi.u.volumeInfo.vsn = 1234;
2495 qi.u.volumeInfo.vnCount = 4;
2496 /* we're supposed to pad it out with zeroes to the end */
2497 memset(&qi.u.volumeInfo.label, 0, sizeof(qi.u.volumeInfo.label));
2498 memcpy(qi.u.volumeInfo.label, "AFS", 4);
2501 case SMB_QUERY_FS_VOLUME_INFO:
2502 /* FS volume info */
2503 memset((char *)&qi.u.FSvolumeInfo.vct, 0, 4);
2504 qi.u.FSvolumeInfo.vsn = 1234;
2505 qi.u.FSvolumeInfo.vnCount = 8;
2506 memcpy(qi.u.FSvolumeInfo.label, "A\0F\0S\0\0\0", 8);
2509 case SMB_QUERY_FS_SIZE_INFO:
2511 qi.u.FSsizeInfo.totalAllocUnits.HighPart = 0;
2512 qi.u.FSsizeInfo.totalAllocUnits.LowPart= 0x7fffffff;
2513 qi.u.FSsizeInfo.availAllocUnits.HighPart = 0;
2514 qi.u.FSsizeInfo.availAllocUnits.LowPart= 0x3fffffff;
2515 qi.u.FSsizeInfo.sectorsPerAllocUnit = 1;
2516 qi.u.FSsizeInfo.bytesPerSector = 1024;
2519 case SMB_QUERY_FS_DEVICE_INFO:
2520 /* FS device info */
2521 qi.u.FSdeviceInfo.devType = 0x14; /* network file system */
2522 qi.u.FSdeviceInfo.characteristics = 0x50; /* remote, virtual */
2525 case SMB_QUERY_FS_ATTRIBUTE_INFO:
2526 /* FS attribute info */
2527 /* attributes, defined in WINNT.H:
2528 * FILE_CASE_SENSITIVE_SEARCH 0x1
2529 * FILE_CASE_PRESERVED_NAMES 0x2
2530 * FILE_VOLUME_QUOTAS 0x10
2531 * <no name defined> 0x4000
2532 * If bit 0x4000 is not set, Windows 95 thinks
2533 * we can't handle long (non-8.3) names,
2534 * despite our protestations to the contrary.
2536 qi.u.FSattributeInfo.attributes = 0x4003;
2537 qi.u.FSattributeInfo.maxCompLength = MAX_PATH;
2538 qi.u.FSattributeInfo.FSnameLength = sizeof(FSname);
2539 memcpy(qi.u.FSattributeInfo.FSname, FSname, sizeof(FSname));
2543 /* copy out return data, and set corresponding sizes */
2544 outp->totalParms = 0;
2545 outp->totalData = responseSize;
2546 memcpy(outp->datap, &qi, responseSize);
2548 /* send and free the packets */
2549 smb_SendTran2Packet(vcp, outp, op);
2550 smb_FreeTran2Packet(outp);
2555 long smb_ReceiveTran2SetFSInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
2557 osi_Log0(smb_logp,"ReceiveTran2SetFSInfo - NOT_SUPPORTED");
2558 return CM_ERROR_BADOP;
2561 struct smb_ShortNameRock {
2565 size_t shortNameLen;
2568 int cm_GetShortNameProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *vrockp,
2571 struct smb_ShortNameRock *rockp;
2575 /* compare both names and vnodes, though probably just comparing vnodes
2576 * would be safe enough.
2578 if (cm_stricmp(dep->name, rockp->maskp) != 0)
2580 if (ntohl(dep->fid.vnode) != rockp->vnode)
2582 /* This is the entry */
2583 cm_Gen8Dot3Name(dep, rockp->shortName, &shortNameEnd);
2584 rockp->shortNameLen = shortNameEnd - rockp->shortName;
2585 return CM_ERROR_STOPNOW;
2588 long cm_GetShortName(char *pathp, cm_user_t *userp, cm_req_t *reqp,
2589 char *tidPathp, int vnode, char *shortName, size_t *shortNameLenp)
2591 struct smb_ShortNameRock rock;
2595 int caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
2599 spacep = cm_GetSpace();
2600 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
2602 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold, userp, tidPathp,
2604 cm_FreeSpace(spacep);
2609 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
2610 cm_ReleaseSCache(dscp);
2611 cm_ReleaseUser(userp);
2612 return CM_ERROR_PATH_NOT_COVERED;
2614 #endif /* DFS_SUPPORT */
2616 if (!lastNamep) lastNamep = pathp;
2619 thyper.HighPart = 0;
2620 rock.shortName = shortName;
2622 rock.maskp = lastNamep;
2623 code = cm_ApplyDir(dscp, cm_GetShortNameProc, &rock, &thyper, userp, reqp, NULL);
2625 cm_ReleaseSCache(dscp);
2628 return CM_ERROR_NOSUCHFILE;
2629 if (code == CM_ERROR_STOPNOW) {
2630 *shortNameLenp = rock.shortNameLen;
2636 long smb_ReceiveTran2QPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
2638 smb_tran2Packet_t *outp;
2641 unsigned short infoLevel;
2642 smb_tran2QPathInfo_t qpi;
2644 unsigned short attributes;
2645 unsigned long extAttributes;
2650 cm_scache_t *scp, *dscp;
2660 infoLevel = p->parmsp[0];
2661 if (infoLevel == SMB_INFO_IS_NAME_VALID)
2663 else if (infoLevel == SMB_INFO_STANDARD)
2664 responseSize = sizeof(qpi.u.QPstandardInfo);
2665 else if (infoLevel == SMB_INFO_QUERY_EA_SIZE)
2666 responseSize = sizeof(qpi.u.QPeaSizeInfo);
2667 else if (infoLevel == SMB_QUERY_FILE_BASIC_INFO)
2668 responseSize = sizeof(qpi.u.QPfileBasicInfo);
2669 else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO)
2670 responseSize = sizeof(qpi.u.QPfileStandardInfo);
2671 else if (infoLevel == SMB_QUERY_FILE_EA_INFO)
2672 responseSize = sizeof(qpi.u.QPfileEaInfo);
2673 else if (infoLevel == SMB_QUERY_FILE_NAME_INFO)
2674 responseSize = sizeof(qpi.u.QPfileNameInfo);
2675 else if (infoLevel == SMB_QUERY_FILE_ALL_INFO)
2676 responseSize = sizeof(qpi.u.QPfileAllInfo);
2677 else if (infoLevel == SMB_QUERY_FILE_ALT_NAME_INFO)
2678 responseSize = sizeof(qpi.u.QPfileAltNameInfo);
2680 osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
2681 p->opcode, infoLevel);
2682 smb_SendTran2Error(vcp, p, opx, CM_ERROR_BADOP);
2686 pathp = (char *)(&p->parmsp[3]);
2687 if (smb_StoreAnsiFilenames)
2688 OemToChar(pathp,pathp);
2689 osi_Log2(smb_logp, "T2 QPathInfo type 0x%x path %s", infoLevel,
2690 osi_LogSaveString(smb_logp, pathp));
2692 outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, responseSize);
2694 if (infoLevel > 0x100)
2695 outp->totalParms = 2;
2697 outp->totalParms = 0;
2698 outp->totalData = responseSize;
2700 /* now, if we're at infoLevel 6, we're only being asked to check
2701 * the syntax, so we just OK things now. In particular, we're *not*
2702 * being asked to verify anything about the state of any parent dirs.
2704 if (infoLevel == SMB_INFO_IS_NAME_VALID) {
2705 smb_SendTran2Packet(vcp, outp, opx);
2706 smb_FreeTran2Packet(outp);
2710 userp = smb_GetTran2User(vcp, p);
2712 osi_Log1(smb_logp, "ReceiveTran2QPathInfo unable to resolve user [%d]", p->uid);
2713 smb_FreeTran2Packet(outp);
2714 return CM_ERROR_BADSMB;
2717 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
2719 cm_ReleaseUser(userp);
2720 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOSUCHPATH);
2721 smb_FreeTran2Packet(outp);
2726 * XXX Strange hack XXX
2728 * As of Patch 7 (13 January 98), we are having the following problem:
2729 * In NT Explorer 4.0, whenever we click on a directory, AFS gets
2730 * requests to look up "desktop.ini" in all the subdirectories.
2731 * This can cause zillions of timeouts looking up non-existent cells
2732 * and volumes, especially in the top-level directory.
2734 * We have not found any way to avoid this or work around it except
2735 * to explicitly ignore the requests for mount points that haven't
2736 * yet been evaluated and for directories that haven't yet been
2739 if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
2740 spacep = cm_GetSpace();
2741 smb_StripLastComponent(spacep->data, &lastComp, pathp);
2742 #ifndef SPECIAL_FOLDERS
2743 /* Make sure that lastComp is not NULL */
2745 if (stricmp(lastComp, "\\desktop.ini") == 0) {
2746 code = cm_NameI(cm_data.rootSCachep, spacep->data,
2750 userp, tidPathp, &req, &dscp);
2753 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
2754 if ( WANTS_DFS_PATHNAMES(p) )
2755 code = CM_ERROR_PATH_NOT_COVERED;
2757 code = CM_ERROR_BADSHARENAME;
2759 #endif /* DFS_SUPPORT */
2760 if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT && !dscp->mountRootFid.volume)
2761 code = CM_ERROR_NOSUCHFILE;
2762 else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
2763 cm_buf_t *bp = buf_Find(dscp, &hzero);
2767 code = CM_ERROR_NOSUCHFILE;
2769 cm_ReleaseSCache(dscp);
2771 cm_FreeSpace(spacep);
2772 cm_ReleaseUser(userp);
2773 smb_SendTran2Error(vcp, p, opx, code);
2774 smb_FreeTran2Packet(outp);
2780 #endif /* SPECIAL_FOLDERS */
2782 cm_FreeSpace(spacep);
2785 /* now do namei and stat, and copy out the info */
2786 code = cm_NameI(cm_data.rootSCachep, pathp,
2787 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, tidPathp, &req, &scp);
2790 cm_ReleaseUser(userp);
2791 smb_SendTran2Error(vcp, p, opx, code);
2792 smb_FreeTran2Packet(outp);
2797 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
2798 cm_ReleaseSCache(scp);
2799 cm_ReleaseUser(userp);
2800 if ( WANTS_DFS_PATHNAMES(p) )
2801 code = CM_ERROR_PATH_NOT_COVERED;
2803 code = CM_ERROR_BADSHARENAME;
2804 smb_SendTran2Error(vcp, p, opx, code);
2805 smb_FreeTran2Packet(outp);
2808 #endif /* DFS_SUPPORT */
2810 lock_ObtainMutex(&scp->mx);
2811 code = cm_SyncOp(scp, NULL, userp, &req, 0,
2812 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
2813 if (code) goto done;
2815 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
2817 /* now we have the status in the cache entry, and everything is locked.
2818 * Marshall the output data.
2820 /* for info level 108, figure out short name */
2821 if (infoLevel == SMB_QUERY_FILE_ALT_NAME_INFO) {
2822 code = cm_GetShortName(pathp, userp, &req,
2823 tidPathp, scp->fid.vnode, shortName,
2829 qpi.u.QPfileAltNameInfo.fileNameLength = (len + 1) * 2;
2830 mbstowcs((unsigned short *)qpi.u.QPfileAltNameInfo.fileName, shortName, len + 1);
2834 else if (infoLevel == SMB_QUERY_FILE_NAME_INFO) {
2835 len = strlen(lastComp);
2836 qpi.u.QPfileNameInfo.fileNameLength = (len + 1) * 2;
2837 mbstowcs((unsigned short *)qpi.u.QPfileNameInfo.fileName, lastComp, len + 1);
2841 else if (infoLevel == SMB_INFO_STANDARD || infoLevel == SMB_INFO_QUERY_EA_SIZE) {
2842 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
2843 qpi.u.QPstandardInfo.creationDateTime = dosTime;
2844 qpi.u.QPstandardInfo.lastAccessDateTime = dosTime;
2845 qpi.u.QPstandardInfo.lastWriteDateTime = dosTime;
2846 qpi.u.QPstandardInfo.dataSize = scp->length.LowPart;
2847 qpi.u.QPstandardInfo.allocationSize = scp->length.LowPart;
2848 attributes = smb_Attributes(scp);
2849 qpi.u.QPstandardInfo.attributes = attributes;
2850 qpi.u.QPstandardInfo.eaSize = 0;
2852 else if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
2853 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
2854 qpi.u.QPfileBasicInfo.creationTime = ft;
2855 qpi.u.QPfileBasicInfo.lastAccessTime = ft;
2856 qpi.u.QPfileBasicInfo.lastWriteTime = ft;
2857 qpi.u.QPfileBasicInfo.changeTime = ft;
2858 extAttributes = smb_ExtAttributes(scp);
2859 qpi.u.QPfileBasicInfo.attributes = extAttributes;
2860 qpi.u.QPfileBasicInfo.reserved = 0;
2862 else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO) {
2863 smb_fid_t *fidp = smb_FindFIDByScache(vcp, scp);
2865 lock_ObtainMutex(&fidp->mx);
2866 delonclose = fidp->flags & SMB_FID_DELONCLOSE;
2867 lock_ReleaseMutex(&fidp->mx);
2868 smb_ReleaseFID(fidp);
2871 qpi.u.QPfileStandardInfo.allocationSize = scp->length;
2872 qpi.u.QPfileStandardInfo.endOfFile = scp->length;
2873 qpi.u.QPfileStandardInfo.numberOfLinks = scp->linkCount;
2874 qpi.u.QPfileStandardInfo.deletePending = (delonclose ? 1 : 0);
2875 qpi.u.QPfileStandardInfo.directory =
2876 ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
2877 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
2878 scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0);
2879 qpi.u.QPfileStandardInfo.reserved = 0;
2881 else if (infoLevel == SMB_QUERY_FILE_EA_INFO) {
2882 qpi.u.QPfileEaInfo.eaSize = 0;
2884 else if (infoLevel == SMB_QUERY_FILE_ALL_INFO) {
2885 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
2886 qpi.u.QPfileAllInfo.creationTime = ft;
2887 qpi.u.QPfileAllInfo.lastAccessTime = ft;
2888 qpi.u.QPfileAllInfo.lastWriteTime = ft;
2889 qpi.u.QPfileAllInfo.changeTime = ft;
2890 extAttributes = smb_ExtAttributes(scp);
2891 qpi.u.QPfileAllInfo.attributes = extAttributes;
2892 qpi.u.QPfileAllInfo.allocationSize = scp->length;
2893 qpi.u.QPfileAllInfo.endOfFile = scp->length;
2894 qpi.u.QPfileAllInfo.numberOfLinks = scp->linkCount;
2895 qpi.u.QPfileAllInfo.deletePending = 0;
2896 qpi.u.QPfileAllInfo.directory =
2897 ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
2898 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
2899 scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0);
2900 qpi.u.QPfileAllInfo.indexNumber.HighPart = scp->fid.cell;
2901 qpi.u.QPfileAllInfo.indexNumber.LowPart = scp->fid.volume;
2902 qpi.u.QPfileAllInfo.eaSize = 0;
2903 qpi.u.QPfileAllInfo.accessFlags = 0;
2904 qpi.u.QPfileAllInfo.indexNumber2.HighPart = scp->fid.vnode;
2905 qpi.u.QPfileAllInfo.indexNumber2.LowPart = scp->fid.unique;
2906 qpi.u.QPfileAllInfo.currentByteOffset.HighPart = 0;
2907 qpi.u.QPfileAllInfo.currentByteOffset.LowPart = 0;
2908 qpi.u.QPfileAllInfo.mode = 0;
2909 qpi.u.QPfileAllInfo.alignmentRequirement = 0;
2910 len = strlen(lastComp);
2911 qpi.u.QPfileAllInfo.fileNameLength = (len + 1) * 2;
2912 mbstowcs((unsigned short *)qpi.u.QPfileAllInfo.fileName, lastComp, len + 1);
2915 /* send and free the packets */
2917 lock_ReleaseMutex(&scp->mx);
2918 cm_ReleaseSCache(scp);
2919 cm_ReleaseUser(userp);
2921 memcpy(outp->datap, &qpi, responseSize);
2922 smb_SendTran2Packet(vcp, outp, opx);
2924 smb_SendTran2Error(vcp, p, opx, code);
2926 smb_FreeTran2Packet(outp);
2931 long smb_ReceiveTran2SetPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
2934 osi_Log0(smb_logp,"ReceiveTran2SetPathInfo - NOT_SUPPORTED");
2935 return CM_ERROR_BADOP;
2939 unsigned short infoLevel;
2941 smb_tran2Packet_t *outp;
2942 smb_tran2QPathInfo_t *spi;
2944 cm_scache_t *scp, *dscp;
2952 infoLevel = p->parmsp[0];
2953 osi_Log1(smb_logp,"ReceiveTran2SetPathInfo type 0x%x", infoLevel);
2954 if (infoLevel != SMB_INFO_STANDARD &&
2955 infoLevel != SMB_INFO_QUERY_EA_SIZE &&
2956 infoLevel != SMB_INFO_QUERY_ALL_EAS) {
2957 osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
2958 p->opcode, infoLevel);
2959 smb_SendTran2Error(vcp, p, opx, CM_ERROR_INVAL);
2963 pathp = (char *)(&p->parmsp[3]);
2964 if (smb_StoreAnsiFilenames)
2965 OemToChar(pathp,pathp);
2966 osi_Log2(smb_logp, "T2 SetPathInfo infolevel 0x%x path %s", infoLevel,
2967 osi_LogSaveString(smb_logp, pathp));
2969 userp = smb_GetTran2User(vcp, p);
2971 osi_Log1(smb_logp,"ReceiveTran2SetPathInfo unable to resolve user [%d]", p->uid);
2972 code = CM_ERROR_BADSMB;
2976 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
2977 if (code == CM_ERROR_TIDIPC) {
2978 /* Attempt to use a TID allocated for IPC. The client
2979 * is probably looking for DCE RPC end points which we
2980 * don't support OR it could be looking to make a DFS
2983 osi_Log0(smb_logp, "Tran2Open received IPC TID");
2984 cm_ReleaseUser(userp);
2985 return CM_ERROR_NOSUCHPATH;
2989 * XXX Strange hack XXX
2991 * As of Patch 7 (13 January 98), we are having the following problem:
2992 * In NT Explorer 4.0, whenever we click on a directory, AFS gets
2993 * requests to look up "desktop.ini" in all the subdirectories.
2994 * This can cause zillions of timeouts looking up non-existent cells
2995 * and volumes, especially in the top-level directory.
2997 * We have not found any way to avoid this or work around it except
2998 * to explicitly ignore the requests for mount points that haven't
2999 * yet been evaluated and for directories that haven't yet been
3002 if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
3003 spacep = cm_GetSpace();
3004 smb_StripLastComponent(spacep->data, &lastComp, pathp);
3005 #ifndef SPECIAL_FOLDERS
3006 /* Make sure that lastComp is not NULL */
3008 if (stricmp(lastComp, "\\desktop.ini") == 0) {
3009 code = cm_NameI(cm_data.rootSCachep, spacep->data,
3013 userp, tidPathp, &req, &dscp);
3016 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
3017 if ( WANTS_DFS_PATHNAMES(p) )
3018 code = CM_ERROR_PATH_NOT_COVERED;
3020 code = CM_ERROR_BADSHARENAME;
3022 #endif /* DFS_SUPPORT */
3023 if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT && !dscp->mountRootFid.volume)
3024 code = CM_ERROR_NOSUCHFILE;
3025 else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
3026 cm_buf_t *bp = buf_Find(dscp, &hzero);
3030 code = CM_ERROR_NOSUCHFILE;
3032 cm_ReleaseSCache(dscp);
3034 cm_FreeSpace(spacep);
3035 cm_ReleaseUser(userp);
3036 smb_SendTran2Error(vcp, p, opx, code);
3042 #endif /* SPECIAL_FOLDERS */
3044 cm_FreeSpace(spacep);
3047 /* now do namei and stat, and copy out the info */
3048 code = cm_NameI(cm_data.rootSCachep, pathp,
3049 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, tidPathp, &req, &scp);
3051 cm_ReleaseUser(userp);
3052 smb_SendTran2Error(vcp, p, opx, code);
3056 fidp = smb_FindFIDByScache(vcp, scp);
3058 cm_ReleaseUser(userp);
3059 cm_ReleaseSCache(scp);
3060 smb_SendTran2Error(vcp, p, opx, code);
3064 lock_ObtainMutex(&fidp->mx);
3065 if (!(fidp->flags & SMB_FID_OPENWRITE)) {
3066 lock_ReleaseMutex(&fidp->mx);
3067 smb_ReleaseFID(fidp);
3068 cm_ReleaseUser(userp);
3069 cm_ReleaseSCache(scp);
3070 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOACCESS);
3073 lock_ReleaseMutex(&fidp->mx);
3075 outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, 0);
3077 outp->totalParms = 2;
3078 outp->totalData = 0;
3080 spi = (smb_tran2QPathInfo_t *)p->datap;
3081 if (infoLevel == SMB_INFO_STANDARD || infoLevel == SMB_INFO_QUERY_EA_SIZE) {
3084 /* lock the vnode with a callback; we need the current status
3085 * to determine what the new status is, in some cases.
3087 lock_ObtainMutex(&scp->mx);
3088 code = cm_SyncOp(scp, NULL, userp, &req, 0,
3089 CM_SCACHESYNC_GETSTATUS
3090 | CM_SCACHESYNC_NEEDCALLBACK);
3092 lock_ReleaseMutex(&scp->mx);
3095 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3097 lock_ReleaseMutex(&scp->mx);
3098 lock_ObtainMutex(&fidp->mx);
3099 lock_ObtainMutex(&scp->mx);
3101 /* prepare for setattr call */
3102 attr.mask = CM_ATTRMASK_LENGTH;
3103 attr.length.LowPart = spi->u.QPstandardInfo.dataSize;
3104 attr.length.HighPart = 0;
3106 if (spi->u.QPstandardInfo.lastWriteDateTime != 0) {
3107 smb_UnixTimeFromSearchTime(&attr.clientModTime, spi->u.QPstandardInfo.lastWriteDateTime);
3108 attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
3109 fidp->flags |= SMB_FID_MTIMESETDONE;
3112 if (spi->u.QPstandardInfo.attributes != 0) {
3113 if ((scp->unixModeBits & 0222)
3114 && (spi->u.QPstandardInfo.attributes & SMB_ATTR_READONLY) != 0) {
3115 /* make a writable file read-only */
3116 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
3117 attr.unixModeBits = scp->unixModeBits & ~0222;
3119 else if ((scp->unixModeBits & 0222) == 0
3120 && (spi->u.QPstandardInfo.attributes & SMB_ATTR_READONLY) == 0) {
3121 /* make a read-only file writable */
3122 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
3123 attr.unixModeBits = scp->unixModeBits | 0222;
3126 lock_ReleaseMutex(&scp->mx);
3127 lock_ReleaseMutex(&fidp->mx);
3131 code = cm_SetAttr(scp, &attr, userp, &req);
3135 else if (infoLevel == SMB_INFO_QUERY_ALL_EAS) {
3136 /* we don't support EAs */
3137 code = CM_ERROR_INVAL;
3141 cm_ReleaseSCache(scp);
3142 cm_ReleaseUser(userp);
3143 smb_ReleaseFID(fidp);
3145 smb_SendTran2Packet(vcp, outp, opx);
3147 smb_SendTran2Error(vcp, p, opx, code);
3148 smb_FreeTran2Packet(outp);
3154 long smb_ReceiveTran2QFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
3156 smb_tran2Packet_t *outp;
3158 unsigned long attributes;
3159 unsigned short infoLevel;
3166 smb_tran2QFileInfo_t qfi;
3173 fidp = smb_FindFID(vcp, fid, 0);
3176 smb_SendTran2Error(vcp, p, opx, CM_ERROR_BADFD);
3180 infoLevel = p->parmsp[1];
3181 if (infoLevel == SMB_QUERY_FILE_BASIC_INFO)
3182 responseSize = sizeof(qfi.u.QFbasicInfo);
3183 else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO)
3184 responseSize = sizeof(qfi.u.QFstandardInfo);
3185 else if (infoLevel == SMB_QUERY_FILE_EA_INFO)
3186 responseSize = sizeof(qfi.u.QFeaInfo);
3187 else if (infoLevel == SMB_QUERY_FILE_NAME_INFO)
3188 responseSize = sizeof(qfi.u.QFfileNameInfo);
3190 osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
3191 p->opcode, infoLevel);
3192 smb_SendTran2Error(vcp, p, opx, CM_ERROR_BADOP);
3193 smb_ReleaseFID(fidp);
3196 osi_Log2(smb_logp, "T2 QFileInfo type 0x%x fid %d", infoLevel, fid);
3198 outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, responseSize);
3200 if (infoLevel > 0x100)
3201 outp->totalParms = 2;
3203 outp->totalParms = 0;
3204 outp->totalData = responseSize;
3206 userp = smb_GetTran2User(vcp, p);
3208 osi_Log1(smb_logp, "ReceiveTran2QFileInfo unable to resolve user [%d]", p->uid);
3209 code = CM_ERROR_BADSMB;
3213 lock_ObtainMutex(&fidp->mx);
3214 delonclose = fidp->flags & SMB_FID_DELONCLOSE;
3216 osi_Log2(afsd_logp,"smb_ReleaseTran2QFileInfo fidp 0x%p scp 0x%p", fidp, scp);
3218 lock_ReleaseMutex(&fidp->mx);
3219 lock_ObtainMutex(&scp->mx);
3220 code = cm_SyncOp(scp, NULL, userp, &req, 0,
3221 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3225 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3227 /* now we have the status in the cache entry, and everything is locked.
3228 * Marshall the output data.
3230 if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
3231 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
3232 qfi.u.QFbasicInfo.creationTime = ft;
3233 qfi.u.QFbasicInfo.lastAccessTime = ft;
3234 qfi.u.QFbasicInfo.lastWriteTime = ft;
3235 qfi.u.QFbasicInfo.lastChangeTime = ft;
3236 attributes = smb_ExtAttributes(scp);
3237 qfi.u.QFbasicInfo.attributes = attributes;
3239 else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO) {
3240 qfi.u.QFstandardInfo.allocationSize = scp->length;
3241 qfi.u.QFstandardInfo.endOfFile = scp->length;
3242 qfi.u.QFstandardInfo.numberOfLinks = scp->linkCount;
3243 qfi.u.QFstandardInfo.deletePending = (delonclose ? 1 : 0);
3244 qfi.u.QFstandardInfo.directory =
3245 ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
3246 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
3247 scp->fileType == CM_SCACHETYPE_INVALID)? 1 : 0);
3249 else if (infoLevel == SMB_QUERY_FILE_EA_INFO) {
3250 qfi.u.QFeaInfo.eaSize = 0;
3252 else if (infoLevel == SMB_QUERY_FILE_NAME_INFO) {
3256 lock_ReleaseMutex(&scp->mx);
3257 lock_ObtainMutex(&fidp->mx);
3258 lock_ObtainMutex(&scp->mx);
3259 if (fidp->NTopen_wholepathp)
3260 name = fidp->NTopen_wholepathp;
3262 name = "\\"; /* probably can't happen */
3263 lock_ReleaseMutex(&fidp->mx);
3264 len = (unsigned long)strlen(name);
3265 outp->totalData = ((len+1)*2) + 4; /* this is actually what we want to return */
3266 qfi.u.QFfileNameInfo.fileNameLength = (len + 1) * 2;
3267 mbstowcs((unsigned short *)qfi.u.QFfileNameInfo.fileName, name, len + 1);
3270 /* send and free the packets */
3272 lock_ReleaseMutex(&scp->mx);
3273 cm_ReleaseSCache(scp);
3274 cm_ReleaseUser(userp);
3275 smb_ReleaseFID(fidp);
3277 memcpy(outp->datap, &qfi, responseSize);
3278 smb_SendTran2Packet(vcp, outp, opx);
3280 smb_SendTran2Error(vcp, p, opx, code);
3282 smb_FreeTran2Packet(outp);
3287 long smb_ReceiveTran2SetFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
3292 unsigned short infoLevel;
3293 smb_tran2Packet_t *outp;
3301 fidp = smb_FindFID(vcp, fid, 0);
3304 smb_SendTran2Error(vcp, p, opx, CM_ERROR_BADFD);
3308 infoLevel = p->parmsp[1];
3309 osi_Log2(smb_logp,"ReceiveTran2SetFileInfo type 0x%x fid %d", infoLevel, fid);
3310 if (infoLevel > SMB_SET_FILE_END_OF_FILE_INFO || infoLevel < SMB_SET_FILE_BASIC_INFO) {
3311 osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
3312 p->opcode, infoLevel);
3313 smb_SendTran2Error(vcp, p, opx, CM_ERROR_BADOP);
3314 smb_ReleaseFID(fidp);
3318 lock_ObtainMutex(&fidp->mx);
3319 if (infoLevel == SMB_SET_FILE_DISPOSITION_INFO && !(fidp->flags & SMB_FID_OPENDELETE)) {
3320 lock_ReleaseMutex(&fidp->mx);
3321 smb_ReleaseFID(fidp);
3322 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOACCESS);
3325 if ((infoLevel == SMB_SET_FILE_ALLOCATION_INFO ||
3326 infoLevel == SMB_SET_FILE_END_OF_FILE_INFO)
3327 && !(fidp->flags & SMB_FID_OPENWRITE)) {
3328 lock_ReleaseMutex(&fidp->mx);
3329 smb_ReleaseFID(fidp);
3330 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOACCESS);
3335 osi_Log2(afsd_logp,"smb_ReceiveTran2SetFileInfo fidp 0x%p scp 0x%p", fidp, scp);
3337 lock_ReleaseMutex(&fidp->mx);
3339 outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, 0);
3341 outp->totalParms = 2;
3342 outp->totalData = 0;
3344 userp = smb_GetTran2User(vcp, p);
3346 osi_Log1(smb_logp,"ReceiveTran2SetFileInfo unable to resolve user [%d]", p->uid);
3347 code = CM_ERROR_BADSMB;
3351 if (infoLevel == SMB_SET_FILE_BASIC_INFO) {
3353 unsigned int attribute;
3355 smb_tran2QFileInfo_t *sfi;
3357 sfi = (smb_tran2QFileInfo_t *)p->datap;
3359 /* lock the vnode with a callback; we need the current status
3360 * to determine what the new status is, in some cases.
3362 lock_ObtainMutex(&scp->mx);
3363 code = cm_SyncOp(scp, NULL, userp, &req, 0,
3364 CM_SCACHESYNC_GETSTATUS
3365 | CM_SCACHESYNC_NEEDCALLBACK);
3367 lock_ReleaseMutex(&scp->mx);
3371 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3373 lock_ReleaseMutex(&scp->mx);
3374 lock_ObtainMutex(&fidp->mx);
3375 lock_ObtainMutex(&scp->mx);
3377 /* prepare for setattr call */
3380 lastMod = sfi->u.QFbasicInfo.lastWriteTime;
3381 /* when called as result of move a b, lastMod is (-1, -1).
3382 * If the check for -1 is not present, timestamp
3383 * of the resulting file will be 1969 (-1)
3385 if (LargeIntegerNotEqualToZero(*((LARGE_INTEGER *)&lastMod)) &&
3386 lastMod.dwLowDateTime != -1 && lastMod.dwHighDateTime != -1) {
3387 attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
3388 smb_UnixTimeFromLargeSearchTime(&attr.clientModTime, &lastMod);
3389 fidp->flags |= SMB_FID_MTIMESETDONE;
3392 attribute = sfi->u.QFbasicInfo.attributes;
3393 if (attribute != 0) {
3394 if ((scp->unixModeBits & 0222)
3395 && (attribute & SMB_ATTR_READONLY) != 0) {
3396 /* make a writable file read-only */
3397 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
3398 attr.unixModeBits = scp->unixModeBits & ~0222;
3400 else if ((scp->unixModeBits & 0222) == 0
3401 && (attribute & SMB_ATTR_READONLY) == 0) {
3402 /* make a read-only file writable */
3403 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
3404 attr.unixModeBits = scp->unixModeBits | 0222;
3407 lock_ReleaseMutex(&scp->mx);
3408 lock_ReleaseMutex(&fidp->mx);
3412 code = cm_SetAttr(scp, &attr, userp, &req);
3416 else if (infoLevel == SMB_SET_FILE_DISPOSITION_INFO) {
3417 if (*((char *)(p->datap))) { /* File is Deleted */
3418 code = cm_CheckNTDelete(fidp->NTopen_dscp, scp, userp,
3421 lock_ObtainMutex(&fidp->mx);
3422 fidp->flags |= SMB_FID_DELONCLOSE;
3423 lock_ReleaseMutex(&fidp->mx);
3428 lock_ObtainMutex(&fidp->mx);
3429 fidp->flags &= ~SMB_FID_DELONCLOSE;
3430 lock_ReleaseMutex(&fidp->mx);
3433 else if (infoLevel == SMB_SET_FILE_ALLOCATION_INFO ||
3434 infoLevel == SMB_SET_FILE_END_OF_FILE_INFO) {
3435 LARGE_INTEGER size = *((LARGE_INTEGER *)(p->datap));
3438 attr.mask = CM_ATTRMASK_LENGTH;
3439 attr.length.LowPart = size.LowPart;
3440 attr.length.HighPart = size.HighPart;
3441 code = cm_SetAttr(scp, &attr, userp, &req);
3445 cm_ReleaseSCache(scp);
3446 cm_ReleaseUser(userp);
3447 smb_ReleaseFID(fidp);
3449 smb_SendTran2Packet(vcp, outp, opx);
3451 smb_SendTran2Error(vcp, p, opx, code);
3452 smb_FreeTran2Packet(outp);
3458 smb_ReceiveTran2FSCTL(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3460 osi_Log0(smb_logp,"ReceiveTran2FSCTL - NOT_SUPPORTED");
3461 return CM_ERROR_BADOP;
3465 smb_ReceiveTran2IOCTL(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3467 osi_Log0(smb_logp,"ReceiveTran2IOCTL - NOT_SUPPORTED");
3468 return CM_ERROR_BADOP;
3472 smb_ReceiveTran2FindNotifyFirst(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3474 osi_Log0(smb_logp,"ReceiveTran2FindNotifyFirst - NOT_SUPPORTED");
3475 return CM_ERROR_BADOP;
3479 smb_ReceiveTran2FindNotifyNext(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3481 osi_Log0(smb_logp,"ReceiveTran2FindNotifyNext - NOT_SUPPORTED");
3482 return CM_ERROR_BADOP;
3486 smb_ReceiveTran2CreateDirectory(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3488 osi_Log0(smb_logp,"ReceiveTran2CreateDirectory - NOT_SUPPORTED");
3489 return CM_ERROR_BADOP;
3493 smb_ReceiveTran2SessionSetup(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3495 osi_Log0(smb_logp,"ReceiveTran2SessionSetup - NOT_SUPPORTED");
3496 return CM_ERROR_BADOP;
3499 struct smb_v2_referral {
3501 USHORT ReferralFlags;
3504 USHORT DfsPathOffset;
3505 USHORT DfsAlternativePathOffset;
3506 USHORT NetworkAddressOffset;
3510 smb_ReceiveTran2GetDFSReferral(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
3512 /* This is a UNICODE only request (bit15 of Flags2) */
3513 /* The TID must be IPC$ */
3515 /* The documentation for the Flags response field is contradictory */
3517 /* Use Version 1 Referral Element Format */
3518 /* ServerType = 0; indicates the next server should be queried for the file */
3519 /* ReferralFlags = 0x01; PathConsumed characters should be stripped */
3520 /* Node = UnicodeString of UNC path of the next share name */
3523 int maxReferralLevel = 0;
3524 char requestFileName[1024] = "";
3525 smb_tran2Packet_t *outp = 0;
3526 cm_user_t *userp = 0;
3528 CPINFO CodePageInfo;
3529 int i, nbnLen, reqLen;
3534 maxReferralLevel = p->parmsp[0];
3536 GetCPInfo(CP_ACP, &CodePageInfo);
3537 WideCharToMultiByte(CP_ACP, 0, (LPCWSTR) &p->parmsp[1], -1,
3538 requestFileName, 1024, NULL, NULL);
3540 osi_Log2(smb_logp,"ReceiveTran2GetDfsReferral [%d][%s]",
3541 maxReferralLevel, osi_LogSaveString(smb_logp, requestFileName));
3543 nbnLen = strlen(cm_NetbiosName);
3544 reqLen = strlen(requestFileName);
3546 if (reqLen == nbnLen + 5 &&
3547 requestFileName[0] == '\\' &&
3548 !_strnicmp(cm_NetbiosName,&requestFileName[1],nbnLen) &&
3549 requestFileName[nbnLen+1] == '\\' &&
3550 (!_strnicmp("all",&requestFileName[nbnLen+2],3) ||
3551 !_strnicmp("*.",&requestFileName[nbnLen+2],2)))
3554 struct smb_v2_referral * v2ref;
3555 outp = smb_GetTran2ResponsePacket(vcp, p, op, 0, 2 * (reqLen + 8));
3557 sp = (USHORT *)outp->datap;
3559 sp[idx++] = reqLen; /* path consumed */
3560 sp[idx++] = 1; /* number of referrals */
3561 sp[idx++] = 0x03; /* flags */
3562 #ifdef DFS_VERSION_1
3563 sp[idx++] = 1; /* Version Number */
3564 sp[idx++] = reqLen + 4; /* Referral Size */
3565 sp[idx++] = 1; /* Type = SMB Server */
3566 sp[idx++] = 0; /* Do not strip path consumed */
3567 for ( i=0;i<=reqLen; i++ )
3568 sp[i+idx] = requestFileName[i];
3569 #else /* DFS_VERSION_2 */
3570 sp[idx++] = 2; /* Version Number */
3571 sp[idx++] = sizeof(struct smb_v2_referral); /* Referral Size */
3572 idx += (sizeof(struct smb_v2_referral) / 2);
3573 v2ref = (struct smb_v2_referral *) &sp[5];
3574 v2ref->ServerType = 1; /* SMB Server */
3575 v2ref->ReferralFlags = 0x03;
3576 v2ref->Proximity = 0; /* closest */
3577 v2ref->TimeToLive = 3600; /* seconds */
3578 v2ref->DfsPathOffset = idx * 2;
3579 v2ref->DfsAlternativePathOffset = idx * 2;
3580 v2ref->NetworkAddressOffset = 0;
3581 for ( i=0;i<=reqLen; i++ )
3582 sp[i+idx] = requestFileName[i];
3585 userp = smb_GetTran2User(vcp, p);
3587 osi_Log1(smb_logp,"ReceiveTran2GetDfsReferral unable to resolve user [%d]", p->uid);
3588 code = CM_ERROR_BADSMB;
3593 code = CM_ERROR_NOSUCHPATH;
3598 cm_ReleaseUser(userp);
3600 smb_SendTran2Packet(vcp, outp, op);
3602 smb_SendTran2Error(vcp, p, op, code);
3604 smb_FreeTran2Packet(outp);
3607 #else /* DFS_SUPPORT */
3608 osi_Log0(smb_logp,"ReceiveTran2GetDfsReferral - NOT_SUPPORTED");
3609 return CM_ERROR_BADOP;
3610 #endif /* DFS_SUPPORT */
3614 smb_ReceiveTran2ReportDFSInconsistency(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3616 /* This is a UNICODE only request (bit15 of Flags2) */
3618 /* There is nothing we can do about this operation. The client is going to
3619 * tell us that there is a Version 1 Referral Element for which there is a DFS Error.
3620 * Unfortunately, there is really nothing we can do about it other then log it
3621 * somewhere. Even then I don't think there is anything for us to do.
3622 * So let's return an error value.
3625 osi_Log0(smb_logp,"ReceiveTran2ReportDFSInconsistency - NOT_SUPPORTED");
3626 return CM_ERROR_BADOP;
3630 smb_ApplyV3DirListPatches(cm_scache_t *dscp,
3631 smb_dirListPatch_t **dirPatchespp, int infoLevel, cm_user_t *userp,
3636 cm_scache_t *targetScp; /* target if scp is a symlink */
3641 unsigned short attr;
3642 unsigned long lattr;
3643 smb_dirListPatch_t *patchp;
3644 smb_dirListPatch_t *npatchp;
3646 for(patchp = *dirPatchespp; patchp; patchp =
3647 (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
3648 code = cm_GetSCache(&patchp->fid, &scp, userp, reqp);
3650 lock_ObtainMutex(&scp->mx);
3651 code = cm_SyncOp(scp, NULL, userp, reqp, 0,
3652 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3654 lock_ReleaseMutex(&scp->mx);
3655 cm_ReleaseSCache(scp);
3657 dptr = patchp->dptr;
3659 /* Plug in fake timestamps. A time stamp of 0 causes 'invalid parameter'
3660 errors in the client. */
3661 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO) {
3662 /* 1969-12-31 23:59:59 +00 */
3663 ft.dwHighDateTime = 0x19DB200;
3664 ft.dwLowDateTime = 0x5BB78980;
3666 /* copy to Creation Time */
3667 *((FILETIME *)dptr) = ft;
3670 /* copy to Last Access Time */
3671 *((FILETIME *)dptr) = ft;
3674 /* copy to Last Write Time */
3675 *((FILETIME *)dptr) = ft;
3678 /* copy to Change Time */
3679 *((FILETIME *)dptr) = ft;
3682 /* merge in hidden attribute */
3683 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
3684 *((u_long *)dptr) = SMB_ATTR_HIDDEN;
3688 /* 1969-12-31 23:59:58 +00*/
3689 dosTime = 0xEBBFBF7D;
3691 /* and copy out date */
3692 shortTemp = (dosTime>>16) & 0xffff;
3693 *((u_short *)dptr) = shortTemp;
3696 /* copy out creation time */
3697 shortTemp = dosTime & 0xffff;
3698 *((u_short *)dptr) = shortTemp;
3701 /* and copy out date */
3702 shortTemp = (dosTime>>16) & 0xffff;
3703 *((u_short *)dptr) = shortTemp;
3706 /* copy out access time */
3707 shortTemp = dosTime & 0xffff;
3708 *((u_short *)dptr) = shortTemp;
3711 /* and copy out date */
3712 shortTemp = (dosTime>>16) & 0xffff;
3713 *((u_short *)dptr) = shortTemp;
3716 /* copy out mod time */
3717 shortTemp = dosTime & 0xffff;
3718 *((u_short *)dptr) = shortTemp;
3721 /* merge in hidden (dot file) attribute */
3722 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
3723 attr = SMB_ATTR_HIDDEN;
3724 *dptr++ = attr & 0xff;
3725 *dptr++ = (attr >> 8) & 0xff;
3731 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3733 /* now watch for a symlink */
3735 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
3736 lock_ReleaseMutex(&scp->mx);
3737 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, reqp);
3739 /* we have a more accurate file to use (the
3740 * target of the symbolic link). Otherwise,
3741 * we'll just use the symlink anyway.
3743 osi_Log2(smb_logp, "symlink vp %x to vp %x",
3745 cm_ReleaseSCache(scp);
3748 lock_ObtainMutex(&scp->mx);
3751 dptr = patchp->dptr;
3753 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO) {
3755 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
3757 /* copy to Creation Time */
3758 *((FILETIME *)dptr) = ft;
3761 /* copy to Last Access Time */
3762 *((FILETIME *)dptr) = ft;
3765 /* copy to Last Write Time */
3766 *((FILETIME *)dptr) = ft;
3769 /* copy to Change Time */
3770 *((FILETIME *)dptr) = ft;
3773 /* Use length for both file length and alloc length */
3774 *((LARGE_INTEGER *)dptr) = scp->length;
3776 *((LARGE_INTEGER *)dptr) = scp->length;
3779 /* Copy attributes */
3780 lattr = smb_ExtAttributes(scp);
3781 if (code == CM_ERROR_NOSUCHPATH && scp->fileType == CM_SCACHETYPE_SYMLINK) {
3782 if (lattr == SMB_ATTR_NORMAL)
3783 lattr = SMB_ATTR_DIRECTORY;
3785 lattr |= SMB_ATTR_DIRECTORY;
3787 /* merge in hidden (dot file) attribute */
3788 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
3789 if (lattr == SMB_ATTR_NORMAL)
3790 lattr = SMB_ATTR_HIDDEN;
3792 lattr |= SMB_ATTR_HIDDEN;
3794 *((u_long *)dptr) = lattr;
3798 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
3800 /* and copy out date */
3801 shortTemp = (dosTime>>16) & 0xffff;
3802 *((u_short *)dptr) = shortTemp;
3805 /* copy out creation time */
3806 shortTemp = dosTime & 0xffff;
3807 *((u_short *)dptr) = shortTemp;
3810 /* and copy out date */
3811 shortTemp = (dosTime>>16) & 0xffff;
3812 *((u_short *)dptr) = shortTemp;
3815 /* copy out access time */
3816 shortTemp = dosTime & 0xffff;
3817 *((u_short *)dptr) = shortTemp;
3820 /* and copy out date */
3821 shortTemp = (dosTime>>16) & 0xffff;
3822 *((u_short *)dptr) = shortTemp;
3825 /* copy out mod time */
3826 shortTemp = dosTime & 0xffff;
3827 *((u_short *)dptr) = shortTemp;
3830 /* copy out file length and alloc length,
3831 * using the same for both
3833 *((u_long *)dptr) = scp->length.LowPart;
3835 *((u_long *)dptr) = scp->length.LowPart;
3838 /* finally copy out attributes as short */
3839 attr = smb_Attributes(scp);
3840 /* merge in hidden (dot file) attribute */
3841 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
3842 if (lattr == SMB_ATTR_NORMAL)
3843 lattr = SMB_ATTR_HIDDEN;
3845 lattr |= SMB_ATTR_HIDDEN;
3847 *dptr++ = attr & 0xff;
3848 *dptr++ = (attr >> 8) & 0xff;
3851 lock_ReleaseMutex(&scp->mx);
3852 cm_ReleaseSCache(scp);
3855 /* now free the patches */
3856 for (patchp = *dirPatchespp; patchp; patchp = npatchp) {
3857 npatchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q);
3861 /* and mark the list as empty */
3862 *dirPatchespp = NULL;
3867 #ifndef USE_OLD_MATCHING
3868 // char table for case insensitive comparison
3869 char mapCaseTable[256];
3871 VOID initUpperCaseTable(VOID)
3874 for (i = 0; i < 256; ++i)
3875 mapCaseTable[i] = toupper(i);
3876 // make '"' match '.'
3877 mapCaseTable[(int)'"'] = toupper('.');
3878 // make '<' match '*'
3879 mapCaseTable[(int)'<'] = toupper('*');
3880 // make '>' match '?'
3881 mapCaseTable[(int)'>'] = toupper('?');
3884 // Compare 'pattern' (containing metacharacters '*' and '?') with the file
3886 // Note : this procedure works recursively calling itself.
3888 // PSZ pattern : string containing metacharacters.
3889 // PSZ name : file name to be compared with 'pattern'.
3891 // BOOL : TRUE/FALSE (match/mistmatch)
3894 szWildCardMatchFileName(PSZ pattern, PSZ name, int casefold)
3896 PSZ pename; // points to the last 'name' character
3898 pename = name + strlen(name) - 1;
3909 if (*pattern == '\0')
3911 for (p = pename; p >= name; --p) {
3912 if ((casefold && (mapCaseTable[*p] == mapCaseTable[*pattern]) ||
3913 !casefold && (*p == *pattern)) &&
3914 szWildCardMatchFileName(pattern + 1, p + 1, casefold))
3919 if ((casefold && mapCaseTable[*name] != mapCaseTable[*pattern]) ||
3920 (!casefold && *name != *pattern))
3927 /* if all we have left are wildcards, then we match */
3928 for (;*pattern; pattern++) {
3929 if (*pattern != '*' && *pattern != '?')
3935 /* do a case-folding search of the star name mask with the name in namep.
3936 * Return 1 if we match, otherwise 0.
3938 int smb_V3MatchMask(char *namep, char *maskp, int flags)
3941 int i, j, star, qmark, casefold, retval;
3943 /* make sure we only match 8.3 names, if requested */
3944 if ((flags & CM_FLAG_8DOT3) && !cm_Is8Dot3(namep))
3947 casefold = (flags & CM_FLAG_CASEFOLD) ? 1 : 0;
3949 /* optimize the pattern:
3950 * if there is a mixture of '?' and '*',
3951 * for example the sequence "*?*?*?*"
3952 * must be turned into the form "*"
3954 newmask = (char *)malloc(strlen(maskp)+1);
3955 for ( i=0, j=0, star=0, qmark=0; maskp[i]; i++) {
3956 switch ( maskp[i] ) {
3968 } else if ( qmark ) {
3972 newmask[j++] = maskp[i];
3979 } else if ( qmark ) {
3983 newmask[j++] = '\0';
3985 retval = szWildCardMatchFileName(newmask, namep, casefold) ? 1:0;
3991 #else /* USE_OLD_MATCHING */
3992 /* do a case-folding search of the star name mask with the name in namep.
3993 * Return 1 if we match, otherwise 0.
3995 int smb_V3MatchMask(char *namep, char *maskp, int flags)
3997 unsigned char tcp1, tcp2; /* Pattern characters */
3998 unsigned char tcn1; /* Name characters */
3999 int sawDot = 0, sawStar = 0, req8dot3 = 0;
4000 char *starNamep, *starMaskp;
4001 static char nullCharp[] = {0};
4002 int casefold = flags & CM_FLAG_CASEFOLD;
4004 /* make sure we only match 8.3 names, if requested */
4005 req8dot3 = (flags & CM_FLAG_8DOT3);
4006 if (req8dot3 && !cm_Is8Dot3(namep))
4011 /* Next pattern character */
4014 /* Next name character */
4018 /* 0 - end of pattern */
4024 else if (tcp1 == '.' || tcp1 == '"') {
4034 * first dot in pattern;
4035 * must match dot or end of name
4040 else if (tcn1 == '.') {
4049 else if (tcp1 == '?') {
4050 if (tcn1 == 0 || tcn1 == '.')
4055 else if (tcp1 == '>') {
4056 if (tcn1 != 0 && tcn1 != '.')
4060 else if (tcp1 == '*' || tcp1 == '<') {
4064 else if ((req8dot3 && tcp2 == '.') || tcp2 == '"') {
4065 while (req8dot3 && tcn1 != '.' && tcn1 != 0)
4080 * pattern character after '*' is not null or
4081 * period. If it is '?' or '>', we are not
4082 * going to understand it. If it is '*' or
4083 * '<', we are going to skip over it. None of
4084 * these are likely, I hope.
4086 /* skip over '*' and '<' */
4087 while (tcp2 == '*' || tcp2 == '<')
4090 /* skip over characters that don't match tcp2 */
4091 while (req8dot3 && tcn1 != '.' && tcn1 != 0 &&
4092 ((casefold && cm_foldUpper[tcn1] != cm_foldUpper[tcp2]) ||
4093 (!casefold && tcn1 != tcp2)))
4097 if ((req8dot3 && tcn1 == '.') || tcn1 == 0)
4100 /* Remember where we are */
4110 /* tcp1 is not a wildcard */
4111 if ((casefold && cm_foldUpper[tcn1] == cm_foldUpper[tcp1]) ||
4112 (!casefold && tcn1 == tcp1)) {
4117 /* if trying to match a star pattern, go back */
4119 maskp = starMaskp - 2;
4120 namep = starNamep + 1;
4129 #endif /* USE_OLD_MATCHING */
4131 long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
4136 long code = 0, code2 = 0;
4140 smb_dirListPatch_t *dirListPatchesp;
4141 smb_dirListPatch_t *curPatchp;
4144 long orbytes; /* # of bytes in this output record */
4145 long ohbytes; /* # of bytes, except file name */
4146 long onbytes; /* # of bytes in name, incl. term. null */
4147 osi_hyper_t dirLength;
4148 osi_hyper_t bufferOffset;
4149 osi_hyper_t curOffset;
4151 smb_dirSearch_t *dsp;
4155 cm_pageHeader_t *pageHeaderp;
4156 cm_user_t *userp = NULL;
4159 long nextEntryCookie;
4160 int numDirChunks; /* # of 32 byte dir chunks in this entry */
4161 char *op; /* output data ptr */
4162 char *origOp; /* original value of op */
4163 cm_space_t *spacep; /* for pathname buffer */
4164 long maxReturnData; /* max # of return data */
4165 long maxReturnParms; /* max # of return parms */
4166 long bytesInBuffer; /* # data bytes in the output buffer */
4168 char *maskp; /* mask part of path */
4172 smb_tran2Packet_t *outp; /* response packet */
4175 char shortName[13]; /* 8.3 name if needed */
4187 if (p->opcode == 1) {
4188 /* find first; obtain basic parameters from request */
4189 attribute = p->parmsp[0];
4190 maxCount = p->parmsp[1];
4191 infoLevel = p->parmsp[3];
4192 searchFlags = p->parmsp[2];
4193 dsp = smb_NewDirSearch(1);
4194 dsp->attribute = attribute;
4195 pathp = ((char *) p->parmsp) + 12; /* points to path */
4196 if (smb_StoreAnsiFilenames)
4197 OemToChar(pathp,pathp);
4199 maskp = strrchr(pathp, '\\');
4203 maskp++; /* skip over backslash */
4204 strcpy(dsp->mask, maskp); /* and save mask */
4205 /* track if this is likely to match a lot of entries */
4206 starPattern = smb_V3IsStarMask(maskp);
4209 osi_assert(p->opcode == 2);
4210 /* find next; obtain basic parameters from request or open dir file */
4211 dsp = smb_FindDirSearch(p->parmsp[0]);
4212 maxCount = p->parmsp[1];
4213 infoLevel = p->parmsp[2];
4214 nextCookie = p->parmsp[3] | (p->parmsp[4] << 16);
4215 searchFlags = p->parmsp[5];
4217 osi_Log2(smb_logp, "T2 search dir bad search ID: id %d nextCookie 0x%x",
4218 p->parmsp[0], nextCookie);
4219 return CM_ERROR_BADFD;
4221 attribute = dsp->attribute;
4224 starPattern = 1; /* assume, since required a Find Next */
4227 switch ( infoLevel ) {
4228 case SMB_INFO_STANDARD:
4231 case SMB_INFO_QUERY_EA_SIZE:
4232 s = "InfoQueryEaSize";
4234 case SMB_INFO_QUERY_EAS_FROM_LIST:
4235 s = "InfoQueryEasFromList";
4237 case SMB_FIND_FILE_DIRECTORY_INFO:
4238 s = "FindFileDirectoryInfo";
4240 case SMB_FIND_FILE_FULL_DIRECTORY_INFO:
4241 s = "FindFileFullDirectoryInfo";
4243 case SMB_FIND_FILE_NAMES_INFO:
4244 s = "FindFileNamesInfo";
4246 case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
4247 s = "FindFileBothDirectoryInfo";
4250 s = "unknownInfoLevel";
4253 osi_Log1(smb_logp, "T2 search dir info level: %s", s);
4256 "T2 search dir attr 0x%x, info level 0x%x, max count %d, flags 0x%x",
4257 attribute, infoLevel, maxCount, searchFlags);
4259 osi_Log3(smb_logp, "...T2 search op %d, id %d, nextCookie 0x%x",
4260 p->opcode, dsp->cookie, nextCookie);
4262 if (infoLevel > SMB_FIND_FILE_BOTH_DIRECTORY_INFO) {
4263 osi_Log1(smb_logp, "Unsupported InfoLevel 0x%x", infoLevel);
4264 smb_ReleaseDirSearch(dsp);
4265 return CM_ERROR_INVAL;
4268 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO)
4269 searchFlags &= ~4; /* no resume keys */
4271 dirListPatchesp = NULL;
4273 maxReturnData = p->maxReturnData;
4274 if (p->opcode == 1) /* find first */
4275 maxReturnParms = 10; /* bytes */
4277 maxReturnParms = 8; /* bytes */
4279 #ifndef CM_CONFIG_MULTITRAN2RESPONSES
4280 if (maxReturnData > 6000)
4281 maxReturnData = 6000;
4282 #endif /* CM_CONFIG_MULTITRAN2RESPONSES */
4284 outp = smb_GetTran2ResponsePacket(vcp, p, opx, maxReturnParms,
4287 osi_Log2(smb_logp, "T2 receive search dir count %d [%s]",
4288 maxCount, osi_LogSaveString(smb_logp, pathp));
4290 /* bail out if request looks bad */
4291 if (p->opcode == 1 && !pathp) {
4292 smb_ReleaseDirSearch(dsp);
4293 smb_FreeTran2Packet(outp);
4294 return CM_ERROR_BADSMB;
4297 osi_Log3(smb_logp, "T2 search dir id %d, nextCookie 0x%x, attr 0x%x",
4298 dsp->cookie, nextCookie, attribute);
4300 userp = smb_GetTran2User(vcp, p);
4302 osi_Log1(smb_logp, "T2 search dir unable to resolve user [%d]", p->uid);
4303 smb_ReleaseDirSearch(dsp);
4304 smb_FreeTran2Packet(outp);
4305 return CM_ERROR_BADSMB;
4308 /* try to get the vnode for the path name next */
4309 lock_ObtainMutex(&dsp->mx);
4312 osi_Log2(afsd_logp,"smb_ReceiveTran2SearchDir dsp 0x%p scp 0x%p", dsp, scp);
4316 spacep = cm_GetSpace();
4317 smb_StripLastComponent(spacep->data, NULL, pathp);
4318 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
4320 cm_ReleaseUser(userp);
4321 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOFILES);
4322 smb_FreeTran2Packet(outp);
4323 lock_ReleaseMutex(&dsp->mx);
4324 smb_DeleteDirSearch(dsp);
4325 smb_ReleaseDirSearch(dsp);
4328 code = cm_NameI(cm_data.rootSCachep, spacep->data,
4329 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
4330 userp, tidPathp, &req, &scp);
4331 cm_FreeSpace(spacep);
4334 #ifdef DFS_SUPPORT_BUT_NOT_FIND_FIRST
4335 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
4336 cm_ReleaseSCache(scp);
4337 cm_ReleaseUser(userp);
4338 if ( WANTS_DFS_PATHNAMES(p) )
4339 code = CM_ERROR_PATH_NOT_COVERED;
4341 code = CM_ERROR_BADSHARENAME;
4342 smb_SendTran2Error(vcp, p, opx, code);
4343 smb_FreeTran2Packet(outp);
4344 lock_ReleaseMutex(&dsp->mx);
4345 smb_DeleteDirSearch(dsp);
4346 smb_ReleaseDirSearch(dsp);
4349 #endif /* DFS_SUPPORT */
4351 osi_Log2(afsd_logp,"smb_ReceiveTran2SearchDir dsp 0x%p scp 0x%p", dsp, scp);
4352 /* we need one hold for the entry we just stored into,
4353 * and one for our own processing. When we're done
4354 * with this function, we'll drop the one for our own
4355 * processing. We held it once from the namei call,
4356 * and so we do another hold now.
4359 lock_ObtainMutex(&scp->mx);
4360 if ((scp->flags & CM_SCACHEFLAG_BULKSTATTING) == 0 &&
4361 LargeIntegerGreaterOrEqualToZero(scp->bulkStatProgress)) {
4362 scp->flags |= CM_SCACHEFLAG_BULKSTATTING;
4363 dsp->flags |= SMB_DIRSEARCH_BULKST;
4365 lock_ReleaseMutex(&scp->mx);
4368 lock_ReleaseMutex(&dsp->mx);
4370 cm_ReleaseUser(userp);
4371 smb_FreeTran2Packet(outp);
4372 smb_DeleteDirSearch(dsp);
4373 smb_ReleaseDirSearch(dsp);
4377 /* get the directory size */
4378 lock_ObtainMutex(&scp->mx);
4379 code = cm_SyncOp(scp, NULL, userp, &req, 0,
4380 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4382 lock_ReleaseMutex(&scp->mx);
4383 cm_ReleaseSCache(scp);
4384 cm_ReleaseUser(userp);
4385 smb_FreeTran2Packet(outp);
4386 smb_DeleteDirSearch(dsp);
4387 smb_ReleaseDirSearch(dsp);
4391 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4394 dirLength = scp->length;
4396 bufferOffset.LowPart = bufferOffset.HighPart = 0;
4397 curOffset.HighPart = 0;
4398 curOffset.LowPart = nextCookie;
4399 origOp = outp->datap;
4407 if (searchFlags & 4)
4408 /* skip over resume key */
4411 /* make sure that curOffset.LowPart doesn't point to the first
4412 * 32 bytes in the 2nd through last dir page, and that it doesn't
4413 * point at the first 13 32-byte chunks in the first dir page,
4414 * since those are dir and page headers, and don't contain useful
4417 temp = curOffset.LowPart & (2048-1);
4418 if (curOffset.HighPart == 0 && curOffset.LowPart < 2048) {
4419 /* we're in the first page */
4420 if (temp < 13*32) temp = 13*32;
4423 /* we're in a later dir page */
4424 if (temp < 32) temp = 32;
4427 /* make sure the low order 5 bits are zero */
4430 /* now put temp bits back ito curOffset.LowPart */
4431 curOffset.LowPart &= ~(2048-1);
4432 curOffset.LowPart |= temp;
4434 /* check if we've passed the dir's EOF */
4435 if (LargeIntegerGreaterThanOrEqualTo(curOffset, dirLength)) {
4436 osi_Log0(smb_logp, "T2 search dir passed eof");
4441 /* check if we've returned all the names that will fit in the
4442 * response packet; we check return count as well as the number
4443 * of bytes requested. We check the # of bytes after we find
4444 * the dir entry, since we'll need to check its size.
4446 if (returnedNames >= maxCount) {
4447 osi_Log2(smb_logp, "T2 search dir returnedNames %d >= maxCount %d",
4448 returnedNames, maxCount);
4452 /* see if we can use the bufferp we have now; compute in which
4453 * page the current offset would be, and check whether that's
4454 * the offset of the buffer we have. If not, get the buffer.
4456 thyper.HighPart = curOffset.HighPart;
4457 thyper.LowPart = curOffset.LowPart & ~(cm_data.buf_blockSize-1);
4458 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
4461 buf_Release(bufferp);
4464 lock_ReleaseMutex(&scp->mx);
4465 lock_ObtainRead(&scp->bufCreateLock);
4466 code = buf_Get(scp, &thyper, &bufferp);
4467 lock_ReleaseRead(&scp->bufCreateLock);
4468 lock_ObtainMutex(&dsp->mx);
4470 /* now, if we're doing a star match, do bulk fetching
4471 * of all of the status info for files in the dir.
4474 smb_ApplyV3DirListPatches(scp, &dirListPatchesp,
4477 lock_ObtainMutex(&scp->mx);
4478 if ((dsp->flags & SMB_DIRSEARCH_BULKST) &&
4479 LargeIntegerGreaterThanOrEqualTo(thyper, scp->bulkStatProgress)) {
4480 /* Don't bulk stat if risking timeout */
4481 int now = GetTickCount();
4482 if (now - req.startTime > RDRtimeout) {
4483 scp->bulkStatProgress = thyper;
4484 scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
4485 dsp->flags &= ~SMB_DIRSEARCH_BULKST;
4487 code = cm_TryBulkStat(scp, &thyper, userp, &req);
4490 lock_ObtainMutex(&scp->mx);
4492 lock_ReleaseMutex(&dsp->mx);
4494 osi_Log2(smb_logp, "T2 search dir buf_Get scp %x failed %d", scp, code);
4498 bufferOffset = thyper;
4500 /* now get the data in the cache */
4502 code = cm_SyncOp(scp, bufferp, userp, &req,
4504 CM_SCACHESYNC_NEEDCALLBACK
4505 | CM_SCACHESYNC_READ);
4507 osi_Log2(smb_logp, "T2 search dir cm_SyncOp scp %x failed %d", scp, code);
4511 cm_SyncOpDone(scp, bufferp, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ);
4513 if (cm_HaveBuffer(scp, bufferp, 0)) {
4514 osi_Log2(smb_logp, "T2 search dir !HaveBuffer scp %x bufferp %x", scp, bufferp);
4518 /* otherwise, load the buffer and try again */
4519 code = cm_GetBuffer(scp, bufferp, NULL, userp,
4522 osi_Log3(smb_logp, "T2 search dir cm_GetBuffer failed scp %x bufferp %x code %d",
4523 scp, bufferp, code);
4528 buf_Release(bufferp);
4532 } /* if (wrong buffer) ... */
4534 /* now we have the buffer containing the entry we're interested
4535 * in; copy it out if it represents a non-deleted entry.
4537 entryInDir = curOffset.LowPart & (2048-1);
4538 entryInBuffer = curOffset.LowPart & (cm_data.buf_blockSize - 1);
4540 /* page header will help tell us which entries are free. Page
4541 * header can change more often than once per buffer, since
4542 * AFS 3 dir page size may be less than (but not more than)
4543 * a buffer package buffer.
4545 /* only look intra-buffer */
4546 temp = curOffset.LowPart & (cm_data.buf_blockSize - 1);
4547 temp &= ~(2048 - 1); /* turn off intra-page bits */
4548 pageHeaderp = (cm_pageHeader_t *) (bufferp->datap + temp);
4550 /* now determine which entry we're looking at in the page.
4551 * If it is free (there's a free bitmap at the start of the
4552 * dir), we should skip these 32 bytes.
4554 slotInPage = (entryInDir & 0x7e0) >> 5;
4555 if (!(pageHeaderp->freeBitmap[slotInPage>>3] &
4556 (1 << (slotInPage & 0x7)))) {
4557 /* this entry is free */
4558 numDirChunks = 1; /* only skip this guy */
4562 tp = bufferp->datap + entryInBuffer;
4563 dep = (cm_dirEntry_t *) tp; /* now points to AFS3 dir entry */
4565 /* while we're here, compute the next entry's location, too,
4566 * since we'll need it when writing out the cookie into the dir
4569 * XXXX Probably should do more sanity checking.
4571 numDirChunks = cm_NameEntries(dep->name, &onbytes);
4573 /* compute offset of cookie representing next entry */
4574 nextEntryCookie = curOffset.LowPart + (CM_DIR_CHUNKSIZE * numDirChunks);
4576 /* Need 8.3 name? */
4578 if (infoLevel == SMB_FIND_FILE_BOTH_DIRECTORY_INFO
4579 && dep->fid.vnode != 0
4580 && !cm_Is8Dot3(dep->name)) {
4581 cm_Gen8Dot3Name(dep, shortName, &shortNameEnd);
4585 osi_Log4(smb_logp, "T2 search dir vn %u uniq %u name %s (%s)",
4586 dep->fid.vnode, dep->fid.unique,
4587 osi_LogSaveString(smb_logp, dep->name),
4588 NeedShortName ? osi_LogSaveString(smb_logp, shortName) : "");
4590 /* When matching, we are using doing a case fold if we have a wildcard mask.
4591 * If we get a non-wildcard match, it's a lookup for a specific file.
4593 if (dep->fid.vnode != 0 &&
4594 (smb_V3MatchMask(dep->name, maskp, (starPattern? CM_FLAG_CASEFOLD : 0)) ||
4596 smb_V3MatchMask(shortName, maskp, CM_FLAG_CASEFOLD)))) {
4598 /* Eliminate entries that don't match requested attributes */
4599 if (smb_hideDotFiles && !(dsp->attribute & SMB_ATTR_HIDDEN) &&
4600 smb_IsDotFile(dep->name)) {
4601 osi_Log0(smb_logp, "T2 search dir skipping hidden");
4602 goto nextEntry; /* no hidden files */
4604 if (!(dsp->attribute & SMB_ATTR_DIRECTORY)) /* no directories */
4606 /* We have already done the cm_TryBulkStat above */
4607 fid.cell = scp->fid.cell;
4608 fid.volume = scp->fid.volume;
4609 fid.vnode = ntohl(dep->fid.vnode);
4610 fid.unique = ntohl(dep->fid.unique);
4611 fileType = cm_FindFileType(&fid);
4612 /*osi_Log2(smb_logp, "smb_ReceiveTran2SearchDir: file %s "
4613 "has filetype %d", dep->name,
4615 if (fileType == CM_SCACHETYPE_DIRECTORY ||
4616 fileType == CM_SCACHETYPE_DFSLINK ||
4617 fileType == CM_SCACHETYPE_INVALID)
4618 osi_Log0(smb_logp, "T2 search dir skipping directory or bad link");
4622 /* finally check if this name will fit */
4624 /* standard dir entry stuff */
4625 if (infoLevel < 0x101)
4626 ohbytes = 23; /* pre-NT */
4627 else if (infoLevel == SMB_FIND_FILE_NAMES_INFO)
4628 ohbytes = 12; /* NT names only */
4630 ohbytes = 64; /* NT */
4632 if (infoLevel == SMB_FIND_FILE_BOTH_DIRECTORY_INFO)
4633 ohbytes += 26; /* Short name & length */
4635 if (searchFlags & 4) {
4636 ohbytes += 4; /* if resume key required */
4639 if (infoLevel != SMB_INFO_STANDARD
4640 && infoLevel != SMB_FIND_FILE_DIRECTORY_INFO
4641 && infoLevel != SMB_FIND_FILE_NAMES_INFO)
4642 ohbytes += 4; /* EASIZE */
4644 /* add header to name & term. null */
4645 orbytes = onbytes + ohbytes + 1;
4647 /* now, we round up the record to a 4 byte alignment,
4648 * and we make sure that we have enough room here for
4649 * even the aligned version (so we don't have to worry
4650 * about an * overflow when we pad things out below).
4651 * That's the reason for the alignment arithmetic below.
4653 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO)
4654 align = (4 - (orbytes & 3)) & 3;
4657 if (orbytes + bytesInBuffer + align > maxReturnData) {
4658 osi_Log1(smb_logp, "T2 dir search exceed max return data %d",
4663 /* this is one of the entries to use: it is not deleted
4664 * and it matches the star pattern we're looking for.
4665 * Put out the name, preceded by its length.
4667 /* First zero everything else */
4668 memset(origOp, 0, ohbytes);
4670 if (infoLevel <= SMB_FIND_FILE_DIRECTORY_INFO)
4671 *(origOp + ohbytes - 1) = (unsigned char) onbytes;
4672 else if (infoLevel == SMB_FIND_FILE_NAMES_INFO)
4673 *((u_long *)(op + 8)) = onbytes;
4675 *((u_long *)(op + 60)) = onbytes;
4676 strcpy(origOp+ohbytes, dep->name);
4677 if (smb_StoreAnsiFilenames)
4678 CharToOem(origOp+ohbytes, origOp+ohbytes);
4680 /* Short name if requested and needed */
4681 if (infoLevel == SMB_FIND_FILE_BOTH_DIRECTORY_INFO) {
4682 if (NeedShortName) {
4683 strcpy(op + 70, shortName);
4684 if (smb_StoreAnsiFilenames)
4685 CharToOem(op + 70, op + 70);
4686 *(op + 68) = (char)(shortNameEnd - shortName);
4690 /* now, adjust the # of entries copied */
4693 /* NextEntryOffset and FileIndex */
4694 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO) {
4695 int entryOffset = orbytes + align;
4696 *((u_long *)op) = entryOffset;
4697 *((u_long *)(op+4)) = nextEntryCookie;
4700 /* now we emit the attribute. This is tricky, since
4701 * we need to really stat the file to find out what
4702 * type of entry we've got. Right now, we're copying
4703 * out data from a buffer, while holding the scp
4704 * locked, so it isn't really convenient to stat
4705 * something now. We'll put in a place holder
4706 * now, and make a second pass before returning this
4707 * to get the real attributes. So, we just skip the
4708 * data for now, and adjust it later. We allocate a
4709 * patch record to make it easy to find this point
4710 * later. The replay will happen at a time when it is
4711 * safe to unlock the directory.
4713 if (infoLevel != SMB_FIND_FILE_NAMES_INFO) {
4714 curPatchp = malloc(sizeof(*curPatchp));
4715 osi_QAdd((osi_queue_t **) &dirListPatchesp,
4717 curPatchp->dptr = op;
4718 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO)
4719 curPatchp->dptr += 8;
4721 if (smb_hideDotFiles && smb_IsDotFile(dep->name)) {
4722 curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
4725 curPatchp->flags = 0;
4727 curPatchp->fid.cell = scp->fid.cell;
4728 curPatchp->fid.volume = scp->fid.volume;
4729 curPatchp->fid.vnode = ntohl(dep->fid.vnode);
4730 curPatchp->fid.unique = ntohl(dep->fid.unique);
4733 curPatchp->dep = dep;
4736 if (searchFlags & 4)
4737 /* put out resume key */
4738 *((u_long *)origOp) = nextEntryCookie;
4740 /* Adjust byte ptr and count */
4741 origOp += orbytes; /* skip entire record */
4742 bytesInBuffer += orbytes;
4744 /* and pad the record out */
4745 while (--align >= 0) {
4749 } /* if we're including this name */
4750 else if (!starPattern &&
4752 dep->fid.vnode != 0 &&
4753 smb_V3MatchMask(dep->name, maskp, CM_FLAG_CASEFOLD)) {
4754 /* We were looking for exact matches, but here's an inexact one*/
4759 /* and adjust curOffset to be where the new cookie is */
4760 thyper.HighPart = 0;
4761 thyper.LowPart = CM_DIR_CHUNKSIZE * numDirChunks;
4762 curOffset = LargeIntegerAdd(thyper, curOffset);
4763 } /* while copying data for dir listing */
4765 /* If we didn't get a star pattern, we did an exact match during the first pass.
4766 * If there were no exact matches found, we fail over to inexact matches by
4767 * marking the query as a star pattern (matches all case permutations), and
4768 * re-running the query.
4770 if (returnedNames == 0 && !starPattern && foundInexact) {
4771 osi_Log0(afsd_logp,"T2 Search: No exact matches. Re-running for inexact matches");
4776 /* release the mutex */
4777 lock_ReleaseMutex(&scp->mx);
4779 buf_Release(bufferp);
4783 /* apply and free last set of patches; if not doing a star match, this
4784 * will be empty, but better safe (and freeing everything) than sorry.
4786 code2 = smb_ApplyV3DirListPatches(scp, &dirListPatchesp, infoLevel, userp,
4789 /* now put out the final parameters */
4790 if (returnedNames == 0)
4792 if (p->opcode == 1) {
4794 outp->parmsp[0] = (unsigned short) dsp->cookie;
4795 outp->parmsp[1] = returnedNames;
4796 outp->parmsp[2] = eos;
4797 outp->parmsp[3] = 0; /* nothing wrong with EAS */
4798 outp->parmsp[4] = 0;
4799 /* don't need last name to continue
4800 * search, cookie is enough. Normally,
4801 * this is the offset of the file name
4802 * of the last entry returned.
4804 outp->totalParms = 10; /* in bytes */
4808 outp->parmsp[0] = returnedNames;
4809 outp->parmsp[1] = eos;
4810 outp->parmsp[2] = 0; /* EAS error */
4811 outp->parmsp[3] = 0; /* last name, as above */
4812 outp->totalParms = 8; /* in bytes */
4815 /* return # of bytes in the buffer */
4816 outp->totalData = bytesInBuffer;
4818 /* Return error code if unsuccessful on first request */
4819 if (code == 0 && p->opcode == 1 && returnedNames == 0)
4820 code = CM_ERROR_NOSUCHFILE;
4822 osi_Log4(smb_logp, "T2 search dir done, opcode %d, id %d, %d names, code %d",
4823 p->opcode, dsp->cookie, returnedNames, code);
4825 /* if we're supposed to close the search after this request, or if
4826 * we're supposed to close the search if we're done, and we're done,
4827 * or if something went wrong, close the search.
4829 /* ((searchFlags & 1) || ((searchFlags & 2) && eos) */
4830 if ((searchFlags & 1) || (returnedNames == 0) ||
4831 ((searchFlags & 2) && eos) || code != 0)
4832 smb_DeleteDirSearch(dsp);
4834 smb_SendTran2Error(vcp, p, opx, code);
4836 smb_SendTran2Packet(vcp, outp, opx);
4838 smb_FreeTran2Packet(outp);
4839 smb_ReleaseDirSearch(dsp);
4840 cm_ReleaseSCache(scp);
4841 cm_ReleaseUser(userp);
4845 long smb_ReceiveV3FindClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4848 smb_dirSearch_t *dsp;
4850 dirHandle = smb_GetSMBParm(inp, 0);
4852 osi_Log1(smb_logp, "SMB3 find close handle %d", dirHandle);
4854 dsp = smb_FindDirSearch(dirHandle);
4857 return CM_ERROR_BADFD;
4859 /* otherwise, we have an FD to destroy */
4860 smb_DeleteDirSearch(dsp);
4861 smb_ReleaseDirSearch(dsp);
4863 /* and return results */
4864 smb_SetSMBDataLength(outp, 0);
4869 long smb_ReceiveV3FindNotifyClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4871 smb_SetSMBDataLength(outp, 0);
4875 long smb_ReceiveV3OpenX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4882 cm_scache_t *dscp; /* dir we're dealing with */
4883 cm_scache_t *scp; /* file we're creating */
4885 int initialModeBits;
4895 int parmSlot; /* which parm we're dealing with */
4904 extraInfo = (smb_GetSMBParm(inp, 2) & 1); /* return extra info */
4905 openFun = smb_GetSMBParm(inp, 8); /* open function */
4906 excl = ((openFun & 3) == 0);
4907 trunc = ((openFun & 3) == 2); /* truncate it */
4908 openMode = (smb_GetSMBParm(inp, 3) & 0x7);
4909 openAction = 0; /* tracks what we did */
4911 attributes = smb_GetSMBParm(inp, 5);
4912 dosTime = smb_GetSMBParm(inp, 6) | (smb_GetSMBParm(inp, 7) << 16);
4914 /* compute initial mode bits based on read-only flag in attributes */
4915 initialModeBits = 0666;
4916 if (attributes & SMB_ATTR_READONLY)
4917 initialModeBits &= ~0222;
4919 pathp = smb_GetSMBData(inp, NULL);
4920 if (smb_StoreAnsiFilenames)
4921 OemToChar(pathp,pathp);
4923 spacep = inp->spacep;
4924 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
4926 if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
4927 /* special case magic file name for receiving IOCTL requests
4928 * (since IOCTL calls themselves aren't getting through).
4931 osi_Log0(smb_logp, "IOCTL Open");
4934 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
4935 smb_SetupIoctlFid(fidp, spacep);
4937 /* set inp->fid so that later read calls in same msg can find fid */
4938 inp->fid = fidp->fid;
4940 /* copy out remainder of the parms */
4942 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
4944 smb_SetSMBParm(outp, parmSlot, /* attrs */ 0); parmSlot++;
4945 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* mod time */
4946 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
4947 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* len */
4948 smb_SetSMBParm(outp, parmSlot, 0x7fff); parmSlot++;
4949 smb_SetSMBParm(outp, parmSlot, openMode); parmSlot++;
4950 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* file type 0 ==> normal file or dir */
4951 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* IPC junk */
4953 /* and the final "always present" stuff */
4954 smb_SetSMBParm(outp, parmSlot, /* openAction found existing file */ 1); parmSlot++;
4955 /* next write out the "unique" ID */
4956 smb_SetSMBParm(outp, parmSlot, 0x1234); parmSlot++;
4957 smb_SetSMBParm(outp, parmSlot, 0x5678); parmSlot++;
4958 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
4959 smb_SetSMBDataLength(outp, 0);
4961 /* and clean up fid reference */
4962 smb_ReleaseFID(fidp);
4966 #ifdef DEBUG_VERBOSE
4968 char *hexp, *asciip;
4969 asciip = (lastNamep ? lastNamep : pathp );
4970 hexp = osi_HexifyString(asciip);
4971 DEBUG_EVENT2("AFS", "V3Open H[%s] A[%s]", hexp, asciip );
4975 userp = smb_GetUserFromVCP(vcp, inp);
4978 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4980 cm_ReleaseUser(userp);
4981 return CM_ERROR_NOSUCHPATH;
4983 code = cm_NameI(cm_data.rootSCachep, pathp,
4984 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
4985 userp, tidPathp, &req, &scp);
4988 if (code == 0 && scp->fileType == CM_SCACHETYPE_DFSLINK) {
4989 cm_ReleaseSCache(scp);
4990 cm_ReleaseUser(userp);
4991 if ( WANTS_DFS_PATHNAMES(inp) )
4992 return CM_ERROR_PATH_NOT_COVERED;
4994 return CM_ERROR_BADSHARENAME;
4996 #endif /* DFS_SUPPORT */
4999 code = cm_NameI(cm_data.rootSCachep, spacep->data,
5000 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
5001 userp, tidPathp, &req, &dscp);
5003 cm_ReleaseUser(userp);
5008 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
5009 cm_ReleaseSCache(dscp);
5010 cm_ReleaseUser(userp);
5011 if ( WANTS_DFS_PATHNAMES(inp) )
5012 return CM_ERROR_PATH_NOT_COVERED;
5014 return CM_ERROR_BADSHARENAME;
5016 #endif /* DFS_SUPPORT */
5017 /* otherwise, scp points to the parent directory. Do a lookup,
5018 * and truncate the file if we find it, otherwise we create the
5025 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD, userp,
5027 if (code && code != CM_ERROR_NOSUCHFILE) {
5028 cm_ReleaseSCache(dscp);
5029 cm_ReleaseUser(userp);
5034 /* if we get here, if code is 0, the file exists and is represented by
5035 * scp. Otherwise, we have to create it. The dir may be represented
5036 * by dscp, or we may have found the file directly. If code is non-zero,
5040 code = cm_CheckOpen(scp, openMode, trunc, userp, &req);
5042 if (dscp) cm_ReleaseSCache(dscp);
5043 cm_ReleaseSCache(scp);
5044 cm_ReleaseUser(userp);
5049 /* oops, file shouldn't be there */
5051 cm_ReleaseSCache(dscp);
5052 cm_ReleaseSCache(scp);
5053 cm_ReleaseUser(userp);
5054 return CM_ERROR_EXISTS;
5058 setAttr.mask = CM_ATTRMASK_LENGTH;
5059 setAttr.length.LowPart = 0;
5060 setAttr.length.HighPart = 0;
5061 code = cm_SetAttr(scp, &setAttr, userp, &req);
5062 openAction = 3; /* truncated existing file */
5064 else openAction = 1; /* found existing file */
5066 else if (!(openFun & SMB_ATTR_DIRECTORY)) {
5067 /* don't create if not found */
5068 if (dscp) cm_ReleaseSCache(dscp);
5069 cm_ReleaseUser(userp);
5070 return CM_ERROR_NOSUCHFILE;
5073 osi_assert(dscp != NULL);
5074 osi_Log1(smb_logp, "smb_ReceiveV3OpenX creating file %s",
5075 osi_LogSaveString(smb_logp, lastNamep));
5076 openAction = 2; /* created file */
5077 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
5078 smb_UnixTimeFromDosUTime(&setAttr.clientModTime, dosTime);
5079 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
5083 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
5084 smb_NotifyChange(FILE_ACTION_ADDED,
5085 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
5086 dscp, lastNamep, NULL, TRUE);
5087 } else if (!excl && code == CM_ERROR_EXISTS) {
5088 /* not an exclusive create, and someone else tried
5089 * creating it already, then we open it anyway. We
5090 * don't bother retrying after this, since if this next
5091 * fails, that means that the file was deleted after we
5092 * started this call.
5094 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
5098 setAttr.mask = CM_ATTRMASK_LENGTH;
5099 setAttr.length.LowPart = 0;
5100 setAttr.length.HighPart = 0;
5101 code = cm_SetAttr(scp, &setAttr, userp, &req);
5103 } /* lookup succeeded */
5107 /* we don't need this any longer */
5109 cm_ReleaseSCache(dscp);
5112 /* something went wrong creating or truncating the file */
5114 cm_ReleaseSCache(scp);
5115 cm_ReleaseUser(userp);
5119 /* make sure we're about to open a file */
5120 if (scp->fileType != CM_SCACHETYPE_FILE) {
5121 cm_ReleaseSCache(scp);
5122 cm_ReleaseUser(userp);
5123 return CM_ERROR_ISDIR;
5126 /* now all we have to do is open the file itself */
5127 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
5131 lock_ObtainMutex(&fidp->mx);
5132 /* save a pointer to the vnode */
5134 lock_ObtainMutex(&scp->mx);
5135 scp->flags |= CM_SCACHEFLAG_SMB_FID;
5136 lock_ReleaseMutex(&scp->mx);
5137 osi_Log2(afsd_logp,"smb_ReceiveV3OpenX fidp 0x%p scp 0x%p", fidp, scp);
5139 fidp->userp = userp;
5141 /* compute open mode */
5143 fidp->flags |= SMB_FID_OPENREAD;
5144 if (openMode == 1 || openMode == 2)
5145 fidp->flags |= SMB_FID_OPENWRITE;
5147 /* remember if the file was newly created */
5149 fidp->flags |= SMB_FID_CREATED;
5151 lock_ReleaseMutex(&fidp->mx);
5152 smb_ReleaseFID(fidp);
5154 cm_Open(scp, 0, userp);
5156 /* set inp->fid so that later read calls in same msg can find fid */
5157 inp->fid = fidp->fid;
5159 /* copy out remainder of the parms */
5161 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
5162 lock_ObtainMutex(&scp->mx);
5164 smb_SetSMBParm(outp, parmSlot, smb_Attributes(scp)); parmSlot++;
5165 smb_DosUTimeFromUnixTime(&dosTime, scp->clientModTime);
5166 smb_SetSMBParm(outp, parmSlot, dosTime & 0xffff); parmSlot++;
5167 smb_SetSMBParm(outp, parmSlot, (dosTime>>16) & 0xffff); parmSlot++;
5168 smb_SetSMBParm(outp, parmSlot, scp->length.LowPart & 0xffff); parmSlot++;
5169 smb_SetSMBParm(outp, parmSlot, (scp->length.LowPart >> 16) & 0xffff); parmSlot++;
5170 smb_SetSMBParm(outp, parmSlot, openMode); parmSlot++;
5171 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* file type 0 ==> normal file or dir */
5172 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* IPC junk */
5174 /* and the final "always present" stuff */
5175 smb_SetSMBParm(outp, parmSlot, openAction); parmSlot++;
5176 /* next write out the "unique" ID */
5177 smb_SetSMBParm(outp, parmSlot, scp->fid.vnode & 0xffff); parmSlot++;
5178 smb_SetSMBParm(outp, parmSlot, scp->fid.volume & 0xffff); parmSlot++;
5179 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
5180 lock_ReleaseMutex(&scp->mx);
5181 smb_SetSMBDataLength(outp, 0);
5183 osi_Log1(smb_logp, "SMB OpenX opening fid %d", fidp->fid);
5185 cm_ReleaseUser(userp);
5186 /* leave scp held since we put it in fidp->scp */
5190 static void smb_GetLockParams(unsigned char LockType,
5192 unsigned int * ppid,
5193 LARGE_INTEGER * pOffset,
5194 LARGE_INTEGER * pLength)
5196 if (LockType & LOCKING_ANDX_LARGE_FILES) {
5198 *ppid = *((USHORT *) *buf);
5199 pOffset->HighPart = *((LONG *)(*buf + 4));
5200 pOffset->LowPart = *((DWORD *)(*buf + 8));
5201 pLength->HighPart = *((LONG *)(*buf + 12));
5202 pLength->LowPart = *((DWORD *)(*buf + 16));
5206 /* Not Large Files */
5207 *ppid = *((USHORT *) *buf);
5208 pOffset->HighPart = 0;
5209 pOffset->LowPart = *((DWORD *)(*buf + 2));
5210 pLength->HighPart = 0;
5211 pLength->LowPart = *((DWORD *)(*buf + 6));
5216 long smb_ReceiveV3LockingX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5223 unsigned char LockType;
5224 unsigned short NumberOfUnlocks, NumberOfLocks;
5228 LARGE_INTEGER LOffset, LLength;
5229 smb_waitingLockRequest_t *wlRequest = NULL;
5230 cm_file_lock_t *lockp;
5238 fid = smb_GetSMBParm(inp, 2);
5239 fid = smb_ChainFID(fid, inp);
5241 fidp = smb_FindFID(vcp, fid, 0);
5243 return CM_ERROR_BADFD;
5245 lock_ObtainMutex(&fidp->mx);
5246 if (fidp->flags & SMB_FID_IOCTL) {
5247 osi_Log0(smb_logp, "smb_ReceiveV3Locking BadFD");
5248 lock_ReleaseMutex(&fidp->mx);
5249 smb_ReleaseFID(fidp);
5250 return CM_ERROR_BADFD;
5253 osi_Log2(afsd_logp,"smb_ReceiveV3LockingX fidp 0x%p scp 0x%p", fidp, scp);
5255 lock_ReleaseMutex(&fidp->mx);
5257 /* set inp->fid so that later read calls in same msg can find fid */
5260 userp = smb_GetUserFromVCP(vcp, inp);
5263 lock_ObtainMutex(&scp->mx);
5264 code = cm_SyncOp(scp, NULL, userp, &req, 0,
5265 CM_SCACHESYNC_NEEDCALLBACK
5266 | CM_SCACHESYNC_GETSTATUS
5267 | CM_SCACHESYNC_LOCK);
5269 osi_Log1(smb_logp, "smb_ReceiveV3Locking SyncOp failure code 0x%x", code);
5273 LockType = smb_GetSMBParm(inp, 3) & 0xff;
5274 Timeout = (smb_GetSMBParm(inp, 5) << 16) + smb_GetSMBParm(inp, 4);
5275 NumberOfUnlocks = smb_GetSMBParm(inp, 6);
5276 NumberOfLocks = smb_GetSMBParm(inp, 7);
5278 if ((LockType & LOCKING_ANDX_CANCEL_LOCK) ||
5279 (LockType & LOCKING_ANDX_CHANGE_LOCKTYPE)) {
5281 /* We don't support these requests. Apparently, we can safely
5282 not deal with them too. */
5283 osi_Log1(smb_logp, "smb_ReceiveV3Locking received unsupported request [%s]",
5284 ((LockType & LOCKING_ANDX_CANCEL_LOCK)?
5285 "LOCKING_ANDX_CANCEL_LOCK":
5286 "LOCKING_ANDX_CHANGE_LOCKTYPE"));
5287 /* No need to call osi_LogSaveString since these are string
5290 code = CM_ERROR_BADOP;
5295 op = smb_GetSMBData(inp, NULL);
5297 for (i=0; i<NumberOfUnlocks; i++) {
5298 smb_GetLockParams(LockType, &op, &pid, &LOffset, &LLength);
5300 key = cm_GenerateKey(vcp->vcID, pid, fidp->fid);
5302 code = cm_Unlock(scp, LockType, LOffset, LLength, key, userp, &req);
5310 for (i=0; i<NumberOfLocks; i++) {
5311 smb_GetLockParams(LockType, &op, &pid, &LOffset, &LLength);
5313 key = cm_GenerateKey(vcp->vcID, pid, fidp->fid);
5315 code = cm_Lock(scp, LockType, LOffset, LLength, key, (Timeout != 0),
5316 userp, &req, &lockp);
5318 if (code == CM_ERROR_WOULDBLOCK && Timeout != 0) {
5319 smb_waitingLock_t * wLock;
5321 /* Put on waiting list */
5322 if(wlRequest == NULL) {
5326 LARGE_INTEGER tOffset, tLength;
5328 wlRequest = malloc(sizeof(smb_waitingLockRequest_t));
5330 osi_assert(wlRequest != NULL);
5332 wlRequest->vcp = vcp;
5334 wlRequest->scp = scp;
5335 osi_Log2(afsd_logp,"smb_ReceiveV3LockingX wlRequest 0x%p scp 0x%p", wlRequest, scp);
5337 wlRequest->inp = smb_CopyPacket(inp);
5338 wlRequest->outp = smb_CopyPacket(outp);
5339 wlRequest->lockType = LockType;
5340 wlRequest->timeRemaining = Timeout;
5341 wlRequest->locks = NULL;
5343 /* The waiting lock request needs to have enough
5344 information to undo all the locks in the request.
5345 We do the following to store info about locks that
5346 have already been granted. Sure, we can get most
5347 of the info from the packet, but the packet doesn't
5348 hold the result of cm_Lock call. In practice we
5349 only receive packets with one or two locks, so we
5350 are only wasting a few bytes here and there and
5351 only for a limited period of time until the waiting
5352 lock times out or is freed. */
5354 for(opt = op_locks, j=i; j > 0; j--) {
5355 smb_GetLockParams(LockType, &opt, &pid, &tOffset, &tLength);
5357 tkey = cm_GenerateKey(vcp->vcID, pid, fidp->fid);
5359 wLock = malloc(sizeof(smb_waitingLock_t));
5361 osi_assert(wLock != NULL);
5364 wLock->LOffset = tOffset;
5365 wLock->LLength = tLength;
5366 wLock->lockp = NULL;
5367 wLock->state = SMB_WAITINGLOCKSTATE_DONE;
5368 osi_QAdd((osi_queue_t **) &wlRequest->locks,
5373 wLock = malloc(sizeof(smb_waitingLock_t));
5375 osi_assert(wLock != NULL);
5378 wLock->LOffset = LOffset;
5379 wLock->LLength = LLength;
5380 wLock->lockp = lockp;
5381 wLock->state = SMB_WAITINGLOCKSTATE_WAITING;
5382 osi_QAdd((osi_queue_t **) &wlRequest->locks,
5385 osi_Log1(smb_logp, "smb_ReceiveV3Locking WaitingLock created 0x%p",
5393 osi_Log1(smb_logp, "smb_ReceiveV3Locking cm_Lock failure code 0x%x", code);
5400 /* Since something went wrong with the lock number i, we now
5401 have to go ahead and release any locks acquired before the
5402 failure. All locks before lock number i (of which there
5403 are i of them) have either been successful or are waiting.
5404 Either case requires calling cm_Unlock(). */
5406 /* And purge the waiting lock */
5407 if(wlRequest != NULL) {
5408 smb_waitingLock_t * wl;
5409 smb_waitingLock_t * wlNext;
5412 for(wl = wlRequest->locks; wl; wl = wlNext) {
5414 wlNext = (smb_waitingLock_t *) osi_QNext(&wl->q);
5416 ul_code = cm_Unlock(scp, LockType, wl->LOffset, wl->LLength, wl->key, userp, &req);
5419 osi_Log1(smb_logp, "smb_ReceiveV3Locking cm_Unlock returns code %d", ul_code);
5421 osi_Log0(smb_logp, "smb_ReceiveV3Locking cm_Unlock successful");
5424 osi_QRemove((osi_queue_t **) &wlRequest->locks, &wl->q);
5429 smb_ReleaseVC(wlRequest->vcp);
5430 cm_ReleaseSCache(wlRequest->scp);
5431 smb_FreePacket(wlRequest->inp);
5432 smb_FreePacket(wlRequest->outp);
5441 if (wlRequest != NULL) {
5443 lock_ObtainWrite(&smb_globalLock);
5444 osi_QAdd((osi_queue_t **)&smb_allWaitingLocks,
5446 osi_Wakeup((LONG_PTR)&smb_allWaitingLocks);
5447 lock_ReleaseWrite(&smb_globalLock);
5449 /* don't send reply immediately */
5450 outp->flags |= SMB_PACKETFLAG_NOSEND;
5453 smb_SetSMBDataLength(outp, 0);
5457 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_LOCK);
5460 lock_ReleaseMutex(&scp->mx);
5461 cm_ReleaseSCache(scp);
5462 cm_ReleaseUser(userp);
5463 smb_ReleaseFID(fidp);
5468 long smb_ReceiveV3GetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5474 afs_uint32 searchTime;
5480 fid = smb_GetSMBParm(inp, 0);
5481 fid = smb_ChainFID(fid, inp);
5483 fidp = smb_FindFID(vcp, fid, 0);
5485 return CM_ERROR_BADFD;
5487 lock_ObtainMutex(&fidp->mx);
5488 if (fidp->flags & SMB_FID_IOCTL) {
5489 lock_ReleaseMutex(&fidp->mx);
5490 smb_ReleaseFID(fidp);
5491 return CM_ERROR_BADFD;
5494 osi_Log2(afsd_logp,"smb_ReceiveV3GetAttributes fidp 0x%p scp 0x%p", fidp, scp);
5496 lock_ReleaseMutex(&fidp->mx);
5498 userp = smb_GetUserFromVCP(vcp, inp);
5501 /* otherwise, stat the file */
5502 lock_ObtainMutex(&scp->mx);
5503 code = cm_SyncOp(scp, NULL, userp, &req, 0,
5504 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5508 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5510 /* decode times. We need a search time, but the response to this
5511 * call provides the date first, not the time, as returned in the
5512 * searchTime variable. So we take the high-order bits first.
5514 smb_SearchTimeFromUnixTime(&searchTime, scp->clientModTime);
5515 smb_SetSMBParm(outp, 0, (searchTime >> 16) & 0xffff); /* ctime */
5516 smb_SetSMBParm(outp, 1, searchTime & 0xffff);
5517 smb_SetSMBParm(outp, 2, (searchTime >> 16) & 0xffff); /* atime */
5518 smb_SetSMBParm(outp, 3, searchTime & 0xffff);
5519 smb_SetSMBParm(outp, 4, (searchTime >> 16) & 0xffff); /* mtime */
5520 smb_SetSMBParm(outp, 5, searchTime & 0xffff);
5522 /* now handle file size and allocation size */
5523 smb_SetSMBParm(outp, 6, scp->length.LowPart & 0xffff); /* file size */
5524 smb_SetSMBParm(outp, 7, (scp->length.LowPart >> 16) & 0xffff);
5525 smb_SetSMBParm(outp, 8, scp->length.LowPart & 0xffff); /* alloc size */
5526 smb_SetSMBParm(outp, 9, (scp->length.LowPart >> 16) & 0xffff);
5528 /* file attribute */
5529 smb_SetSMBParm(outp, 10, smb_Attributes(scp));
5531 /* and finalize stuff */
5532 smb_SetSMBDataLength(outp, 0);
5536 lock_ReleaseMutex(&scp->mx);
5537 cm_ReleaseSCache(scp);
5538 cm_ReleaseUser(userp);
5539 smb_ReleaseFID(fidp);
5543 long smb_ReceiveV3SetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5549 afs_uint32 searchTime;
5557 fid = smb_GetSMBParm(inp, 0);
5558 fid = smb_ChainFID(fid, inp);
5560 fidp = smb_FindFID(vcp, fid, 0);
5562 return CM_ERROR_BADFD;
5564 lock_ObtainMutex(&fidp->mx);
5565 if (fidp->flags & SMB_FID_IOCTL) {
5566 lock_ReleaseMutex(&fidp->mx);
5567 smb_ReleaseFID(fidp);
5568 return CM_ERROR_BADFD;
5571 osi_Log2(afsd_logp,"smb_ReceiveV3SetAttributes fidp 0x%p scp 0x%p", fidp, scp);
5573 lock_ReleaseMutex(&fidp->mx);
5575 userp = smb_GetUserFromVCP(vcp, inp);
5578 /* now prepare to call cm_setattr. This message only sets various times,
5579 * and AFS only implements mtime, and we'll set the mtime if that's
5580 * requested. The others we'll ignore.
5582 searchTime = smb_GetSMBParm(inp, 5) | (smb_GetSMBParm(inp, 6) << 16);
5584 if (searchTime != 0) {
5585 smb_UnixTimeFromSearchTime(&unixTime, searchTime);
5587 if ( unixTime != -1 ) {
5588 attrs.mask = CM_ATTRMASK_CLIENTMODTIME;
5589 attrs.clientModTime = unixTime;
5590 code = cm_SetAttr(scp, &attrs, userp, &req);
5592 osi_Log1(smb_logp, "SMB receive V3SetAttributes [fid=%ld]", fid);
5594 osi_Log1(smb_logp, "**smb_UnixTimeFromSearchTime failed searchTime=%ld", searchTime);
5600 cm_ReleaseSCache(scp);
5601 cm_ReleaseUser(userp);
5602 smb_ReleaseFID(fidp);
5606 long smb_ReceiveV3WriteX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5609 long count, written = 0, total_written = 0;
5616 int inDataBlockCount;
5618 fd = smb_GetSMBParm(inp, 2);
5619 count = smb_GetSMBParm(inp, 10);
5621 offset.HighPart = 0;
5622 offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
5624 if (*inp->wctp == 14) {
5625 /* we have a request with 64-bit file offsets */
5626 #ifdef AFS_LARGEFILES
5627 offset.HighPart = smb_GetSMBParm(inp, 12) | (smb_GetSMBParm(inp, 13) << 16);
5629 if ((smb_GetSMBParm(inp, 12) | (smb_GetSMBParm(inp, 13) << 16)) != 0) {
5631 osi_Log0(smb_logp, "smb_ReceiveV3WriteX offset requires largefile support");
5632 /* we shouldn't have received this op if we didn't specify
5633 largefile support */
5634 return CM_ERROR_BADOP;
5639 op = inp->data + smb_GetSMBParm(inp, 11);
5640 inDataBlockCount = count;
5642 osi_Log4(smb_logp, "smb_ReceiveV3WriteX fid %d, off 0x%x:%08x, size 0x%x",
5643 fd, offset.HighPart, offset.LowPart, count);
5645 fd = smb_ChainFID(fd, inp);
5646 fidp = smb_FindFID(vcp, fd, 0);
5648 return CM_ERROR_BADFD;
5650 lock_ObtainMutex(&fidp->mx);
5651 if (fidp->flags & SMB_FID_IOCTL) {
5652 lock_ReleaseMutex(&fidp->mx);
5653 code = smb_IoctlV3Write(fidp, vcp, inp, outp);
5654 smb_ReleaseFID(fidp);
5657 lock_ReleaseMutex(&fidp->mx);
5658 userp = smb_GetUserFromVCP(vcp, inp);
5660 /* special case: 0 bytes transferred means there is no data
5661 transferred. A slight departure from SMB_COM_WRITE where this
5662 means that we are supposed to truncate the file at this
5667 LARGE_INTEGER LOffset;
5668 LARGE_INTEGER LLength;
5670 pid = ((smb_t *) inp)->pid;
5671 key = cm_GenerateKey(vcp->vcID, pid, fd);
5673 LOffset.HighPart = offset.HighPart;
5674 LOffset.LowPart = offset.LowPart;
5675 LLength.HighPart = 0;
5676 LLength.LowPart = count;
5678 lock_ObtainMutex(&fidp->scp->mx);
5679 code = cm_LockCheckWrite(fidp->scp, LOffset, LLength, key);
5680 lock_ReleaseMutex(&fidp->scp->mx);
5687 * Work around bug in NT client
5689 * When copying a file, the NT client should first copy the data,
5690 * then copy the last write time. But sometimes the NT client does
5691 * these in the wrong order, so the data copies would inadvertently
5692 * cause the last write time to be overwritten. We try to detect this,
5693 * and don't set client mod time if we think that would go against the
5696 lock_ObtainMutex(&fidp->mx);
5697 if ((fidp->flags & SMB_FID_MTIMESETDONE) != SMB_FID_MTIMESETDONE) {
5698 fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
5699 fidp->scp->clientModTime = time(NULL);
5701 lock_ReleaseMutex(&fidp->mx);
5704 while ( code == 0 && count > 0 ) {
5705 code = smb_WriteData(fidp, &offset, count, op, userp, &written);
5706 if (code == 0 && written == 0)
5707 code = CM_ERROR_PARTIALWRITE;
5709 offset = LargeIntegerAdd(offset,
5710 ConvertLongToLargeInteger(written));
5712 total_written += written;
5718 /* slots 0 and 1 are reserved for request chaining and will be
5719 filled in when we return. */
5720 smb_SetSMBParm(outp, 2, total_written);
5721 smb_SetSMBParm(outp, 3, 0); /* reserved */
5722 smb_SetSMBParm(outp, 4, 0); /* reserved */
5723 smb_SetSMBParm(outp, 5, 0); /* reserved */
5724 smb_SetSMBDataLength(outp, 0);
5727 smb_ReleaseFID(fidp);
5728 cm_ReleaseUser(userp);
5733 long smb_ReceiveV3ReadX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5737 long finalCount = 0;
5746 fd = smb_GetSMBParm(inp, 2);
5747 count = smb_GetSMBParm(inp, 5);
5748 offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
5750 if (*inp->wctp == 12) {
5751 /* a request with 64-bit offsets */
5752 #ifdef AFS_LARGEFILES
5753 offset.HighPart = smb_GetSMBParm(inp, 10) | (smb_GetSMBParm(inp, 11) << 16);
5755 if (LargeIntegerLessThanZero(offset)) {
5756 osi_Log2(smb_logp, "smb_ReceiveV3Read offset too large (0x%x:%08x)",
5757 offset.HighPart, offset.LowPart);
5758 return CM_ERROR_BADSMB;
5761 if ((smb_GetSMBParm(inp, 10) | (smb_GetSMBParm(inp, 11) << 16)) != 0) {
5762 osi_Log0(smb_logp, "smb_ReceiveV3Read offset is 64-bit. Dropping");
5763 return CM_ERROR_BADSMB;
5765 offset.HighPart = 0;
5769 offset.HighPart = 0;
5772 osi_Log4(smb_logp, "smb_ReceiveV3Read fd %d, off 0x%x:%08x, size 0x%x",
5773 fd, offset.HighPart, offset.LowPart, count);
5775 fd = smb_ChainFID(fd, inp);
5776 fidp = smb_FindFID(vcp, fd, 0);
5778 return CM_ERROR_BADFD;
5781 pid = ((smb_t *) inp)->pid;
5782 key = cm_GenerateKey(vcp->vcID, pid, fd);
5784 LARGE_INTEGER LOffset, LLength;
5786 LOffset.HighPart = offset.HighPart;
5787 LOffset.LowPart = offset.LowPart;
5788 LLength.HighPart = 0;
5789 LLength.LowPart = count;
5791 lock_ObtainMutex(&fidp->scp->mx);
5792 code = cm_LockCheckRead(fidp->scp, LOffset, LLength, key);
5793 lock_ReleaseMutex(&fidp->scp->mx);
5797 smb_ReleaseFID(fidp);
5801 /* set inp->fid so that later read calls in same msg can find fid */
5804 lock_ObtainMutex(&fidp->mx);
5805 if (fidp->flags & SMB_FID_IOCTL) {
5806 lock_ReleaseMutex(&fidp->mx);
5807 code = smb_IoctlV3Read(fidp, vcp, inp, outp);
5808 smb_ReleaseFID(fidp);
5811 lock_ReleaseMutex(&fidp->mx);
5813 userp = smb_GetUserFromVCP(vcp, inp);
5815 /* 0 and 1 are reserved for request chaining, were setup by our caller,
5816 * and will be further filled in after we return.
5818 smb_SetSMBParm(outp, 2, 0); /* remaining bytes, for pipes */
5819 smb_SetSMBParm(outp, 3, 0); /* resvd */
5820 smb_SetSMBParm(outp, 4, 0); /* resvd */
5821 smb_SetSMBParm(outp, 5, count); /* # of bytes we're going to read */
5822 /* fill in #6 when we have all the parameters' space reserved */
5823 smb_SetSMBParm(outp, 7, 0); /* resv'd */
5824 smb_SetSMBParm(outp, 8, 0); /* resv'd */
5825 smb_SetSMBParm(outp, 9, 0); /* resv'd */
5826 smb_SetSMBParm(outp, 10, 0); /* resv'd */
5827 smb_SetSMBParm(outp, 11, 0); /* reserved */
5829 /* get op ptr after putting in the parms, since otherwise we don't
5830 * know where the data really is.
5832 op = smb_GetSMBData(outp, NULL);
5834 /* now fill in offset from start of SMB header to first data byte (to op) */
5835 smb_SetSMBParm(outp, 6, ((int) (op - outp->data)));
5837 /* set the packet data length the count of the # of bytes */
5838 smb_SetSMBDataLength(outp, count);
5840 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount);
5842 /* fix some things up */
5843 smb_SetSMBParm(outp, 5, finalCount);
5844 smb_SetSMBDataLength(outp, finalCount);
5846 smb_ReleaseFID(fidp);
5848 cm_ReleaseUser(userp);
5853 * Values for createDisp, copied from NTDDK.H
5855 #define FILE_SUPERSEDE 0 // (???)
5856 #define FILE_OPEN 1 // (open)
5857 #define FILE_CREATE 2 // (exclusive)
5858 #define FILE_OPEN_IF 3 // (non-exclusive)
5859 #define FILE_OVERWRITE 4 // (open & truncate, but do not create)
5860 #define FILE_OVERWRITE_IF 5 // (open & truncate, or create)
5863 #define REQUEST_OPLOCK 2
5864 #define REQUEST_BATCH_OPLOCK 4
5865 #define OPEN_DIRECTORY 8
5866 #define EXTENDED_RESPONSE_REQUIRED 0x10
5868 /* CreateOptions field. */
5869 #define FILE_DIRECTORY_FILE 0x0001
5870 #define FILE_WRITE_THROUGH 0x0002
5871 #define FILE_SEQUENTIAL_ONLY 0x0004
5872 #define FILE_NON_DIRECTORY_FILE 0x0040
5873 #define FILE_NO_EA_KNOWLEDGE 0x0200
5874 #define FILE_EIGHT_DOT_THREE_ONLY 0x0400
5875 #define FILE_RANDOM_ACCESS 0x0800
5876 #define FILE_DELETE_ON_CLOSE 0x1000
5877 #define FILE_OPEN_BY_FILE_ID 0x2000
5879 long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5881 char *pathp, *realPathp;
5885 cm_scache_t *dscp; /* parent dir */
5886 cm_scache_t *scp; /* file to create or open */
5887 cm_scache_t *targetScp; /* if scp is a symlink */
5891 unsigned short nameLength;
5893 unsigned int requestOpLock;
5894 unsigned int requestBatchOpLock;
5895 unsigned int mustBeDir;
5896 unsigned int extendedRespRequired;
5897 unsigned int treeCreate;
5899 unsigned int desiredAccess;
5900 unsigned int extAttributes;
5901 unsigned int createDisp;
5902 unsigned int createOptions;
5903 unsigned int shareAccess;
5904 int initialModeBits;
5905 unsigned short baseFid;
5906 smb_fid_t *baseFidp;
5908 cm_scache_t *baseDirp;
5909 unsigned short openAction;
5921 /* This code is very long and has a lot of if-then-else clauses
5922 * scp and dscp get reused frequently and we need to ensure that
5923 * we don't lose a reference. Start by ensuring that they are NULL.
5930 nameLength = smb_GetSMBOffsetParm(inp, 2, 1);
5931 flags = smb_GetSMBOffsetParm(inp, 3, 1)
5932 | (smb_GetSMBOffsetParm(inp, 4, 1) << 16);
5933 requestOpLock = flags & REQUEST_OPLOCK;
5934 requestBatchOpLock = flags & REQUEST_BATCH_OPLOCK;
5935 mustBeDir = flags & OPEN_DIRECTORY;
5936 extendedRespRequired = flags & EXTENDED_RESPONSE_REQUIRED;
5939 * Why all of a sudden 32-bit FID?
5940 * We will reject all bits higher than 16.
5942 if (smb_GetSMBOffsetParm(inp, 6, 1) != 0)
5943 return CM_ERROR_INVAL;
5944 baseFid = smb_GetSMBOffsetParm(inp, 5, 1);
5945 desiredAccess = smb_GetSMBOffsetParm(inp, 7, 1)
5946 | (smb_GetSMBOffsetParm(inp, 8, 1) << 16);
5947 extAttributes = smb_GetSMBOffsetParm(inp, 13, 1)
5948 | (smb_GetSMBOffsetParm(inp, 14, 1) << 16);
5949 shareAccess = smb_GetSMBOffsetParm(inp, 15, 1)
5950 | (smb_GetSMBOffsetParm(inp, 16, 1) << 16);
5951 createDisp = smb_GetSMBOffsetParm(inp, 17, 1)
5952 | (smb_GetSMBOffsetParm(inp, 18, 1) << 16);
5953 createOptions = smb_GetSMBOffsetParm(inp, 19, 1)
5954 | (smb_GetSMBOffsetParm(inp, 20, 1) << 16);
5956 /* mustBeDir is never set; createOptions directory bit seems to be
5959 if (createOptions & FILE_DIRECTORY_FILE)
5961 else if (createOptions & FILE_NON_DIRECTORY_FILE)
5967 * compute initial mode bits based on read-only flag in
5968 * extended attributes
5970 initialModeBits = 0666;
5971 if (extAttributes & SMB_ATTR_READONLY)
5972 initialModeBits &= ~0222;
5974 pathp = smb_GetSMBData(inp, NULL);
5975 /* Sometimes path is not null-terminated, so we make a copy. */
5976 realPathp = malloc(nameLength+1);
5977 memcpy(realPathp, pathp, nameLength);
5978 realPathp[nameLength] = 0;
5979 if (smb_StoreAnsiFilenames)
5980 OemToChar(realPathp,realPathp);
5982 spacep = inp->spacep;
5983 smb_StripLastComponent(spacep->data, &lastNamep, realPathp);
5985 osi_Log1(smb_logp,"NTCreateX for [%s]",osi_LogSaveString(smb_logp,realPathp));
5986 osi_Log4(smb_logp,"... da=[%x] ea=[%x] cd=[%x] co=[%x]", desiredAccess, extAttributes, createDisp, createOptions);
5987 osi_Log3(smb_logp,"... share=[%x] flags=[%x] lastNamep=[%s]", shareAccess, flags, osi_LogSaveString(smb_logp,(lastNamep?lastNamep:"null")));
5989 if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
5990 /* special case magic file name for receiving IOCTL requests
5991 * (since IOCTL calls themselves aren't getting through).
5993 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
5994 smb_SetupIoctlFid(fidp, spacep);
5995 osi_Log1(smb_logp,"NTCreateX Setting up IOCTL on fid[%d]",fidp->fid);
5997 /* set inp->fid so that later read calls in same msg can find fid */
5998 inp->fid = fidp->fid;
6002 smb_SetSMBParmByte(outp, parmSlot, 0); /* oplock */
6003 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
6004 smb_SetSMBParmLong(outp, parmSlot, 1); parmSlot += 2; /* Action */
6006 memset(&ft, 0, sizeof(ft));
6007 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
6008 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
6009 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
6010 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
6011 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2; /* attr */
6012 sz.HighPart = 0x7fff; sz.LowPart = 0;
6013 smb_SetSMBParmDouble(outp, parmSlot, (char *)&sz); parmSlot += 4; /* alen */
6014 smb_SetSMBParmDouble(outp, parmSlot, (char *)&sz); parmSlot += 4; /* len */
6015 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* filetype */
6016 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* dev state */
6017 smb_SetSMBParmByte(outp, parmSlot, 0); /* is a dir? */
6018 smb_SetSMBDataLength(outp, 0);
6020 /* clean up fid reference */
6021 smb_ReleaseFID(fidp);
6026 #ifdef DEBUG_VERBOSE
6028 char *hexp, *asciip;
6029 asciip = (lastNamep? lastNamep : realPathp);
6030 hexp = osi_HexifyString( asciip );
6031 DEBUG_EVENT2("AFS", "NTCreateX H[%s] A[%s]", hexp, asciip);
6036 userp = smb_GetUserFromVCP(vcp, inp);
6038 osi_Log1(smb_logp, "NTCreateX Invalid user [%d]", ((smb_t *) inp)->uid);
6040 return CM_ERROR_INVAL;
6045 baseDirp = cm_data.rootSCachep;
6046 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
6047 if (code == CM_ERROR_TIDIPC) {
6048 /* Attempt to use a TID allocated for IPC. The client
6049 * is probably looking for DCE RPC end points which we
6050 * don't support OR it could be looking to make a DFS
6053 osi_Log0(smb_logp, "NTCreateX received IPC TID");
6056 cm_ReleaseUser(userp);
6057 return CM_ERROR_NOSUCHFILE;
6058 #endif /* DFS_SUPPORT */
6061 baseFidp = smb_FindFID(vcp, baseFid, 0);
6063 osi_Log1(smb_logp, "NTCreateX Invalid base fid [%d]", baseFid);
6065 cm_ReleaseUser(userp);
6066 return CM_ERROR_INVAL;
6068 baseDirp = baseFidp->scp;
6072 osi_Log1(smb_logp, "NTCreateX tidPathp=[%s]", (tidPathp==NULL)?"null": osi_LogSaveString(smb_logp,tidPathp));
6074 /* compute open mode */
6076 if (desiredAccess & DELETE)
6077 fidflags |= SMB_FID_OPENDELETE;
6078 if (desiredAccess & AFS_ACCESS_READ)
6079 fidflags |= SMB_FID_OPENREAD;
6080 if (desiredAccess & AFS_ACCESS_WRITE)
6081 fidflags |= SMB_FID_OPENWRITE;
6082 if (createOptions & FILE_DELETE_ON_CLOSE)
6083 fidflags |= SMB_FID_DELONCLOSE;
6084 if (createOptions & FILE_SEQUENTIAL_ONLY && !(createOptions & FILE_RANDOM_ACCESS))
6085 fidflags |= SMB_FID_SEQUENTIAL;
6086 if (createOptions & FILE_RANDOM_ACCESS && !(createOptions & FILE_SEQUENTIAL_ONLY))
6087 fidflags |= SMB_FID_RANDOM;
6089 /* and the share mode */
6090 if (shareAccess & FILE_SHARE_READ)
6091 fidflags |= SMB_FID_SHARE_READ;
6092 if (shareAccess & FILE_SHARE_WRITE)
6093 fidflags |= SMB_FID_SHARE_WRITE;
6095 osi_Log1(smb_logp, "NTCreateX fidflags 0x%x", fidflags);
6098 /* For an exclusive create, we want to do a case sensitive match for the last component. */
6099 if ( createDisp == FILE_CREATE ||
6100 createDisp == FILE_OVERWRITE ||
6101 createDisp == FILE_OVERWRITE_IF) {
6102 code = cm_NameI(baseDirp, spacep->data, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
6103 userp, tidPathp, &req, &dscp);
6106 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
6107 cm_ReleaseSCache(dscp);
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 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp, CM_FLAG_FOLLOW,
6120 if (code == CM_ERROR_NOSUCHFILE) {
6121 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp,
6122 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, &req, &scp);
6123 if (code == 0 && realDirFlag == 1) {
6124 cm_ReleaseSCache(scp);
6125 cm_ReleaseSCache(dscp);
6126 cm_ReleaseUser(userp);
6129 smb_ReleaseFID(baseFidp);
6130 return CM_ERROR_EXISTS;
6134 /* we have both scp and dscp */
6136 code = cm_NameI(baseDirp, realPathp, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
6137 userp, tidPathp, &req, &scp);
6139 if (code == 0 && scp->fileType == CM_SCACHETYPE_DFSLINK) {
6140 cm_ReleaseSCache(scp);
6141 cm_ReleaseUser(userp);
6144 smb_ReleaseFID(baseFidp);
6145 if ( WANTS_DFS_PATHNAMES(inp) )
6146 return CM_ERROR_PATH_NOT_COVERED;
6148 return CM_ERROR_BADSHARENAME;
6150 #endif /* DFS_SUPPORT */
6151 /* we might have scp but not dscp */
6157 if (!foundscp || (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE))) {
6158 /* look up parent directory */
6159 /* If we are trying to create a path (i.e. multiple nested directories), then we don't *need*
6160 * the immediate parent. We have to work our way up realPathp until we hit something that we
6164 /* we might or might not have scp */
6170 code = cm_NameI(baseDirp, spacep->data,
6171 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
6172 userp, tidPathp, &req, &dscp);
6175 if (code == 0 && dscp->fileType == CM_SCACHETYPE_DFSLINK) {
6177 cm_ReleaseSCache(scp);
6178 cm_ReleaseSCache(dscp);
6179 cm_ReleaseUser(userp);
6182 smb_ReleaseFID(baseFidp);
6183 if ( WANTS_DFS_PATHNAMES(inp) )
6184 return CM_ERROR_PATH_NOT_COVERED;
6186 return CM_ERROR_BADSHARENAME;
6188 #endif /* DFS_SUPPORT */
6191 (tp = strrchr(spacep->data,'\\')) &&
6192 (createDisp == FILE_CREATE) &&
6193 (realDirFlag == 1)) {
6196 treeStartp = realPathp + (tp - spacep->data);
6198 if (*tp && !smb_IsLegalFilename(tp)) {
6200 smb_ReleaseFID(baseFidp);
6201 cm_ReleaseUser(userp);
6204 cm_ReleaseSCache(scp);
6205 return CM_ERROR_BADNTFILENAME;
6209 } while (dscp == NULL && code == 0);
6213 /* we might have scp and we might have dscp */
6216 smb_ReleaseFID(baseFidp);
6219 osi_Log0(smb_logp,"NTCreateX parent not found");
6221 cm_ReleaseSCache(scp);
6223 cm_ReleaseSCache(dscp);
6224 cm_ReleaseUser(userp);
6229 if (treeCreate && dscp->fileType == CM_SCACHETYPE_FILE) {
6230 /* A file exists where we want a directory. */
6232 cm_ReleaseSCache(scp);
6233 cm_ReleaseSCache(dscp);
6234 cm_ReleaseUser(userp);
6236 return CM_ERROR_EXISTS;
6240 lastNamep = realPathp;
6244 if (!smb_IsLegalFilename(lastNamep)) {
6246 cm_ReleaseSCache(scp);
6248 cm_ReleaseSCache(dscp);
6249 cm_ReleaseUser(userp);
6251 return CM_ERROR_BADNTFILENAME;
6254 if (!foundscp && !treeCreate) {
6255 if ( createDisp == FILE_CREATE ||
6256 createDisp == FILE_OVERWRITE ||
6257 createDisp == FILE_OVERWRITE_IF)
6259 code = cm_Lookup(dscp, lastNamep,
6260 CM_FLAG_FOLLOW, userp, &req, &scp);
6262 code = cm_Lookup(dscp, lastNamep,
6263 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
6266 if (code && code != CM_ERROR_NOSUCHFILE) {
6268 cm_ReleaseSCache(dscp);
6269 cm_ReleaseUser(userp);
6274 /* we have scp and dscp */
6276 /* we have scp but not dscp */
6278 smb_ReleaseFID(baseFidp);
6281 /* if we get here, if code is 0, the file exists and is represented by
6282 * scp. Otherwise, we have to create it. The dir may be represented
6283 * by dscp, or we may have found the file directly. If code is non-zero,
6286 if (code == 0 && !treeCreate) {
6287 code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp, &req);
6290 cm_ReleaseSCache(dscp);
6292 cm_ReleaseSCache(scp);
6293 cm_ReleaseUser(userp);
6298 if (createDisp == FILE_CREATE) {
6299 /* oops, file shouldn't be there */
6301 cm_ReleaseSCache(dscp);
6303 cm_ReleaseSCache(scp);
6304 cm_ReleaseUser(userp);
6306 return CM_ERROR_EXISTS;
6309 if ( createDisp == FILE_OVERWRITE ||
6310 createDisp == FILE_OVERWRITE_IF) {
6312 setAttr.mask = CM_ATTRMASK_LENGTH;
6313 setAttr.length.LowPart = 0;
6314 setAttr.length.HighPart = 0;
6315 /* now watch for a symlink */
6317 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
6319 osi_assert(dscp != NULL);
6320 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
6322 /* we have a more accurate file to use (the
6323 * target of the symbolic link). Otherwise,
6324 * we'll just use the symlink anyway.
6326 osi_Log2(smb_logp, "symlink vp %x to vp %x",
6328 cm_ReleaseSCache(scp);
6332 code = cm_SetAttr(scp, &setAttr, userp, &req);
6333 openAction = 3; /* truncated existing file */
6336 openAction = 1; /* found existing file */
6338 } else if (createDisp == FILE_OPEN || createDisp == FILE_OVERWRITE) {
6339 /* don't create if not found */
6341 cm_ReleaseSCache(dscp);
6343 cm_ReleaseSCache(scp);
6344 cm_ReleaseUser(userp);
6346 return CM_ERROR_NOSUCHFILE;
6347 } else if (realDirFlag == 0 || realDirFlag == -1) {
6348 osi_assert(dscp != NULL);
6349 osi_Log1(smb_logp, "smb_ReceiveNTCreateX creating file %s",
6350 osi_LogSaveString(smb_logp, lastNamep));
6351 openAction = 2; /* created file */
6352 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
6353 setAttr.clientModTime = time(NULL);
6354 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp, &req);
6357 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
6358 smb_NotifyChange(FILE_ACTION_ADDED,
6359 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
6360 dscp, lastNamep, NULL, TRUE);
6361 } else if (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE) {
6362 /* Not an exclusive create, and someone else tried
6363 * creating it already, then we open it anyway. We
6364 * don't bother retrying after this, since if this next
6365 * fails, that means that the file was deleted after we
6366 * started this call.
6368 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
6371 if (createDisp == FILE_OVERWRITE_IF) {
6372 setAttr.mask = CM_ATTRMASK_LENGTH;
6373 setAttr.length.LowPart = 0;
6374 setAttr.length.HighPart = 0;
6376 /* now watch for a symlink */
6378 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
6380 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
6382 /* we have a more accurate file to use (the
6383 * target of the symbolic link). Otherwise,
6384 * we'll just use the symlink anyway.
6386 osi_Log2(smb_logp, "symlink vp %x to vp %x",
6388 cm_ReleaseSCache(scp);
6392 code = cm_SetAttr(scp, &setAttr, userp, &req);
6394 } /* lookup succeeded */
6398 char *cp; /* This component */
6399 int clen = 0; /* length of component */
6400 cm_scache_t *tscp1, *tscp2;
6403 /* create directory */
6405 treeStartp = lastNamep;
6406 osi_assert(dscp != NULL);
6407 osi_Log1(smb_logp, "smb_ReceiveNTCreateX creating directory [%s]",
6408 osi_LogSaveString(smb_logp, treeStartp));
6409 openAction = 2; /* created directory */
6411 /* if the request is to create the root directory
6412 * it will appear as a directory name of the nul-string
6413 * and a code of CM_ERROR_NOSUCHFILE
6415 if ( !*treeStartp && code == CM_ERROR_NOSUCHFILE)
6416 code = CM_ERROR_EXISTS;
6418 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
6419 setAttr.clientModTime = time(NULL);
6424 cm_HoldSCache(tscp1);
6428 tp = strchr(pp, '\\');
6431 clen = (int)strlen(cp);
6432 isLast = 1; /* indicate last component. the supplied path never ends in a slash */
6434 clen = (int)(tp - pp);
6435 strncpy(cp,pp,clen);
6442 continue; /* the supplied path can't have consecutive slashes either , but */
6444 /* cp is the next component to be created. */
6445 code = cm_MakeDir(tscp1, cp, 0, &setAttr, userp, &req);
6446 if (code == 0 && (tscp1->flags & CM_SCACHEFLAG_ANYWATCH))
6447 smb_NotifyChange(FILE_ACTION_ADDED,
6448 FILE_NOTIFY_CHANGE_DIR_NAME,
6449 tscp1, cp, NULL, TRUE);
6451 (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE)) {
6452 /* Not an exclusive create, and someone else tried
6453 * creating it already, then we open it anyway. We
6454 * don't bother retrying after this, since if this next
6455 * fails, that means that the file was deleted after we
6456 * started this call.
6458 code = cm_Lookup(tscp1, cp, CM_FLAG_CASEFOLD,
6459 userp, &req, &tscp2);
6464 if (!isLast) { /* for anything other than dscp, release it unless it's the last one */
6465 cm_ReleaseSCache(tscp1);
6466 tscp1 = tscp2; /* Newly created directory will be next parent */
6467 /* the hold is transfered to tscp1 from tscp2 */
6472 cm_ReleaseSCache(dscp);
6475 cm_ReleaseSCache(scp);
6478 * if we get here and code == 0, then scp is the last directory created, and dscp is the
6484 /* something went wrong creating or truncating the file */
6486 cm_ReleaseSCache(scp);
6488 cm_ReleaseSCache(dscp);
6489 cm_ReleaseUser(userp);
6494 /* make sure we have file vs. dir right (only applies for single component case) */
6495 if (realDirFlag == 0 && scp->fileType != CM_SCACHETYPE_FILE) {
6496 /* now watch for a symlink */
6498 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
6499 cm_scache_t * targetScp = 0;
6500 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
6502 /* we have a more accurate file to use (the
6503 * target of the symbolic link). Otherwise,
6504 * we'll just use the symlink anyway.
6506 osi_Log2(smb_logp, "symlink vp %x to vp %x", scp, targetScp);
6507 cm_ReleaseSCache(scp);
6512 if (scp->fileType != CM_SCACHETYPE_FILE) {
6514 cm_ReleaseSCache(dscp);
6515 cm_ReleaseSCache(scp);
6516 cm_ReleaseUser(userp);
6518 return CM_ERROR_ISDIR;
6522 /* (only applies to single component case) */
6523 if (realDirFlag == 1 && scp->fileType == CM_SCACHETYPE_FILE) {
6524 cm_ReleaseSCache(scp);
6526 cm_ReleaseSCache(dscp);
6527 cm_ReleaseUser(userp);
6529 return CM_ERROR_NOTDIR;
6532 /* open the file itself */
6533 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
6536 /* save a reference to the user */
6538 fidp->userp = userp;
6540 /* If we are restricting sharing, we should do so with a suitable
6542 if (scp->fileType == CM_SCACHETYPE_FILE &&
6543 !(fidflags & SMB_FID_SHARE_WRITE)) {
6545 LARGE_INTEGER LOffset, LLength;
6548 LOffset.HighPart = SMB_FID_QLOCK_HIGH;
6549 LOffset.LowPart = SMB_FID_QLOCK_LOW;
6550 LLength.HighPart = 0;
6551 LLength.LowPart = SMB_FID_QLOCK_LENGTH;
6553 if (fidflags & SMB_FID_SHARE_READ) {
6554 sLockType = LOCKING_ANDX_SHARED_LOCK;
6559 key = cm_GenerateKey(vcp->vcID, SMB_FID_QLOCK_PID, fidp->fid);
6561 lock_ObtainMutex(&scp->mx);
6562 code = cm_Lock(scp, sLockType, LOffset, LLength, key, 0, userp, &req, NULL);
6563 lock_ReleaseMutex(&scp->mx);
6566 /* shouldn't this be smb_CloseFID() fidp->flags = SMB_FID_DELETE; */
6567 smb_CloseFID(vcp, fidp, NULL, 0);
6568 smb_ReleaseFID(fidp);
6570 cm_ReleaseSCache(scp);
6572 cm_ReleaseSCache(dscp);
6573 cm_ReleaseUser(userp);
6580 lock_ObtainMutex(&fidp->mx);
6581 /* save a pointer to the vnode */
6582 fidp->scp = scp; /* Hold transfered to fidp->scp and no longer needed */
6583 lock_ObtainMutex(&scp->mx);
6584 scp->flags |= CM_SCACHEFLAG_SMB_FID;
6585 lock_ReleaseMutex(&scp->mx);
6586 osi_Log2(afsd_logp,"smb_ReceiveNTCreateX fidp 0x%p scp 0x%p", fidp, scp);
6588 fidp->flags = fidflags;
6590 /* remember if the file was newly created */
6592 fidp->flags |= SMB_FID_CREATED;
6594 /* save parent dir and pathname for delete or change notification */
6595 if (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE)) {
6596 osi_Log2(afsd_logp,"smb_ReceiveNTCreateX fidp 0x%p dscp 0x%p", fidp, dscp);
6597 fidp->flags |= SMB_FID_NTOPEN;
6598 fidp->NTopen_dscp = dscp;
6600 fidp->NTopen_pathp = strdup(lastNamep);
6602 fidp->NTopen_wholepathp = realPathp;
6603 lock_ReleaseMutex(&fidp->mx);
6605 /* we don't need this any longer */
6607 cm_ReleaseSCache(dscp);
6611 cm_Open(scp, 0, userp);
6613 /* set inp->fid so that later read calls in same msg can find fid */
6614 inp->fid = fidp->fid;
6618 lock_ObtainMutex(&scp->mx);
6619 smb_SetSMBParmByte(outp, parmSlot, 0); /* oplock */
6620 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
6621 smb_SetSMBParmLong(outp, parmSlot, openAction); parmSlot += 2;
6622 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
6623 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
6624 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
6625 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
6626 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
6627 smb_SetSMBParmLong(outp, parmSlot, smb_ExtAttributes(scp));
6629 smb_SetSMBParmDouble(outp, parmSlot, (char *)&scp->length); parmSlot += 4;
6630 smb_SetSMBParmDouble(outp, parmSlot, (char *)&scp->length); parmSlot += 4;
6631 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* filetype */
6632 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* dev state */
6633 smb_SetSMBParmByte(outp, parmSlot,
6634 (scp->fileType == CM_SCACHETYPE_DIRECTORY ||
6635 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
6636 scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0); /* is a dir? */
6637 lock_ReleaseMutex(&scp->mx);
6638 smb_SetSMBDataLength(outp, 0);
6640 osi_Log2(smb_logp, "SMB NT CreateX opening fid %d path %s", fidp->fid,
6641 osi_LogSaveString(smb_logp, realPathp));
6643 smb_ReleaseFID(fidp);
6645 cm_ReleaseUser(userp);
6647 /* Can't free realPathp if we get here since
6648 fidp->NTopen_wholepathp is pointing there */
6650 /* leave scp held since we put it in fidp->scp */
6655 * A lot of stuff copied verbatim from NT Create&X to NT Tran Create.
6656 * Instead, ultimately, would like to use a subroutine for common code.
6658 long smb_ReceiveNTTranCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6660 char *pathp, *realPathp;
6664 cm_scache_t *dscp; /* parent dir */
6665 cm_scache_t *scp; /* file to create or open */
6666 cm_scache_t *targetScp; /* if scp is a symlink */
6669 unsigned long nameLength;
6671 unsigned int requestOpLock;
6672 unsigned int requestBatchOpLock;
6673 unsigned int mustBeDir;
6674 unsigned int extendedRespRequired;
6676 unsigned int desiredAccess;
6677 #ifdef DEBUG_VERBOSE
6678 unsigned int allocSize;
6680 unsigned int shareAccess;
6681 unsigned int extAttributes;
6682 unsigned int createDisp;
6683 #ifdef DEBUG_VERBOSE
6686 unsigned int createOptions;
6687 int initialModeBits;
6688 unsigned short baseFid;
6689 smb_fid_t *baseFidp;
6691 cm_scache_t *baseDirp;
6692 unsigned short openAction;
6698 int parmOffset, dataOffset;
6710 parmOffset = smb_GetSMBOffsetParm(inp, 11, 1)
6711 | (smb_GetSMBOffsetParm(inp, 12, 1) << 16);
6712 parmp = inp->data + parmOffset;
6713 lparmp = (ULONG *) parmp;
6716 requestOpLock = flags & REQUEST_OPLOCK;
6717 requestBatchOpLock = flags & REQUEST_BATCH_OPLOCK;
6718 mustBeDir = flags & OPEN_DIRECTORY;
6719 extendedRespRequired = flags & EXTENDED_RESPONSE_REQUIRED;
6722 * Why all of a sudden 32-bit FID?
6723 * We will reject all bits higher than 16.
6725 if (lparmp[1] & 0xFFFF0000)
6726 return CM_ERROR_INVAL;
6727 baseFid = (unsigned short)lparmp[1];
6728 desiredAccess = lparmp[2];
6729 #ifdef DEBUG_VERBOSE
6730 allocSize = lparmp[3];
6731 #endif /* DEBUG_VERSOSE */
6732 extAttributes = lparmp[5];
6733 shareAccess = lparmp[6];
6734 createDisp = lparmp[7];
6735 createOptions = lparmp[8];
6736 #ifdef DEBUG_VERBOSE
6739 nameLength = lparmp[11];
6741 #ifdef DEBUG_VERBOSE
6742 osi_Log4(smb_logp,"NTTranCreate with da[%x],ea[%x],sa[%x],cd[%x]",desiredAccess,extAttributes,shareAccess,createDisp);
6743 osi_Log3(smb_logp,"... co[%x],sdl[%x],as[%x]",createOptions,sdLen,allocSize);
6744 osi_Log1(smb_logp,"... flags[%x]",flags);
6747 /* mustBeDir is never set; createOptions directory bit seems to be
6750 if (createOptions & FILE_DIRECTORY_FILE)
6752 else if (createOptions & FILE_NON_DIRECTORY_FILE)
6758 * compute initial mode bits based on read-only flag in
6759 * extended attributes
6761 initialModeBits = 0666;
6762 if (extAttributes & SMB_ATTR_READONLY)
6763 initialModeBits &= ~0222;
6765 pathp = parmp + (13 * sizeof(ULONG)) + sizeof(UCHAR);
6766 /* Sometimes path is not null-terminated, so we make a copy. */
6767 realPathp = malloc(nameLength+1);
6768 memcpy(realPathp, pathp, nameLength);
6769 realPathp[nameLength] = 0;
6770 if (smb_StoreAnsiFilenames)
6771 OemToChar(realPathp,realPathp);
6773 spacep = cm_GetSpace();
6774 smb_StripLastComponent(spacep->data, &lastNamep, realPathp);
6777 * Nothing here to handle SMB_IOCTL_FILENAME.
6778 * Will add it if necessary.
6781 #ifdef DEBUG_VERBOSE
6783 char *hexp, *asciip;
6784 asciip = (lastNamep? lastNamep : realPathp);
6785 hexp = osi_HexifyString( asciip );
6786 DEBUG_EVENT2("AFS", "NTTranCreate H[%s] A[%s]", hexp, asciip);
6791 userp = smb_GetUserFromVCP(vcp, inp);
6793 osi_Log1(smb_logp, "NTTranCreate invalid user [%d]", ((smb_t *) inp)->uid);
6795 return CM_ERROR_INVAL;
6800 baseDirp = cm_data.rootSCachep;
6801 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
6802 if (code == CM_ERROR_TIDIPC) {
6803 /* Attempt to use a TID allocated for IPC. The client
6804 * is probably looking for DCE RPC end points which we
6805 * don't support OR it could be looking to make a DFS
6808 osi_Log0(smb_logp, "NTTranCreate received IPC TID");
6811 cm_ReleaseUser(userp);
6812 return CM_ERROR_NOSUCHPATH;
6816 baseFidp = smb_FindFID(vcp, baseFid, 0);
6818 osi_Log1(smb_logp, "NTTranCreate Invalid fid [%d]", baseFid);
6820 cm_ReleaseUser(userp);
6821 return CM_ERROR_INVAL;
6823 baseDirp = baseFidp->scp;
6827 /* compute open mode */
6829 if (desiredAccess & DELETE)
6830 fidflags |= SMB_FID_OPENDELETE;
6831 if (desiredAccess & AFS_ACCESS_READ)
6832 fidflags |= SMB_FID_OPENREAD;
6833 if (desiredAccess & AFS_ACCESS_WRITE)
6834 fidflags |= SMB_FID_OPENWRITE;
6835 if (createOptions & FILE_DELETE_ON_CLOSE)
6836 fidflags |= SMB_FID_DELONCLOSE;
6837 if (createOptions & FILE_SEQUENTIAL_ONLY && !(createOptions & FILE_RANDOM_ACCESS))
6838 fidflags |= SMB_FID_SEQUENTIAL;
6839 if (createOptions & FILE_RANDOM_ACCESS && !(createOptions & FILE_SEQUENTIAL_ONLY))
6840 fidflags |= SMB_FID_RANDOM;
6842 /* And the share mode */
6843 if (shareAccess & FILE_SHARE_READ)
6844 fidflags |= SMB_FID_SHARE_READ;
6845 if (shareAccess & FILE_SHARE_WRITE)
6846 fidflags |= SMB_FID_SHARE_WRITE;
6850 if ( createDisp == FILE_OPEN ||
6851 createDisp == FILE_OVERWRITE ||
6852 createDisp == FILE_OVERWRITE_IF) {
6853 code = cm_NameI(baseDirp, spacep->data, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
6854 userp, tidPathp, &req, &dscp);
6857 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
6858 cm_ReleaseSCache(dscp);
6859 cm_ReleaseUser(userp);
6862 smb_ReleaseFID(baseFidp);
6863 if ( WANTS_DFS_PATHNAMES(inp) )
6864 return CM_ERROR_PATH_NOT_COVERED;
6866 return CM_ERROR_BADSHARENAME;
6868 #endif /* DFS_SUPPORT */
6869 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp, CM_FLAG_FOLLOW,
6871 if (code == CM_ERROR_NOSUCHFILE) {
6872 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp,
6873 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, &req, &scp);
6874 if (code == 0 && realDirFlag == 1) {
6875 cm_ReleaseSCache(scp);
6876 cm_ReleaseSCache(dscp);
6877 cm_ReleaseUser(userp);
6880 smb_ReleaseFID(baseFidp);
6881 return CM_ERROR_EXISTS;
6887 code = cm_NameI(baseDirp, realPathp, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
6888 userp, tidPathp, &req, &scp);
6890 if (code == 0 && scp->fileType == CM_SCACHETYPE_DFSLINK) {
6891 cm_ReleaseSCache(scp);
6892 cm_ReleaseUser(userp);
6895 smb_ReleaseFID(baseFidp);
6896 if ( WANTS_DFS_PATHNAMES(inp) )
6897 return CM_ERROR_PATH_NOT_COVERED;
6899 return CM_ERROR_BADSHARENAME;
6901 #endif /* DFS_SUPPORT */
6907 if (code != 0 || (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE))) {
6908 /* look up parent directory */
6910 code = cm_NameI(baseDirp, spacep->data,
6911 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
6912 userp, tidPathp, &req, &dscp);
6914 if (code == 0 && dscp->fileType == CM_SCACHETYPE_DFSLINK) {
6915 cm_ReleaseSCache(dscp);
6916 cm_ReleaseUser(userp);
6919 smb_ReleaseFID(baseFidp);
6920 if ( WANTS_DFS_PATHNAMES(inp) )
6921 return CM_ERROR_PATH_NOT_COVERED;
6923 return CM_ERROR_BADSHARENAME;
6925 #endif /* DFS_SUPPORT */
6929 cm_FreeSpace(spacep);
6932 smb_ReleaseFID(baseFidp);
6935 cm_ReleaseUser(userp);
6941 lastNamep = realPathp;
6945 if (!smb_IsLegalFilename(lastNamep))
6946 return CM_ERROR_BADNTFILENAME;
6949 if (createDisp == FILE_CREATE || createDisp == FILE_OVERWRITE_IF) {
6950 code = cm_Lookup(dscp, lastNamep,
6951 CM_FLAG_FOLLOW, userp, &req, &scp);
6953 code = cm_Lookup(dscp, lastNamep,
6954 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
6957 if (code && code != CM_ERROR_NOSUCHFILE) {
6958 cm_ReleaseSCache(dscp);
6959 cm_ReleaseUser(userp);
6966 smb_ReleaseFID(baseFidp);
6967 cm_FreeSpace(spacep);
6970 /* if we get here, if code is 0, the file exists and is represented by
6971 * scp. Otherwise, we have to create it. The dir may be represented
6972 * by dscp, or we may have found the file directly. If code is non-zero,
6976 code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp,
6980 cm_ReleaseSCache(dscp);
6981 cm_ReleaseSCache(scp);
6982 cm_ReleaseUser(userp);
6987 if (createDisp == FILE_CREATE) {
6988 /* oops, file shouldn't be there */
6990 cm_ReleaseSCache(dscp);
6991 cm_ReleaseSCache(scp);
6992 cm_ReleaseUser(userp);
6994 return CM_ERROR_EXISTS;
6997 if (createDisp == FILE_OVERWRITE ||
6998 createDisp == FILE_OVERWRITE_IF) {
6999 setAttr.mask = CM_ATTRMASK_LENGTH;
7000 setAttr.length.LowPart = 0;
7001 setAttr.length.HighPart = 0;
7003 /* now watch for a symlink */
7005 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
7007 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
7009 /* we have a more accurate file to use (the
7010 * target of the symbolic link). Otherwise,
7011 * we'll just use the symlink anyway.
7013 osi_Log2(smb_logp, "symlink vp %x to vp %x",
7015 cm_ReleaseSCache(scp);
7019 code = cm_SetAttr(scp, &setAttr, userp, &req);
7020 openAction = 3; /* truncated existing file */
7022 else openAction = 1; /* found existing file */
7024 else if (createDisp == FILE_OPEN || createDisp == FILE_OVERWRITE) {
7025 /* don't create if not found */
7027 cm_ReleaseSCache(dscp);
7028 cm_ReleaseUser(userp);
7030 return CM_ERROR_NOSUCHFILE;
7032 else if (realDirFlag == 0 || realDirFlag == -1) {
7033 osi_assert(dscp != NULL);
7034 osi_Log1(smb_logp, "smb_ReceiveNTTranCreate creating file %s",
7035 osi_LogSaveString(smb_logp, lastNamep));
7036 openAction = 2; /* created file */
7037 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
7038 setAttr.clientModTime = time(NULL);
7039 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
7043 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
7044 smb_NotifyChange(FILE_ACTION_ADDED,
7045 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
7046 dscp, lastNamep, NULL, TRUE);
7047 } else if (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE) {
7048 /* Not an exclusive create, and someone else tried
7049 * creating it already, then we open it anyway. We
7050 * don't bother retrying after this, since if this next
7051 * fails, that means that the file was deleted after we
7052 * started this call.
7054 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
7057 if (createDisp == FILE_OVERWRITE_IF) {
7058 setAttr.mask = CM_ATTRMASK_LENGTH;
7059 setAttr.length.LowPart = 0;
7060 setAttr.length.HighPart = 0;
7062 /* now watch for a symlink */
7064 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
7066 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
7068 /* we have a more accurate file to use (the
7069 * target of the symbolic link). Otherwise,
7070 * we'll just use the symlink anyway.
7072 osi_Log2(smb_logp, "symlink vp %x to vp %x",
7074 cm_ReleaseSCache(scp);
7078 code = cm_SetAttr(scp, &setAttr, userp, &req);
7080 } /* lookup succeeded */
7083 /* create directory */
7084 osi_assert(dscp != NULL);
7086 "smb_ReceiveNTTranCreate creating directory %s",
7087 osi_LogSaveString(smb_logp, lastNamep));
7088 openAction = 2; /* created directory */
7089 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
7090 setAttr.clientModTime = time(NULL);
7091 code = cm_MakeDir(dscp, lastNamep, 0, &setAttr, userp, &req);
7092 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
7093 smb_NotifyChange(FILE_ACTION_ADDED,
7094 FILE_NOTIFY_CHANGE_DIR_NAME,
7095 dscp, lastNamep, NULL, TRUE);
7097 (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE)) {
7098 /* Not an exclusive create, and someone else tried
7099 * creating it already, then we open it anyway. We
7100 * don't bother retrying after this, since if this next
7101 * fails, that means that the file was deleted after we
7102 * started this call.
7104 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
7110 /* something went wrong creating or truncating the file */
7112 cm_ReleaseSCache(scp);
7113 cm_ReleaseUser(userp);
7118 /* make sure we have file vs. dir right */
7119 if (realDirFlag == 0 && scp->fileType != CM_SCACHETYPE_FILE) {
7120 /* now watch for a symlink */
7122 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
7124 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
7126 /* we have a more accurate file to use (the
7127 * target of the symbolic link). Otherwise,
7128 * we'll just use the symlink anyway.
7130 osi_Log2(smb_logp, "symlink vp %x to vp %x",
7132 cm_ReleaseSCache(scp);
7137 if (scp->fileType != CM_SCACHETYPE_FILE) {
7138 cm_ReleaseSCache(scp);
7139 cm_ReleaseUser(userp);
7141 return CM_ERROR_ISDIR;
7145 if (realDirFlag == 1 && scp->fileType == CM_SCACHETYPE_FILE) {
7146 cm_ReleaseSCache(scp);
7147 cm_ReleaseUser(userp);
7149 return CM_ERROR_NOTDIR;
7152 /* open the file itself */
7153 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
7156 /* save a reference to the user */
7158 fidp->userp = userp;
7160 /* If we are restricting sharing, we should do so with a suitable
7162 if (scp->fileType == CM_SCACHETYPE_FILE &&
7163 !(fidflags & SMB_FID_SHARE_WRITE)) {
7165 LARGE_INTEGER LOffset, LLength;
7168 LOffset.HighPart = SMB_FID_QLOCK_HIGH;
7169 LOffset.LowPart = SMB_FID_QLOCK_LOW;
7170 LLength.HighPart = 0;
7171 LLength.LowPart = SMB_FID_QLOCK_LENGTH;
7173 if (fidflags & SMB_FID_SHARE_READ) {
7174 sLockType = LOCKING_ANDX_SHARED_LOCK;
7179 key = cm_GenerateKey(vcp->vcID, SMB_FID_QLOCK_PID, fidp->fid);
7181 lock_ObtainMutex(&scp->mx);
7182 code = cm_Lock(scp, sLockType, LOffset, LLength, key, 0, userp, &req, NULL);
7183 lock_ReleaseMutex(&scp->mx);
7186 /* Shouldn't this be smb_CloseFID()? fidp->flags = SMB_FID_DELETE; */
7187 smb_CloseFID(vcp, fidp, NULL, 0);
7188 smb_ReleaseFID(fidp);
7190 cm_ReleaseSCache(scp);
7191 cm_ReleaseUser(userp);
7194 return CM_ERROR_SHARING_VIOLATION;
7198 lock_ObtainMutex(&fidp->mx);
7199 /* save a pointer to the vnode */
7201 lock_ObtainMutex(&scp->mx);
7202 scp->flags |= CM_SCACHEFLAG_SMB_FID;
7203 lock_ReleaseMutex(&scp->mx);
7204 osi_Log2(afsd_logp,"smb_ReceiveNTTranCreate fidp 0x%p scp 0x%p", fidp, scp);
7206 fidp->flags = fidflags;
7208 /* remember if the file was newly created */
7210 fidp->flags |= SMB_FID_CREATED;
7212 /* save parent dir and pathname for deletion or change notification */
7213 if (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE)) {
7214 fidp->flags |= SMB_FID_NTOPEN;
7215 fidp->NTopen_dscp = dscp;
7216 osi_Log2(afsd_logp,"smb_ReceiveNTTranCreate fidp 0x%p dscp 0x%p", fidp, dscp);
7218 fidp->NTopen_pathp = strdup(lastNamep);
7220 fidp->NTopen_wholepathp = realPathp;
7221 lock_ReleaseMutex(&fidp->mx);
7223 /* we don't need this any longer */
7225 cm_ReleaseSCache(dscp);
7227 cm_Open(scp, 0, userp);
7229 /* set inp->fid so that later read calls in same msg can find fid */
7230 inp->fid = fidp->fid;
7232 /* check whether we are required to send an extended response */
7233 if (!extendedRespRequired) {
7235 parmOffset = 8*4 + 39;
7236 parmOffset += 1; /* pad to 4 */
7237 dataOffset = parmOffset + 70;
7241 /* Total Parameter Count */
7242 smb_SetSMBParmLong(outp, parmSlot, 70); parmSlot += 2;
7243 /* Total Data Count */
7244 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
7245 /* Parameter Count */
7246 smb_SetSMBParmLong(outp, parmSlot, 70); parmSlot += 2;
7247 /* Parameter Offset */
7248 smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
7249 /* Parameter Displacement */
7250 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
7252 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
7254 smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
7255 /* Data Displacement */
7256 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
7257 smb_SetSMBParmByte(outp, parmSlot, 0); /* Setup Count */
7258 smb_SetSMBDataLength(outp, 70);
7260 lock_ObtainMutex(&scp->mx);
7261 outData = smb_GetSMBData(outp, NULL);
7262 outData++; /* round to get to parmOffset */
7263 *outData = 0; outData++; /* oplock */
7264 *outData = 0; outData++; /* reserved */
7265 *((USHORT *)outData) = fidp->fid; outData += 2; /* fid */
7266 *((ULONG *)outData) = openAction; outData += 4;
7267 *((ULONG *)outData) = 0; outData += 4; /* EA error offset */
7268 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
7269 *((FILETIME *)outData) = ft; outData += 8; /* creation time */
7270 *((FILETIME *)outData) = ft; outData += 8; /* last access time */
7271 *((FILETIME *)outData) = ft; outData += 8; /* last write time */
7272 *((FILETIME *)outData) = ft; outData += 8; /* change time */
7273 *((ULONG *)outData) = smb_ExtAttributes(scp); outData += 4;
7274 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* alloc sz */
7275 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* EOF */
7276 *((USHORT *)outData) = 0; outData += 2; /* filetype */
7277 *((USHORT *)outData) = 0; outData += 2; /* dev state */
7278 *((USHORT *)outData) = ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
7279 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
7280 scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0);
7281 outData += 2; /* is a dir? */
7282 lock_ReleaseMutex(&scp->mx);
7285 parmOffset = 8*4 + 39;
7286 parmOffset += 1; /* pad to 4 */
7287 dataOffset = parmOffset + 104;
7291 /* Total Parameter Count */
7292 smb_SetSMBParmLong(outp, parmSlot, 101); parmSlot += 2;
7293 /* Total Data Count */
7294 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
7295 /* Parameter Count */
7296 smb_SetSMBParmLong(outp, parmSlot, 101); parmSlot += 2;
7297 /* Parameter Offset */
7298 smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
7299 /* Parameter Displacement */
7300 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
7302 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
7304 smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
7305 /* Data Displacement */
7306 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
7307 smb_SetSMBParmByte(outp, parmSlot, 0); /* Setup Count */
7308 smb_SetSMBDataLength(outp, 105);
7310 lock_ObtainMutex(&scp->mx);
7311 outData = smb_GetSMBData(outp, NULL);
7312 outData++; /* round to get to parmOffset */
7313 *outData = 0; outData++; /* oplock */
7314 *outData = 1; outData++; /* response type */
7315 *((USHORT *)outData) = fidp->fid; outData += 2; /* fid */
7316 *((ULONG *)outData) = openAction; outData += 4;
7317 *((ULONG *)outData) = 0; outData += 4; /* EA error offset */
7318 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
7319 *((FILETIME *)outData) = ft; outData += 8; /* creation time */
7320 *((FILETIME *)outData) = ft; outData += 8; /* last access time */
7321 *((FILETIME *)outData) = ft; outData += 8; /* last write time */
7322 *((FILETIME *)outData) = ft; outData += 8; /* change time */
7323 *((ULONG *)outData) = smb_ExtAttributes(scp); outData += 4;
7324 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* alloc sz */
7325 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* EOF */
7326 *((USHORT *)outData) = 0; outData += 2; /* filetype */
7327 *((USHORT *)outData) = 0; outData += 2; /* dev state */
7328 *((USHORT *)outData) = ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
7329 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
7330 scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0);
7331 outData += 1; /* is a dir? */
7332 memset(outData,0,24); outData += 24; /* Volume ID and file ID */
7333 *((ULONG *)outData) = 0x001f01ffL; outData += 4; /* Maxmimal access rights */
7334 *((ULONG *)outData) = 0; outData += 4; /* Guest Access rights */
7335 lock_ReleaseMutex(&scp->mx);
7338 osi_Log1(smb_logp, "SMB NTTranCreate opening fid %d", fidp->fid);
7340 smb_ReleaseFID(fidp);
7342 cm_ReleaseUser(userp);
7344 /* free(realPathp); Can't free realPathp here because fidp->NTopen_wholepathp points there */
7345 /* leave scp held since we put it in fidp->scp */
7349 long smb_ReceiveNTTranNotifyChange(smb_vc_t *vcp, smb_packet_t *inp,
7352 smb_packet_t *savedPacketp;
7353 ULONG filter; USHORT fid, watchtree;
7357 filter = smb_GetSMBParm(inp, 19) |
7358 (smb_GetSMBParm(inp, 20) << 16);
7359 fid = smb_GetSMBParm(inp, 21);
7360 watchtree = smb_GetSMBParm(inp, 22) && 0xffff; /* TODO: should this be 0xff ? */
7362 fidp = smb_FindFID(vcp, fid, 0);
7364 osi_Log1(smb_logp, "ERROR: NotifyChange given invalid fid [%d]", fid);
7365 return CM_ERROR_BADFD;
7368 savedPacketp = smb_CopyPacket(inp);
7370 if (savedPacketp->vcp)
7371 smb_ReleaseVC(savedPacketp->vcp);
7372 savedPacketp->vcp = vcp;
7373 lock_ObtainMutex(&smb_Dir_Watch_Lock);
7374 savedPacketp->nextp = smb_Directory_Watches;
7375 smb_Directory_Watches = savedPacketp;
7376 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
7378 osi_Log4(smb_logp, "Request for NotifyChange filter 0x%x fid %d wtree %d file %s",
7379 filter, fid, watchtree, osi_LogSaveString(smb_logp, fidp->NTopen_wholepathp));
7382 osi_Log2(afsd_logp,"smb_ReceiveNTTranNotifyChange fidp 0x%p scp 0x%p", fidp, scp);
7383 lock_ObtainMutex(&scp->mx);
7385 scp->flags |= CM_SCACHEFLAG_WATCHEDSUBTREE;
7387 scp->flags |= CM_SCACHEFLAG_WATCHED;
7388 lock_ReleaseMutex(&scp->mx);
7389 smb_ReleaseFID(fidp);
7391 outp->flags |= SMB_PACKETFLAG_NOSEND;
7395 unsigned char nullSecurityDesc[36] = {
7396 0x01, /* security descriptor revision */
7397 0x00, /* reserved, should be zero */
7398 0x00, 0x80, /* security descriptor control;
7399 * 0x8000 : self-relative format */
7400 0x14, 0x00, 0x00, 0x00, /* offset of owner SID */
7401 0x1c, 0x00, 0x00, 0x00, /* offset of group SID */
7402 0x00, 0x00, 0x00, 0x00, /* offset of DACL would go here */
7403 0x00, 0x00, 0x00, 0x00, /* offset of SACL would go here */
7404 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
7405 /* "null SID" owner SID */
7406 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
7407 /* "null SID" group SID */
7410 long smb_ReceiveNTTranQuerySecurityDesc(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7412 int parmOffset, parmCount, dataOffset, dataCount;
7420 ULONG securityInformation;
7422 parmOffset = smb_GetSMBOffsetParm(inp, 11, 1)
7423 | (smb_GetSMBOffsetParm(inp, 12, 1) << 16);
7424 parmp = inp->data + parmOffset;
7425 sparmp = (USHORT *) parmp;
7426 lparmp = (ULONG *) parmp;
7429 securityInformation = lparmp[1];
7431 maxData = smb_GetSMBOffsetParm(inp, 7, 1)
7432 | (smb_GetSMBOffsetParm(inp, 8, 1) << 16);
7440 parmOffset = 8*4 + 39;
7441 parmOffset += 1; /* pad to 4 */
7443 dataOffset = parmOffset + parmCount;
7447 /* Total Parameter Count */
7448 smb_SetSMBParmLong(outp, parmSlot, parmCount); parmSlot += 2;
7449 /* Total Data Count */
7450 smb_SetSMBParmLong(outp, parmSlot, dataCount); parmSlot += 2;
7451 /* Parameter Count */
7452 smb_SetSMBParmLong(outp, parmSlot, parmCount); parmSlot += 2;
7453 /* Parameter Offset */
7454 smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
7455 /* Parameter Displacement */
7456 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
7458 smb_SetSMBParmLong(outp, parmSlot, dataCount); parmSlot += 2;
7460 smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
7461 /* Data Displacement */
7462 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
7463 smb_SetSMBParmByte(outp, parmSlot, 0); /* Setup Count */
7464 smb_SetSMBDataLength(outp, 1 + parmCount + dataCount);
7466 outData = smb_GetSMBData(outp, NULL);
7467 outData++; /* round to get to parmOffset */
7468 *((ULONG *)outData) = 36; outData += 4; /* length */
7470 if (maxData >= 36) {
7471 memcpy(outData, nullSecurityDesc, 36);
7475 return CM_ERROR_BUFFERTOOSMALL;
7478 long smb_ReceiveNTTransact(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7480 unsigned short function;
7482 function = smb_GetSMBParm(inp, 18);
7484 osi_Log1(smb_logp, "SMB NT Transact function %d", function);
7486 /* We can handle long names */
7487 if (vcp->flags & SMB_VCFLAG_USENT)
7488 ((smb_t *)outp)->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
7492 return smb_ReceiveNTTranCreate(vcp, inp, outp);
7494 osi_Log0(smb_logp, "SMB NT Transact Ioctl - not implemented");
7497 osi_Log0(smb_logp, "SMB NT Transact SetSecurityDesc - not implemented");
7500 return smb_ReceiveNTTranNotifyChange(vcp, inp, outp);
7502 osi_Log0(smb_logp, "SMB NT Transact Rename - not implemented");
7505 return smb_ReceiveNTTranQuerySecurityDesc(vcp, inp, outp);
7507 return CM_ERROR_INVAL;
7511 * smb_NotifyChange -- find relevant change notification messages and
7514 * If we don't know the file name (i.e. a callback break), filename is
7515 * NULL, and we return a zero-length list.
7517 void smb_NotifyChange(DWORD action, DWORD notifyFilter,
7518 cm_scache_t *dscp, char *filename, char *otherFilename,
7519 BOOL isDirectParent)
7521 smb_packet_t *watch, *lastWatch, *nextWatch;
7522 ULONG parmSlot, parmCount, parmOffset, dataOffset, nameLen;
7523 char *outData, *oldOutData;
7527 BOOL twoEntries = FALSE;
7528 ULONG otherNameLen, oldParmCount = 0;
7532 /* Get ready for rename within directory */
7533 if (action == FILE_ACTION_RENAMED_OLD_NAME && otherFilename != NULL) {
7535 otherAction = FILE_ACTION_RENAMED_NEW_NAME;
7538 osi_Log2(smb_logp,"in smb_NotifyChange for file [%s] dscp [%x]",
7539 osi_LogSaveString(smb_logp,filename),dscp);
7541 lock_ObtainMutex(&smb_Dir_Watch_Lock);
7542 watch = smb_Directory_Watches;
7544 filter = smb_GetSMBParm(watch, 19)
7545 | (smb_GetSMBParm(watch, 20) << 16);
7546 fid = smb_GetSMBParm(watch, 21);
7547 wtree = smb_GetSMBParm(watch, 22) & 0xffff; /* TODO: should this be 0xff ? */
7548 maxLen = smb_GetSMBOffsetParm(watch, 5, 1)
7549 | (smb_GetSMBOffsetParm(watch, 6, 1) << 16);
7552 * Strange hack - bug in NT Client and NT Server that we
7555 if (filter == 3 && wtree)
7558 fidp = smb_FindFID(watch->vcp, fid, 0);
7560 osi_Log1(smb_logp," no fidp for fid[%d]",fid);
7562 watch = watch->nextp;
7565 if (fidp->scp != dscp
7566 || (filter & notifyFilter) == 0
7567 || (!isDirectParent && !wtree)) {
7568 osi_Log1(smb_logp," passing fidp->scp[%x]", fidp->scp);
7569 smb_ReleaseFID(fidp);
7571 watch = watch->nextp;
7574 smb_ReleaseFID(fidp);
7577 "Sending Change Notification for fid %d filter 0x%x wtree %d file %s",
7578 fid, filter, wtree, osi_LogSaveString(smb_logp, filename));
7580 nextWatch = watch->nextp;
7581 if (watch == smb_Directory_Watches)
7582 smb_Directory_Watches = nextWatch;
7584 lastWatch->nextp = nextWatch;
7586 /* Turn off WATCHED flag in dscp */
7587 lock_ObtainMutex(&dscp->mx);
7589 dscp->flags &= ~CM_SCACHEFLAG_WATCHEDSUBTREE;
7591 dscp->flags &= ~CM_SCACHEFLAG_WATCHED;
7592 lock_ReleaseMutex(&dscp->mx);
7594 /* Convert to response packet */
7595 ((smb_t *) watch)->reb = SMB_FLAGS_SERVER_TO_CLIENT | SMB_FLAGS_CANONICAL_PATHNAMES;
7596 ((smb_t *) watch)->wct = 0;
7599 if (filename == NULL)
7602 nameLen = (ULONG)strlen(filename);
7603 parmCount = 3*4 + nameLen*2;
7604 parmCount = (parmCount + 3) & ~3; /* pad to 4 */
7606 otherNameLen = (ULONG)strlen(otherFilename);
7607 oldParmCount = parmCount;
7608 parmCount += 3*4 + otherNameLen*2;
7609 parmCount = (parmCount + 3) & ~3; /* pad to 4 */
7611 if (maxLen < parmCount)
7612 parmCount = 0; /* not enough room */
7614 parmOffset = 8*4 + 39;
7615 parmOffset += 1; /* pad to 4 */
7616 dataOffset = parmOffset + parmCount;
7620 /* Total Parameter Count */
7621 smb_SetSMBParmLong(watch, parmSlot, parmCount); parmSlot += 2;
7622 /* Total Data Count */
7623 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
7624 /* Parameter Count */
7625 smb_SetSMBParmLong(watch, parmSlot, parmCount); parmSlot += 2;
7626 /* Parameter Offset */
7627 smb_SetSMBParmLong(watch, parmSlot, parmOffset); parmSlot += 2;
7628 /* Parameter Displacement */
7629 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
7631 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
7633 smb_SetSMBParmLong(watch, parmSlot, dataOffset); parmSlot += 2;
7634 /* Data Displacement */
7635 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
7636 smb_SetSMBParmByte(watch, parmSlot, 0); /* Setup Count */
7637 smb_SetSMBDataLength(watch, parmCount + 1);
7639 if (parmCount != 0) {
7641 outData = smb_GetSMBData(watch, NULL);
7642 outData++; /* round to get to parmOffset */
7643 oldOutData = outData;
7644 *((DWORD *)outData) = oldParmCount; outData += 4;
7645 /* Next Entry Offset */
7646 *((DWORD *)outData) = action; outData += 4;
7648 *((DWORD *)outData) = nameLen*2; outData += 4;
7649 /* File Name Length */
7650 p = strdup(filename);
7651 if (smb_StoreAnsiFilenames)
7653 mbstowcs((WCHAR *)outData, p, nameLen);
7657 outData = oldOutData + oldParmCount;
7658 *((DWORD *)outData) = 0; outData += 4;
7659 /* Next Entry Offset */
7660 *((DWORD *)outData) = otherAction; outData += 4;
7662 *((DWORD *)outData) = otherNameLen*2;
7663 outData += 4; /* File Name Length */
7664 p = strdup(otherFilename);
7665 if (smb_StoreAnsiFilenames)
7667 mbstowcs((WCHAR *)outData, p, otherNameLen); /* File Name */
7673 * If filename is null, we don't know the cause of the
7674 * change notification. We return zero data (see above),
7675 * and set error code to NT_STATUS_NOTIFY_ENUM_DIR
7676 * (= 0x010C). We set the error code here by hand, without
7677 * modifying wct and bcc.
7679 if (filename == NULL) {
7680 ((smb_t *) watch)->rcls = 0x0C;
7681 ((smb_t *) watch)->reh = 0x01;
7682 ((smb_t *) watch)->errLow = 0;
7683 ((smb_t *) watch)->errHigh = 0;
7684 /* Set NT Status codes flag */
7685 ((smb_t *) watch)->flg2 |= SMB_FLAGS2_32BIT_STATUS;
7688 smb_SendPacket(watch->vcp, watch);
7689 smb_FreePacket(watch);
7692 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
7695 long smb_ReceiveNTCancel(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7697 unsigned char *replyWctp;
7698 smb_packet_t *watch, *lastWatch;
7699 USHORT fid, watchtree;
7703 osi_Log0(smb_logp, "SMB3 receive NT cancel");
7705 lock_ObtainMutex(&smb_Dir_Watch_Lock);
7706 watch = smb_Directory_Watches;
7708 if (((smb_t *)watch)->uid == ((smb_t *)inp)->uid
7709 && ((smb_t *)watch)->pid == ((smb_t *)inp)->pid
7710 && ((smb_t *)watch)->mid == ((smb_t *)inp)->mid
7711 && ((smb_t *)watch)->tid == ((smb_t *)inp)->tid) {
7712 if (watch == smb_Directory_Watches)
7713 smb_Directory_Watches = watch->nextp;
7715 lastWatch->nextp = watch->nextp;
7716 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
7718 /* Turn off WATCHED flag in scp */
7719 fid = smb_GetSMBParm(watch, 21);
7720 watchtree = smb_GetSMBParm(watch, 22) & 0xffff;
7722 if (vcp != watch->vcp)
7723 osi_Log2(smb_logp, "smb_ReceiveNTCancel: vcp %x not equal to watch vcp %x",
7726 fidp = smb_FindFID(vcp, fid, 0);
7728 osi_Log3(smb_logp, "Cancelling change notification for fid %d wtree %d file %s",
7730 osi_LogSaveString(smb_logp, (fidp)?fidp->NTopen_wholepathp:""));
7733 osi_Log2(afsd_logp,"smb_ReceiveNTCancel fidp 0x%p scp 0x%p", fidp, scp);
7734 lock_ObtainMutex(&scp->mx);
7736 scp->flags &= ~CM_SCACHEFLAG_WATCHEDSUBTREE;
7738 scp->flags &= ~CM_SCACHEFLAG_WATCHED;
7739 lock_ReleaseMutex(&scp->mx);
7740 smb_ReleaseFID(fidp);
7742 osi_Log2(smb_logp,"NTCancel unable to resolve fid [%d] in vcp[%x]", fid,vcp);
7745 /* assume STATUS32; return 0xC0000120 (CANCELED) */
7746 replyWctp = watch->wctp;
7750 ((smb_t *)watch)->rcls = 0x20;
7751 ((smb_t *)watch)->reh = 0x1;
7752 ((smb_t *)watch)->errLow = 0;
7753 ((smb_t *)watch)->errHigh = 0xC0;
7754 ((smb_t *)watch)->flg2 |= SMB_FLAGS2_32BIT_STATUS;
7755 smb_SendPacket(vcp, watch);
7756 smb_FreePacket(watch);
7760 watch = watch->nextp;
7762 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
7768 * NT rename also does hard links.
7771 #define RENAME_FLAG_MOVE_CLUSTER_INFORMATION 0x102
7772 #define RENAME_FLAG_HARD_LINK 0x103
7773 #define RENAME_FLAG_RENAME 0x104
7774 #define RENAME_FLAG_COPY 0x105
7776 long smb_ReceiveNTRename(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7778 char *oldPathp, *newPathp;
7784 attrs = smb_GetSMBParm(inp, 0);
7785 rename_type = smb_GetSMBParm(inp, 1);
7787 if (rename_type != RENAME_FLAG_RENAME && rename_type != RENAME_FLAG_HARD_LINK) {
7788 osi_Log1(smb_logp, "NTRename invalid infolevel [%x]", rename_type);
7789 return CM_ERROR_NOACCESS;
7792 tp = smb_GetSMBData(inp, NULL);
7793 oldPathp = smb_ParseASCIIBlock(tp, &tp);
7794 if (smb_StoreAnsiFilenames)
7795 OemToChar(oldPathp,oldPathp);
7796 newPathp = smb_ParseASCIIBlock(tp, &tp);
7797 if (smb_StoreAnsiFilenames)
7798 OemToChar(newPathp,newPathp);
7800 osi_Log3(smb_logp, "NTRename for [%s]->[%s] type [%s]",
7801 osi_LogSaveString(smb_logp, oldPathp),
7802 osi_LogSaveString(smb_logp, newPathp),
7803 ((rename_type==RENAME_FLAG_RENAME)?"rename":"hardlink"));
7805 if (rename_type == RENAME_FLAG_RENAME) {
7806 code = smb_Rename(vcp,inp,oldPathp,newPathp,attrs);
7807 } else { /* RENAME_FLAG_HARD_LINK */
7808 code = smb_Link(vcp,inp,oldPathp,newPathp);
7815 lock_InitializeMutex(&smb_Dir_Watch_Lock, "Directory Watch List Lock");
7818 cm_user_t *smb_FindCMUserByName(char *usern, char *machine, afs_uint32 flags)
7820 smb_username_t *unp;
7823 unp = smb_FindUserByName(usern, machine, flags);
7825 lock_ObtainMutex(&unp->mx);
7826 unp->userp = cm_NewUser();
7827 lock_ReleaseMutex(&unp->mx);
7828 osi_Log2(smb_logp,"smb_FindCMUserByName New user name[%s] machine[%s]",osi_LogSaveString(smb_logp,usern),osi_LogSaveString(smb_logp,machine));
7830 osi_Log2(smb_logp,"smb_FindCMUserByName Not found name[%s] machine[%s]",osi_LogSaveString(smb_logp,usern),osi_LogSaveString(smb_logp,machine));
7834 smb_ReleaseUsername(unp);