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;
2651 int scp_mx_held = 0;
2661 infoLevel = p->parmsp[0];
2662 if (infoLevel == SMB_INFO_IS_NAME_VALID)
2664 else if (infoLevel == SMB_INFO_STANDARD)
2665 responseSize = sizeof(qpi.u.QPstandardInfo);
2666 else if (infoLevel == SMB_INFO_QUERY_EA_SIZE)
2667 responseSize = sizeof(qpi.u.QPeaSizeInfo);
2668 else if (infoLevel == SMB_QUERY_FILE_BASIC_INFO)
2669 responseSize = sizeof(qpi.u.QPfileBasicInfo);
2670 else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO)
2671 responseSize = sizeof(qpi.u.QPfileStandardInfo);
2672 else if (infoLevel == SMB_QUERY_FILE_EA_INFO)
2673 responseSize = sizeof(qpi.u.QPfileEaInfo);
2674 else if (infoLevel == SMB_QUERY_FILE_NAME_INFO)
2675 responseSize = sizeof(qpi.u.QPfileNameInfo);
2676 else if (infoLevel == SMB_QUERY_FILE_ALL_INFO)
2677 responseSize = sizeof(qpi.u.QPfileAllInfo);
2678 else if (infoLevel == SMB_QUERY_FILE_ALT_NAME_INFO)
2679 responseSize = sizeof(qpi.u.QPfileAltNameInfo);
2681 osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
2682 p->opcode, infoLevel);
2683 smb_SendTran2Error(vcp, p, opx, CM_ERROR_BADOP);
2687 pathp = (char *)(&p->parmsp[3]);
2688 if (smb_StoreAnsiFilenames)
2689 OemToChar(pathp,pathp);
2690 osi_Log2(smb_logp, "T2 QPathInfo type 0x%x path %s", infoLevel,
2691 osi_LogSaveString(smb_logp, pathp));
2693 outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, responseSize);
2695 if (infoLevel > 0x100)
2696 outp->totalParms = 2;
2698 outp->totalParms = 0;
2699 outp->totalData = responseSize;
2701 /* now, if we're at infoLevel 6, we're only being asked to check
2702 * the syntax, so we just OK things now. In particular, we're *not*
2703 * being asked to verify anything about the state of any parent dirs.
2705 if (infoLevel == SMB_INFO_IS_NAME_VALID) {
2706 smb_SendTran2Packet(vcp, outp, opx);
2707 smb_FreeTran2Packet(outp);
2711 userp = smb_GetTran2User(vcp, p);
2713 osi_Log1(smb_logp, "ReceiveTran2QPathInfo unable to resolve user [%d]", p->uid);
2714 smb_FreeTran2Packet(outp);
2715 return CM_ERROR_BADSMB;
2718 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
2720 cm_ReleaseUser(userp);
2721 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOSUCHPATH);
2722 smb_FreeTran2Packet(outp);
2727 * XXX Strange hack XXX
2729 * As of Patch 7 (13 January 98), we are having the following problem:
2730 * In NT Explorer 4.0, whenever we click on a directory, AFS gets
2731 * requests to look up "desktop.ini" in all the subdirectories.
2732 * This can cause zillions of timeouts looking up non-existent cells
2733 * and volumes, especially in the top-level directory.
2735 * We have not found any way to avoid this or work around it except
2736 * to explicitly ignore the requests for mount points that haven't
2737 * yet been evaluated and for directories that haven't yet been
2740 if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
2741 spacep = cm_GetSpace();
2742 smb_StripLastComponent(spacep->data, &lastComp, pathp);
2743 #ifndef SPECIAL_FOLDERS
2744 /* Make sure that lastComp is not NULL */
2746 if (stricmp(lastComp, "\\desktop.ini") == 0) {
2747 code = cm_NameI(cm_data.rootSCachep, spacep->data,
2751 userp, tidPathp, &req, &dscp);
2754 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
2755 if ( WANTS_DFS_PATHNAMES(p) )
2756 code = CM_ERROR_PATH_NOT_COVERED;
2758 code = CM_ERROR_BADSHARENAME;
2760 #endif /* DFS_SUPPORT */
2761 if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT && !dscp->mountRootFid.volume)
2762 code = CM_ERROR_NOSUCHFILE;
2763 else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
2764 cm_buf_t *bp = buf_Find(dscp, &hzero);
2768 code = CM_ERROR_NOSUCHFILE;
2770 cm_ReleaseSCache(dscp);
2772 cm_FreeSpace(spacep);
2773 cm_ReleaseUser(userp);
2774 smb_SendTran2Error(vcp, p, opx, code);
2775 smb_FreeTran2Packet(outp);
2781 #endif /* SPECIAL_FOLDERS */
2783 cm_FreeSpace(spacep);
2786 /* now do namei and stat, and copy out the info */
2787 code = cm_NameI(cm_data.rootSCachep, pathp,
2788 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, tidPathp, &req, &scp);
2791 cm_ReleaseUser(userp);
2792 smb_SendTran2Error(vcp, p, opx, code);
2793 smb_FreeTran2Packet(outp);
2798 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
2799 cm_ReleaseSCache(scp);
2800 cm_ReleaseUser(userp);
2801 if ( WANTS_DFS_PATHNAMES(p) )
2802 code = CM_ERROR_PATH_NOT_COVERED;
2804 code = CM_ERROR_BADSHARENAME;
2805 smb_SendTran2Error(vcp, p, opx, code);
2806 smb_FreeTran2Packet(outp);
2809 #endif /* DFS_SUPPORT */
2811 lock_ObtainMutex(&scp->mx);
2813 code = cm_SyncOp(scp, NULL, userp, &req, 0,
2814 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
2815 if (code) goto done;
2817 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
2819 /* now we have the status in the cache entry, and everything is locked.
2820 * Marshall the output data.
2822 /* for info level 108, figure out short name */
2823 if (infoLevel == SMB_QUERY_FILE_ALT_NAME_INFO) {
2824 code = cm_GetShortName(pathp, userp, &req,
2825 tidPathp, scp->fid.vnode, shortName,
2831 qpi.u.QPfileAltNameInfo.fileNameLength = (len + 1) * 2;
2832 mbstowcs((unsigned short *)qpi.u.QPfileAltNameInfo.fileName, shortName, len + 1);
2836 else if (infoLevel == SMB_QUERY_FILE_NAME_INFO) {
2837 len = strlen(lastComp);
2838 qpi.u.QPfileNameInfo.fileNameLength = (len + 1) * 2;
2839 mbstowcs((unsigned short *)qpi.u.QPfileNameInfo.fileName, lastComp, len + 1);
2843 else if (infoLevel == SMB_INFO_STANDARD || infoLevel == SMB_INFO_QUERY_EA_SIZE) {
2844 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
2845 qpi.u.QPstandardInfo.creationDateTime = dosTime;
2846 qpi.u.QPstandardInfo.lastAccessDateTime = dosTime;
2847 qpi.u.QPstandardInfo.lastWriteDateTime = dosTime;
2848 qpi.u.QPstandardInfo.dataSize = scp->length.LowPart;
2849 qpi.u.QPstandardInfo.allocationSize = scp->length.LowPart;
2850 attributes = smb_Attributes(scp);
2851 qpi.u.QPstandardInfo.attributes = attributes;
2852 qpi.u.QPstandardInfo.eaSize = 0;
2854 else if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
2855 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
2856 qpi.u.QPfileBasicInfo.creationTime = ft;
2857 qpi.u.QPfileBasicInfo.lastAccessTime = ft;
2858 qpi.u.QPfileBasicInfo.lastWriteTime = ft;
2859 qpi.u.QPfileBasicInfo.changeTime = ft;
2860 extAttributes = smb_ExtAttributes(scp);
2861 qpi.u.QPfileBasicInfo.attributes = extAttributes;
2862 qpi.u.QPfileBasicInfo.reserved = 0;
2864 else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO) {
2865 smb_fid_t *fidp = smb_FindFIDByScache(vcp, scp);
2867 qpi.u.QPfileStandardInfo.allocationSize = scp->length;
2868 qpi.u.QPfileStandardInfo.endOfFile = scp->length;
2869 qpi.u.QPfileStandardInfo.numberOfLinks = scp->linkCount;
2870 qpi.u.QPfileStandardInfo.directory =
2871 ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
2872 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
2873 scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0);
2874 qpi.u.QPfileStandardInfo.reserved = 0;
2877 lock_ReleaseMutex(&scp->mx);
2879 lock_ObtainMutex(&fidp->mx);
2880 delonclose = fidp->flags & SMB_FID_DELONCLOSE;
2881 lock_ReleaseMutex(&fidp->mx);
2882 smb_ReleaseFID(fidp);
2884 qpi.u.QPfileStandardInfo.deletePending = (delonclose ? 1 : 0);
2886 else if (infoLevel == SMB_QUERY_FILE_EA_INFO) {
2887 qpi.u.QPfileEaInfo.eaSize = 0;
2889 else if (infoLevel == SMB_QUERY_FILE_ALL_INFO) {
2890 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
2891 qpi.u.QPfileAllInfo.creationTime = ft;
2892 qpi.u.QPfileAllInfo.lastAccessTime = ft;
2893 qpi.u.QPfileAllInfo.lastWriteTime = ft;
2894 qpi.u.QPfileAllInfo.changeTime = ft;
2895 extAttributes = smb_ExtAttributes(scp);
2896 qpi.u.QPfileAllInfo.attributes = extAttributes;
2897 qpi.u.QPfileAllInfo.allocationSize = scp->length;
2898 qpi.u.QPfileAllInfo.endOfFile = scp->length;
2899 qpi.u.QPfileAllInfo.numberOfLinks = scp->linkCount;
2900 qpi.u.QPfileAllInfo.deletePending = 0;
2901 qpi.u.QPfileAllInfo.directory =
2902 ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
2903 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
2904 scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0);
2905 qpi.u.QPfileAllInfo.indexNumber.HighPart = scp->fid.cell;
2906 qpi.u.QPfileAllInfo.indexNumber.LowPart = scp->fid.volume;
2907 qpi.u.QPfileAllInfo.eaSize = 0;
2908 qpi.u.QPfileAllInfo.accessFlags = 0;
2909 qpi.u.QPfileAllInfo.indexNumber2.HighPart = scp->fid.vnode;
2910 qpi.u.QPfileAllInfo.indexNumber2.LowPart = scp->fid.unique;
2911 qpi.u.QPfileAllInfo.currentByteOffset.HighPart = 0;
2912 qpi.u.QPfileAllInfo.currentByteOffset.LowPart = 0;
2913 qpi.u.QPfileAllInfo.mode = 0;
2914 qpi.u.QPfileAllInfo.alignmentRequirement = 0;
2915 len = strlen(lastComp);
2916 qpi.u.QPfileAllInfo.fileNameLength = (len + 1) * 2;
2917 mbstowcs((unsigned short *)qpi.u.QPfileAllInfo.fileName, lastComp, len + 1);
2920 /* send and free the packets */
2923 lock_ReleaseMutex(&scp->mx);
2924 cm_ReleaseSCache(scp);
2925 cm_ReleaseUser(userp);
2927 memcpy(outp->datap, &qpi, responseSize);
2928 smb_SendTran2Packet(vcp, outp, opx);
2930 smb_SendTran2Error(vcp, p, opx, code);
2932 smb_FreeTran2Packet(outp);
2937 long smb_ReceiveTran2SetPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
2940 osi_Log0(smb_logp,"ReceiveTran2SetPathInfo - NOT_SUPPORTED");
2941 return CM_ERROR_BADOP;
2945 unsigned short infoLevel;
2947 smb_tran2Packet_t *outp;
2948 smb_tran2QPathInfo_t *spi;
2950 cm_scache_t *scp, *dscp;
2958 infoLevel = p->parmsp[0];
2959 osi_Log1(smb_logp,"ReceiveTran2SetPathInfo type 0x%x", infoLevel);
2960 if (infoLevel != SMB_INFO_STANDARD &&
2961 infoLevel != SMB_INFO_QUERY_EA_SIZE &&
2962 infoLevel != SMB_INFO_QUERY_ALL_EAS) {
2963 osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
2964 p->opcode, infoLevel);
2965 smb_SendTran2Error(vcp, p, opx, CM_ERROR_INVAL);
2969 pathp = (char *)(&p->parmsp[3]);
2970 if (smb_StoreAnsiFilenames)
2971 OemToChar(pathp,pathp);
2972 osi_Log2(smb_logp, "T2 SetPathInfo infolevel 0x%x path %s", infoLevel,
2973 osi_LogSaveString(smb_logp, pathp));
2975 userp = smb_GetTran2User(vcp, p);
2977 osi_Log1(smb_logp,"ReceiveTran2SetPathInfo unable to resolve user [%d]", p->uid);
2978 code = CM_ERROR_BADSMB;
2982 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
2983 if (code == CM_ERROR_TIDIPC) {
2984 /* Attempt to use a TID allocated for IPC. The client
2985 * is probably looking for DCE RPC end points which we
2986 * don't support OR it could be looking to make a DFS
2989 osi_Log0(smb_logp, "Tran2Open received IPC TID");
2990 cm_ReleaseUser(userp);
2991 return CM_ERROR_NOSUCHPATH;
2995 * XXX Strange hack XXX
2997 * As of Patch 7 (13 January 98), we are having the following problem:
2998 * In NT Explorer 4.0, whenever we click on a directory, AFS gets
2999 * requests to look up "desktop.ini" in all the subdirectories.
3000 * This can cause zillions of timeouts looking up non-existent cells
3001 * and volumes, especially in the top-level directory.
3003 * We have not found any way to avoid this or work around it except
3004 * to explicitly ignore the requests for mount points that haven't
3005 * yet been evaluated and for directories that haven't yet been
3008 if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
3009 spacep = cm_GetSpace();
3010 smb_StripLastComponent(spacep->data, &lastComp, pathp);
3011 #ifndef SPECIAL_FOLDERS
3012 /* Make sure that lastComp is not NULL */
3014 if (stricmp(lastComp, "\\desktop.ini") == 0) {
3015 code = cm_NameI(cm_data.rootSCachep, spacep->data,
3019 userp, tidPathp, &req, &dscp);
3022 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
3023 if ( WANTS_DFS_PATHNAMES(p) )
3024 code = CM_ERROR_PATH_NOT_COVERED;
3026 code = CM_ERROR_BADSHARENAME;
3028 #endif /* DFS_SUPPORT */
3029 if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT && !dscp->mountRootFid.volume)
3030 code = CM_ERROR_NOSUCHFILE;
3031 else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
3032 cm_buf_t *bp = buf_Find(dscp, &hzero);
3036 code = CM_ERROR_NOSUCHFILE;
3038 cm_ReleaseSCache(dscp);
3040 cm_FreeSpace(spacep);
3041 cm_ReleaseUser(userp);
3042 smb_SendTran2Error(vcp, p, opx, code);
3048 #endif /* SPECIAL_FOLDERS */
3050 cm_FreeSpace(spacep);
3053 /* now do namei and stat, and copy out the info */
3054 code = cm_NameI(cm_data.rootSCachep, pathp,
3055 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, tidPathp, &req, &scp);
3057 cm_ReleaseUser(userp);
3058 smb_SendTran2Error(vcp, p, opx, code);
3062 fidp = smb_FindFIDByScache(vcp, scp);
3064 cm_ReleaseSCache(scp);
3065 cm_ReleaseUser(userp);
3066 smb_SendTran2Error(vcp, p, opx, code);
3070 lock_ObtainMutex(&fidp->mx);
3071 if (!(fidp->flags & SMB_FID_OPENWRITE)) {
3072 lock_ReleaseMutex(&fidp->mx);
3073 cm_ReleaseSCache(scp);
3074 smb_ReleaseFID(fidp);
3075 cm_ReleaseUser(userp);
3076 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOACCESS);
3079 lock_ReleaseMutex(&fidp->mx);
3081 outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, 0);
3083 outp->totalParms = 2;
3084 outp->totalData = 0;
3086 spi = (smb_tran2QPathInfo_t *)p->datap;
3087 if (infoLevel == SMB_INFO_STANDARD || infoLevel == SMB_INFO_QUERY_EA_SIZE) {
3090 /* lock the vnode with a callback; we need the current status
3091 * to determine what the new status is, in some cases.
3093 lock_ObtainMutex(&scp->mx);
3094 code = cm_SyncOp(scp, NULL, userp, &req, 0,
3095 CM_SCACHESYNC_GETSTATUS
3096 | CM_SCACHESYNC_NEEDCALLBACK);
3098 lock_ReleaseMutex(&scp->mx);
3101 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3103 lock_ReleaseMutex(&scp->mx);
3104 lock_ObtainMutex(&fidp->mx);
3105 lock_ObtainMutex(&scp->mx);
3107 /* prepare for setattr call */
3108 attr.mask = CM_ATTRMASK_LENGTH;
3109 attr.length.LowPart = spi->u.QPstandardInfo.dataSize;
3110 attr.length.HighPart = 0;
3112 if (spi->u.QPstandardInfo.lastWriteDateTime != 0) {
3113 smb_UnixTimeFromSearchTime(&attr.clientModTime, spi->u.QPstandardInfo.lastWriteDateTime);
3114 attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
3115 fidp->flags |= SMB_FID_MTIMESETDONE;
3118 if (spi->u.QPstandardInfo.attributes != 0) {
3119 if ((scp->unixModeBits & 0222)
3120 && (spi->u.QPstandardInfo.attributes & SMB_ATTR_READONLY) != 0) {
3121 /* make a writable file read-only */
3122 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
3123 attr.unixModeBits = scp->unixModeBits & ~0222;
3125 else if ((scp->unixModeBits & 0222) == 0
3126 && (spi->u.QPstandardInfo.attributes & SMB_ATTR_READONLY) == 0) {
3127 /* make a read-only file writable */
3128 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
3129 attr.unixModeBits = scp->unixModeBits | 0222;
3132 lock_ReleaseMutex(&scp->mx);
3133 lock_ReleaseMutex(&fidp->mx);
3137 code = cm_SetAttr(scp, &attr, userp, &req);
3141 else if (infoLevel == SMB_INFO_QUERY_ALL_EAS) {
3142 /* we don't support EAs */
3143 code = CM_ERROR_INVAL;
3147 cm_ReleaseSCache(scp);
3148 cm_ReleaseUser(userp);
3149 smb_ReleaseFID(fidp);
3151 smb_SendTran2Packet(vcp, outp, opx);
3153 smb_SendTran2Error(vcp, p, opx, code);
3154 smb_FreeTran2Packet(outp);
3160 long smb_ReceiveTran2QFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
3162 smb_tran2Packet_t *outp;
3164 unsigned long attributes;
3165 unsigned short infoLevel;
3172 smb_tran2QFileInfo_t qfi;
3179 fidp = smb_FindFID(vcp, fid, 0);
3182 smb_SendTran2Error(vcp, p, opx, CM_ERROR_BADFD);
3186 infoLevel = p->parmsp[1];
3187 if (infoLevel == SMB_QUERY_FILE_BASIC_INFO)
3188 responseSize = sizeof(qfi.u.QFbasicInfo);
3189 else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO)
3190 responseSize = sizeof(qfi.u.QFstandardInfo);
3191 else if (infoLevel == SMB_QUERY_FILE_EA_INFO)
3192 responseSize = sizeof(qfi.u.QFeaInfo);
3193 else if (infoLevel == SMB_QUERY_FILE_NAME_INFO)
3194 responseSize = sizeof(qfi.u.QFfileNameInfo);
3196 osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
3197 p->opcode, infoLevel);
3198 smb_SendTran2Error(vcp, p, opx, CM_ERROR_BADOP);
3199 smb_ReleaseFID(fidp);
3202 osi_Log2(smb_logp, "T2 QFileInfo type 0x%x fid %d", infoLevel, fid);
3204 outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, responseSize);
3206 if (infoLevel > 0x100)
3207 outp->totalParms = 2;
3209 outp->totalParms = 0;
3210 outp->totalData = responseSize;
3212 userp = smb_GetTran2User(vcp, p);
3214 osi_Log1(smb_logp, "ReceiveTran2QFileInfo unable to resolve user [%d]", p->uid);
3215 code = CM_ERROR_BADSMB;
3219 lock_ObtainMutex(&fidp->mx);
3220 delonclose = fidp->flags & SMB_FID_DELONCLOSE;
3222 osi_Log2(afsd_logp,"smb_ReleaseTran2QFileInfo fidp 0x%p scp 0x%p", fidp, scp);
3224 lock_ReleaseMutex(&fidp->mx);
3225 lock_ObtainMutex(&scp->mx);
3226 code = cm_SyncOp(scp, NULL, userp, &req, 0,
3227 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3231 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3233 /* now we have the status in the cache entry, and everything is locked.
3234 * Marshall the output data.
3236 if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
3237 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
3238 qfi.u.QFbasicInfo.creationTime = ft;
3239 qfi.u.QFbasicInfo.lastAccessTime = ft;
3240 qfi.u.QFbasicInfo.lastWriteTime = ft;
3241 qfi.u.QFbasicInfo.lastChangeTime = ft;
3242 attributes = smb_ExtAttributes(scp);
3243 qfi.u.QFbasicInfo.attributes = attributes;
3245 else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO) {
3246 qfi.u.QFstandardInfo.allocationSize = scp->length;
3247 qfi.u.QFstandardInfo.endOfFile = scp->length;
3248 qfi.u.QFstandardInfo.numberOfLinks = scp->linkCount;
3249 qfi.u.QFstandardInfo.deletePending = (delonclose ? 1 : 0);
3250 qfi.u.QFstandardInfo.directory =
3251 ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
3252 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
3253 scp->fileType == CM_SCACHETYPE_INVALID)? 1 : 0);
3255 else if (infoLevel == SMB_QUERY_FILE_EA_INFO) {
3256 qfi.u.QFeaInfo.eaSize = 0;
3258 else if (infoLevel == SMB_QUERY_FILE_NAME_INFO) {
3262 lock_ReleaseMutex(&scp->mx);
3263 lock_ObtainMutex(&fidp->mx);
3264 lock_ObtainMutex(&scp->mx);
3265 if (fidp->NTopen_wholepathp)
3266 name = fidp->NTopen_wholepathp;
3268 name = "\\"; /* probably can't happen */
3269 lock_ReleaseMutex(&fidp->mx);
3270 len = (unsigned long)strlen(name);
3271 outp->totalData = ((len+1)*2) + 4; /* this is actually what we want to return */
3272 qfi.u.QFfileNameInfo.fileNameLength = (len + 1) * 2;
3273 mbstowcs((unsigned short *)qfi.u.QFfileNameInfo.fileName, name, len + 1);
3276 /* send and free the packets */
3278 lock_ReleaseMutex(&scp->mx);
3279 cm_ReleaseSCache(scp);
3280 cm_ReleaseUser(userp);
3281 smb_ReleaseFID(fidp);
3283 memcpy(outp->datap, &qfi, responseSize);
3284 smb_SendTran2Packet(vcp, outp, opx);
3286 smb_SendTran2Error(vcp, p, opx, code);
3288 smb_FreeTran2Packet(outp);
3293 long smb_ReceiveTran2SetFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
3298 unsigned short infoLevel;
3299 smb_tran2Packet_t *outp;
3307 fidp = smb_FindFID(vcp, fid, 0);
3310 smb_SendTran2Error(vcp, p, opx, CM_ERROR_BADFD);
3314 infoLevel = p->parmsp[1];
3315 osi_Log2(smb_logp,"ReceiveTran2SetFileInfo type 0x%x fid %d", infoLevel, fid);
3316 if (infoLevel > SMB_SET_FILE_END_OF_FILE_INFO || infoLevel < SMB_SET_FILE_BASIC_INFO) {
3317 osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
3318 p->opcode, infoLevel);
3319 smb_SendTran2Error(vcp, p, opx, CM_ERROR_BADOP);
3320 smb_ReleaseFID(fidp);
3324 lock_ObtainMutex(&fidp->mx);
3325 if (infoLevel == SMB_SET_FILE_DISPOSITION_INFO && !(fidp->flags & SMB_FID_OPENDELETE)) {
3326 lock_ReleaseMutex(&fidp->mx);
3327 smb_ReleaseFID(fidp);
3328 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOACCESS);
3331 if ((infoLevel == SMB_SET_FILE_ALLOCATION_INFO ||
3332 infoLevel == SMB_SET_FILE_END_OF_FILE_INFO)
3333 && !(fidp->flags & SMB_FID_OPENWRITE)) {
3334 lock_ReleaseMutex(&fidp->mx);
3335 smb_ReleaseFID(fidp);
3336 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOACCESS);
3341 osi_Log2(afsd_logp,"smb_ReceiveTran2SetFileInfo fidp 0x%p scp 0x%p", fidp, scp);
3343 lock_ReleaseMutex(&fidp->mx);
3345 outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, 0);
3347 outp->totalParms = 2;
3348 outp->totalData = 0;
3350 userp = smb_GetTran2User(vcp, p);
3352 osi_Log1(smb_logp,"ReceiveTran2SetFileInfo unable to resolve user [%d]", p->uid);
3353 code = CM_ERROR_BADSMB;
3357 if (infoLevel == SMB_SET_FILE_BASIC_INFO) {
3359 unsigned int attribute;
3361 smb_tran2QFileInfo_t *sfi;
3363 sfi = (smb_tran2QFileInfo_t *)p->datap;
3365 /* lock the vnode with a callback; we need the current status
3366 * to determine what the new status is, in some cases.
3368 lock_ObtainMutex(&scp->mx);
3369 code = cm_SyncOp(scp, NULL, userp, &req, 0,
3370 CM_SCACHESYNC_GETSTATUS
3371 | CM_SCACHESYNC_NEEDCALLBACK);
3373 lock_ReleaseMutex(&scp->mx);
3377 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3379 lock_ReleaseMutex(&scp->mx);
3380 lock_ObtainMutex(&fidp->mx);
3381 lock_ObtainMutex(&scp->mx);
3383 /* prepare for setattr call */
3386 lastMod = sfi->u.QFbasicInfo.lastWriteTime;
3387 /* when called as result of move a b, lastMod is (-1, -1).
3388 * If the check for -1 is not present, timestamp
3389 * of the resulting file will be 1969 (-1)
3391 if (LargeIntegerNotEqualToZero(*((LARGE_INTEGER *)&lastMod)) &&
3392 lastMod.dwLowDateTime != -1 && lastMod.dwHighDateTime != -1) {
3393 attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
3394 smb_UnixTimeFromLargeSearchTime(&attr.clientModTime, &lastMod);
3395 fidp->flags |= SMB_FID_MTIMESETDONE;
3398 attribute = sfi->u.QFbasicInfo.attributes;
3399 if (attribute != 0) {
3400 if ((scp->unixModeBits & 0222)
3401 && (attribute & SMB_ATTR_READONLY) != 0) {
3402 /* make a writable file read-only */
3403 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
3404 attr.unixModeBits = scp->unixModeBits & ~0222;
3406 else if ((scp->unixModeBits & 0222) == 0
3407 && (attribute & SMB_ATTR_READONLY) == 0) {
3408 /* make a read-only file writable */
3409 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
3410 attr.unixModeBits = scp->unixModeBits | 0222;
3413 lock_ReleaseMutex(&scp->mx);
3414 lock_ReleaseMutex(&fidp->mx);
3418 code = cm_SetAttr(scp, &attr, userp, &req);
3422 else if (infoLevel == SMB_SET_FILE_DISPOSITION_INFO) {
3423 if (*((char *)(p->datap))) { /* File is Deleted */
3424 code = cm_CheckNTDelete(fidp->NTopen_dscp, scp, userp,
3427 lock_ObtainMutex(&fidp->mx);
3428 fidp->flags |= SMB_FID_DELONCLOSE;
3429 lock_ReleaseMutex(&fidp->mx);
3434 lock_ObtainMutex(&fidp->mx);
3435 fidp->flags &= ~SMB_FID_DELONCLOSE;
3436 lock_ReleaseMutex(&fidp->mx);
3439 else if (infoLevel == SMB_SET_FILE_ALLOCATION_INFO ||
3440 infoLevel == SMB_SET_FILE_END_OF_FILE_INFO) {
3441 LARGE_INTEGER size = *((LARGE_INTEGER *)(p->datap));
3444 attr.mask = CM_ATTRMASK_LENGTH;
3445 attr.length.LowPart = size.LowPart;
3446 attr.length.HighPart = size.HighPart;
3447 code = cm_SetAttr(scp, &attr, userp, &req);
3451 cm_ReleaseSCache(scp);
3452 cm_ReleaseUser(userp);
3453 smb_ReleaseFID(fidp);
3455 smb_SendTran2Packet(vcp, outp, opx);
3457 smb_SendTran2Error(vcp, p, opx, code);
3458 smb_FreeTran2Packet(outp);
3464 smb_ReceiveTran2FSCTL(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3466 osi_Log0(smb_logp,"ReceiveTran2FSCTL - NOT_SUPPORTED");
3467 return CM_ERROR_BADOP;
3471 smb_ReceiveTran2IOCTL(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3473 osi_Log0(smb_logp,"ReceiveTran2IOCTL - NOT_SUPPORTED");
3474 return CM_ERROR_BADOP;
3478 smb_ReceiveTran2FindNotifyFirst(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3480 osi_Log0(smb_logp,"ReceiveTran2FindNotifyFirst - NOT_SUPPORTED");
3481 return CM_ERROR_BADOP;
3485 smb_ReceiveTran2FindNotifyNext(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3487 osi_Log0(smb_logp,"ReceiveTran2FindNotifyNext - NOT_SUPPORTED");
3488 return CM_ERROR_BADOP;
3492 smb_ReceiveTran2CreateDirectory(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3494 osi_Log0(smb_logp,"ReceiveTran2CreateDirectory - NOT_SUPPORTED");
3495 return CM_ERROR_BADOP;
3499 smb_ReceiveTran2SessionSetup(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3501 osi_Log0(smb_logp,"ReceiveTran2SessionSetup - NOT_SUPPORTED");
3502 return CM_ERROR_BADOP;
3505 struct smb_v2_referral {
3507 USHORT ReferralFlags;
3510 USHORT DfsPathOffset;
3511 USHORT DfsAlternativePathOffset;
3512 USHORT NetworkAddressOffset;
3516 smb_ReceiveTran2GetDFSReferral(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
3518 /* This is a UNICODE only request (bit15 of Flags2) */
3519 /* The TID must be IPC$ */
3521 /* The documentation for the Flags response field is contradictory */
3523 /* Use Version 1 Referral Element Format */
3524 /* ServerType = 0; indicates the next server should be queried for the file */
3525 /* ReferralFlags = 0x01; PathConsumed characters should be stripped */
3526 /* Node = UnicodeString of UNC path of the next share name */
3529 int maxReferralLevel = 0;
3530 char requestFileName[1024] = "";
3531 smb_tran2Packet_t *outp = 0;
3532 cm_user_t *userp = 0;
3534 CPINFO CodePageInfo;
3535 int i, nbnLen, reqLen;
3540 maxReferralLevel = p->parmsp[0];
3542 GetCPInfo(CP_ACP, &CodePageInfo);
3543 WideCharToMultiByte(CP_ACP, 0, (LPCWSTR) &p->parmsp[1], -1,
3544 requestFileName, 1024, NULL, NULL);
3546 osi_Log2(smb_logp,"ReceiveTran2GetDfsReferral [%d][%s]",
3547 maxReferralLevel, osi_LogSaveString(smb_logp, requestFileName));
3549 nbnLen = strlen(cm_NetbiosName);
3550 reqLen = strlen(requestFileName);
3552 if (reqLen == nbnLen + 5 &&
3553 requestFileName[0] == '\\' &&
3554 !_strnicmp(cm_NetbiosName,&requestFileName[1],nbnLen) &&
3555 requestFileName[nbnLen+1] == '\\' &&
3556 (!_strnicmp("all",&requestFileName[nbnLen+2],3) ||
3557 !_strnicmp("*.",&requestFileName[nbnLen+2],2)))
3560 struct smb_v2_referral * v2ref;
3561 outp = smb_GetTran2ResponsePacket(vcp, p, op, 0, 2 * (reqLen + 8));
3563 sp = (USHORT *)outp->datap;
3565 sp[idx++] = reqLen; /* path consumed */
3566 sp[idx++] = 1; /* number of referrals */
3567 sp[idx++] = 0x03; /* flags */
3568 #ifdef DFS_VERSION_1
3569 sp[idx++] = 1; /* Version Number */
3570 sp[idx++] = reqLen + 4; /* Referral Size */
3571 sp[idx++] = 1; /* Type = SMB Server */
3572 sp[idx++] = 0; /* Do not strip path consumed */
3573 for ( i=0;i<=reqLen; i++ )
3574 sp[i+idx] = requestFileName[i];
3575 #else /* DFS_VERSION_2 */
3576 sp[idx++] = 2; /* Version Number */
3577 sp[idx++] = sizeof(struct smb_v2_referral); /* Referral Size */
3578 idx += (sizeof(struct smb_v2_referral) / 2);
3579 v2ref = (struct smb_v2_referral *) &sp[5];
3580 v2ref->ServerType = 1; /* SMB Server */
3581 v2ref->ReferralFlags = 0x03;
3582 v2ref->Proximity = 0; /* closest */
3583 v2ref->TimeToLive = 3600; /* seconds */
3584 v2ref->DfsPathOffset = idx * 2;
3585 v2ref->DfsAlternativePathOffset = idx * 2;
3586 v2ref->NetworkAddressOffset = 0;
3587 for ( i=0;i<=reqLen; i++ )
3588 sp[i+idx] = requestFileName[i];
3591 userp = smb_GetTran2User(vcp, p);
3593 osi_Log1(smb_logp,"ReceiveTran2GetDfsReferral unable to resolve user [%d]", p->uid);
3594 code = CM_ERROR_BADSMB;
3599 code = CM_ERROR_NOSUCHPATH;
3604 cm_ReleaseUser(userp);
3606 smb_SendTran2Packet(vcp, outp, op);
3608 smb_SendTran2Error(vcp, p, op, code);
3610 smb_FreeTran2Packet(outp);
3613 #else /* DFS_SUPPORT */
3614 osi_Log0(smb_logp,"ReceiveTran2GetDfsReferral - NOT_SUPPORTED");
3615 return CM_ERROR_BADOP;
3616 #endif /* DFS_SUPPORT */
3620 smb_ReceiveTran2ReportDFSInconsistency(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3622 /* This is a UNICODE only request (bit15 of Flags2) */
3624 /* There is nothing we can do about this operation. The client is going to
3625 * tell us that there is a Version 1 Referral Element for which there is a DFS Error.
3626 * Unfortunately, there is really nothing we can do about it other then log it
3627 * somewhere. Even then I don't think there is anything for us to do.
3628 * So let's return an error value.
3631 osi_Log0(smb_logp,"ReceiveTran2ReportDFSInconsistency - NOT_SUPPORTED");
3632 return CM_ERROR_BADOP;
3636 smb_ApplyV3DirListPatches(cm_scache_t *dscp,
3637 smb_dirListPatch_t **dirPatchespp, int infoLevel, cm_user_t *userp,
3642 cm_scache_t *targetScp; /* target if scp is a symlink */
3647 unsigned short attr;
3648 unsigned long lattr;
3649 smb_dirListPatch_t *patchp;
3650 smb_dirListPatch_t *npatchp;
3652 for(patchp = *dirPatchespp; patchp; patchp =
3653 (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
3654 code = cm_GetSCache(&patchp->fid, &scp, userp, reqp);
3656 lock_ObtainMutex(&scp->mx);
3657 code = cm_SyncOp(scp, NULL, userp, reqp, 0,
3658 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3660 lock_ReleaseMutex(&scp->mx);
3661 cm_ReleaseSCache(scp);
3663 dptr = patchp->dptr;
3665 /* Plug in fake timestamps. A time stamp of 0 causes 'invalid parameter'
3666 errors in the client. */
3667 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO) {
3668 /* 1969-12-31 23:59:59 +00 */
3669 ft.dwHighDateTime = 0x19DB200;
3670 ft.dwLowDateTime = 0x5BB78980;
3672 /* copy to Creation Time */
3673 *((FILETIME *)dptr) = ft;
3676 /* copy to Last Access Time */
3677 *((FILETIME *)dptr) = ft;
3680 /* copy to Last Write Time */
3681 *((FILETIME *)dptr) = ft;
3684 /* copy to Change Time */
3685 *((FILETIME *)dptr) = ft;
3688 /* merge in hidden attribute */
3689 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
3690 *((u_long *)dptr) = SMB_ATTR_HIDDEN;
3694 /* 1969-12-31 23:59:58 +00*/
3695 dosTime = 0xEBBFBF7D;
3697 /* and copy out date */
3698 shortTemp = (dosTime>>16) & 0xffff;
3699 *((u_short *)dptr) = shortTemp;
3702 /* copy out creation time */
3703 shortTemp = dosTime & 0xffff;
3704 *((u_short *)dptr) = shortTemp;
3707 /* and copy out date */
3708 shortTemp = (dosTime>>16) & 0xffff;
3709 *((u_short *)dptr) = shortTemp;
3712 /* copy out access time */
3713 shortTemp = dosTime & 0xffff;
3714 *((u_short *)dptr) = shortTemp;
3717 /* and copy out date */
3718 shortTemp = (dosTime>>16) & 0xffff;
3719 *((u_short *)dptr) = shortTemp;
3722 /* copy out mod time */
3723 shortTemp = dosTime & 0xffff;
3724 *((u_short *)dptr) = shortTemp;
3727 /* merge in hidden (dot file) attribute */
3728 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
3729 attr = SMB_ATTR_HIDDEN;
3730 *dptr++ = attr & 0xff;
3731 *dptr++ = (attr >> 8) & 0xff;
3737 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3739 /* now watch for a symlink */
3741 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
3742 lock_ReleaseMutex(&scp->mx);
3743 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, reqp);
3745 /* we have a more accurate file to use (the
3746 * target of the symbolic link). Otherwise,
3747 * we'll just use the symlink anyway.
3749 osi_Log2(smb_logp, "symlink vp %x to vp %x",
3751 cm_ReleaseSCache(scp);
3754 lock_ObtainMutex(&scp->mx);
3757 dptr = patchp->dptr;
3759 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO) {
3761 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
3763 /* copy to Creation Time */
3764 *((FILETIME *)dptr) = ft;
3767 /* copy to Last Access Time */
3768 *((FILETIME *)dptr) = ft;
3771 /* copy to Last Write Time */
3772 *((FILETIME *)dptr) = ft;
3775 /* copy to Change Time */
3776 *((FILETIME *)dptr) = ft;
3779 /* Use length for both file length and alloc length */
3780 *((LARGE_INTEGER *)dptr) = scp->length;
3782 *((LARGE_INTEGER *)dptr) = scp->length;
3785 /* Copy attributes */
3786 lattr = smb_ExtAttributes(scp);
3787 if (code == CM_ERROR_NOSUCHPATH && scp->fileType == CM_SCACHETYPE_SYMLINK) {
3788 if (lattr == SMB_ATTR_NORMAL)
3789 lattr = SMB_ATTR_DIRECTORY;
3791 lattr |= SMB_ATTR_DIRECTORY;
3793 /* merge in hidden (dot file) attribute */
3794 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
3795 if (lattr == SMB_ATTR_NORMAL)
3796 lattr = SMB_ATTR_HIDDEN;
3798 lattr |= SMB_ATTR_HIDDEN;
3800 *((u_long *)dptr) = lattr;
3804 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
3806 /* and copy out date */
3807 shortTemp = (dosTime>>16) & 0xffff;
3808 *((u_short *)dptr) = shortTemp;
3811 /* copy out creation time */
3812 shortTemp = dosTime & 0xffff;
3813 *((u_short *)dptr) = shortTemp;
3816 /* and copy out date */
3817 shortTemp = (dosTime>>16) & 0xffff;
3818 *((u_short *)dptr) = shortTemp;
3821 /* copy out access time */
3822 shortTemp = dosTime & 0xffff;
3823 *((u_short *)dptr) = shortTemp;
3826 /* and copy out date */
3827 shortTemp = (dosTime>>16) & 0xffff;
3828 *((u_short *)dptr) = shortTemp;
3831 /* copy out mod time */
3832 shortTemp = dosTime & 0xffff;
3833 *((u_short *)dptr) = shortTemp;
3836 /* copy out file length and alloc length,
3837 * using the same for both
3839 *((u_long *)dptr) = scp->length.LowPart;
3841 *((u_long *)dptr) = scp->length.LowPart;
3844 /* finally copy out attributes as short */
3845 attr = smb_Attributes(scp);
3846 /* merge in hidden (dot file) attribute */
3847 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
3848 if (lattr == SMB_ATTR_NORMAL)
3849 lattr = SMB_ATTR_HIDDEN;
3851 lattr |= SMB_ATTR_HIDDEN;
3853 *dptr++ = attr & 0xff;
3854 *dptr++ = (attr >> 8) & 0xff;
3857 lock_ReleaseMutex(&scp->mx);
3858 cm_ReleaseSCache(scp);
3861 /* now free the patches */
3862 for (patchp = *dirPatchespp; patchp; patchp = npatchp) {
3863 npatchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q);
3867 /* and mark the list as empty */
3868 *dirPatchespp = NULL;
3873 #ifndef USE_OLD_MATCHING
3874 // char table for case insensitive comparison
3875 char mapCaseTable[256];
3877 VOID initUpperCaseTable(VOID)
3880 for (i = 0; i < 256; ++i)
3881 mapCaseTable[i] = toupper(i);
3882 // make '"' match '.'
3883 mapCaseTable[(int)'"'] = toupper('.');
3884 // make '<' match '*'
3885 mapCaseTable[(int)'<'] = toupper('*');
3886 // make '>' match '?'
3887 mapCaseTable[(int)'>'] = toupper('?');
3890 // Compare 'pattern' (containing metacharacters '*' and '?') with the file
3892 // Note : this procedure works recursively calling itself.
3894 // PSZ pattern : string containing metacharacters.
3895 // PSZ name : file name to be compared with 'pattern'.
3897 // BOOL : TRUE/FALSE (match/mistmatch)
3900 szWildCardMatchFileName(PSZ pattern, PSZ name, int casefold)
3902 PSZ pename; // points to the last 'name' character
3904 pename = name + strlen(name) - 1;
3915 if (*pattern == '\0')
3917 for (p = pename; p >= name; --p) {
3918 if ((casefold && (mapCaseTable[*p] == mapCaseTable[*pattern]) ||
3919 !casefold && (*p == *pattern)) &&
3920 szWildCardMatchFileName(pattern + 1, p + 1, casefold))
3925 if ((casefold && mapCaseTable[*name] != mapCaseTable[*pattern]) ||
3926 (!casefold && *name != *pattern))
3933 /* if all we have left are wildcards, then we match */
3934 for (;*pattern; pattern++) {
3935 if (*pattern != '*' && *pattern != '?')
3941 /* do a case-folding search of the star name mask with the name in namep.
3942 * Return 1 if we match, otherwise 0.
3944 int smb_V3MatchMask(char *namep, char *maskp, int flags)
3947 int i, j, star, qmark, casefold, retval;
3949 /* make sure we only match 8.3 names, if requested */
3950 if ((flags & CM_FLAG_8DOT3) && !cm_Is8Dot3(namep))
3953 casefold = (flags & CM_FLAG_CASEFOLD) ? 1 : 0;
3955 /* optimize the pattern:
3956 * if there is a mixture of '?' and '*',
3957 * for example the sequence "*?*?*?*"
3958 * must be turned into the form "*"
3960 newmask = (char *)malloc(strlen(maskp)+1);
3961 for ( i=0, j=0, star=0, qmark=0; maskp[i]; i++) {
3962 switch ( maskp[i] ) {
3974 } else if ( qmark ) {
3978 newmask[j++] = maskp[i];
3985 } else if ( qmark ) {
3989 newmask[j++] = '\0';
3991 retval = szWildCardMatchFileName(newmask, namep, casefold) ? 1:0;
3997 #else /* USE_OLD_MATCHING */
3998 /* do a case-folding search of the star name mask with the name in namep.
3999 * Return 1 if we match, otherwise 0.
4001 int smb_V3MatchMask(char *namep, char *maskp, int flags)
4003 unsigned char tcp1, tcp2; /* Pattern characters */
4004 unsigned char tcn1; /* Name characters */
4005 int sawDot = 0, sawStar = 0, req8dot3 = 0;
4006 char *starNamep, *starMaskp;
4007 static char nullCharp[] = {0};
4008 int casefold = flags & CM_FLAG_CASEFOLD;
4010 /* make sure we only match 8.3 names, if requested */
4011 req8dot3 = (flags & CM_FLAG_8DOT3);
4012 if (req8dot3 && !cm_Is8Dot3(namep))
4017 /* Next pattern character */
4020 /* Next name character */
4024 /* 0 - end of pattern */
4030 else if (tcp1 == '.' || tcp1 == '"') {
4040 * first dot in pattern;
4041 * must match dot or end of name
4046 else if (tcn1 == '.') {
4055 else if (tcp1 == '?') {
4056 if (tcn1 == 0 || tcn1 == '.')
4061 else if (tcp1 == '>') {
4062 if (tcn1 != 0 && tcn1 != '.')
4066 else if (tcp1 == '*' || tcp1 == '<') {
4070 else if ((req8dot3 && tcp2 == '.') || tcp2 == '"') {
4071 while (req8dot3 && tcn1 != '.' && tcn1 != 0)
4086 * pattern character after '*' is not null or
4087 * period. If it is '?' or '>', we are not
4088 * going to understand it. If it is '*' or
4089 * '<', we are going to skip over it. None of
4090 * these are likely, I hope.
4092 /* skip over '*' and '<' */
4093 while (tcp2 == '*' || tcp2 == '<')
4096 /* skip over characters that don't match tcp2 */
4097 while (req8dot3 && tcn1 != '.' && tcn1 != 0 &&
4098 ((casefold && cm_foldUpper[tcn1] != cm_foldUpper[tcp2]) ||
4099 (!casefold && tcn1 != tcp2)))
4103 if ((req8dot3 && tcn1 == '.') || tcn1 == 0)
4106 /* Remember where we are */
4116 /* tcp1 is not a wildcard */
4117 if ((casefold && cm_foldUpper[tcn1] == cm_foldUpper[tcp1]) ||
4118 (!casefold && tcn1 == tcp1)) {
4123 /* if trying to match a star pattern, go back */
4125 maskp = starMaskp - 2;
4126 namep = starNamep + 1;
4135 #endif /* USE_OLD_MATCHING */
4137 long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
4142 long code = 0, code2 = 0;
4146 smb_dirListPatch_t *dirListPatchesp;
4147 smb_dirListPatch_t *curPatchp;
4150 long orbytes; /* # of bytes in this output record */
4151 long ohbytes; /* # of bytes, except file name */
4152 long onbytes; /* # of bytes in name, incl. term. null */
4153 osi_hyper_t dirLength;
4154 osi_hyper_t bufferOffset;
4155 osi_hyper_t curOffset;
4157 smb_dirSearch_t *dsp;
4161 cm_pageHeader_t *pageHeaderp;
4162 cm_user_t *userp = NULL;
4165 long nextEntryCookie;
4166 int numDirChunks; /* # of 32 byte dir chunks in this entry */
4167 char *op; /* output data ptr */
4168 char *origOp; /* original value of op */
4169 cm_space_t *spacep; /* for pathname buffer */
4170 long maxReturnData; /* max # of return data */
4171 long maxReturnParms; /* max # of return parms */
4172 long bytesInBuffer; /* # data bytes in the output buffer */
4174 char *maskp; /* mask part of path */
4178 smb_tran2Packet_t *outp; /* response packet */
4181 char shortName[13]; /* 8.3 name if needed */
4193 if (p->opcode == 1) {
4194 /* find first; obtain basic parameters from request */
4195 attribute = p->parmsp[0];
4196 maxCount = p->parmsp[1];
4197 infoLevel = p->parmsp[3];
4198 searchFlags = p->parmsp[2];
4199 dsp = smb_NewDirSearch(1);
4200 dsp->attribute = attribute;
4201 pathp = ((char *) p->parmsp) + 12; /* points to path */
4202 if (smb_StoreAnsiFilenames)
4203 OemToChar(pathp,pathp);
4205 maskp = strrchr(pathp, '\\');
4209 maskp++; /* skip over backslash */
4210 strcpy(dsp->mask, maskp); /* and save mask */
4211 /* track if this is likely to match a lot of entries */
4212 starPattern = smb_V3IsStarMask(maskp);
4215 osi_assert(p->opcode == 2);
4216 /* find next; obtain basic parameters from request or open dir file */
4217 dsp = smb_FindDirSearch(p->parmsp[0]);
4218 maxCount = p->parmsp[1];
4219 infoLevel = p->parmsp[2];
4220 nextCookie = p->parmsp[3] | (p->parmsp[4] << 16);
4221 searchFlags = p->parmsp[5];
4223 osi_Log2(smb_logp, "T2 search dir bad search ID: id %d nextCookie 0x%x",
4224 p->parmsp[0], nextCookie);
4225 return CM_ERROR_BADFD;
4227 attribute = dsp->attribute;
4230 starPattern = 1; /* assume, since required a Find Next */
4233 switch ( infoLevel ) {
4234 case SMB_INFO_STANDARD:
4237 case SMB_INFO_QUERY_EA_SIZE:
4238 s = "InfoQueryEaSize";
4240 case SMB_INFO_QUERY_EAS_FROM_LIST:
4241 s = "InfoQueryEasFromList";
4243 case SMB_FIND_FILE_DIRECTORY_INFO:
4244 s = "FindFileDirectoryInfo";
4246 case SMB_FIND_FILE_FULL_DIRECTORY_INFO:
4247 s = "FindFileFullDirectoryInfo";
4249 case SMB_FIND_FILE_NAMES_INFO:
4250 s = "FindFileNamesInfo";
4252 case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
4253 s = "FindFileBothDirectoryInfo";
4256 s = "unknownInfoLevel";
4259 osi_Log1(smb_logp, "T2 search dir info level: %s", s);
4262 "T2 search dir attr 0x%x, info level 0x%x, max count %d, flags 0x%x",
4263 attribute, infoLevel, maxCount, searchFlags);
4265 osi_Log3(smb_logp, "...T2 search op %d, id %d, nextCookie 0x%x",
4266 p->opcode, dsp->cookie, nextCookie);
4268 if (infoLevel > SMB_FIND_FILE_BOTH_DIRECTORY_INFO) {
4269 osi_Log1(smb_logp, "Unsupported InfoLevel 0x%x", infoLevel);
4270 smb_ReleaseDirSearch(dsp);
4271 return CM_ERROR_INVAL;
4274 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO)
4275 searchFlags &= ~4; /* no resume keys */
4277 dirListPatchesp = NULL;
4279 maxReturnData = p->maxReturnData;
4280 if (p->opcode == 1) /* find first */
4281 maxReturnParms = 10; /* bytes */
4283 maxReturnParms = 8; /* bytes */
4285 #ifndef CM_CONFIG_MULTITRAN2RESPONSES
4286 if (maxReturnData > 6000)
4287 maxReturnData = 6000;
4288 #endif /* CM_CONFIG_MULTITRAN2RESPONSES */
4290 outp = smb_GetTran2ResponsePacket(vcp, p, opx, maxReturnParms,
4293 osi_Log2(smb_logp, "T2 receive search dir count %d [%s]",
4294 maxCount, osi_LogSaveString(smb_logp, pathp));
4296 /* bail out if request looks bad */
4297 if (p->opcode == 1 && !pathp) {
4298 smb_ReleaseDirSearch(dsp);
4299 smb_FreeTran2Packet(outp);
4300 return CM_ERROR_BADSMB;
4303 osi_Log3(smb_logp, "T2 search dir id %d, nextCookie 0x%x, attr 0x%x",
4304 dsp->cookie, nextCookie, attribute);
4306 userp = smb_GetTran2User(vcp, p);
4308 osi_Log1(smb_logp, "T2 search dir unable to resolve user [%d]", p->uid);
4309 smb_ReleaseDirSearch(dsp);
4310 smb_FreeTran2Packet(outp);
4311 return CM_ERROR_BADSMB;
4314 /* try to get the vnode for the path name next */
4315 lock_ObtainMutex(&dsp->mx);
4318 osi_Log2(afsd_logp,"smb_ReceiveTran2SearchDir dsp 0x%p scp 0x%p", dsp, scp);
4322 spacep = cm_GetSpace();
4323 smb_StripLastComponent(spacep->data, NULL, pathp);
4324 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
4326 cm_ReleaseUser(userp);
4327 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOFILES);
4328 smb_FreeTran2Packet(outp);
4329 lock_ReleaseMutex(&dsp->mx);
4330 smb_DeleteDirSearch(dsp);
4331 smb_ReleaseDirSearch(dsp);
4334 code = cm_NameI(cm_data.rootSCachep, spacep->data,
4335 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
4336 userp, tidPathp, &req, &scp);
4337 cm_FreeSpace(spacep);
4340 #ifdef DFS_SUPPORT_BUT_NOT_FIND_FIRST
4341 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
4342 cm_ReleaseSCache(scp);
4343 cm_ReleaseUser(userp);
4344 if ( WANTS_DFS_PATHNAMES(p) )
4345 code = CM_ERROR_PATH_NOT_COVERED;
4347 code = CM_ERROR_BADSHARENAME;
4348 smb_SendTran2Error(vcp, p, opx, code);
4349 smb_FreeTran2Packet(outp);
4350 lock_ReleaseMutex(&dsp->mx);
4351 smb_DeleteDirSearch(dsp);
4352 smb_ReleaseDirSearch(dsp);
4355 #endif /* DFS_SUPPORT */
4357 osi_Log2(afsd_logp,"smb_ReceiveTran2SearchDir dsp 0x%p scp 0x%p", dsp, scp);
4358 /* we need one hold for the entry we just stored into,
4359 * and one for our own processing. When we're done
4360 * with this function, we'll drop the one for our own
4361 * processing. We held it once from the namei call,
4362 * and so we do another hold now.
4365 lock_ObtainMutex(&scp->mx);
4366 if ((scp->flags & CM_SCACHEFLAG_BULKSTATTING) == 0 &&
4367 LargeIntegerGreaterOrEqualToZero(scp->bulkStatProgress)) {
4368 scp->flags |= CM_SCACHEFLAG_BULKSTATTING;
4369 dsp->flags |= SMB_DIRSEARCH_BULKST;
4371 lock_ReleaseMutex(&scp->mx);
4374 lock_ReleaseMutex(&dsp->mx);
4376 cm_ReleaseUser(userp);
4377 smb_FreeTran2Packet(outp);
4378 smb_DeleteDirSearch(dsp);
4379 smb_ReleaseDirSearch(dsp);
4383 /* get the directory size */
4384 lock_ObtainMutex(&scp->mx);
4385 code = cm_SyncOp(scp, NULL, userp, &req, 0,
4386 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4388 lock_ReleaseMutex(&scp->mx);
4389 cm_ReleaseSCache(scp);
4390 cm_ReleaseUser(userp);
4391 smb_FreeTran2Packet(outp);
4392 smb_DeleteDirSearch(dsp);
4393 smb_ReleaseDirSearch(dsp);
4397 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4400 dirLength = scp->length;
4402 bufferOffset.LowPart = bufferOffset.HighPart = 0;
4403 curOffset.HighPart = 0;
4404 curOffset.LowPart = nextCookie;
4405 origOp = outp->datap;
4413 if (searchFlags & 4)
4414 /* skip over resume key */
4417 /* make sure that curOffset.LowPart doesn't point to the first
4418 * 32 bytes in the 2nd through last dir page, and that it doesn't
4419 * point at the first 13 32-byte chunks in the first dir page,
4420 * since those are dir and page headers, and don't contain useful
4423 temp = curOffset.LowPart & (2048-1);
4424 if (curOffset.HighPart == 0 && curOffset.LowPart < 2048) {
4425 /* we're in the first page */
4426 if (temp < 13*32) temp = 13*32;
4429 /* we're in a later dir page */
4430 if (temp < 32) temp = 32;
4433 /* make sure the low order 5 bits are zero */
4436 /* now put temp bits back ito curOffset.LowPart */
4437 curOffset.LowPart &= ~(2048-1);
4438 curOffset.LowPart |= temp;
4440 /* check if we've passed the dir's EOF */
4441 if (LargeIntegerGreaterThanOrEqualTo(curOffset, dirLength)) {
4442 osi_Log0(smb_logp, "T2 search dir passed eof");
4447 /* check if we've returned all the names that will fit in the
4448 * response packet; we check return count as well as the number
4449 * of bytes requested. We check the # of bytes after we find
4450 * the dir entry, since we'll need to check its size.
4452 if (returnedNames >= maxCount) {
4453 osi_Log2(smb_logp, "T2 search dir returnedNames %d >= maxCount %d",
4454 returnedNames, maxCount);
4458 /* see if we can use the bufferp we have now; compute in which
4459 * page the current offset would be, and check whether that's
4460 * the offset of the buffer we have. If not, get the buffer.
4462 thyper.HighPart = curOffset.HighPart;
4463 thyper.LowPart = curOffset.LowPart & ~(cm_data.buf_blockSize-1);
4464 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
4467 buf_Release(bufferp);
4470 lock_ReleaseMutex(&scp->mx);
4471 lock_ObtainRead(&scp->bufCreateLock);
4472 code = buf_Get(scp, &thyper, &bufferp);
4473 lock_ReleaseRead(&scp->bufCreateLock);
4474 lock_ObtainMutex(&dsp->mx);
4476 /* now, if we're doing a star match, do bulk fetching
4477 * of all of the status info for files in the dir.
4480 smb_ApplyV3DirListPatches(scp, &dirListPatchesp,
4483 lock_ObtainMutex(&scp->mx);
4484 if ((dsp->flags & SMB_DIRSEARCH_BULKST) &&
4485 LargeIntegerGreaterThanOrEqualTo(thyper, scp->bulkStatProgress)) {
4486 /* Don't bulk stat if risking timeout */
4487 int now = GetTickCount();
4488 if (now - req.startTime > RDRtimeout) {
4489 scp->bulkStatProgress = thyper;
4490 scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
4491 dsp->flags &= ~SMB_DIRSEARCH_BULKST;
4493 code = cm_TryBulkStat(scp, &thyper, userp, &req);
4496 lock_ObtainMutex(&scp->mx);
4498 lock_ReleaseMutex(&dsp->mx);
4500 osi_Log2(smb_logp, "T2 search dir buf_Get scp %x failed %d", scp, code);
4504 bufferOffset = thyper;
4506 /* now get the data in the cache */
4508 code = cm_SyncOp(scp, bufferp, userp, &req,
4510 CM_SCACHESYNC_NEEDCALLBACK
4511 | CM_SCACHESYNC_READ);
4513 osi_Log2(smb_logp, "T2 search dir cm_SyncOp scp %x failed %d", scp, code);
4517 cm_SyncOpDone(scp, bufferp, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ);
4519 if (cm_HaveBuffer(scp, bufferp, 0)) {
4520 osi_Log2(smb_logp, "T2 search dir !HaveBuffer scp %x bufferp %x", scp, bufferp);
4524 /* otherwise, load the buffer and try again */
4525 code = cm_GetBuffer(scp, bufferp, NULL, userp,
4528 osi_Log3(smb_logp, "T2 search dir cm_GetBuffer failed scp %x bufferp %x code %d",
4529 scp, bufferp, code);
4534 buf_Release(bufferp);
4538 } /* if (wrong buffer) ... */
4540 /* now we have the buffer containing the entry we're interested
4541 * in; copy it out if it represents a non-deleted entry.
4543 entryInDir = curOffset.LowPart & (2048-1);
4544 entryInBuffer = curOffset.LowPart & (cm_data.buf_blockSize - 1);
4546 /* page header will help tell us which entries are free. Page
4547 * header can change more often than once per buffer, since
4548 * AFS 3 dir page size may be less than (but not more than)
4549 * a buffer package buffer.
4551 /* only look intra-buffer */
4552 temp = curOffset.LowPart & (cm_data.buf_blockSize - 1);
4553 temp &= ~(2048 - 1); /* turn off intra-page bits */
4554 pageHeaderp = (cm_pageHeader_t *) (bufferp->datap + temp);
4556 /* now determine which entry we're looking at in the page.
4557 * If it is free (there's a free bitmap at the start of the
4558 * dir), we should skip these 32 bytes.
4560 slotInPage = (entryInDir & 0x7e0) >> 5;
4561 if (!(pageHeaderp->freeBitmap[slotInPage>>3] &
4562 (1 << (slotInPage & 0x7)))) {
4563 /* this entry is free */
4564 numDirChunks = 1; /* only skip this guy */
4568 tp = bufferp->datap + entryInBuffer;
4569 dep = (cm_dirEntry_t *) tp; /* now points to AFS3 dir entry */
4571 /* while we're here, compute the next entry's location, too,
4572 * since we'll need it when writing out the cookie into the dir
4575 * XXXX Probably should do more sanity checking.
4577 numDirChunks = cm_NameEntries(dep->name, &onbytes);
4579 /* compute offset of cookie representing next entry */
4580 nextEntryCookie = curOffset.LowPart + (CM_DIR_CHUNKSIZE * numDirChunks);
4582 /* Need 8.3 name? */
4584 if (infoLevel == SMB_FIND_FILE_BOTH_DIRECTORY_INFO
4585 && dep->fid.vnode != 0
4586 && !cm_Is8Dot3(dep->name)) {
4587 cm_Gen8Dot3Name(dep, shortName, &shortNameEnd);
4591 osi_Log4(smb_logp, "T2 search dir vn %u uniq %u name %s (%s)",
4592 dep->fid.vnode, dep->fid.unique,
4593 osi_LogSaveString(smb_logp, dep->name),
4594 NeedShortName ? osi_LogSaveString(smb_logp, shortName) : "");
4596 /* When matching, we are using doing a case fold if we have a wildcard mask.
4597 * If we get a non-wildcard match, it's a lookup for a specific file.
4599 if (dep->fid.vnode != 0 &&
4600 (smb_V3MatchMask(dep->name, maskp, (starPattern? CM_FLAG_CASEFOLD : 0)) ||
4602 smb_V3MatchMask(shortName, maskp, CM_FLAG_CASEFOLD)))) {
4604 /* Eliminate entries that don't match requested attributes */
4605 if (smb_hideDotFiles && !(dsp->attribute & SMB_ATTR_HIDDEN) &&
4606 smb_IsDotFile(dep->name)) {
4607 osi_Log0(smb_logp, "T2 search dir skipping hidden");
4608 goto nextEntry; /* no hidden files */
4610 if (!(dsp->attribute & SMB_ATTR_DIRECTORY)) /* no directories */
4612 /* We have already done the cm_TryBulkStat above */
4613 fid.cell = scp->fid.cell;
4614 fid.volume = scp->fid.volume;
4615 fid.vnode = ntohl(dep->fid.vnode);
4616 fid.unique = ntohl(dep->fid.unique);
4617 fileType = cm_FindFileType(&fid);
4618 /*osi_Log2(smb_logp, "smb_ReceiveTran2SearchDir: file %s "
4619 "has filetype %d", dep->name,
4621 if (fileType == CM_SCACHETYPE_DIRECTORY ||
4622 fileType == CM_SCACHETYPE_DFSLINK ||
4623 fileType == CM_SCACHETYPE_INVALID)
4624 osi_Log0(smb_logp, "T2 search dir skipping directory or bad link");
4628 /* finally check if this name will fit */
4630 /* standard dir entry stuff */
4631 if (infoLevel < 0x101)
4632 ohbytes = 23; /* pre-NT */
4633 else if (infoLevel == SMB_FIND_FILE_NAMES_INFO)
4634 ohbytes = 12; /* NT names only */
4636 ohbytes = 64; /* NT */
4638 if (infoLevel == SMB_FIND_FILE_BOTH_DIRECTORY_INFO)
4639 ohbytes += 26; /* Short name & length */
4641 if (searchFlags & 4) {
4642 ohbytes += 4; /* if resume key required */
4645 if (infoLevel != SMB_INFO_STANDARD
4646 && infoLevel != SMB_FIND_FILE_DIRECTORY_INFO
4647 && infoLevel != SMB_FIND_FILE_NAMES_INFO)
4648 ohbytes += 4; /* EASIZE */
4650 /* add header to name & term. null */
4651 orbytes = onbytes + ohbytes + 1;
4653 /* now, we round up the record to a 4 byte alignment,
4654 * and we make sure that we have enough room here for
4655 * even the aligned version (so we don't have to worry
4656 * about an * overflow when we pad things out below).
4657 * That's the reason for the alignment arithmetic below.
4659 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO)
4660 align = (4 - (orbytes & 3)) & 3;
4663 if (orbytes + bytesInBuffer + align > maxReturnData) {
4664 osi_Log1(smb_logp, "T2 dir search exceed max return data %d",
4669 /* this is one of the entries to use: it is not deleted
4670 * and it matches the star pattern we're looking for.
4671 * Put out the name, preceded by its length.
4673 /* First zero everything else */
4674 memset(origOp, 0, ohbytes);
4676 if (infoLevel <= SMB_FIND_FILE_DIRECTORY_INFO)
4677 *(origOp + ohbytes - 1) = (unsigned char) onbytes;
4678 else if (infoLevel == SMB_FIND_FILE_NAMES_INFO)
4679 *((u_long *)(op + 8)) = onbytes;
4681 *((u_long *)(op + 60)) = onbytes;
4682 strcpy(origOp+ohbytes, dep->name);
4683 if (smb_StoreAnsiFilenames)
4684 CharToOem(origOp+ohbytes, origOp+ohbytes);
4686 /* Short name if requested and needed */
4687 if (infoLevel == SMB_FIND_FILE_BOTH_DIRECTORY_INFO) {
4688 if (NeedShortName) {
4689 strcpy(op + 70, shortName);
4690 if (smb_StoreAnsiFilenames)
4691 CharToOem(op + 70, op + 70);
4692 *(op + 68) = (char)(shortNameEnd - shortName);
4696 /* now, adjust the # of entries copied */
4699 /* NextEntryOffset and FileIndex */
4700 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO) {
4701 int entryOffset = orbytes + align;
4702 *((u_long *)op) = entryOffset;
4703 *((u_long *)(op+4)) = nextEntryCookie;
4706 /* now we emit the attribute. This is tricky, since
4707 * we need to really stat the file to find out what
4708 * type of entry we've got. Right now, we're copying
4709 * out data from a buffer, while holding the scp
4710 * locked, so it isn't really convenient to stat
4711 * something now. We'll put in a place holder
4712 * now, and make a second pass before returning this
4713 * to get the real attributes. So, we just skip the
4714 * data for now, and adjust it later. We allocate a
4715 * patch record to make it easy to find this point
4716 * later. The replay will happen at a time when it is
4717 * safe to unlock the directory.
4719 if (infoLevel != SMB_FIND_FILE_NAMES_INFO) {
4720 curPatchp = malloc(sizeof(*curPatchp));
4721 osi_QAdd((osi_queue_t **) &dirListPatchesp,
4723 curPatchp->dptr = op;
4724 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO)
4725 curPatchp->dptr += 8;
4727 if (smb_hideDotFiles && smb_IsDotFile(dep->name)) {
4728 curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
4731 curPatchp->flags = 0;
4733 curPatchp->fid.cell = scp->fid.cell;
4734 curPatchp->fid.volume = scp->fid.volume;
4735 curPatchp->fid.vnode = ntohl(dep->fid.vnode);
4736 curPatchp->fid.unique = ntohl(dep->fid.unique);
4739 curPatchp->dep = dep;
4742 if (searchFlags & 4)
4743 /* put out resume key */
4744 *((u_long *)origOp) = nextEntryCookie;
4746 /* Adjust byte ptr and count */
4747 origOp += orbytes; /* skip entire record */
4748 bytesInBuffer += orbytes;
4750 /* and pad the record out */
4751 while (--align >= 0) {
4755 } /* if we're including this name */
4756 else if (!starPattern &&
4758 dep->fid.vnode != 0 &&
4759 smb_V3MatchMask(dep->name, maskp, CM_FLAG_CASEFOLD)) {
4760 /* We were looking for exact matches, but here's an inexact one*/
4765 /* and adjust curOffset to be where the new cookie is */
4766 thyper.HighPart = 0;
4767 thyper.LowPart = CM_DIR_CHUNKSIZE * numDirChunks;
4768 curOffset = LargeIntegerAdd(thyper, curOffset);
4769 } /* while copying data for dir listing */
4771 /* If we didn't get a star pattern, we did an exact match during the first pass.
4772 * If there were no exact matches found, we fail over to inexact matches by
4773 * marking the query as a star pattern (matches all case permutations), and
4774 * re-running the query.
4776 if (returnedNames == 0 && !starPattern && foundInexact) {
4777 osi_Log0(afsd_logp,"T2 Search: No exact matches. Re-running for inexact matches");
4782 /* release the mutex */
4783 lock_ReleaseMutex(&scp->mx);
4785 buf_Release(bufferp);
4789 /* apply and free last set of patches; if not doing a star match, this
4790 * will be empty, but better safe (and freeing everything) than sorry.
4792 code2 = smb_ApplyV3DirListPatches(scp, &dirListPatchesp, infoLevel, userp,
4795 /* now put out the final parameters */
4796 if (returnedNames == 0)
4798 if (p->opcode == 1) {
4800 outp->parmsp[0] = (unsigned short) dsp->cookie;
4801 outp->parmsp[1] = returnedNames;
4802 outp->parmsp[2] = eos;
4803 outp->parmsp[3] = 0; /* nothing wrong with EAS */
4804 outp->parmsp[4] = 0;
4805 /* don't need last name to continue
4806 * search, cookie is enough. Normally,
4807 * this is the offset of the file name
4808 * of the last entry returned.
4810 outp->totalParms = 10; /* in bytes */
4814 outp->parmsp[0] = returnedNames;
4815 outp->parmsp[1] = eos;
4816 outp->parmsp[2] = 0; /* EAS error */
4817 outp->parmsp[3] = 0; /* last name, as above */
4818 outp->totalParms = 8; /* in bytes */
4821 /* return # of bytes in the buffer */
4822 outp->totalData = bytesInBuffer;
4824 /* Return error code if unsuccessful on first request */
4825 if (code == 0 && p->opcode == 1 && returnedNames == 0)
4826 code = CM_ERROR_NOSUCHFILE;
4828 osi_Log4(smb_logp, "T2 search dir done, opcode %d, id %d, %d names, code %d",
4829 p->opcode, dsp->cookie, returnedNames, code);
4831 /* if we're supposed to close the search after this request, or if
4832 * we're supposed to close the search if we're done, and we're done,
4833 * or if something went wrong, close the search.
4835 /* ((searchFlags & 1) || ((searchFlags & 2) && eos) */
4836 if ((searchFlags & 1) || (returnedNames == 0) ||
4837 ((searchFlags & 2) && eos) || code != 0)
4838 smb_DeleteDirSearch(dsp);
4840 smb_SendTran2Error(vcp, p, opx, code);
4842 smb_SendTran2Packet(vcp, outp, opx);
4844 smb_FreeTran2Packet(outp);
4845 smb_ReleaseDirSearch(dsp);
4846 cm_ReleaseSCache(scp);
4847 cm_ReleaseUser(userp);
4851 long smb_ReceiveV3FindClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4854 smb_dirSearch_t *dsp;
4856 dirHandle = smb_GetSMBParm(inp, 0);
4858 osi_Log1(smb_logp, "SMB3 find close handle %d", dirHandle);
4860 dsp = smb_FindDirSearch(dirHandle);
4863 return CM_ERROR_BADFD;
4865 /* otherwise, we have an FD to destroy */
4866 smb_DeleteDirSearch(dsp);
4867 smb_ReleaseDirSearch(dsp);
4869 /* and return results */
4870 smb_SetSMBDataLength(outp, 0);
4875 long smb_ReceiveV3FindNotifyClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4877 smb_SetSMBDataLength(outp, 0);
4881 long smb_ReceiveV3OpenX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4888 cm_scache_t *dscp; /* dir we're dealing with */
4889 cm_scache_t *scp; /* file we're creating */
4891 int initialModeBits;
4901 int parmSlot; /* which parm we're dealing with */
4910 extraInfo = (smb_GetSMBParm(inp, 2) & 1); /* return extra info */
4911 openFun = smb_GetSMBParm(inp, 8); /* open function */
4912 excl = ((openFun & 3) == 0);
4913 trunc = ((openFun & 3) == 2); /* truncate it */
4914 openMode = (smb_GetSMBParm(inp, 3) & 0x7);
4915 openAction = 0; /* tracks what we did */
4917 attributes = smb_GetSMBParm(inp, 5);
4918 dosTime = smb_GetSMBParm(inp, 6) | (smb_GetSMBParm(inp, 7) << 16);
4920 /* compute initial mode bits based on read-only flag in attributes */
4921 initialModeBits = 0666;
4922 if (attributes & SMB_ATTR_READONLY)
4923 initialModeBits &= ~0222;
4925 pathp = smb_GetSMBData(inp, NULL);
4926 if (smb_StoreAnsiFilenames)
4927 OemToChar(pathp,pathp);
4929 spacep = inp->spacep;
4930 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
4932 if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
4933 /* special case magic file name for receiving IOCTL requests
4934 * (since IOCTL calls themselves aren't getting through).
4937 osi_Log0(smb_logp, "IOCTL Open");
4940 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
4941 smb_SetupIoctlFid(fidp, spacep);
4943 /* set inp->fid so that later read calls in same msg can find fid */
4944 inp->fid = fidp->fid;
4946 /* copy out remainder of the parms */
4948 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
4950 smb_SetSMBParm(outp, parmSlot, /* attrs */ 0); parmSlot++;
4951 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* mod time */
4952 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
4953 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* len */
4954 smb_SetSMBParm(outp, parmSlot, 0x7fff); parmSlot++;
4955 smb_SetSMBParm(outp, parmSlot, openMode); parmSlot++;
4956 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* file type 0 ==> normal file or dir */
4957 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* IPC junk */
4959 /* and the final "always present" stuff */
4960 smb_SetSMBParm(outp, parmSlot, /* openAction found existing file */ 1); parmSlot++;
4961 /* next write out the "unique" ID */
4962 smb_SetSMBParm(outp, parmSlot, 0x1234); parmSlot++;
4963 smb_SetSMBParm(outp, parmSlot, 0x5678); parmSlot++;
4964 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
4965 smb_SetSMBDataLength(outp, 0);
4967 /* and clean up fid reference */
4968 smb_ReleaseFID(fidp);
4972 #ifdef DEBUG_VERBOSE
4974 char *hexp, *asciip;
4975 asciip = (lastNamep ? lastNamep : pathp );
4976 hexp = osi_HexifyString(asciip);
4977 DEBUG_EVENT2("AFS", "V3Open H[%s] A[%s]", hexp, asciip );
4981 userp = smb_GetUserFromVCP(vcp, inp);
4984 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4986 cm_ReleaseUser(userp);
4987 return CM_ERROR_NOSUCHPATH;
4989 code = cm_NameI(cm_data.rootSCachep, pathp,
4990 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
4991 userp, tidPathp, &req, &scp);
4994 if (code == 0 && scp->fileType == CM_SCACHETYPE_DFSLINK) {
4995 cm_ReleaseSCache(scp);
4996 cm_ReleaseUser(userp);
4997 if ( WANTS_DFS_PATHNAMES(inp) )
4998 return CM_ERROR_PATH_NOT_COVERED;
5000 return CM_ERROR_BADSHARENAME;
5002 #endif /* DFS_SUPPORT */
5005 code = cm_NameI(cm_data.rootSCachep, spacep->data,
5006 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
5007 userp, tidPathp, &req, &dscp);
5009 cm_ReleaseUser(userp);
5014 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
5015 cm_ReleaseSCache(dscp);
5016 cm_ReleaseUser(userp);
5017 if ( WANTS_DFS_PATHNAMES(inp) )
5018 return CM_ERROR_PATH_NOT_COVERED;
5020 return CM_ERROR_BADSHARENAME;
5022 #endif /* DFS_SUPPORT */
5023 /* otherwise, scp points to the parent directory. Do a lookup,
5024 * and truncate the file if we find it, otherwise we create the
5031 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD, userp,
5033 if (code && code != CM_ERROR_NOSUCHFILE) {
5034 cm_ReleaseSCache(dscp);
5035 cm_ReleaseUser(userp);
5040 /* if we get here, if code is 0, the file exists and is represented by
5041 * scp. Otherwise, we have to create it. The dir may be represented
5042 * by dscp, or we may have found the file directly. If code is non-zero,
5046 code = cm_CheckOpen(scp, openMode, trunc, userp, &req);
5048 if (dscp) cm_ReleaseSCache(dscp);
5049 cm_ReleaseSCache(scp);
5050 cm_ReleaseUser(userp);
5055 /* oops, file shouldn't be there */
5057 cm_ReleaseSCache(dscp);
5058 cm_ReleaseSCache(scp);
5059 cm_ReleaseUser(userp);
5060 return CM_ERROR_EXISTS;
5064 setAttr.mask = CM_ATTRMASK_LENGTH;
5065 setAttr.length.LowPart = 0;
5066 setAttr.length.HighPart = 0;
5067 code = cm_SetAttr(scp, &setAttr, userp, &req);
5068 openAction = 3; /* truncated existing file */
5070 else openAction = 1; /* found existing file */
5072 else if (!(openFun & SMB_ATTR_DIRECTORY)) {
5073 /* don't create if not found */
5074 if (dscp) cm_ReleaseSCache(dscp);
5075 cm_ReleaseUser(userp);
5076 return CM_ERROR_NOSUCHFILE;
5079 osi_assert(dscp != NULL);
5080 osi_Log1(smb_logp, "smb_ReceiveV3OpenX creating file %s",
5081 osi_LogSaveString(smb_logp, lastNamep));
5082 openAction = 2; /* created file */
5083 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
5084 smb_UnixTimeFromDosUTime(&setAttr.clientModTime, dosTime);
5085 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
5089 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
5090 smb_NotifyChange(FILE_ACTION_ADDED,
5091 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
5092 dscp, lastNamep, NULL, TRUE);
5093 } else if (!excl && code == CM_ERROR_EXISTS) {
5094 /* not an exclusive create, and someone else tried
5095 * creating it already, then we open it anyway. We
5096 * don't bother retrying after this, since if this next
5097 * fails, that means that the file was deleted after we
5098 * started this call.
5100 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
5104 setAttr.mask = CM_ATTRMASK_LENGTH;
5105 setAttr.length.LowPart = 0;
5106 setAttr.length.HighPart = 0;
5107 code = cm_SetAttr(scp, &setAttr, userp, &req);
5109 } /* lookup succeeded */
5113 /* we don't need this any longer */
5115 cm_ReleaseSCache(dscp);
5118 /* something went wrong creating or truncating the file */
5120 cm_ReleaseSCache(scp);
5121 cm_ReleaseUser(userp);
5125 /* make sure we're about to open a file */
5126 if (scp->fileType != CM_SCACHETYPE_FILE) {
5127 cm_ReleaseSCache(scp);
5128 cm_ReleaseUser(userp);
5129 return CM_ERROR_ISDIR;
5132 /* now all we have to do is open the file itself */
5133 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
5137 lock_ObtainMutex(&fidp->mx);
5138 /* save a pointer to the vnode */
5140 lock_ObtainMutex(&scp->mx);
5141 scp->flags |= CM_SCACHEFLAG_SMB_FID;
5142 lock_ReleaseMutex(&scp->mx);
5143 osi_Log2(afsd_logp,"smb_ReceiveV3OpenX fidp 0x%p scp 0x%p", fidp, scp);
5145 fidp->userp = userp;
5147 /* compute open mode */
5149 fidp->flags |= SMB_FID_OPENREAD;
5150 if (openMode == 1 || openMode == 2)
5151 fidp->flags |= SMB_FID_OPENWRITE;
5153 /* remember if the file was newly created */
5155 fidp->flags |= SMB_FID_CREATED;
5157 lock_ReleaseMutex(&fidp->mx);
5158 smb_ReleaseFID(fidp);
5160 cm_Open(scp, 0, userp);
5162 /* set inp->fid so that later read calls in same msg can find fid */
5163 inp->fid = fidp->fid;
5165 /* copy out remainder of the parms */
5167 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
5168 lock_ObtainMutex(&scp->mx);
5170 smb_SetSMBParm(outp, parmSlot, smb_Attributes(scp)); parmSlot++;
5171 smb_DosUTimeFromUnixTime(&dosTime, scp->clientModTime);
5172 smb_SetSMBParm(outp, parmSlot, dosTime & 0xffff); parmSlot++;
5173 smb_SetSMBParm(outp, parmSlot, (dosTime>>16) & 0xffff); parmSlot++;
5174 smb_SetSMBParm(outp, parmSlot, scp->length.LowPart & 0xffff); parmSlot++;
5175 smb_SetSMBParm(outp, parmSlot, (scp->length.LowPart >> 16) & 0xffff); parmSlot++;
5176 smb_SetSMBParm(outp, parmSlot, openMode); parmSlot++;
5177 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* file type 0 ==> normal file or dir */
5178 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* IPC junk */
5180 /* and the final "always present" stuff */
5181 smb_SetSMBParm(outp, parmSlot, openAction); parmSlot++;
5182 /* next write out the "unique" ID */
5183 smb_SetSMBParm(outp, parmSlot, scp->fid.vnode & 0xffff); parmSlot++;
5184 smb_SetSMBParm(outp, parmSlot, scp->fid.volume & 0xffff); parmSlot++;
5185 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
5186 lock_ReleaseMutex(&scp->mx);
5187 smb_SetSMBDataLength(outp, 0);
5189 osi_Log1(smb_logp, "SMB OpenX opening fid %d", fidp->fid);
5191 cm_ReleaseUser(userp);
5192 /* leave scp held since we put it in fidp->scp */
5196 static void smb_GetLockParams(unsigned char LockType,
5198 unsigned int * ppid,
5199 LARGE_INTEGER * pOffset,
5200 LARGE_INTEGER * pLength)
5202 if (LockType & LOCKING_ANDX_LARGE_FILES) {
5204 *ppid = *((USHORT *) *buf);
5205 pOffset->HighPart = *((LONG *)(*buf + 4));
5206 pOffset->LowPart = *((DWORD *)(*buf + 8));
5207 pLength->HighPart = *((LONG *)(*buf + 12));
5208 pLength->LowPart = *((DWORD *)(*buf + 16));
5212 /* Not Large Files */
5213 *ppid = *((USHORT *) *buf);
5214 pOffset->HighPart = 0;
5215 pOffset->LowPart = *((DWORD *)(*buf + 2));
5216 pLength->HighPart = 0;
5217 pLength->LowPart = *((DWORD *)(*buf + 6));
5222 long smb_ReceiveV3LockingX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5229 unsigned char LockType;
5230 unsigned short NumberOfUnlocks, NumberOfLocks;
5234 LARGE_INTEGER LOffset, LLength;
5235 smb_waitingLockRequest_t *wlRequest = NULL;
5236 cm_file_lock_t *lockp;
5244 fid = smb_GetSMBParm(inp, 2);
5245 fid = smb_ChainFID(fid, inp);
5247 fidp = smb_FindFID(vcp, fid, 0);
5249 return CM_ERROR_BADFD;
5251 lock_ObtainMutex(&fidp->mx);
5252 if (fidp->flags & SMB_FID_IOCTL) {
5253 osi_Log0(smb_logp, "smb_ReceiveV3Locking BadFD");
5254 lock_ReleaseMutex(&fidp->mx);
5255 smb_ReleaseFID(fidp);
5256 return CM_ERROR_BADFD;
5259 osi_Log2(afsd_logp,"smb_ReceiveV3LockingX fidp 0x%p scp 0x%p", fidp, scp);
5261 lock_ReleaseMutex(&fidp->mx);
5263 /* set inp->fid so that later read calls in same msg can find fid */
5266 userp = smb_GetUserFromVCP(vcp, inp);
5269 lock_ObtainMutex(&scp->mx);
5270 code = cm_SyncOp(scp, NULL, userp, &req, 0,
5271 CM_SCACHESYNC_NEEDCALLBACK
5272 | CM_SCACHESYNC_GETSTATUS
5273 | CM_SCACHESYNC_LOCK);
5275 osi_Log1(smb_logp, "smb_ReceiveV3Locking SyncOp failure code 0x%x", code);
5279 LockType = smb_GetSMBParm(inp, 3) & 0xff;
5280 Timeout = (smb_GetSMBParm(inp, 5) << 16) + smb_GetSMBParm(inp, 4);
5281 NumberOfUnlocks = smb_GetSMBParm(inp, 6);
5282 NumberOfLocks = smb_GetSMBParm(inp, 7);
5284 if ((LockType & LOCKING_ANDX_CANCEL_LOCK) ||
5285 (LockType & LOCKING_ANDX_CHANGE_LOCKTYPE)) {
5287 /* We don't support these requests. Apparently, we can safely
5288 not deal with them too. */
5289 osi_Log1(smb_logp, "smb_ReceiveV3Locking received unsupported request [%s]",
5290 ((LockType & LOCKING_ANDX_CANCEL_LOCK)?
5291 "LOCKING_ANDX_CANCEL_LOCK":
5292 "LOCKING_ANDX_CHANGE_LOCKTYPE"));
5293 /* No need to call osi_LogSaveString since these are string
5296 code = CM_ERROR_BADOP;
5301 op = smb_GetSMBData(inp, NULL);
5303 for (i=0; i<NumberOfUnlocks; i++) {
5304 smb_GetLockParams(LockType, &op, &pid, &LOffset, &LLength);
5306 key = cm_GenerateKey(vcp->vcID, pid, fidp->fid);
5308 code = cm_Unlock(scp, LockType, LOffset, LLength, key, userp, &req);
5316 for (i=0; i<NumberOfLocks; i++) {
5317 smb_GetLockParams(LockType, &op, &pid, &LOffset, &LLength);
5319 key = cm_GenerateKey(vcp->vcID, pid, fidp->fid);
5321 code = cm_Lock(scp, LockType, LOffset, LLength, key, (Timeout != 0),
5322 userp, &req, &lockp);
5324 if (code == CM_ERROR_WOULDBLOCK && Timeout != 0) {
5325 smb_waitingLock_t * wLock;
5327 /* Put on waiting list */
5328 if(wlRequest == NULL) {
5332 LARGE_INTEGER tOffset, tLength;
5334 wlRequest = malloc(sizeof(smb_waitingLockRequest_t));
5336 osi_assert(wlRequest != NULL);
5338 wlRequest->vcp = vcp;
5340 wlRequest->scp = scp;
5341 osi_Log2(afsd_logp,"smb_ReceiveV3LockingX wlRequest 0x%p scp 0x%p", wlRequest, scp);
5343 wlRequest->inp = smb_CopyPacket(inp);
5344 wlRequest->outp = smb_CopyPacket(outp);
5345 wlRequest->lockType = LockType;
5346 wlRequest->timeRemaining = Timeout;
5347 wlRequest->locks = NULL;
5349 /* The waiting lock request needs to have enough
5350 information to undo all the locks in the request.
5351 We do the following to store info about locks that
5352 have already been granted. Sure, we can get most
5353 of the info from the packet, but the packet doesn't
5354 hold the result of cm_Lock call. In practice we
5355 only receive packets with one or two locks, so we
5356 are only wasting a few bytes here and there and
5357 only for a limited period of time until the waiting
5358 lock times out or is freed. */
5360 for(opt = op_locks, j=i; j > 0; j--) {
5361 smb_GetLockParams(LockType, &opt, &pid, &tOffset, &tLength);
5363 tkey = cm_GenerateKey(vcp->vcID, pid, fidp->fid);
5365 wLock = malloc(sizeof(smb_waitingLock_t));
5367 osi_assert(wLock != NULL);
5370 wLock->LOffset = tOffset;
5371 wLock->LLength = tLength;
5372 wLock->lockp = NULL;
5373 wLock->state = SMB_WAITINGLOCKSTATE_DONE;
5374 osi_QAdd((osi_queue_t **) &wlRequest->locks,
5379 wLock = malloc(sizeof(smb_waitingLock_t));
5381 osi_assert(wLock != NULL);
5384 wLock->LOffset = LOffset;
5385 wLock->LLength = LLength;
5386 wLock->lockp = lockp;
5387 wLock->state = SMB_WAITINGLOCKSTATE_WAITING;
5388 osi_QAdd((osi_queue_t **) &wlRequest->locks,
5391 osi_Log1(smb_logp, "smb_ReceiveV3Locking WaitingLock created 0x%p",
5399 osi_Log1(smb_logp, "smb_ReceiveV3Locking cm_Lock failure code 0x%x", code);
5406 /* Since something went wrong with the lock number i, we now
5407 have to go ahead and release any locks acquired before the
5408 failure. All locks before lock number i (of which there
5409 are i of them) have either been successful or are waiting.
5410 Either case requires calling cm_Unlock(). */
5412 /* And purge the waiting lock */
5413 if(wlRequest != NULL) {
5414 smb_waitingLock_t * wl;
5415 smb_waitingLock_t * wlNext;
5418 for(wl = wlRequest->locks; wl; wl = wlNext) {
5420 wlNext = (smb_waitingLock_t *) osi_QNext(&wl->q);
5422 ul_code = cm_Unlock(scp, LockType, wl->LOffset, wl->LLength, wl->key, userp, &req);
5425 osi_Log1(smb_logp, "smb_ReceiveV3Locking cm_Unlock returns code %d", ul_code);
5427 osi_Log0(smb_logp, "smb_ReceiveV3Locking cm_Unlock successful");
5430 osi_QRemove((osi_queue_t **) &wlRequest->locks, &wl->q);
5435 smb_ReleaseVC(wlRequest->vcp);
5436 cm_ReleaseSCache(wlRequest->scp);
5437 smb_FreePacket(wlRequest->inp);
5438 smb_FreePacket(wlRequest->outp);
5447 if (wlRequest != NULL) {
5449 lock_ObtainWrite(&smb_globalLock);
5450 osi_QAdd((osi_queue_t **)&smb_allWaitingLocks,
5452 osi_Wakeup((LONG_PTR)&smb_allWaitingLocks);
5453 lock_ReleaseWrite(&smb_globalLock);
5455 /* don't send reply immediately */
5456 outp->flags |= SMB_PACKETFLAG_NOSEND;
5459 smb_SetSMBDataLength(outp, 0);
5463 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_LOCK);
5466 lock_ReleaseMutex(&scp->mx);
5467 cm_ReleaseSCache(scp);
5468 cm_ReleaseUser(userp);
5469 smb_ReleaseFID(fidp);
5474 long smb_ReceiveV3GetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5480 afs_uint32 searchTime;
5486 fid = smb_GetSMBParm(inp, 0);
5487 fid = smb_ChainFID(fid, inp);
5489 fidp = smb_FindFID(vcp, fid, 0);
5491 return CM_ERROR_BADFD;
5493 lock_ObtainMutex(&fidp->mx);
5494 if (fidp->flags & SMB_FID_IOCTL) {
5495 lock_ReleaseMutex(&fidp->mx);
5496 smb_ReleaseFID(fidp);
5497 return CM_ERROR_BADFD;
5500 osi_Log2(afsd_logp,"smb_ReceiveV3GetAttributes fidp 0x%p scp 0x%p", fidp, scp);
5502 lock_ReleaseMutex(&fidp->mx);
5504 userp = smb_GetUserFromVCP(vcp, inp);
5507 /* otherwise, stat the file */
5508 lock_ObtainMutex(&scp->mx);
5509 code = cm_SyncOp(scp, NULL, userp, &req, 0,
5510 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5514 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5516 /* decode times. We need a search time, but the response to this
5517 * call provides the date first, not the time, as returned in the
5518 * searchTime variable. So we take the high-order bits first.
5520 smb_SearchTimeFromUnixTime(&searchTime, scp->clientModTime);
5521 smb_SetSMBParm(outp, 0, (searchTime >> 16) & 0xffff); /* ctime */
5522 smb_SetSMBParm(outp, 1, searchTime & 0xffff);
5523 smb_SetSMBParm(outp, 2, (searchTime >> 16) & 0xffff); /* atime */
5524 smb_SetSMBParm(outp, 3, searchTime & 0xffff);
5525 smb_SetSMBParm(outp, 4, (searchTime >> 16) & 0xffff); /* mtime */
5526 smb_SetSMBParm(outp, 5, searchTime & 0xffff);
5528 /* now handle file size and allocation size */
5529 smb_SetSMBParm(outp, 6, scp->length.LowPart & 0xffff); /* file size */
5530 smb_SetSMBParm(outp, 7, (scp->length.LowPart >> 16) & 0xffff);
5531 smb_SetSMBParm(outp, 8, scp->length.LowPart & 0xffff); /* alloc size */
5532 smb_SetSMBParm(outp, 9, (scp->length.LowPart >> 16) & 0xffff);
5534 /* file attribute */
5535 smb_SetSMBParm(outp, 10, smb_Attributes(scp));
5537 /* and finalize stuff */
5538 smb_SetSMBDataLength(outp, 0);
5542 lock_ReleaseMutex(&scp->mx);
5543 cm_ReleaseSCache(scp);
5544 cm_ReleaseUser(userp);
5545 smb_ReleaseFID(fidp);
5549 long smb_ReceiveV3SetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5555 afs_uint32 searchTime;
5563 fid = smb_GetSMBParm(inp, 0);
5564 fid = smb_ChainFID(fid, inp);
5566 fidp = smb_FindFID(vcp, fid, 0);
5568 return CM_ERROR_BADFD;
5570 lock_ObtainMutex(&fidp->mx);
5571 if (fidp->flags & SMB_FID_IOCTL) {
5572 lock_ReleaseMutex(&fidp->mx);
5573 smb_ReleaseFID(fidp);
5574 return CM_ERROR_BADFD;
5577 osi_Log2(afsd_logp,"smb_ReceiveV3SetAttributes fidp 0x%p scp 0x%p", fidp, scp);
5579 lock_ReleaseMutex(&fidp->mx);
5581 userp = smb_GetUserFromVCP(vcp, inp);
5584 /* now prepare to call cm_setattr. This message only sets various times,
5585 * and AFS only implements mtime, and we'll set the mtime if that's
5586 * requested. The others we'll ignore.
5588 searchTime = smb_GetSMBParm(inp, 5) | (smb_GetSMBParm(inp, 6) << 16);
5590 if (searchTime != 0) {
5591 smb_UnixTimeFromSearchTime(&unixTime, searchTime);
5593 if ( unixTime != -1 ) {
5594 attrs.mask = CM_ATTRMASK_CLIENTMODTIME;
5595 attrs.clientModTime = unixTime;
5596 code = cm_SetAttr(scp, &attrs, userp, &req);
5598 osi_Log1(smb_logp, "SMB receive V3SetAttributes [fid=%ld]", fid);
5600 osi_Log1(smb_logp, "**smb_UnixTimeFromSearchTime failed searchTime=%ld", searchTime);
5606 cm_ReleaseSCache(scp);
5607 cm_ReleaseUser(userp);
5608 smb_ReleaseFID(fidp);
5612 long smb_ReceiveV3WriteX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5615 long count, written = 0, total_written = 0;
5622 int inDataBlockCount;
5624 fd = smb_GetSMBParm(inp, 2);
5625 count = smb_GetSMBParm(inp, 10);
5627 offset.HighPart = 0;
5628 offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
5630 if (*inp->wctp == 14) {
5631 /* we have a request with 64-bit file offsets */
5632 #ifdef AFS_LARGEFILES
5633 offset.HighPart = smb_GetSMBParm(inp, 12) | (smb_GetSMBParm(inp, 13) << 16);
5635 if ((smb_GetSMBParm(inp, 12) | (smb_GetSMBParm(inp, 13) << 16)) != 0) {
5637 osi_Log0(smb_logp, "smb_ReceiveV3WriteX offset requires largefile support");
5638 /* we shouldn't have received this op if we didn't specify
5639 largefile support */
5640 return CM_ERROR_BADOP;
5645 op = inp->data + smb_GetSMBParm(inp, 11);
5646 inDataBlockCount = count;
5648 osi_Log4(smb_logp, "smb_ReceiveV3WriteX fid %d, off 0x%x:%08x, size 0x%x",
5649 fd, offset.HighPart, offset.LowPart, count);
5651 fd = smb_ChainFID(fd, inp);
5652 fidp = smb_FindFID(vcp, fd, 0);
5654 return CM_ERROR_BADFD;
5656 lock_ObtainMutex(&fidp->mx);
5657 if (fidp->flags & SMB_FID_IOCTL) {
5658 lock_ReleaseMutex(&fidp->mx);
5659 code = smb_IoctlV3Write(fidp, vcp, inp, outp);
5660 smb_ReleaseFID(fidp);
5663 lock_ReleaseMutex(&fidp->mx);
5664 userp = smb_GetUserFromVCP(vcp, inp);
5666 /* special case: 0 bytes transferred means there is no data
5667 transferred. A slight departure from SMB_COM_WRITE where this
5668 means that we are supposed to truncate the file at this
5673 LARGE_INTEGER LOffset;
5674 LARGE_INTEGER LLength;
5676 pid = ((smb_t *) inp)->pid;
5677 key = cm_GenerateKey(vcp->vcID, pid, fd);
5679 LOffset.HighPart = offset.HighPart;
5680 LOffset.LowPart = offset.LowPart;
5681 LLength.HighPart = 0;
5682 LLength.LowPart = count;
5684 lock_ObtainMutex(&fidp->scp->mx);
5685 code = cm_LockCheckWrite(fidp->scp, LOffset, LLength, key);
5686 lock_ReleaseMutex(&fidp->scp->mx);
5693 * Work around bug in NT client
5695 * When copying a file, the NT client should first copy the data,
5696 * then copy the last write time. But sometimes the NT client does
5697 * these in the wrong order, so the data copies would inadvertently
5698 * cause the last write time to be overwritten. We try to detect this,
5699 * and don't set client mod time if we think that would go against the
5702 lock_ObtainMutex(&fidp->mx);
5703 if ((fidp->flags & SMB_FID_MTIMESETDONE) != SMB_FID_MTIMESETDONE) {
5704 fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
5705 fidp->scp->clientModTime = time(NULL);
5707 lock_ReleaseMutex(&fidp->mx);
5710 while ( code == 0 && count > 0 ) {
5711 code = smb_WriteData(fidp, &offset, count, op, userp, &written);
5712 if (code == 0 && written == 0)
5713 code = CM_ERROR_PARTIALWRITE;
5715 offset = LargeIntegerAdd(offset,
5716 ConvertLongToLargeInteger(written));
5718 total_written += written;
5724 /* slots 0 and 1 are reserved for request chaining and will be
5725 filled in when we return. */
5726 smb_SetSMBParm(outp, 2, total_written);
5727 smb_SetSMBParm(outp, 3, 0); /* reserved */
5728 smb_SetSMBParm(outp, 4, 0); /* reserved */
5729 smb_SetSMBParm(outp, 5, 0); /* reserved */
5730 smb_SetSMBDataLength(outp, 0);
5733 cm_ReleaseUser(userp);
5734 smb_ReleaseFID(fidp);
5739 long smb_ReceiveV3ReadX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5743 long finalCount = 0;
5752 fd = smb_GetSMBParm(inp, 2);
5753 count = smb_GetSMBParm(inp, 5);
5754 offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
5756 if (*inp->wctp == 12) {
5757 /* a request with 64-bit offsets */
5758 #ifdef AFS_LARGEFILES
5759 offset.HighPart = smb_GetSMBParm(inp, 10) | (smb_GetSMBParm(inp, 11) << 16);
5761 if (LargeIntegerLessThanZero(offset)) {
5762 osi_Log2(smb_logp, "smb_ReceiveV3Read offset too large (0x%x:%08x)",
5763 offset.HighPart, offset.LowPart);
5764 return CM_ERROR_BADSMB;
5767 if ((smb_GetSMBParm(inp, 10) | (smb_GetSMBParm(inp, 11) << 16)) != 0) {
5768 osi_Log0(smb_logp, "smb_ReceiveV3Read offset is 64-bit. Dropping");
5769 return CM_ERROR_BADSMB;
5771 offset.HighPart = 0;
5775 offset.HighPart = 0;
5778 osi_Log4(smb_logp, "smb_ReceiveV3Read fd %d, off 0x%x:%08x, size 0x%x",
5779 fd, offset.HighPart, offset.LowPart, count);
5781 fd = smb_ChainFID(fd, inp);
5782 fidp = smb_FindFID(vcp, fd, 0);
5784 return CM_ERROR_BADFD;
5787 pid = ((smb_t *) inp)->pid;
5788 key = cm_GenerateKey(vcp->vcID, pid, fd);
5790 LARGE_INTEGER LOffset, LLength;
5792 LOffset.HighPart = offset.HighPart;
5793 LOffset.LowPart = offset.LowPart;
5794 LLength.HighPart = 0;
5795 LLength.LowPart = count;
5797 lock_ObtainMutex(&fidp->scp->mx);
5798 code = cm_LockCheckRead(fidp->scp, LOffset, LLength, key);
5799 lock_ReleaseMutex(&fidp->scp->mx);
5803 smb_ReleaseFID(fidp);
5807 /* set inp->fid so that later read calls in same msg can find fid */
5810 lock_ObtainMutex(&fidp->mx);
5811 if (fidp->flags & SMB_FID_IOCTL) {
5812 lock_ReleaseMutex(&fidp->mx);
5813 code = smb_IoctlV3Read(fidp, vcp, inp, outp);
5814 smb_ReleaseFID(fidp);
5817 lock_ReleaseMutex(&fidp->mx);
5819 userp = smb_GetUserFromVCP(vcp, inp);
5821 /* 0 and 1 are reserved for request chaining, were setup by our caller,
5822 * and will be further filled in after we return.
5824 smb_SetSMBParm(outp, 2, 0); /* remaining bytes, for pipes */
5825 smb_SetSMBParm(outp, 3, 0); /* resvd */
5826 smb_SetSMBParm(outp, 4, 0); /* resvd */
5827 smb_SetSMBParm(outp, 5, count); /* # of bytes we're going to read */
5828 /* fill in #6 when we have all the parameters' space reserved */
5829 smb_SetSMBParm(outp, 7, 0); /* resv'd */
5830 smb_SetSMBParm(outp, 8, 0); /* resv'd */
5831 smb_SetSMBParm(outp, 9, 0); /* resv'd */
5832 smb_SetSMBParm(outp, 10, 0); /* resv'd */
5833 smb_SetSMBParm(outp, 11, 0); /* reserved */
5835 /* get op ptr after putting in the parms, since otherwise we don't
5836 * know where the data really is.
5838 op = smb_GetSMBData(outp, NULL);
5840 /* now fill in offset from start of SMB header to first data byte (to op) */
5841 smb_SetSMBParm(outp, 6, ((int) (op - outp->data)));
5843 /* set the packet data length the count of the # of bytes */
5844 smb_SetSMBDataLength(outp, count);
5846 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount);
5848 /* fix some things up */
5849 smb_SetSMBParm(outp, 5, finalCount);
5850 smb_SetSMBDataLength(outp, finalCount);
5852 cm_ReleaseUser(userp);
5853 smb_ReleaseFID(fidp);
5858 * Values for createDisp, copied from NTDDK.H
5860 #define FILE_SUPERSEDE 0 // (???)
5861 #define FILE_OPEN 1 // (open)
5862 #define FILE_CREATE 2 // (exclusive)
5863 #define FILE_OPEN_IF 3 // (non-exclusive)
5864 #define FILE_OVERWRITE 4 // (open & truncate, but do not create)
5865 #define FILE_OVERWRITE_IF 5 // (open & truncate, or create)
5868 #define REQUEST_OPLOCK 2
5869 #define REQUEST_BATCH_OPLOCK 4
5870 #define OPEN_DIRECTORY 8
5871 #define EXTENDED_RESPONSE_REQUIRED 0x10
5873 /* CreateOptions field. */
5874 #define FILE_DIRECTORY_FILE 0x0001
5875 #define FILE_WRITE_THROUGH 0x0002
5876 #define FILE_SEQUENTIAL_ONLY 0x0004
5877 #define FILE_NON_DIRECTORY_FILE 0x0040
5878 #define FILE_NO_EA_KNOWLEDGE 0x0200
5879 #define FILE_EIGHT_DOT_THREE_ONLY 0x0400
5880 #define FILE_RANDOM_ACCESS 0x0800
5881 #define FILE_DELETE_ON_CLOSE 0x1000
5882 #define FILE_OPEN_BY_FILE_ID 0x2000
5884 long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5886 char *pathp, *realPathp;
5890 cm_scache_t *dscp; /* parent dir */
5891 cm_scache_t *scp; /* file to create or open */
5892 cm_scache_t *targetScp; /* if scp is a symlink */
5896 unsigned short nameLength;
5898 unsigned int requestOpLock;
5899 unsigned int requestBatchOpLock;
5900 unsigned int mustBeDir;
5901 unsigned int extendedRespRequired;
5902 unsigned int treeCreate;
5904 unsigned int desiredAccess;
5905 unsigned int extAttributes;
5906 unsigned int createDisp;
5907 unsigned int createOptions;
5908 unsigned int shareAccess;
5909 int initialModeBits;
5910 unsigned short baseFid;
5911 smb_fid_t *baseFidp;
5913 cm_scache_t *baseDirp;
5914 unsigned short openAction;
5926 /* This code is very long and has a lot of if-then-else clauses
5927 * scp and dscp get reused frequently and we need to ensure that
5928 * we don't lose a reference. Start by ensuring that they are NULL.
5935 nameLength = smb_GetSMBOffsetParm(inp, 2, 1);
5936 flags = smb_GetSMBOffsetParm(inp, 3, 1)
5937 | (smb_GetSMBOffsetParm(inp, 4, 1) << 16);
5938 requestOpLock = flags & REQUEST_OPLOCK;
5939 requestBatchOpLock = flags & REQUEST_BATCH_OPLOCK;
5940 mustBeDir = flags & OPEN_DIRECTORY;
5941 extendedRespRequired = flags & EXTENDED_RESPONSE_REQUIRED;
5944 * Why all of a sudden 32-bit FID?
5945 * We will reject all bits higher than 16.
5947 if (smb_GetSMBOffsetParm(inp, 6, 1) != 0)
5948 return CM_ERROR_INVAL;
5949 baseFid = smb_GetSMBOffsetParm(inp, 5, 1);
5950 desiredAccess = smb_GetSMBOffsetParm(inp, 7, 1)
5951 | (smb_GetSMBOffsetParm(inp, 8, 1) << 16);
5952 extAttributes = smb_GetSMBOffsetParm(inp, 13, 1)
5953 | (smb_GetSMBOffsetParm(inp, 14, 1) << 16);
5954 shareAccess = smb_GetSMBOffsetParm(inp, 15, 1)
5955 | (smb_GetSMBOffsetParm(inp, 16, 1) << 16);
5956 createDisp = smb_GetSMBOffsetParm(inp, 17, 1)
5957 | (smb_GetSMBOffsetParm(inp, 18, 1) << 16);
5958 createOptions = smb_GetSMBOffsetParm(inp, 19, 1)
5959 | (smb_GetSMBOffsetParm(inp, 20, 1) << 16);
5961 /* mustBeDir is never set; createOptions directory bit seems to be
5964 if (createOptions & FILE_DIRECTORY_FILE)
5966 else if (createOptions & FILE_NON_DIRECTORY_FILE)
5972 * compute initial mode bits based on read-only flag in
5973 * extended attributes
5975 initialModeBits = 0666;
5976 if (extAttributes & SMB_ATTR_READONLY)
5977 initialModeBits &= ~0222;
5979 pathp = smb_GetSMBData(inp, NULL);
5980 /* Sometimes path is not null-terminated, so we make a copy. */
5981 realPathp = malloc(nameLength+1);
5982 memcpy(realPathp, pathp, nameLength);
5983 realPathp[nameLength] = 0;
5984 if (smb_StoreAnsiFilenames)
5985 OemToChar(realPathp,realPathp);
5987 spacep = inp->spacep;
5988 smb_StripLastComponent(spacep->data, &lastNamep, realPathp);
5990 osi_Log1(smb_logp,"NTCreateX for [%s]",osi_LogSaveString(smb_logp,realPathp));
5991 osi_Log4(smb_logp,"... da=[%x] ea=[%x] cd=[%x] co=[%x]", desiredAccess, extAttributes, createDisp, createOptions);
5992 osi_Log3(smb_logp,"... share=[%x] flags=[%x] lastNamep=[%s]", shareAccess, flags, osi_LogSaveString(smb_logp,(lastNamep?lastNamep:"null")));
5994 if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
5995 /* special case magic file name for receiving IOCTL requests
5996 * (since IOCTL calls themselves aren't getting through).
5998 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
5999 smb_SetupIoctlFid(fidp, spacep);
6000 osi_Log1(smb_logp,"NTCreateX Setting up IOCTL on fid[%d]",fidp->fid);
6002 /* set inp->fid so that later read calls in same msg can find fid */
6003 inp->fid = fidp->fid;
6007 smb_SetSMBParmByte(outp, parmSlot, 0); /* oplock */
6008 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
6009 smb_SetSMBParmLong(outp, parmSlot, 1); parmSlot += 2; /* Action */
6011 memset(&ft, 0, sizeof(ft));
6012 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
6013 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
6014 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
6015 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
6016 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2; /* attr */
6017 sz.HighPart = 0x7fff; sz.LowPart = 0;
6018 smb_SetSMBParmDouble(outp, parmSlot, (char *)&sz); parmSlot += 4; /* alen */
6019 smb_SetSMBParmDouble(outp, parmSlot, (char *)&sz); parmSlot += 4; /* len */
6020 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* filetype */
6021 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* dev state */
6022 smb_SetSMBParmByte(outp, parmSlot, 0); /* is a dir? */
6023 smb_SetSMBDataLength(outp, 0);
6025 /* clean up fid reference */
6026 smb_ReleaseFID(fidp);
6031 #ifdef DEBUG_VERBOSE
6033 char *hexp, *asciip;
6034 asciip = (lastNamep? lastNamep : realPathp);
6035 hexp = osi_HexifyString( asciip );
6036 DEBUG_EVENT2("AFS", "NTCreateX H[%s] A[%s]", hexp, asciip);
6041 userp = smb_GetUserFromVCP(vcp, inp);
6043 osi_Log1(smb_logp, "NTCreateX Invalid user [%d]", ((smb_t *) inp)->uid);
6045 return CM_ERROR_INVAL;
6050 baseDirp = cm_data.rootSCachep;
6051 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
6052 if (code == CM_ERROR_TIDIPC) {
6053 /* Attempt to use a TID allocated for IPC. The client
6054 * is probably looking for DCE RPC end points which we
6055 * don't support OR it could be looking to make a DFS
6058 osi_Log0(smb_logp, "NTCreateX received IPC TID");
6061 cm_ReleaseUser(userp);
6062 return CM_ERROR_NOSUCHFILE;
6063 #endif /* DFS_SUPPORT */
6066 baseFidp = smb_FindFID(vcp, baseFid, 0);
6068 osi_Log1(smb_logp, "NTCreateX Invalid base fid [%d]", baseFid);
6070 cm_ReleaseUser(userp);
6071 return CM_ERROR_INVAL;
6073 baseDirp = baseFidp->scp;
6077 osi_Log1(smb_logp, "NTCreateX tidPathp=[%s]", (tidPathp==NULL)?"null": osi_LogSaveString(smb_logp,tidPathp));
6079 /* compute open mode */
6081 if (desiredAccess & DELETE)
6082 fidflags |= SMB_FID_OPENDELETE;
6083 if (desiredAccess & AFS_ACCESS_READ)
6084 fidflags |= SMB_FID_OPENREAD;
6085 if (desiredAccess & AFS_ACCESS_WRITE)
6086 fidflags |= SMB_FID_OPENWRITE;
6087 if (createOptions & FILE_DELETE_ON_CLOSE)
6088 fidflags |= SMB_FID_DELONCLOSE;
6089 if (createOptions & FILE_SEQUENTIAL_ONLY && !(createOptions & FILE_RANDOM_ACCESS))
6090 fidflags |= SMB_FID_SEQUENTIAL;
6091 if (createOptions & FILE_RANDOM_ACCESS && !(createOptions & FILE_SEQUENTIAL_ONLY))
6092 fidflags |= SMB_FID_RANDOM;
6094 /* and the share mode */
6095 if (shareAccess & FILE_SHARE_READ)
6096 fidflags |= SMB_FID_SHARE_READ;
6097 if (shareAccess & FILE_SHARE_WRITE)
6098 fidflags |= SMB_FID_SHARE_WRITE;
6100 osi_Log1(smb_logp, "NTCreateX fidflags 0x%x", fidflags);
6103 /* For an exclusive create, we want to do a case sensitive match for the last component. */
6104 if ( createDisp == FILE_CREATE ||
6105 createDisp == FILE_OVERWRITE ||
6106 createDisp == FILE_OVERWRITE_IF) {
6107 code = cm_NameI(baseDirp, spacep->data, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
6108 userp, tidPathp, &req, &dscp);
6111 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
6112 cm_ReleaseSCache(dscp);
6113 cm_ReleaseUser(userp);
6116 smb_ReleaseFID(baseFidp);
6117 if ( WANTS_DFS_PATHNAMES(inp) )
6118 return CM_ERROR_PATH_NOT_COVERED;
6120 return CM_ERROR_BADSHARENAME;
6122 #endif /* DFS_SUPPORT */
6123 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp, CM_FLAG_FOLLOW,
6125 if (code == CM_ERROR_NOSUCHFILE) {
6126 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp,
6127 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, &req, &scp);
6128 if (code == 0 && realDirFlag == 1) {
6129 cm_ReleaseSCache(scp);
6130 cm_ReleaseSCache(dscp);
6131 cm_ReleaseUser(userp);
6134 smb_ReleaseFID(baseFidp);
6135 return CM_ERROR_EXISTS;
6139 /* we have both scp and dscp */
6141 code = cm_NameI(baseDirp, realPathp, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
6142 userp, tidPathp, &req, &scp);
6144 if (code == 0 && scp->fileType == CM_SCACHETYPE_DFSLINK) {
6145 cm_ReleaseSCache(scp);
6146 cm_ReleaseUser(userp);
6149 smb_ReleaseFID(baseFidp);
6150 if ( WANTS_DFS_PATHNAMES(inp) )
6151 return CM_ERROR_PATH_NOT_COVERED;
6153 return CM_ERROR_BADSHARENAME;
6155 #endif /* DFS_SUPPORT */
6156 /* we might have scp but not dscp */
6162 if (!foundscp || (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE))) {
6163 /* look up parent directory */
6164 /* If we are trying to create a path (i.e. multiple nested directories), then we don't *need*
6165 * the immediate parent. We have to work our way up realPathp until we hit something that we
6169 /* we might or might not have scp */
6175 code = cm_NameI(baseDirp, spacep->data,
6176 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
6177 userp, tidPathp, &req, &dscp);
6180 if (code == 0 && dscp->fileType == CM_SCACHETYPE_DFSLINK) {
6182 cm_ReleaseSCache(scp);
6183 cm_ReleaseSCache(dscp);
6184 cm_ReleaseUser(userp);
6187 smb_ReleaseFID(baseFidp);
6188 if ( WANTS_DFS_PATHNAMES(inp) )
6189 return CM_ERROR_PATH_NOT_COVERED;
6191 return CM_ERROR_BADSHARENAME;
6193 #endif /* DFS_SUPPORT */
6196 (tp = strrchr(spacep->data,'\\')) &&
6197 (createDisp == FILE_CREATE) &&
6198 (realDirFlag == 1)) {
6201 treeStartp = realPathp + (tp - spacep->data);
6203 if (*tp && !smb_IsLegalFilename(tp)) {
6204 cm_ReleaseUser(userp);
6206 smb_ReleaseFID(baseFidp);
6209 cm_ReleaseSCache(scp);
6210 return CM_ERROR_BADNTFILENAME;
6214 } while (dscp == NULL && code == 0);
6218 /* we might have scp and we might have dscp */
6221 smb_ReleaseFID(baseFidp);
6224 osi_Log0(smb_logp,"NTCreateX parent not found");
6226 cm_ReleaseSCache(scp);
6228 cm_ReleaseSCache(dscp);
6229 cm_ReleaseUser(userp);
6234 if (treeCreate && dscp->fileType == CM_SCACHETYPE_FILE) {
6235 /* A file exists where we want a directory. */
6237 cm_ReleaseSCache(scp);
6238 cm_ReleaseSCache(dscp);
6239 cm_ReleaseUser(userp);
6241 return CM_ERROR_EXISTS;
6245 lastNamep = realPathp;
6249 if (!smb_IsLegalFilename(lastNamep)) {
6251 cm_ReleaseSCache(scp);
6253 cm_ReleaseSCache(dscp);
6254 cm_ReleaseUser(userp);
6256 return CM_ERROR_BADNTFILENAME;
6259 if (!foundscp && !treeCreate) {
6260 if ( createDisp == FILE_CREATE ||
6261 createDisp == FILE_OVERWRITE ||
6262 createDisp == FILE_OVERWRITE_IF)
6264 code = cm_Lookup(dscp, lastNamep,
6265 CM_FLAG_FOLLOW, userp, &req, &scp);
6267 code = cm_Lookup(dscp, lastNamep,
6268 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
6271 if (code && code != CM_ERROR_NOSUCHFILE) {
6273 cm_ReleaseSCache(dscp);
6274 cm_ReleaseUser(userp);
6279 /* we have scp and dscp */
6281 /* we have scp but not dscp */
6283 smb_ReleaseFID(baseFidp);
6286 /* if we get here, if code is 0, the file exists and is represented by
6287 * scp. Otherwise, we have to create it. The dir may be represented
6288 * by dscp, or we may have found the file directly. If code is non-zero,
6291 if (code == 0 && !treeCreate) {
6292 code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp, &req);
6295 cm_ReleaseSCache(dscp);
6297 cm_ReleaseSCache(scp);
6298 cm_ReleaseUser(userp);
6303 if (createDisp == FILE_CREATE) {
6304 /* oops, file shouldn't be there */
6306 cm_ReleaseSCache(dscp);
6308 cm_ReleaseSCache(scp);
6309 cm_ReleaseUser(userp);
6311 return CM_ERROR_EXISTS;
6314 if ( createDisp == FILE_OVERWRITE ||
6315 createDisp == FILE_OVERWRITE_IF) {
6317 setAttr.mask = CM_ATTRMASK_LENGTH;
6318 setAttr.length.LowPart = 0;
6319 setAttr.length.HighPart = 0;
6320 /* now watch for a symlink */
6322 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
6324 osi_assert(dscp != NULL);
6325 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
6327 /* we have a more accurate file to use (the
6328 * target of the symbolic link). Otherwise,
6329 * we'll just use the symlink anyway.
6331 osi_Log2(smb_logp, "symlink vp %x to vp %x",
6333 cm_ReleaseSCache(scp);
6337 code = cm_SetAttr(scp, &setAttr, userp, &req);
6338 openAction = 3; /* truncated existing file */
6341 openAction = 1; /* found existing file */
6343 } else if (createDisp == FILE_OPEN || createDisp == FILE_OVERWRITE) {
6344 /* don't create if not found */
6346 cm_ReleaseSCache(dscp);
6348 cm_ReleaseSCache(scp);
6349 cm_ReleaseUser(userp);
6351 return CM_ERROR_NOSUCHFILE;
6352 } else if (realDirFlag == 0 || realDirFlag == -1) {
6353 osi_assert(dscp != NULL);
6354 osi_Log1(smb_logp, "smb_ReceiveNTCreateX creating file %s",
6355 osi_LogSaveString(smb_logp, lastNamep));
6356 openAction = 2; /* created file */
6357 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
6358 setAttr.clientModTime = time(NULL);
6359 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp, &req);
6362 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
6363 smb_NotifyChange(FILE_ACTION_ADDED,
6364 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
6365 dscp, lastNamep, NULL, TRUE);
6366 } else if (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE) {
6367 /* Not an exclusive create, and someone else tried
6368 * creating it already, then we open it anyway. We
6369 * don't bother retrying after this, since if this next
6370 * fails, that means that the file was deleted after we
6371 * started this call.
6373 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
6376 if (createDisp == FILE_OVERWRITE_IF) {
6377 setAttr.mask = CM_ATTRMASK_LENGTH;
6378 setAttr.length.LowPart = 0;
6379 setAttr.length.HighPart = 0;
6381 /* now watch for a symlink */
6383 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
6385 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
6387 /* we have a more accurate file to use (the
6388 * target of the symbolic link). Otherwise,
6389 * we'll just use the symlink anyway.
6391 osi_Log2(smb_logp, "symlink vp %x to vp %x",
6393 cm_ReleaseSCache(scp);
6397 code = cm_SetAttr(scp, &setAttr, userp, &req);
6399 } /* lookup succeeded */
6403 char *cp; /* This component */
6404 int clen = 0; /* length of component */
6405 cm_scache_t *tscp1, *tscp2;
6408 /* create directory */
6410 treeStartp = lastNamep;
6411 osi_assert(dscp != NULL);
6412 osi_Log1(smb_logp, "smb_ReceiveNTCreateX creating directory [%s]",
6413 osi_LogSaveString(smb_logp, treeStartp));
6414 openAction = 2; /* created directory */
6416 /* if the request is to create the root directory
6417 * it will appear as a directory name of the nul-string
6418 * and a code of CM_ERROR_NOSUCHFILE
6420 if ( !*treeStartp && code == CM_ERROR_NOSUCHFILE)
6421 code = CM_ERROR_EXISTS;
6423 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
6424 setAttr.clientModTime = time(NULL);
6429 cm_HoldSCache(tscp1);
6433 tp = strchr(pp, '\\');
6436 clen = (int)strlen(cp);
6437 isLast = 1; /* indicate last component. the supplied path never ends in a slash */
6439 clen = (int)(tp - pp);
6440 strncpy(cp,pp,clen);
6447 continue; /* the supplied path can't have consecutive slashes either , but */
6449 /* cp is the next component to be created. */
6450 code = cm_MakeDir(tscp1, cp, 0, &setAttr, userp, &req);
6451 if (code == 0 && (tscp1->flags & CM_SCACHEFLAG_ANYWATCH))
6452 smb_NotifyChange(FILE_ACTION_ADDED,
6453 FILE_NOTIFY_CHANGE_DIR_NAME,
6454 tscp1, cp, NULL, TRUE);
6456 (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE)) {
6457 /* Not an exclusive create, and someone else tried
6458 * creating it already, then we open it anyway. We
6459 * don't bother retrying after this, since if this next
6460 * fails, that means that the file was deleted after we
6461 * started this call.
6463 code = cm_Lookup(tscp1, cp, CM_FLAG_CASEFOLD,
6464 userp, &req, &tscp2);
6469 if (!isLast) { /* for anything other than dscp, release it unless it's the last one */
6470 cm_ReleaseSCache(tscp1);
6471 tscp1 = tscp2; /* Newly created directory will be next parent */
6472 /* the hold is transfered to tscp1 from tscp2 */
6477 cm_ReleaseSCache(dscp);
6480 cm_ReleaseSCache(scp);
6483 * if we get here and code == 0, then scp is the last directory created, and dscp is the
6489 /* something went wrong creating or truncating the file */
6491 cm_ReleaseSCache(scp);
6493 cm_ReleaseSCache(dscp);
6494 cm_ReleaseUser(userp);
6499 /* make sure we have file vs. dir right (only applies for single component case) */
6500 if (realDirFlag == 0 && scp->fileType != CM_SCACHETYPE_FILE) {
6501 /* now watch for a symlink */
6503 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
6504 cm_scache_t * targetScp = 0;
6505 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
6507 /* we have a more accurate file to use (the
6508 * target of the symbolic link). Otherwise,
6509 * we'll just use the symlink anyway.
6511 osi_Log2(smb_logp, "symlink vp %x to vp %x", scp, targetScp);
6512 cm_ReleaseSCache(scp);
6517 if (scp->fileType != CM_SCACHETYPE_FILE) {
6519 cm_ReleaseSCache(dscp);
6520 cm_ReleaseSCache(scp);
6521 cm_ReleaseUser(userp);
6523 return CM_ERROR_ISDIR;
6527 /* (only applies to single component case) */
6528 if (realDirFlag == 1 && scp->fileType == CM_SCACHETYPE_FILE) {
6529 cm_ReleaseSCache(scp);
6531 cm_ReleaseSCache(dscp);
6532 cm_ReleaseUser(userp);
6534 return CM_ERROR_NOTDIR;
6537 /* open the file itself */
6538 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
6541 /* save a reference to the user */
6543 fidp->userp = userp;
6545 /* If we are restricting sharing, we should do so with a suitable
6547 if (scp->fileType == CM_SCACHETYPE_FILE &&
6548 !(fidflags & SMB_FID_SHARE_WRITE)) {
6550 LARGE_INTEGER LOffset, LLength;
6553 LOffset.HighPart = SMB_FID_QLOCK_HIGH;
6554 LOffset.LowPart = SMB_FID_QLOCK_LOW;
6555 LLength.HighPart = 0;
6556 LLength.LowPart = SMB_FID_QLOCK_LENGTH;
6558 if (fidflags & SMB_FID_SHARE_READ) {
6559 sLockType = LOCKING_ANDX_SHARED_LOCK;
6564 key = cm_GenerateKey(vcp->vcID, SMB_FID_QLOCK_PID, fidp->fid);
6566 lock_ObtainMutex(&scp->mx);
6567 code = cm_Lock(scp, sLockType, LOffset, LLength, key, 0, userp, &req, NULL);
6568 lock_ReleaseMutex(&scp->mx);
6571 cm_ReleaseSCache(scp);
6573 cm_ReleaseSCache(dscp);
6574 cm_ReleaseUser(userp);
6575 /* shouldn't this be smb_CloseFID() fidp->flags = SMB_FID_DELETE; */
6576 smb_CloseFID(vcp, fidp, NULL, 0);
6577 smb_ReleaseFID(fidp);
6583 lock_ObtainMutex(&fidp->mx);
6584 /* save a pointer to the vnode */
6585 fidp->scp = scp; /* Hold transfered to fidp->scp and no longer needed */
6586 lock_ObtainMutex(&scp->mx);
6587 scp->flags |= CM_SCACHEFLAG_SMB_FID;
6588 lock_ReleaseMutex(&scp->mx);
6589 osi_Log2(afsd_logp,"smb_ReceiveNTCreateX fidp 0x%p scp 0x%p", fidp, scp);
6591 fidp->flags = fidflags;
6593 /* remember if the file was newly created */
6595 fidp->flags |= SMB_FID_CREATED;
6597 /* save parent dir and pathname for delete or change notification */
6598 if (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE)) {
6599 osi_Log2(afsd_logp,"smb_ReceiveNTCreateX fidp 0x%p dscp 0x%p", fidp, dscp);
6600 fidp->flags |= SMB_FID_NTOPEN;
6601 fidp->NTopen_dscp = dscp;
6603 fidp->NTopen_pathp = strdup(lastNamep);
6605 fidp->NTopen_wholepathp = realPathp;
6606 lock_ReleaseMutex(&fidp->mx);
6608 /* we don't need this any longer */
6610 cm_ReleaseSCache(dscp);
6614 cm_Open(scp, 0, userp);
6616 /* set inp->fid so that later read calls in same msg can find fid */
6617 inp->fid = fidp->fid;
6621 lock_ObtainMutex(&scp->mx);
6622 smb_SetSMBParmByte(outp, parmSlot, 0); /* oplock */
6623 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
6624 smb_SetSMBParmLong(outp, parmSlot, openAction); parmSlot += 2;
6625 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
6626 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
6627 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
6628 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
6629 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
6630 smb_SetSMBParmLong(outp, parmSlot, smb_ExtAttributes(scp));
6632 smb_SetSMBParmDouble(outp, parmSlot, (char *)&scp->length); parmSlot += 4;
6633 smb_SetSMBParmDouble(outp, parmSlot, (char *)&scp->length); parmSlot += 4;
6634 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* filetype */
6635 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* dev state */
6636 smb_SetSMBParmByte(outp, parmSlot,
6637 (scp->fileType == CM_SCACHETYPE_DIRECTORY ||
6638 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
6639 scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0); /* is a dir? */
6640 lock_ReleaseMutex(&scp->mx);
6641 smb_SetSMBDataLength(outp, 0);
6643 osi_Log2(smb_logp, "SMB NT CreateX opening fid %d path %s", fidp->fid,
6644 osi_LogSaveString(smb_logp, realPathp));
6646 cm_ReleaseUser(userp);
6647 smb_ReleaseFID(fidp);
6649 /* Can't free realPathp if we get here since
6650 fidp->NTopen_wholepathp is pointing there */
6652 /* leave scp held since we put it in fidp->scp */
6657 * A lot of stuff copied verbatim from NT Create&X to NT Tran Create.
6658 * Instead, ultimately, would like to use a subroutine for common code.
6660 long smb_ReceiveNTTranCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6662 char *pathp, *realPathp;
6666 cm_scache_t *dscp; /* parent dir */
6667 cm_scache_t *scp; /* file to create or open */
6668 cm_scache_t *targetScp; /* if scp is a symlink */
6671 unsigned long nameLength;
6673 unsigned int requestOpLock;
6674 unsigned int requestBatchOpLock;
6675 unsigned int mustBeDir;
6676 unsigned int extendedRespRequired;
6678 unsigned int desiredAccess;
6679 #ifdef DEBUG_VERBOSE
6680 unsigned int allocSize;
6682 unsigned int shareAccess;
6683 unsigned int extAttributes;
6684 unsigned int createDisp;
6685 #ifdef DEBUG_VERBOSE
6688 unsigned int createOptions;
6689 int initialModeBits;
6690 unsigned short baseFid;
6691 smb_fid_t *baseFidp;
6693 cm_scache_t *baseDirp;
6694 unsigned short openAction;
6700 int parmOffset, dataOffset;
6712 parmOffset = smb_GetSMBOffsetParm(inp, 11, 1)
6713 | (smb_GetSMBOffsetParm(inp, 12, 1) << 16);
6714 parmp = inp->data + parmOffset;
6715 lparmp = (ULONG *) parmp;
6718 requestOpLock = flags & REQUEST_OPLOCK;
6719 requestBatchOpLock = flags & REQUEST_BATCH_OPLOCK;
6720 mustBeDir = flags & OPEN_DIRECTORY;
6721 extendedRespRequired = flags & EXTENDED_RESPONSE_REQUIRED;
6724 * Why all of a sudden 32-bit FID?
6725 * We will reject all bits higher than 16.
6727 if (lparmp[1] & 0xFFFF0000)
6728 return CM_ERROR_INVAL;
6729 baseFid = (unsigned short)lparmp[1];
6730 desiredAccess = lparmp[2];
6731 #ifdef DEBUG_VERBOSE
6732 allocSize = lparmp[3];
6733 #endif /* DEBUG_VERSOSE */
6734 extAttributes = lparmp[5];
6735 shareAccess = lparmp[6];
6736 createDisp = lparmp[7];
6737 createOptions = lparmp[8];
6738 #ifdef DEBUG_VERBOSE
6741 nameLength = lparmp[11];
6743 #ifdef DEBUG_VERBOSE
6744 osi_Log4(smb_logp,"NTTranCreate with da[%x],ea[%x],sa[%x],cd[%x]",desiredAccess,extAttributes,shareAccess,createDisp);
6745 osi_Log3(smb_logp,"... co[%x],sdl[%x],as[%x]",createOptions,sdLen,allocSize);
6746 osi_Log1(smb_logp,"... flags[%x]",flags);
6749 /* mustBeDir is never set; createOptions directory bit seems to be
6752 if (createOptions & FILE_DIRECTORY_FILE)
6754 else if (createOptions & FILE_NON_DIRECTORY_FILE)
6760 * compute initial mode bits based on read-only flag in
6761 * extended attributes
6763 initialModeBits = 0666;
6764 if (extAttributes & SMB_ATTR_READONLY)
6765 initialModeBits &= ~0222;
6767 pathp = parmp + (13 * sizeof(ULONG)) + sizeof(UCHAR);
6768 /* Sometimes path is not null-terminated, so we make a copy. */
6769 realPathp = malloc(nameLength+1);
6770 memcpy(realPathp, pathp, nameLength);
6771 realPathp[nameLength] = 0;
6772 if (smb_StoreAnsiFilenames)
6773 OemToChar(realPathp,realPathp);
6775 spacep = cm_GetSpace();
6776 smb_StripLastComponent(spacep->data, &lastNamep, realPathp);
6779 * Nothing here to handle SMB_IOCTL_FILENAME.
6780 * Will add it if necessary.
6783 #ifdef DEBUG_VERBOSE
6785 char *hexp, *asciip;
6786 asciip = (lastNamep? lastNamep : realPathp);
6787 hexp = osi_HexifyString( asciip );
6788 DEBUG_EVENT2("AFS", "NTTranCreate H[%s] A[%s]", hexp, asciip);
6793 userp = smb_GetUserFromVCP(vcp, inp);
6795 osi_Log1(smb_logp, "NTTranCreate invalid user [%d]", ((smb_t *) inp)->uid);
6797 return CM_ERROR_INVAL;
6802 baseDirp = cm_data.rootSCachep;
6803 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
6804 if (code == CM_ERROR_TIDIPC) {
6805 /* Attempt to use a TID allocated for IPC. The client
6806 * is probably looking for DCE RPC end points which we
6807 * don't support OR it could be looking to make a DFS
6810 osi_Log0(smb_logp, "NTTranCreate received IPC TID");
6813 cm_ReleaseUser(userp);
6814 return CM_ERROR_NOSUCHPATH;
6818 baseFidp = smb_FindFID(vcp, baseFid, 0);
6820 osi_Log1(smb_logp, "NTTranCreate Invalid fid [%d]", baseFid);
6822 cm_ReleaseUser(userp);
6823 return CM_ERROR_INVAL;
6825 baseDirp = baseFidp->scp;
6829 /* compute open mode */
6831 if (desiredAccess & DELETE)
6832 fidflags |= SMB_FID_OPENDELETE;
6833 if (desiredAccess & AFS_ACCESS_READ)
6834 fidflags |= SMB_FID_OPENREAD;
6835 if (desiredAccess & AFS_ACCESS_WRITE)
6836 fidflags |= SMB_FID_OPENWRITE;
6837 if (createOptions & FILE_DELETE_ON_CLOSE)
6838 fidflags |= SMB_FID_DELONCLOSE;
6839 if (createOptions & FILE_SEQUENTIAL_ONLY && !(createOptions & FILE_RANDOM_ACCESS))
6840 fidflags |= SMB_FID_SEQUENTIAL;
6841 if (createOptions & FILE_RANDOM_ACCESS && !(createOptions & FILE_SEQUENTIAL_ONLY))
6842 fidflags |= SMB_FID_RANDOM;
6844 /* And the share mode */
6845 if (shareAccess & FILE_SHARE_READ)
6846 fidflags |= SMB_FID_SHARE_READ;
6847 if (shareAccess & FILE_SHARE_WRITE)
6848 fidflags |= SMB_FID_SHARE_WRITE;
6852 if ( createDisp == FILE_OPEN ||
6853 createDisp == FILE_OVERWRITE ||
6854 createDisp == FILE_OVERWRITE_IF) {
6855 code = cm_NameI(baseDirp, spacep->data, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
6856 userp, tidPathp, &req, &dscp);
6859 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
6860 cm_ReleaseSCache(dscp);
6861 cm_ReleaseUser(userp);
6864 smb_ReleaseFID(baseFidp);
6865 if ( WANTS_DFS_PATHNAMES(inp) )
6866 return CM_ERROR_PATH_NOT_COVERED;
6868 return CM_ERROR_BADSHARENAME;
6870 #endif /* DFS_SUPPORT */
6871 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp, CM_FLAG_FOLLOW,
6873 if (code == CM_ERROR_NOSUCHFILE) {
6874 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp,
6875 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, &req, &scp);
6876 if (code == 0 && realDirFlag == 1) {
6877 cm_ReleaseSCache(scp);
6878 cm_ReleaseSCache(dscp);
6879 cm_ReleaseUser(userp);
6882 smb_ReleaseFID(baseFidp);
6883 return CM_ERROR_EXISTS;
6889 code = cm_NameI(baseDirp, realPathp, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
6890 userp, tidPathp, &req, &scp);
6892 if (code == 0 && scp->fileType == CM_SCACHETYPE_DFSLINK) {
6893 cm_ReleaseSCache(scp);
6894 cm_ReleaseUser(userp);
6897 smb_ReleaseFID(baseFidp);
6898 if ( WANTS_DFS_PATHNAMES(inp) )
6899 return CM_ERROR_PATH_NOT_COVERED;
6901 return CM_ERROR_BADSHARENAME;
6903 #endif /* DFS_SUPPORT */
6909 if (code != 0 || (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE))) {
6910 /* look up parent directory */
6912 code = cm_NameI(baseDirp, spacep->data,
6913 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
6914 userp, tidPathp, &req, &dscp);
6916 if (code == 0 && dscp->fileType == CM_SCACHETYPE_DFSLINK) {
6917 cm_ReleaseSCache(dscp);
6918 cm_ReleaseUser(userp);
6921 smb_ReleaseFID(baseFidp);
6922 if ( WANTS_DFS_PATHNAMES(inp) )
6923 return CM_ERROR_PATH_NOT_COVERED;
6925 return CM_ERROR_BADSHARENAME;
6927 #endif /* DFS_SUPPORT */
6931 cm_FreeSpace(spacep);
6934 smb_ReleaseFID(baseFidp);
6937 cm_ReleaseUser(userp);
6943 lastNamep = realPathp;
6947 if (!smb_IsLegalFilename(lastNamep))
6948 return CM_ERROR_BADNTFILENAME;
6951 if (createDisp == FILE_CREATE || createDisp == FILE_OVERWRITE_IF) {
6952 code = cm_Lookup(dscp, lastNamep,
6953 CM_FLAG_FOLLOW, userp, &req, &scp);
6955 code = cm_Lookup(dscp, lastNamep,
6956 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
6959 if (code && code != CM_ERROR_NOSUCHFILE) {
6960 cm_ReleaseSCache(dscp);
6961 cm_ReleaseUser(userp);
6968 smb_ReleaseFID(baseFidp);
6969 cm_FreeSpace(spacep);
6972 /* if we get here, if code is 0, the file exists and is represented by
6973 * scp. Otherwise, we have to create it. The dir may be represented
6974 * by dscp, or we may have found the file directly. If code is non-zero,
6978 code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp,
6982 cm_ReleaseSCache(dscp);
6983 cm_ReleaseSCache(scp);
6984 cm_ReleaseUser(userp);
6989 if (createDisp == FILE_CREATE) {
6990 /* oops, file shouldn't be there */
6992 cm_ReleaseSCache(dscp);
6993 cm_ReleaseSCache(scp);
6994 cm_ReleaseUser(userp);
6996 return CM_ERROR_EXISTS;
6999 if (createDisp == FILE_OVERWRITE ||
7000 createDisp == FILE_OVERWRITE_IF) {
7001 setAttr.mask = CM_ATTRMASK_LENGTH;
7002 setAttr.length.LowPart = 0;
7003 setAttr.length.HighPart = 0;
7005 /* now watch for a symlink */
7007 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
7009 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
7011 /* we have a more accurate file to use (the
7012 * target of the symbolic link). Otherwise,
7013 * we'll just use the symlink anyway.
7015 osi_Log2(smb_logp, "symlink vp %x to vp %x",
7017 cm_ReleaseSCache(scp);
7021 code = cm_SetAttr(scp, &setAttr, userp, &req);
7022 openAction = 3; /* truncated existing file */
7024 else openAction = 1; /* found existing file */
7026 else if (createDisp == FILE_OPEN || createDisp == FILE_OVERWRITE) {
7027 /* don't create if not found */
7029 cm_ReleaseSCache(dscp);
7030 cm_ReleaseUser(userp);
7032 return CM_ERROR_NOSUCHFILE;
7034 else if (realDirFlag == 0 || realDirFlag == -1) {
7035 osi_assert(dscp != NULL);
7036 osi_Log1(smb_logp, "smb_ReceiveNTTranCreate creating file %s",
7037 osi_LogSaveString(smb_logp, lastNamep));
7038 openAction = 2; /* created file */
7039 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
7040 setAttr.clientModTime = time(NULL);
7041 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
7045 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
7046 smb_NotifyChange(FILE_ACTION_ADDED,
7047 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
7048 dscp, lastNamep, NULL, TRUE);
7049 } else if (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE) {
7050 /* Not an exclusive create, and someone else tried
7051 * creating it already, then we open it anyway. We
7052 * don't bother retrying after this, since if this next
7053 * fails, that means that the file was deleted after we
7054 * started this call.
7056 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
7059 if (createDisp == FILE_OVERWRITE_IF) {
7060 setAttr.mask = CM_ATTRMASK_LENGTH;
7061 setAttr.length.LowPart = 0;
7062 setAttr.length.HighPart = 0;
7064 /* now watch for a symlink */
7066 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
7068 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
7070 /* we have a more accurate file to use (the
7071 * target of the symbolic link). Otherwise,
7072 * we'll just use the symlink anyway.
7074 osi_Log2(smb_logp, "symlink vp %x to vp %x",
7076 cm_ReleaseSCache(scp);
7080 code = cm_SetAttr(scp, &setAttr, userp, &req);
7082 } /* lookup succeeded */
7085 /* create directory */
7086 osi_assert(dscp != NULL);
7088 "smb_ReceiveNTTranCreate creating directory %s",
7089 osi_LogSaveString(smb_logp, lastNamep));
7090 openAction = 2; /* created directory */
7091 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
7092 setAttr.clientModTime = time(NULL);
7093 code = cm_MakeDir(dscp, lastNamep, 0, &setAttr, userp, &req);
7094 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
7095 smb_NotifyChange(FILE_ACTION_ADDED,
7096 FILE_NOTIFY_CHANGE_DIR_NAME,
7097 dscp, lastNamep, NULL, TRUE);
7099 (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE)) {
7100 /* Not an exclusive create, and someone else tried
7101 * creating it already, then we open it anyway. We
7102 * don't bother retrying after this, since if this next
7103 * fails, that means that the file was deleted after we
7104 * started this call.
7106 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
7112 /* something went wrong creating or truncating the file */
7114 cm_ReleaseSCache(scp);
7115 cm_ReleaseUser(userp);
7120 /* make sure we have file vs. dir right */
7121 if (realDirFlag == 0 && scp->fileType != CM_SCACHETYPE_FILE) {
7122 /* now watch for a symlink */
7124 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
7126 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
7128 /* we have a more accurate file to use (the
7129 * target of the symbolic link). Otherwise,
7130 * we'll just use the symlink anyway.
7132 osi_Log2(smb_logp, "symlink vp %x to vp %x",
7134 cm_ReleaseSCache(scp);
7139 if (scp->fileType != CM_SCACHETYPE_FILE) {
7140 cm_ReleaseSCache(scp);
7141 cm_ReleaseUser(userp);
7143 return CM_ERROR_ISDIR;
7147 if (realDirFlag == 1 && scp->fileType == CM_SCACHETYPE_FILE) {
7148 cm_ReleaseSCache(scp);
7149 cm_ReleaseUser(userp);
7151 return CM_ERROR_NOTDIR;
7154 /* open the file itself */
7155 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
7158 /* save a reference to the user */
7160 fidp->userp = userp;
7162 /* If we are restricting sharing, we should do so with a suitable
7164 if (scp->fileType == CM_SCACHETYPE_FILE &&
7165 !(fidflags & SMB_FID_SHARE_WRITE)) {
7167 LARGE_INTEGER LOffset, LLength;
7170 LOffset.HighPart = SMB_FID_QLOCK_HIGH;
7171 LOffset.LowPart = SMB_FID_QLOCK_LOW;
7172 LLength.HighPart = 0;
7173 LLength.LowPart = SMB_FID_QLOCK_LENGTH;
7175 if (fidflags & SMB_FID_SHARE_READ) {
7176 sLockType = LOCKING_ANDX_SHARED_LOCK;
7181 key = cm_GenerateKey(vcp->vcID, SMB_FID_QLOCK_PID, fidp->fid);
7183 lock_ObtainMutex(&scp->mx);
7184 code = cm_Lock(scp, sLockType, LOffset, LLength, key, 0, userp, &req, NULL);
7185 lock_ReleaseMutex(&scp->mx);
7188 cm_ReleaseSCache(scp);
7189 cm_ReleaseUser(userp);
7190 /* Shouldn't this be smb_CloseFID()? fidp->flags = SMB_FID_DELETE; */
7191 smb_CloseFID(vcp, fidp, NULL, 0);
7192 smb_ReleaseFID(fidp);
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 cm_ReleaseUser(userp);
7341 smb_ReleaseFID(fidp);
7343 /* free(realPathp); Can't free realPathp here because fidp->NTopen_wholepathp points there */
7344 /* leave scp held since we put it in fidp->scp */
7348 long smb_ReceiveNTTranNotifyChange(smb_vc_t *vcp, smb_packet_t *inp,
7351 smb_packet_t *savedPacketp;
7352 ULONG filter; USHORT fid, watchtree;
7356 filter = smb_GetSMBParm(inp, 19) |
7357 (smb_GetSMBParm(inp, 20) << 16);
7358 fid = smb_GetSMBParm(inp, 21);
7359 watchtree = smb_GetSMBParm(inp, 22) && 0xffff; /* TODO: should this be 0xff ? */
7361 fidp = smb_FindFID(vcp, fid, 0);
7363 osi_Log1(smb_logp, "ERROR: NotifyChange given invalid fid [%d]", fid);
7364 return CM_ERROR_BADFD;
7367 savedPacketp = smb_CopyPacket(inp);
7369 if (savedPacketp->vcp)
7370 smb_ReleaseVC(savedPacketp->vcp);
7371 savedPacketp->vcp = vcp;
7372 lock_ObtainMutex(&smb_Dir_Watch_Lock);
7373 savedPacketp->nextp = smb_Directory_Watches;
7374 smb_Directory_Watches = savedPacketp;
7375 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
7377 osi_Log4(smb_logp, "Request for NotifyChange filter 0x%x fid %d wtree %d file %s",
7378 filter, fid, watchtree, osi_LogSaveString(smb_logp, fidp->NTopen_wholepathp));
7381 osi_Log2(afsd_logp,"smb_ReceiveNTTranNotifyChange fidp 0x%p scp 0x%p", fidp, scp);
7382 lock_ObtainMutex(&scp->mx);
7384 scp->flags |= CM_SCACHEFLAG_WATCHEDSUBTREE;
7386 scp->flags |= CM_SCACHEFLAG_WATCHED;
7387 lock_ReleaseMutex(&scp->mx);
7388 smb_ReleaseFID(fidp);
7390 outp->flags |= SMB_PACKETFLAG_NOSEND;
7394 unsigned char nullSecurityDesc[36] = {
7395 0x01, /* security descriptor revision */
7396 0x00, /* reserved, should be zero */
7397 0x00, 0x80, /* security descriptor control;
7398 * 0x8000 : self-relative format */
7399 0x14, 0x00, 0x00, 0x00, /* offset of owner SID */
7400 0x1c, 0x00, 0x00, 0x00, /* offset of group SID */
7401 0x00, 0x00, 0x00, 0x00, /* offset of DACL would go here */
7402 0x00, 0x00, 0x00, 0x00, /* offset of SACL would go here */
7403 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
7404 /* "null SID" owner SID */
7405 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
7406 /* "null SID" group SID */
7409 long smb_ReceiveNTTranQuerySecurityDesc(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7411 int parmOffset, parmCount, dataOffset, dataCount;
7419 ULONG securityInformation;
7421 parmOffset = smb_GetSMBOffsetParm(inp, 11, 1)
7422 | (smb_GetSMBOffsetParm(inp, 12, 1) << 16);
7423 parmp = inp->data + parmOffset;
7424 sparmp = (USHORT *) parmp;
7425 lparmp = (ULONG *) parmp;
7428 securityInformation = lparmp[1];
7430 maxData = smb_GetSMBOffsetParm(inp, 7, 1)
7431 | (smb_GetSMBOffsetParm(inp, 8, 1) << 16);
7439 parmOffset = 8*4 + 39;
7440 parmOffset += 1; /* pad to 4 */
7442 dataOffset = parmOffset + parmCount;
7446 /* Total Parameter Count */
7447 smb_SetSMBParmLong(outp, parmSlot, parmCount); parmSlot += 2;
7448 /* Total Data Count */
7449 smb_SetSMBParmLong(outp, parmSlot, dataCount); parmSlot += 2;
7450 /* Parameter Count */
7451 smb_SetSMBParmLong(outp, parmSlot, parmCount); parmSlot += 2;
7452 /* Parameter Offset */
7453 smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
7454 /* Parameter Displacement */
7455 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
7457 smb_SetSMBParmLong(outp, parmSlot, dataCount); parmSlot += 2;
7459 smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
7460 /* Data Displacement */
7461 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
7462 smb_SetSMBParmByte(outp, parmSlot, 0); /* Setup Count */
7463 smb_SetSMBDataLength(outp, 1 + parmCount + dataCount);
7465 outData = smb_GetSMBData(outp, NULL);
7466 outData++; /* round to get to parmOffset */
7467 *((ULONG *)outData) = 36; outData += 4; /* length */
7469 if (maxData >= 36) {
7470 memcpy(outData, nullSecurityDesc, 36);
7474 return CM_ERROR_BUFFERTOOSMALL;
7477 long smb_ReceiveNTTransact(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7479 unsigned short function;
7481 function = smb_GetSMBParm(inp, 18);
7483 osi_Log1(smb_logp, "SMB NT Transact function %d", function);
7485 /* We can handle long names */
7486 if (vcp->flags & SMB_VCFLAG_USENT)
7487 ((smb_t *)outp)->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
7491 return smb_ReceiveNTTranCreate(vcp, inp, outp);
7493 osi_Log0(smb_logp, "SMB NT Transact Ioctl - not implemented");
7496 osi_Log0(smb_logp, "SMB NT Transact SetSecurityDesc - not implemented");
7499 return smb_ReceiveNTTranNotifyChange(vcp, inp, outp);
7501 osi_Log0(smb_logp, "SMB NT Transact Rename - not implemented");
7504 return smb_ReceiveNTTranQuerySecurityDesc(vcp, inp, outp);
7506 return CM_ERROR_INVAL;
7510 * smb_NotifyChange -- find relevant change notification messages and
7513 * If we don't know the file name (i.e. a callback break), filename is
7514 * NULL, and we return a zero-length list.
7516 void smb_NotifyChange(DWORD action, DWORD notifyFilter,
7517 cm_scache_t *dscp, char *filename, char *otherFilename,
7518 BOOL isDirectParent)
7520 smb_packet_t *watch, *lastWatch, *nextWatch;
7521 ULONG parmSlot, parmCount, parmOffset, dataOffset, nameLen;
7522 char *outData, *oldOutData;
7526 BOOL twoEntries = FALSE;
7527 ULONG otherNameLen, oldParmCount = 0;
7531 /* Get ready for rename within directory */
7532 if (action == FILE_ACTION_RENAMED_OLD_NAME && otherFilename != NULL) {
7534 otherAction = FILE_ACTION_RENAMED_NEW_NAME;
7537 osi_Log2(smb_logp,"in smb_NotifyChange for file [%s] dscp [%x]",
7538 osi_LogSaveString(smb_logp,filename),dscp);
7540 lock_ObtainMutex(&smb_Dir_Watch_Lock);
7541 watch = smb_Directory_Watches;
7543 filter = smb_GetSMBParm(watch, 19)
7544 | (smb_GetSMBParm(watch, 20) << 16);
7545 fid = smb_GetSMBParm(watch, 21);
7546 wtree = smb_GetSMBParm(watch, 22) & 0xffff; /* TODO: should this be 0xff ? */
7547 maxLen = smb_GetSMBOffsetParm(watch, 5, 1)
7548 | (smb_GetSMBOffsetParm(watch, 6, 1) << 16);
7551 * Strange hack - bug in NT Client and NT Server that we
7554 if (filter == 3 && wtree)
7557 fidp = smb_FindFID(watch->vcp, fid, 0);
7559 osi_Log1(smb_logp," no fidp for fid[%d]",fid);
7561 watch = watch->nextp;
7564 if (fidp->scp != dscp
7565 || (filter & notifyFilter) == 0
7566 || (!isDirectParent && !wtree)) {
7567 osi_Log1(smb_logp," passing fidp->scp[%x]", fidp->scp);
7568 smb_ReleaseFID(fidp);
7570 watch = watch->nextp;
7573 smb_ReleaseFID(fidp);
7576 "Sending Change Notification for fid %d filter 0x%x wtree %d file %s",
7577 fid, filter, wtree, osi_LogSaveString(smb_logp, filename));
7579 nextWatch = watch->nextp;
7580 if (watch == smb_Directory_Watches)
7581 smb_Directory_Watches = nextWatch;
7583 lastWatch->nextp = nextWatch;
7585 /* Turn off WATCHED flag in dscp */
7586 lock_ObtainMutex(&dscp->mx);
7588 dscp->flags &= ~CM_SCACHEFLAG_WATCHEDSUBTREE;
7590 dscp->flags &= ~CM_SCACHEFLAG_WATCHED;
7591 lock_ReleaseMutex(&dscp->mx);
7593 /* Convert to response packet */
7594 ((smb_t *) watch)->reb = SMB_FLAGS_SERVER_TO_CLIENT | SMB_FLAGS_CANONICAL_PATHNAMES;
7595 ((smb_t *) watch)->wct = 0;
7598 if (filename == NULL)
7601 nameLen = (ULONG)strlen(filename);
7602 parmCount = 3*4 + nameLen*2;
7603 parmCount = (parmCount + 3) & ~3; /* pad to 4 */
7605 otherNameLen = (ULONG)strlen(otherFilename);
7606 oldParmCount = parmCount;
7607 parmCount += 3*4 + otherNameLen*2;
7608 parmCount = (parmCount + 3) & ~3; /* pad to 4 */
7610 if (maxLen < parmCount)
7611 parmCount = 0; /* not enough room */
7613 parmOffset = 8*4 + 39;
7614 parmOffset += 1; /* pad to 4 */
7615 dataOffset = parmOffset + parmCount;
7619 /* Total Parameter Count */
7620 smb_SetSMBParmLong(watch, parmSlot, parmCount); parmSlot += 2;
7621 /* Total Data Count */
7622 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
7623 /* Parameter Count */
7624 smb_SetSMBParmLong(watch, parmSlot, parmCount); parmSlot += 2;
7625 /* Parameter Offset */
7626 smb_SetSMBParmLong(watch, parmSlot, parmOffset); parmSlot += 2;
7627 /* Parameter Displacement */
7628 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
7630 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
7632 smb_SetSMBParmLong(watch, parmSlot, dataOffset); parmSlot += 2;
7633 /* Data Displacement */
7634 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
7635 smb_SetSMBParmByte(watch, parmSlot, 0); /* Setup Count */
7636 smb_SetSMBDataLength(watch, parmCount + 1);
7638 if (parmCount != 0) {
7640 outData = smb_GetSMBData(watch, NULL);
7641 outData++; /* round to get to parmOffset */
7642 oldOutData = outData;
7643 *((DWORD *)outData) = oldParmCount; outData += 4;
7644 /* Next Entry Offset */
7645 *((DWORD *)outData) = action; outData += 4;
7647 *((DWORD *)outData) = nameLen*2; outData += 4;
7648 /* File Name Length */
7649 p = strdup(filename);
7650 if (smb_StoreAnsiFilenames)
7652 mbstowcs((WCHAR *)outData, p, nameLen);
7656 outData = oldOutData + oldParmCount;
7657 *((DWORD *)outData) = 0; outData += 4;
7658 /* Next Entry Offset */
7659 *((DWORD *)outData) = otherAction; outData += 4;
7661 *((DWORD *)outData) = otherNameLen*2;
7662 outData += 4; /* File Name Length */
7663 p = strdup(otherFilename);
7664 if (smb_StoreAnsiFilenames)
7666 mbstowcs((WCHAR *)outData, p, otherNameLen); /* File Name */
7672 * If filename is null, we don't know the cause of the
7673 * change notification. We return zero data (see above),
7674 * and set error code to NT_STATUS_NOTIFY_ENUM_DIR
7675 * (= 0x010C). We set the error code here by hand, without
7676 * modifying wct and bcc.
7678 if (filename == NULL) {
7679 ((smb_t *) watch)->rcls = 0x0C;
7680 ((smb_t *) watch)->reh = 0x01;
7681 ((smb_t *) watch)->errLow = 0;
7682 ((smb_t *) watch)->errHigh = 0;
7683 /* Set NT Status codes flag */
7684 ((smb_t *) watch)->flg2 |= SMB_FLAGS2_32BIT_STATUS;
7687 smb_SendPacket(watch->vcp, watch);
7688 smb_FreePacket(watch);
7691 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
7694 long smb_ReceiveNTCancel(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7696 unsigned char *replyWctp;
7697 smb_packet_t *watch, *lastWatch;
7698 USHORT fid, watchtree;
7702 osi_Log0(smb_logp, "SMB3 receive NT cancel");
7704 lock_ObtainMutex(&smb_Dir_Watch_Lock);
7705 watch = smb_Directory_Watches;
7707 if (((smb_t *)watch)->uid == ((smb_t *)inp)->uid
7708 && ((smb_t *)watch)->pid == ((smb_t *)inp)->pid
7709 && ((smb_t *)watch)->mid == ((smb_t *)inp)->mid
7710 && ((smb_t *)watch)->tid == ((smb_t *)inp)->tid) {
7711 if (watch == smb_Directory_Watches)
7712 smb_Directory_Watches = watch->nextp;
7714 lastWatch->nextp = watch->nextp;
7715 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
7717 /* Turn off WATCHED flag in scp */
7718 fid = smb_GetSMBParm(watch, 21);
7719 watchtree = smb_GetSMBParm(watch, 22) & 0xffff;
7721 if (vcp != watch->vcp)
7722 osi_Log2(smb_logp, "smb_ReceiveNTCancel: vcp %x not equal to watch vcp %x",
7725 fidp = smb_FindFID(vcp, fid, 0);
7727 osi_Log3(smb_logp, "Cancelling change notification for fid %d wtree %d file %s",
7729 osi_LogSaveString(smb_logp, (fidp)?fidp->NTopen_wholepathp:""));
7732 osi_Log2(afsd_logp,"smb_ReceiveNTCancel fidp 0x%p scp 0x%p", fidp, scp);
7733 lock_ObtainMutex(&scp->mx);
7735 scp->flags &= ~CM_SCACHEFLAG_WATCHEDSUBTREE;
7737 scp->flags &= ~CM_SCACHEFLAG_WATCHED;
7738 lock_ReleaseMutex(&scp->mx);
7739 smb_ReleaseFID(fidp);
7741 osi_Log2(smb_logp,"NTCancel unable to resolve fid [%d] in vcp[%x]", fid,vcp);
7744 /* assume STATUS32; return 0xC0000120 (CANCELED) */
7745 replyWctp = watch->wctp;
7749 ((smb_t *)watch)->rcls = 0x20;
7750 ((smb_t *)watch)->reh = 0x1;
7751 ((smb_t *)watch)->errLow = 0;
7752 ((smb_t *)watch)->errHigh = 0xC0;
7753 ((smb_t *)watch)->flg2 |= SMB_FLAGS2_32BIT_STATUS;
7754 smb_SendPacket(vcp, watch);
7755 smb_FreePacket(watch);
7759 watch = watch->nextp;
7761 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
7767 * NT rename also does hard links.
7770 #define RENAME_FLAG_MOVE_CLUSTER_INFORMATION 0x102
7771 #define RENAME_FLAG_HARD_LINK 0x103
7772 #define RENAME_FLAG_RENAME 0x104
7773 #define RENAME_FLAG_COPY 0x105
7775 long smb_ReceiveNTRename(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7777 char *oldPathp, *newPathp;
7783 attrs = smb_GetSMBParm(inp, 0);
7784 rename_type = smb_GetSMBParm(inp, 1);
7786 if (rename_type != RENAME_FLAG_RENAME && rename_type != RENAME_FLAG_HARD_LINK) {
7787 osi_Log1(smb_logp, "NTRename invalid infolevel [%x]", rename_type);
7788 return CM_ERROR_NOACCESS;
7791 tp = smb_GetSMBData(inp, NULL);
7792 oldPathp = smb_ParseASCIIBlock(tp, &tp);
7793 if (smb_StoreAnsiFilenames)
7794 OemToChar(oldPathp,oldPathp);
7795 newPathp = smb_ParseASCIIBlock(tp, &tp);
7796 if (smb_StoreAnsiFilenames)
7797 OemToChar(newPathp,newPathp);
7799 osi_Log3(smb_logp, "NTRename for [%s]->[%s] type [%s]",
7800 osi_LogSaveString(smb_logp, oldPathp),
7801 osi_LogSaveString(smb_logp, newPathp),
7802 ((rename_type==RENAME_FLAG_RENAME)?"rename":"hardlink"));
7804 if (rename_type == RENAME_FLAG_RENAME) {
7805 code = smb_Rename(vcp,inp,oldPathp,newPathp,attrs);
7806 } else { /* RENAME_FLAG_HARD_LINK */
7807 code = smb_Link(vcp,inp,oldPathp,newPathp);
7814 lock_InitializeMutex(&smb_Dir_Watch_Lock, "Directory Watch List Lock");
7817 cm_user_t *smb_FindCMUserByName(char *usern, char *machine, afs_uint32 flags)
7819 smb_username_t *unp;
7822 unp = smb_FindUserByName(usern, machine, flags);
7824 lock_ObtainMutex(&unp->mx);
7825 unp->userp = cm_NewUser();
7826 lock_ReleaseMutex(&unp->mx);
7827 osi_Log2(smb_logp,"smb_FindCMUserByName New user name[%s] machine[%s]",osi_LogSaveString(smb_logp,usern),osi_LogSaveString(smb_logp,machine));
7829 osi_Log2(smb_logp,"smb_FindCMUserByName Not found name[%s] machine[%s]",osi_LogSaveString(smb_logp,usern),osi_LogSaveString(smb_logp,machine));
7833 smb_ReleaseUsername(unp);