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 */
2362 fidp->userp = userp;
2364 /* compute open mode */
2366 fidp->flags |= SMB_FID_OPENREAD;
2367 if (openMode == 1 || openMode == 2)
2368 fidp->flags |= SMB_FID_OPENWRITE;
2370 /* remember that the file was newly created */
2372 fidp->flags |= SMB_FID_CREATED;
2374 lock_ReleaseMutex(&fidp->mx);
2376 smb_ReleaseFID(fidp);
2378 cm_Open(scp, 0, userp);
2380 /* copy out remainder of the parms */
2382 outp->parmsp[parmSlot++] = fidp->fid;
2383 lock_ObtainMutex(&scp->mx);
2385 outp->parmsp[parmSlot++] = smb_Attributes(scp);
2386 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
2387 outp->parmsp[parmSlot++] = (unsigned short)(dosTime & 0xffff);
2388 outp->parmsp[parmSlot++] = (unsigned short)((dosTime>>16) & 0xffff);
2389 outp->parmsp[parmSlot++] = (unsigned short) (scp->length.LowPart & 0xffff);
2390 outp->parmsp[parmSlot++] = (unsigned short) ((scp->length.LowPart >> 16) & 0xffff);
2391 outp->parmsp[parmSlot++] = openMode;
2392 outp->parmsp[parmSlot++] = 0; /* file type 0 ==> normal file or dir */
2393 outp->parmsp[parmSlot++] = 0; /* IPC junk */
2395 /* and the final "always present" stuff */
2396 outp->parmsp[parmSlot++] = openAction;
2397 /* next write out the "unique" ID */
2398 outp->parmsp[parmSlot++] = (unsigned short) (scp->fid.vnode & 0xffff);
2399 outp->parmsp[parmSlot++] = (unsigned short) (scp->fid.volume & 0xffff);
2400 outp->parmsp[parmSlot++] = 0;
2401 if (returnEALength) {
2402 outp->parmsp[parmSlot++] = 0;
2403 outp->parmsp[parmSlot++] = 0;
2405 lock_ReleaseMutex(&scp->mx);
2406 outp->totalData = 0; /* total # of data bytes */
2407 outp->totalParms = parmSlot * 2; /* shorts are two bytes */
2409 smb_SendTran2Packet(vcp, outp, op);
2411 smb_FreeTran2Packet(outp);
2413 cm_ReleaseUser(userp);
2414 /* leave scp held since we put it in fidp->scp */
2418 long smb_ReceiveTran2FindFirst(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
2420 osi_Log0(smb_logp,"ReceiveTran2FindFirst - NOT_SUPPORTED");
2421 return CM_ERROR_BADOP;
2424 long smb_ReceiveTran2FindNext(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
2426 osi_Log0(smb_logp,"ReceiveTran2FindNext - NOT_SUPPORTED");
2427 return CM_ERROR_BADOP;
2430 long smb_ReceiveTran2QFSInfoFid(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
2433 unsigned short infolevel;
2435 infolevel = p->parmsp[0];
2437 osi_Log2(smb_logp, "T2 QFSInfoFid InfoLevel 0x%x fid 0x%x - NOT_SUPPORTED", infolevel, fid);
2439 return CM_ERROR_BADOP;
2442 long smb_ReceiveTran2QFSInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
2444 smb_tran2Packet_t *outp;
2445 smb_tran2QFSInfo_t qi;
2447 static char FSname[8] = {'A', 0, 'F', 0, 'S', 0, 0, 0};
2449 osi_Log1(smb_logp, "T2 QFSInfo type 0x%x", p->parmsp[0]);
2451 switch (p->parmsp[0]) {
2452 case SMB_INFO_ALLOCATION:
2453 responseSize = sizeof(qi.u.allocInfo);
2455 case SMB_INFO_VOLUME:
2456 responseSize = sizeof(qi.u.volumeInfo);
2458 case SMB_QUERY_FS_VOLUME_INFO:
2459 responseSize = sizeof(qi.u.FSvolumeInfo);
2461 case SMB_QUERY_FS_SIZE_INFO:
2462 responseSize = sizeof(qi.u.FSsizeInfo);
2464 case SMB_QUERY_FS_DEVICE_INFO:
2465 responseSize = sizeof(qi.u.FSdeviceInfo);
2467 case SMB_QUERY_FS_ATTRIBUTE_INFO:
2468 responseSize = sizeof(qi.u.FSattributeInfo);
2470 case SMB_INFO_UNIX: /* CIFS Unix Info */
2471 case SMB_INFO_MACOS: /* Mac FS Info */
2473 return CM_ERROR_BADOP;
2476 outp = smb_GetTran2ResponsePacket(vcp, p, op, 0, responseSize);
2477 switch (p->parmsp[0]) {
2478 case SMB_INFO_ALLOCATION:
2480 qi.u.allocInfo.FSID = 0;
2481 qi.u.allocInfo.sectorsPerAllocUnit = 1;
2482 qi.u.allocInfo.totalAllocUnits = 0x7fffffff;
2483 qi.u.allocInfo.availAllocUnits = 0x3fffffff;
2484 qi.u.allocInfo.bytesPerSector = 1024;
2487 case SMB_INFO_VOLUME:
2489 qi.u.volumeInfo.vsn = 1234;
2490 qi.u.volumeInfo.vnCount = 4;
2491 /* we're supposed to pad it out with zeroes to the end */
2492 memset(&qi.u.volumeInfo.label, 0, sizeof(qi.u.volumeInfo.label));
2493 memcpy(qi.u.volumeInfo.label, "AFS", 4);
2496 case SMB_QUERY_FS_VOLUME_INFO:
2497 /* FS volume info */
2498 memset((char *)&qi.u.FSvolumeInfo.vct, 0, 4);
2499 qi.u.FSvolumeInfo.vsn = 1234;
2500 qi.u.FSvolumeInfo.vnCount = 8;
2501 memcpy(qi.u.FSvolumeInfo.label, "A\0F\0S\0\0\0", 8);
2504 case SMB_QUERY_FS_SIZE_INFO:
2506 qi.u.FSsizeInfo.totalAllocUnits.HighPart = 0;
2507 qi.u.FSsizeInfo.totalAllocUnits.LowPart= 0x7fffffff;
2508 qi.u.FSsizeInfo.availAllocUnits.HighPart = 0;
2509 qi.u.FSsizeInfo.availAllocUnits.LowPart= 0x3fffffff;
2510 qi.u.FSsizeInfo.sectorsPerAllocUnit = 1;
2511 qi.u.FSsizeInfo.bytesPerSector = 1024;
2514 case SMB_QUERY_FS_DEVICE_INFO:
2515 /* FS device info */
2516 qi.u.FSdeviceInfo.devType = 0x14; /* network file system */
2517 qi.u.FSdeviceInfo.characteristics = 0x50; /* remote, virtual */
2520 case SMB_QUERY_FS_ATTRIBUTE_INFO:
2521 /* FS attribute info */
2522 /* attributes, defined in WINNT.H:
2523 * FILE_CASE_SENSITIVE_SEARCH 0x1
2524 * FILE_CASE_PRESERVED_NAMES 0x2
2525 * FILE_VOLUME_QUOTAS 0x10
2526 * <no name defined> 0x4000
2527 * If bit 0x4000 is not set, Windows 95 thinks
2528 * we can't handle long (non-8.3) names,
2529 * despite our protestations to the contrary.
2531 qi.u.FSattributeInfo.attributes = 0x4003;
2532 qi.u.FSattributeInfo.maxCompLength = MAX_PATH;
2533 qi.u.FSattributeInfo.FSnameLength = sizeof(FSname);
2534 memcpy(qi.u.FSattributeInfo.FSname, FSname, sizeof(FSname));
2538 /* copy out return data, and set corresponding sizes */
2539 outp->totalParms = 0;
2540 outp->totalData = responseSize;
2541 memcpy(outp->datap, &qi, responseSize);
2543 /* send and free the packets */
2544 smb_SendTran2Packet(vcp, outp, op);
2545 smb_FreeTran2Packet(outp);
2550 long smb_ReceiveTran2SetFSInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
2552 osi_Log0(smb_logp,"ReceiveTran2SetFSInfo - NOT_SUPPORTED");
2553 return CM_ERROR_BADOP;
2556 struct smb_ShortNameRock {
2560 size_t shortNameLen;
2563 int cm_GetShortNameProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *vrockp,
2566 struct smb_ShortNameRock *rockp;
2570 /* compare both names and vnodes, though probably just comparing vnodes
2571 * would be safe enough.
2573 if (cm_stricmp(dep->name, rockp->maskp) != 0)
2575 if (ntohl(dep->fid.vnode) != rockp->vnode)
2577 /* This is the entry */
2578 cm_Gen8Dot3Name(dep, rockp->shortName, &shortNameEnd);
2579 rockp->shortNameLen = shortNameEnd - rockp->shortName;
2580 return CM_ERROR_STOPNOW;
2583 long cm_GetShortName(char *pathp, cm_user_t *userp, cm_req_t *reqp,
2584 char *tidPathp, int vnode, char *shortName, size_t *shortNameLenp)
2586 struct smb_ShortNameRock rock;
2590 int caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
2594 spacep = cm_GetSpace();
2595 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
2597 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold, userp, tidPathp,
2599 cm_FreeSpace(spacep);
2604 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
2605 cm_ReleaseSCache(dscp);
2606 cm_ReleaseUser(userp);
2607 return CM_ERROR_PATH_NOT_COVERED;
2609 #endif /* DFS_SUPPORT */
2611 if (!lastNamep) lastNamep = pathp;
2614 thyper.HighPart = 0;
2615 rock.shortName = shortName;
2617 rock.maskp = lastNamep;
2618 code = cm_ApplyDir(dscp, cm_GetShortNameProc, &rock, &thyper, userp, reqp, NULL);
2620 cm_ReleaseSCache(dscp);
2623 return CM_ERROR_NOSUCHFILE;
2624 if (code == CM_ERROR_STOPNOW) {
2625 *shortNameLenp = rock.shortNameLen;
2631 long smb_ReceiveTran2QPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
2633 smb_tran2Packet_t *outp;
2636 unsigned short infoLevel;
2637 smb_tran2QPathInfo_t qpi;
2639 unsigned short attributes;
2640 unsigned long extAttributes;
2645 cm_scache_t *scp, *dscp;
2655 infoLevel = p->parmsp[0];
2656 if (infoLevel == SMB_INFO_IS_NAME_VALID)
2658 else if (infoLevel == SMB_INFO_STANDARD)
2659 responseSize = sizeof(qpi.u.QPstandardInfo);
2660 else if (infoLevel == SMB_INFO_QUERY_EA_SIZE)
2661 responseSize = sizeof(qpi.u.QPeaSizeInfo);
2662 else if (infoLevel == SMB_QUERY_FILE_BASIC_INFO)
2663 responseSize = sizeof(qpi.u.QPfileBasicInfo);
2664 else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO)
2665 responseSize = sizeof(qpi.u.QPfileStandardInfo);
2666 else if (infoLevel == SMB_QUERY_FILE_EA_INFO)
2667 responseSize = sizeof(qpi.u.QPfileEaInfo);
2668 else if (infoLevel == SMB_QUERY_FILE_NAME_INFO)
2669 responseSize = sizeof(qpi.u.QPfileNameInfo);
2670 else if (infoLevel == SMB_QUERY_FILE_ALL_INFO)
2671 responseSize = sizeof(qpi.u.QPfileAllInfo);
2672 else if (infoLevel == SMB_QUERY_FILE_ALT_NAME_INFO)
2673 responseSize = sizeof(qpi.u.QPfileAltNameInfo);
2675 osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
2676 p->opcode, infoLevel);
2677 smb_SendTran2Error(vcp, p, opx, CM_ERROR_BADOP);
2681 pathp = (char *)(&p->parmsp[3]);
2682 if (smb_StoreAnsiFilenames)
2683 OemToChar(pathp,pathp);
2684 osi_Log2(smb_logp, "T2 QPathInfo type 0x%x path %s", infoLevel,
2685 osi_LogSaveString(smb_logp, pathp));
2687 outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, responseSize);
2689 if (infoLevel > 0x100)
2690 outp->totalParms = 2;
2692 outp->totalParms = 0;
2693 outp->totalData = responseSize;
2695 /* now, if we're at infoLevel 6, we're only being asked to check
2696 * the syntax, so we just OK things now. In particular, we're *not*
2697 * being asked to verify anything about the state of any parent dirs.
2699 if (infoLevel == SMB_INFO_IS_NAME_VALID) {
2700 smb_SendTran2Packet(vcp, outp, opx);
2701 smb_FreeTran2Packet(outp);
2705 userp = smb_GetTran2User(vcp, p);
2707 osi_Log1(smb_logp, "ReceiveTran2QPathInfo unable to resolve user [%d]", p->uid);
2708 smb_FreeTran2Packet(outp);
2709 return CM_ERROR_BADSMB;
2712 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
2714 cm_ReleaseUser(userp);
2715 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOSUCHPATH);
2716 smb_FreeTran2Packet(outp);
2721 * XXX Strange hack XXX
2723 * As of Patch 7 (13 January 98), we are having the following problem:
2724 * In NT Explorer 4.0, whenever we click on a directory, AFS gets
2725 * requests to look up "desktop.ini" in all the subdirectories.
2726 * This can cause zillions of timeouts looking up non-existent cells
2727 * and volumes, especially in the top-level directory.
2729 * We have not found any way to avoid this or work around it except
2730 * to explicitly ignore the requests for mount points that haven't
2731 * yet been evaluated and for directories that haven't yet been
2734 if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
2735 spacep = cm_GetSpace();
2736 smb_StripLastComponent(spacep->data, &lastComp, pathp);
2737 #ifndef SPECIAL_FOLDERS
2738 /* Make sure that lastComp is not NULL */
2740 if (stricmp(lastComp, "\\desktop.ini") == 0) {
2741 code = cm_NameI(cm_data.rootSCachep, spacep->data,
2745 userp, tidPathp, &req, &dscp);
2748 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
2749 if ( WANTS_DFS_PATHNAMES(p) )
2750 code = CM_ERROR_PATH_NOT_COVERED;
2752 code = CM_ERROR_BADSHARENAME;
2754 #endif /* DFS_SUPPORT */
2755 if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT && !dscp->mountRootFid.volume)
2756 code = CM_ERROR_NOSUCHFILE;
2757 else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
2758 cm_buf_t *bp = buf_Find(dscp, &hzero);
2762 code = CM_ERROR_NOSUCHFILE;
2764 cm_ReleaseSCache(dscp);
2766 cm_FreeSpace(spacep);
2767 cm_ReleaseUser(userp);
2768 smb_SendTran2Error(vcp, p, opx, code);
2769 smb_FreeTran2Packet(outp);
2775 #endif /* SPECIAL_FOLDERS */
2777 cm_FreeSpace(spacep);
2780 /* now do namei and stat, and copy out the info */
2781 code = cm_NameI(cm_data.rootSCachep, pathp,
2782 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, tidPathp, &req, &scp);
2785 cm_ReleaseUser(userp);
2786 smb_SendTran2Error(vcp, p, opx, code);
2787 smb_FreeTran2Packet(outp);
2792 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
2793 cm_ReleaseSCache(scp);
2794 cm_ReleaseUser(userp);
2795 if ( WANTS_DFS_PATHNAMES(p) )
2796 code = CM_ERROR_PATH_NOT_COVERED;
2798 code = CM_ERROR_BADSHARENAME;
2799 smb_SendTran2Error(vcp, p, opx, code);
2800 smb_FreeTran2Packet(outp);
2803 #endif /* DFS_SUPPORT */
2805 lock_ObtainMutex(&scp->mx);
2806 code = cm_SyncOp(scp, NULL, userp, &req, 0,
2807 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
2808 if (code) goto done;
2810 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
2812 /* now we have the status in the cache entry, and everything is locked.
2813 * Marshall the output data.
2815 /* for info level 108, figure out short name */
2816 if (infoLevel == SMB_QUERY_FILE_ALT_NAME_INFO) {
2817 code = cm_GetShortName(pathp, userp, &req,
2818 tidPathp, scp->fid.vnode, shortName,
2824 qpi.u.QPfileAltNameInfo.fileNameLength = (len + 1) * 2;
2825 mbstowcs((unsigned short *)qpi.u.QPfileAltNameInfo.fileName, shortName, len + 1);
2829 else if (infoLevel == SMB_QUERY_FILE_NAME_INFO) {
2830 len = strlen(lastComp);
2831 qpi.u.QPfileNameInfo.fileNameLength = (len + 1) * 2;
2832 mbstowcs((unsigned short *)qpi.u.QPfileNameInfo.fileName, lastComp, len + 1);
2836 else if (infoLevel == SMB_INFO_STANDARD || infoLevel == SMB_INFO_QUERY_EA_SIZE) {
2837 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
2838 qpi.u.QPstandardInfo.creationDateTime = dosTime;
2839 qpi.u.QPstandardInfo.lastAccessDateTime = dosTime;
2840 qpi.u.QPstandardInfo.lastWriteDateTime = dosTime;
2841 qpi.u.QPstandardInfo.dataSize = scp->length.LowPart;
2842 qpi.u.QPstandardInfo.allocationSize = scp->length.LowPart;
2843 attributes = smb_Attributes(scp);
2844 qpi.u.QPstandardInfo.attributes = attributes;
2845 qpi.u.QPstandardInfo.eaSize = 0;
2847 else if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
2848 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
2849 qpi.u.QPfileBasicInfo.creationTime = ft;
2850 qpi.u.QPfileBasicInfo.lastAccessTime = ft;
2851 qpi.u.QPfileBasicInfo.lastWriteTime = ft;
2852 qpi.u.QPfileBasicInfo.changeTime = ft;
2853 extAttributes = smb_ExtAttributes(scp);
2854 qpi.u.QPfileBasicInfo.attributes = extAttributes;
2855 qpi.u.QPfileBasicInfo.reserved = 0;
2857 else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO) {
2858 smb_fid_t *fidp = smb_FindFIDByScache(vcp, scp);
2860 lock_ObtainMutex(&fidp->mx);
2861 delonclose = fidp->flags & SMB_FID_DELONCLOSE;
2862 lock_ReleaseMutex(&fidp->mx);
2863 smb_ReleaseFID(fidp);
2866 qpi.u.QPfileStandardInfo.allocationSize = scp->length;
2867 qpi.u.QPfileStandardInfo.endOfFile = scp->length;
2868 qpi.u.QPfileStandardInfo.numberOfLinks = scp->linkCount;
2869 qpi.u.QPfileStandardInfo.deletePending = (delonclose ? 1 : 0);
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;
2876 else if (infoLevel == SMB_QUERY_FILE_EA_INFO) {
2877 qpi.u.QPfileEaInfo.eaSize = 0;
2879 else if (infoLevel == SMB_QUERY_FILE_ALL_INFO) {
2880 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
2881 qpi.u.QPfileAllInfo.creationTime = ft;
2882 qpi.u.QPfileAllInfo.lastAccessTime = ft;
2883 qpi.u.QPfileAllInfo.lastWriteTime = ft;
2884 qpi.u.QPfileAllInfo.changeTime = ft;
2885 extAttributes = smb_ExtAttributes(scp);
2886 qpi.u.QPfileAllInfo.attributes = extAttributes;
2887 qpi.u.QPfileAllInfo.allocationSize = scp->length;
2888 qpi.u.QPfileAllInfo.endOfFile = scp->length;
2889 qpi.u.QPfileAllInfo.numberOfLinks = scp->linkCount;
2890 qpi.u.QPfileAllInfo.deletePending = 0;
2891 qpi.u.QPfileAllInfo.directory =
2892 ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
2893 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
2894 scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0);
2895 qpi.u.QPfileAllInfo.indexNumber.HighPart = scp->fid.cell;
2896 qpi.u.QPfileAllInfo.indexNumber.LowPart = scp->fid.volume;
2897 qpi.u.QPfileAllInfo.eaSize = 0;
2898 qpi.u.QPfileAllInfo.accessFlags = 0;
2899 qpi.u.QPfileAllInfo.indexNumber2.HighPart = scp->fid.vnode;
2900 qpi.u.QPfileAllInfo.indexNumber2.LowPart = scp->fid.unique;
2901 qpi.u.QPfileAllInfo.currentByteOffset.HighPart = 0;
2902 qpi.u.QPfileAllInfo.currentByteOffset.LowPart = 0;
2903 qpi.u.QPfileAllInfo.mode = 0;
2904 qpi.u.QPfileAllInfo.alignmentRequirement = 0;
2905 len = strlen(lastComp);
2906 qpi.u.QPfileAllInfo.fileNameLength = (len + 1) * 2;
2907 mbstowcs((unsigned short *)qpi.u.QPfileAllInfo.fileName, lastComp, len + 1);
2910 /* send and free the packets */
2912 lock_ReleaseMutex(&scp->mx);
2913 cm_ReleaseSCache(scp);
2914 cm_ReleaseUser(userp);
2916 memcpy(outp->datap, &qpi, responseSize);
2917 smb_SendTran2Packet(vcp, outp, opx);
2919 smb_SendTran2Error(vcp, p, opx, code);
2921 smb_FreeTran2Packet(outp);
2926 long smb_ReceiveTran2SetPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
2929 osi_Log0(smb_logp,"ReceiveTran2SetPathInfo - NOT_SUPPORTED");
2930 return CM_ERROR_BADOP;
2934 unsigned short infoLevel;
2936 smb_tran2Packet_t *outp;
2937 smb_tran2QPathInfo_t *spi;
2939 cm_scache_t *scp, *dscp;
2947 infoLevel = p->parmsp[0];
2948 osi_Log1(smb_logp,"ReceiveTran2SetPathInfo type 0x%x", infoLevel);
2949 if (infoLevel != SMB_INFO_STANDARD &&
2950 infoLevel != SMB_INFO_QUERY_EA_SIZE &&
2951 infoLevel != SMB_INFO_QUERY_ALL_EAS) {
2952 osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
2953 p->opcode, infoLevel);
2954 smb_SendTran2Error(vcp, p, opx, CM_ERROR_INVAL);
2958 pathp = (char *)(&p->parmsp[3]);
2959 if (smb_StoreAnsiFilenames)
2960 OemToChar(pathp,pathp);
2961 osi_Log2(smb_logp, "T2 SetPathInfo infolevel 0x%x path %s", infoLevel,
2962 osi_LogSaveString(smb_logp, pathp));
2964 userp = smb_GetTran2User(vcp, p);
2966 osi_Log1(smb_logp,"ReceiveTran2SetPathInfo unable to resolve user [%d]", p->uid);
2967 code = CM_ERROR_BADSMB;
2971 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
2972 if (code == CM_ERROR_TIDIPC) {
2973 /* Attempt to use a TID allocated for IPC. The client
2974 * is probably looking for DCE RPC end points which we
2975 * don't support OR it could be looking to make a DFS
2978 osi_Log0(smb_logp, "Tran2Open received IPC TID");
2979 cm_ReleaseUser(userp);
2980 return CM_ERROR_NOSUCHPATH;
2984 * XXX Strange hack XXX
2986 * As of Patch 7 (13 January 98), we are having the following problem:
2987 * In NT Explorer 4.0, whenever we click on a directory, AFS gets
2988 * requests to look up "desktop.ini" in all the subdirectories.
2989 * This can cause zillions of timeouts looking up non-existent cells
2990 * and volumes, especially in the top-level directory.
2992 * We have not found any way to avoid this or work around it except
2993 * to explicitly ignore the requests for mount points that haven't
2994 * yet been evaluated and for directories that haven't yet been
2997 if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
2998 spacep = cm_GetSpace();
2999 smb_StripLastComponent(spacep->data, &lastComp, pathp);
3000 #ifndef SPECIAL_FOLDERS
3001 /* Make sure that lastComp is not NULL */
3003 if (stricmp(lastComp, "\\desktop.ini") == 0) {
3004 code = cm_NameI(cm_data.rootSCachep, spacep->data,
3008 userp, tidPathp, &req, &dscp);
3011 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
3012 if ( WANTS_DFS_PATHNAMES(p) )
3013 code = CM_ERROR_PATH_NOT_COVERED;
3015 code = CM_ERROR_BADSHARENAME;
3017 #endif /* DFS_SUPPORT */
3018 if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT && !dscp->mountRootFid.volume)
3019 code = CM_ERROR_NOSUCHFILE;
3020 else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
3021 cm_buf_t *bp = buf_Find(dscp, &hzero);
3025 code = CM_ERROR_NOSUCHFILE;
3027 cm_ReleaseSCache(dscp);
3029 cm_FreeSpace(spacep);
3030 cm_ReleaseUser(userp);
3031 smb_SendTran2Error(vcp, p, opx, code);
3037 #endif /* SPECIAL_FOLDERS */
3039 cm_FreeSpace(spacep);
3042 /* now do namei and stat, and copy out the info */
3043 code = cm_NameI(cm_data.rootSCachep, pathp,
3044 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, tidPathp, &req, &scp);
3046 cm_ReleaseUser(userp);
3047 smb_SendTran2Error(vcp, p, opx, code);
3051 fidp = smb_FindFIDByScache(vcp, scp);
3053 cm_ReleaseUser(userp);
3054 cm_ReleaseSCache(scp);
3055 smb_SendTran2Error(vcp, p, opx, code);
3059 lock_ObtainMutex(&fidp->mx);
3060 if (!(fidp->flags & SMB_FID_OPENWRITE)) {
3061 lock_ReleaseMutex(&fidp->mx);
3062 smb_ReleaseFID(fidp);
3063 cm_ReleaseUser(userp);
3064 cm_ReleaseSCache(scp);
3065 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOACCESS);
3068 lock_ReleaseMutex(&fidp->mx);
3070 outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, 0);
3072 outp->totalParms = 2;
3073 outp->totalData = 0;
3075 spi = (smb_tran2QPathInfo_t *)p->datap;
3076 if (infoLevel == SMB_INFO_STANDARD || infoLevel == SMB_INFO_QUERY_EA_SIZE) {
3079 /* lock the vnode with a callback; we need the current status
3080 * to determine what the new status is, in some cases.
3082 lock_ObtainMutex(&scp->mx);
3083 code = cm_SyncOp(scp, NULL, userp, &req, 0,
3084 CM_SCACHESYNC_GETSTATUS
3085 | CM_SCACHESYNC_NEEDCALLBACK);
3087 lock_ReleaseMutex(&scp->mx);
3090 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3092 lock_ReleaseMutex(&scp->mx);
3093 lock_ObtainMutex(&fidp->mx);
3094 lock_ObtainMutex(&scp->mx);
3096 /* prepare for setattr call */
3097 attr.mask = CM_ATTRMASK_LENGTH;
3098 attr.length.LowPart = spi->u.QPstandardInfo.dataSize;
3099 attr.length.HighPart = 0;
3101 if (spi->u.QPstandardInfo.lastWriteDateTime != 0) {
3102 smb_UnixTimeFromSearchTime(&attr.clientModTime, spi->u.QPstandardInfo.lastWriteDateTime);
3103 attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
3104 fidp->flags |= SMB_FID_MTIMESETDONE;
3107 if (spi->u.QPstandardInfo.attributes != 0) {
3108 if ((scp->unixModeBits & 0222)
3109 && (spi->u.QPstandardInfo.attributes & SMB_ATTR_READONLY) != 0) {
3110 /* make a writable file read-only */
3111 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
3112 attr.unixModeBits = scp->unixModeBits & ~0222;
3114 else if ((scp->unixModeBits & 0222) == 0
3115 && (spi->u.QPstandardInfo.attributes & SMB_ATTR_READONLY) == 0) {
3116 /* make a read-only file writable */
3117 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
3118 attr.unixModeBits = scp->unixModeBits | 0222;
3121 lock_ReleaseMutex(&scp->mx);
3122 lock_ReleaseMutex(&fidp->mx);
3126 code = cm_SetAttr(scp, &attr, userp, &req);
3130 else if (infoLevel == SMB_INFO_QUERY_ALL_EAS) {
3131 /* we don't support EAs */
3132 code = CM_ERROR_INVAL;
3136 cm_ReleaseSCache(scp);
3137 cm_ReleaseUser(userp);
3138 smb_ReleaseFID(fidp);
3140 smb_SendTran2Packet(vcp, outp, opx);
3142 smb_SendTran2Error(vcp, p, opx, code);
3143 smb_FreeTran2Packet(outp);
3149 long smb_ReceiveTran2QFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
3151 smb_tran2Packet_t *outp;
3153 unsigned long attributes;
3154 unsigned short infoLevel;
3161 smb_tran2QFileInfo_t qfi;
3168 fidp = smb_FindFID(vcp, fid, 0);
3171 smb_SendTran2Error(vcp, p, opx, CM_ERROR_BADFD);
3175 infoLevel = p->parmsp[1];
3176 if (infoLevel == SMB_QUERY_FILE_BASIC_INFO)
3177 responseSize = sizeof(qfi.u.QFbasicInfo);
3178 else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO)
3179 responseSize = sizeof(qfi.u.QFstandardInfo);
3180 else if (infoLevel == SMB_QUERY_FILE_EA_INFO)
3181 responseSize = sizeof(qfi.u.QFeaInfo);
3182 else if (infoLevel == SMB_QUERY_FILE_NAME_INFO)
3183 responseSize = sizeof(qfi.u.QFfileNameInfo);
3185 osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
3186 p->opcode, infoLevel);
3187 smb_SendTran2Error(vcp, p, opx, CM_ERROR_BADOP);
3188 smb_ReleaseFID(fidp);
3191 osi_Log2(smb_logp, "T2 QFileInfo type 0x%x fid %d", infoLevel, fid);
3193 outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, responseSize);
3195 if (infoLevel > 0x100)
3196 outp->totalParms = 2;
3198 outp->totalParms = 0;
3199 outp->totalData = responseSize;
3201 userp = smb_GetTran2User(vcp, p);
3203 osi_Log1(smb_logp, "ReceiveTran2QFileInfo unable to resolve user [%d]", p->uid);
3204 code = CM_ERROR_BADSMB;
3208 lock_ObtainMutex(&fidp->mx);
3209 delonclose = fidp->flags & SMB_FID_DELONCLOSE;
3212 lock_ReleaseMutex(&fidp->mx);
3213 lock_ObtainMutex(&scp->mx);
3214 code = cm_SyncOp(scp, NULL, userp, &req, 0,
3215 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3219 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3221 /* now we have the status in the cache entry, and everything is locked.
3222 * Marshall the output data.
3224 if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
3225 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
3226 qfi.u.QFbasicInfo.creationTime = ft;
3227 qfi.u.QFbasicInfo.lastAccessTime = ft;
3228 qfi.u.QFbasicInfo.lastWriteTime = ft;
3229 qfi.u.QFbasicInfo.lastChangeTime = ft;
3230 attributes = smb_ExtAttributes(scp);
3231 qfi.u.QFbasicInfo.attributes = attributes;
3233 else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO) {
3234 qfi.u.QFstandardInfo.allocationSize = scp->length;
3235 qfi.u.QFstandardInfo.endOfFile = scp->length;
3236 qfi.u.QFstandardInfo.numberOfLinks = scp->linkCount;
3237 qfi.u.QFstandardInfo.deletePending = (delonclose ? 1 : 0);
3238 qfi.u.QFstandardInfo.directory =
3239 ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
3240 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
3241 scp->fileType == CM_SCACHETYPE_INVALID)? 1 : 0);
3243 else if (infoLevel == SMB_QUERY_FILE_EA_INFO) {
3244 qfi.u.QFeaInfo.eaSize = 0;
3246 else if (infoLevel == SMB_QUERY_FILE_NAME_INFO) {
3250 lock_ReleaseMutex(&scp->mx);
3251 lock_ObtainMutex(&fidp->mx);
3252 lock_ObtainMutex(&scp->mx);
3253 if (fidp->NTopen_wholepathp)
3254 name = fidp->NTopen_wholepathp;
3256 name = "\\"; /* probably can't happen */
3257 lock_ReleaseMutex(&fidp->mx);
3258 len = (unsigned long)strlen(name);
3259 outp->totalData = ((len+1)*2) + 4; /* this is actually what we want to return */
3260 qfi.u.QFfileNameInfo.fileNameLength = (len + 1) * 2;
3261 mbstowcs((unsigned short *)qfi.u.QFfileNameInfo.fileName, name, len + 1);
3264 /* send and free the packets */
3266 lock_ReleaseMutex(&scp->mx);
3267 cm_ReleaseSCache(scp);
3268 cm_ReleaseUser(userp);
3269 smb_ReleaseFID(fidp);
3271 memcpy(outp->datap, &qfi, responseSize);
3272 smb_SendTran2Packet(vcp, outp, opx);
3274 smb_SendTran2Error(vcp, p, opx, code);
3276 smb_FreeTran2Packet(outp);
3281 long smb_ReceiveTran2SetFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
3286 unsigned short infoLevel;
3287 smb_tran2Packet_t *outp;
3295 fidp = smb_FindFID(vcp, fid, 0);
3298 smb_SendTran2Error(vcp, p, opx, CM_ERROR_BADFD);
3302 infoLevel = p->parmsp[1];
3303 osi_Log2(smb_logp,"ReceiveTran2SetFileInfo type 0x%x fid %d", infoLevel, fid);
3304 if (infoLevel > SMB_SET_FILE_END_OF_FILE_INFO || infoLevel < SMB_SET_FILE_BASIC_INFO) {
3305 osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
3306 p->opcode, infoLevel);
3307 smb_SendTran2Error(vcp, p, opx, CM_ERROR_BADOP);
3308 smb_ReleaseFID(fidp);
3312 lock_ObtainMutex(&fidp->mx);
3313 if (infoLevel == SMB_SET_FILE_DISPOSITION_INFO && !(fidp->flags & SMB_FID_OPENDELETE)) {
3314 lock_ReleaseMutex(&fidp->mx);
3315 smb_ReleaseFID(fidp);
3316 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOACCESS);
3319 if ((infoLevel == SMB_SET_FILE_ALLOCATION_INFO ||
3320 infoLevel == SMB_SET_FILE_END_OF_FILE_INFO)
3321 && !(fidp->flags & SMB_FID_OPENWRITE)) {
3322 lock_ReleaseMutex(&fidp->mx);
3323 smb_ReleaseFID(fidp);
3324 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOACCESS);
3330 lock_ReleaseMutex(&fidp->mx);
3332 outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, 0);
3334 outp->totalParms = 2;
3335 outp->totalData = 0;
3337 userp = smb_GetTran2User(vcp, p);
3339 osi_Log1(smb_logp,"ReceiveTran2SetFileInfo unable to resolve user [%d]", p->uid);
3340 code = CM_ERROR_BADSMB;
3344 if (infoLevel == SMB_SET_FILE_BASIC_INFO) {
3346 unsigned int attribute;
3348 smb_tran2QFileInfo_t *sfi;
3350 sfi = (smb_tran2QFileInfo_t *)p->datap;
3352 /* lock the vnode with a callback; we need the current status
3353 * to determine what the new status is, in some cases.
3355 lock_ObtainMutex(&scp->mx);
3356 code = cm_SyncOp(scp, NULL, userp, &req, 0,
3357 CM_SCACHESYNC_GETSTATUS
3358 | CM_SCACHESYNC_NEEDCALLBACK);
3360 lock_ReleaseMutex(&scp->mx);
3364 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3366 lock_ReleaseMutex(&scp->mx);
3367 lock_ObtainMutex(&fidp->mx);
3368 lock_ObtainMutex(&scp->mx);
3370 /* prepare for setattr call */
3373 lastMod = sfi->u.QFbasicInfo.lastWriteTime;
3374 /* when called as result of move a b, lastMod is (-1, -1).
3375 * If the check for -1 is not present, timestamp
3376 * of the resulting file will be 1969 (-1)
3378 if (LargeIntegerNotEqualToZero(*((LARGE_INTEGER *)&lastMod)) &&
3379 lastMod.dwLowDateTime != -1 && lastMod.dwHighDateTime != -1) {
3380 attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
3381 smb_UnixTimeFromLargeSearchTime(&attr.clientModTime, &lastMod);
3382 fidp->flags |= SMB_FID_MTIMESETDONE;
3385 attribute = sfi->u.QFbasicInfo.attributes;
3386 if (attribute != 0) {
3387 if ((scp->unixModeBits & 0222)
3388 && (attribute & SMB_ATTR_READONLY) != 0) {
3389 /* make a writable file read-only */
3390 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
3391 attr.unixModeBits = scp->unixModeBits & ~0222;
3393 else if ((scp->unixModeBits & 0222) == 0
3394 && (attribute & SMB_ATTR_READONLY) == 0) {
3395 /* make a read-only file writable */
3396 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
3397 attr.unixModeBits = scp->unixModeBits | 0222;
3400 lock_ReleaseMutex(&scp->mx);
3401 lock_ReleaseMutex(&fidp->mx);
3405 code = cm_SetAttr(scp, &attr, userp, &req);
3409 else if (infoLevel == SMB_SET_FILE_DISPOSITION_INFO) {
3410 if (*((char *)(p->datap))) { /* File is Deleted */
3411 code = cm_CheckNTDelete(fidp->NTopen_dscp, scp, userp,
3414 lock_ObtainMutex(&fidp->mx);
3415 fidp->flags |= SMB_FID_DELONCLOSE;
3416 lock_ReleaseMutex(&fidp->mx);
3421 lock_ObtainMutex(&fidp->mx);
3422 fidp->flags &= ~SMB_FID_DELONCLOSE;
3423 lock_ReleaseMutex(&fidp->mx);
3426 else if (infoLevel == SMB_SET_FILE_ALLOCATION_INFO ||
3427 infoLevel == SMB_SET_FILE_END_OF_FILE_INFO) {
3428 LARGE_INTEGER size = *((LARGE_INTEGER *)(p->datap));
3431 attr.mask = CM_ATTRMASK_LENGTH;
3432 attr.length.LowPart = size.LowPart;
3433 attr.length.HighPart = size.HighPart;
3434 code = cm_SetAttr(scp, &attr, userp, &req);
3438 cm_ReleaseSCache(scp);
3439 cm_ReleaseUser(userp);
3440 smb_ReleaseFID(fidp);
3442 smb_SendTran2Packet(vcp, outp, opx);
3444 smb_SendTran2Error(vcp, p, opx, code);
3445 smb_FreeTran2Packet(outp);
3451 smb_ReceiveTran2FSCTL(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3453 osi_Log0(smb_logp,"ReceiveTran2FSCTL - NOT_SUPPORTED");
3454 return CM_ERROR_BADOP;
3458 smb_ReceiveTran2IOCTL(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3460 osi_Log0(smb_logp,"ReceiveTran2IOCTL - NOT_SUPPORTED");
3461 return CM_ERROR_BADOP;
3465 smb_ReceiveTran2FindNotifyFirst(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3467 osi_Log0(smb_logp,"ReceiveTran2FindNotifyFirst - NOT_SUPPORTED");
3468 return CM_ERROR_BADOP;
3472 smb_ReceiveTran2FindNotifyNext(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3474 osi_Log0(smb_logp,"ReceiveTran2FindNotifyNext - NOT_SUPPORTED");
3475 return CM_ERROR_BADOP;
3479 smb_ReceiveTran2CreateDirectory(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3481 osi_Log0(smb_logp,"ReceiveTran2CreateDirectory - NOT_SUPPORTED");
3482 return CM_ERROR_BADOP;
3486 smb_ReceiveTran2SessionSetup(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3488 osi_Log0(smb_logp,"ReceiveTran2SessionSetup - NOT_SUPPORTED");
3489 return CM_ERROR_BADOP;
3492 struct smb_v2_referral {
3494 USHORT ReferralFlags;
3497 USHORT DfsPathOffset;
3498 USHORT DfsAlternativePathOffset;
3499 USHORT NetworkAddressOffset;
3503 smb_ReceiveTran2GetDFSReferral(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
3505 /* This is a UNICODE only request (bit15 of Flags2) */
3506 /* The TID must be IPC$ */
3508 /* The documentation for the Flags response field is contradictory */
3510 /* Use Version 1 Referral Element Format */
3511 /* ServerType = 0; indicates the next server should be queried for the file */
3512 /* ReferralFlags = 0x01; PathConsumed characters should be stripped */
3513 /* Node = UnicodeString of UNC path of the next share name */
3516 int maxReferralLevel = 0;
3517 char requestFileName[1024] = "";
3518 smb_tran2Packet_t *outp = 0;
3519 cm_user_t *userp = 0;
3521 CPINFO CodePageInfo;
3522 int i, nbnLen, reqLen;
3527 maxReferralLevel = p->parmsp[0];
3529 GetCPInfo(CP_ACP, &CodePageInfo);
3530 WideCharToMultiByte(CP_ACP, 0, (LPCWSTR) &p->parmsp[1], -1,
3531 requestFileName, 1024, NULL, NULL);
3533 osi_Log2(smb_logp,"ReceiveTran2GetDfsReferral [%d][%s]",
3534 maxReferralLevel, osi_LogSaveString(smb_logp, requestFileName));
3536 nbnLen = strlen(cm_NetbiosName);
3537 reqLen = strlen(requestFileName);
3539 if (reqLen == nbnLen + 5 &&
3540 requestFileName[0] == '\\' &&
3541 !_strnicmp(cm_NetbiosName,&requestFileName[1],nbnLen) &&
3542 requestFileName[nbnLen+1] == '\\' &&
3543 (!_strnicmp("all",&requestFileName[nbnLen+2],3) ||
3544 !_strnicmp("*.",&requestFileName[nbnLen+2],2)))
3547 struct smb_v2_referral * v2ref;
3548 outp = smb_GetTran2ResponsePacket(vcp, p, op, 0, 2 * (reqLen + 8));
3550 sp = (USHORT *)outp->datap;
3552 sp[idx++] = reqLen; /* path consumed */
3553 sp[idx++] = 1; /* number of referrals */
3554 sp[idx++] = 0x03; /* flags */
3555 #ifdef DFS_VERSION_1
3556 sp[idx++] = 1; /* Version Number */
3557 sp[idx++] = reqLen + 4; /* Referral Size */
3558 sp[idx++] = 1; /* Type = SMB Server */
3559 sp[idx++] = 0; /* Do not strip path consumed */
3560 for ( i=0;i<=reqLen; i++ )
3561 sp[i+idx] = requestFileName[i];
3562 #else /* DFS_VERSION_2 */
3563 sp[idx++] = 2; /* Version Number */
3564 sp[idx++] = sizeof(struct smb_v2_referral); /* Referral Size */
3565 idx += (sizeof(struct smb_v2_referral) / 2);
3566 v2ref = (struct smb_v2_referral *) &sp[5];
3567 v2ref->ServerType = 1; /* SMB Server */
3568 v2ref->ReferralFlags = 0x03;
3569 v2ref->Proximity = 0; /* closest */
3570 v2ref->TimeToLive = 3600; /* seconds */
3571 v2ref->DfsPathOffset = idx * 2;
3572 v2ref->DfsAlternativePathOffset = idx * 2;
3573 v2ref->NetworkAddressOffset = 0;
3574 for ( i=0;i<=reqLen; i++ )
3575 sp[i+idx] = requestFileName[i];
3578 userp = smb_GetTran2User(vcp, p);
3580 osi_Log1(smb_logp,"ReceiveTran2GetDfsReferral unable to resolve user [%d]", p->uid);
3581 code = CM_ERROR_BADSMB;
3586 code = CM_ERROR_NOSUCHPATH;
3591 cm_ReleaseUser(userp);
3593 smb_SendTran2Packet(vcp, outp, op);
3595 smb_SendTran2Error(vcp, p, op, code);
3597 smb_FreeTran2Packet(outp);
3600 #else /* DFS_SUPPORT */
3601 osi_Log0(smb_logp,"ReceiveTran2GetDfsReferral - NOT_SUPPORTED");
3602 return CM_ERROR_BADOP;
3603 #endif /* DFS_SUPPORT */
3607 smb_ReceiveTran2ReportDFSInconsistency(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3609 /* This is a UNICODE only request (bit15 of Flags2) */
3611 /* There is nothing we can do about this operation. The client is going to
3612 * tell us that there is a Version 1 Referral Element for which there is a DFS Error.
3613 * Unfortunately, there is really nothing we can do about it other then log it
3614 * somewhere. Even then I don't think there is anything for us to do.
3615 * So let's return an error value.
3618 osi_Log0(smb_logp,"ReceiveTran2ReportDFSInconsistency - NOT_SUPPORTED");
3619 return CM_ERROR_BADOP;
3623 smb_ApplyV3DirListPatches(cm_scache_t *dscp,
3624 smb_dirListPatch_t **dirPatchespp, int infoLevel, cm_user_t *userp,
3629 cm_scache_t *targetScp; /* target if scp is a symlink */
3634 unsigned short attr;
3635 unsigned long lattr;
3636 smb_dirListPatch_t *patchp;
3637 smb_dirListPatch_t *npatchp;
3639 for(patchp = *dirPatchespp; patchp; patchp =
3640 (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
3641 code = cm_GetSCache(&patchp->fid, &scp, userp, reqp);
3643 lock_ObtainMutex(&scp->mx);
3644 code = cm_SyncOp(scp, NULL, userp, reqp, 0,
3645 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3647 lock_ReleaseMutex(&scp->mx);
3648 cm_ReleaseSCache(scp);
3650 dptr = patchp->dptr;
3652 /* Plug in fake timestamps. A time stamp of 0 causes 'invalid parameter'
3653 errors in the client. */
3654 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO) {
3655 /* 1969-12-31 23:59:59 +00 */
3656 ft.dwHighDateTime = 0x19DB200;
3657 ft.dwLowDateTime = 0x5BB78980;
3659 /* copy to Creation Time */
3660 *((FILETIME *)dptr) = ft;
3663 /* copy to Last Access Time */
3664 *((FILETIME *)dptr) = ft;
3667 /* copy to Last Write Time */
3668 *((FILETIME *)dptr) = ft;
3671 /* copy to Change Time */
3672 *((FILETIME *)dptr) = ft;
3675 /* merge in hidden attribute */
3676 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
3677 *((u_long *)dptr) = SMB_ATTR_HIDDEN;
3681 /* 1969-12-31 23:59:58 +00*/
3682 dosTime = 0xEBBFBF7D;
3684 /* and copy out date */
3685 shortTemp = (dosTime>>16) & 0xffff;
3686 *((u_short *)dptr) = shortTemp;
3689 /* copy out creation time */
3690 shortTemp = dosTime & 0xffff;
3691 *((u_short *)dptr) = shortTemp;
3694 /* and copy out date */
3695 shortTemp = (dosTime>>16) & 0xffff;
3696 *((u_short *)dptr) = shortTemp;
3699 /* copy out access time */
3700 shortTemp = dosTime & 0xffff;
3701 *((u_short *)dptr) = shortTemp;
3704 /* and copy out date */
3705 shortTemp = (dosTime>>16) & 0xffff;
3706 *((u_short *)dptr) = shortTemp;
3709 /* copy out mod time */
3710 shortTemp = dosTime & 0xffff;
3711 *((u_short *)dptr) = shortTemp;
3714 /* merge in hidden (dot file) attribute */
3715 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
3716 attr = SMB_ATTR_HIDDEN;
3717 *dptr++ = attr & 0xff;
3718 *dptr++ = (attr >> 8) & 0xff;
3724 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3726 /* now watch for a symlink */
3728 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
3729 lock_ReleaseMutex(&scp->mx);
3730 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, reqp);
3732 /* we have a more accurate file to use (the
3733 * target of the symbolic link). Otherwise,
3734 * we'll just use the symlink anyway.
3736 osi_Log2(smb_logp, "symlink vp %x to vp %x",
3738 cm_ReleaseSCache(scp);
3741 lock_ObtainMutex(&scp->mx);
3744 dptr = patchp->dptr;
3746 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO) {
3748 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
3750 /* copy to Creation Time */
3751 *((FILETIME *)dptr) = ft;
3754 /* copy to Last Access Time */
3755 *((FILETIME *)dptr) = ft;
3758 /* copy to Last Write Time */
3759 *((FILETIME *)dptr) = ft;
3762 /* copy to Change Time */
3763 *((FILETIME *)dptr) = ft;
3766 /* Use length for both file length and alloc length */
3767 *((LARGE_INTEGER *)dptr) = scp->length;
3769 *((LARGE_INTEGER *)dptr) = scp->length;
3772 /* Copy attributes */
3773 lattr = smb_ExtAttributes(scp);
3774 if (code == CM_ERROR_NOSUCHPATH && scp->fileType == CM_SCACHETYPE_SYMLINK) {
3775 if (lattr == SMB_ATTR_NORMAL)
3776 lattr = SMB_ATTR_DIRECTORY;
3778 lattr |= SMB_ATTR_DIRECTORY;
3780 /* merge in hidden (dot file) attribute */
3781 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
3782 if (lattr == SMB_ATTR_NORMAL)
3783 lattr = SMB_ATTR_HIDDEN;
3785 lattr |= SMB_ATTR_HIDDEN;
3787 *((u_long *)dptr) = lattr;
3791 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
3793 /* and copy out date */
3794 shortTemp = (dosTime>>16) & 0xffff;
3795 *((u_short *)dptr) = shortTemp;
3798 /* copy out creation time */
3799 shortTemp = dosTime & 0xffff;
3800 *((u_short *)dptr) = shortTemp;
3803 /* and copy out date */
3804 shortTemp = (dosTime>>16) & 0xffff;
3805 *((u_short *)dptr) = shortTemp;
3808 /* copy out access time */
3809 shortTemp = dosTime & 0xffff;
3810 *((u_short *)dptr) = shortTemp;
3813 /* and copy out date */
3814 shortTemp = (dosTime>>16) & 0xffff;
3815 *((u_short *)dptr) = shortTemp;
3818 /* copy out mod time */
3819 shortTemp = dosTime & 0xffff;
3820 *((u_short *)dptr) = shortTemp;
3823 /* copy out file length and alloc length,
3824 * using the same for both
3826 *((u_long *)dptr) = scp->length.LowPart;
3828 *((u_long *)dptr) = scp->length.LowPart;
3831 /* finally copy out attributes as short */
3832 attr = smb_Attributes(scp);
3833 /* merge in hidden (dot file) attribute */
3834 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
3835 if (lattr == SMB_ATTR_NORMAL)
3836 lattr = SMB_ATTR_HIDDEN;
3838 lattr |= SMB_ATTR_HIDDEN;
3840 *dptr++ = attr & 0xff;
3841 *dptr++ = (attr >> 8) & 0xff;
3844 lock_ReleaseMutex(&scp->mx);
3845 cm_ReleaseSCache(scp);
3848 /* now free the patches */
3849 for (patchp = *dirPatchespp; patchp; patchp = npatchp) {
3850 npatchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q);
3854 /* and mark the list as empty */
3855 *dirPatchespp = NULL;
3860 #ifndef USE_OLD_MATCHING
3861 // char table for case insensitive comparison
3862 char mapCaseTable[256];
3864 VOID initUpperCaseTable(VOID)
3867 for (i = 0; i < 256; ++i)
3868 mapCaseTable[i] = toupper(i);
3869 // make '"' match '.'
3870 mapCaseTable[(int)'"'] = toupper('.');
3871 // make '<' match '*'
3872 mapCaseTable[(int)'<'] = toupper('*');
3873 // make '>' match '?'
3874 mapCaseTable[(int)'>'] = toupper('?');
3877 // Compare 'pattern' (containing metacharacters '*' and '?') with the file
3879 // Note : this procedure works recursively calling itself.
3881 // PSZ pattern : string containing metacharacters.
3882 // PSZ name : file name to be compared with 'pattern'.
3884 // BOOL : TRUE/FALSE (match/mistmatch)
3887 szWildCardMatchFileName(PSZ pattern, PSZ name, int casefold)
3889 PSZ pename; // points to the last 'name' character
3891 pename = name + strlen(name) - 1;
3902 if (*pattern == '\0')
3904 for (p = pename; p >= name; --p) {
3905 if ((casefold && (mapCaseTable[*p] == mapCaseTable[*pattern]) ||
3906 !casefold && (*p == *pattern)) &&
3907 szWildCardMatchFileName(pattern + 1, p + 1, casefold))
3912 if ((casefold && mapCaseTable[*name] != mapCaseTable[*pattern]) ||
3913 (!casefold && *name != *pattern))
3920 /* if all we have left are wildcards, then we match */
3921 for (;*pattern; pattern++) {
3922 if (*pattern != '*' && *pattern != '?')
3928 /* do a case-folding search of the star name mask with the name in namep.
3929 * Return 1 if we match, otherwise 0.
3931 int smb_V3MatchMask(char *namep, char *maskp, int flags)
3934 int i, j, star, qmark, casefold, retval;
3936 /* make sure we only match 8.3 names, if requested */
3937 if ((flags & CM_FLAG_8DOT3) && !cm_Is8Dot3(namep))
3940 casefold = (flags & CM_FLAG_CASEFOLD) ? 1 : 0;
3942 /* optimize the pattern:
3943 * if there is a mixture of '?' and '*',
3944 * for example the sequence "*?*?*?*"
3945 * must be turned into the form "*"
3947 newmask = (char *)malloc(strlen(maskp)+1);
3948 for ( i=0, j=0, star=0, qmark=0; maskp[i]; i++) {
3949 switch ( maskp[i] ) {
3961 } else if ( qmark ) {
3965 newmask[j++] = maskp[i];
3972 } else if ( qmark ) {
3976 newmask[j++] = '\0';
3978 retval = szWildCardMatchFileName(newmask, namep, casefold) ? 1:0;
3984 #else /* USE_OLD_MATCHING */
3985 /* do a case-folding search of the star name mask with the name in namep.
3986 * Return 1 if we match, otherwise 0.
3988 int smb_V3MatchMask(char *namep, char *maskp, int flags)
3990 unsigned char tcp1, tcp2; /* Pattern characters */
3991 unsigned char tcn1; /* Name characters */
3992 int sawDot = 0, sawStar = 0, req8dot3 = 0;
3993 char *starNamep, *starMaskp;
3994 static char nullCharp[] = {0};
3995 int casefold = flags & CM_FLAG_CASEFOLD;
3997 /* make sure we only match 8.3 names, if requested */
3998 req8dot3 = (flags & CM_FLAG_8DOT3);
3999 if (req8dot3 && !cm_Is8Dot3(namep))
4004 /* Next pattern character */
4007 /* Next name character */
4011 /* 0 - end of pattern */
4017 else if (tcp1 == '.' || tcp1 == '"') {
4027 * first dot in pattern;
4028 * must match dot or end of name
4033 else if (tcn1 == '.') {
4042 else if (tcp1 == '?') {
4043 if (tcn1 == 0 || tcn1 == '.')
4048 else if (tcp1 == '>') {
4049 if (tcn1 != 0 && tcn1 != '.')
4053 else if (tcp1 == '*' || tcp1 == '<') {
4057 else if ((req8dot3 && tcp2 == '.') || tcp2 == '"') {
4058 while (req8dot3 && tcn1 != '.' && tcn1 != 0)
4073 * pattern character after '*' is not null or
4074 * period. If it is '?' or '>', we are not
4075 * going to understand it. If it is '*' or
4076 * '<', we are going to skip over it. None of
4077 * these are likely, I hope.
4079 /* skip over '*' and '<' */
4080 while (tcp2 == '*' || tcp2 == '<')
4083 /* skip over characters that don't match tcp2 */
4084 while (req8dot3 && tcn1 != '.' && tcn1 != 0 &&
4085 ((casefold && cm_foldUpper[tcn1] != cm_foldUpper[tcp2]) ||
4086 (!casefold && tcn1 != tcp2)))
4090 if ((req8dot3 && tcn1 == '.') || tcn1 == 0)
4093 /* Remember where we are */
4103 /* tcp1 is not a wildcard */
4104 if ((casefold && cm_foldUpper[tcn1] == cm_foldUpper[tcp1]) ||
4105 (!casefold && tcn1 == tcp1)) {
4110 /* if trying to match a star pattern, go back */
4112 maskp = starMaskp - 2;
4113 namep = starNamep + 1;
4122 #endif /* USE_OLD_MATCHING */
4124 long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
4129 long code = 0, code2 = 0;
4133 smb_dirListPatch_t *dirListPatchesp;
4134 smb_dirListPatch_t *curPatchp;
4137 long orbytes; /* # of bytes in this output record */
4138 long ohbytes; /* # of bytes, except file name */
4139 long onbytes; /* # of bytes in name, incl. term. null */
4140 osi_hyper_t dirLength;
4141 osi_hyper_t bufferOffset;
4142 osi_hyper_t curOffset;
4144 smb_dirSearch_t *dsp;
4148 cm_pageHeader_t *pageHeaderp;
4149 cm_user_t *userp = NULL;
4152 long nextEntryCookie;
4153 int numDirChunks; /* # of 32 byte dir chunks in this entry */
4154 char *op; /* output data ptr */
4155 char *origOp; /* original value of op */
4156 cm_space_t *spacep; /* for pathname buffer */
4157 long maxReturnData; /* max # of return data */
4158 long maxReturnParms; /* max # of return parms */
4159 long bytesInBuffer; /* # data bytes in the output buffer */
4161 char *maskp; /* mask part of path */
4165 smb_tran2Packet_t *outp; /* response packet */
4168 char shortName[13]; /* 8.3 name if needed */
4180 if (p->opcode == 1) {
4181 /* find first; obtain basic parameters from request */
4182 attribute = p->parmsp[0];
4183 maxCount = p->parmsp[1];
4184 infoLevel = p->parmsp[3];
4185 searchFlags = p->parmsp[2];
4186 dsp = smb_NewDirSearch(1);
4187 dsp->attribute = attribute;
4188 pathp = ((char *) p->parmsp) + 12; /* points to path */
4189 if (smb_StoreAnsiFilenames)
4190 OemToChar(pathp,pathp);
4192 maskp = strrchr(pathp, '\\');
4196 maskp++; /* skip over backslash */
4197 strcpy(dsp->mask, maskp); /* and save mask */
4198 /* track if this is likely to match a lot of entries */
4199 starPattern = smb_V3IsStarMask(maskp);
4202 osi_assert(p->opcode == 2);
4203 /* find next; obtain basic parameters from request or open dir file */
4204 dsp = smb_FindDirSearch(p->parmsp[0]);
4205 maxCount = p->parmsp[1];
4206 infoLevel = p->parmsp[2];
4207 nextCookie = p->parmsp[3] | (p->parmsp[4] << 16);
4208 searchFlags = p->parmsp[5];
4210 osi_Log2(smb_logp, "T2 search dir bad search ID: id %d nextCookie 0x%x",
4211 p->parmsp[0], nextCookie);
4212 return CM_ERROR_BADFD;
4214 attribute = dsp->attribute;
4217 starPattern = 1; /* assume, since required a Find Next */
4220 switch ( infoLevel ) {
4221 case SMB_INFO_STANDARD:
4224 case SMB_INFO_QUERY_EA_SIZE:
4225 s = "InfoQueryEaSize";
4227 case SMB_INFO_QUERY_EAS_FROM_LIST:
4228 s = "InfoQueryEasFromList";
4230 case SMB_FIND_FILE_DIRECTORY_INFO:
4231 s = "FindFileDirectoryInfo";
4233 case SMB_FIND_FILE_FULL_DIRECTORY_INFO:
4234 s = "FindFileFullDirectoryInfo";
4236 case SMB_FIND_FILE_NAMES_INFO:
4237 s = "FindFileNamesInfo";
4239 case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
4240 s = "FindFileBothDirectoryInfo";
4243 s = "unknownInfoLevel";
4246 osi_Log1(smb_logp, "T2 search dir info level: %s", s);
4249 "T2 search dir attr 0x%x, info level 0x%x, max count %d, flags 0x%x",
4250 attribute, infoLevel, maxCount, searchFlags);
4252 osi_Log3(smb_logp, "...T2 search op %d, id %d, nextCookie 0x%x",
4253 p->opcode, dsp->cookie, nextCookie);
4255 if (infoLevel > SMB_FIND_FILE_BOTH_DIRECTORY_INFO) {
4256 osi_Log1(smb_logp, "Unsupported InfoLevel 0x%x", infoLevel);
4257 smb_ReleaseDirSearch(dsp);
4258 return CM_ERROR_INVAL;
4261 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO)
4262 searchFlags &= ~4; /* no resume keys */
4264 dirListPatchesp = NULL;
4266 maxReturnData = p->maxReturnData;
4267 if (p->opcode == 1) /* find first */
4268 maxReturnParms = 10; /* bytes */
4270 maxReturnParms = 8; /* bytes */
4272 #ifndef CM_CONFIG_MULTITRAN2RESPONSES
4273 if (maxReturnData > 6000)
4274 maxReturnData = 6000;
4275 #endif /* CM_CONFIG_MULTITRAN2RESPONSES */
4277 outp = smb_GetTran2ResponsePacket(vcp, p, opx, maxReturnParms,
4280 osi_Log2(smb_logp, "T2 receive search dir count %d [%s]",
4281 maxCount, osi_LogSaveString(smb_logp, pathp));
4283 /* bail out if request looks bad */
4284 if (p->opcode == 1 && !pathp) {
4285 smb_ReleaseDirSearch(dsp);
4286 smb_FreeTran2Packet(outp);
4287 return CM_ERROR_BADSMB;
4290 osi_Log3(smb_logp, "T2 search dir id %d, nextCookie 0x%x, attr 0x%x",
4291 dsp->cookie, nextCookie, attribute);
4293 userp = smb_GetTran2User(vcp, p);
4295 osi_Log1(smb_logp, "T2 search dir unable to resolve user [%d]", p->uid);
4296 smb_ReleaseDirSearch(dsp);
4297 smb_FreeTran2Packet(outp);
4298 return CM_ERROR_BADSMB;
4301 /* try to get the vnode for the path name next */
4302 lock_ObtainMutex(&dsp->mx);
4308 spacep = cm_GetSpace();
4309 smb_StripLastComponent(spacep->data, NULL, pathp);
4310 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
4312 cm_ReleaseUser(userp);
4313 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOFILES);
4314 smb_FreeTran2Packet(outp);
4315 lock_ReleaseMutex(&dsp->mx);
4316 smb_DeleteDirSearch(dsp);
4317 smb_ReleaseDirSearch(dsp);
4320 code = cm_NameI(cm_data.rootSCachep, spacep->data,
4321 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
4322 userp, tidPathp, &req, &scp);
4323 cm_FreeSpace(spacep);
4326 #ifdef DFS_SUPPORT_BUT_NOT_FIND_FIRST
4327 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
4328 cm_ReleaseSCache(scp);
4329 cm_ReleaseUser(userp);
4330 if ( WANTS_DFS_PATHNAMES(p) )
4331 code = CM_ERROR_PATH_NOT_COVERED;
4333 code = CM_ERROR_BADSHARENAME;
4334 smb_SendTran2Error(vcp, p, opx, code);
4335 smb_FreeTran2Packet(outp);
4336 lock_ReleaseMutex(&dsp->mx);
4337 smb_DeleteDirSearch(dsp);
4338 smb_ReleaseDirSearch(dsp);
4341 #endif /* DFS_SUPPORT */
4343 /* we need one hold for the entry we just stored into,
4344 * and one for our own processing. When we're done
4345 * with this function, we'll drop the one for our own
4346 * processing. We held it once from the namei call,
4347 * and so we do another hold now.
4350 lock_ObtainMutex(&scp->mx);
4351 if ((scp->flags & CM_SCACHEFLAG_BULKSTATTING) == 0 &&
4352 LargeIntegerGreaterOrEqualToZero(scp->bulkStatProgress)) {
4353 scp->flags |= CM_SCACHEFLAG_BULKSTATTING;
4354 dsp->flags |= SMB_DIRSEARCH_BULKST;
4356 lock_ReleaseMutex(&scp->mx);
4359 lock_ReleaseMutex(&dsp->mx);
4361 cm_ReleaseUser(userp);
4362 smb_FreeTran2Packet(outp);
4363 smb_DeleteDirSearch(dsp);
4364 smb_ReleaseDirSearch(dsp);
4368 /* get the directory size */
4369 lock_ObtainMutex(&scp->mx);
4370 code = cm_SyncOp(scp, NULL, userp, &req, 0,
4371 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4373 lock_ReleaseMutex(&scp->mx);
4374 cm_ReleaseSCache(scp);
4375 cm_ReleaseUser(userp);
4376 smb_FreeTran2Packet(outp);
4377 smb_DeleteDirSearch(dsp);
4378 smb_ReleaseDirSearch(dsp);
4382 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4385 dirLength = scp->length;
4387 bufferOffset.LowPart = bufferOffset.HighPart = 0;
4388 curOffset.HighPart = 0;
4389 curOffset.LowPart = nextCookie;
4390 origOp = outp->datap;
4398 if (searchFlags & 4)
4399 /* skip over resume key */
4402 /* make sure that curOffset.LowPart doesn't point to the first
4403 * 32 bytes in the 2nd through last dir page, and that it doesn't
4404 * point at the first 13 32-byte chunks in the first dir page,
4405 * since those are dir and page headers, and don't contain useful
4408 temp = curOffset.LowPart & (2048-1);
4409 if (curOffset.HighPart == 0 && curOffset.LowPart < 2048) {
4410 /* we're in the first page */
4411 if (temp < 13*32) temp = 13*32;
4414 /* we're in a later dir page */
4415 if (temp < 32) temp = 32;
4418 /* make sure the low order 5 bits are zero */
4421 /* now put temp bits back ito curOffset.LowPart */
4422 curOffset.LowPart &= ~(2048-1);
4423 curOffset.LowPart |= temp;
4425 /* check if we've passed the dir's EOF */
4426 if (LargeIntegerGreaterThanOrEqualTo(curOffset, dirLength)) {
4427 osi_Log0(smb_logp, "T2 search dir passed eof");
4432 /* check if we've returned all the names that will fit in the
4433 * response packet; we check return count as well as the number
4434 * of bytes requested. We check the # of bytes after we find
4435 * the dir entry, since we'll need to check its size.
4437 if (returnedNames >= maxCount) {
4438 osi_Log2(smb_logp, "T2 search dir returnedNames %d >= maxCount %d",
4439 returnedNames, maxCount);
4443 /* see if we can use the bufferp we have now; compute in which
4444 * page the current offset would be, and check whether that's
4445 * the offset of the buffer we have. If not, get the buffer.
4447 thyper.HighPart = curOffset.HighPart;
4448 thyper.LowPart = curOffset.LowPart & ~(cm_data.buf_blockSize-1);
4449 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
4452 buf_Release(bufferp);
4455 lock_ReleaseMutex(&scp->mx);
4456 lock_ObtainRead(&scp->bufCreateLock);
4457 code = buf_Get(scp, &thyper, &bufferp);
4458 lock_ReleaseRead(&scp->bufCreateLock);
4459 lock_ObtainMutex(&dsp->mx);
4461 /* now, if we're doing a star match, do bulk fetching
4462 * of all of the status info for files in the dir.
4465 smb_ApplyV3DirListPatches(scp, &dirListPatchesp,
4468 lock_ObtainMutex(&scp->mx);
4469 if ((dsp->flags & SMB_DIRSEARCH_BULKST) &&
4470 LargeIntegerGreaterThanOrEqualTo(thyper, scp->bulkStatProgress)) {
4471 /* Don't bulk stat if risking timeout */
4472 int now = GetTickCount();
4473 if (now - req.startTime > RDRtimeout) {
4474 scp->bulkStatProgress = thyper;
4475 scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
4476 dsp->flags &= ~SMB_DIRSEARCH_BULKST;
4478 code = cm_TryBulkStat(scp, &thyper, userp, &req);
4481 lock_ObtainMutex(&scp->mx);
4483 lock_ReleaseMutex(&dsp->mx);
4485 osi_Log2(smb_logp, "T2 search dir buf_Get scp %x failed %d", scp, code);
4489 bufferOffset = thyper;
4491 /* now get the data in the cache */
4493 code = cm_SyncOp(scp, bufferp, userp, &req,
4495 CM_SCACHESYNC_NEEDCALLBACK
4496 | CM_SCACHESYNC_READ);
4498 osi_Log2(smb_logp, "T2 search dir cm_SyncOp scp %x failed %d", scp, code);
4502 cm_SyncOpDone(scp, bufferp, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ);
4504 if (cm_HaveBuffer(scp, bufferp, 0)) {
4505 osi_Log2(smb_logp, "T2 search dir !HaveBuffer scp %x bufferp %x", scp, bufferp);
4509 /* otherwise, load the buffer and try again */
4510 code = cm_GetBuffer(scp, bufferp, NULL, userp,
4513 osi_Log3(smb_logp, "T2 search dir cm_GetBuffer failed scp %x bufferp %x code %d",
4514 scp, bufferp, code);
4519 buf_Release(bufferp);
4523 } /* if (wrong buffer) ... */
4525 /* now we have the buffer containing the entry we're interested
4526 * in; copy it out if it represents a non-deleted entry.
4528 entryInDir = curOffset.LowPart & (2048-1);
4529 entryInBuffer = curOffset.LowPart & (cm_data.buf_blockSize - 1);
4531 /* page header will help tell us which entries are free. Page
4532 * header can change more often than once per buffer, since
4533 * AFS 3 dir page size may be less than (but not more than)
4534 * a buffer package buffer.
4536 /* only look intra-buffer */
4537 temp = curOffset.LowPart & (cm_data.buf_blockSize - 1);
4538 temp &= ~(2048 - 1); /* turn off intra-page bits */
4539 pageHeaderp = (cm_pageHeader_t *) (bufferp->datap + temp);
4541 /* now determine which entry we're looking at in the page.
4542 * If it is free (there's a free bitmap at the start of the
4543 * dir), we should skip these 32 bytes.
4545 slotInPage = (entryInDir & 0x7e0) >> 5;
4546 if (!(pageHeaderp->freeBitmap[slotInPage>>3] &
4547 (1 << (slotInPage & 0x7)))) {
4548 /* this entry is free */
4549 numDirChunks = 1; /* only skip this guy */
4553 tp = bufferp->datap + entryInBuffer;
4554 dep = (cm_dirEntry_t *) tp; /* now points to AFS3 dir entry */
4556 /* while we're here, compute the next entry's location, too,
4557 * since we'll need it when writing out the cookie into the dir
4560 * XXXX Probably should do more sanity checking.
4562 numDirChunks = cm_NameEntries(dep->name, &onbytes);
4564 /* compute offset of cookie representing next entry */
4565 nextEntryCookie = curOffset.LowPart + (CM_DIR_CHUNKSIZE * numDirChunks);
4567 /* Need 8.3 name? */
4569 if (infoLevel == SMB_FIND_FILE_BOTH_DIRECTORY_INFO
4570 && dep->fid.vnode != 0
4571 && !cm_Is8Dot3(dep->name)) {
4572 cm_Gen8Dot3Name(dep, shortName, &shortNameEnd);
4576 osi_Log4(smb_logp, "T2 search dir vn %u uniq %u name %s (%s)",
4577 dep->fid.vnode, dep->fid.unique,
4578 osi_LogSaveString(smb_logp, dep->name),
4579 NeedShortName ? osi_LogSaveString(smb_logp, shortName) : "");
4581 /* When matching, we are using doing a case fold if we have a wildcard mask.
4582 * If we get a non-wildcard match, it's a lookup for a specific file.
4584 if (dep->fid.vnode != 0 &&
4585 (smb_V3MatchMask(dep->name, maskp, (starPattern? CM_FLAG_CASEFOLD : 0)) ||
4587 smb_V3MatchMask(shortName, maskp, CM_FLAG_CASEFOLD)))) {
4589 /* Eliminate entries that don't match requested attributes */
4590 if (smb_hideDotFiles && !(dsp->attribute & SMB_ATTR_HIDDEN) &&
4591 smb_IsDotFile(dep->name)) {
4592 osi_Log0(smb_logp, "T2 search dir skipping hidden");
4593 goto nextEntry; /* no hidden files */
4595 if (!(dsp->attribute & SMB_ATTR_DIRECTORY)) /* no directories */
4597 /* We have already done the cm_TryBulkStat above */
4598 fid.cell = scp->fid.cell;
4599 fid.volume = scp->fid.volume;
4600 fid.vnode = ntohl(dep->fid.vnode);
4601 fid.unique = ntohl(dep->fid.unique);
4602 fileType = cm_FindFileType(&fid);
4603 /*osi_Log2(smb_logp, "smb_ReceiveTran2SearchDir: file %s "
4604 "has filetype %d", dep->name,
4606 if (fileType == CM_SCACHETYPE_DIRECTORY ||
4607 fileType == CM_SCACHETYPE_DFSLINK ||
4608 fileType == CM_SCACHETYPE_INVALID)
4609 osi_Log0(smb_logp, "T2 search dir skipping directory or bad link");
4613 /* finally check if this name will fit */
4615 /* standard dir entry stuff */
4616 if (infoLevel < 0x101)
4617 ohbytes = 23; /* pre-NT */
4618 else if (infoLevel == SMB_FIND_FILE_NAMES_INFO)
4619 ohbytes = 12; /* NT names only */
4621 ohbytes = 64; /* NT */
4623 if (infoLevel == SMB_FIND_FILE_BOTH_DIRECTORY_INFO)
4624 ohbytes += 26; /* Short name & length */
4626 if (searchFlags & 4) {
4627 ohbytes += 4; /* if resume key required */
4630 if (infoLevel != SMB_INFO_STANDARD
4631 && infoLevel != SMB_FIND_FILE_DIRECTORY_INFO
4632 && infoLevel != SMB_FIND_FILE_NAMES_INFO)
4633 ohbytes += 4; /* EASIZE */
4635 /* add header to name & term. null */
4636 orbytes = onbytes + ohbytes + 1;
4638 /* now, we round up the record to a 4 byte alignment,
4639 * and we make sure that we have enough room here for
4640 * even the aligned version (so we don't have to worry
4641 * about an * overflow when we pad things out below).
4642 * That's the reason for the alignment arithmetic below.
4644 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO)
4645 align = (4 - (orbytes & 3)) & 3;
4648 if (orbytes + bytesInBuffer + align > maxReturnData) {
4649 osi_Log1(smb_logp, "T2 dir search exceed max return data %d",
4654 /* this is one of the entries to use: it is not deleted
4655 * and it matches the star pattern we're looking for.
4656 * Put out the name, preceded by its length.
4658 /* First zero everything else */
4659 memset(origOp, 0, ohbytes);
4661 if (infoLevel <= SMB_FIND_FILE_DIRECTORY_INFO)
4662 *(origOp + ohbytes - 1) = (unsigned char) onbytes;
4663 else if (infoLevel == SMB_FIND_FILE_NAMES_INFO)
4664 *((u_long *)(op + 8)) = onbytes;
4666 *((u_long *)(op + 60)) = onbytes;
4667 strcpy(origOp+ohbytes, dep->name);
4668 if (smb_StoreAnsiFilenames)
4669 CharToOem(origOp+ohbytes, origOp+ohbytes);
4671 /* Short name if requested and needed */
4672 if (infoLevel == SMB_FIND_FILE_BOTH_DIRECTORY_INFO) {
4673 if (NeedShortName) {
4674 strcpy(op + 70, shortName);
4675 if (smb_StoreAnsiFilenames)
4676 CharToOem(op + 70, op + 70);
4677 *(op + 68) = (char)(shortNameEnd - shortName);
4681 /* now, adjust the # of entries copied */
4684 /* NextEntryOffset and FileIndex */
4685 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO) {
4686 int entryOffset = orbytes + align;
4687 *((u_long *)op) = entryOffset;
4688 *((u_long *)(op+4)) = nextEntryCookie;
4691 /* now we emit the attribute. This is tricky, since
4692 * we need to really stat the file to find out what
4693 * type of entry we've got. Right now, we're copying
4694 * out data from a buffer, while holding the scp
4695 * locked, so it isn't really convenient to stat
4696 * something now. We'll put in a place holder
4697 * now, and make a second pass before returning this
4698 * to get the real attributes. So, we just skip the
4699 * data for now, and adjust it later. We allocate a
4700 * patch record to make it easy to find this point
4701 * later. The replay will happen at a time when it is
4702 * safe to unlock the directory.
4704 if (infoLevel != SMB_FIND_FILE_NAMES_INFO) {
4705 curPatchp = malloc(sizeof(*curPatchp));
4706 osi_QAdd((osi_queue_t **) &dirListPatchesp,
4708 curPatchp->dptr = op;
4709 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO)
4710 curPatchp->dptr += 8;
4712 if (smb_hideDotFiles && smb_IsDotFile(dep->name)) {
4713 curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
4716 curPatchp->flags = 0;
4718 curPatchp->fid.cell = scp->fid.cell;
4719 curPatchp->fid.volume = scp->fid.volume;
4720 curPatchp->fid.vnode = ntohl(dep->fid.vnode);
4721 curPatchp->fid.unique = ntohl(dep->fid.unique);
4724 curPatchp->dep = dep;
4727 if (searchFlags & 4)
4728 /* put out resume key */
4729 *((u_long *)origOp) = nextEntryCookie;
4731 /* Adjust byte ptr and count */
4732 origOp += orbytes; /* skip entire record */
4733 bytesInBuffer += orbytes;
4735 /* and pad the record out */
4736 while (--align >= 0) {
4740 } /* if we're including this name */
4741 else if (!starPattern &&
4743 dep->fid.vnode != 0 &&
4744 smb_V3MatchMask(dep->name, maskp, CM_FLAG_CASEFOLD)) {
4745 /* We were looking for exact matches, but here's an inexact one*/
4750 /* and adjust curOffset to be where the new cookie is */
4751 thyper.HighPart = 0;
4752 thyper.LowPart = CM_DIR_CHUNKSIZE * numDirChunks;
4753 curOffset = LargeIntegerAdd(thyper, curOffset);
4754 } /* while copying data for dir listing */
4756 /* If we didn't get a star pattern, we did an exact match during the first pass.
4757 * If there were no exact matches found, we fail over to inexact matches by
4758 * marking the query as a star pattern (matches all case permutations), and
4759 * re-running the query.
4761 if (returnedNames == 0 && !starPattern && foundInexact) {
4762 osi_Log0(afsd_logp,"T2 Search: No exact matches. Re-running for inexact matches");
4767 /* release the mutex */
4768 lock_ReleaseMutex(&scp->mx);
4770 buf_Release(bufferp);
4774 /* apply and free last set of patches; if not doing a star match, this
4775 * will be empty, but better safe (and freeing everything) than sorry.
4777 code2 = smb_ApplyV3DirListPatches(scp, &dirListPatchesp, infoLevel, userp,
4780 /* now put out the final parameters */
4781 if (returnedNames == 0)
4783 if (p->opcode == 1) {
4785 outp->parmsp[0] = (unsigned short) dsp->cookie;
4786 outp->parmsp[1] = returnedNames;
4787 outp->parmsp[2] = eos;
4788 outp->parmsp[3] = 0; /* nothing wrong with EAS */
4789 outp->parmsp[4] = 0;
4790 /* don't need last name to continue
4791 * search, cookie is enough. Normally,
4792 * this is the offset of the file name
4793 * of the last entry returned.
4795 outp->totalParms = 10; /* in bytes */
4799 outp->parmsp[0] = returnedNames;
4800 outp->parmsp[1] = eos;
4801 outp->parmsp[2] = 0; /* EAS error */
4802 outp->parmsp[3] = 0; /* last name, as above */
4803 outp->totalParms = 8; /* in bytes */
4806 /* return # of bytes in the buffer */
4807 outp->totalData = bytesInBuffer;
4809 /* Return error code if unsuccessful on first request */
4810 if (code == 0 && p->opcode == 1 && returnedNames == 0)
4811 code = CM_ERROR_NOSUCHFILE;
4813 osi_Log4(smb_logp, "T2 search dir done, opcode %d, id %d, %d names, code %d",
4814 p->opcode, dsp->cookie, returnedNames, code);
4816 /* if we're supposed to close the search after this request, or if
4817 * we're supposed to close the search if we're done, and we're done,
4818 * or if something went wrong, close the search.
4820 /* ((searchFlags & 1) || ((searchFlags & 2) && eos) */
4821 if ((searchFlags & 1) || (returnedNames == 0) ||
4822 ((searchFlags & 2) && eos) || code != 0)
4823 smb_DeleteDirSearch(dsp);
4825 smb_SendTran2Error(vcp, p, opx, code);
4827 smb_SendTran2Packet(vcp, outp, opx);
4829 smb_FreeTran2Packet(outp);
4830 smb_ReleaseDirSearch(dsp);
4831 cm_ReleaseSCache(scp);
4832 cm_ReleaseUser(userp);
4836 long smb_ReceiveV3FindClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4839 smb_dirSearch_t *dsp;
4841 dirHandle = smb_GetSMBParm(inp, 0);
4843 osi_Log1(smb_logp, "SMB3 find close handle %d", dirHandle);
4845 dsp = smb_FindDirSearch(dirHandle);
4848 return CM_ERROR_BADFD;
4850 /* otherwise, we have an FD to destroy */
4851 smb_DeleteDirSearch(dsp);
4852 smb_ReleaseDirSearch(dsp);
4854 /* and return results */
4855 smb_SetSMBDataLength(outp, 0);
4860 long smb_ReceiveV3FindNotifyClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4862 smb_SetSMBDataLength(outp, 0);
4866 long smb_ReceiveV3OpenX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4873 cm_scache_t *dscp; /* dir we're dealing with */
4874 cm_scache_t *scp; /* file we're creating */
4876 int initialModeBits;
4886 int parmSlot; /* which parm we're dealing with */
4895 extraInfo = (smb_GetSMBParm(inp, 2) & 1); /* return extra info */
4896 openFun = smb_GetSMBParm(inp, 8); /* open function */
4897 excl = ((openFun & 3) == 0);
4898 trunc = ((openFun & 3) == 2); /* truncate it */
4899 openMode = (smb_GetSMBParm(inp, 3) & 0x7);
4900 openAction = 0; /* tracks what we did */
4902 attributes = smb_GetSMBParm(inp, 5);
4903 dosTime = smb_GetSMBParm(inp, 6) | (smb_GetSMBParm(inp, 7) << 16);
4905 /* compute initial mode bits based on read-only flag in attributes */
4906 initialModeBits = 0666;
4907 if (attributes & SMB_ATTR_READONLY)
4908 initialModeBits &= ~0222;
4910 pathp = smb_GetSMBData(inp, NULL);
4911 if (smb_StoreAnsiFilenames)
4912 OemToChar(pathp,pathp);
4914 spacep = inp->spacep;
4915 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
4917 if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
4918 /* special case magic file name for receiving IOCTL requests
4919 * (since IOCTL calls themselves aren't getting through).
4922 osi_Log0(smb_logp, "IOCTL Open");
4925 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
4926 smb_SetupIoctlFid(fidp, spacep);
4928 /* set inp->fid so that later read calls in same msg can find fid */
4929 inp->fid = fidp->fid;
4931 /* copy out remainder of the parms */
4933 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
4935 smb_SetSMBParm(outp, parmSlot, /* attrs */ 0); parmSlot++;
4936 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* mod time */
4937 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
4938 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* len */
4939 smb_SetSMBParm(outp, parmSlot, 0x7fff); parmSlot++;
4940 smb_SetSMBParm(outp, parmSlot, openMode); parmSlot++;
4941 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* file type 0 ==> normal file or dir */
4942 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* IPC junk */
4944 /* and the final "always present" stuff */
4945 smb_SetSMBParm(outp, parmSlot, /* openAction found existing file */ 1); parmSlot++;
4946 /* next write out the "unique" ID */
4947 smb_SetSMBParm(outp, parmSlot, 0x1234); parmSlot++;
4948 smb_SetSMBParm(outp, parmSlot, 0x5678); parmSlot++;
4949 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
4950 smb_SetSMBDataLength(outp, 0);
4952 /* and clean up fid reference */
4953 smb_ReleaseFID(fidp);
4957 #ifdef DEBUG_VERBOSE
4959 char *hexp, *asciip;
4960 asciip = (lastNamep ? lastNamep : pathp );
4961 hexp = osi_HexifyString(asciip);
4962 DEBUG_EVENT2("AFS", "V3Open H[%s] A[%s]", hexp, asciip );
4966 userp = smb_GetUserFromVCP(vcp, inp);
4969 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4971 cm_ReleaseUser(userp);
4972 return CM_ERROR_NOSUCHPATH;
4974 code = cm_NameI(cm_data.rootSCachep, pathp,
4975 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
4976 userp, tidPathp, &req, &scp);
4979 if (code == 0 && scp->fileType == CM_SCACHETYPE_DFSLINK) {
4980 cm_ReleaseSCache(scp);
4981 cm_ReleaseUser(userp);
4982 if ( WANTS_DFS_PATHNAMES(inp) )
4983 return CM_ERROR_PATH_NOT_COVERED;
4985 return CM_ERROR_BADSHARENAME;
4987 #endif /* DFS_SUPPORT */
4990 code = cm_NameI(cm_data.rootSCachep, spacep->data,
4991 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
4992 userp, tidPathp, &req, &dscp);
4994 cm_ReleaseUser(userp);
4999 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
5000 cm_ReleaseSCache(dscp);
5001 cm_ReleaseUser(userp);
5002 if ( WANTS_DFS_PATHNAMES(inp) )
5003 return CM_ERROR_PATH_NOT_COVERED;
5005 return CM_ERROR_BADSHARENAME;
5007 #endif /* DFS_SUPPORT */
5008 /* otherwise, scp points to the parent directory. Do a lookup,
5009 * and truncate the file if we find it, otherwise we create the
5016 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD, userp,
5018 if (code && code != CM_ERROR_NOSUCHFILE) {
5019 cm_ReleaseSCache(dscp);
5020 cm_ReleaseUser(userp);
5025 /* if we get here, if code is 0, the file exists and is represented by
5026 * scp. Otherwise, we have to create it. The dir may be represented
5027 * by dscp, or we may have found the file directly. If code is non-zero,
5031 code = cm_CheckOpen(scp, openMode, trunc, userp, &req);
5033 if (dscp) cm_ReleaseSCache(dscp);
5034 cm_ReleaseSCache(scp);
5035 cm_ReleaseUser(userp);
5040 /* oops, file shouldn't be there */
5042 cm_ReleaseSCache(dscp);
5043 cm_ReleaseSCache(scp);
5044 cm_ReleaseUser(userp);
5045 return CM_ERROR_EXISTS;
5049 setAttr.mask = CM_ATTRMASK_LENGTH;
5050 setAttr.length.LowPart = 0;
5051 setAttr.length.HighPart = 0;
5052 code = cm_SetAttr(scp, &setAttr, userp, &req);
5053 openAction = 3; /* truncated existing file */
5055 else openAction = 1; /* found existing file */
5057 else if (!(openFun & SMB_ATTR_DIRECTORY)) {
5058 /* don't create if not found */
5059 if (dscp) cm_ReleaseSCache(dscp);
5060 cm_ReleaseUser(userp);
5061 return CM_ERROR_NOSUCHFILE;
5064 osi_assert(dscp != NULL);
5065 osi_Log1(smb_logp, "smb_ReceiveV3OpenX creating file %s",
5066 osi_LogSaveString(smb_logp, lastNamep));
5067 openAction = 2; /* created file */
5068 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
5069 smb_UnixTimeFromDosUTime(&setAttr.clientModTime, dosTime);
5070 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
5074 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
5075 smb_NotifyChange(FILE_ACTION_ADDED,
5076 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
5077 dscp, lastNamep, NULL, TRUE);
5078 } else if (!excl && code == CM_ERROR_EXISTS) {
5079 /* not an exclusive create, and someone else tried
5080 * creating it already, then we open it anyway. We
5081 * don't bother retrying after this, since if this next
5082 * fails, that means that the file was deleted after we
5083 * started this call.
5085 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
5089 setAttr.mask = CM_ATTRMASK_LENGTH;
5090 setAttr.length.LowPart = 0;
5091 setAttr.length.HighPart = 0;
5092 code = cm_SetAttr(scp, &setAttr, userp, &req);
5094 } /* lookup succeeded */
5098 /* we don't need this any longer */
5100 cm_ReleaseSCache(dscp);
5103 /* something went wrong creating or truncating the file */
5105 cm_ReleaseSCache(scp);
5106 cm_ReleaseUser(userp);
5110 /* make sure we're about to open a file */
5111 if (scp->fileType != CM_SCACHETYPE_FILE) {
5112 cm_ReleaseSCache(scp);
5113 cm_ReleaseUser(userp);
5114 return CM_ERROR_ISDIR;
5117 /* now all we have to do is open the file itself */
5118 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
5122 lock_ObtainMutex(&fidp->mx);
5123 /* save a pointer to the vnode */
5126 fidp->userp = userp;
5128 /* compute open mode */
5130 fidp->flags |= SMB_FID_OPENREAD;
5131 if (openMode == 1 || openMode == 2)
5132 fidp->flags |= SMB_FID_OPENWRITE;
5134 /* remember if the file was newly created */
5136 fidp->flags |= SMB_FID_CREATED;
5138 lock_ReleaseMutex(&fidp->mx);
5139 smb_ReleaseFID(fidp);
5141 cm_Open(scp, 0, userp);
5143 /* set inp->fid so that later read calls in same msg can find fid */
5144 inp->fid = fidp->fid;
5146 /* copy out remainder of the parms */
5148 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
5149 lock_ObtainMutex(&scp->mx);
5151 smb_SetSMBParm(outp, parmSlot, smb_Attributes(scp)); parmSlot++;
5152 smb_DosUTimeFromUnixTime(&dosTime, scp->clientModTime);
5153 smb_SetSMBParm(outp, parmSlot, dosTime & 0xffff); parmSlot++;
5154 smb_SetSMBParm(outp, parmSlot, (dosTime>>16) & 0xffff); parmSlot++;
5155 smb_SetSMBParm(outp, parmSlot, scp->length.LowPart & 0xffff); parmSlot++;
5156 smb_SetSMBParm(outp, parmSlot, (scp->length.LowPart >> 16) & 0xffff); parmSlot++;
5157 smb_SetSMBParm(outp, parmSlot, openMode); parmSlot++;
5158 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* file type 0 ==> normal file or dir */
5159 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* IPC junk */
5161 /* and the final "always present" stuff */
5162 smb_SetSMBParm(outp, parmSlot, openAction); parmSlot++;
5163 /* next write out the "unique" ID */
5164 smb_SetSMBParm(outp, parmSlot, scp->fid.vnode & 0xffff); parmSlot++;
5165 smb_SetSMBParm(outp, parmSlot, scp->fid.volume & 0xffff); parmSlot++;
5166 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
5167 lock_ReleaseMutex(&scp->mx);
5168 smb_SetSMBDataLength(outp, 0);
5170 osi_Log1(smb_logp, "SMB OpenX opening fid %d", fidp->fid);
5172 cm_ReleaseUser(userp);
5173 /* leave scp held since we put it in fidp->scp */
5177 static void smb_GetLockParams(unsigned char LockType,
5179 unsigned int * ppid,
5180 LARGE_INTEGER * pOffset,
5181 LARGE_INTEGER * pLength)
5183 if (LockType & LOCKING_ANDX_LARGE_FILES) {
5185 *ppid = *((USHORT *) *buf);
5186 pOffset->HighPart = *((LONG *)(*buf + 4));
5187 pOffset->LowPart = *((DWORD *)(*buf + 8));
5188 pLength->HighPart = *((LONG *)(*buf + 12));
5189 pLength->LowPart = *((DWORD *)(*buf + 16));
5193 /* Not Large Files */
5194 *ppid = *((USHORT *) *buf);
5195 pOffset->HighPart = 0;
5196 pOffset->LowPart = *((DWORD *)(*buf + 2));
5197 pLength->HighPart = 0;
5198 pLength->LowPart = *((DWORD *)(*buf + 6));
5203 long smb_ReceiveV3LockingX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5210 unsigned char LockType;
5211 unsigned short NumberOfUnlocks, NumberOfLocks;
5215 LARGE_INTEGER LOffset, LLength;
5216 smb_waitingLockRequest_t *wlRequest = NULL;
5217 cm_file_lock_t *lockp;
5225 fid = smb_GetSMBParm(inp, 2);
5226 fid = smb_ChainFID(fid, inp);
5228 fidp = smb_FindFID(vcp, fid, 0);
5230 return CM_ERROR_BADFD;
5232 lock_ObtainMutex(&fidp->mx);
5233 if (fidp->flags & SMB_FID_IOCTL) {
5234 osi_Log0(smb_logp, "smb_ReceiveV3Locking BadFD");
5235 lock_ReleaseMutex(&fidp->mx);
5236 smb_ReleaseFID(fidp);
5237 return CM_ERROR_BADFD;
5241 lock_ReleaseMutex(&fidp->mx);
5243 /* set inp->fid so that later read calls in same msg can find fid */
5246 userp = smb_GetUserFromVCP(vcp, inp);
5249 lock_ObtainMutex(&scp->mx);
5250 code = cm_SyncOp(scp, NULL, userp, &req, 0,
5251 CM_SCACHESYNC_NEEDCALLBACK
5252 | CM_SCACHESYNC_GETSTATUS
5253 | CM_SCACHESYNC_LOCK);
5255 osi_Log1(smb_logp, "smb_ReceiveV3Locking SyncOp failure code 0x%x", code);
5259 LockType = smb_GetSMBParm(inp, 3) & 0xff;
5260 Timeout = (smb_GetSMBParm(inp, 5) << 16) + smb_GetSMBParm(inp, 4);
5261 NumberOfUnlocks = smb_GetSMBParm(inp, 6);
5262 NumberOfLocks = smb_GetSMBParm(inp, 7);
5264 if ((LockType & LOCKING_ANDX_CANCEL_LOCK) ||
5265 (LockType & LOCKING_ANDX_CHANGE_LOCKTYPE)) {
5267 /* We don't support these requests. Apparently, we can safely
5268 not deal with them too. */
5269 osi_Log1(smb_logp, "smb_ReceiveV3Locking received unsupported request [%s]",
5270 ((LockType & LOCKING_ANDX_CANCEL_LOCK)?
5271 "LOCKING_ANDX_CANCEL_LOCK":
5272 "LOCKING_ANDX_CHANGE_LOCKTYPE"));
5273 /* No need to call osi_LogSaveString since these are string
5276 code = CM_ERROR_BADOP;
5281 op = smb_GetSMBData(inp, NULL);
5283 for (i=0; i<NumberOfUnlocks; i++) {
5284 smb_GetLockParams(LockType, &op, &pid, &LOffset, &LLength);
5286 key = cm_GenerateKey(vcp->vcID, pid, fidp->fid);
5288 code = cm_Unlock(scp, LockType, LOffset, LLength, key, userp, &req);
5296 for (i=0; i<NumberOfLocks; i++) {
5297 smb_GetLockParams(LockType, &op, &pid, &LOffset, &LLength);
5299 key = cm_GenerateKey(vcp->vcID, pid, fidp->fid);
5301 code = cm_Lock(scp, LockType, LOffset, LLength, key, (Timeout != 0),
5302 userp, &req, &lockp);
5304 if (code == CM_ERROR_WOULDBLOCK && Timeout != 0) {
5305 smb_waitingLock_t * wLock;
5307 /* Put on waiting list */
5308 if(wlRequest == NULL) {
5312 LARGE_INTEGER tOffset, tLength;
5314 wlRequest = malloc(sizeof(smb_waitingLockRequest_t));
5316 osi_assert(wlRequest != NULL);
5318 wlRequest->vcp = vcp;
5320 wlRequest->scp = scp;
5322 wlRequest->inp = smb_CopyPacket(inp);
5323 wlRequest->outp = smb_CopyPacket(outp);
5324 wlRequest->lockType = LockType;
5325 wlRequest->timeRemaining = Timeout;
5326 wlRequest->locks = NULL;
5328 /* The waiting lock request needs to have enough
5329 information to undo all the locks in the request.
5330 We do the following to store info about locks that
5331 have already been granted. Sure, we can get most
5332 of the info from the packet, but the packet doesn't
5333 hold the result of cm_Lock call. In practice we
5334 only receive packets with one or two locks, so we
5335 are only wasting a few bytes here and there and
5336 only for a limited period of time until the waiting
5337 lock times out or is freed. */
5339 for(opt = op_locks, j=i; j > 0; j--) {
5340 smb_GetLockParams(LockType, &opt, &pid, &tOffset, &tLength);
5342 tkey = cm_GenerateKey(vcp->vcID, pid, fidp->fid);
5344 wLock = malloc(sizeof(smb_waitingLock_t));
5346 osi_assert(wLock != NULL);
5349 wLock->LOffset = tOffset;
5350 wLock->LLength = tLength;
5351 wLock->lockp = NULL;
5352 wLock->state = SMB_WAITINGLOCKSTATE_DONE;
5353 osi_QAdd((osi_queue_t **) &wlRequest->locks,
5358 wLock = malloc(sizeof(smb_waitingLock_t));
5360 osi_assert(wLock != NULL);
5363 wLock->LOffset = LOffset;
5364 wLock->LLength = LLength;
5365 wLock->lockp = lockp;
5366 wLock->state = SMB_WAITINGLOCKSTATE_WAITING;
5367 osi_QAdd((osi_queue_t **) &wlRequest->locks,
5370 osi_Log1(smb_logp, "smb_ReceiveV3Locking WaitingLock created 0x%p",
5378 osi_Log1(smb_logp, "smb_ReceiveV3Locking cm_Lock failure code 0x%x", code);
5385 /* Since something went wrong with the lock number i, we now
5386 have to go ahead and release any locks acquired before the
5387 failure. All locks before lock number i (of which there
5388 are i of them) have either been successful or are waiting.
5389 Either case requires calling cm_Unlock(). */
5391 /* And purge the waiting lock */
5392 if(wlRequest != NULL) {
5393 smb_waitingLock_t * wl;
5394 smb_waitingLock_t * wlNext;
5397 for(wl = wlRequest->locks; wl; wl = wlNext) {
5399 wlNext = (smb_waitingLock_t *) osi_QNext(&wl->q);
5401 ul_code = cm_Unlock(scp, LockType, wl->LOffset, wl->LLength, wl->key, userp, &req);
5404 osi_Log1(smb_logp, "smb_ReceiveV3Locking cm_Unlock returns code %d", ul_code);
5406 osi_Log0(smb_logp, "smb_ReceiveV3Locking cm_Unlock successful");
5409 osi_QRemove((osi_queue_t **) &wlRequest->locks, &wl->q);
5414 smb_ReleaseVC(wlRequest->vcp);
5415 cm_ReleaseSCache(wlRequest->scp);
5416 smb_FreePacket(wlRequest->inp);
5417 smb_FreePacket(wlRequest->outp);
5426 if (wlRequest != NULL) {
5428 lock_ObtainWrite(&smb_globalLock);
5429 osi_QAdd((osi_queue_t **)&smb_allWaitingLocks,
5431 osi_Wakeup((LONG_PTR)&smb_allWaitingLocks);
5432 lock_ReleaseWrite(&smb_globalLock);
5434 /* don't send reply immediately */
5435 outp->flags |= SMB_PACKETFLAG_NOSEND;
5438 smb_SetSMBDataLength(outp, 0);
5442 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_LOCK);
5445 lock_ReleaseMutex(&scp->mx);
5446 cm_ReleaseSCache(scp);
5447 cm_ReleaseUser(userp);
5448 smb_ReleaseFID(fidp);
5453 long smb_ReceiveV3GetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5459 afs_uint32 searchTime;
5465 fid = smb_GetSMBParm(inp, 0);
5466 fid = smb_ChainFID(fid, inp);
5468 fidp = smb_FindFID(vcp, fid, 0);
5470 return CM_ERROR_BADFD;
5472 lock_ObtainMutex(&fidp->mx);
5473 if (fidp->flags & SMB_FID_IOCTL) {
5474 lock_ReleaseMutex(&fidp->mx);
5475 smb_ReleaseFID(fidp);
5476 return CM_ERROR_BADFD;
5480 lock_ReleaseMutex(&fidp->mx);
5482 userp = smb_GetUserFromVCP(vcp, inp);
5485 /* otherwise, stat the file */
5486 lock_ObtainMutex(&scp->mx);
5487 code = cm_SyncOp(scp, NULL, userp, &req, 0,
5488 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5492 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5494 /* decode times. We need a search time, but the response to this
5495 * call provides the date first, not the time, as returned in the
5496 * searchTime variable. So we take the high-order bits first.
5498 smb_SearchTimeFromUnixTime(&searchTime, scp->clientModTime);
5499 smb_SetSMBParm(outp, 0, (searchTime >> 16) & 0xffff); /* ctime */
5500 smb_SetSMBParm(outp, 1, searchTime & 0xffff);
5501 smb_SetSMBParm(outp, 2, (searchTime >> 16) & 0xffff); /* atime */
5502 smb_SetSMBParm(outp, 3, searchTime & 0xffff);
5503 smb_SetSMBParm(outp, 4, (searchTime >> 16) & 0xffff); /* mtime */
5504 smb_SetSMBParm(outp, 5, searchTime & 0xffff);
5506 /* now handle file size and allocation size */
5507 smb_SetSMBParm(outp, 6, scp->length.LowPart & 0xffff); /* file size */
5508 smb_SetSMBParm(outp, 7, (scp->length.LowPart >> 16) & 0xffff);
5509 smb_SetSMBParm(outp, 8, scp->length.LowPart & 0xffff); /* alloc size */
5510 smb_SetSMBParm(outp, 9, (scp->length.LowPart >> 16) & 0xffff);
5512 /* file attribute */
5513 smb_SetSMBParm(outp, 10, smb_Attributes(scp));
5515 /* and finalize stuff */
5516 smb_SetSMBDataLength(outp, 0);
5520 lock_ReleaseMutex(&scp->mx);
5521 cm_ReleaseSCache(scp);
5522 cm_ReleaseUser(userp);
5523 smb_ReleaseFID(fidp);
5527 long smb_ReceiveV3SetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5533 afs_uint32 searchTime;
5541 fid = smb_GetSMBParm(inp, 0);
5542 fid = smb_ChainFID(fid, inp);
5544 fidp = smb_FindFID(vcp, fid, 0);
5546 return CM_ERROR_BADFD;
5548 lock_ObtainMutex(&fidp->mx);
5549 if (fidp->flags & SMB_FID_IOCTL) {
5550 lock_ReleaseMutex(&fidp->mx);
5551 smb_ReleaseFID(fidp);
5552 return CM_ERROR_BADFD;
5556 lock_ReleaseMutex(&fidp->mx);
5558 userp = smb_GetUserFromVCP(vcp, inp);
5561 /* now prepare to call cm_setattr. This message only sets various times,
5562 * and AFS only implements mtime, and we'll set the mtime if that's
5563 * requested. The others we'll ignore.
5565 searchTime = smb_GetSMBParm(inp, 5) | (smb_GetSMBParm(inp, 6) << 16);
5567 if (searchTime != 0) {
5568 smb_UnixTimeFromSearchTime(&unixTime, searchTime);
5570 if ( unixTime != -1 ) {
5571 attrs.mask = CM_ATTRMASK_CLIENTMODTIME;
5572 attrs.clientModTime = unixTime;
5573 code = cm_SetAttr(scp, &attrs, userp, &req);
5575 osi_Log1(smb_logp, "SMB receive V3SetAttributes [fid=%ld]", fid);
5577 osi_Log1(smb_logp, "**smb_UnixTimeFromSearchTime failed searchTime=%ld", searchTime);
5583 cm_ReleaseSCache(scp);
5584 cm_ReleaseUser(userp);
5585 smb_ReleaseFID(fidp);
5589 long smb_ReceiveV3WriteX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5592 long count, written = 0, total_written = 0;
5599 int inDataBlockCount;
5601 fd = smb_GetSMBParm(inp, 2);
5602 count = smb_GetSMBParm(inp, 10);
5604 offset.HighPart = 0;
5605 offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
5607 if (*inp->wctp == 14) {
5608 /* we have a request with 64-bit file offsets */
5609 #ifdef AFS_LARGEFILES
5610 offset.HighPart = smb_GetSMBParm(inp, 12) | (smb_GetSMBParm(inp, 13) << 16);
5612 if ((smb_GetSMBParm(inp, 12) | (smb_GetSMBParm(inp, 13) << 16)) != 0) {
5614 osi_Log0(smb_logp, "smb_ReceiveV3WriteX offset requires largefile support");
5615 /* we shouldn't have received this op if we didn't specify
5616 largefile support */
5617 return CM_ERROR_BADOP;
5622 op = inp->data + smb_GetSMBParm(inp, 11);
5623 inDataBlockCount = count;
5625 osi_Log4(smb_logp, "smb_ReceiveV3WriteX fid %d, off 0x%x:%08x, size 0x%x",
5626 fd, offset.HighPart, offset.LowPart, count);
5628 fd = smb_ChainFID(fd, inp);
5629 fidp = smb_FindFID(vcp, fd, 0);
5631 return CM_ERROR_BADFD;
5633 lock_ObtainMutex(&fidp->mx);
5634 if (fidp->flags & SMB_FID_IOCTL) {
5635 lock_ReleaseMutex(&fidp->mx);
5636 code = smb_IoctlV3Write(fidp, vcp, inp, outp);
5637 smb_ReleaseFID(fidp);
5640 lock_ReleaseMutex(&fidp->mx);
5641 userp = smb_GetUserFromVCP(vcp, inp);
5643 /* special case: 0 bytes transferred means there is no data
5644 transferred. A slight departure from SMB_COM_WRITE where this
5645 means that we are supposed to truncate the file at this
5650 LARGE_INTEGER LOffset;
5651 LARGE_INTEGER LLength;
5653 pid = ((smb_t *) inp)->pid;
5654 key = cm_GenerateKey(vcp->vcID, pid, fd);
5656 LOffset.HighPart = offset.HighPart;
5657 LOffset.LowPart = offset.LowPart;
5658 LLength.HighPart = 0;
5659 LLength.LowPart = count;
5661 lock_ObtainMutex(&fidp->scp->mx);
5662 code = cm_LockCheckWrite(fidp->scp, LOffset, LLength, key);
5663 lock_ReleaseMutex(&fidp->scp->mx);
5670 * Work around bug in NT client
5672 * When copying a file, the NT client should first copy the data,
5673 * then copy the last write time. But sometimes the NT client does
5674 * these in the wrong order, so the data copies would inadvertently
5675 * cause the last write time to be overwritten. We try to detect this,
5676 * and don't set client mod time if we think that would go against the
5679 lock_ObtainMutex(&fidp->mx);
5680 if ((fidp->flags & SMB_FID_MTIMESETDONE) != SMB_FID_MTIMESETDONE) {
5681 fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
5682 fidp->scp->clientModTime = time(NULL);
5684 lock_ReleaseMutex(&fidp->mx);
5687 while ( code == 0 && count > 0 ) {
5688 code = smb_WriteData(fidp, &offset, count, op, userp, &written);
5689 if (code == 0 && written == 0)
5690 code = CM_ERROR_PARTIALWRITE;
5692 offset = LargeIntegerAdd(offset,
5693 ConvertLongToLargeInteger(written));
5695 total_written += written;
5701 /* slots 0 and 1 are reserved for request chaining and will be
5702 filled in when we return. */
5703 smb_SetSMBParm(outp, 2, total_written);
5704 smb_SetSMBParm(outp, 3, 0); /* reserved */
5705 smb_SetSMBParm(outp, 4, 0); /* reserved */
5706 smb_SetSMBParm(outp, 5, 0); /* reserved */
5707 smb_SetSMBDataLength(outp, 0);
5710 smb_ReleaseFID(fidp);
5711 cm_ReleaseUser(userp);
5716 long smb_ReceiveV3ReadX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5720 long finalCount = 0;
5729 fd = smb_GetSMBParm(inp, 2);
5730 count = smb_GetSMBParm(inp, 5);
5731 offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
5733 if (*inp->wctp == 12) {
5734 /* a request with 64-bit offsets */
5735 #ifdef AFS_LARGEFILES
5736 offset.HighPart = smb_GetSMBParm(inp, 10) | (smb_GetSMBParm(inp, 11) << 16);
5738 if (LargeIntegerLessThanZero(offset)) {
5739 osi_Log2(smb_logp, "smb_ReceiveV3Read offset too large (0x%x:%08x)",
5740 offset.HighPart, offset.LowPart);
5741 return CM_ERROR_BADSMB;
5744 if ((smb_GetSMBParm(inp, 10) | (smb_GetSMBParm(inp, 11) << 16)) != 0) {
5745 osi_Log0(smb_logp, "smb_ReceiveV3Read offset is 64-bit. Dropping");
5746 return CM_ERROR_BADSMB;
5748 offset.HighPart = 0;
5752 offset.HighPart = 0;
5755 osi_Log4(smb_logp, "smb_ReceiveV3Read fd %d, off 0x%x:%08x, size 0x%x",
5756 fd, offset.HighPart, offset.LowPart, count);
5758 fd = smb_ChainFID(fd, inp);
5759 fidp = smb_FindFID(vcp, fd, 0);
5761 return CM_ERROR_BADFD;
5764 pid = ((smb_t *) inp)->pid;
5765 key = cm_GenerateKey(vcp->vcID, pid, fd);
5767 LARGE_INTEGER LOffset, LLength;
5769 LOffset.HighPart = offset.HighPart;
5770 LOffset.LowPart = offset.LowPart;
5771 LLength.HighPart = 0;
5772 LLength.LowPart = count;
5774 lock_ObtainMutex(&fidp->scp->mx);
5775 code = cm_LockCheckRead(fidp->scp, LOffset, LLength, key);
5776 lock_ReleaseMutex(&fidp->scp->mx);
5780 smb_ReleaseFID(fidp);
5784 /* set inp->fid so that later read calls in same msg can find fid */
5787 lock_ObtainMutex(&fidp->mx);
5788 if (fidp->flags & SMB_FID_IOCTL) {
5789 lock_ReleaseMutex(&fidp->mx);
5790 code = smb_IoctlV3Read(fidp, vcp, inp, outp);
5791 smb_ReleaseFID(fidp);
5794 lock_ReleaseMutex(&fidp->mx);
5796 userp = smb_GetUserFromVCP(vcp, inp);
5798 /* 0 and 1 are reserved for request chaining, were setup by our caller,
5799 * and will be further filled in after we return.
5801 smb_SetSMBParm(outp, 2, 0); /* remaining bytes, for pipes */
5802 smb_SetSMBParm(outp, 3, 0); /* resvd */
5803 smb_SetSMBParm(outp, 4, 0); /* resvd */
5804 smb_SetSMBParm(outp, 5, count); /* # of bytes we're going to read */
5805 /* fill in #6 when we have all the parameters' space reserved */
5806 smb_SetSMBParm(outp, 7, 0); /* resv'd */
5807 smb_SetSMBParm(outp, 8, 0); /* resv'd */
5808 smb_SetSMBParm(outp, 9, 0); /* resv'd */
5809 smb_SetSMBParm(outp, 10, 0); /* resv'd */
5810 smb_SetSMBParm(outp, 11, 0); /* reserved */
5812 /* get op ptr after putting in the parms, since otherwise we don't
5813 * know where the data really is.
5815 op = smb_GetSMBData(outp, NULL);
5817 /* now fill in offset from start of SMB header to first data byte (to op) */
5818 smb_SetSMBParm(outp, 6, ((int) (op - outp->data)));
5820 /* set the packet data length the count of the # of bytes */
5821 smb_SetSMBDataLength(outp, count);
5823 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount);
5825 /* fix some things up */
5826 smb_SetSMBParm(outp, 5, finalCount);
5827 smb_SetSMBDataLength(outp, finalCount);
5829 smb_ReleaseFID(fidp);
5831 cm_ReleaseUser(userp);
5836 * Values for createDisp, copied from NTDDK.H
5838 #define FILE_SUPERSEDE 0 // (???)
5839 #define FILE_OPEN 1 // (open)
5840 #define FILE_CREATE 2 // (exclusive)
5841 #define FILE_OPEN_IF 3 // (non-exclusive)
5842 #define FILE_OVERWRITE 4 // (open & truncate, but do not create)
5843 #define FILE_OVERWRITE_IF 5 // (open & truncate, or create)
5846 #define REQUEST_OPLOCK 2
5847 #define REQUEST_BATCH_OPLOCK 4
5848 #define OPEN_DIRECTORY 8
5849 #define EXTENDED_RESPONSE_REQUIRED 0x10
5851 /* CreateOptions field. */
5852 #define FILE_DIRECTORY_FILE 0x0001
5853 #define FILE_WRITE_THROUGH 0x0002
5854 #define FILE_SEQUENTIAL_ONLY 0x0004
5855 #define FILE_NON_DIRECTORY_FILE 0x0040
5856 #define FILE_NO_EA_KNOWLEDGE 0x0200
5857 #define FILE_EIGHT_DOT_THREE_ONLY 0x0400
5858 #define FILE_RANDOM_ACCESS 0x0800
5859 #define FILE_DELETE_ON_CLOSE 0x1000
5860 #define FILE_OPEN_BY_FILE_ID 0x2000
5862 long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5864 char *pathp, *realPathp;
5868 cm_scache_t *dscp; /* parent dir */
5869 cm_scache_t *scp; /* file to create or open */
5870 cm_scache_t *targetScp; /* if scp is a symlink */
5874 unsigned short nameLength;
5876 unsigned int requestOpLock;
5877 unsigned int requestBatchOpLock;
5878 unsigned int mustBeDir;
5879 unsigned int extendedRespRequired;
5880 unsigned int treeCreate;
5882 unsigned int desiredAccess;
5883 unsigned int extAttributes;
5884 unsigned int createDisp;
5885 unsigned int createOptions;
5886 unsigned int shareAccess;
5887 int initialModeBits;
5888 unsigned short baseFid;
5889 smb_fid_t *baseFidp;
5891 cm_scache_t *baseDirp;
5892 unsigned short openAction;
5904 /* This code is very long and has a lot of if-then-else clauses
5905 * scp and dscp get reused frequently and we need to ensure that
5906 * we don't lose a reference. Start by ensuring that they are NULL.
5913 nameLength = smb_GetSMBOffsetParm(inp, 2, 1);
5914 flags = smb_GetSMBOffsetParm(inp, 3, 1)
5915 | (smb_GetSMBOffsetParm(inp, 4, 1) << 16);
5916 requestOpLock = flags & REQUEST_OPLOCK;
5917 requestBatchOpLock = flags & REQUEST_BATCH_OPLOCK;
5918 mustBeDir = flags & OPEN_DIRECTORY;
5919 extendedRespRequired = flags & EXTENDED_RESPONSE_REQUIRED;
5922 * Why all of a sudden 32-bit FID?
5923 * We will reject all bits higher than 16.
5925 if (smb_GetSMBOffsetParm(inp, 6, 1) != 0)
5926 return CM_ERROR_INVAL;
5927 baseFid = smb_GetSMBOffsetParm(inp, 5, 1);
5928 desiredAccess = smb_GetSMBOffsetParm(inp, 7, 1)
5929 | (smb_GetSMBOffsetParm(inp, 8, 1) << 16);
5930 extAttributes = smb_GetSMBOffsetParm(inp, 13, 1)
5931 | (smb_GetSMBOffsetParm(inp, 14, 1) << 16);
5932 shareAccess = smb_GetSMBOffsetParm(inp, 15, 1)
5933 | (smb_GetSMBOffsetParm(inp, 16, 1) << 16);
5934 createDisp = smb_GetSMBOffsetParm(inp, 17, 1)
5935 | (smb_GetSMBOffsetParm(inp, 18, 1) << 16);
5936 createOptions = smb_GetSMBOffsetParm(inp, 19, 1)
5937 | (smb_GetSMBOffsetParm(inp, 20, 1) << 16);
5939 /* mustBeDir is never set; createOptions directory bit seems to be
5942 if (createOptions & FILE_DIRECTORY_FILE)
5944 else if (createOptions & FILE_NON_DIRECTORY_FILE)
5950 * compute initial mode bits based on read-only flag in
5951 * extended attributes
5953 initialModeBits = 0666;
5954 if (extAttributes & SMB_ATTR_READONLY)
5955 initialModeBits &= ~0222;
5957 pathp = smb_GetSMBData(inp, NULL);
5958 /* Sometimes path is not null-terminated, so we make a copy. */
5959 realPathp = malloc(nameLength+1);
5960 memcpy(realPathp, pathp, nameLength);
5961 realPathp[nameLength] = 0;
5962 if (smb_StoreAnsiFilenames)
5963 OemToChar(realPathp,realPathp);
5965 spacep = inp->spacep;
5966 smb_StripLastComponent(spacep->data, &lastNamep, realPathp);
5968 osi_Log1(smb_logp,"NTCreateX for [%s]",osi_LogSaveString(smb_logp,realPathp));
5969 osi_Log4(smb_logp,"... da=[%x] ea=[%x] cd=[%x] co=[%x]", desiredAccess, extAttributes, createDisp, createOptions);
5970 osi_Log3(smb_logp,"... share=[%x] flags=[%x] lastNamep=[%s]", shareAccess, flags, osi_LogSaveString(smb_logp,(lastNamep?lastNamep:"null")));
5972 if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
5973 /* special case magic file name for receiving IOCTL requests
5974 * (since IOCTL calls themselves aren't getting through).
5976 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
5977 smb_SetupIoctlFid(fidp, spacep);
5978 osi_Log1(smb_logp,"NTCreateX Setting up IOCTL on fid[%d]",fidp->fid);
5980 /* set inp->fid so that later read calls in same msg can find fid */
5981 inp->fid = fidp->fid;
5985 smb_SetSMBParmByte(outp, parmSlot, 0); /* oplock */
5986 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
5987 smb_SetSMBParmLong(outp, parmSlot, 1); parmSlot += 2; /* Action */
5989 memset(&ft, 0, sizeof(ft));
5990 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
5991 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
5992 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
5993 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
5994 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2; /* attr */
5995 sz.HighPart = 0x7fff; sz.LowPart = 0;
5996 smb_SetSMBParmDouble(outp, parmSlot, (char *)&sz); parmSlot += 4; /* alen */
5997 smb_SetSMBParmDouble(outp, parmSlot, (char *)&sz); parmSlot += 4; /* len */
5998 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* filetype */
5999 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* dev state */
6000 smb_SetSMBParmByte(outp, parmSlot, 0); /* is a dir? */
6001 smb_SetSMBDataLength(outp, 0);
6003 /* clean up fid reference */
6004 smb_ReleaseFID(fidp);
6009 #ifdef DEBUG_VERBOSE
6011 char *hexp, *asciip;
6012 asciip = (lastNamep? lastNamep : realPathp);
6013 hexp = osi_HexifyString( asciip );
6014 DEBUG_EVENT2("AFS", "NTCreateX H[%s] A[%s]", hexp, asciip);
6019 userp = smb_GetUserFromVCP(vcp, inp);
6021 osi_Log1(smb_logp, "NTCreateX Invalid user [%d]", ((smb_t *) inp)->uid);
6023 return CM_ERROR_INVAL;
6028 baseDirp = cm_data.rootSCachep;
6029 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
6030 if (code == CM_ERROR_TIDIPC) {
6031 /* Attempt to use a TID allocated for IPC. The client
6032 * is probably looking for DCE RPC end points which we
6033 * don't support OR it could be looking to make a DFS
6036 osi_Log0(smb_logp, "NTCreateX received IPC TID");
6039 cm_ReleaseUser(userp);
6040 return CM_ERROR_NOSUCHFILE;
6041 #endif /* DFS_SUPPORT */
6044 baseFidp = smb_FindFID(vcp, baseFid, 0);
6046 osi_Log1(smb_logp, "NTCreateX Invalid base fid [%d]", baseFid);
6048 cm_ReleaseUser(userp);
6049 return CM_ERROR_INVAL;
6051 baseDirp = baseFidp->scp;
6055 osi_Log1(smb_logp, "NTCreateX tidPathp=[%s]", (tidPathp==NULL)?"null": osi_LogSaveString(smb_logp,tidPathp));
6057 /* compute open mode */
6059 if (desiredAccess & DELETE)
6060 fidflags |= SMB_FID_OPENDELETE;
6061 if (desiredAccess & AFS_ACCESS_READ)
6062 fidflags |= SMB_FID_OPENREAD;
6063 if (desiredAccess & AFS_ACCESS_WRITE)
6064 fidflags |= SMB_FID_OPENWRITE;
6065 if (createOptions & FILE_DELETE_ON_CLOSE)
6066 fidflags |= SMB_FID_DELONCLOSE;
6067 if (createOptions & FILE_SEQUENTIAL_ONLY && !(createOptions & FILE_RANDOM_ACCESS))
6068 fidflags |= SMB_FID_SEQUENTIAL;
6069 if (createOptions & FILE_RANDOM_ACCESS && !(createOptions & FILE_SEQUENTIAL_ONLY))
6070 fidflags |= SMB_FID_RANDOM;
6072 /* and the share mode */
6073 if (shareAccess & FILE_SHARE_READ)
6074 fidflags |= SMB_FID_SHARE_READ;
6075 if (shareAccess & FILE_SHARE_WRITE)
6076 fidflags |= SMB_FID_SHARE_WRITE;
6078 osi_Log1(smb_logp, "NTCreateX fidflags 0x%x", fidflags);
6081 /* For an exclusive create, we want to do a case sensitive match for the last component. */
6082 if ( createDisp == FILE_CREATE ||
6083 createDisp == FILE_OVERWRITE ||
6084 createDisp == FILE_OVERWRITE_IF) {
6085 code = cm_NameI(baseDirp, spacep->data, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
6086 userp, tidPathp, &req, &dscp);
6089 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
6090 cm_ReleaseSCache(dscp);
6091 cm_ReleaseUser(userp);
6094 smb_ReleaseFID(baseFidp);
6095 if ( WANTS_DFS_PATHNAMES(inp) )
6096 return CM_ERROR_PATH_NOT_COVERED;
6098 return CM_ERROR_BADSHARENAME;
6100 #endif /* DFS_SUPPORT */
6101 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp, CM_FLAG_FOLLOW,
6103 if (code == CM_ERROR_NOSUCHFILE) {
6104 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp,
6105 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, &req, &scp);
6106 if (code == 0 && realDirFlag == 1) {
6107 cm_ReleaseSCache(scp);
6108 cm_ReleaseSCache(dscp);
6109 cm_ReleaseUser(userp);
6112 smb_ReleaseFID(baseFidp);
6113 return CM_ERROR_EXISTS;
6117 /* we have both scp and dscp */
6119 code = cm_NameI(baseDirp, realPathp, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
6120 userp, tidPathp, &req, &scp);
6122 if (code == 0 && scp->fileType == CM_SCACHETYPE_DFSLINK) {
6123 cm_ReleaseSCache(scp);
6124 cm_ReleaseUser(userp);
6127 smb_ReleaseFID(baseFidp);
6128 if ( WANTS_DFS_PATHNAMES(inp) )
6129 return CM_ERROR_PATH_NOT_COVERED;
6131 return CM_ERROR_BADSHARENAME;
6133 #endif /* DFS_SUPPORT */
6134 /* we might have scp but not dscp */
6140 if (!foundscp || (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE))) {
6141 /* look up parent directory */
6142 /* If we are trying to create a path (i.e. multiple nested directories), then we don't *need*
6143 * the immediate parent. We have to work our way up realPathp until we hit something that we
6147 /* we might or might not have scp */
6153 code = cm_NameI(baseDirp, spacep->data,
6154 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
6155 userp, tidPathp, &req, &dscp);
6158 if (code == 0 && dscp->fileType == CM_SCACHETYPE_DFSLINK) {
6160 cm_ReleaseSCache(scp);
6161 cm_ReleaseSCache(dscp);
6162 cm_ReleaseUser(userp);
6165 smb_ReleaseFID(baseFidp);
6166 if ( WANTS_DFS_PATHNAMES(inp) )
6167 return CM_ERROR_PATH_NOT_COVERED;
6169 return CM_ERROR_BADSHARENAME;
6171 #endif /* DFS_SUPPORT */
6174 (tp = strrchr(spacep->data,'\\')) &&
6175 (createDisp == FILE_CREATE) &&
6176 (realDirFlag == 1)) {
6179 treeStartp = realPathp + (tp - spacep->data);
6181 if (*tp && !smb_IsLegalFilename(tp)) {
6183 smb_ReleaseFID(baseFidp);
6184 cm_ReleaseUser(userp);
6187 cm_ReleaseSCache(scp);
6188 return CM_ERROR_BADNTFILENAME;
6192 } while (dscp == NULL && code == 0);
6196 /* we might have scp and we might have dscp */
6199 smb_ReleaseFID(baseFidp);
6202 osi_Log0(smb_logp,"NTCreateX parent not found");
6204 cm_ReleaseSCache(scp);
6206 cm_ReleaseSCache(dscp);
6207 cm_ReleaseUser(userp);
6212 if (treeCreate && dscp->fileType == CM_SCACHETYPE_FILE) {
6213 /* A file exists where we want a directory. */
6215 cm_ReleaseSCache(scp);
6216 cm_ReleaseSCache(dscp);
6217 cm_ReleaseUser(userp);
6219 return CM_ERROR_EXISTS;
6223 lastNamep = realPathp;
6227 if (!smb_IsLegalFilename(lastNamep)) {
6229 cm_ReleaseSCache(scp);
6231 cm_ReleaseSCache(dscp);
6232 cm_ReleaseUser(userp);
6234 return CM_ERROR_BADNTFILENAME;
6237 if (!foundscp && !treeCreate) {
6238 if ( createDisp == FILE_CREATE ||
6239 createDisp == FILE_OVERWRITE ||
6240 createDisp == FILE_OVERWRITE_IF)
6242 code = cm_Lookup(dscp, lastNamep,
6243 CM_FLAG_FOLLOW, userp, &req, &scp);
6245 code = cm_Lookup(dscp, lastNamep,
6246 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
6249 if (code && code != CM_ERROR_NOSUCHFILE) {
6251 cm_ReleaseSCache(dscp);
6252 cm_ReleaseUser(userp);
6257 /* we have scp and dscp */
6259 /* we have scp but not dscp */
6261 smb_ReleaseFID(baseFidp);
6264 /* if we get here, if code is 0, the file exists and is represented by
6265 * scp. Otherwise, we have to create it. The dir may be represented
6266 * by dscp, or we may have found the file directly. If code is non-zero,
6269 if (code == 0 && !treeCreate) {
6270 code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp, &req);
6273 cm_ReleaseSCache(dscp);
6275 cm_ReleaseSCache(scp);
6276 cm_ReleaseUser(userp);
6281 if (createDisp == FILE_CREATE) {
6282 /* oops, file shouldn't be there */
6284 cm_ReleaseSCache(dscp);
6286 cm_ReleaseSCache(scp);
6287 cm_ReleaseUser(userp);
6289 return CM_ERROR_EXISTS;
6292 if ( createDisp == FILE_OVERWRITE ||
6293 createDisp == FILE_OVERWRITE_IF) {
6295 setAttr.mask = CM_ATTRMASK_LENGTH;
6296 setAttr.length.LowPart = 0;
6297 setAttr.length.HighPart = 0;
6298 /* now watch for a symlink */
6300 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
6302 osi_assert(dscp != NULL);
6303 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
6305 /* we have a more accurate file to use (the
6306 * target of the symbolic link). Otherwise,
6307 * we'll just use the symlink anyway.
6309 osi_Log2(smb_logp, "symlink vp %x to vp %x",
6311 cm_ReleaseSCache(scp);
6315 code = cm_SetAttr(scp, &setAttr, userp, &req);
6316 openAction = 3; /* truncated existing file */
6319 openAction = 1; /* found existing file */
6321 } else if (createDisp == FILE_OPEN || createDisp == FILE_OVERWRITE) {
6322 /* don't create if not found */
6324 cm_ReleaseSCache(dscp);
6326 cm_ReleaseSCache(scp);
6327 cm_ReleaseUser(userp);
6329 return CM_ERROR_NOSUCHFILE;
6330 } else if (realDirFlag == 0 || realDirFlag == -1) {
6331 osi_assert(dscp != NULL);
6332 osi_Log1(smb_logp, "smb_ReceiveNTCreateX creating file %s",
6333 osi_LogSaveString(smb_logp, lastNamep));
6334 openAction = 2; /* created file */
6335 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
6336 setAttr.clientModTime = time(NULL);
6337 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp, &req);
6340 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
6341 smb_NotifyChange(FILE_ACTION_ADDED,
6342 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
6343 dscp, lastNamep, NULL, TRUE);
6344 } else if (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE) {
6345 /* Not an exclusive create, and someone else tried
6346 * creating it already, then we open it anyway. We
6347 * don't bother retrying after this, since if this next
6348 * fails, that means that the file was deleted after we
6349 * started this call.
6351 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
6354 if (createDisp == FILE_OVERWRITE_IF) {
6355 setAttr.mask = CM_ATTRMASK_LENGTH;
6356 setAttr.length.LowPart = 0;
6357 setAttr.length.HighPart = 0;
6359 /* now watch for a symlink */
6361 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
6363 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
6365 /* we have a more accurate file to use (the
6366 * target of the symbolic link). Otherwise,
6367 * we'll just use the symlink anyway.
6369 osi_Log2(smb_logp, "symlink vp %x to vp %x",
6371 cm_ReleaseSCache(scp);
6375 code = cm_SetAttr(scp, &setAttr, userp, &req);
6377 } /* lookup succeeded */
6381 char *cp; /* This component */
6382 int clen = 0; /* length of component */
6383 cm_scache_t *tscp1, *tscp2;
6386 /* create directory */
6388 treeStartp = lastNamep;
6389 osi_assert(dscp != NULL);
6390 osi_Log1(smb_logp, "smb_ReceiveNTCreateX creating directory [%s]",
6391 osi_LogSaveString(smb_logp, treeStartp));
6392 openAction = 2; /* created directory */
6394 /* if the request is to create the root directory
6395 * it will appear as a directory name of the nul-string
6396 * and a code of CM_ERROR_NOSUCHFILE
6398 if ( !*treeStartp && code == CM_ERROR_NOSUCHFILE)
6399 code = CM_ERROR_EXISTS;
6401 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
6402 setAttr.clientModTime = time(NULL);
6407 cm_HoldSCache(tscp1);
6411 tp = strchr(pp, '\\');
6414 clen = (int)strlen(cp);
6415 isLast = 1; /* indicate last component. the supplied path never ends in a slash */
6417 clen = (int)(tp - pp);
6418 strncpy(cp,pp,clen);
6425 continue; /* the supplied path can't have consecutive slashes either , but */
6427 /* cp is the next component to be created. */
6428 code = cm_MakeDir(tscp1, cp, 0, &setAttr, userp, &req);
6429 if (code == 0 && (tscp1->flags & CM_SCACHEFLAG_ANYWATCH))
6430 smb_NotifyChange(FILE_ACTION_ADDED,
6431 FILE_NOTIFY_CHANGE_DIR_NAME,
6432 tscp1, cp, NULL, TRUE);
6434 (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE)) {
6435 /* Not an exclusive create, and someone else tried
6436 * creating it already, then we open it anyway. We
6437 * don't bother retrying after this, since if this next
6438 * fails, that means that the file was deleted after we
6439 * started this call.
6441 code = cm_Lookup(tscp1, cp, CM_FLAG_CASEFOLD,
6442 userp, &req, &tscp2);
6447 if (!isLast) { /* for anything other than dscp, release it unless it's the last one */
6448 cm_ReleaseSCache(tscp1);
6449 tscp1 = tscp2; /* Newly created directory will be next parent */
6450 /* the hold is transfered to tscp1 from tscp2 */
6455 cm_ReleaseSCache(dscp);
6458 cm_ReleaseSCache(scp);
6461 * if we get here and code == 0, then scp is the last directory created, and dscp is the
6467 /* something went wrong creating or truncating the file */
6469 cm_ReleaseSCache(scp);
6471 cm_ReleaseSCache(dscp);
6472 cm_ReleaseUser(userp);
6477 /* make sure we have file vs. dir right (only applies for single component case) */
6478 if (realDirFlag == 0 && scp->fileType != CM_SCACHETYPE_FILE) {
6479 /* now watch for a symlink */
6481 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
6482 cm_scache_t * targetScp = 0;
6483 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
6485 /* we have a more accurate file to use (the
6486 * target of the symbolic link). Otherwise,
6487 * we'll just use the symlink anyway.
6489 osi_Log2(smb_logp, "symlink vp %x to vp %x", scp, targetScp);
6490 cm_ReleaseSCache(scp);
6495 if (scp->fileType != CM_SCACHETYPE_FILE) {
6497 cm_ReleaseSCache(dscp);
6498 cm_ReleaseSCache(scp);
6499 cm_ReleaseUser(userp);
6501 return CM_ERROR_ISDIR;
6505 /* (only applies to single component case) */
6506 if (realDirFlag == 1 && scp->fileType == CM_SCACHETYPE_FILE) {
6507 cm_ReleaseSCache(scp);
6509 cm_ReleaseSCache(dscp);
6510 cm_ReleaseUser(userp);
6512 return CM_ERROR_NOTDIR;
6515 /* open the file itself */
6516 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
6519 /* save a reference to the user */
6521 fidp->userp = userp;
6523 /* If we are restricting sharing, we should do so with a suitable
6525 if (scp->fileType == CM_SCACHETYPE_FILE &&
6526 !(fidflags & SMB_FID_SHARE_WRITE)) {
6528 LARGE_INTEGER LOffset, LLength;
6531 LOffset.HighPart = SMB_FID_QLOCK_HIGH;
6532 LOffset.LowPart = SMB_FID_QLOCK_LOW;
6533 LLength.HighPart = 0;
6534 LLength.LowPart = SMB_FID_QLOCK_LENGTH;
6536 if (fidflags & SMB_FID_SHARE_READ) {
6537 sLockType = LOCKING_ANDX_SHARED_LOCK;
6542 key = cm_GenerateKey(vcp->vcID, SMB_FID_QLOCK_PID, fidp->fid);
6544 lock_ObtainMutex(&scp->mx);
6545 code = cm_Lock(scp, sLockType, LOffset, LLength, key, 0, userp, &req, NULL);
6546 lock_ReleaseMutex(&scp->mx);
6549 /* shouldn't this be smb_CloseFID() fidp->flags = SMB_FID_DELETE; */
6550 smb_CloseFID(vcp, fidp, NULL, 0);
6551 smb_ReleaseFID(fidp);
6553 cm_ReleaseSCache(scp);
6555 cm_ReleaseSCache(dscp);
6556 cm_ReleaseUser(userp);
6563 lock_ObtainMutex(&fidp->mx);
6564 /* save a pointer to the vnode */
6565 fidp->scp = scp; /* Hold transfered to fidp->scp and no longer needed */
6567 fidp->flags = fidflags;
6569 /* remember if the file was newly created */
6571 fidp->flags |= SMB_FID_CREATED;
6573 /* save parent dir and pathname for delete or change notification */
6574 if (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE)) {
6575 fidp->flags |= SMB_FID_NTOPEN;
6576 fidp->NTopen_dscp = dscp;
6577 cm_HoldSCache(dscp);
6578 fidp->NTopen_pathp = strdup(lastNamep);
6580 fidp->NTopen_wholepathp = realPathp;
6581 lock_ReleaseMutex(&fidp->mx);
6583 /* we don't need this any longer */
6585 cm_ReleaseSCache(dscp);
6589 cm_Open(scp, 0, userp);
6591 /* set inp->fid so that later read calls in same msg can find fid */
6592 inp->fid = fidp->fid;
6596 lock_ObtainMutex(&scp->mx);
6597 smb_SetSMBParmByte(outp, parmSlot, 0); /* oplock */
6598 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
6599 smb_SetSMBParmLong(outp, parmSlot, openAction); parmSlot += 2;
6600 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
6601 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
6602 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
6603 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
6604 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
6605 smb_SetSMBParmLong(outp, parmSlot, smb_ExtAttributes(scp));
6607 smb_SetSMBParmDouble(outp, parmSlot, (char *)&scp->length); parmSlot += 4;
6608 smb_SetSMBParmDouble(outp, parmSlot, (char *)&scp->length); parmSlot += 4;
6609 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* filetype */
6610 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* dev state */
6611 smb_SetSMBParmByte(outp, parmSlot,
6612 (scp->fileType == CM_SCACHETYPE_DIRECTORY ||
6613 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
6614 scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0); /* is a dir? */
6615 lock_ReleaseMutex(&scp->mx);
6616 smb_SetSMBDataLength(outp, 0);
6618 osi_Log2(smb_logp, "SMB NT CreateX opening fid %d path %s", fidp->fid,
6619 osi_LogSaveString(smb_logp, realPathp));
6621 smb_ReleaseFID(fidp);
6623 cm_ReleaseUser(userp);
6625 /* Can't free realPathp if we get here since
6626 fidp->NTopen_wholepathp is pointing there */
6628 /* leave scp held since we put it in fidp->scp */
6633 * A lot of stuff copied verbatim from NT Create&X to NT Tran Create.
6634 * Instead, ultimately, would like to use a subroutine for common code.
6636 long smb_ReceiveNTTranCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6638 char *pathp, *realPathp;
6642 cm_scache_t *dscp; /* parent dir */
6643 cm_scache_t *scp; /* file to create or open */
6644 cm_scache_t *targetScp; /* if scp is a symlink */
6647 unsigned long nameLength;
6649 unsigned int requestOpLock;
6650 unsigned int requestBatchOpLock;
6651 unsigned int mustBeDir;
6652 unsigned int extendedRespRequired;
6654 unsigned int desiredAccess;
6655 #ifdef DEBUG_VERBOSE
6656 unsigned int allocSize;
6658 unsigned int shareAccess;
6659 unsigned int extAttributes;
6660 unsigned int createDisp;
6661 #ifdef DEBUG_VERBOSE
6664 unsigned int createOptions;
6665 int initialModeBits;
6666 unsigned short baseFid;
6667 smb_fid_t *baseFidp;
6669 cm_scache_t *baseDirp;
6670 unsigned short openAction;
6676 int parmOffset, dataOffset;
6688 parmOffset = smb_GetSMBOffsetParm(inp, 11, 1)
6689 | (smb_GetSMBOffsetParm(inp, 12, 1) << 16);
6690 parmp = inp->data + parmOffset;
6691 lparmp = (ULONG *) parmp;
6694 requestOpLock = flags & REQUEST_OPLOCK;
6695 requestBatchOpLock = flags & REQUEST_BATCH_OPLOCK;
6696 mustBeDir = flags & OPEN_DIRECTORY;
6697 extendedRespRequired = flags & EXTENDED_RESPONSE_REQUIRED;
6700 * Why all of a sudden 32-bit FID?
6701 * We will reject all bits higher than 16.
6703 if (lparmp[1] & 0xFFFF0000)
6704 return CM_ERROR_INVAL;
6705 baseFid = (unsigned short)lparmp[1];
6706 desiredAccess = lparmp[2];
6707 #ifdef DEBUG_VERBOSE
6708 allocSize = lparmp[3];
6709 #endif /* DEBUG_VERSOSE */
6710 extAttributes = lparmp[5];
6711 shareAccess = lparmp[6];
6712 createDisp = lparmp[7];
6713 createOptions = lparmp[8];
6714 #ifdef DEBUG_VERBOSE
6717 nameLength = lparmp[11];
6719 #ifdef DEBUG_VERBOSE
6720 osi_Log4(smb_logp,"NTTranCreate with da[%x],ea[%x],sa[%x],cd[%x]",desiredAccess,extAttributes,shareAccess,createDisp);
6721 osi_Log3(smb_logp,"... co[%x],sdl[%x],as[%x]",createOptions,sdLen,allocSize);
6722 osi_Log1(smb_logp,"... flags[%x]",flags);
6725 /* mustBeDir is never set; createOptions directory bit seems to be
6728 if (createOptions & FILE_DIRECTORY_FILE)
6730 else if (createOptions & FILE_NON_DIRECTORY_FILE)
6736 * compute initial mode bits based on read-only flag in
6737 * extended attributes
6739 initialModeBits = 0666;
6740 if (extAttributes & SMB_ATTR_READONLY)
6741 initialModeBits &= ~0222;
6743 pathp = parmp + (13 * sizeof(ULONG)) + sizeof(UCHAR);
6744 /* Sometimes path is not null-terminated, so we make a copy. */
6745 realPathp = malloc(nameLength+1);
6746 memcpy(realPathp, pathp, nameLength);
6747 realPathp[nameLength] = 0;
6748 if (smb_StoreAnsiFilenames)
6749 OemToChar(realPathp,realPathp);
6751 spacep = cm_GetSpace();
6752 smb_StripLastComponent(spacep->data, &lastNamep, realPathp);
6755 * Nothing here to handle SMB_IOCTL_FILENAME.
6756 * Will add it if necessary.
6759 #ifdef DEBUG_VERBOSE
6761 char *hexp, *asciip;
6762 asciip = (lastNamep? lastNamep : realPathp);
6763 hexp = osi_HexifyString( asciip );
6764 DEBUG_EVENT2("AFS", "NTTranCreate H[%s] A[%s]", hexp, asciip);
6769 userp = smb_GetUserFromVCP(vcp, inp);
6771 osi_Log1(smb_logp, "NTTranCreate invalid user [%d]", ((smb_t *) inp)->uid);
6773 return CM_ERROR_INVAL;
6778 baseDirp = cm_data.rootSCachep;
6779 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
6780 if (code == CM_ERROR_TIDIPC) {
6781 /* Attempt to use a TID allocated for IPC. The client
6782 * is probably looking for DCE RPC end points which we
6783 * don't support OR it could be looking to make a DFS
6786 osi_Log0(smb_logp, "NTTranCreate received IPC TID");
6789 cm_ReleaseUser(userp);
6790 return CM_ERROR_NOSUCHPATH;
6794 baseFidp = smb_FindFID(vcp, baseFid, 0);
6796 osi_Log1(smb_logp, "NTTranCreate Invalid fid [%d]", baseFid);
6798 cm_ReleaseUser(userp);
6799 return CM_ERROR_INVAL;
6801 baseDirp = baseFidp->scp;
6805 /* compute open mode */
6807 if (desiredAccess & DELETE)
6808 fidflags |= SMB_FID_OPENDELETE;
6809 if (desiredAccess & AFS_ACCESS_READ)
6810 fidflags |= SMB_FID_OPENREAD;
6811 if (desiredAccess & AFS_ACCESS_WRITE)
6812 fidflags |= SMB_FID_OPENWRITE;
6813 if (createOptions & FILE_DELETE_ON_CLOSE)
6814 fidflags |= SMB_FID_DELONCLOSE;
6815 if (createOptions & FILE_SEQUENTIAL_ONLY && !(createOptions & FILE_RANDOM_ACCESS))
6816 fidflags |= SMB_FID_SEQUENTIAL;
6817 if (createOptions & FILE_RANDOM_ACCESS && !(createOptions & FILE_SEQUENTIAL_ONLY))
6818 fidflags |= SMB_FID_RANDOM;
6820 /* And the share mode */
6821 if (shareAccess & FILE_SHARE_READ)
6822 fidflags |= SMB_FID_SHARE_READ;
6823 if (shareAccess & FILE_SHARE_WRITE)
6824 fidflags |= SMB_FID_SHARE_WRITE;
6828 if ( createDisp == FILE_OPEN ||
6829 createDisp == FILE_OVERWRITE ||
6830 createDisp == FILE_OVERWRITE_IF) {
6831 code = cm_NameI(baseDirp, spacep->data, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
6832 userp, tidPathp, &req, &dscp);
6835 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
6836 cm_ReleaseSCache(dscp);
6837 cm_ReleaseUser(userp);
6840 smb_ReleaseFID(baseFidp);
6841 if ( WANTS_DFS_PATHNAMES(inp) )
6842 return CM_ERROR_PATH_NOT_COVERED;
6844 return CM_ERROR_BADSHARENAME;
6846 #endif /* DFS_SUPPORT */
6847 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp, CM_FLAG_FOLLOW,
6849 if (code == CM_ERROR_NOSUCHFILE) {
6850 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp,
6851 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, &req, &scp);
6852 if (code == 0 && realDirFlag == 1) {
6853 cm_ReleaseSCache(scp);
6854 cm_ReleaseSCache(dscp);
6855 cm_ReleaseUser(userp);
6858 smb_ReleaseFID(baseFidp);
6859 return CM_ERROR_EXISTS;
6865 code = cm_NameI(baseDirp, realPathp, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
6866 userp, tidPathp, &req, &scp);
6868 if (code == 0 && scp->fileType == CM_SCACHETYPE_DFSLINK) {
6869 cm_ReleaseSCache(scp);
6870 cm_ReleaseUser(userp);
6873 smb_ReleaseFID(baseFidp);
6874 if ( WANTS_DFS_PATHNAMES(inp) )
6875 return CM_ERROR_PATH_NOT_COVERED;
6877 return CM_ERROR_BADSHARENAME;
6879 #endif /* DFS_SUPPORT */
6885 if (code != 0 || (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE))) {
6886 /* look up parent directory */
6888 code = cm_NameI(baseDirp, spacep->data,
6889 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
6890 userp, tidPathp, &req, &dscp);
6892 if (code == 0 && dscp->fileType == CM_SCACHETYPE_DFSLINK) {
6893 cm_ReleaseSCache(dscp);
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 */
6907 cm_FreeSpace(spacep);
6910 smb_ReleaseFID(baseFidp);
6913 cm_ReleaseUser(userp);
6919 lastNamep = realPathp;
6923 if (!smb_IsLegalFilename(lastNamep))
6924 return CM_ERROR_BADNTFILENAME;
6927 if (createDisp == FILE_CREATE || createDisp == FILE_OVERWRITE_IF) {
6928 code = cm_Lookup(dscp, lastNamep,
6929 CM_FLAG_FOLLOW, userp, &req, &scp);
6931 code = cm_Lookup(dscp, lastNamep,
6932 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
6935 if (code && code != CM_ERROR_NOSUCHFILE) {
6936 cm_ReleaseSCache(dscp);
6937 cm_ReleaseUser(userp);
6944 smb_ReleaseFID(baseFidp);
6945 cm_FreeSpace(spacep);
6948 /* if we get here, if code is 0, the file exists and is represented by
6949 * scp. Otherwise, we have to create it. The dir may be represented
6950 * by dscp, or we may have found the file directly. If code is non-zero,
6954 code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp,
6958 cm_ReleaseSCache(dscp);
6959 cm_ReleaseSCache(scp);
6960 cm_ReleaseUser(userp);
6965 if (createDisp == FILE_CREATE) {
6966 /* oops, file shouldn't be there */
6968 cm_ReleaseSCache(dscp);
6969 cm_ReleaseSCache(scp);
6970 cm_ReleaseUser(userp);
6972 return CM_ERROR_EXISTS;
6975 if (createDisp == FILE_OVERWRITE ||
6976 createDisp == FILE_OVERWRITE_IF) {
6977 setAttr.mask = CM_ATTRMASK_LENGTH;
6978 setAttr.length.LowPart = 0;
6979 setAttr.length.HighPart = 0;
6981 /* now watch for a symlink */
6983 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
6985 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
6987 /* we have a more accurate file to use (the
6988 * target of the symbolic link). Otherwise,
6989 * we'll just use the symlink anyway.
6991 osi_Log2(smb_logp, "symlink vp %x to vp %x",
6993 cm_ReleaseSCache(scp);
6997 code = cm_SetAttr(scp, &setAttr, userp, &req);
6998 openAction = 3; /* truncated existing file */
7000 else openAction = 1; /* found existing file */
7002 else if (createDisp == FILE_OPEN || createDisp == FILE_OVERWRITE) {
7003 /* don't create if not found */
7005 cm_ReleaseSCache(dscp);
7006 cm_ReleaseUser(userp);
7008 return CM_ERROR_NOSUCHFILE;
7010 else if (realDirFlag == 0 || realDirFlag == -1) {
7011 osi_assert(dscp != NULL);
7012 osi_Log1(smb_logp, "smb_ReceiveNTTranCreate creating file %s",
7013 osi_LogSaveString(smb_logp, lastNamep));
7014 openAction = 2; /* created file */
7015 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
7016 setAttr.clientModTime = time(NULL);
7017 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
7021 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
7022 smb_NotifyChange(FILE_ACTION_ADDED,
7023 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
7024 dscp, lastNamep, NULL, TRUE);
7025 } else if (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE) {
7026 /* Not an exclusive create, and someone else tried
7027 * creating it already, then we open it anyway. We
7028 * don't bother retrying after this, since if this next
7029 * fails, that means that the file was deleted after we
7030 * started this call.
7032 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
7035 if (createDisp == FILE_OVERWRITE_IF) {
7036 setAttr.mask = CM_ATTRMASK_LENGTH;
7037 setAttr.length.LowPart = 0;
7038 setAttr.length.HighPart = 0;
7040 /* now watch for a symlink */
7042 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
7044 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
7046 /* we have a more accurate file to use (the
7047 * target of the symbolic link). Otherwise,
7048 * we'll just use the symlink anyway.
7050 osi_Log2(smb_logp, "symlink vp %x to vp %x",
7052 cm_ReleaseSCache(scp);
7056 code = cm_SetAttr(scp, &setAttr, userp, &req);
7058 } /* lookup succeeded */
7061 /* create directory */
7062 osi_assert(dscp != NULL);
7064 "smb_ReceiveNTTranCreate creating directory %s",
7065 osi_LogSaveString(smb_logp, lastNamep));
7066 openAction = 2; /* created directory */
7067 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
7068 setAttr.clientModTime = time(NULL);
7069 code = cm_MakeDir(dscp, lastNamep, 0, &setAttr, userp, &req);
7070 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
7071 smb_NotifyChange(FILE_ACTION_ADDED,
7072 FILE_NOTIFY_CHANGE_DIR_NAME,
7073 dscp, lastNamep, NULL, TRUE);
7075 (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE)) {
7076 /* Not an exclusive create, and someone else tried
7077 * creating it already, then we open it anyway. We
7078 * don't bother retrying after this, since if this next
7079 * fails, that means that the file was deleted after we
7080 * started this call.
7082 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
7088 /* something went wrong creating or truncating the file */
7090 cm_ReleaseSCache(scp);
7091 cm_ReleaseUser(userp);
7096 /* make sure we have file vs. dir right */
7097 if (realDirFlag == 0 && scp->fileType != CM_SCACHETYPE_FILE) {
7098 /* now watch for a symlink */
7100 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
7102 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
7104 /* we have a more accurate file to use (the
7105 * target of the symbolic link). Otherwise,
7106 * we'll just use the symlink anyway.
7108 osi_Log2(smb_logp, "symlink vp %x to vp %x",
7110 cm_ReleaseSCache(scp);
7115 if (scp->fileType != CM_SCACHETYPE_FILE) {
7116 cm_ReleaseSCache(scp);
7117 cm_ReleaseUser(userp);
7119 return CM_ERROR_ISDIR;
7123 if (realDirFlag == 1 && scp->fileType == CM_SCACHETYPE_FILE) {
7124 cm_ReleaseSCache(scp);
7125 cm_ReleaseUser(userp);
7127 return CM_ERROR_NOTDIR;
7130 /* open the file itself */
7131 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
7134 /* save a reference to the user */
7136 fidp->userp = userp;
7138 /* If we are restricting sharing, we should do so with a suitable
7140 if (scp->fileType == CM_SCACHETYPE_FILE &&
7141 !(fidflags & SMB_FID_SHARE_WRITE)) {
7143 LARGE_INTEGER LOffset, LLength;
7146 LOffset.HighPart = SMB_FID_QLOCK_HIGH;
7147 LOffset.LowPart = SMB_FID_QLOCK_LOW;
7148 LLength.HighPart = 0;
7149 LLength.LowPart = SMB_FID_QLOCK_LENGTH;
7151 if (fidflags & SMB_FID_SHARE_READ) {
7152 sLockType = LOCKING_ANDX_SHARED_LOCK;
7157 key = cm_GenerateKey(vcp->vcID, SMB_FID_QLOCK_PID, fidp->fid);
7159 lock_ObtainMutex(&scp->mx);
7160 code = cm_Lock(scp, sLockType, LOffset, LLength, key, 0, userp, &req, NULL);
7161 lock_ReleaseMutex(&scp->mx);
7164 /* Shouldn't this be smb_CloseFID()? fidp->flags = SMB_FID_DELETE; */
7165 smb_CloseFID(vcp, fidp, NULL, 0);
7166 smb_ReleaseFID(fidp);
7168 cm_ReleaseSCache(scp);
7169 cm_ReleaseUser(userp);
7172 return CM_ERROR_SHARING_VIOLATION;
7176 lock_ObtainMutex(&fidp->mx);
7177 /* save a pointer to the vnode */
7180 fidp->flags = fidflags;
7182 /* remember if the file was newly created */
7184 fidp->flags |= SMB_FID_CREATED;
7186 /* save parent dir and pathname for deletion or change notification */
7187 if (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE)) {
7188 fidp->flags |= SMB_FID_NTOPEN;
7189 fidp->NTopen_dscp = dscp;
7190 cm_HoldSCache(dscp);
7191 fidp->NTopen_pathp = strdup(lastNamep);
7193 fidp->NTopen_wholepathp = realPathp;
7194 lock_ReleaseMutex(&fidp->mx);
7196 /* we don't need this any longer */
7198 cm_ReleaseSCache(dscp);
7200 cm_Open(scp, 0, userp);
7202 /* set inp->fid so that later read calls in same msg can find fid */
7203 inp->fid = fidp->fid;
7205 /* check whether we are required to send an extended response */
7206 if (!extendedRespRequired) {
7208 parmOffset = 8*4 + 39;
7209 parmOffset += 1; /* pad to 4 */
7210 dataOffset = parmOffset + 70;
7214 /* Total Parameter Count */
7215 smb_SetSMBParmLong(outp, parmSlot, 70); parmSlot += 2;
7216 /* Total Data Count */
7217 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
7218 /* Parameter Count */
7219 smb_SetSMBParmLong(outp, parmSlot, 70); parmSlot += 2;
7220 /* Parameter Offset */
7221 smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
7222 /* Parameter Displacement */
7223 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
7225 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
7227 smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
7228 /* Data Displacement */
7229 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
7230 smb_SetSMBParmByte(outp, parmSlot, 0); /* Setup Count */
7231 smb_SetSMBDataLength(outp, 70);
7233 lock_ObtainMutex(&scp->mx);
7234 outData = smb_GetSMBData(outp, NULL);
7235 outData++; /* round to get to parmOffset */
7236 *outData = 0; outData++; /* oplock */
7237 *outData = 0; outData++; /* reserved */
7238 *((USHORT *)outData) = fidp->fid; outData += 2; /* fid */
7239 *((ULONG *)outData) = openAction; outData += 4;
7240 *((ULONG *)outData) = 0; outData += 4; /* EA error offset */
7241 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
7242 *((FILETIME *)outData) = ft; outData += 8; /* creation time */
7243 *((FILETIME *)outData) = ft; outData += 8; /* last access time */
7244 *((FILETIME *)outData) = ft; outData += 8; /* last write time */
7245 *((FILETIME *)outData) = ft; outData += 8; /* change time */
7246 *((ULONG *)outData) = smb_ExtAttributes(scp); outData += 4;
7247 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* alloc sz */
7248 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* EOF */
7249 *((USHORT *)outData) = 0; outData += 2; /* filetype */
7250 *((USHORT *)outData) = 0; outData += 2; /* dev state */
7251 *((USHORT *)outData) = ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
7252 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
7253 scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0);
7254 outData += 2; /* is a dir? */
7255 lock_ReleaseMutex(&scp->mx);
7258 parmOffset = 8*4 + 39;
7259 parmOffset += 1; /* pad to 4 */
7260 dataOffset = parmOffset + 104;
7264 /* Total Parameter Count */
7265 smb_SetSMBParmLong(outp, parmSlot, 101); parmSlot += 2;
7266 /* Total Data Count */
7267 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
7268 /* Parameter Count */
7269 smb_SetSMBParmLong(outp, parmSlot, 101); parmSlot += 2;
7270 /* Parameter Offset */
7271 smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
7272 /* Parameter Displacement */
7273 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
7275 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
7277 smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
7278 /* Data Displacement */
7279 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
7280 smb_SetSMBParmByte(outp, parmSlot, 0); /* Setup Count */
7281 smb_SetSMBDataLength(outp, 105);
7283 lock_ObtainMutex(&scp->mx);
7284 outData = smb_GetSMBData(outp, NULL);
7285 outData++; /* round to get to parmOffset */
7286 *outData = 0; outData++; /* oplock */
7287 *outData = 1; outData++; /* response type */
7288 *((USHORT *)outData) = fidp->fid; outData += 2; /* fid */
7289 *((ULONG *)outData) = openAction; outData += 4;
7290 *((ULONG *)outData) = 0; outData += 4; /* EA error offset */
7291 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
7292 *((FILETIME *)outData) = ft; outData += 8; /* creation time */
7293 *((FILETIME *)outData) = ft; outData += 8; /* last access time */
7294 *((FILETIME *)outData) = ft; outData += 8; /* last write time */
7295 *((FILETIME *)outData) = ft; outData += 8; /* change time */
7296 *((ULONG *)outData) = smb_ExtAttributes(scp); outData += 4;
7297 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* alloc sz */
7298 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* EOF */
7299 *((USHORT *)outData) = 0; outData += 2; /* filetype */
7300 *((USHORT *)outData) = 0; outData += 2; /* dev state */
7301 *((USHORT *)outData) = ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
7302 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
7303 scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0);
7304 outData += 1; /* is a dir? */
7305 memset(outData,0,24); outData += 24; /* Volume ID and file ID */
7306 *((ULONG *)outData) = 0x001f01ffL; outData += 4; /* Maxmimal access rights */
7307 *((ULONG *)outData) = 0; outData += 4; /* Guest Access rights */
7308 lock_ReleaseMutex(&scp->mx);
7311 osi_Log1(smb_logp, "SMB NTTranCreate opening fid %d", fidp->fid);
7313 smb_ReleaseFID(fidp);
7315 cm_ReleaseUser(userp);
7317 /* free(realPathp); Can't free realPathp here because fidp->NTopen_wholepathp points there */
7318 /* leave scp held since we put it in fidp->scp */
7322 long smb_ReceiveNTTranNotifyChange(smb_vc_t *vcp, smb_packet_t *inp,
7325 smb_packet_t *savedPacketp;
7326 ULONG filter; USHORT fid, watchtree;
7330 filter = smb_GetSMBParm(inp, 19) |
7331 (smb_GetSMBParm(inp, 20) << 16);
7332 fid = smb_GetSMBParm(inp, 21);
7333 watchtree = smb_GetSMBParm(inp, 22) && 0xffff; /* TODO: should this be 0xff ? */
7335 fidp = smb_FindFID(vcp, fid, 0);
7337 osi_Log1(smb_logp, "ERROR: NotifyChange given invalid fid [%d]", fid);
7338 return CM_ERROR_BADFD;
7341 savedPacketp = smb_CopyPacket(inp);
7343 if (savedPacketp->vcp)
7344 smb_ReleaseVC(savedPacketp->vcp);
7345 savedPacketp->vcp = vcp;
7346 lock_ObtainMutex(&smb_Dir_Watch_Lock);
7347 savedPacketp->nextp = smb_Directory_Watches;
7348 smb_Directory_Watches = savedPacketp;
7349 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
7351 osi_Log4(smb_logp, "Request for NotifyChange filter 0x%x fid %d wtree %d file %s",
7352 filter, fid, watchtree, osi_LogSaveString(smb_logp, fidp->NTopen_wholepathp));
7355 lock_ObtainMutex(&scp->mx);
7357 scp->flags |= CM_SCACHEFLAG_WATCHEDSUBTREE;
7359 scp->flags |= CM_SCACHEFLAG_WATCHED;
7360 lock_ReleaseMutex(&scp->mx);
7361 smb_ReleaseFID(fidp);
7363 outp->flags |= SMB_PACKETFLAG_NOSEND;
7367 unsigned char nullSecurityDesc[36] = {
7368 0x01, /* security descriptor revision */
7369 0x00, /* reserved, should be zero */
7370 0x00, 0x80, /* security descriptor control;
7371 * 0x8000 : self-relative format */
7372 0x14, 0x00, 0x00, 0x00, /* offset of owner SID */
7373 0x1c, 0x00, 0x00, 0x00, /* offset of group SID */
7374 0x00, 0x00, 0x00, 0x00, /* offset of DACL would go here */
7375 0x00, 0x00, 0x00, 0x00, /* offset of SACL would go here */
7376 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
7377 /* "null SID" owner SID */
7378 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
7379 /* "null SID" group SID */
7382 long smb_ReceiveNTTranQuerySecurityDesc(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7384 int parmOffset, parmCount, dataOffset, dataCount;
7392 ULONG securityInformation;
7394 parmOffset = smb_GetSMBOffsetParm(inp, 11, 1)
7395 | (smb_GetSMBOffsetParm(inp, 12, 1) << 16);
7396 parmp = inp->data + parmOffset;
7397 sparmp = (USHORT *) parmp;
7398 lparmp = (ULONG *) parmp;
7401 securityInformation = lparmp[1];
7403 maxData = smb_GetSMBOffsetParm(inp, 7, 1)
7404 | (smb_GetSMBOffsetParm(inp, 8, 1) << 16);
7412 parmOffset = 8*4 + 39;
7413 parmOffset += 1; /* pad to 4 */
7415 dataOffset = parmOffset + parmCount;
7419 /* Total Parameter Count */
7420 smb_SetSMBParmLong(outp, parmSlot, parmCount); parmSlot += 2;
7421 /* Total Data Count */
7422 smb_SetSMBParmLong(outp, parmSlot, dataCount); parmSlot += 2;
7423 /* Parameter Count */
7424 smb_SetSMBParmLong(outp, parmSlot, parmCount); parmSlot += 2;
7425 /* Parameter Offset */
7426 smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
7427 /* Parameter Displacement */
7428 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
7430 smb_SetSMBParmLong(outp, parmSlot, dataCount); parmSlot += 2;
7432 smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
7433 /* Data Displacement */
7434 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
7435 smb_SetSMBParmByte(outp, parmSlot, 0); /* Setup Count */
7436 smb_SetSMBDataLength(outp, 1 + parmCount + dataCount);
7438 outData = smb_GetSMBData(outp, NULL);
7439 outData++; /* round to get to parmOffset */
7440 *((ULONG *)outData) = 36; outData += 4; /* length */
7442 if (maxData >= 36) {
7443 memcpy(outData, nullSecurityDesc, 36);
7447 return CM_ERROR_BUFFERTOOSMALL;
7450 long smb_ReceiveNTTransact(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7452 unsigned short function;
7454 function = smb_GetSMBParm(inp, 18);
7456 osi_Log1(smb_logp, "SMB NT Transact function %d", function);
7458 /* We can handle long names */
7459 if (vcp->flags & SMB_VCFLAG_USENT)
7460 ((smb_t *)outp)->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
7464 return smb_ReceiveNTTranCreate(vcp, inp, outp);
7466 osi_Log0(smb_logp, "SMB NT Transact Ioctl - not implemented");
7469 osi_Log0(smb_logp, "SMB NT Transact SetSecurityDesc - not implemented");
7472 return smb_ReceiveNTTranNotifyChange(vcp, inp, outp);
7474 osi_Log0(smb_logp, "SMB NT Transact Rename - not implemented");
7477 return smb_ReceiveNTTranQuerySecurityDesc(vcp, inp, outp);
7479 return CM_ERROR_INVAL;
7483 * smb_NotifyChange -- find relevant change notification messages and
7486 * If we don't know the file name (i.e. a callback break), filename is
7487 * NULL, and we return a zero-length list.
7489 void smb_NotifyChange(DWORD action, DWORD notifyFilter,
7490 cm_scache_t *dscp, char *filename, char *otherFilename,
7491 BOOL isDirectParent)
7493 smb_packet_t *watch, *lastWatch, *nextWatch;
7494 ULONG parmSlot, parmCount, parmOffset, dataOffset, nameLen;
7495 char *outData, *oldOutData;
7499 BOOL twoEntries = FALSE;
7500 ULONG otherNameLen, oldParmCount = 0;
7504 /* Get ready for rename within directory */
7505 if (action == FILE_ACTION_RENAMED_OLD_NAME && otherFilename != NULL) {
7507 otherAction = FILE_ACTION_RENAMED_NEW_NAME;
7510 osi_Log2(smb_logp,"in smb_NotifyChange for file [%s] dscp [%x]",
7511 osi_LogSaveString(smb_logp,filename),dscp);
7513 lock_ObtainMutex(&smb_Dir_Watch_Lock);
7514 watch = smb_Directory_Watches;
7516 filter = smb_GetSMBParm(watch, 19)
7517 | (smb_GetSMBParm(watch, 20) << 16);
7518 fid = smb_GetSMBParm(watch, 21);
7519 wtree = smb_GetSMBParm(watch, 22) & 0xffff; /* TODO: should this be 0xff ? */
7520 maxLen = smb_GetSMBOffsetParm(watch, 5, 1)
7521 | (smb_GetSMBOffsetParm(watch, 6, 1) << 16);
7524 * Strange hack - bug in NT Client and NT Server that we
7527 if (filter == 3 && wtree)
7530 fidp = smb_FindFID(watch->vcp, fid, 0);
7532 osi_Log1(smb_logp," no fidp for fid[%d]",fid);
7534 watch = watch->nextp;
7537 if (fidp->scp != dscp
7538 || (filter & notifyFilter) == 0
7539 || (!isDirectParent && !wtree)) {
7540 osi_Log1(smb_logp," passing fidp->scp[%x]", fidp->scp);
7541 smb_ReleaseFID(fidp);
7543 watch = watch->nextp;
7546 smb_ReleaseFID(fidp);
7549 "Sending Change Notification for fid %d filter 0x%x wtree %d file %s",
7550 fid, filter, wtree, osi_LogSaveString(smb_logp, filename));
7552 nextWatch = watch->nextp;
7553 if (watch == smb_Directory_Watches)
7554 smb_Directory_Watches = nextWatch;
7556 lastWatch->nextp = nextWatch;
7558 /* Turn off WATCHED flag in dscp */
7559 lock_ObtainMutex(&dscp->mx);
7561 dscp->flags &= ~CM_SCACHEFLAG_WATCHEDSUBTREE;
7563 dscp->flags &= ~CM_SCACHEFLAG_WATCHED;
7564 lock_ReleaseMutex(&dscp->mx);
7566 /* Convert to response packet */
7567 ((smb_t *) watch)->reb = SMB_FLAGS_SERVER_TO_CLIENT | SMB_FLAGS_CANONICAL_PATHNAMES;
7568 ((smb_t *) watch)->wct = 0;
7571 if (filename == NULL)
7574 nameLen = (ULONG)strlen(filename);
7575 parmCount = 3*4 + nameLen*2;
7576 parmCount = (parmCount + 3) & ~3; /* pad to 4 */
7578 otherNameLen = (ULONG)strlen(otherFilename);
7579 oldParmCount = parmCount;
7580 parmCount += 3*4 + otherNameLen*2;
7581 parmCount = (parmCount + 3) & ~3; /* pad to 4 */
7583 if (maxLen < parmCount)
7584 parmCount = 0; /* not enough room */
7586 parmOffset = 8*4 + 39;
7587 parmOffset += 1; /* pad to 4 */
7588 dataOffset = parmOffset + parmCount;
7592 /* Total Parameter Count */
7593 smb_SetSMBParmLong(watch, parmSlot, parmCount); parmSlot += 2;
7594 /* Total Data Count */
7595 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
7596 /* Parameter Count */
7597 smb_SetSMBParmLong(watch, parmSlot, parmCount); parmSlot += 2;
7598 /* Parameter Offset */
7599 smb_SetSMBParmLong(watch, parmSlot, parmOffset); parmSlot += 2;
7600 /* Parameter Displacement */
7601 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
7603 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
7605 smb_SetSMBParmLong(watch, parmSlot, dataOffset); parmSlot += 2;
7606 /* Data Displacement */
7607 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
7608 smb_SetSMBParmByte(watch, parmSlot, 0); /* Setup Count */
7609 smb_SetSMBDataLength(watch, parmCount + 1);
7611 if (parmCount != 0) {
7613 outData = smb_GetSMBData(watch, NULL);
7614 outData++; /* round to get to parmOffset */
7615 oldOutData = outData;
7616 *((DWORD *)outData) = oldParmCount; outData += 4;
7617 /* Next Entry Offset */
7618 *((DWORD *)outData) = action; outData += 4;
7620 *((DWORD *)outData) = nameLen*2; outData += 4;
7621 /* File Name Length */
7622 p = strdup(filename);
7623 if (smb_StoreAnsiFilenames)
7625 mbstowcs((WCHAR *)outData, p, nameLen);
7629 outData = oldOutData + oldParmCount;
7630 *((DWORD *)outData) = 0; outData += 4;
7631 /* Next Entry Offset */
7632 *((DWORD *)outData) = otherAction; outData += 4;
7634 *((DWORD *)outData) = otherNameLen*2;
7635 outData += 4; /* File Name Length */
7636 p = strdup(otherFilename);
7637 if (smb_StoreAnsiFilenames)
7639 mbstowcs((WCHAR *)outData, p, otherNameLen); /* File Name */
7645 * If filename is null, we don't know the cause of the
7646 * change notification. We return zero data (see above),
7647 * and set error code to NT_STATUS_NOTIFY_ENUM_DIR
7648 * (= 0x010C). We set the error code here by hand, without
7649 * modifying wct and bcc.
7651 if (filename == NULL) {
7652 ((smb_t *) watch)->rcls = 0x0C;
7653 ((smb_t *) watch)->reh = 0x01;
7654 ((smb_t *) watch)->errLow = 0;
7655 ((smb_t *) watch)->errHigh = 0;
7656 /* Set NT Status codes flag */
7657 ((smb_t *) watch)->flg2 |= SMB_FLAGS2_32BIT_STATUS;
7660 smb_SendPacket(watch->vcp, watch);
7661 smb_FreePacket(watch);
7664 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
7667 long smb_ReceiveNTCancel(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7669 unsigned char *replyWctp;
7670 smb_packet_t *watch, *lastWatch;
7671 USHORT fid, watchtree;
7675 osi_Log0(smb_logp, "SMB3 receive NT cancel");
7677 lock_ObtainMutex(&smb_Dir_Watch_Lock);
7678 watch = smb_Directory_Watches;
7680 if (((smb_t *)watch)->uid == ((smb_t *)inp)->uid
7681 && ((smb_t *)watch)->pid == ((smb_t *)inp)->pid
7682 && ((smb_t *)watch)->mid == ((smb_t *)inp)->mid
7683 && ((smb_t *)watch)->tid == ((smb_t *)inp)->tid) {
7684 if (watch == smb_Directory_Watches)
7685 smb_Directory_Watches = watch->nextp;
7687 lastWatch->nextp = watch->nextp;
7688 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
7690 /* Turn off WATCHED flag in scp */
7691 fid = smb_GetSMBParm(watch, 21);
7692 watchtree = smb_GetSMBParm(watch, 22) & 0xffff;
7694 if (vcp != watch->vcp)
7695 osi_Log2(smb_logp, "smb_ReceiveNTCancel: vcp %x not equal to watch vcp %x",
7698 fidp = smb_FindFID(vcp, fid, 0);
7700 osi_Log3(smb_logp, "Cancelling change notification for fid %d wtree %d file %s",
7702 osi_LogSaveString(smb_logp, (fidp)?fidp->NTopen_wholepathp:""));
7705 lock_ObtainMutex(&scp->mx);
7707 scp->flags &= ~CM_SCACHEFLAG_WATCHEDSUBTREE;
7709 scp->flags &= ~CM_SCACHEFLAG_WATCHED;
7710 lock_ReleaseMutex(&scp->mx);
7711 smb_ReleaseFID(fidp);
7713 osi_Log2(smb_logp,"NTCancel unable to resolve fid [%d] in vcp[%x]", fid,vcp);
7716 /* assume STATUS32; return 0xC0000120 (CANCELED) */
7717 replyWctp = watch->wctp;
7721 ((smb_t *)watch)->rcls = 0x20;
7722 ((smb_t *)watch)->reh = 0x1;
7723 ((smb_t *)watch)->errLow = 0;
7724 ((smb_t *)watch)->errHigh = 0xC0;
7725 ((smb_t *)watch)->flg2 |= SMB_FLAGS2_32BIT_STATUS;
7726 smb_SendPacket(vcp, watch);
7727 smb_FreePacket(watch);
7731 watch = watch->nextp;
7733 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
7739 * NT rename also does hard links.
7742 #define RENAME_FLAG_MOVE_CLUSTER_INFORMATION 0x102
7743 #define RENAME_FLAG_HARD_LINK 0x103
7744 #define RENAME_FLAG_RENAME 0x104
7745 #define RENAME_FLAG_COPY 0x105
7747 long smb_ReceiveNTRename(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7749 char *oldPathp, *newPathp;
7755 attrs = smb_GetSMBParm(inp, 0);
7756 rename_type = smb_GetSMBParm(inp, 1);
7758 if (rename_type != RENAME_FLAG_RENAME && rename_type != RENAME_FLAG_HARD_LINK) {
7759 osi_Log1(smb_logp, "NTRename invalid infolevel [%x]", rename_type);
7760 return CM_ERROR_NOACCESS;
7763 tp = smb_GetSMBData(inp, NULL);
7764 oldPathp = smb_ParseASCIIBlock(tp, &tp);
7765 if (smb_StoreAnsiFilenames)
7766 OemToChar(oldPathp,oldPathp);
7767 newPathp = smb_ParseASCIIBlock(tp, &tp);
7768 if (smb_StoreAnsiFilenames)
7769 OemToChar(newPathp,newPathp);
7771 osi_Log3(smb_logp, "NTRename for [%s]->[%s] type [%s]",
7772 osi_LogSaveString(smb_logp, oldPathp),
7773 osi_LogSaveString(smb_logp, newPathp),
7774 ((rename_type==RENAME_FLAG_RENAME)?"rename":"hardlink"));
7776 if (rename_type == RENAME_FLAG_RENAME) {
7777 code = smb_Rename(vcp,inp,oldPathp,newPathp,attrs);
7778 } else { /* RENAME_FLAG_HARD_LINK */
7779 code = smb_Link(vcp,inp,oldPathp,newPathp);
7786 lock_InitializeMutex(&smb_Dir_Watch_Lock, "Directory Watch List Lock");
7789 cm_user_t *smb_FindCMUserByName(char *usern, char *machine, afs_uint32 flags)
7791 smb_username_t *unp;
7794 unp = smb_FindUserByName(usern, machine, flags);
7796 lock_ObtainMutex(&unp->mx);
7797 unp->userp = cm_NewUser();
7798 lock_ReleaseMutex(&unp->mx);
7799 osi_Log2(smb_logp,"smb_FindCMUserByName New user name[%s] machine[%s]",osi_LogSaveString(smb_logp,usern),osi_LogSaveString(smb_logp,machine));
7801 osi_Log2(smb_logp,"smb_FindCMUserByName Not found name[%s] machine[%s]",osi_LogSaveString(smb_logp,usern),osi_LogSaveString(smb_logp,machine));
7805 smb_ReleaseUsername(unp);