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 const char **smb_ExecutableExtensions = NULL;
44 /* retrieve a held reference to a user structure corresponding to an incoming
46 cm_user_t *smb_GetTran2User(smb_vc_t *vcp, smb_tran2Packet_t *inp)
51 uidp = smb_FindUID(vcp, inp->uid, 0);
55 up = smb_GetUserFromUID(uidp);
63 * Return boolean specifying if the path name is thought to be an
64 * executable file. For now .exe or .dll.
66 afs_uint32 smb_IsExecutableFileName(const char *name)
70 if ( smb_ExecutableExtensions == NULL || name == NULL)
75 for ( i=0; smb_ExecutableExtensions[i]; i++) {
76 j = len - strlen(smb_ExecutableExtensions[i]);
77 if (_stricmp(smb_ExecutableExtensions[i], &name[j]) == 0)
85 * Return extended attributes.
86 * Right now, we aren't using any of the "new" bits, so this looks exactly
87 * like smb_Attributes() (see smb.c).
89 unsigned long smb_ExtAttributes(cm_scache_t *scp)
93 if (scp->fileType == CM_SCACHETYPE_DIRECTORY ||
94 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
95 scp->fileType == CM_SCACHETYPE_INVALID)
97 attrs = SMB_ATTR_DIRECTORY;
98 #ifdef SPECIAL_FOLDERS
99 attrs |= SMB_ATTR_SYSTEM; /* FILE_ATTRIBUTE_SYSTEM */
100 #endif /* SPECIAL_FOLDERS */
101 } else if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
102 attrs = SMB_ATTR_DIRECTORY | SMB_ATTR_SPARSE_FILE;
106 * We used to mark a file RO if it was in an RO volume, but that
107 * turns out to be impolitic in NT. See defect 10007.
110 if ((scp->unixModeBits & 0222) == 0 || (scp->flags & CM_SCACHEFLAG_RO))
111 attrs |= SMB_ATTR_READONLY; /* Read-only */
113 if ((scp->unixModeBits & 0222) == 0)
114 attrs |= SMB_ATTR_READONLY; /* Read-only */
118 attrs = SMB_ATTR_NORMAL; /* FILE_ATTRIBUTE_NORMAL */
123 int smb_V3IsStarMask(char *maskp)
127 while (tc = *maskp++)
128 if (tc == '?' || tc == '*' || tc == '<' || tc == '>')
133 unsigned char *smb_ParseString(unsigned char *inp, char **chainpp)
136 /* skip over null-terminated string */
137 *chainpp = inp + strlen(inp) + 1;
142 void OutputDebugF(char * format, ...) {
147 va_start( args, format );
148 len = _vscprintf( format, args ) // _vscprintf doesn't count
149 + 3; // terminating '\0' + '\n'
150 buffer = malloc( len * sizeof(char) );
151 vsprintf( buffer, format, args );
152 osi_Log0(smb_logp, osi_LogSaveString(smb_logp, buffer));
153 strcat(buffer, "\n");
154 OutputDebugString(buffer);
158 void OutputDebugHexDump(unsigned char * buffer, int len) {
161 static char tr[16] = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
163 OutputDebugF("Hexdump length [%d]",len);
165 for (i=0;i<len;i++) {
168 osi_Log0(smb_logp, osi_LogSaveString(smb_logp, buf));
170 OutputDebugString(buf);
172 sprintf(buf,"%5x",i);
173 memset(buf+5,' ',80);
178 j = j*3 + 7 + ((j>7)?1:0);
181 buf[j] = tr[k / 16]; buf[j+1] = tr[k % 16];
184 j = j + 56 + ((j>7)?1:0) + pcts;
186 buf[j] = (k>32 && k<127)?k:'.';
193 osi_Log0(smb_logp, osi_LogSaveString(smb_logp, buf));
195 OutputDebugString(buf);
199 #define SMB_EXT_SEC_PACKAGE_NAME "Negotiate"
201 void smb_NegotiateExtendedSecurity(void ** secBlob, int * secBlobLength) {
202 SECURITY_STATUS status, istatus;
203 CredHandle creds = {0,0};
205 SecBufferDesc secOut;
213 OutputDebugF("Negotiating Extended Security");
215 status = AcquireCredentialsHandle( NULL,
216 SMB_EXT_SEC_PACKAGE_NAME,
225 if (status != SEC_E_OK) {
226 /* Really bad. We return an empty security blob */
227 OutputDebugF("AcquireCredentialsHandle failed with %lX", status);
232 secOut.pBuffers = &secTok;
233 secOut.ulVersion = SECBUFFER_VERSION;
235 secTok.BufferType = SECBUFFER_TOKEN;
237 secTok.pvBuffer = NULL;
239 ctx.dwLower = ctx.dwUpper = 0;
241 status = AcceptSecurityContext( &creds,
244 ASC_REQ_CONNECTION | ASC_REQ_EXTENDED_ERROR | ASC_REQ_ALLOCATE_MEMORY,
245 SECURITY_NETWORK_DREP,
252 if (status == SEC_I_COMPLETE_NEEDED || status == SEC_I_COMPLETE_AND_CONTINUE) {
253 OutputDebugF("Completing token...");
254 istatus = CompleteAuthToken(&ctx, &secOut);
255 if ( istatus != SEC_E_OK )
256 OutputDebugF("Token completion failed: %x", istatus);
259 if (status == SEC_I_COMPLETE_AND_CONTINUE || status == SEC_I_CONTINUE_NEEDED) {
260 if (secTok.pvBuffer) {
261 *secBlobLength = secTok.cbBuffer;
262 *secBlob = malloc( secTok.cbBuffer );
263 memcpy(*secBlob, secTok.pvBuffer, secTok.cbBuffer );
266 if ( status != SEC_E_OK )
267 OutputDebugF("AcceptSecurityContext status != CONTINUE %lX", status);
270 /* Discard partial security context */
271 DeleteSecurityContext(&ctx);
273 if (secTok.pvBuffer) FreeContextBuffer( secTok.pvBuffer );
275 /* Discard credentials handle. We'll reacquire one when we get the session setup X */
276 FreeCredentialsHandle(&creds);
282 struct smb_ext_context {
289 long smb_AuthenticateUserExt(smb_vc_t * vcp, char * usern, char * secBlobIn, int secBlobInLength, char ** secBlobOut, int * secBlobOutLength) {
290 SECURITY_STATUS status, istatus;
294 SecBufferDesc secBufIn;
296 SecBufferDesc secBufOut;
299 struct smb_ext_context * secCtx = NULL;
300 struct smb_ext_context * newSecCtx = NULL;
301 void * assembledBlob = NULL;
302 int assembledBlobLength = 0;
305 OutputDebugF("In smb_AuthenticateUserExt");
308 *secBlobOutLength = 0;
310 if (vcp->flags & SMB_VCFLAG_AUTH_IN_PROGRESS) {
311 secCtx = vcp->secCtx;
312 lock_ObtainMutex(&vcp->mx);
313 vcp->flags &= ~SMB_VCFLAG_AUTH_IN_PROGRESS;
315 lock_ReleaseMutex(&vcp->mx);
319 OutputDebugF("Received incoming token:");
320 OutputDebugHexDump(secBlobIn,secBlobInLength);
324 OutputDebugF("Continuing with existing context.");
325 creds = secCtx->creds;
328 if (secCtx->partialToken) {
329 assembledBlobLength = secCtx->partialTokenLen + secBlobInLength;
330 assembledBlob = malloc(assembledBlobLength);
331 memcpy(assembledBlob,secCtx->partialToken, secCtx->partialTokenLen);
332 memcpy(((BYTE *)assembledBlob) + secCtx->partialTokenLen, secBlobIn, secBlobInLength);
335 status = AcquireCredentialsHandle( NULL,
336 SMB_EXT_SEC_PACKAGE_NAME,
345 if (status != SEC_E_OK) {
346 OutputDebugF("Can't acquire Credentials handle [%lX]", status);
347 code = CM_ERROR_BADPASSWORD; /* means "try again when I'm sober" */
355 secBufIn.cBuffers = 1;
356 secBufIn.pBuffers = &secTokIn;
357 secBufIn.ulVersion = SECBUFFER_VERSION;
359 secTokIn.BufferType = SECBUFFER_TOKEN;
361 secTokIn.cbBuffer = assembledBlobLength;
362 secTokIn.pvBuffer = assembledBlob;
364 secTokIn.cbBuffer = secBlobInLength;
365 secTokIn.pvBuffer = secBlobIn;
368 secBufOut.cBuffers = 1;
369 secBufOut.pBuffers = &secTokOut;
370 secBufOut.ulVersion = SECBUFFER_VERSION;
372 secTokOut.BufferType = SECBUFFER_TOKEN;
373 secTokOut.cbBuffer = 0;
374 secTokOut.pvBuffer = NULL;
376 status = AcceptSecurityContext( &creds,
377 ((secCtx)?&ctx:NULL),
379 ASC_REQ_CONNECTION | ASC_REQ_EXTENDED_ERROR | ASC_REQ_ALLOCATE_MEMORY,
380 SECURITY_NETWORK_DREP,
387 if (status == SEC_I_COMPLETE_NEEDED || status == SEC_I_COMPLETE_AND_CONTINUE) {
388 OutputDebugF("Completing token...");
389 istatus = CompleteAuthToken(&ctx, &secBufOut);
390 if ( istatus != SEC_E_OK )
391 OutputDebugF("Token completion failed: %lX", istatus);
394 if (status == SEC_I_COMPLETE_AND_CONTINUE || status == SEC_I_CONTINUE_NEEDED) {
395 OutputDebugF("Continue needed");
397 newSecCtx = malloc(sizeof(*newSecCtx));
399 newSecCtx->creds = creds;
400 newSecCtx->ctx = ctx;
401 newSecCtx->partialToken = NULL;
402 newSecCtx->partialTokenLen = 0;
404 lock_ObtainMutex( &vcp->mx );
405 vcp->flags |= SMB_VCFLAG_AUTH_IN_PROGRESS;
406 vcp->secCtx = newSecCtx;
407 lock_ReleaseMutex( &vcp->mx );
409 code = CM_ERROR_GSSCONTINUE;
412 if ((status == SEC_I_COMPLETE_NEEDED || status == SEC_E_OK ||
413 status == SEC_I_COMPLETE_AND_CONTINUE || status == SEC_I_CONTINUE_NEEDED) &&
414 secTokOut.pvBuffer) {
415 OutputDebugF("Need to send token back to client");
417 *secBlobOutLength = secTokOut.cbBuffer;
418 *secBlobOut = malloc(secTokOut.cbBuffer);
419 memcpy(*secBlobOut, secTokOut.pvBuffer, secTokOut.cbBuffer);
421 OutputDebugF("Outgoing token:");
422 OutputDebugHexDump(*secBlobOut,*secBlobOutLength);
423 } else if (status == SEC_E_INCOMPLETE_MESSAGE) {
424 OutputDebugF("Incomplete message");
426 newSecCtx = malloc(sizeof(*newSecCtx));
428 newSecCtx->creds = creds;
429 newSecCtx->ctx = ctx;
430 newSecCtx->partialToken = malloc(secTokOut.cbBuffer);
431 memcpy(newSecCtx->partialToken, secTokOut.pvBuffer, secTokOut.cbBuffer);
432 newSecCtx->partialTokenLen = secTokOut.cbBuffer;
434 lock_ObtainMutex( &vcp->mx );
435 vcp->flags |= SMB_VCFLAG_AUTH_IN_PROGRESS;
436 vcp->secCtx = newSecCtx;
437 lock_ReleaseMutex( &vcp->mx );
439 code = CM_ERROR_GSSCONTINUE;
442 if (status == SEC_E_OK || status == SEC_I_COMPLETE_NEEDED) {
444 SecPkgContext_Names names;
446 OutputDebugF("Authentication completed");
447 OutputDebugF("Returned flags : [%lX]", flags);
449 if (!QueryContextAttributes(&ctx, SECPKG_ATTR_NAMES, &names)) {
450 OutputDebugF("Received name [%s]", names.sUserName);
451 strcpy(usern, names.sUserName);
452 strlwr(usern); /* in tandem with smb_GetNormalizedUsername */
453 FreeContextBuffer(names.sUserName);
455 /* Force the user to retry if the context is invalid */
456 OutputDebugF("QueryContextAttributes Names failed [%x]", GetLastError());
457 code = CM_ERROR_BADPASSWORD;
461 case SEC_E_INVALID_TOKEN:
462 OutputDebugF("Returning bad password :: INVALID_TOKEN");
464 case SEC_E_INVALID_HANDLE:
465 OutputDebugF("Returning bad password :: INVALID_HANDLE");
467 case SEC_E_LOGON_DENIED:
468 OutputDebugF("Returning bad password :: LOGON_DENIED");
470 case SEC_E_UNKNOWN_CREDENTIALS:
471 OutputDebugF("Returning bad password :: UNKNOWN_CREDENTIALS");
473 case SEC_E_NO_CREDENTIALS:
474 OutputDebugF("Returning bad password :: NO_CREDENTIALS");
476 case SEC_E_CONTEXT_EXPIRED:
477 OutputDebugF("Returning bad password :: CONTEXT_EXPIRED");
479 case SEC_E_INCOMPLETE_CREDENTIALS:
480 OutputDebugF("Returning bad password :: INCOMPLETE_CREDENTIALS");
482 case SEC_E_WRONG_PRINCIPAL:
483 OutputDebugF("Returning bad password :: WRONG_PRINCIPAL");
485 case SEC_E_TIME_SKEW:
486 OutputDebugF("Returning bad password :: TIME_SKEW");
489 OutputDebugF("Returning bad password :: Status == %lX", status);
491 code = CM_ERROR_BADPASSWORD;
495 if (secCtx->partialToken) free(secCtx->partialToken);
503 if (secTokOut.pvBuffer)
504 FreeContextBuffer(secTokOut.pvBuffer);
506 if (code != CM_ERROR_GSSCONTINUE) {
507 DeleteSecurityContext(&ctx);
508 FreeCredentialsHandle(&creds);
516 #define P_RESP_LEN 128
518 /* LsaLogonUser expects input parameters to be in a contiguous block of memory.
519 So put stuff in a struct. */
520 struct Lm20AuthBlob {
521 MSV1_0_LM20_LOGON lmlogon;
522 BYTE ciResponse[P_RESP_LEN]; /* Unicode representation */
523 BYTE csResponse[P_RESP_LEN]; /* ANSI representation */
524 WCHAR accountNameW[P_LEN];
525 WCHAR primaryDomainW[P_LEN];
526 WCHAR workstationW[MAX_COMPUTERNAME_LENGTH + 1];
527 TOKEN_GROUPS tgroups;
528 TOKEN_SOURCE tsource;
531 long smb_AuthenticateUserLM(smb_vc_t *vcp, char * accountName, char * primaryDomain, char * ciPwd, unsigned ciPwdLength, char * csPwd, unsigned csPwdLength)
534 struct Lm20AuthBlob lmAuth;
535 PMSV1_0_LM20_LOGON_PROFILE lmprofilep;
536 QUOTA_LIMITS quotaLimits;
538 ULONG lmprofilepSize;
542 OutputDebugF("In smb_AuthenticateUser for user [%s] domain [%s]", accountName, primaryDomain);
543 OutputDebugF("ciPwdLength is %d and csPwdLength is %d", ciPwdLength, csPwdLength);
545 if (ciPwdLength > P_RESP_LEN || csPwdLength > P_RESP_LEN) {
546 OutputDebugF("ciPwdLength or csPwdLength is too long");
547 return CM_ERROR_BADPASSWORD;
550 memset(&lmAuth,0,sizeof(lmAuth));
552 lmAuth.lmlogon.MessageType = MsV1_0NetworkLogon;
554 lmAuth.lmlogon.LogonDomainName.Buffer = lmAuth.primaryDomainW;
555 mbstowcs(lmAuth.primaryDomainW, primaryDomain, P_LEN);
556 lmAuth.lmlogon.LogonDomainName.Length = (USHORT)(wcslen(lmAuth.primaryDomainW) * sizeof(WCHAR));
557 lmAuth.lmlogon.LogonDomainName.MaximumLength = P_LEN * sizeof(WCHAR);
559 lmAuth.lmlogon.UserName.Buffer = lmAuth.accountNameW;
560 mbstowcs(lmAuth.accountNameW, accountName, P_LEN);
561 lmAuth.lmlogon.UserName.Length = (USHORT)(wcslen(lmAuth.accountNameW) * sizeof(WCHAR));
562 lmAuth.lmlogon.UserName.MaximumLength = P_LEN * sizeof(WCHAR);
564 lmAuth.lmlogon.Workstation.Buffer = lmAuth.workstationW;
565 lmAuth.lmlogon.Workstation.MaximumLength = (MAX_COMPUTERNAME_LENGTH + 1) * sizeof(WCHAR);
566 size = MAX_COMPUTERNAME_LENGTH + 1;
567 GetComputerNameW(lmAuth.workstationW, &size);
568 lmAuth.lmlogon.Workstation.Length = (USHORT)(wcslen(lmAuth.workstationW) * sizeof(WCHAR));
570 memcpy(lmAuth.lmlogon.ChallengeToClient, vcp->encKey, MSV1_0_CHALLENGE_LENGTH);
572 lmAuth.lmlogon.CaseInsensitiveChallengeResponse.Buffer = lmAuth.ciResponse;
573 lmAuth.lmlogon.CaseInsensitiveChallengeResponse.Length = ciPwdLength;
574 lmAuth.lmlogon.CaseInsensitiveChallengeResponse.MaximumLength = P_RESP_LEN;
575 memcpy(lmAuth.ciResponse, ciPwd, ciPwdLength);
577 lmAuth.lmlogon.CaseSensitiveChallengeResponse.Buffer = lmAuth.csResponse;
578 lmAuth.lmlogon.CaseSensitiveChallengeResponse.Length = csPwdLength;
579 lmAuth.lmlogon.CaseSensitiveChallengeResponse.MaximumLength = P_RESP_LEN;
580 memcpy(lmAuth.csResponse, csPwd, csPwdLength);
582 lmAuth.lmlogon.ParameterControl = 0;
584 lmAuth.tgroups.GroupCount = 0;
585 lmAuth.tgroups.Groups[0].Sid = NULL;
586 lmAuth.tgroups.Groups[0].Attributes = 0;
588 lmAuth.tsource.SourceIdentifier.HighPart = (DWORD)((LONG_PTR)vcp << 32);
589 lmAuth.tsource.SourceIdentifier.LowPart = (DWORD)((LONG_PTR)vcp & _UI32_MAX);
590 strcpy(lmAuth.tsource.SourceName,"OpenAFS"); /* 8 char limit */
592 nts = LsaLogonUser( smb_lsaHandle,
607 if (nts != STATUS_SUCCESS || ntsEx != STATUS_SUCCESS)
608 osi_Log2(smb_logp,"LsaLogonUser failure: nts %u ntsEx %u",
611 OutputDebugF("Return from LsaLogonUser is 0x%lX", nts);
612 OutputDebugF("Extended status is 0x%lX", ntsEx);
614 if (nts == ERROR_SUCCESS) {
616 LsaFreeReturnBuffer(lmprofilep);
617 CloseHandle(lmToken);
621 if (nts == 0xC000015BL)
622 return CM_ERROR_BADLOGONTYPE;
623 else /* our catchall is a bad password though we could be more specific */
624 return CM_ERROR_BADPASSWORD;
628 /* The buffer pointed to by usern is assumed to be at least SMB_MAX_USERNAME_LENGTH bytes */
629 long smb_GetNormalizedUsername(char * usern, const char * accountName, const char * domainName)
634 /* check if we have sane input */
635 if ((strlen(accountName) + strlen(domainName) + 1) > SMB_MAX_USERNAME_LENGTH)
638 /* we could get : [accountName][domainName]
644 atsign = strchr(accountName, '@');
646 if (atsign) /* [user@domain][] -> [user@domain][domain] */
651 /* if for some reason the client doesn't know what domain to use,
652 it will either return an empty string or a '?' */
653 if (!domain[0] || domain[0] == '?')
654 /* Empty domains and empty usernames are usually sent from tokenless contexts.
655 This way such logins will get an empty username (easy to check). I don't know
656 when a non-empty username would be supplied with an anonymous domain, but *shrug* */
657 strcpy(usern,accountName);
659 /* TODO: what about WIN.MIT.EDU\user vs. WIN\user? */
660 strcpy(usern,domain);
663 strncat(usern,accountName,atsign - accountName);
665 strcat(usern,accountName);
673 /* When using SMB auth, all SMB sessions have to pass through here
674 * first to authenticate the user.
676 * Caveat: If not using SMB auth, the protocol does not require
677 * sending a session setup packet, which means that we can't rely on a
678 * UID in subsequent packets. Though in practice we get one anyway.
680 long smb_ReceiveV3SessionSetupX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
684 unsigned short newUid;
685 unsigned long caps = 0;
689 char usern[SMB_MAX_USERNAME_LENGTH];
690 char *secBlobOut = NULL;
691 int secBlobOutLength = 0;
693 /* Check for bad conns */
694 if (vcp->flags & SMB_VCFLAG_REMOTECONN)
695 return CM_ERROR_REMOTECONN;
697 if (vcp->flags & SMB_VCFLAG_USENT) {
698 if (smb_authType == SMB_AUTH_EXTENDED) {
699 /* extended authentication */
703 OutputDebugF("NT Session Setup: Extended");
705 if (!(vcp->flags & SMB_VCFLAG_SESSX_RCVD)) {
706 caps = smb_GetSMBParm(inp,10) | (((unsigned long) smb_GetSMBParm(inp,11)) << 16);
709 secBlobInLength = smb_GetSMBParm(inp, 7);
710 secBlobIn = smb_GetSMBData(inp, NULL);
712 code = smb_AuthenticateUserExt(vcp, usern, secBlobIn, secBlobInLength, &secBlobOut, &secBlobOutLength);
714 if (code == CM_ERROR_GSSCONTINUE) {
715 smb_SetSMBParm(outp, 2, 0);
716 smb_SetSMBParm(outp, 3, secBlobOutLength);
717 smb_SetSMBDataLength(outp, secBlobOutLength + smb_ServerOSLength + smb_ServerLanManagerLength + smb_ServerDomainNameLength);
718 tp = smb_GetSMBData(outp, NULL);
719 if (secBlobOutLength) {
720 memcpy(tp, secBlobOut, secBlobOutLength);
722 tp += secBlobOutLength;
724 memcpy(tp,smb_ServerOS,smb_ServerOSLength);
725 tp += smb_ServerOSLength;
726 memcpy(tp,smb_ServerLanManager,smb_ServerLanManagerLength);
727 tp += smb_ServerLanManagerLength;
728 memcpy(tp,smb_ServerDomainName,smb_ServerDomainNameLength);
729 tp += smb_ServerDomainNameLength;
732 /* TODO: handle return code and continue auth. Also free secBlobOut if applicable. */
734 unsigned ciPwdLength, csPwdLength;
740 if (smb_authType == SMB_AUTH_NTLM)
741 OutputDebugF("NT Session Setup: NTLM");
743 OutputDebugF("NT Session Setup: None");
745 /* TODO: parse for extended auth as well */
746 ciPwdLength = smb_GetSMBParm(inp, 7); /* case insensitive password length */
747 csPwdLength = smb_GetSMBParm(inp, 8); /* case sensitive password length */
749 tp = smb_GetSMBData(inp, &datalen);
751 OutputDebugF("Session packet data size [%d]",datalen);
758 accountName = smb_ParseString(tp, &tp);
759 primaryDomain = smb_ParseString(tp, NULL);
761 OutputDebugF("Account Name: %s",accountName);
762 OutputDebugF("Primary Domain: %s", primaryDomain);
763 OutputDebugF("Case Sensitive Password: %s", csPwd && csPwd[0] ? "yes" : "no");
764 OutputDebugF("Case Insensitive Password: %s", ciPwd && ciPwd[0] ? "yes" : "no");
766 if (smb_GetNormalizedUsername(usern, accountName, primaryDomain)) {
767 /* shouldn't happen */
768 code = CM_ERROR_BADSMB;
769 goto after_read_packet;
772 /* capabilities are only valid for first session packet */
773 if (!(vcp->flags & SMB_VCFLAG_SESSX_RCVD)) {
774 caps = smb_GetSMBParm(inp, 11) | (((unsigned long)smb_GetSMBParm(inp, 12)) << 16);
777 if (smb_authType == SMB_AUTH_NTLM) {
778 code = smb_AuthenticateUserLM(vcp, accountName, primaryDomain, ciPwd, ciPwdLength, csPwd, csPwdLength);
780 OutputDebugF("LM authentication failed [%d]", code);
782 OutputDebugF("LM authentication succeeded");
786 unsigned ciPwdLength;
791 switch ( smb_authType ) {
792 case SMB_AUTH_EXTENDED:
793 OutputDebugF("V3 Session Setup: Extended");
796 OutputDebugF("V3 Session Setup: NTLM");
799 OutputDebugF("V3 Session Setup: None");
801 ciPwdLength = smb_GetSMBParm(inp, 7);
802 tp = smb_GetSMBData(inp, NULL);
806 accountName = smb_ParseString(tp, &tp);
807 primaryDomain = smb_ParseString(tp, NULL);
809 OutputDebugF("Account Name: %s",accountName);
810 OutputDebugF("Primary Domain: %s", primaryDomain);
811 OutputDebugF("Case Insensitive Password: %s", ciPwd && ciPwd[0] ? "yes" : "no");
813 if ( smb_GetNormalizedUsername(usern, accountName, primaryDomain)) {
814 /* shouldn't happen */
815 code = CM_ERROR_BADSMB;
816 goto after_read_packet;
819 /* even if we wanted extended auth, if we only negotiated V3, we have to fallback
822 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
823 code = smb_AuthenticateUserLM(vcp,accountName,primaryDomain,ciPwd,ciPwdLength,"",0);
825 OutputDebugF("LM authentication failed [%d]", code);
827 OutputDebugF("LM authentication succeeded");
832 /* note down that we received a session setup X and set the capabilities flag */
833 if (!(vcp->flags & SMB_VCFLAG_SESSX_RCVD)) {
834 lock_ObtainMutex(&vcp->mx);
835 vcp->flags |= SMB_VCFLAG_SESSX_RCVD;
836 /* for the moment we can only deal with NTSTATUS */
837 if (caps & NTNEGOTIATE_CAPABILITY_NTSTATUS) {
838 vcp->flags |= SMB_VCFLAG_STATUS32;
840 lock_ReleaseMutex(&vcp->mx);
843 /* code would be non-zero if there was an authentication failure.
844 Ideally we would like to invalidate the uid for this session or break
845 early to avoid accidently stealing someone else's tokens. */
851 OutputDebugF("Received username=[%s]", usern);
853 /* On Windows 2000, this function appears to be called more often than
854 it is expected to be called. This resulted in multiple smb_user_t
855 records existing all for the same user session which results in all
856 of the users tokens disappearing.
858 To avoid this problem, we look for an existing smb_user_t record
859 based on the users name, and use that one if we find it.
862 uidp = smb_FindUserByNameThisSession(vcp, usern);
863 if (uidp) { /* already there, so don't create a new one */
865 newUid = uidp->userID;
866 osi_Log3(smb_logp,"smb_ReceiveV3SessionSetupX FindUserByName:Lana[%d],lsn[%d],userid[%d]",
867 vcp->lana,vcp->lsn,newUid);
868 smb_ReleaseUID(uidp);
873 /* do a global search for the username/machine name pair */
874 unp = smb_FindUserByName(usern, vcp->rname, SMB_FLAG_CREATE);
875 lock_ObtainMutex(&unp->mx);
876 if (unp->flags & SMB_USERNAMEFLAG_AFSLOGON) {
877 /* clear the afslogon flag so that the tickets can now
878 * be freed when the refCount returns to zero.
880 unp->flags &= ~SMB_USERNAMEFLAG_AFSLOGON;
882 lock_ReleaseMutex(&unp->mx);
884 /* Create a new UID and cm_user_t structure */
887 userp = cm_NewUser();
888 cm_HoldUserVCRef(userp);
889 lock_ObtainMutex(&vcp->mx);
890 if (!vcp->uidCounter)
891 vcp->uidCounter++; /* handle unlikely wraparounds */
892 newUid = (strlen(usern)==0)?0:vcp->uidCounter++;
893 lock_ReleaseMutex(&vcp->mx);
895 /* Create a new smb_user_t structure and connect them up */
896 lock_ObtainMutex(&unp->mx);
898 lock_ReleaseMutex(&unp->mx);
900 uidp = smb_FindUID(vcp, newUid, SMB_FLAG_CREATE);
902 lock_ObtainMutex(&uidp->mx);
904 osi_Log4(smb_logp,"smb_ReceiveV3SessionSetupX MakeNewUser:VCP[%p],Lana[%d],lsn[%d],userid[%d]",vcp,vcp->lana,vcp->lsn,newUid);
905 lock_ReleaseMutex(&uidp->mx);
906 smb_ReleaseUID(uidp);
910 /* Return UID to the client */
911 ((smb_t *)outp)->uid = newUid;
912 /* Also to the next chained message */
913 ((smb_t *)inp)->uid = newUid;
915 osi_Log3(smb_logp, "SMB3 session setup name %s creating ID %d%s",
916 osi_LogSaveString(smb_logp, usern), newUid, osi_LogSaveString(smb_logp, s1));
918 smb_SetSMBParm(outp, 2, 0);
920 if (vcp->flags & SMB_VCFLAG_USENT) {
921 if (smb_authType == SMB_AUTH_EXTENDED) {
922 smb_SetSMBParm(outp, 3, secBlobOutLength);
923 smb_SetSMBDataLength(outp, secBlobOutLength + smb_ServerOSLength + smb_ServerLanManagerLength + smb_ServerDomainNameLength);
924 tp = smb_GetSMBData(outp, NULL);
925 if (secBlobOutLength) {
926 memcpy(tp, secBlobOut, secBlobOutLength);
928 tp += secBlobOutLength;
930 memcpy(tp,smb_ServerOS,smb_ServerOSLength);
931 tp += smb_ServerOSLength;
932 memcpy(tp,smb_ServerLanManager,smb_ServerLanManagerLength);
933 tp += smb_ServerLanManagerLength;
934 memcpy(tp,smb_ServerDomainName,smb_ServerDomainNameLength);
935 tp += smb_ServerDomainNameLength;
937 smb_SetSMBDataLength(outp, 0);
940 if (smb_authType == SMB_AUTH_EXTENDED) {
941 smb_SetSMBDataLength(outp, smb_ServerOSLength + smb_ServerLanManagerLength + smb_ServerDomainNameLength);
942 tp = smb_GetSMBData(outp, NULL);
943 memcpy(tp,smb_ServerOS,smb_ServerOSLength);
944 tp += smb_ServerOSLength;
945 memcpy(tp,smb_ServerLanManager,smb_ServerLanManagerLength);
946 tp += smb_ServerLanManagerLength;
947 memcpy(tp,smb_ServerDomainName,smb_ServerDomainNameLength);
948 tp += smb_ServerDomainNameLength;
950 smb_SetSMBDataLength(outp, 0);
957 long smb_ReceiveV3UserLogoffX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
961 /* find the tree and free it */
962 uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
964 smb_username_t * unp;
966 osi_Log2(smb_logp, "SMB3 user logoffX uid %d name %s", uidp->userID,
967 osi_LogSaveString(smb_logp, (uidp->unp) ? uidp->unp->name: " "));
969 lock_ObtainMutex(&uidp->mx);
970 uidp->flags |= SMB_USERFLAG_DELETE;
972 * it doesn't get deleted right away
973 * because the vcp points to it
976 lock_ReleaseMutex(&uidp->mx);
979 /* we can't do this. we get logoff messages prior to a session
980 * disconnect even though it doesn't mean the user is logging out.
981 * we need to create a new pioctl and EventLogoff handler to set
982 * SMB_USERNAMEFLAG_LOGOFF.
984 if (unp && smb_LogoffTokenTransfer) {
985 lock_ObtainMutex(&unp->mx);
986 unp->flags |= SMB_USERNAMEFLAG_LOGOFF;
987 unp->last_logoff_t = osi_Time() + smb_LogoffTransferTimeout;
988 lock_ReleaseMutex(&unp->mx);
992 smb_ReleaseUID(uidp);
995 osi_Log0(smb_logp, "SMB3 user logoffX");
997 smb_SetSMBDataLength(outp, 0);
1001 #define SMB_SUPPORT_SEARCH_BITS 0x0001
1002 #define SMB_SHARE_IS_IN_DFS 0x0002
1004 long smb_ReceiveV3TreeConnectX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
1007 smb_user_t *uidp = NULL;
1008 unsigned short newTid;
1009 char shareName[AFSPATHMAX];
1016 cm_user_t *userp = NULL;
1019 osi_Log0(smb_logp, "SMB3 receive tree connect");
1021 /* parse input parameters */
1022 tp = smb_GetSMBData(inp, NULL);
1023 passwordp = smb_ParseString(tp, &tp);
1024 pathp = smb_ParseString(tp, &tp);
1025 if (smb_StoreAnsiFilenames)
1026 OemToChar(pathp,pathp);
1027 servicep = smb_ParseString(tp, &tp);
1029 tp = strrchr(pathp, '\\');
1031 return CM_ERROR_BADSMB;
1033 strcpy(shareName, tp+1);
1035 osi_Log2(smb_logp, "Tree connect pathp[%s] shareName[%s]",
1036 osi_LogSaveString(smb_logp, pathp),
1037 osi_LogSaveString(smb_logp, shareName));
1039 if (strcmp(servicep, "IPC") == 0 || strcmp(shareName, "IPC$") == 0) {
1041 osi_Log0(smb_logp, "TreeConnectX connecting to IPC$");
1044 return CM_ERROR_NOIPC;
1048 uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
1050 userp = smb_GetUserFromUID(uidp);
1052 lock_ObtainMutex(&vcp->mx);
1053 newTid = vcp->tidCounter++;
1054 lock_ReleaseMutex(&vcp->mx);
1056 tidp = smb_FindTID(vcp, newTid, SMB_FLAG_CREATE);
1059 if (!strcmp(shareName, "*."))
1060 strcpy(shareName, "all");
1061 shareFound = smb_FindShare(vcp, uidp, shareName, &sharePath);
1064 smb_ReleaseUID(uidp);
1065 smb_ReleaseTID(tidp);
1066 return CM_ERROR_BADSHARENAME;
1069 if (vcp->flags & SMB_VCFLAG_USENT)
1071 int policy = smb_FindShareCSCPolicy(shareName);
1072 smb_SetSMBParm(outp, 2, SMB_SUPPORT_SEARCH_BITS |
1074 SMB_SHARE_IS_IN_DFS |
1079 smb_SetSMBParm(outp, 2, 0);
1083 smb_ReleaseUID(uidp);
1085 lock_ObtainMutex(&tidp->mx);
1086 tidp->userp = userp;
1087 tidp->pathname = sharePath;
1089 tidp->flags |= SMB_TIDFLAG_IPC;
1090 lock_ReleaseMutex(&tidp->mx);
1091 smb_ReleaseTID(tidp);
1093 ((smb_t *)outp)->tid = newTid;
1094 ((smb_t *)inp)->tid = newTid;
1095 tp = smb_GetSMBData(outp, NULL);
1097 /* XXX - why is this a drive letter? */
1105 smb_SetSMBDataLength(outp, 7);
1108 smb_SetSMBDataLength(outp, 4);
1111 osi_Log1(smb_logp, "SMB3 tree connect created ID %d", newTid);
1115 /* must be called with global tran lock held */
1116 smb_tran2Packet_t *smb_FindTran2Packet(smb_vc_t *vcp, smb_packet_t *inp)
1118 smb_tran2Packet_t *tp;
1121 smbp = (smb_t *) inp->data;
1122 for (tp = smb_tran2AssemblyQueuep; tp; tp = (smb_tran2Packet_t *) osi_QNext(&tp->q)) {
1123 if (tp->vcp == vcp && tp->mid == smbp->mid && tp->tid == smbp->tid)
1129 smb_tran2Packet_t *smb_NewTran2Packet(smb_vc_t *vcp, smb_packet_t *inp,
1130 int totalParms, int totalData)
1132 smb_tran2Packet_t *tp;
1135 smbp = (smb_t *) inp->data;
1136 tp = malloc(sizeof(*tp));
1137 memset(tp, 0, sizeof(*tp));
1140 tp->curData = tp->curParms = 0;
1141 tp->totalData = totalData;
1142 tp->totalParms = totalParms;
1143 tp->tid = smbp->tid;
1144 tp->mid = smbp->mid;
1145 tp->uid = smbp->uid;
1146 tp->pid = smbp->pid;
1147 tp->res[0] = smbp->res[0];
1148 osi_QAdd((osi_queue_t **)&smb_tran2AssemblyQueuep, &tp->q);
1149 if (totalParms != 0)
1150 tp->parmsp = malloc(totalParms);
1152 tp->datap = malloc(totalData);
1153 if (smbp->com == 0x25 || smbp->com == 0x26)
1156 tp->opcode = smb_GetSMBParm(inp, 14);
1159 tp->flags |= SMB_TRAN2PFLAG_ALLOC;
1163 smb_tran2Packet_t *smb_GetTran2ResponsePacket(smb_vc_t *vcp,
1164 smb_tran2Packet_t *inp, smb_packet_t *outp,
1165 int totalParms, int totalData)
1167 smb_tran2Packet_t *tp;
1168 unsigned short parmOffset;
1169 unsigned short dataOffset;
1170 unsigned short dataAlign;
1172 tp = malloc(sizeof(*tp));
1173 memset(tp, 0, sizeof(*tp));
1176 tp->curData = tp->curParms = 0;
1177 tp->totalData = totalData;
1178 tp->totalParms = totalParms;
1179 tp->oldTotalParms = totalParms;
1184 tp->res[0] = inp->res[0];
1185 tp->opcode = inp->opcode;
1189 * We calculate where the parameters and data will start.
1190 * This calculation must parallel the calculation in
1191 * smb_SendTran2Packet.
1194 parmOffset = 10*2 + 35;
1195 parmOffset++; /* round to even */
1196 tp->parmsp = (unsigned short *) (outp->data + parmOffset);
1198 dataOffset = parmOffset + totalParms;
1199 dataAlign = dataOffset & 2; /* quad-align */
1200 dataOffset += dataAlign;
1201 tp->datap = outp->data + dataOffset;
1206 /* free a tran2 packet */
1207 void smb_FreeTran2Packet(smb_tran2Packet_t *t2p)
1210 smb_ReleaseVC(t2p->vcp);
1213 if (t2p->flags & SMB_TRAN2PFLAG_ALLOC) {
1222 /* called with a VC, an input packet to respond to, and an error code.
1223 * sends an error response.
1225 void smb_SendTran2Error(smb_vc_t *vcp, smb_tran2Packet_t *t2p,
1226 smb_packet_t *tp, long code)
1229 unsigned short errCode;
1230 unsigned char errClass;
1231 unsigned long NTStatus;
1233 if (vcp->flags & SMB_VCFLAG_STATUS32)
1234 smb_MapNTError(code, &NTStatus);
1236 smb_MapCoreError(code, vcp, &errCode, &errClass);
1238 smb_FormatResponsePacket(vcp, NULL, tp);
1239 smbp = (smb_t *) tp;
1241 /* We can handle long names */
1242 if (vcp->flags & SMB_VCFLAG_USENT)
1243 smbp->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
1245 /* now copy important fields from the tran 2 packet */
1246 smbp->com = t2p->com;
1247 smbp->tid = t2p->tid;
1248 smbp->mid = t2p->mid;
1249 smbp->pid = t2p->pid;
1250 smbp->uid = t2p->uid;
1251 smbp->res[0] = t2p->res[0];
1252 if (vcp->flags & SMB_VCFLAG_STATUS32) {
1253 smbp->rcls = (unsigned char) (NTStatus & 0xff);
1254 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
1255 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
1256 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
1257 smbp->flg2 |= SMB_FLAGS2_32BIT_STATUS;
1260 smbp->rcls = errClass;
1261 smbp->errLow = (unsigned char) (errCode & 0xff);
1262 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
1266 smb_SendPacket(vcp, tp);
1269 void smb_SendTran2Packet(smb_vc_t *vcp, smb_tran2Packet_t *t2p, smb_packet_t *tp)
1272 unsigned short parmOffset;
1273 unsigned short dataOffset;
1274 unsigned short totalLength;
1275 unsigned short dataAlign;
1278 smb_FormatResponsePacket(vcp, NULL, tp);
1279 smbp = (smb_t *) tp;
1281 /* We can handle long names */
1282 if (vcp->flags & SMB_VCFLAG_USENT)
1283 smbp->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
1285 /* now copy important fields from the tran 2 packet */
1286 smbp->com = t2p->com;
1287 smbp->tid = t2p->tid;
1288 smbp->mid = t2p->mid;
1289 smbp->pid = t2p->pid;
1290 smbp->uid = t2p->uid;
1291 smbp->res[0] = t2p->res[0];
1293 totalLength = 1 + t2p->totalData + t2p->totalParms;
1295 /* now add the core parameters (tran2 info) to the packet */
1296 smb_SetSMBParm(tp, 0, t2p->totalParms); /* parm bytes */
1297 smb_SetSMBParm(tp, 1, t2p->totalData); /* data bytes */
1298 smb_SetSMBParm(tp, 2, 0); /* reserved */
1299 smb_SetSMBParm(tp, 3, t2p->totalParms); /* parm bytes in this packet */
1300 parmOffset = 10*2 + 35; /* parm offset in packet */
1301 parmOffset++; /* round to even */
1302 smb_SetSMBParm(tp, 4, parmOffset); /* 11 parm words plus *
1303 * hdr, bcc and wct */
1304 smb_SetSMBParm(tp, 5, 0); /* parm displacement */
1305 smb_SetSMBParm(tp, 6, t2p->totalData); /* data in this packet */
1306 dataOffset = parmOffset + t2p->oldTotalParms;
1307 dataAlign = dataOffset & 2; /* quad-align */
1308 dataOffset += dataAlign;
1309 smb_SetSMBParm(tp, 7, dataOffset); /* offset of data */
1310 smb_SetSMBParm(tp, 8, 0); /* data displacement */
1311 smb_SetSMBParm(tp, 9, 0); /* low: setup word count *
1314 datap = smb_GetSMBData(tp, NULL);
1315 *datap++ = 0; /* we rounded to even */
1317 totalLength += dataAlign;
1318 smb_SetSMBDataLength(tp, totalLength);
1320 /* next, send the datagram */
1321 smb_SendPacket(vcp, tp);
1324 long smb_ReceiveV3Trans(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
1326 smb_tran2Packet_t *asp;
1339 /* We sometimes see 0 word count. What to do? */
1340 if (*inp->wctp == 0) {
1341 osi_Log0(smb_logp, "Transaction2 word count = 0");
1342 LogEvent(EVENTLOG_WARNING_TYPE, MSG_SMB_ZERO_TRANSACTION_COUNT);
1344 smb_SetSMBDataLength(outp, 0);
1345 smb_SendPacket(vcp, outp);
1349 totalParms = smb_GetSMBParm(inp, 0);
1350 totalData = smb_GetSMBParm(inp, 1);
1352 firstPacket = (inp->inCom == 0x25);
1354 /* find the packet we're reassembling */
1355 lock_ObtainWrite(&smb_globalLock);
1356 asp = smb_FindTran2Packet(vcp, inp);
1358 asp = smb_NewTran2Packet(vcp, inp, totalParms, totalData);
1360 lock_ReleaseWrite(&smb_globalLock);
1362 /* now merge in this latest packet; start by looking up offsets */
1364 parmDisp = dataDisp = 0;
1365 parmOffset = smb_GetSMBParm(inp, 10);
1366 dataOffset = smb_GetSMBParm(inp, 12);
1367 parmCount = smb_GetSMBParm(inp, 9);
1368 dataCount = smb_GetSMBParm(inp, 11);
1369 asp->maxReturnParms = smb_GetSMBParm(inp, 2);
1370 asp->maxReturnData = smb_GetSMBParm(inp, 3);
1372 osi_Log3(smb_logp, "SMB3 received Trans init packet total data %d, cur data %d, max return data %d",
1373 totalData, dataCount, asp->maxReturnData);
1376 parmDisp = smb_GetSMBParm(inp, 4);
1377 parmOffset = smb_GetSMBParm(inp, 3);
1378 dataDisp = smb_GetSMBParm(inp, 7);
1379 dataOffset = smb_GetSMBParm(inp, 6);
1380 parmCount = smb_GetSMBParm(inp, 2);
1381 dataCount = smb_GetSMBParm(inp, 5);
1383 osi_Log2(smb_logp, "SMB3 received Trans aux packet parms %d, data %d",
1384 parmCount, dataCount);
1387 /* now copy the parms and data */
1388 if ( asp->totalParms > 0 && parmCount != 0 )
1390 memcpy(((char *)asp->parmsp) + parmDisp, inp->data + parmOffset, parmCount);
1392 if ( asp->totalData > 0 && dataCount != 0 ) {
1393 memcpy(asp->datap + dataDisp, inp->data + dataOffset, dataCount);
1396 /* account for new bytes */
1397 asp->curData += dataCount;
1398 asp->curParms += parmCount;
1400 /* finally, if we're done, remove the packet from the queue and dispatch it */
1401 if (asp->totalParms > 0 &&
1402 asp->curParms > 0 &&
1403 asp->totalData <= asp->curData &&
1404 asp->totalParms <= asp->curParms) {
1405 /* we've received it all */
1406 lock_ObtainWrite(&smb_globalLock);
1407 osi_QRemove((osi_queue_t **) &smb_tran2AssemblyQueuep, &asp->q);
1408 lock_ReleaseWrite(&smb_globalLock);
1410 /* now dispatch it */
1411 rapOp = asp->parmsp[0];
1413 if ( rapOp >= 0 && rapOp < SMB_RAP_NOPCODES && smb_rapDispatchTable[rapOp].procp) {
1414 osi_Log4(smb_logp,"AFS Server - Dispatch-RAP %s vcp[%p] lana[%d] lsn[%d]",myCrt_RapDispatch(rapOp),vcp,vcp->lana,vcp->lsn);
1415 code = (*smb_rapDispatchTable[rapOp].procp)(vcp, asp, outp);
1416 osi_Log4(smb_logp,"AFS Server - Dispatch-RAP return code 0x%x vcp[%x] lana[%d] lsn[%d]",code,vcp,vcp->lana,vcp->lsn);
1419 osi_Log4(smb_logp,"AFS Server - Dispatch-RAP [INVALID] op[%x] vcp[%p] lana[%d] lsn[%d]", rapOp, vcp, vcp->lana, vcp->lsn);
1420 code = CM_ERROR_BADOP;
1423 /* if an error is returned, we're supposed to send an error packet,
1424 * otherwise the dispatched function already did the data sending.
1425 * We give dispatched proc the responsibility since it knows how much
1426 * space to allocate.
1429 smb_SendTran2Error(vcp, asp, outp, code);
1432 /* free the input tran 2 packet */
1433 smb_FreeTran2Packet(asp);
1435 else if (firstPacket) {
1436 /* the first packet in a multi-packet request, we need to send an
1437 * ack to get more data.
1439 smb_SetSMBDataLength(outp, 0);
1440 smb_SendPacket(vcp, outp);
1446 /* ANSI versions. The unicode versions support arbitrary length
1447 share names, but we don't support unicode yet. */
1449 typedef struct smb_rap_share_info_0 {
1450 char shi0_netname[13];
1451 } smb_rap_share_info_0_t;
1453 typedef struct smb_rap_share_info_1 {
1454 char shi1_netname[13];
1457 DWORD shi1_remark; /* char *shi1_remark; data offset */
1458 } smb_rap_share_info_1_t;
1460 typedef struct smb_rap_share_info_2 {
1461 char shi2_netname[13];
1463 unsigned short shi2_type;
1464 DWORD shi2_remark; /* char *shi2_remark; data offset */
1465 unsigned short shi2_permissions;
1466 unsigned short shi2_max_uses;
1467 unsigned short shi2_current_uses;
1468 DWORD shi2_path; /* char *shi2_path; data offset */
1469 unsigned short shi2_passwd[9];
1470 unsigned short shi2_pad2;
1471 } smb_rap_share_info_2_t;
1473 #define SMB_RAP_MAX_SHARES 512
1475 typedef struct smb_rap_share_list {
1478 smb_rap_share_info_0_t * shares;
1479 } smb_rap_share_list_t;
1481 int smb_rapCollectSharesProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp) {
1482 smb_rap_share_list_t * sp;
1487 if (name[0] == '.' && (!name[1] || (name[1] == '.' && !name[2])))
1488 return 0; /* skip over '.' and '..' */
1490 sp = (smb_rap_share_list_t *) vrockp;
1492 strncpy(sp->shares[sp->cShare].shi0_netname, name, 12);
1493 sp->shares[sp->cShare].shi0_netname[12] = 0;
1497 if (sp->cShare >= sp->maxShares)
1498 return CM_ERROR_STOPNOW;
1503 long smb_ReceiveRAPNetShareEnum(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1505 smb_tran2Packet_t *outp;
1506 unsigned short * tp;
1510 int outParmsTotal; /* total parameter bytes */
1511 int outDataTotal; /* total data bytes */
1514 DWORD allSubmount = 0;
1516 DWORD nRegShares = 0;
1517 DWORD nSharesRet = 0;
1519 HKEY hkSubmount = NULL;
1520 smb_rap_share_info_1_t * shares;
1523 char thisShare[AFSPATHMAX];
1527 smb_rap_share_list_t rootShares;
1532 tp = p->parmsp + 1; /* skip over function number (always 0) */
1533 (void) smb_ParseString((char *) tp, (char **) &tp); /* skip over parm descriptor */
1534 (void) smb_ParseString((char *) tp, (char **) &tp); /* skip over data descriptor */
1538 if (infoLevel != 1) {
1539 return CM_ERROR_INVAL;
1542 /* first figure out how many shares there are */
1543 rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY, 0,
1544 KEY_QUERY_VALUE, &hkParam);
1545 if (rv == ERROR_SUCCESS) {
1546 len = sizeof(allSubmount);
1547 rv = RegQueryValueEx(hkParam, "AllSubmount", NULL, NULL,
1548 (BYTE *) &allSubmount, &len);
1549 if (rv != ERROR_SUCCESS || allSubmount != 0) {
1552 RegCloseKey (hkParam);
1555 rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_OPENAFS_SUBKEY "\\Submounts",
1556 0, KEY_QUERY_VALUE, &hkSubmount);
1557 if (rv == ERROR_SUCCESS) {
1558 rv = RegQueryInfoKey(hkSubmount, NULL, NULL, NULL, NULL,
1559 NULL, NULL, &nRegShares, NULL, NULL, NULL, NULL);
1560 if (rv != ERROR_SUCCESS)
1566 /* fetch the root shares */
1567 rootShares.maxShares = SMB_RAP_MAX_SHARES;
1568 rootShares.cShare = 0;
1569 rootShares.shares = malloc( sizeof(smb_rap_share_info_0_t) * SMB_RAP_MAX_SHARES );
1573 userp = smb_GetTran2User(vcp,p);
1575 thyper.HighPart = 0;
1578 cm_HoldSCache(cm_data.rootSCachep);
1579 cm_ApplyDir(cm_data.rootSCachep, smb_rapCollectSharesProc, &rootShares, &thyper, userp, &req, NULL);
1580 cm_ReleaseSCache(cm_data.rootSCachep);
1582 cm_ReleaseUser(userp);
1584 nShares = (USHORT)(rootShares.cShare + nRegShares + allSubmount);
1586 #define REMARK_LEN 1
1587 outParmsTotal = 8; /* 4 dwords */
1588 outDataTotal = (sizeof(smb_rap_share_info_1_t) + REMARK_LEN) * nShares ;
1589 if(outDataTotal > bufsize) {
1590 nSharesRet = bufsize / (sizeof(smb_rap_share_info_1_t) + REMARK_LEN);
1591 outDataTotal = (sizeof(smb_rap_share_info_1_t) + REMARK_LEN) * nSharesRet;
1594 nSharesRet = nShares;
1597 outp = smb_GetTran2ResponsePacket(vcp, p, op, outParmsTotal, outDataTotal);
1599 /* now for the submounts */
1600 shares = (smb_rap_share_info_1_t *) outp->datap;
1601 cstrp = outp->datap + sizeof(smb_rap_share_info_1_t) * nSharesRet;
1603 memset(outp->datap, 0, (sizeof(smb_rap_share_info_1_t) + REMARK_LEN) * nSharesRet);
1606 strcpy( shares[cshare].shi1_netname, "all" );
1607 shares[cshare].shi1_remark = (DWORD)(cstrp - outp->datap);
1608 /* type and pad are zero already */
1614 for (dw=0; dw < nRegShares && cshare < nSharesRet; dw++) {
1615 len = sizeof(thisShare);
1616 rv = RegEnumValue(hkSubmount, dw, thisShare, &len, NULL, NULL, NULL, NULL);
1617 if (rv == ERROR_SUCCESS && strlen(thisShare) && (!allSubmount || stricmp(thisShare,"all"))) {
1618 strncpy(shares[cshare].shi1_netname, thisShare, sizeof(shares->shi1_netname)-1);
1619 shares[cshare].shi1_netname[sizeof(shares->shi1_netname)-1] = 0; /* unfortunate truncation */
1620 shares[cshare].shi1_remark = (DWORD)(cstrp - outp->datap);
1625 nShares--; /* uncount key */
1628 RegCloseKey(hkSubmount);
1631 nonrootShares = cshare;
1633 for (i=0; i < rootShares.cShare && cshare < nSharesRet; i++) {
1634 /* in case there are collisions with submounts, submounts have higher priority */
1635 for (j=0; j < nonrootShares; j++)
1636 if (!stricmp(shares[j].shi1_netname, rootShares.shares[i].shi0_netname))
1639 if (j < nonrootShares) {
1640 nShares--; /* uncount */
1644 strcpy(shares[cshare].shi1_netname, rootShares.shares[i].shi0_netname);
1645 shares[cshare].shi1_remark = (DWORD)(cstrp - outp->datap);
1650 outp->parmsp[0] = ((cshare == nShares)? ERROR_SUCCESS : ERROR_MORE_DATA);
1651 outp->parmsp[1] = 0;
1652 outp->parmsp[2] = cshare;
1653 outp->parmsp[3] = nShares;
1655 outp->totalData = (int)(cstrp - outp->datap);
1656 outp->totalParms = outParmsTotal;
1658 smb_SendTran2Packet(vcp, outp, op);
1659 smb_FreeTran2Packet(outp);
1661 free(rootShares.shares);
1666 long smb_ReceiveRAPNetShareGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1668 smb_tran2Packet_t *outp;
1669 unsigned short * tp;
1671 BOOL shareFound = FALSE;
1672 unsigned short infoLevel;
1673 unsigned short bufsize;
1683 tp = p->parmsp + 1; /* skip over function number (always 1) */
1684 (void) smb_ParseString( (char *) tp, (char **) &tp); /* skip over param descriptor */
1685 (void) smb_ParseString( (char *) tp, (char **) &tp); /* skip over data descriptor */
1686 shareName = smb_ParseString( (char *) tp, (char **) &tp);
1693 totalData = sizeof(smb_rap_share_info_0_t);
1694 else if(infoLevel == SMB_INFO_STANDARD)
1695 totalData = sizeof(smb_rap_share_info_1_t) + 1; /* + empty string */
1696 else if(infoLevel == SMB_INFO_QUERY_EA_SIZE)
1697 totalData = sizeof(smb_rap_share_info_2_t) + 2; /* + two empty strings */
1699 return CM_ERROR_INVAL;
1701 outp = smb_GetTran2ResponsePacket(vcp, p, op, totalParam, totalData);
1703 if(!stricmp(shareName,"all") || !strcmp(shareName,"*.")) {
1704 rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY, 0,
1705 KEY_QUERY_VALUE, &hkParam);
1706 if (rv == ERROR_SUCCESS) {
1707 len = sizeof(allSubmount);
1708 rv = RegQueryValueEx(hkParam, "AllSubmount", NULL, NULL,
1709 (BYTE *) &allSubmount, &len);
1710 if (rv != ERROR_SUCCESS || allSubmount != 0) {
1713 RegCloseKey (hkParam);
1720 rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY "\\Submounts", 0,
1721 KEY_QUERY_VALUE, &hkSubmount);
1722 if (rv == ERROR_SUCCESS) {
1723 rv = RegQueryValueEx(hkSubmount, shareName, NULL, NULL, NULL, NULL);
1724 if (rv == ERROR_SUCCESS) {
1727 RegCloseKey(hkSubmount);
1732 smb_FreeTran2Packet(outp);
1733 return CM_ERROR_BADSHARENAME;
1736 memset(outp->datap, 0, totalData);
1738 outp->parmsp[0] = 0;
1739 outp->parmsp[1] = 0;
1740 outp->parmsp[2] = totalData;
1742 if (infoLevel == 0) {
1743 smb_rap_share_info_0_t * info = (smb_rap_share_info_0_t *) outp->datap;
1744 strncpy(info->shi0_netname, shareName, sizeof(info->shi0_netname)-1);
1745 info->shi0_netname[sizeof(info->shi0_netname)-1] = 0;
1746 } else if(infoLevel == SMB_INFO_STANDARD) {
1747 smb_rap_share_info_1_t * info = (smb_rap_share_info_1_t *) outp->datap;
1748 strncpy(info->shi1_netname, shareName, sizeof(info->shi1_netname)-1);
1749 info->shi1_netname[sizeof(info->shi1_netname)-1] = 0;
1750 info->shi1_remark = (DWORD)(((unsigned char *) (info + 1)) - outp->datap);
1751 /* type and pad are already zero */
1752 } else { /* infoLevel==2 */
1753 smb_rap_share_info_2_t * info = (smb_rap_share_info_2_t *) outp->datap;
1754 strncpy(info->shi2_netname, shareName, sizeof(info->shi2_netname)-1);
1755 info->shi2_netname[sizeof(info->shi2_netname)-1] = 0;
1756 info->shi2_remark = (DWORD)(((unsigned char *) (info + 1)) - outp->datap);
1757 info->shi2_permissions = ACCESS_ALL;
1758 info->shi2_max_uses = (unsigned short) -1;
1759 info->shi2_path = (DWORD)(1 + (((unsigned char *) (info + 1)) - outp->datap));
1762 outp->totalData = totalData;
1763 outp->totalParms = totalParam;
1765 smb_SendTran2Packet(vcp, outp, op);
1766 smb_FreeTran2Packet(outp);
1771 typedef struct smb_rap_wksta_info_10 {
1772 DWORD wki10_computername; /*char *wki10_computername;*/
1773 DWORD wki10_username; /* char *wki10_username; */
1774 DWORD wki10_langroup; /* char *wki10_langroup;*/
1775 unsigned char wki10_ver_major;
1776 unsigned char wki10_ver_minor;
1777 DWORD wki10_logon_domain; /*char *wki10_logon_domain;*/
1778 DWORD wki10_oth_domains; /* char *wki10_oth_domains;*/
1779 } smb_rap_wksta_info_10_t;
1782 long smb_ReceiveRAPNetWkstaGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1784 smb_tran2Packet_t *outp;
1788 unsigned short * tp;
1791 smb_rap_wksta_info_10_t * info;
1795 tp = p->parmsp + 1; /* Skip over function number */
1796 (void) smb_ParseString((unsigned char*) tp, (char **) &tp); /* skip over param descriptor */
1797 (void) smb_ParseString((unsigned char*) tp, (char **) &tp); /* skip over data descriptor */
1801 if (infoLevel != 10) {
1802 return CM_ERROR_INVAL;
1808 totalData = sizeof(*info) + /* info */
1809 MAX_COMPUTERNAME_LENGTH + /* wki10_computername */
1810 SMB_MAX_USERNAME_LENGTH + /* wki10_username */
1811 MAX_COMPUTERNAME_LENGTH + /* wki10_langroup */
1812 MAX_COMPUTERNAME_LENGTH + /* wki10_logon_domain */
1813 1; /* wki10_oth_domains (null)*/
1815 outp = smb_GetTran2ResponsePacket(vcp, p, op, totalParams, totalData);
1817 memset(outp->parmsp,0,totalParams);
1818 memset(outp->datap,0,totalData);
1820 info = (smb_rap_wksta_info_10_t *) outp->datap;
1821 cstrp = (char *) (info + 1);
1823 info->wki10_computername = (DWORD) (cstrp - outp->datap);
1824 strcpy(cstrp, smb_localNamep);
1825 cstrp += strlen(cstrp) + 1;
1827 info->wki10_username = (DWORD) (cstrp - outp->datap);
1828 uidp = smb_FindUID(vcp, p->uid, 0);
1830 lock_ObtainMutex(&uidp->mx);
1831 if(uidp->unp && uidp->unp->name)
1832 strcpy(cstrp, uidp->unp->name);
1833 lock_ReleaseMutex(&uidp->mx);
1834 smb_ReleaseUID(uidp);
1836 cstrp += strlen(cstrp) + 1;
1838 info->wki10_langroup = (DWORD) (cstrp - outp->datap);
1839 strcpy(cstrp, "WORKGROUP");
1840 cstrp += strlen(cstrp) + 1;
1842 /* TODO: Not sure what values these should take, but these work */
1843 info->wki10_ver_major = 5;
1844 info->wki10_ver_minor = 1;
1846 info->wki10_logon_domain = (DWORD) (cstrp - outp->datap);
1847 strcpy(cstrp, smb_ServerDomainName);
1848 cstrp += strlen(cstrp) + 1;
1850 info->wki10_oth_domains = (DWORD) (cstrp - outp->datap);
1851 cstrp ++; /* no other domains */
1853 outp->totalData = (unsigned short) (cstrp - outp->datap); /* actual data size */
1854 outp->parmsp[2] = outp->totalData;
1855 outp->totalParms = totalParams;
1857 smb_SendTran2Packet(vcp,outp,op);
1858 smb_FreeTran2Packet(outp);
1863 typedef struct smb_rap_server_info_0 {
1865 } smb_rap_server_info_0_t;
1867 typedef struct smb_rap_server_info_1 {
1869 char sv1_version_major;
1870 char sv1_version_minor;
1871 unsigned long sv1_type;
1872 DWORD *sv1_comment_or_master_browser; /* char *sv1_comment_or_master_browser;*/
1873 } smb_rap_server_info_1_t;
1875 char smb_ServerComment[] = "OpenAFS Client";
1876 int smb_ServerCommentLen = sizeof(smb_ServerComment);
1878 #define SMB_SV_TYPE_SERVER 0x00000002L
1879 #define SMB_SV_TYPE_NT 0x00001000L
1880 #define SMB_SV_TYPE_SERVER_NT 0x00008000L
1882 long smb_ReceiveRAPNetServerGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1884 smb_tran2Packet_t *outp;
1888 unsigned short * tp;
1891 smb_rap_server_info_0_t * info0;
1892 smb_rap_server_info_1_t * info1;
1895 tp = p->parmsp + 1; /* Skip over function number */
1896 (void) smb_ParseString((unsigned char*) tp, (char **) &tp); /* skip over param descriptor */
1897 (void) smb_ParseString((unsigned char*) tp, (char **) &tp); /* skip over data descriptor */
1901 if (infoLevel != 0 && infoLevel != 1) {
1902 return CM_ERROR_INVAL;
1908 (infoLevel == 0) ? sizeof(smb_rap_server_info_0_t)
1909 : (sizeof(smb_rap_server_info_1_t) + smb_ServerCommentLen);
1911 outp = smb_GetTran2ResponsePacket(vcp, p, op, totalParams, totalData);
1913 memset(outp->parmsp,0,totalParams);
1914 memset(outp->datap,0,totalData);
1916 if (infoLevel == 0) {
1917 info0 = (smb_rap_server_info_0_t *) outp->datap;
1918 cstrp = (char *) (info0 + 1);
1919 strcpy(info0->sv0_name, "AFS");
1920 } else { /* infoLevel == SMB_INFO_STANDARD */
1921 info1 = (smb_rap_server_info_1_t *) outp->datap;
1922 cstrp = (char *) (info1 + 1);
1923 strcpy(info1->sv1_name, "AFS");
1926 SMB_SV_TYPE_SERVER |
1928 SMB_SV_TYPE_SERVER_NT;
1930 info1->sv1_version_major = 5;
1931 info1->sv1_version_minor = 1;
1932 info1->sv1_comment_or_master_browser = (DWORD *) (cstrp - outp->datap);
1934 strcpy(cstrp, smb_ServerComment);
1936 cstrp += smb_ServerCommentLen;
1939 totalData = (DWORD)(cstrp - outp->datap);
1940 outp->totalData = min(bufsize,totalData); /* actual data size */
1941 outp->parmsp[0] = (outp->totalData == totalData)? 0 : ERROR_MORE_DATA;
1942 outp->parmsp[2] = totalData;
1943 outp->totalParms = totalParams;
1945 smb_SendTran2Packet(vcp,outp,op);
1946 smb_FreeTran2Packet(outp);
1951 long smb_ReceiveV3Tran2A(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
1953 smb_tran2Packet_t *asp;
1965 /* We sometimes see 0 word count. What to do? */
1966 if (*inp->wctp == 0) {
1967 osi_Log0(smb_logp, "Transaction2 word count = 0");
1968 LogEvent(EVENTLOG_WARNING_TYPE, MSG_SMB_ZERO_TRANSACTION_COUNT);
1970 smb_SetSMBDataLength(outp, 0);
1971 smb_SendPacket(vcp, outp);
1975 totalParms = smb_GetSMBParm(inp, 0);
1976 totalData = smb_GetSMBParm(inp, 1);
1978 firstPacket = (inp->inCom == 0x32);
1980 /* find the packet we're reassembling */
1981 lock_ObtainWrite(&smb_globalLock);
1982 asp = smb_FindTran2Packet(vcp, inp);
1984 asp = smb_NewTran2Packet(vcp, inp, totalParms, totalData);
1986 lock_ReleaseWrite(&smb_globalLock);
1988 /* now merge in this latest packet; start by looking up offsets */
1990 parmDisp = dataDisp = 0;
1991 parmOffset = smb_GetSMBParm(inp, 10);
1992 dataOffset = smb_GetSMBParm(inp, 12);
1993 parmCount = smb_GetSMBParm(inp, 9);
1994 dataCount = smb_GetSMBParm(inp, 11);
1995 asp->maxReturnParms = smb_GetSMBParm(inp, 2);
1996 asp->maxReturnData = smb_GetSMBParm(inp, 3);
1998 osi_Log3(smb_logp, "SMB3 received T2 init packet total data %d, cur data %d, max return data %d",
1999 totalData, dataCount, asp->maxReturnData);
2002 parmDisp = smb_GetSMBParm(inp, 4);
2003 parmOffset = smb_GetSMBParm(inp, 3);
2004 dataDisp = smb_GetSMBParm(inp, 7);
2005 dataOffset = smb_GetSMBParm(inp, 6);
2006 parmCount = smb_GetSMBParm(inp, 2);
2007 dataCount = smb_GetSMBParm(inp, 5);
2009 osi_Log2(smb_logp, "SMB3 received T2 aux packet parms %d, data %d",
2010 parmCount, dataCount);
2013 /* now copy the parms and data */
2014 if ( asp->totalParms > 0 && parmCount != 0 )
2016 memcpy(((char *)asp->parmsp) + parmDisp, inp->data + parmOffset, parmCount);
2018 if ( asp->totalData > 0 && dataCount != 0 ) {
2019 memcpy(asp->datap + dataDisp, inp->data + dataOffset, dataCount);
2022 /* account for new bytes */
2023 asp->curData += dataCount;
2024 asp->curParms += parmCount;
2026 /* finally, if we're done, remove the packet from the queue and dispatch it */
2027 if (asp->totalParms > 0 &&
2028 asp->curParms > 0 &&
2029 asp->totalData <= asp->curData &&
2030 asp->totalParms <= asp->curParms) {
2031 /* we've received it all */
2032 lock_ObtainWrite(&smb_globalLock);
2033 osi_QRemove((osi_queue_t **) &smb_tran2AssemblyQueuep, &asp->q);
2034 lock_ReleaseWrite(&smb_globalLock);
2036 /* now dispatch it */
2037 if ( asp->opcode >= 0 && asp->opcode < 20 && smb_tran2DispatchTable[asp->opcode].procp) {
2038 osi_Log4(smb_logp,"AFS Server - Dispatch-2 %s vcp[%p] lana[%d] lsn[%d]",myCrt_2Dispatch(asp->opcode),vcp,vcp->lana,vcp->lsn);
2039 code = (*smb_tran2DispatchTable[asp->opcode].procp)(vcp, asp, outp);
2042 osi_Log4(smb_logp,"AFS Server - Dispatch-2 [INVALID] op[%x] vcp[%p] lana[%d] lsn[%d]", asp->opcode, vcp, vcp->lana, vcp->lsn);
2043 code = CM_ERROR_BADOP;
2046 /* if an error is returned, we're supposed to send an error packet,
2047 * otherwise the dispatched function already did the data sending.
2048 * We give dispatched proc the responsibility since it knows how much
2049 * space to allocate.
2052 smb_SendTran2Error(vcp, asp, outp, code);
2055 /* free the input tran 2 packet */
2056 smb_FreeTran2Packet(asp);
2058 else if (firstPacket) {
2059 /* the first packet in a multi-packet request, we need to send an
2060 * ack to get more data.
2062 smb_SetSMBDataLength(outp, 0);
2063 smb_SendPacket(vcp, outp);
2069 long smb_ReceiveTran2Open(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
2072 smb_tran2Packet_t *outp;
2077 cm_scache_t *dscp; /* dir we're dealing with */
2078 cm_scache_t *scp; /* file we're creating */
2080 int initialModeBits;
2090 int parmSlot; /* which parm we're dealing with */
2091 long returnEALength;
2100 extraInfo = (p->parmsp[0] & 1); /* return extra info */
2101 returnEALength = (p->parmsp[0] & 8); /* return extended attr length */
2103 openFun = p->parmsp[6]; /* open function */
2104 excl = ((openFun & 3) == 0);
2105 trunc = ((openFun & 3) == 2); /* truncate it */
2106 openMode = (p->parmsp[1] & 0x7);
2107 openAction = 0; /* tracks what we did */
2109 attributes = p->parmsp[3];
2110 dosTime = p->parmsp[4] | (p->parmsp[5] << 16);
2112 /* compute initial mode bits based on read-only flag in attributes */
2113 initialModeBits = 0666;
2114 if (attributes & SMB_ATTR_READONLY)
2115 initialModeBits &= ~0222;
2117 pathp = (char *) (&p->parmsp[14]);
2118 if (smb_StoreAnsiFilenames)
2119 OemToChar(pathp,pathp);
2121 outp = smb_GetTran2ResponsePacket(vcp, p, op, 40, 0);
2123 spacep = cm_GetSpace();
2124 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
2126 if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
2127 /* special case magic file name for receiving IOCTL requests
2128 * (since IOCTL calls themselves aren't getting through).
2130 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
2131 smb_SetupIoctlFid(fidp, spacep);
2133 /* copy out remainder of the parms */
2135 outp->parmsp[parmSlot++] = fidp->fid;
2137 outp->parmsp[parmSlot++] = 0; /* attrs */
2138 outp->parmsp[parmSlot++] = 0; /* mod time */
2139 outp->parmsp[parmSlot++] = 0;
2140 outp->parmsp[parmSlot++] = 0; /* len */
2141 outp->parmsp[parmSlot++] = 0x7fff;
2142 outp->parmsp[parmSlot++] = openMode;
2143 outp->parmsp[parmSlot++] = 0; /* file type 0 ==> normal file or dir */
2144 outp->parmsp[parmSlot++] = 0; /* IPC junk */
2146 /* and the final "always present" stuff */
2147 outp->parmsp[parmSlot++] = 1; /* openAction found existing file */
2148 /* next write out the "unique" ID */
2149 outp->parmsp[parmSlot++] = 0x1234;
2150 outp->parmsp[parmSlot++] = 0x5678;
2151 outp->parmsp[parmSlot++] = 0;
2152 if (returnEALength) {
2153 outp->parmsp[parmSlot++] = 0;
2154 outp->parmsp[parmSlot++] = 0;
2157 outp->totalData = 0;
2158 outp->totalParms = parmSlot * 2;
2160 smb_SendTran2Packet(vcp, outp, op);
2162 smb_FreeTran2Packet(outp);
2164 /* and clean up fid reference */
2165 smb_ReleaseFID(fidp);
2169 #ifdef DEBUG_VERBOSE
2171 char *hexp, *asciip;
2172 asciip = (lastNamep ? lastNamep : pathp);
2173 hexp = osi_HexifyString( asciip );
2174 DEBUG_EVENT2("AFS","T2Open H[%s] A[%s]", hexp, asciip);
2179 userp = smb_GetTran2User(vcp, p);
2180 /* In the off chance that userp is NULL, we log and abandon */
2182 osi_Log1(smb_logp, "ReceiveTran2Open user [%d] not resolvable", p->uid);
2183 smb_FreeTran2Packet(outp);
2184 return CM_ERROR_BADSMB;
2187 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
2188 if (code == CM_ERROR_TIDIPC) {
2189 /* Attempt to use a TID allocated for IPC. The client
2190 * is probably looking for DCE RPC end points which we
2191 * don't support OR it could be looking to make a DFS
2194 osi_Log0(smb_logp, "Tran2Open received IPC TID");
2196 cm_ReleaseUser(userp);
2197 smb_FreeTran2Packet(outp);
2198 return CM_ERROR_NOSUCHPATH;
2203 code = cm_NameI(cm_data.rootSCachep, pathp,
2204 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
2205 userp, tidPathp, &req, &scp);
2207 code = cm_NameI(cm_data.rootSCachep, spacep->data,
2208 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
2209 userp, tidPathp, &req, &dscp);
2210 cm_FreeSpace(spacep);
2213 cm_ReleaseUser(userp);
2214 smb_FreeTran2Packet(outp);
2219 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
2220 cm_ReleaseSCache(dscp);
2221 cm_ReleaseUser(userp);
2222 smb_FreeTran2Packet(outp);
2223 if ( WANTS_DFS_PATHNAMES(p) )
2224 return CM_ERROR_PATH_NOT_COVERED;
2226 return CM_ERROR_BADSHARENAME;
2228 #endif /* DFS_SUPPORT */
2230 /* otherwise, scp points to the parent directory. Do a lookup,
2231 * and truncate the file if we find it, otherwise we create the
2238 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD, userp,
2240 if (code && code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
2241 cm_ReleaseSCache(dscp);
2242 cm_ReleaseUser(userp);
2243 smb_FreeTran2Packet(outp);
2248 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
2249 cm_ReleaseSCache(scp);
2250 cm_ReleaseUser(userp);
2251 smb_FreeTran2Packet(outp);
2252 if ( WANTS_DFS_PATHNAMES(p) )
2253 return CM_ERROR_PATH_NOT_COVERED;
2255 return CM_ERROR_BADSHARENAME;
2257 #endif /* DFS_SUPPORT */
2259 /* macintosh is expensive to program for it */
2260 cm_FreeSpace(spacep);
2263 /* if we get here, if code is 0, the file exists and is represented by
2264 * scp. Otherwise, we have to create it.
2267 code = cm_CheckOpen(scp, openMode, trunc, userp, &req);
2270 cm_ReleaseSCache(dscp);
2271 cm_ReleaseSCache(scp);
2272 cm_ReleaseUser(userp);
2273 smb_FreeTran2Packet(outp);
2278 /* oops, file shouldn't be there */
2280 cm_ReleaseSCache(dscp);
2281 cm_ReleaseSCache(scp);
2282 cm_ReleaseUser(userp);
2283 smb_FreeTran2Packet(outp);
2284 return CM_ERROR_EXISTS;
2288 setAttr.mask = CM_ATTRMASK_LENGTH;
2289 setAttr.length.LowPart = 0;
2290 setAttr.length.HighPart = 0;
2291 code = cm_SetAttr(scp, &setAttr, userp, &req);
2292 openAction = 3; /* truncated existing file */
2295 openAction = 1; /* found existing file */
2297 else if (!(openFun & 0x10)) {
2298 /* don't create if not found */
2300 cm_ReleaseSCache(dscp);
2301 osi_assert(scp == NULL);
2302 cm_ReleaseUser(userp);
2303 smb_FreeTran2Packet(outp);
2304 return CM_ERROR_NOSUCHFILE;
2307 osi_assert(dscp != NULL && scp == NULL);
2308 openAction = 2; /* created file */
2309 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
2310 smb_UnixTimeFromSearchTime(&setAttr.clientModTime, dosTime);
2311 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
2315 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
2316 smb_NotifyChange(FILE_ACTION_ADDED,
2317 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
2318 dscp, lastNamep, NULL, TRUE);
2319 } else if (!excl && code == CM_ERROR_EXISTS) {
2320 /* not an exclusive create, and someone else tried
2321 * creating it already, then we open it anyway. We
2322 * don't bother retrying after this, since if this next
2323 * fails, that means that the file was deleted after we
2324 * started this call.
2326 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
2330 setAttr.mask = CM_ATTRMASK_LENGTH;
2331 setAttr.length.LowPart = 0;
2332 setAttr.length.HighPart = 0;
2333 code = cm_SetAttr(scp, &setAttr, userp,
2336 } /* lookup succeeded */
2340 /* we don't need this any longer */
2342 cm_ReleaseSCache(dscp);
2345 /* something went wrong creating or truncating the file */
2347 cm_ReleaseSCache(scp);
2348 cm_ReleaseUser(userp);
2349 smb_FreeTran2Packet(outp);
2353 /* make sure we're about to open a file */
2354 if (scp->fileType != CM_SCACHETYPE_FILE) {
2356 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
2357 cm_scache_t * targetScp = 0;
2358 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
2360 /* we have a more accurate file to use (the
2361 * target of the symbolic link). Otherwise,
2362 * we'll just use the symlink anyway.
2364 osi_Log2(smb_logp, "symlink vp %x to vp %x",
2366 cm_ReleaseSCache(scp);
2370 if (scp->fileType != CM_SCACHETYPE_FILE) {
2371 cm_ReleaseSCache(scp);
2372 cm_ReleaseUser(userp);
2373 smb_FreeTran2Packet(outp);
2374 return CM_ERROR_ISDIR;
2378 /* now all we have to do is open the file itself */
2379 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
2383 lock_ObtainMutex(&fidp->mx);
2384 /* save a pointer to the vnode */
2385 osi_Log2(smb_logp,"smb_ReceiveTran2Open fidp 0x%p scp 0x%p", fidp, scp);
2387 lock_ObtainMutex(&scp->mx);
2388 scp->flags |= CM_SCACHEFLAG_SMB_FID;
2389 lock_ReleaseMutex(&scp->mx);
2392 fidp->userp = userp;
2394 /* compute open mode */
2396 fidp->flags |= SMB_FID_OPENREAD_LISTDIR;
2397 if (openMode == 1 || openMode == 2)
2398 fidp->flags |= SMB_FID_OPENWRITE;
2400 /* remember that the file was newly created */
2402 fidp->flags |= SMB_FID_CREATED;
2404 lock_ReleaseMutex(&fidp->mx);
2406 smb_ReleaseFID(fidp);
2408 cm_Open(scp, 0, userp);
2410 /* copy out remainder of the parms */
2412 outp->parmsp[parmSlot++] = fidp->fid;
2413 lock_ObtainMutex(&scp->mx);
2415 outp->parmsp[parmSlot++] = smb_Attributes(scp);
2416 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
2417 outp->parmsp[parmSlot++] = (unsigned short)(dosTime & 0xffff);
2418 outp->parmsp[parmSlot++] = (unsigned short)((dosTime>>16) & 0xffff);
2419 outp->parmsp[parmSlot++] = (unsigned short) (scp->length.LowPart & 0xffff);
2420 outp->parmsp[parmSlot++] = (unsigned short) ((scp->length.LowPart >> 16) & 0xffff);
2421 outp->parmsp[parmSlot++] = openMode;
2422 outp->parmsp[parmSlot++] = 0; /* file type 0 ==> normal file or dir */
2423 outp->parmsp[parmSlot++] = 0; /* IPC junk */
2425 /* and the final "always present" stuff */
2426 outp->parmsp[parmSlot++] = openAction;
2427 /* next write out the "unique" ID */
2428 outp->parmsp[parmSlot++] = (unsigned short) (scp->fid.vnode & 0xffff);
2429 outp->parmsp[parmSlot++] = (unsigned short) (scp->fid.volume & 0xffff);
2430 outp->parmsp[parmSlot++] = 0;
2431 if (returnEALength) {
2432 outp->parmsp[parmSlot++] = 0;
2433 outp->parmsp[parmSlot++] = 0;
2435 lock_ReleaseMutex(&scp->mx);
2436 outp->totalData = 0; /* total # of data bytes */
2437 outp->totalParms = parmSlot * 2; /* shorts are two bytes */
2439 smb_SendTran2Packet(vcp, outp, op);
2441 smb_FreeTran2Packet(outp);
2443 cm_ReleaseUser(userp);
2444 /* leave scp held since we put it in fidp->scp */
2448 long smb_ReceiveTran2QFSInfoFid(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
2451 unsigned short infolevel;
2453 infolevel = p->parmsp[0];
2455 osi_Log2(smb_logp, "T2 QFSInfoFid InfoLevel 0x%x fid 0x%x - NOT_SUPPORTED", infolevel, fid);
2457 return CM_ERROR_BAD_LEVEL;
2460 long smb_ReceiveTran2QFSInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
2462 smb_tran2Packet_t *outp;
2463 smb_tran2QFSInfo_t qi;
2465 static char FSname[8] = {'A', 0, 'F', 0, 'S', 0, 0, 0};
2467 osi_Log1(smb_logp, "T2 QFSInfo type 0x%x", p->parmsp[0]);
2469 switch (p->parmsp[0]) {
2470 case SMB_INFO_ALLOCATION:
2471 responseSize = sizeof(qi.u.allocInfo);
2473 case SMB_INFO_VOLUME:
2474 responseSize = sizeof(qi.u.volumeInfo);
2476 case SMB_QUERY_FS_VOLUME_INFO:
2477 responseSize = sizeof(qi.u.FSvolumeInfo);
2479 case SMB_QUERY_FS_SIZE_INFO:
2480 responseSize = sizeof(qi.u.FSsizeInfo);
2482 case SMB_QUERY_FS_DEVICE_INFO:
2483 responseSize = sizeof(qi.u.FSdeviceInfo);
2485 case SMB_QUERY_FS_ATTRIBUTE_INFO:
2486 responseSize = sizeof(qi.u.FSattributeInfo);
2488 case SMB_INFO_UNIX: /* CIFS Unix Info */
2489 case SMB_INFO_MACOS: /* Mac FS Info */
2491 return CM_ERROR_BADOP;
2494 outp = smb_GetTran2ResponsePacket(vcp, p, op, 0, responseSize);
2495 switch (p->parmsp[0]) {
2496 case SMB_INFO_ALLOCATION:
2498 qi.u.allocInfo.FSID = 0;
2499 qi.u.allocInfo.sectorsPerAllocUnit = 1;
2500 qi.u.allocInfo.totalAllocUnits = 0x7fffffff;
2501 qi.u.allocInfo.availAllocUnits = 0x3fffffff;
2502 qi.u.allocInfo.bytesPerSector = 1024;
2505 case SMB_INFO_VOLUME:
2507 qi.u.volumeInfo.vsn = 1234;
2508 qi.u.volumeInfo.vnCount = 4;
2509 /* we're supposed to pad it out with zeroes to the end */
2510 memset(&qi.u.volumeInfo.label, 0, sizeof(qi.u.volumeInfo.label));
2511 memcpy(qi.u.volumeInfo.label, "AFS", 4);
2514 case SMB_QUERY_FS_VOLUME_INFO:
2515 /* FS volume info */
2516 memset((char *)&qi.u.FSvolumeInfo.vct, 0, 4);
2517 qi.u.FSvolumeInfo.vsn = 1234;
2518 qi.u.FSvolumeInfo.vnCount = 8;
2519 memcpy(qi.u.FSvolumeInfo.label, "A\0F\0S\0\0\0", 8);
2522 case SMB_QUERY_FS_SIZE_INFO:
2524 qi.u.FSsizeInfo.totalAllocUnits.HighPart = 0;
2525 qi.u.FSsizeInfo.totalAllocUnits.LowPart= 0x7fffffff;
2526 qi.u.FSsizeInfo.availAllocUnits.HighPart = 0;
2527 qi.u.FSsizeInfo.availAllocUnits.LowPart= 0x3fffffff;
2528 qi.u.FSsizeInfo.sectorsPerAllocUnit = 1;
2529 qi.u.FSsizeInfo.bytesPerSector = 1024;
2532 case SMB_QUERY_FS_DEVICE_INFO:
2533 /* FS device info */
2534 qi.u.FSdeviceInfo.devType = 0x14; /* network file system */
2535 qi.u.FSdeviceInfo.characteristics = 0x50; /* remote, virtual */
2538 case SMB_QUERY_FS_ATTRIBUTE_INFO:
2539 /* FS attribute info */
2540 /* attributes, defined in WINNT.H:
2541 * FILE_CASE_SENSITIVE_SEARCH 0x1
2542 * FILE_CASE_PRESERVED_NAMES 0x2
2543 * FILE_VOLUME_QUOTAS 0x10
2544 * <no name defined> 0x4000
2545 * If bit 0x4000 is not set, Windows 95 thinks
2546 * we can't handle long (non-8.3) names,
2547 * despite our protestations to the contrary.
2549 qi.u.FSattributeInfo.attributes = 0x4003;
2550 qi.u.FSattributeInfo.maxCompLength = MAX_PATH;
2551 qi.u.FSattributeInfo.FSnameLength = sizeof(FSname);
2552 memcpy(qi.u.FSattributeInfo.FSname, FSname, sizeof(FSname));
2556 /* copy out return data, and set corresponding sizes */
2557 outp->totalParms = 0;
2558 outp->totalData = responseSize;
2559 memcpy(outp->datap, &qi, responseSize);
2561 /* send and free the packets */
2562 smb_SendTran2Packet(vcp, outp, op);
2563 smb_FreeTran2Packet(outp);
2568 long smb_ReceiveTran2SetFSInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
2570 osi_Log0(smb_logp,"ReceiveTran2SetFSInfo - NOT_SUPPORTED");
2571 return CM_ERROR_BADOP;
2574 struct smb_ShortNameRock {
2578 size_t shortNameLen;
2581 int cm_GetShortNameProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *vrockp,
2584 struct smb_ShortNameRock *rockp;
2588 /* compare both names and vnodes, though probably just comparing vnodes
2589 * would be safe enough.
2591 if (cm_stricmp(dep->name, rockp->maskp) != 0)
2593 if (ntohl(dep->fid.vnode) != rockp->vnode)
2595 /* This is the entry */
2596 cm_Gen8Dot3Name(dep, rockp->shortName, &shortNameEnd);
2597 rockp->shortNameLen = shortNameEnd - rockp->shortName;
2598 return CM_ERROR_STOPNOW;
2601 long cm_GetShortName(char *pathp, cm_user_t *userp, cm_req_t *reqp,
2602 char *tidPathp, int vnode, char *shortName, size_t *shortNameLenp)
2604 struct smb_ShortNameRock rock;
2608 int caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
2612 spacep = cm_GetSpace();
2613 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
2615 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold, userp, tidPathp,
2617 cm_FreeSpace(spacep);
2622 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
2623 cm_ReleaseSCache(dscp);
2624 cm_ReleaseUser(userp);
2625 return CM_ERROR_PATH_NOT_COVERED;
2627 #endif /* DFS_SUPPORT */
2629 if (!lastNamep) lastNamep = pathp;
2632 thyper.HighPart = 0;
2633 rock.shortName = shortName;
2635 rock.maskp = lastNamep;
2636 code = cm_ApplyDir(dscp, cm_GetShortNameProc, &rock, &thyper, userp, reqp, NULL);
2638 cm_ReleaseSCache(dscp);
2641 return CM_ERROR_NOSUCHFILE;
2642 if (code == CM_ERROR_STOPNOW) {
2643 *shortNameLenp = rock.shortNameLen;
2649 long smb_ReceiveTran2QPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
2651 smb_tran2Packet_t *outp;
2654 unsigned short infoLevel;
2655 smb_tran2QPathInfo_t qpi;
2657 unsigned short attributes;
2658 unsigned long extAttributes;
2663 cm_scache_t *scp, *dscp;
2664 int scp_mx_held = 0;
2674 infoLevel = p->parmsp[0];
2675 if (infoLevel == SMB_INFO_IS_NAME_VALID)
2677 else if (infoLevel == SMB_INFO_STANDARD)
2678 responseSize = sizeof(qpi.u.QPstandardInfo);
2679 else if (infoLevel == SMB_INFO_QUERY_EA_SIZE)
2680 responseSize = sizeof(qpi.u.QPeaSizeInfo);
2681 else if (infoLevel == SMB_QUERY_FILE_BASIC_INFO)
2682 responseSize = sizeof(qpi.u.QPfileBasicInfo);
2683 else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO)
2684 responseSize = sizeof(qpi.u.QPfileStandardInfo);
2685 else if (infoLevel == SMB_QUERY_FILE_EA_INFO)
2686 responseSize = sizeof(qpi.u.QPfileEaInfo);
2687 else if (infoLevel == SMB_QUERY_FILE_NAME_INFO)
2688 responseSize = sizeof(qpi.u.QPfileNameInfo);
2689 else if (infoLevel == SMB_QUERY_FILE_ALL_INFO)
2690 responseSize = sizeof(qpi.u.QPfileAllInfo);
2691 else if (infoLevel == SMB_QUERY_FILE_ALT_NAME_INFO)
2692 responseSize = sizeof(qpi.u.QPfileAltNameInfo);
2694 osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
2695 p->opcode, infoLevel);
2696 smb_SendTran2Error(vcp, p, opx, CM_ERROR_BAD_LEVEL);
2700 pathp = (char *)(&p->parmsp[3]);
2701 if (smb_StoreAnsiFilenames)
2702 OemToChar(pathp,pathp);
2703 osi_Log2(smb_logp, "T2 QPathInfo type 0x%x path %s", infoLevel,
2704 osi_LogSaveString(smb_logp, pathp));
2706 outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, responseSize);
2708 if (infoLevel > 0x100)
2709 outp->totalParms = 2;
2711 outp->totalParms = 0;
2712 outp->totalData = responseSize;
2714 /* now, if we're at infoLevel 6, we're only being asked to check
2715 * the syntax, so we just OK things now. In particular, we're *not*
2716 * being asked to verify anything about the state of any parent dirs.
2718 if (infoLevel == SMB_INFO_IS_NAME_VALID) {
2719 smb_SendTran2Packet(vcp, outp, opx);
2720 smb_FreeTran2Packet(outp);
2724 userp = smb_GetTran2User(vcp, p);
2726 osi_Log1(smb_logp, "ReceiveTran2QPathInfo unable to resolve user [%d]", p->uid);
2727 smb_FreeTran2Packet(outp);
2728 return CM_ERROR_BADSMB;
2731 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
2733 cm_ReleaseUser(userp);
2734 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOSUCHPATH);
2735 smb_FreeTran2Packet(outp);
2740 * XXX Strange hack XXX
2742 * As of Patch 7 (13 January 98), we are having the following problem:
2743 * In NT Explorer 4.0, whenever we click on a directory, AFS gets
2744 * requests to look up "desktop.ini" in all the subdirectories.
2745 * This can cause zillions of timeouts looking up non-existent cells
2746 * and volumes, especially in the top-level directory.
2748 * We have not found any way to avoid this or work around it except
2749 * to explicitly ignore the requests for mount points that haven't
2750 * yet been evaluated and for directories that haven't yet been
2753 if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
2754 spacep = cm_GetSpace();
2755 smb_StripLastComponent(spacep->data, &lastComp, pathp);
2756 #ifndef SPECIAL_FOLDERS
2757 /* Make sure that lastComp is not NULL */
2759 if (stricmp(lastComp, "\\desktop.ini") == 0) {
2760 code = cm_NameI(cm_data.rootSCachep, spacep->data,
2764 userp, tidPathp, &req, &dscp);
2767 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
2768 if ( WANTS_DFS_PATHNAMES(p) )
2769 code = CM_ERROR_PATH_NOT_COVERED;
2771 code = CM_ERROR_BADSHARENAME;
2773 #endif /* DFS_SUPPORT */
2774 if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT && !dscp->mountRootFid.volume)
2775 code = CM_ERROR_NOSUCHFILE;
2776 else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
2777 cm_buf_t *bp = buf_Find(dscp, &hzero);
2783 code = CM_ERROR_NOSUCHFILE;
2785 cm_ReleaseSCache(dscp);
2787 cm_FreeSpace(spacep);
2788 cm_ReleaseUser(userp);
2789 smb_SendTran2Error(vcp, p, opx, code);
2790 smb_FreeTran2Packet(outp);
2796 #endif /* SPECIAL_FOLDERS */
2798 cm_FreeSpace(spacep);
2801 /* now do namei and stat, and copy out the info */
2802 code = cm_NameI(cm_data.rootSCachep, pathp,
2803 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, tidPathp, &req, &scp);
2806 cm_ReleaseUser(userp);
2807 smb_SendTran2Error(vcp, p, opx, code);
2808 smb_FreeTran2Packet(outp);
2813 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
2814 cm_ReleaseSCache(scp);
2815 cm_ReleaseUser(userp);
2816 if ( WANTS_DFS_PATHNAMES(p) )
2817 code = CM_ERROR_PATH_NOT_COVERED;
2819 code = CM_ERROR_BADSHARENAME;
2820 smb_SendTran2Error(vcp, p, opx, code);
2821 smb_FreeTran2Packet(outp);
2824 #endif /* DFS_SUPPORT */
2826 lock_ObtainMutex(&scp->mx);
2828 code = cm_SyncOp(scp, NULL, userp, &req, 0,
2829 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
2830 if (code) goto done;
2832 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
2834 /* now we have the status in the cache entry, and everything is locked.
2835 * Marshall the output data.
2837 /* for info level 108, figure out short name */
2838 if (infoLevel == SMB_QUERY_FILE_ALT_NAME_INFO) {
2839 code = cm_GetShortName(pathp, userp, &req,
2840 tidPathp, scp->fid.vnode, shortName,
2846 qpi.u.QPfileAltNameInfo.fileNameLength = (len + 1) * 2;
2847 mbstowcs((unsigned short *)qpi.u.QPfileAltNameInfo.fileName, shortName, len + 1);
2851 else if (infoLevel == SMB_QUERY_FILE_NAME_INFO) {
2852 len = strlen(lastComp);
2853 qpi.u.QPfileNameInfo.fileNameLength = (len + 1) * 2;
2854 mbstowcs((unsigned short *)qpi.u.QPfileNameInfo.fileName, lastComp, len + 1);
2858 else if (infoLevel == SMB_INFO_STANDARD || infoLevel == SMB_INFO_QUERY_EA_SIZE) {
2859 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
2860 qpi.u.QPstandardInfo.creationDateTime = dosTime;
2861 qpi.u.QPstandardInfo.lastAccessDateTime = dosTime;
2862 qpi.u.QPstandardInfo.lastWriteDateTime = dosTime;
2863 qpi.u.QPstandardInfo.dataSize = scp->length.LowPart;
2864 qpi.u.QPstandardInfo.allocationSize = scp->length.LowPart;
2865 attributes = smb_Attributes(scp);
2866 qpi.u.QPstandardInfo.attributes = attributes;
2867 qpi.u.QPstandardInfo.eaSize = 0;
2869 else if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
2870 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
2871 qpi.u.QPfileBasicInfo.creationTime = ft;
2872 qpi.u.QPfileBasicInfo.lastAccessTime = ft;
2873 qpi.u.QPfileBasicInfo.lastWriteTime = ft;
2874 qpi.u.QPfileBasicInfo.changeTime = ft;
2875 extAttributes = smb_ExtAttributes(scp);
2876 qpi.u.QPfileBasicInfo.attributes = extAttributes;
2877 qpi.u.QPfileBasicInfo.reserved = 0;
2879 else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO) {
2880 smb_fid_t *fidp = smb_FindFIDByScache(vcp, scp);
2882 qpi.u.QPfileStandardInfo.allocationSize = scp->length;
2883 qpi.u.QPfileStandardInfo.endOfFile = scp->length;
2884 qpi.u.QPfileStandardInfo.numberOfLinks = scp->linkCount;
2885 qpi.u.QPfileStandardInfo.directory =
2886 ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
2887 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
2888 scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0);
2889 qpi.u.QPfileStandardInfo.reserved = 0;
2892 lock_ReleaseMutex(&scp->mx);
2894 lock_ObtainMutex(&fidp->mx);
2895 delonclose = fidp->flags & SMB_FID_DELONCLOSE;
2896 lock_ReleaseMutex(&fidp->mx);
2897 smb_ReleaseFID(fidp);
2899 qpi.u.QPfileStandardInfo.deletePending = (delonclose ? 1 : 0);
2901 else if (infoLevel == SMB_QUERY_FILE_EA_INFO) {
2902 qpi.u.QPfileEaInfo.eaSize = 0;
2904 else if (infoLevel == SMB_QUERY_FILE_ALL_INFO) {
2905 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
2906 qpi.u.QPfileAllInfo.creationTime = ft;
2907 qpi.u.QPfileAllInfo.lastAccessTime = ft;
2908 qpi.u.QPfileAllInfo.lastWriteTime = ft;
2909 qpi.u.QPfileAllInfo.changeTime = ft;
2910 extAttributes = smb_ExtAttributes(scp);
2911 qpi.u.QPfileAllInfo.attributes = extAttributes;
2912 qpi.u.QPfileAllInfo.allocationSize = scp->length;
2913 qpi.u.QPfileAllInfo.endOfFile = scp->length;
2914 qpi.u.QPfileAllInfo.numberOfLinks = scp->linkCount;
2915 qpi.u.QPfileAllInfo.deletePending = 0;
2916 qpi.u.QPfileAllInfo.directory =
2917 ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
2918 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
2919 scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0);
2920 qpi.u.QPfileAllInfo.indexNumber.HighPart = scp->fid.cell;
2921 qpi.u.QPfileAllInfo.indexNumber.LowPart = scp->fid.volume;
2922 qpi.u.QPfileAllInfo.eaSize = 0;
2923 qpi.u.QPfileAllInfo.accessFlags = 0;
2924 qpi.u.QPfileAllInfo.indexNumber2.HighPart = scp->fid.vnode;
2925 qpi.u.QPfileAllInfo.indexNumber2.LowPart = scp->fid.unique;
2926 qpi.u.QPfileAllInfo.currentByteOffset.HighPart = 0;
2927 qpi.u.QPfileAllInfo.currentByteOffset.LowPart = 0;
2928 qpi.u.QPfileAllInfo.mode = 0;
2929 qpi.u.QPfileAllInfo.alignmentRequirement = 0;
2930 len = strlen(lastComp);
2931 qpi.u.QPfileAllInfo.fileNameLength = (len + 1) * 2;
2932 mbstowcs((unsigned short *)qpi.u.QPfileAllInfo.fileName, lastComp, len + 1);
2935 /* send and free the packets */
2938 lock_ReleaseMutex(&scp->mx);
2939 cm_ReleaseSCache(scp);
2940 cm_ReleaseUser(userp);
2942 memcpy(outp->datap, &qpi, responseSize);
2943 smb_SendTran2Packet(vcp, outp, opx);
2945 smb_SendTran2Error(vcp, p, opx, code);
2947 smb_FreeTran2Packet(outp);
2952 long smb_ReceiveTran2SetPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
2955 osi_Log0(smb_logp,"ReceiveTran2SetPathInfo - NOT_SUPPORTED");
2956 return CM_ERROR_BADOP;
2960 unsigned short infoLevel;
2962 smb_tran2Packet_t *outp;
2963 smb_tran2QPathInfo_t *spi;
2965 cm_scache_t *scp, *dscp;
2973 infoLevel = p->parmsp[0];
2974 osi_Log1(smb_logp,"ReceiveTran2SetPathInfo type 0x%x", infoLevel);
2975 if (infoLevel != SMB_INFO_STANDARD &&
2976 infoLevel != SMB_INFO_QUERY_EA_SIZE &&
2977 infoLevel != SMB_INFO_QUERY_ALL_EAS) {
2978 osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
2979 p->opcode, infoLevel);
2980 smb_SendTran2Error(vcp, p, opx, CM_ERROR_BAD_LEVEL);
2984 pathp = (char *)(&p->parmsp[3]);
2985 if (smb_StoreAnsiFilenames)
2986 OemToChar(pathp,pathp);
2987 osi_Log2(smb_logp, "T2 SetPathInfo infolevel 0x%x path %s", infoLevel,
2988 osi_LogSaveString(smb_logp, pathp));
2990 userp = smb_GetTran2User(vcp, p);
2992 osi_Log1(smb_logp,"ReceiveTran2SetPathInfo unable to resolve user [%d]", p->uid);
2993 code = CM_ERROR_BADSMB;
2997 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
2998 if (code == CM_ERROR_TIDIPC) {
2999 /* Attempt to use a TID allocated for IPC. The client
3000 * is probably looking for DCE RPC end points which we
3001 * don't support OR it could be looking to make a DFS
3004 osi_Log0(smb_logp, "Tran2Open received IPC TID");
3005 cm_ReleaseUser(userp);
3006 return CM_ERROR_NOSUCHPATH;
3010 * XXX Strange hack XXX
3012 * As of Patch 7 (13 January 98), we are having the following problem:
3013 * In NT Explorer 4.0, whenever we click on a directory, AFS gets
3014 * requests to look up "desktop.ini" in all the subdirectories.
3015 * This can cause zillions of timeouts looking up non-existent cells
3016 * and volumes, especially in the top-level directory.
3018 * We have not found any way to avoid this or work around it except
3019 * to explicitly ignore the requests for mount points that haven't
3020 * yet been evaluated and for directories that haven't yet been
3023 if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
3024 spacep = cm_GetSpace();
3025 smb_StripLastComponent(spacep->data, &lastComp, pathp);
3026 #ifndef SPECIAL_FOLDERS
3027 /* Make sure that lastComp is not NULL */
3029 if (stricmp(lastComp, "\\desktop.ini") == 0) {
3030 code = cm_NameI(cm_data.rootSCachep, spacep->data,
3034 userp, tidPathp, &req, &dscp);
3037 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
3038 if ( WANTS_DFS_PATHNAMES(p) )
3039 code = CM_ERROR_PATH_NOT_COVERED;
3041 code = CM_ERROR_BADSHARENAME;
3043 #endif /* DFS_SUPPORT */
3044 if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT && !dscp->mountRootFid.volume)
3045 code = CM_ERROR_NOSUCHFILE;
3046 else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
3047 cm_buf_t *bp = buf_Find(dscp, &hzero);
3053 code = CM_ERROR_NOSUCHFILE;
3055 cm_ReleaseSCache(dscp);
3057 cm_FreeSpace(spacep);
3058 cm_ReleaseUser(userp);
3059 smb_SendTran2Error(vcp, p, opx, code);
3065 #endif /* SPECIAL_FOLDERS */
3067 cm_FreeSpace(spacep);
3070 /* now do namei and stat, and copy out the info */
3071 code = cm_NameI(cm_data.rootSCachep, pathp,
3072 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, tidPathp, &req, &scp);
3074 cm_ReleaseUser(userp);
3075 smb_SendTran2Error(vcp, p, opx, code);
3079 fidp = smb_FindFIDByScache(vcp, scp);
3081 cm_ReleaseSCache(scp);
3082 cm_ReleaseUser(userp);
3083 smb_SendTran2Error(vcp, p, opx, code);
3087 lock_ObtainMutex(&fidp->mx);
3088 if (!(fidp->flags & SMB_FID_OPENWRITE)) {
3089 lock_ReleaseMutex(&fidp->mx);
3090 cm_ReleaseSCache(scp);
3091 smb_ReleaseFID(fidp);
3092 cm_ReleaseUser(userp);
3093 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOACCESS);
3096 lock_ReleaseMutex(&fidp->mx);
3098 outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, 0);
3100 outp->totalParms = 2;
3101 outp->totalData = 0;
3103 spi = (smb_tran2QPathInfo_t *)p->datap;
3104 if (infoLevel == SMB_INFO_STANDARD || infoLevel == SMB_INFO_QUERY_EA_SIZE) {
3107 /* lock the vnode with a callback; we need the current status
3108 * to determine what the new status is, in some cases.
3110 lock_ObtainMutex(&scp->mx);
3111 code = cm_SyncOp(scp, NULL, userp, &req, 0,
3112 CM_SCACHESYNC_GETSTATUS
3113 | CM_SCACHESYNC_NEEDCALLBACK);
3115 lock_ReleaseMutex(&scp->mx);
3118 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3120 lock_ReleaseMutex(&scp->mx);
3121 lock_ObtainMutex(&fidp->mx);
3122 lock_ObtainMutex(&scp->mx);
3124 /* prepare for setattr call */
3125 attr.mask = CM_ATTRMASK_LENGTH;
3126 attr.length.LowPart = spi->u.QPstandardInfo.dataSize;
3127 attr.length.HighPart = 0;
3129 if (spi->u.QPstandardInfo.lastWriteDateTime != 0) {
3130 smb_UnixTimeFromSearchTime(&attr.clientModTime, spi->u.QPstandardInfo.lastWriteDateTime);
3131 attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
3132 fidp->flags |= SMB_FID_MTIMESETDONE;
3135 if (spi->u.QPstandardInfo.attributes != 0) {
3136 if ((scp->unixModeBits & 0222)
3137 && (spi->u.QPstandardInfo.attributes & SMB_ATTR_READONLY) != 0) {
3138 /* make a writable file read-only */
3139 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
3140 attr.unixModeBits = scp->unixModeBits & ~0222;
3142 else if ((scp->unixModeBits & 0222) == 0
3143 && (spi->u.QPstandardInfo.attributes & SMB_ATTR_READONLY) == 0) {
3144 /* make a read-only file writable */
3145 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
3146 attr.unixModeBits = scp->unixModeBits | 0222;
3149 lock_ReleaseMutex(&scp->mx);
3150 lock_ReleaseMutex(&fidp->mx);
3154 code = cm_SetAttr(scp, &attr, userp, &req);
3158 else if (infoLevel == SMB_INFO_QUERY_ALL_EAS) {
3159 /* we don't support EAs */
3160 code = CM_ERROR_INVAL;
3164 cm_ReleaseSCache(scp);
3165 cm_ReleaseUser(userp);
3166 smb_ReleaseFID(fidp);
3168 smb_SendTran2Packet(vcp, outp, opx);
3170 smb_SendTran2Error(vcp, p, opx, code);
3171 smb_FreeTran2Packet(outp);
3177 long smb_ReceiveTran2QFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
3179 smb_tran2Packet_t *outp;
3181 unsigned long attributes;
3182 unsigned short infoLevel;
3189 smb_tran2QFileInfo_t qfi;
3196 fidp = smb_FindFID(vcp, fid, 0);
3199 smb_SendTran2Error(vcp, p, opx, CM_ERROR_BADFD);
3203 infoLevel = p->parmsp[1];
3204 if (infoLevel == SMB_QUERY_FILE_BASIC_INFO)
3205 responseSize = sizeof(qfi.u.QFbasicInfo);
3206 else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO)
3207 responseSize = sizeof(qfi.u.QFstandardInfo);
3208 else if (infoLevel == SMB_QUERY_FILE_EA_INFO)
3209 responseSize = sizeof(qfi.u.QFeaInfo);
3210 else if (infoLevel == SMB_QUERY_FILE_NAME_INFO)
3211 responseSize = sizeof(qfi.u.QFfileNameInfo);
3213 osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
3214 p->opcode, infoLevel);
3215 smb_SendTran2Error(vcp, p, opx, CM_ERROR_BAD_LEVEL);
3216 smb_ReleaseFID(fidp);
3219 osi_Log2(smb_logp, "T2 QFileInfo type 0x%x fid %d", infoLevel, fid);
3221 outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, responseSize);
3223 if (infoLevel > 0x100)
3224 outp->totalParms = 2;
3226 outp->totalParms = 0;
3227 outp->totalData = responseSize;
3229 userp = smb_GetTran2User(vcp, p);
3231 osi_Log1(smb_logp, "ReceiveTran2QFileInfo unable to resolve user [%d]", p->uid);
3232 code = CM_ERROR_BADSMB;
3236 lock_ObtainMutex(&fidp->mx);
3237 delonclose = fidp->flags & SMB_FID_DELONCLOSE;
3239 osi_Log2(smb_logp,"smb_ReleaseTran2QFileInfo fidp 0x%p scp 0x%p", fidp, scp);
3241 lock_ReleaseMutex(&fidp->mx);
3242 lock_ObtainMutex(&scp->mx);
3243 code = cm_SyncOp(scp, NULL, userp, &req, 0,
3244 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3248 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3250 /* now we have the status in the cache entry, and everything is locked.
3251 * Marshall the output data.
3253 if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
3254 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
3255 qfi.u.QFbasicInfo.creationTime = ft;
3256 qfi.u.QFbasicInfo.lastAccessTime = ft;
3257 qfi.u.QFbasicInfo.lastWriteTime = ft;
3258 qfi.u.QFbasicInfo.lastChangeTime = ft;
3259 attributes = smb_ExtAttributes(scp);
3260 qfi.u.QFbasicInfo.attributes = attributes;
3262 else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO) {
3263 qfi.u.QFstandardInfo.allocationSize = scp->length;
3264 qfi.u.QFstandardInfo.endOfFile = scp->length;
3265 qfi.u.QFstandardInfo.numberOfLinks = scp->linkCount;
3266 qfi.u.QFstandardInfo.deletePending = (delonclose ? 1 : 0);
3267 qfi.u.QFstandardInfo.directory =
3268 ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
3269 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
3270 scp->fileType == CM_SCACHETYPE_INVALID)? 1 : 0);
3272 else if (infoLevel == SMB_QUERY_FILE_EA_INFO) {
3273 qfi.u.QFeaInfo.eaSize = 0;
3275 else if (infoLevel == SMB_QUERY_FILE_NAME_INFO) {
3279 lock_ReleaseMutex(&scp->mx);
3280 lock_ObtainMutex(&fidp->mx);
3281 lock_ObtainMutex(&scp->mx);
3282 if (fidp->NTopen_wholepathp)
3283 name = fidp->NTopen_wholepathp;
3285 name = "\\"; /* probably can't happen */
3286 lock_ReleaseMutex(&fidp->mx);
3287 len = (unsigned long)strlen(name);
3288 outp->totalData = ((len+1)*2) + 4; /* this is actually what we want to return */
3289 qfi.u.QFfileNameInfo.fileNameLength = (len + 1) * 2;
3290 mbstowcs((unsigned short *)qfi.u.QFfileNameInfo.fileName, name, len + 1);
3293 /* send and free the packets */
3295 lock_ReleaseMutex(&scp->mx);
3296 cm_ReleaseSCache(scp);
3297 cm_ReleaseUser(userp);
3298 smb_ReleaseFID(fidp);
3300 memcpy(outp->datap, &qfi, responseSize);
3301 smb_SendTran2Packet(vcp, outp, opx);
3303 smb_SendTran2Error(vcp, p, opx, code);
3305 smb_FreeTran2Packet(outp);
3310 long smb_ReceiveTran2SetFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
3315 unsigned short infoLevel;
3316 smb_tran2Packet_t *outp;
3317 cm_user_t *userp = NULL;
3318 cm_scache_t *scp = NULL;
3324 fidp = smb_FindFID(vcp, fid, 0);
3327 smb_SendTran2Error(vcp, p, opx, CM_ERROR_BADFD);
3331 infoLevel = p->parmsp[1];
3332 osi_Log2(smb_logp,"ReceiveTran2SetFileInfo type 0x%x fid %d", infoLevel, fid);
3333 if (infoLevel > SMB_SET_FILE_END_OF_FILE_INFO || infoLevel < SMB_SET_FILE_BASIC_INFO) {
3334 osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
3335 p->opcode, infoLevel);
3336 smb_SendTran2Error(vcp, p, opx, CM_ERROR_BAD_LEVEL);
3337 smb_ReleaseFID(fidp);
3341 lock_ObtainMutex(&fidp->mx);
3342 if (infoLevel == SMB_SET_FILE_DISPOSITION_INFO &&
3343 !(fidp->flags & SMB_FID_OPENDELETE)) {
3344 osi_Log3(smb_logp,"smb_ReceiveTran2SetFileInfo !SMB_FID_OPENDELETE fidp 0x%p scp 0x%p fidp->flags 0x%x",
3345 fidp, fidp->scp, fidp->flags);
3346 lock_ReleaseMutex(&fidp->mx);
3347 smb_ReleaseFID(fidp);
3348 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOACCESS);
3351 if ((infoLevel == SMB_SET_FILE_ALLOCATION_INFO ||
3352 infoLevel == SMB_SET_FILE_END_OF_FILE_INFO)
3353 && !(fidp->flags & SMB_FID_OPENWRITE)) {
3354 osi_Log3(smb_logp,"smb_ReceiveTran2SetFileInfo !SMB_FID_OPENWRITE fidp 0x%p scp 0x%p fidp->flags 0x%x",
3355 fidp, fidp->scp, fidp->flags);
3356 lock_ReleaseMutex(&fidp->mx);
3357 smb_ReleaseFID(fidp);
3358 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOACCESS);
3363 osi_Log2(smb_logp,"smb_ReceiveTran2SetFileInfo fidp 0x%p scp 0x%p", fidp, scp);
3365 lock_ReleaseMutex(&fidp->mx);
3367 outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, 0);
3369 outp->totalParms = 2;
3370 outp->totalData = 0;
3372 userp = smb_GetTran2User(vcp, p);
3374 osi_Log1(smb_logp,"ReceiveTran2SetFileInfo unable to resolve user [%d]", p->uid);
3375 code = CM_ERROR_BADSMB;
3379 if (infoLevel == SMB_SET_FILE_BASIC_INFO) {
3381 unsigned int attribute;
3383 smb_tran2QFileInfo_t *sfi;
3385 sfi = (smb_tran2QFileInfo_t *)p->datap;
3387 /* lock the vnode with a callback; we need the current status
3388 * to determine what the new status is, in some cases.
3390 lock_ObtainMutex(&scp->mx);
3391 code = cm_SyncOp(scp, NULL, userp, &req, 0,
3392 CM_SCACHESYNC_GETSTATUS
3393 | CM_SCACHESYNC_NEEDCALLBACK);
3395 lock_ReleaseMutex(&scp->mx);
3399 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3401 lock_ReleaseMutex(&scp->mx);
3402 lock_ObtainMutex(&fidp->mx);
3403 lock_ObtainMutex(&scp->mx);
3405 /* prepare for setattr call */
3408 lastMod = sfi->u.QFbasicInfo.lastWriteTime;
3409 /* when called as result of move a b, lastMod is (-1, -1).
3410 * If the check for -1 is not present, timestamp
3411 * of the resulting file will be 1969 (-1)
3413 if (LargeIntegerNotEqualToZero(*((LARGE_INTEGER *)&lastMod)) &&
3414 lastMod.dwLowDateTime != -1 && lastMod.dwHighDateTime != -1) {
3415 attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
3416 smb_UnixTimeFromLargeSearchTime(&attr.clientModTime, &lastMod);
3417 fidp->flags |= SMB_FID_MTIMESETDONE;
3420 attribute = sfi->u.QFbasicInfo.attributes;
3421 if (attribute != 0) {
3422 if ((scp->unixModeBits & 0222)
3423 && (attribute & SMB_ATTR_READONLY) != 0) {
3424 /* make a writable file read-only */
3425 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
3426 attr.unixModeBits = scp->unixModeBits & ~0222;
3428 else if ((scp->unixModeBits & 0222) == 0
3429 && (attribute & SMB_ATTR_READONLY) == 0) {
3430 /* make a read-only file writable */
3431 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
3432 attr.unixModeBits = scp->unixModeBits | 0222;
3435 lock_ReleaseMutex(&scp->mx);
3436 lock_ReleaseMutex(&fidp->mx);
3440 code = cm_SetAttr(scp, &attr, userp, &req);
3444 else if (infoLevel == SMB_SET_FILE_DISPOSITION_INFO) {
3445 int delflag = *((char *)(p->datap));
3446 osi_Log3(smb_logp,"smb_ReceiveTran2SetFileInfo Delete? %d fidp 0x%p scp 0x%p",
3447 delflag, fidp, scp);
3448 if (*((char *)(p->datap))) { /* File is Deleted */
3449 code = cm_CheckNTDelete(fidp->NTopen_dscp, scp, userp,
3452 lock_ObtainMutex(&fidp->mx);
3453 fidp->flags |= SMB_FID_DELONCLOSE;
3454 lock_ReleaseMutex(&fidp->mx);
3456 osi_Log3(smb_logp,"smb_ReceiveTran2SetFileInfo CheckNTDelete fidp 0x%p scp 0x%p code 0x%x",
3462 lock_ObtainMutex(&fidp->mx);
3463 fidp->flags &= ~SMB_FID_DELONCLOSE;
3464 lock_ReleaseMutex(&fidp->mx);
3467 else if (infoLevel == SMB_SET_FILE_ALLOCATION_INFO ||
3468 infoLevel == SMB_SET_FILE_END_OF_FILE_INFO) {
3469 LARGE_INTEGER size = *((LARGE_INTEGER *)(p->datap));
3472 attr.mask = CM_ATTRMASK_LENGTH;
3473 attr.length.LowPart = size.LowPart;
3474 attr.length.HighPart = size.HighPart;
3475 code = cm_SetAttr(scp, &attr, userp, &req);
3479 cm_ReleaseSCache(scp);
3480 cm_ReleaseUser(userp);
3481 smb_ReleaseFID(fidp);
3483 smb_SendTran2Packet(vcp, outp, opx);
3485 smb_SendTran2Error(vcp, p, opx, code);
3486 smb_FreeTran2Packet(outp);
3492 smb_ReceiveTran2FSCTL(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3494 osi_Log0(smb_logp,"ReceiveTran2FSCTL - NOT_SUPPORTED");
3495 return CM_ERROR_BADOP;
3499 smb_ReceiveTran2IOCTL(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3501 osi_Log0(smb_logp,"ReceiveTran2IOCTL - NOT_SUPPORTED");
3502 return CM_ERROR_BADOP;
3506 smb_ReceiveTran2FindNotifyFirst(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3508 osi_Log0(smb_logp,"ReceiveTran2FindNotifyFirst - NOT_SUPPORTED");
3509 return CM_ERROR_BADOP;
3513 smb_ReceiveTran2FindNotifyNext(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3515 osi_Log0(smb_logp,"ReceiveTran2FindNotifyNext - NOT_SUPPORTED");
3516 return CM_ERROR_BADOP;
3520 smb_ReceiveTran2CreateDirectory(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3522 osi_Log0(smb_logp,"ReceiveTran2CreateDirectory - NOT_SUPPORTED");
3523 return CM_ERROR_BADOP;
3527 smb_ReceiveTran2SessionSetup(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3529 osi_Log0(smb_logp,"ReceiveTran2SessionSetup - NOT_SUPPORTED");
3530 return CM_ERROR_BADOP;
3533 struct smb_v2_referral {
3535 USHORT ReferralFlags;
3538 USHORT DfsPathOffset;
3539 USHORT DfsAlternativePathOffset;
3540 USHORT NetworkAddressOffset;
3544 smb_ReceiveTran2GetDFSReferral(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
3546 /* This is a UNICODE only request (bit15 of Flags2) */
3547 /* The TID must be IPC$ */
3549 /* The documentation for the Flags response field is contradictory */
3551 /* Use Version 1 Referral Element Format */
3552 /* ServerType = 0; indicates the next server should be queried for the file */
3553 /* ReferralFlags = 0x01; PathConsumed characters should be stripped */
3554 /* Node = UnicodeString of UNC path of the next share name */
3557 int maxReferralLevel = 0;
3558 char requestFileName[1024] = "";
3559 smb_tran2Packet_t *outp = 0;
3560 cm_user_t *userp = 0;
3562 CPINFO CodePageInfo;
3563 int i, nbnLen, reqLen;
3568 maxReferralLevel = p->parmsp[0];
3570 GetCPInfo(CP_ACP, &CodePageInfo);
3571 WideCharToMultiByte(CP_ACP, 0, (LPCWSTR) &p->parmsp[1], -1,
3572 requestFileName, 1024, NULL, NULL);
3574 osi_Log2(smb_logp,"ReceiveTran2GetDfsReferral [%d][%s]",
3575 maxReferralLevel, osi_LogSaveString(smb_logp, requestFileName));
3577 nbnLen = strlen(cm_NetbiosName);
3578 reqLen = strlen(requestFileName);
3580 if (reqLen == nbnLen + 5 &&
3581 requestFileName[0] == '\\' &&
3582 !_strnicmp(cm_NetbiosName,&requestFileName[1],nbnLen) &&
3583 requestFileName[nbnLen+1] == '\\' &&
3584 (!_strnicmp("all",&requestFileName[nbnLen+2],3) ||
3585 !_strnicmp("*.",&requestFileName[nbnLen+2],2)))
3588 struct smb_v2_referral * v2ref;
3589 outp = smb_GetTran2ResponsePacket(vcp, p, op, 0, 2 * (reqLen + 8));
3591 sp = (USHORT *)outp->datap;
3593 sp[idx++] = reqLen; /* path consumed */
3594 sp[idx++] = 1; /* number of referrals */
3595 sp[idx++] = 0x03; /* flags */
3596 #ifdef DFS_VERSION_1
3597 sp[idx++] = 1; /* Version Number */
3598 sp[idx++] = reqLen + 4; /* Referral Size */
3599 sp[idx++] = 1; /* Type = SMB Server */
3600 sp[idx++] = 0; /* Do not strip path consumed */
3601 for ( i=0;i<=reqLen; i++ )
3602 sp[i+idx] = requestFileName[i];
3603 #else /* DFS_VERSION_2 */
3604 sp[idx++] = 2; /* Version Number */
3605 sp[idx++] = sizeof(struct smb_v2_referral); /* Referral Size */
3606 idx += (sizeof(struct smb_v2_referral) / 2);
3607 v2ref = (struct smb_v2_referral *) &sp[5];
3608 v2ref->ServerType = 1; /* SMB Server */
3609 v2ref->ReferralFlags = 0x03;
3610 v2ref->Proximity = 0; /* closest */
3611 v2ref->TimeToLive = 3600; /* seconds */
3612 v2ref->DfsPathOffset = idx * 2;
3613 v2ref->DfsAlternativePathOffset = idx * 2;
3614 v2ref->NetworkAddressOffset = 0;
3615 for ( i=0;i<=reqLen; i++ )
3616 sp[i+idx] = requestFileName[i];
3619 userp = smb_GetTran2User(vcp, p);
3621 osi_Log1(smb_logp,"ReceiveTran2GetDfsReferral unable to resolve user [%d]", p->uid);
3622 code = CM_ERROR_BADSMB;
3627 code = CM_ERROR_NOSUCHPATH;
3632 cm_ReleaseUser(userp);
3634 smb_SendTran2Packet(vcp, outp, op);
3636 smb_SendTran2Error(vcp, p, op, code);
3638 smb_FreeTran2Packet(outp);
3641 #else /* DFS_SUPPORT */
3642 osi_Log0(smb_logp,"ReceiveTran2GetDfsReferral - NOT_SUPPORTED");
3643 return CM_ERROR_BADOP;
3644 #endif /* DFS_SUPPORT */
3648 smb_ReceiveTran2ReportDFSInconsistency(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3650 /* This is a UNICODE only request (bit15 of Flags2) */
3652 /* There is nothing we can do about this operation. The client is going to
3653 * tell us that there is a Version 1 Referral Element for which there is a DFS Error.
3654 * Unfortunately, there is really nothing we can do about it other then log it
3655 * somewhere. Even then I don't think there is anything for us to do.
3656 * So let's return an error value.
3659 osi_Log0(smb_logp,"ReceiveTran2ReportDFSInconsistency - NOT_SUPPORTED");
3660 return CM_ERROR_BADOP;
3664 smb_ApplyV3DirListPatches(cm_scache_t *dscp,
3665 smb_dirListPatch_t **dirPatchespp, int infoLevel, cm_user_t *userp,
3670 cm_scache_t *targetScp; /* target if scp is a symlink */
3675 unsigned short attr;
3676 unsigned long lattr;
3677 smb_dirListPatch_t *patchp;
3678 smb_dirListPatch_t *npatchp;
3680 afs_int32 mustFake = 0;
3682 code = cm_FindACLCache(dscp, userp, &rights);
3683 if (code == 0 && !(rights & PRSFS_READ))
3685 else if (code == -1) {
3686 lock_ObtainMutex(&dscp->mx);
3687 code = cm_SyncOp(dscp, NULL, userp, reqp, PRSFS_READ,
3688 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3689 lock_ReleaseMutex(&dscp->mx);
3690 if (code == CM_ERROR_NOACCESS) {
3698 for(patchp = *dirPatchespp; patchp; patchp =
3699 (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
3700 code = cm_GetSCache(&patchp->fid, &scp, userp, reqp);
3704 lock_ObtainMutex(&scp->mx);
3706 code = cm_SyncOp(scp, NULL, userp, reqp, 0,
3707 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3708 if (mustFake || code) {
3709 lock_ReleaseMutex(&scp->mx);
3711 dptr = patchp->dptr;
3713 /* Plug in fake timestamps. A time stamp of 0 causes 'invalid parameter'
3714 errors in the client. */
3715 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO) {
3716 /* 1969-12-31 23:59:59 +00 */
3717 ft.dwHighDateTime = 0x19DB200;
3718 ft.dwLowDateTime = 0x5BB78980;
3720 /* copy to Creation Time */
3721 *((FILETIME *)dptr) = ft;
3724 /* copy to Last Access Time */
3725 *((FILETIME *)dptr) = ft;
3728 /* copy to Last Write Time */
3729 *((FILETIME *)dptr) = ft;
3732 /* copy to Change Time */
3733 *((FILETIME *)dptr) = ft;
3736 switch (scp->fileType) {
3737 case CM_SCACHETYPE_DIRECTORY:
3738 case CM_SCACHETYPE_MOUNTPOINT:
3739 case CM_SCACHETYPE_SYMLINK:
3740 case CM_SCACHETYPE_INVALID:
3741 *((u_long *)dptr) = SMB_ATTR_DIRECTORY;
3744 /* if we get here we either have a normal file
3745 * or we have a file for which we have never
3746 * received status info. In this case, we can
3747 * check the even/odd value of the entry's vnode.
3748 * even means it is to be treated as a directory
3749 * and odd means it is to be treated as a file.
3751 if (mustFake && (scp->fid.vnode & 0x1))
3752 *((u_long *)dptr) = SMB_ATTR_DIRECTORY;
3754 *((u_long *)dptr) = SMB_ATTR_NORMAL;
3757 /* merge in hidden attribute */
3758 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
3759 *((u_long *)dptr) |= SMB_ATTR_HIDDEN;
3763 /* 1969-12-31 23:59:58 +00*/
3764 dosTime = 0xEBBFBF7D;
3766 /* and copy out date */
3767 shortTemp = (dosTime>>16) & 0xffff;
3768 *((u_short *)dptr) = shortTemp;
3771 /* copy out creation time */
3772 shortTemp = dosTime & 0xffff;
3773 *((u_short *)dptr) = shortTemp;
3776 /* and copy out date */
3777 shortTemp = (dosTime>>16) & 0xffff;
3778 *((u_short *)dptr) = shortTemp;
3781 /* copy out access time */
3782 shortTemp = dosTime & 0xffff;
3783 *((u_short *)dptr) = shortTemp;
3786 /* and copy out date */
3787 shortTemp = (dosTime>>16) & 0xffff;
3788 *((u_short *)dptr) = shortTemp;
3791 /* copy out mod time */
3792 shortTemp = dosTime & 0xffff;
3793 *((u_short *)dptr) = shortTemp;
3796 /* set the attribute */
3797 switch (scp->fileType) {
3798 case CM_SCACHETYPE_DIRECTORY:
3799 case CM_SCACHETYPE_MOUNTPOINT:
3800 case CM_SCACHETYPE_SYMLINK:
3801 case CM_SCACHETYPE_INVALID:
3802 attr = SMB_ATTR_DIRECTORY;
3804 attr = SMB_ATTR_NORMAL;
3806 /* merge in hidden (dot file) attribute */
3807 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
3808 attr |= SMB_ATTR_HIDDEN;
3810 *dptr++ = attr & 0xff;
3811 *dptr++ = (attr >> 8) & 0xff;
3814 cm_ReleaseSCache(scp);
3818 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3820 /* now watch for a symlink */
3822 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
3823 lock_ReleaseMutex(&scp->mx);
3824 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, reqp);
3826 /* we have a more accurate file to use (the
3827 * target of the symbolic link). Otherwise,
3828 * we'll just use the symlink anyway.
3830 osi_Log2(smb_logp, "symlink vp %x to vp %x",
3832 cm_ReleaseSCache(scp);
3835 lock_ObtainMutex(&scp->mx);
3838 dptr = patchp->dptr;
3840 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO) {
3842 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
3844 /* copy to Creation Time */
3845 *((FILETIME *)dptr) = ft;
3848 /* copy to Last Access Time */
3849 *((FILETIME *)dptr) = ft;
3852 /* copy to Last Write Time */
3853 *((FILETIME *)dptr) = ft;
3856 /* copy to Change Time */
3857 *((FILETIME *)dptr) = ft;
3860 /* Use length for both file length and alloc length */
3861 *((LARGE_INTEGER *)dptr) = scp->length;
3863 *((LARGE_INTEGER *)dptr) = scp->length;
3866 /* Copy attributes */
3867 lattr = smb_ExtAttributes(scp);
3868 if (code == CM_ERROR_NOSUCHPATH && scp->fileType == CM_SCACHETYPE_SYMLINK) {
3869 if (lattr == SMB_ATTR_NORMAL)
3870 lattr = SMB_ATTR_DIRECTORY;
3872 lattr |= SMB_ATTR_DIRECTORY;
3874 /* merge in hidden (dot file) attribute */
3875 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
3876 if (lattr == SMB_ATTR_NORMAL)
3877 lattr = SMB_ATTR_HIDDEN;
3879 lattr |= SMB_ATTR_HIDDEN;
3881 *((u_long *)dptr) = lattr;
3885 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
3887 /* and copy out date */
3888 shortTemp = (dosTime>>16) & 0xffff;
3889 *((u_short *)dptr) = shortTemp;
3892 /* copy out creation time */
3893 shortTemp = dosTime & 0xffff;
3894 *((u_short *)dptr) = shortTemp;
3897 /* and copy out date */
3898 shortTemp = (dosTime>>16) & 0xffff;
3899 *((u_short *)dptr) = shortTemp;
3902 /* copy out access time */
3903 shortTemp = dosTime & 0xffff;
3904 *((u_short *)dptr) = shortTemp;
3907 /* and copy out date */
3908 shortTemp = (dosTime>>16) & 0xffff;
3909 *((u_short *)dptr) = shortTemp;
3912 /* copy out mod time */
3913 shortTemp = dosTime & 0xffff;
3914 *((u_short *)dptr) = shortTemp;
3917 /* copy out file length and alloc length,
3918 * using the same for both
3920 *((u_long *)dptr) = scp->length.LowPart;
3922 *((u_long *)dptr) = scp->length.LowPart;
3925 /* finally copy out attributes as short */
3926 attr = smb_Attributes(scp);
3927 /* merge in hidden (dot file) attribute */
3928 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
3929 if (lattr == SMB_ATTR_NORMAL)
3930 lattr = SMB_ATTR_HIDDEN;
3932 lattr |= SMB_ATTR_HIDDEN;
3934 *dptr++ = attr & 0xff;
3935 *dptr++ = (attr >> 8) & 0xff;
3938 lock_ReleaseMutex(&scp->mx);
3939 cm_ReleaseSCache(scp);
3942 /* now free the patches */
3943 for (patchp = *dirPatchespp; patchp; patchp = npatchp) {
3944 npatchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q);
3948 /* and mark the list as empty */
3949 *dirPatchespp = NULL;
3954 #ifndef USE_OLD_MATCHING
3955 // char table for case insensitive comparison
3956 char mapCaseTable[256];
3958 VOID initUpperCaseTable(VOID)
3961 for (i = 0; i < 256; ++i)
3962 mapCaseTable[i] = toupper(i);
3963 // make '"' match '.'
3964 mapCaseTable[(int)'"'] = toupper('.');
3965 // make '<' match '*'
3966 mapCaseTable[(int)'<'] = toupper('*');
3967 // make '>' match '?'
3968 mapCaseTable[(int)'>'] = toupper('?');
3971 // Compare 'pattern' (containing metacharacters '*' and '?') with the file
3973 // Note : this procedure works recursively calling itself.
3975 // PSZ pattern : string containing metacharacters.
3976 // PSZ name : file name to be compared with 'pattern'.
3978 // BOOL : TRUE/FALSE (match/mistmatch)
3981 szWildCardMatchFileName(PSZ pattern, PSZ name, int casefold)
3983 PSZ pename; // points to the last 'name' character
3985 pename = name + strlen(name) - 1;
3996 if (*pattern == '\0')
3998 for (p = pename; p >= name; --p) {
3999 if ((casefold && (mapCaseTable[*p] == mapCaseTable[*pattern]) ||
4000 !casefold && (*p == *pattern)) &&
4001 szWildCardMatchFileName(pattern + 1, p + 1, casefold))
4006 if ((casefold && mapCaseTable[*name] != mapCaseTable[*pattern]) ||
4007 (!casefold && *name != *pattern))
4014 /* if all we have left are wildcards, then we match */
4015 for (;*pattern; pattern++) {
4016 if (*pattern != '*' && *pattern != '?')
4022 /* do a case-folding search of the star name mask with the name in namep.
4023 * Return 1 if we match, otherwise 0.
4025 int smb_V3MatchMask(char *namep, char *maskp, int flags)
4028 int i, j, star, qmark, casefold, retval;
4030 /* make sure we only match 8.3 names, if requested */
4031 if ((flags & CM_FLAG_8DOT3) && !cm_Is8Dot3(namep))
4034 casefold = (flags & CM_FLAG_CASEFOLD) ? 1 : 0;
4036 /* optimize the pattern:
4037 * if there is a mixture of '?' and '*',
4038 * for example the sequence "*?*?*?*"
4039 * must be turned into the form "*"
4041 newmask = (char *)malloc(strlen(maskp)+1);
4042 for ( i=0, j=0, star=0, qmark=0; maskp[i]; i++) {
4043 switch ( maskp[i] ) {
4055 } else if ( qmark ) {
4059 newmask[j++] = maskp[i];
4066 } else if ( qmark ) {
4070 newmask[j++] = '\0';
4072 retval = szWildCardMatchFileName(newmask, namep, casefold) ? 1:0;
4078 #else /* USE_OLD_MATCHING */
4079 /* do a case-folding search of the star name mask with the name in namep.
4080 * Return 1 if we match, otherwise 0.
4082 int smb_V3MatchMask(char *namep, char *maskp, int flags)
4084 unsigned char tcp1, tcp2; /* Pattern characters */
4085 unsigned char tcn1; /* Name characters */
4086 int sawDot = 0, sawStar = 0, req8dot3 = 0;
4087 char *starNamep, *starMaskp;
4088 static char nullCharp[] = {0};
4089 int casefold = flags & CM_FLAG_CASEFOLD;
4091 /* make sure we only match 8.3 names, if requested */
4092 req8dot3 = (flags & CM_FLAG_8DOT3);
4093 if (req8dot3 && !cm_Is8Dot3(namep))
4098 /* Next pattern character */
4101 /* Next name character */
4105 /* 0 - end of pattern */
4111 else if (tcp1 == '.' || tcp1 == '"') {
4121 * first dot in pattern;
4122 * must match dot or end of name
4127 else if (tcn1 == '.') {
4136 else if (tcp1 == '?') {
4137 if (tcn1 == 0 || tcn1 == '.')
4142 else if (tcp1 == '>') {
4143 if (tcn1 != 0 && tcn1 != '.')
4147 else if (tcp1 == '*' || tcp1 == '<') {
4151 else if ((req8dot3 && tcp2 == '.') || tcp2 == '"') {
4152 while (req8dot3 && tcn1 != '.' && tcn1 != 0)
4167 * pattern character after '*' is not null or
4168 * period. If it is '?' or '>', we are not
4169 * going to understand it. If it is '*' or
4170 * '<', we are going to skip over it. None of
4171 * these are likely, I hope.
4173 /* skip over '*' and '<' */
4174 while (tcp2 == '*' || tcp2 == '<')
4177 /* skip over characters that don't match tcp2 */
4178 while (req8dot3 && tcn1 != '.' && tcn1 != 0 &&
4179 ((casefold && cm_foldUpper[tcn1] != cm_foldUpper[tcp2]) ||
4180 (!casefold && tcn1 != tcp2)))
4184 if ((req8dot3 && tcn1 == '.') || tcn1 == 0)
4187 /* Remember where we are */
4197 /* tcp1 is not a wildcard */
4198 if ((casefold && cm_foldUpper[tcn1] == cm_foldUpper[tcp1]) ||
4199 (!casefold && tcn1 == tcp1)) {
4204 /* if trying to match a star pattern, go back */
4206 maskp = starMaskp - 2;
4207 namep = starNamep + 1;
4216 #endif /* USE_OLD_MATCHING */
4218 /* smb_ReceiveTran2SearchDir implements both
4219 * Tran2_Find_First and Tran2_Find_Next
4221 #define TRAN2_FIND_FLAG_CLOSE_SEARCH 0x01
4222 #define TRAN2_FIND_FLAG_CLOSE_SEARCH_IF_END 0x02
4223 #define TRAN2_FIND_FLAG_RETURN_RESUME_KEYS 0x04
4224 #define TRAN2_FIND_FLAG_CONTINUE_SEARCH 0x08
4225 #define TRAN2_FIND_FLAG_BACKUP_INTENT 0x10
4227 /* this is an optimized handler for T2SearchDir that handles the case
4228 where there are no wildcards in the search path. I.e. an
4229 application is using FindFirst(Ex) to get information about a
4230 single file or directory. It will attempt to do a single lookup.
4231 If that fails, then smb_ReceiveTran2SearchDir() will fall back to
4232 the usual mechanism.
4234 This function will return either CM_ERROR_NOSUCHFILE or SUCCESS.
4236 long smb_T2SearchDirSingle(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
4240 long code = 0, code2 = 0;
4243 smb_dirListPatch_t *dirListPatchesp;
4244 smb_dirListPatch_t *curPatchp;
4245 long orbytes; /* # of bytes in this output record */
4246 long ohbytes; /* # of bytes, except file name */
4247 long onbytes; /* # of bytes in name, incl. term. null */
4248 cm_scache_t *scp = NULL;
4249 cm_scache_t *targetscp = NULL;
4250 cm_user_t *userp = NULL;
4251 char *op; /* output data ptr */
4252 char *origOp; /* original value of op */
4253 cm_space_t *spacep; /* for pathname buffer */
4254 long maxReturnData; /* max # of return data */
4255 long maxReturnParms; /* max # of return parms */
4256 long bytesInBuffer; /* # data bytes in the output buffer */
4257 char *maskp; /* mask part of path */
4261 smb_tran2Packet_t *outp; /* response packet */
4264 char shortName[13]; /* 8.3 name if needed */
4273 osi_assert(p->opcode == 1);
4275 /* find first; obtain basic parameters from request */
4277 /* note that since we are going to failover to regular
4278 * processing at smb_ReceiveTran2SearchDir(), we shouldn't
4279 * modify any of the input parameters here. */
4280 attribute = p->parmsp[0];
4281 maxCount = p->parmsp[1];
4282 infoLevel = p->parmsp[3];
4283 searchFlags = p->parmsp[2];
4284 pathp = ((char *) p->parmsp) + 12; /* points to path */
4286 maskp = strrchr(pathp, '\\');
4290 maskp++; /* skip over backslash */
4291 /* track if this is likely to match a lot of entries */
4293 osi_Log2(smb_logp, "smb_T2SearchDirSingle : path[%s], mask[%s]",
4294 osi_LogSaveString(smb_logp, pathp),
4295 osi_LogSaveString(smb_logp, maskp));
4297 switch ( infoLevel ) {
4298 case SMB_INFO_STANDARD:
4301 case SMB_INFO_QUERY_EA_SIZE:
4302 s = "InfoQueryEaSize";
4304 case SMB_INFO_QUERY_EAS_FROM_LIST:
4305 s = "InfoQueryEasFromList";
4307 case SMB_FIND_FILE_DIRECTORY_INFO:
4308 s = "FindFileDirectoryInfo";
4310 case SMB_FIND_FILE_FULL_DIRECTORY_INFO:
4311 s = "FindFileFullDirectoryInfo";
4313 case SMB_FIND_FILE_NAMES_INFO:
4314 s = "FindFileNamesInfo";
4316 case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
4317 s = "FindFileBothDirectoryInfo";
4320 s = "unknownInfoLevel";
4323 osi_Log1(smb_logp, "smb_T2SearchDirSingle info level: %s", s);
4326 "smb_T2SearchDirSingle attr 0x%x, info level 0x%x, max count %d, flags 0x%x",
4327 attribute, infoLevel, maxCount, searchFlags);
4329 if (infoLevel > SMB_FIND_FILE_BOTH_DIRECTORY_INFO) {
4330 osi_Log1(smb_logp, "Unsupported InfoLevel 0x%x", infoLevel);
4331 return CM_ERROR_INVAL;
4334 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO)
4335 searchFlags &= ~TRAN2_FIND_FLAG_RETURN_RESUME_KEYS; /* no resume keys */
4337 dirListPatchesp = NULL;
4339 maxReturnData = p->maxReturnData;
4340 maxReturnParms = 10; /* return params for findfirst, which
4341 is the only one we handle.*/
4343 #ifndef CM_CONFIG_MULTITRAN2RESPONSES
4344 if (maxReturnData > 6000)
4345 maxReturnData = 6000;
4346 #endif /* CM_CONFIG_MULTITRAN2RESPONSES */
4348 outp = smb_GetTran2ResponsePacket(vcp, p, opx, maxReturnParms,
4351 osi_Log2(smb_logp, "T2SDSingle search dir count %d [%s]",
4352 maxCount, osi_LogSaveString(smb_logp, pathp));
4354 /* bail out if request looks bad */
4356 smb_FreeTran2Packet(outp);
4357 return CM_ERROR_BADSMB;
4360 userp = smb_GetTran2User(vcp, p);
4362 osi_Log1(smb_logp, "T2SDSingle search dir unable to resolve user [%d]", p->uid);
4363 smb_FreeTran2Packet(outp);
4364 return CM_ERROR_BADSMB;
4367 /* try to get the vnode for the path name next */
4368 spacep = cm_GetSpace();
4369 smb_StripLastComponent(spacep->data, NULL, pathp);
4370 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
4372 cm_ReleaseUser(userp);
4373 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOFILES);
4374 smb_FreeTran2Packet(outp);
4378 code = cm_NameI(cm_data.rootSCachep, spacep->data,
4379 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
4380 userp, tidPathp, &req, &scp);
4381 cm_FreeSpace(spacep);
4384 cm_ReleaseUser(userp);
4385 smb_SendTran2Error(vcp, p, opx, code);
4386 smb_FreeTran2Packet(outp);
4390 #ifdef DFS_SUPPORT_BUT_NOT_FIND_FIRST
4391 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
4392 cm_ReleaseSCache(scp);
4393 cm_ReleaseUser(userp);
4394 if ( WANTS_DFS_PATHNAMES(p) )
4395 code = CM_ERROR_PATH_NOT_COVERED;
4397 code = CM_ERROR_BADSHARENAME;
4398 smb_SendTran2Error(vcp, p, opx, code);
4399 smb_FreeTran2Packet(outp);
4402 #endif /* DFS_SUPPORT */
4403 osi_Log1(smb_logp,"T2SDSingle scp 0x%p", scp);
4405 /* now do a single case sensitive lookup for the file in question */
4406 code = cm_Lookup(scp, maskp, CM_FLAG_NOMOUNTCHASE, userp, &req, &targetscp);
4408 /* if a case sensitive match failed, we try a case insensitive one
4410 if (code == CM_ERROR_NOSUCHFILE || code == CM_ERROR_BPLUS_NOMATCH) {
4411 code = cm_Lookup(scp, maskp, CM_FLAG_NOMOUNTCHASE | CM_FLAG_CASEFOLD, userp, &req, &targetscp);
4414 if (code == 0 && targetscp->fid.vnode == 0) {
4415 cm_ReleaseSCache(targetscp);
4416 code = CM_ERROR_NOSUCHFILE;
4420 /* if we can't find the directory entry, this block will
4421 return CM_ERROR_NOSUCHFILE, which we will pass on to
4422 smb_ReceiveTran2SearchDir(). */
4423 cm_ReleaseSCache(scp);
4424 cm_ReleaseUser(userp);
4425 if (code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
4426 smb_SendTran2Error(vcp, p, opx, code);
4429 smb_FreeTran2Packet(outp);
4433 /* now that we have the target in sight, we proceed with filling
4434 up the return data. */
4436 op = origOp = outp->datap;
4439 if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS) {
4440 /* skip over resume key */
4444 if (infoLevel == SMB_FIND_FILE_BOTH_DIRECTORY_INFO
4445 && targetscp->fid.vnode != 0
4446 && !cm_Is8Dot3(maskp)) {
4449 dfid.vnode = htonl(targetscp->fid.vnode);
4450 dfid.unique = htonl(targetscp->fid.unique);
4452 cm_Gen8Dot3NameInt(maskp, &dfid, shortName, &shortNameEnd);
4458 osi_Log4(smb_logp, "T2SDSingle dir vn %u uniq %u name %s (%s)",
4459 htonl(targetscp->fid.vnode),
4460 htonl(targetscp->fid.unique),
4461 osi_LogSaveString(smb_logp, pathp),
4462 NeedShortName ? osi_LogSaveString(smb_logp, shortName) : "");
4464 /* Eliminate entries that don't match requested attributes */
4465 if (smb_hideDotFiles && !(attribute & SMB_ATTR_HIDDEN) &&
4466 smb_IsDotFile(maskp)) {
4468 code = CM_ERROR_NOSUCHFILE;
4469 osi_Log0(smb_logp, "T2SDSingle skipping hidden file");
4474 if (!(attribute & SMB_ATTR_DIRECTORY) &&
4475 (targetscp->fileType == CM_SCACHETYPE_DIRECTORY ||
4476 targetscp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
4477 targetscp->fileType == CM_SCACHETYPE_DFSLINK ||
4478 targetscp->fileType == CM_SCACHETYPE_INVALID)) {
4480 code = CM_ERROR_NOSUCHFILE;
4481 osi_Log0(smb_logp, "T2SDSingle skipping directory or bad link");
4486 /* Check if the name will fit */
4487 if (infoLevel < 0x101)
4488 ohbytes = 23; /* pre-NT */
4489 else if (infoLevel == SMB_FIND_FILE_NAMES_INFO)
4490 ohbytes = 12; /* NT names only */
4492 ohbytes = 64; /* NT */
4494 if (infoLevel == SMB_FIND_FILE_BOTH_DIRECTORY_INFO)
4495 ohbytes += 26; /* Short name & length */
4497 if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS) {
4498 ohbytes += 4; /* if resume key required */
4501 if (infoLevel != SMB_INFO_STANDARD
4502 && infoLevel != SMB_FIND_FILE_DIRECTORY_INFO
4503 && infoLevel != SMB_FIND_FILE_NAMES_INFO)
4504 ohbytes += 4; /* EASIZE */
4506 /* add header to name & term. null */
4507 onbytes = strlen(maskp);
4508 orbytes = ohbytes + onbytes + 1;
4510 /* now, we round up the record to a 4 byte alignment, and we make
4511 * sure that we have enough room here for even the aligned version
4512 * (so we don't have to worry about an * overflow when we pad
4513 * things out below). That's the reason for the alignment
4516 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO)
4517 align = (4 - (orbytes & 3)) & 3;
4521 if (orbytes + align > maxReturnData) {
4523 /* even though this request is unlikely to succeed with a
4524 failover, we do it anyway. */
4525 code = CM_ERROR_NOSUCHFILE;
4526 osi_Log1(smb_logp, "T2 dir search exceed max return data %d",
4531 /* this is one of the entries to use: it is not deleted and it
4532 * matches the star pattern we're looking for. Put out the name,
4533 * preceded by its length.
4535 /* First zero everything else */
4536 memset(origOp, 0, ohbytes);
4538 if (infoLevel <= SMB_FIND_FILE_DIRECTORY_INFO)
4539 *(origOp + ohbytes - 1) = (unsigned char) onbytes;
4540 else if (infoLevel == SMB_FIND_FILE_NAMES_INFO)
4541 *((u_long *)(op + 8)) = onbytes;
4543 *((u_long *)(op + 60)) = onbytes;
4544 strcpy(origOp+ohbytes, maskp);
4545 if (smb_StoreAnsiFilenames)
4546 CharToOem(origOp+ohbytes, origOp+ohbytes);
4548 /* Short name if requested and needed */
4549 if (infoLevel == SMB_FIND_FILE_BOTH_DIRECTORY_INFO) {
4550 if (NeedShortName) {
4551 strcpy(op + 70, shortName);
4552 if (smb_StoreAnsiFilenames)
4553 CharToOem(op + 70, op + 70);
4554 *(op + 68) = (char)(shortNameEnd - shortName);
4558 /* NextEntryOffset and FileIndex */
4559 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO) {
4560 int entryOffset = orbytes + align;
4561 *((u_long *)op) = 0;
4562 *((u_long *)(op+4)) = 0;
4565 if (infoLevel != SMB_FIND_FILE_NAMES_INFO) {
4566 curPatchp = malloc(sizeof(*curPatchp));
4567 osi_QAdd((osi_queue_t **) &dirListPatchesp,
4569 curPatchp->dptr = op;
4570 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO)
4571 curPatchp->dptr += 8;
4573 if (smb_hideDotFiles && smb_IsDotFile(maskp)) {
4574 curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
4576 curPatchp->flags = 0;
4579 curPatchp->fid.cell = targetscp->fid.cell;
4580 curPatchp->fid.volume = targetscp->fid.volume;
4581 curPatchp->fid.vnode = targetscp->fid.vnode;
4582 curPatchp->fid.unique = targetscp->fid.unique;
4585 curPatchp->dep = NULL;
4588 if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS) {
4589 /* put out resume key */
4590 *((u_long *)origOp) = 0;
4593 /* Adjust byte ptr and count */
4594 origOp += orbytes; /* skip entire record */
4595 bytesInBuffer += orbytes;
4597 /* and pad the record out */
4598 while (--align >= 0) {
4603 /* apply the patches */
4604 code2 = smb_ApplyV3DirListPatches(scp, &dirListPatchesp, infoLevel, userp, &req);
4606 outp->parmsp[0] = 0;
4607 outp->parmsp[1] = 1; /* number of names returned */
4608 outp->parmsp[2] = 1; /* end of search */
4609 outp->parmsp[3] = 0; /* nothing wrong with EAS */
4610 outp->parmsp[4] = 0;
4612 outp->totalParms = 10; /* in bytes */
4614 outp->totalData = bytesInBuffer;
4616 osi_Log0(smb_logp, "T2SDSingle done.");
4618 if (code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
4620 smb_SendTran2Error(vcp, p, opx, code);
4622 smb_SendTran2Packet(vcp, outp, opx);
4627 smb_FreeTran2Packet(outp);
4628 cm_ReleaseSCache(scp);
4629 cm_ReleaseSCache(targetscp);
4630 cm_ReleaseUser(userp);
4636 long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
4641 long code = 0, code2 = 0;
4645 smb_dirListPatch_t *dirListPatchesp;
4646 smb_dirListPatch_t *curPatchp;
4649 long orbytes; /* # of bytes in this output record */
4650 long ohbytes; /* # of bytes, except file name */
4651 long onbytes; /* # of bytes in name, incl. term. null */
4652 osi_hyper_t dirLength;
4653 osi_hyper_t bufferOffset;
4654 osi_hyper_t curOffset;
4656 smb_dirSearch_t *dsp;
4660 cm_pageHeader_t *pageHeaderp;
4661 cm_user_t *userp = NULL;
4664 long nextEntryCookie;
4665 int numDirChunks; /* # of 32 byte dir chunks in this entry */
4666 char *op; /* output data ptr */
4667 char *origOp; /* original value of op */
4668 cm_space_t *spacep; /* for pathname buffer */
4669 long maxReturnData; /* max # of return data */
4670 long maxReturnParms; /* max # of return parms */
4671 long bytesInBuffer; /* # data bytes in the output buffer */
4673 char *maskp; /* mask part of path */
4677 smb_tran2Packet_t *outp; /* response packet */
4680 char shortName[13]; /* 8.3 name if needed */
4692 if (p->opcode == 1) {
4693 /* find first; obtain basic parameters from request */
4694 attribute = p->parmsp[0];
4695 maxCount = p->parmsp[1];
4696 infoLevel = p->parmsp[3];
4697 searchFlags = p->parmsp[2];
4698 pathp = ((char *) p->parmsp) + 12; /* points to path */
4699 if (smb_StoreAnsiFilenames)
4700 OemToChar(pathp,pathp);
4702 maskp = strrchr(pathp, '\\');
4706 maskp++; /* skip over backslash */
4708 /* track if this is likely to match a lot of entries */
4709 starPattern = smb_V3IsStarMask(maskp);
4711 #ifndef NOFINDFIRSTOPTIMIZE
4713 /* if this is for a single directory or file, we let the
4714 optimized routine handle it. The only error it
4715 returns is CM_ERROR_NOSUCHFILE. The */
4716 code = smb_T2SearchDirSingle(vcp, p, opx);
4718 /* we only failover if we see a CM_ERROR_NOSUCHFILE */
4719 if (code != CM_ERROR_NOSUCHFILE) {
4721 if (code == CM_ERROR_BPLUS_NOMATCH)
4722 code = CM_ERROR_NOSUCHFILE;
4730 dsp = smb_NewDirSearch(1);
4731 dsp->attribute = attribute;
4732 strcpy(dsp->mask, maskp); /* and save mask */
4735 osi_assert(p->opcode == 2);
4736 /* find next; obtain basic parameters from request or open dir file */
4737 dsp = smb_FindDirSearch(p->parmsp[0]);
4738 maxCount = p->parmsp[1];
4739 infoLevel = p->parmsp[2];
4740 nextCookie = p->parmsp[3] | (p->parmsp[4] << 16);
4741 searchFlags = p->parmsp[5];
4743 osi_Log2(smb_logp, "T2 search dir bad search ID: id %d nextCookie 0x%x",
4744 p->parmsp[0], nextCookie);
4745 return CM_ERROR_BADFD;
4747 attribute = dsp->attribute;
4750 starPattern = 1; /* assume, since required a Find Next */
4753 switch ( infoLevel ) {
4754 case SMB_INFO_STANDARD:
4757 case SMB_INFO_QUERY_EA_SIZE:
4758 s = "InfoQueryEaSize";
4760 case SMB_INFO_QUERY_EAS_FROM_LIST:
4761 s = "InfoQueryEasFromList";
4763 case SMB_FIND_FILE_DIRECTORY_INFO:
4764 s = "FindFileDirectoryInfo";
4766 case SMB_FIND_FILE_FULL_DIRECTORY_INFO:
4767 s = "FindFileFullDirectoryInfo";
4769 case SMB_FIND_FILE_NAMES_INFO:
4770 s = "FindFileNamesInfo";
4772 case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
4773 s = "FindFileBothDirectoryInfo";
4776 s = "unknownInfoLevel";
4779 osi_Log1(smb_logp, "T2 search dir info level: %s", s);
4782 "T2 search dir attr 0x%x, info level 0x%x, max count %d, flags 0x%x",
4783 attribute, infoLevel, maxCount, searchFlags);
4785 osi_Log3(smb_logp, "...T2 search op %d, id %d, nextCookie 0x%x",
4786 p->opcode, dsp->cookie, nextCookie);
4788 if (infoLevel > SMB_FIND_FILE_BOTH_DIRECTORY_INFO) {
4789 osi_Log1(smb_logp, "Unsupported InfoLevel 0x%x", infoLevel);
4790 smb_ReleaseDirSearch(dsp);
4791 return CM_ERROR_INVAL;
4794 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO)
4795 searchFlags &= ~TRAN2_FIND_FLAG_RETURN_RESUME_KEYS; /* no resume keys */
4797 dirListPatchesp = NULL;
4799 maxReturnData = p->maxReturnData;
4800 if (p->opcode == 1) /* find first */
4801 maxReturnParms = 10; /* bytes */
4803 maxReturnParms = 8; /* bytes */
4805 #ifndef CM_CONFIG_MULTITRAN2RESPONSES
4806 if (maxReturnData > 6000)
4807 maxReturnData = 6000;
4808 #endif /* CM_CONFIG_MULTITRAN2RESPONSES */
4810 outp = smb_GetTran2ResponsePacket(vcp, p, opx, maxReturnParms,
4813 osi_Log2(smb_logp, "T2 receive search dir count %d [%s]",
4814 maxCount, osi_LogSaveString(smb_logp, pathp));
4816 /* bail out if request looks bad */
4817 if (p->opcode == 1 && !pathp) {
4818 smb_ReleaseDirSearch(dsp);
4819 smb_FreeTran2Packet(outp);
4820 return CM_ERROR_BADSMB;
4823 osi_Log3(smb_logp, "T2 search dir id %d, nextCookie 0x%x, attr 0x%x",
4824 dsp->cookie, nextCookie, attribute);
4826 userp = smb_GetTran2User(vcp, p);
4828 osi_Log1(smb_logp, "T2 search dir unable to resolve user [%d]", p->uid);
4829 smb_ReleaseDirSearch(dsp);
4830 smb_FreeTran2Packet(outp);
4831 return CM_ERROR_BADSMB;
4834 /* try to get the vnode for the path name next */
4835 lock_ObtainMutex(&dsp->mx);
4838 osi_Log2(smb_logp,"smb_ReceiveTran2SearchDir dsp 0x%p scp 0x%p", dsp, scp);
4842 spacep = cm_GetSpace();
4843 smb_StripLastComponent(spacep->data, NULL, pathp);
4844 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
4846 cm_ReleaseUser(userp);
4847 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOFILES);
4848 smb_FreeTran2Packet(outp);
4849 lock_ReleaseMutex(&dsp->mx);
4850 smb_DeleteDirSearch(dsp);
4851 smb_ReleaseDirSearch(dsp);
4854 code = cm_NameI(cm_data.rootSCachep, spacep->data,
4855 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
4856 userp, tidPathp, &req, &scp);
4857 cm_FreeSpace(spacep);
4860 #ifdef DFS_SUPPORT_BUT_NOT_FIND_FIRST
4861 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
4862 cm_ReleaseSCache(scp);
4863 cm_ReleaseUser(userp);
4864 if ( WANTS_DFS_PATHNAMES(p) )
4865 code = CM_ERROR_PATH_NOT_COVERED;
4867 code = CM_ERROR_BADSHARENAME;
4868 smb_SendTran2Error(vcp, p, opx, code);
4869 smb_FreeTran2Packet(outp);
4870 lock_ReleaseMutex(&dsp->mx);
4871 smb_DeleteDirSearch(dsp);
4872 smb_ReleaseDirSearch(dsp);
4875 #endif /* DFS_SUPPORT */
4877 osi_Log2(smb_logp,"smb_ReceiveTran2SearchDir dsp 0x%p scp 0x%p", dsp, scp);
4878 /* we need one hold for the entry we just stored into,
4879 * and one for our own processing. When we're done
4880 * with this function, we'll drop the one for our own
4881 * processing. We held it once from the namei call,
4882 * and so we do another hold now.
4885 lock_ObtainMutex(&scp->mx);
4886 if ((scp->flags & CM_SCACHEFLAG_BULKSTATTING) == 0 &&
4887 LargeIntegerGreaterOrEqualToZero(scp->bulkStatProgress)) {
4888 scp->flags |= CM_SCACHEFLAG_BULKSTATTING;
4889 dsp->flags |= SMB_DIRSEARCH_BULKST;
4891 lock_ReleaseMutex(&scp->mx);
4894 lock_ReleaseMutex(&dsp->mx);
4896 cm_ReleaseUser(userp);
4897 smb_FreeTran2Packet(outp);
4898 smb_DeleteDirSearch(dsp);
4899 smb_ReleaseDirSearch(dsp);
4903 /* get the directory size */
4904 lock_ObtainMutex(&scp->mx);
4905 code = cm_SyncOp(scp, NULL, userp, &req, 0,
4906 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4908 lock_ReleaseMutex(&scp->mx);
4909 cm_ReleaseSCache(scp);
4910 cm_ReleaseUser(userp);
4911 smb_FreeTran2Packet(outp);
4912 smb_DeleteDirSearch(dsp);
4913 smb_ReleaseDirSearch(dsp);
4917 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4920 dirLength = scp->length;
4922 bufferOffset.LowPart = bufferOffset.HighPart = 0;
4923 curOffset.HighPart = 0;
4924 curOffset.LowPart = nextCookie;
4925 origOp = outp->datap;
4933 if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS)
4934 /* skip over resume key */
4937 /* make sure that curOffset.LowPart doesn't point to the first
4938 * 32 bytes in the 2nd through last dir page, and that it doesn't
4939 * point at the first 13 32-byte chunks in the first dir page,
4940 * since those are dir and page headers, and don't contain useful
4943 temp = curOffset.LowPart & (2048-1);
4944 if (curOffset.HighPart == 0 && curOffset.LowPart < 2048) {
4945 /* we're in the first page */
4946 if (temp < 13*32) temp = 13*32;
4949 /* we're in a later dir page */
4950 if (temp < 32) temp = 32;
4953 /* make sure the low order 5 bits are zero */
4956 /* now put temp bits back ito curOffset.LowPart */
4957 curOffset.LowPart &= ~(2048-1);
4958 curOffset.LowPart |= temp;
4960 /* check if we've passed the dir's EOF */
4961 if (LargeIntegerGreaterThanOrEqualTo(curOffset, dirLength)) {
4962 osi_Log0(smb_logp, "T2 search dir passed eof");
4967 /* check if we've returned all the names that will fit in the
4968 * response packet; we check return count as well as the number
4969 * of bytes requested. We check the # of bytes after we find
4970 * the dir entry, since we'll need to check its size.
4972 if (returnedNames >= maxCount) {
4973 osi_Log2(smb_logp, "T2 search dir returnedNames %d >= maxCount %d",
4974 returnedNames, maxCount);
4978 /* see if we can use the bufferp we have now; compute in which
4979 * page the current offset would be, and check whether that's
4980 * the offset of the buffer we have. If not, get the buffer.
4982 thyper.HighPart = curOffset.HighPart;
4983 thyper.LowPart = curOffset.LowPart & ~(cm_data.buf_blockSize-1);
4984 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
4987 buf_Release(bufferp);
4990 lock_ReleaseMutex(&scp->mx);
4991 lock_ObtainRead(&scp->bufCreateLock);
4992 code = buf_Get(scp, &thyper, &bufferp);
4993 lock_ReleaseRead(&scp->bufCreateLock);
4994 lock_ObtainMutex(&dsp->mx);
4996 /* now, if we're doing a star match, do bulk fetching
4997 * of all of the status info for files in the dir.
5000 smb_ApplyV3DirListPatches(scp, &dirListPatchesp,
5003 lock_ObtainMutex(&scp->mx);
5004 if ((dsp->flags & SMB_DIRSEARCH_BULKST) &&
5005 LargeIntegerGreaterThanOrEqualTo(thyper, scp->bulkStatProgress)) {
5006 /* Don't bulk stat if risking timeout */
5007 DWORD now = GetTickCount();
5008 if (now - req.startTime > RDRtimeout * 1000) {
5009 scp->bulkStatProgress = thyper;
5010 scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
5011 dsp->flags &= ~SMB_DIRSEARCH_BULKST;
5013 code = cm_TryBulkStat(scp, &thyper, userp, &req);
5016 lock_ObtainMutex(&scp->mx);
5018 lock_ReleaseMutex(&dsp->mx);
5020 osi_Log2(smb_logp, "T2 search dir buf_Get scp %x failed %d", scp, code);
5024 bufferOffset = thyper;
5026 /* now get the data in the cache */
5028 code = cm_SyncOp(scp, bufferp, userp, &req,
5030 CM_SCACHESYNC_NEEDCALLBACK
5031 | CM_SCACHESYNC_READ);
5033 osi_Log2(smb_logp, "T2 search dir cm_SyncOp scp %x failed %d", scp, code);
5037 cm_SyncOpDone(scp, bufferp, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ);
5039 if (cm_HaveBuffer(scp, bufferp, 0)) {
5040 osi_Log2(smb_logp, "T2 search dir !HaveBuffer scp %x bufferp %x", scp, bufferp);
5044 /* otherwise, load the buffer and try again */
5045 code = cm_GetBuffer(scp, bufferp, NULL, userp,
5048 osi_Log3(smb_logp, "T2 search dir cm_GetBuffer failed scp %x bufferp %x code %d",
5049 scp, bufferp, code);
5054 buf_Release(bufferp);
5058 } /* if (wrong buffer) ... */
5060 /* now we have the buffer containing the entry we're interested
5061 * in; copy it out if it represents a non-deleted entry.
5063 entryInDir = curOffset.LowPart & (2048-1);
5064 entryInBuffer = curOffset.LowPart & (cm_data.buf_blockSize - 1);
5066 /* page header will help tell us which entries are free. Page
5067 * header can change more often than once per buffer, since
5068 * AFS 3 dir page size may be less than (but not more than)
5069 * a buffer package buffer.
5071 /* only look intra-buffer */
5072 temp = curOffset.LowPart & (cm_data.buf_blockSize - 1);
5073 temp &= ~(2048 - 1); /* turn off intra-page bits */
5074 pageHeaderp = (cm_pageHeader_t *) (bufferp->datap + temp);
5076 /* now determine which entry we're looking at in the page.
5077 * If it is free (there's a free bitmap at the start of the
5078 * dir), we should skip these 32 bytes.
5080 slotInPage = (entryInDir & 0x7e0) >> 5;
5081 if (!(pageHeaderp->freeBitmap[slotInPage>>3] &
5082 (1 << (slotInPage & 0x7)))) {
5083 /* this entry is free */
5084 numDirChunks = 1; /* only skip this guy */
5088 tp = bufferp->datap + entryInBuffer;
5089 dep = (cm_dirEntry_t *) tp; /* now points to AFS3 dir entry */
5091 /* while we're here, compute the next entry's location, too,
5092 * since we'll need it when writing out the cookie into the dir
5095 * XXXX Probably should do more sanity checking.
5097 numDirChunks = cm_NameEntries(dep->name, &onbytes);
5099 /* compute offset of cookie representing next entry */
5100 nextEntryCookie = curOffset.LowPart + (CM_DIR_CHUNKSIZE * numDirChunks);
5102 /* Need 8.3 name? */
5104 if (infoLevel == SMB_FIND_FILE_BOTH_DIRECTORY_INFO
5105 && dep->fid.vnode != 0
5106 && !cm_Is8Dot3(dep->name)) {
5107 cm_Gen8Dot3Name(dep, shortName, &shortNameEnd);
5111 osi_Log4(smb_logp, "T2 search dir vn %u uniq %u name %s (%s)",
5112 dep->fid.vnode, dep->fid.unique,
5113 osi_LogSaveString(smb_logp, dep->name),
5114 NeedShortName ? osi_LogSaveString(smb_logp, shortName) : "");
5116 /* When matching, we are using doing a case fold if we have a wildcard mask.
5117 * If we get a non-wildcard match, it's a lookup for a specific file.
5119 if (dep->fid.vnode != 0 &&
5120 (smb_V3MatchMask(dep->name, maskp, (starPattern? CM_FLAG_CASEFOLD : 0)) ||
5122 smb_V3MatchMask(shortName, maskp, CM_FLAG_CASEFOLD)))) {
5124 /* Eliminate entries that don't match requested attributes */
5125 if (smb_hideDotFiles && !(dsp->attribute & SMB_ATTR_HIDDEN) &&
5126 smb_IsDotFile(dep->name)) {
5127 osi_Log0(smb_logp, "T2 search dir skipping hidden");
5128 goto nextEntry; /* no hidden files */
5130 if (!(dsp->attribute & SMB_ATTR_DIRECTORY)) /* no directories */
5132 /* We have already done the cm_TryBulkStat above */
5133 fid.cell = scp->fid.cell;
5134 fid.volume = scp->fid.volume;
5135 fid.vnode = ntohl(dep->fid.vnode);
5136 fid.unique = ntohl(dep->fid.unique);
5137 fileType = cm_FindFileType(&fid);
5138 /*osi_Log2(smb_logp, "smb_ReceiveTran2SearchDir: file %s "
5139 "has filetype %d", dep->name,
5141 if (fileType == CM_SCACHETYPE_DIRECTORY ||
5142 fileType == CM_SCACHETYPE_MOUNTPOINT ||
5143 fileType == CM_SCACHETYPE_DFSLINK ||
5144 fileType == CM_SCACHETYPE_INVALID)
5145 osi_Log0(smb_logp, "T2 search dir skipping directory or bad link");
5149 /* finally check if this name will fit */
5151 /* standard dir entry stuff */
5152 if (infoLevel < 0x101)
5153 ohbytes = 23; /* pre-NT */
5154 else if (infoLevel == SMB_FIND_FILE_NAMES_INFO)
5155 ohbytes = 12; /* NT names only */
5157 ohbytes = 64; /* NT */
5159 if (infoLevel == SMB_FIND_FILE_BOTH_DIRECTORY_INFO)
5160 ohbytes += 26; /* Short name & length */
5162 if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS) {
5163 ohbytes += 4; /* if resume key required */
5166 if (infoLevel != SMB_INFO_STANDARD
5167 && infoLevel != SMB_FIND_FILE_DIRECTORY_INFO
5168 && infoLevel != SMB_FIND_FILE_NAMES_INFO)
5169 ohbytes += 4; /* EASIZE */
5171 /* add header to name & term. null */
5172 orbytes = onbytes + ohbytes + 1;
5174 /* now, we round up the record to a 4 byte alignment,
5175 * and we make sure that we have enough room here for
5176 * even the aligned version (so we don't have to worry
5177 * about an * overflow when we pad things out below).
5178 * That's the reason for the alignment arithmetic below.
5180 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO)
5181 align = (4 - (orbytes & 3)) & 3;
5184 if (orbytes + bytesInBuffer + align > maxReturnData) {
5185 osi_Log1(smb_logp, "T2 dir search exceed max return data %d",
5190 /* this is one of the entries to use: it is not deleted
5191 * and it matches the star pattern we're looking for.
5192 * Put out the name, preceded by its length.
5194 /* First zero everything else */
5195 memset(origOp, 0, ohbytes);
5197 if (infoLevel <= SMB_FIND_FILE_DIRECTORY_INFO)
5198 *(origOp + ohbytes - 1) = (unsigned char) onbytes;
5199 else if (infoLevel == SMB_FIND_FILE_NAMES_INFO)
5200 *((u_long *)(op + 8)) = onbytes;
5202 *((u_long *)(op + 60)) = onbytes;
5203 strcpy(origOp+ohbytes, dep->name);
5204 if (smb_StoreAnsiFilenames)
5205 CharToOem(origOp+ohbytes, origOp+ohbytes);
5207 /* Short name if requested and needed */
5208 if (infoLevel == SMB_FIND_FILE_BOTH_DIRECTORY_INFO) {
5209 if (NeedShortName) {
5210 strcpy(op + 70, shortName);
5211 if (smb_StoreAnsiFilenames)
5212 CharToOem(op + 70, op + 70);
5213 *(op + 68) = (char)(shortNameEnd - shortName);
5217 /* now, adjust the # of entries copied */
5220 /* NextEntryOffset and FileIndex */
5221 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO) {
5222 int entryOffset = orbytes + align;
5223 *((u_long *)op) = entryOffset;
5224 *((u_long *)(op+4)) = nextEntryCookie;
5227 /* now we emit the attribute. This is tricky, since
5228 * we need to really stat the file to find out what
5229 * type of entry we've got. Right now, we're copying
5230 * out data from a buffer, while holding the scp
5231 * locked, so it isn't really convenient to stat
5232 * something now. We'll put in a place holder
5233 * now, and make a second pass before returning this
5234 * to get the real attributes. So, we just skip the
5235 * data for now, and adjust it later. We allocate a
5236 * patch record to make it easy to find this point
5237 * later. The replay will happen at a time when it is
5238 * safe to unlock the directory.
5240 if (infoLevel != SMB_FIND_FILE_NAMES_INFO) {
5241 curPatchp = malloc(sizeof(*curPatchp));
5242 osi_QAdd((osi_queue_t **) &dirListPatchesp,
5244 curPatchp->dptr = op;
5245 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO)
5246 curPatchp->dptr += 8;
5248 if (smb_hideDotFiles && smb_IsDotFile(dep->name)) {
5249 curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
5252 curPatchp->flags = 0;
5254 curPatchp->fid.cell = scp->fid.cell;
5255 curPatchp->fid.volume = scp->fid.volume;
5256 curPatchp->fid.vnode = ntohl(dep->fid.vnode);
5257 curPatchp->fid.unique = ntohl(dep->fid.unique);
5260 curPatchp->dep = dep;
5263 if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS)
5264 /* put out resume key */
5265 *((u_long *)origOp) = nextEntryCookie;
5267 /* Adjust byte ptr and count */
5268 origOp += orbytes; /* skip entire record */
5269 bytesInBuffer += orbytes;
5271 /* and pad the record out */
5272 while (--align >= 0) {
5276 } /* if we're including this name */
5277 else if (!starPattern &&
5279 dep->fid.vnode != 0 &&
5280 smb_V3MatchMask(dep->name, maskp, CM_FLAG_CASEFOLD)) {
5281 /* We were looking for exact matches, but here's an inexact one*/
5286 /* and adjust curOffset to be where the new cookie is */
5287 thyper.HighPart = 0;
5288 thyper.LowPart = CM_DIR_CHUNKSIZE * numDirChunks;
5289 curOffset = LargeIntegerAdd(thyper, curOffset);
5290 } /* while copying data for dir listing */
5292 /* If we didn't get a star pattern, we did an exact match during the first pass.
5293 * If there were no exact matches found, we fail over to inexact matches by
5294 * marking the query as a star pattern (matches all case permutations), and
5295 * re-running the query.
5297 if (returnedNames == 0 && !starPattern && foundInexact) {
5298 osi_Log0(smb_logp,"T2 Search: No exact matches. Re-running for inexact matches");
5303 /* release the mutex */
5304 lock_ReleaseMutex(&scp->mx);
5306 buf_Release(bufferp);
5310 /* apply and free last set of patches; if not doing a star match, this
5311 * will be empty, but better safe (and freeing everything) than sorry.
5313 code2 = smb_ApplyV3DirListPatches(scp, &dirListPatchesp, infoLevel, userp,
5316 /* now put out the final parameters */
5317 if (returnedNames == 0)
5319 if (p->opcode == 1) {
5321 outp->parmsp[0] = (unsigned short) dsp->cookie;
5322 outp->parmsp[1] = returnedNames;
5323 outp->parmsp[2] = eos;
5324 outp->parmsp[3] = 0; /* nothing wrong with EAS */
5325 outp->parmsp[4] = 0;
5326 /* don't need last name to continue
5327 * search, cookie is enough. Normally,
5328 * this is the offset of the file name
5329 * of the last entry returned.
5331 outp->totalParms = 10; /* in bytes */
5335 outp->parmsp[0] = returnedNames;
5336 outp->parmsp[1] = eos;
5337 outp->parmsp[2] = 0; /* EAS error */
5338 outp->parmsp[3] = 0; /* last name, as above */
5339 outp->totalParms = 8; /* in bytes */
5342 /* return # of bytes in the buffer */
5343 outp->totalData = bytesInBuffer;
5345 /* Return error code if unsuccessful on first request */
5346 if (code == 0 && p->opcode == 1 && returnedNames == 0)
5347 code = CM_ERROR_NOSUCHFILE;
5349 osi_Log4(smb_logp, "T2 search dir done, opcode %d, id %d, %d names, code %d",
5350 p->opcode, dsp->cookie, returnedNames, code);
5352 /* if we're supposed to close the search after this request, or if
5353 * we're supposed to close the search if we're done, and we're done,
5354 * or if something went wrong, close the search.
5356 if ((searchFlags & TRAN2_FIND_FLAG_CLOSE_SEARCH) ||
5357 (returnedNames == 0) ||
5358 ((searchFlags & TRAN2_FIND_FLAG_CLOSE_SEARCH_IF_END) && eos) ||
5360 smb_DeleteDirSearch(dsp);
5363 smb_SendTran2Error(vcp, p, opx, code);
5365 smb_SendTran2Packet(vcp, outp, opx);
5367 smb_FreeTran2Packet(outp);
5368 smb_ReleaseDirSearch(dsp);
5369 cm_ReleaseSCache(scp);
5370 cm_ReleaseUser(userp);
5374 long smb_ReceiveV3FindClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5377 smb_dirSearch_t *dsp;
5379 dirHandle = smb_GetSMBParm(inp, 0);
5381 osi_Log1(smb_logp, "SMB3 find close handle %d", dirHandle);
5383 dsp = smb_FindDirSearch(dirHandle);
5386 return CM_ERROR_BADFD;
5388 /* otherwise, we have an FD to destroy */
5389 smb_DeleteDirSearch(dsp);
5390 smb_ReleaseDirSearch(dsp);
5392 /* and return results */
5393 smb_SetSMBDataLength(outp, 0);
5398 long smb_ReceiveV3FindNotifyClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5400 smb_SetSMBDataLength(outp, 0);
5404 long smb_ReceiveV3OpenX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5411 cm_scache_t *dscp; /* dir we're dealing with */
5412 cm_scache_t *scp; /* file we're creating */
5414 int initialModeBits;
5424 int parmSlot; /* which parm we're dealing with */
5433 extraInfo = (smb_GetSMBParm(inp, 2) & 1); /* return extra info */
5434 openFun = smb_GetSMBParm(inp, 8); /* open function */
5435 excl = ((openFun & 3) == 0);
5436 trunc = ((openFun & 3) == 2); /* truncate it */
5437 openMode = (smb_GetSMBParm(inp, 3) & 0x7);
5438 openAction = 0; /* tracks what we did */
5440 attributes = smb_GetSMBParm(inp, 5);
5441 dosTime = smb_GetSMBParm(inp, 6) | (smb_GetSMBParm(inp, 7) << 16);
5443 /* compute initial mode bits based on read-only flag in attributes */
5444 initialModeBits = 0666;
5445 if (attributes & SMB_ATTR_READONLY)
5446 initialModeBits &= ~0222;
5448 pathp = smb_GetSMBData(inp, NULL);
5449 if (smb_StoreAnsiFilenames)
5450 OemToChar(pathp,pathp);
5452 spacep = inp->spacep;
5453 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
5455 if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
5456 /* special case magic file name for receiving IOCTL requests
5457 * (since IOCTL calls themselves aren't getting through).
5460 osi_Log0(smb_logp, "IOCTL Open");
5463 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
5464 smb_SetupIoctlFid(fidp, spacep);
5466 /* set inp->fid so that later read calls in same msg can find fid */
5467 inp->fid = fidp->fid;
5469 /* copy out remainder of the parms */
5471 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
5473 smb_SetSMBParm(outp, parmSlot, /* attrs */ 0); parmSlot++;
5474 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* mod time */
5475 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
5476 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* len */
5477 smb_SetSMBParm(outp, parmSlot, 0x7fff); parmSlot++;
5478 smb_SetSMBParm(outp, parmSlot, openMode); parmSlot++;
5479 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* file type 0 ==> normal file or dir */
5480 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* IPC junk */
5482 /* and the final "always present" stuff */
5483 smb_SetSMBParm(outp, parmSlot, /* openAction found existing file */ 1); parmSlot++;
5484 /* next write out the "unique" ID */
5485 smb_SetSMBParm(outp, parmSlot, 0x1234); parmSlot++;
5486 smb_SetSMBParm(outp, parmSlot, 0x5678); parmSlot++;
5487 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
5488 smb_SetSMBDataLength(outp, 0);
5490 /* and clean up fid reference */
5491 smb_ReleaseFID(fidp);
5495 #ifdef DEBUG_VERBOSE
5497 char *hexp, *asciip;
5498 asciip = (lastNamep ? lastNamep : pathp );
5499 hexp = osi_HexifyString(asciip);
5500 DEBUG_EVENT2("AFS", "V3Open H[%s] A[%s]", hexp, asciip );
5504 userp = smb_GetUserFromVCP(vcp, inp);
5507 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5509 cm_ReleaseUser(userp);
5510 return CM_ERROR_NOSUCHPATH;
5512 code = cm_NameI(cm_data.rootSCachep, pathp,
5513 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
5514 userp, tidPathp, &req, &scp);
5517 if (code == 0 && scp->fileType == CM_SCACHETYPE_DFSLINK) {
5518 cm_ReleaseSCache(scp);
5519 cm_ReleaseUser(userp);
5520 if ( WANTS_DFS_PATHNAMES(inp) )
5521 return CM_ERROR_PATH_NOT_COVERED;
5523 return CM_ERROR_BADSHARENAME;
5525 #endif /* DFS_SUPPORT */
5528 code = cm_NameI(cm_data.rootSCachep, spacep->data,
5529 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
5530 userp, tidPathp, &req, &dscp);
5532 cm_ReleaseUser(userp);
5537 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
5538 cm_ReleaseSCache(dscp);
5539 cm_ReleaseUser(userp);
5540 if ( WANTS_DFS_PATHNAMES(inp) )
5541 return CM_ERROR_PATH_NOT_COVERED;
5543 return CM_ERROR_BADSHARENAME;
5545 #endif /* DFS_SUPPORT */
5546 /* otherwise, scp points to the parent directory. Do a lookup,
5547 * and truncate the file if we find it, otherwise we create the
5554 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD, userp,
5556 if (code && code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
5557 cm_ReleaseSCache(dscp);
5558 cm_ReleaseUser(userp);
5563 /* if we get here, if code is 0, the file exists and is represented by
5564 * scp. Otherwise, we have to create it. The dir may be represented
5565 * by dscp, or we may have found the file directly. If code is non-zero,
5569 code = cm_CheckOpen(scp, openMode, trunc, userp, &req);
5571 if (dscp) cm_ReleaseSCache(dscp);
5572 cm_ReleaseSCache(scp);
5573 cm_ReleaseUser(userp);
5578 /* oops, file shouldn't be there */
5580 cm_ReleaseSCache(dscp);
5581 cm_ReleaseSCache(scp);
5582 cm_ReleaseUser(userp);
5583 return CM_ERROR_EXISTS;
5587 setAttr.mask = CM_ATTRMASK_LENGTH;
5588 setAttr.length.LowPart = 0;
5589 setAttr.length.HighPart = 0;
5590 code = cm_SetAttr(scp, &setAttr, userp, &req);
5591 openAction = 3; /* truncated existing file */
5593 else openAction = 1; /* found existing file */
5595 else if (!(openFun & SMB_ATTR_DIRECTORY)) {
5596 /* don't create if not found */
5597 if (dscp) cm_ReleaseSCache(dscp);
5598 cm_ReleaseUser(userp);
5599 return CM_ERROR_NOSUCHFILE;
5602 osi_assert(dscp != NULL);
5603 osi_Log1(smb_logp, "smb_ReceiveV3OpenX creating file %s",
5604 osi_LogSaveString(smb_logp, lastNamep));
5605 openAction = 2; /* created file */
5606 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
5607 smb_UnixTimeFromDosUTime(&setAttr.clientModTime, dosTime);
5608 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
5612 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
5613 smb_NotifyChange(FILE_ACTION_ADDED,
5614 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
5615 dscp, lastNamep, NULL, TRUE);
5616 } else if (!excl && code == CM_ERROR_EXISTS) {
5617 /* not an exclusive create, and someone else tried
5618 * creating it already, then we open it anyway. We
5619 * don't bother retrying after this, since if this next
5620 * fails, that means that the file was deleted after we
5621 * started this call.
5623 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
5627 setAttr.mask = CM_ATTRMASK_LENGTH;
5628 setAttr.length.LowPart = 0;
5629 setAttr.length.HighPart = 0;
5630 code = cm_SetAttr(scp, &setAttr, userp, &req);
5632 } /* lookup succeeded */
5636 /* we don't need this any longer */
5638 cm_ReleaseSCache(dscp);
5641 /* something went wrong creating or truncating the file */
5643 cm_ReleaseSCache(scp);
5644 cm_ReleaseUser(userp);
5648 /* make sure we're about to open a file */
5649 if (scp->fileType != CM_SCACHETYPE_FILE) {
5650 cm_ReleaseSCache(scp);
5651 cm_ReleaseUser(userp);
5652 return CM_ERROR_ISDIR;
5655 /* now all we have to do is open the file itself */
5656 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
5660 lock_ObtainMutex(&fidp->mx);
5661 /* save a pointer to the vnode */
5663 lock_ObtainMutex(&scp->mx);
5664 scp->flags |= CM_SCACHEFLAG_SMB_FID;
5665 lock_ReleaseMutex(&scp->mx);
5666 osi_Log2(smb_logp,"smb_ReceiveV3OpenX fidp 0x%p scp 0x%p", fidp, scp);
5668 fidp->userp = userp;
5670 /* compute open mode */
5672 fidp->flags |= SMB_FID_OPENREAD_LISTDIR;
5673 if (openMode == 1 || openMode == 2)
5674 fidp->flags |= SMB_FID_OPENWRITE;
5676 /* remember if the file was newly created */
5678 fidp->flags |= SMB_FID_CREATED;
5680 lock_ReleaseMutex(&fidp->mx);
5681 smb_ReleaseFID(fidp);
5683 cm_Open(scp, 0, userp);
5685 /* set inp->fid so that later read calls in same msg can find fid */
5686 inp->fid = fidp->fid;
5688 /* copy out remainder of the parms */
5690 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
5691 lock_ObtainMutex(&scp->mx);
5693 smb_SetSMBParm(outp, parmSlot, smb_Attributes(scp)); parmSlot++;
5694 smb_DosUTimeFromUnixTime(&dosTime, scp->clientModTime);
5695 smb_SetSMBParm(outp, parmSlot, dosTime & 0xffff); parmSlot++;
5696 smb_SetSMBParm(outp, parmSlot, (dosTime>>16) & 0xffff); parmSlot++;
5697 smb_SetSMBParm(outp, parmSlot, scp->length.LowPart & 0xffff); parmSlot++;
5698 smb_SetSMBParm(outp, parmSlot, (scp->length.LowPart >> 16) & 0xffff); parmSlot++;
5699 smb_SetSMBParm(outp, parmSlot, openMode); parmSlot++;
5700 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* file type 0 ==> normal file or dir */
5701 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* IPC junk */
5703 /* and the final "always present" stuff */
5704 smb_SetSMBParm(outp, parmSlot, openAction); parmSlot++;
5705 /* next write out the "unique" ID */
5706 smb_SetSMBParm(outp, parmSlot, scp->fid.vnode & 0xffff); parmSlot++;
5707 smb_SetSMBParm(outp, parmSlot, scp->fid.volume & 0xffff); parmSlot++;
5708 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
5709 lock_ReleaseMutex(&scp->mx);
5710 smb_SetSMBDataLength(outp, 0);
5712 osi_Log1(smb_logp, "SMB OpenX opening fid %d", fidp->fid);
5714 cm_ReleaseUser(userp);
5715 /* leave scp held since we put it in fidp->scp */
5719 static void smb_GetLockParams(unsigned char LockType,
5721 unsigned int * ppid,
5722 LARGE_INTEGER * pOffset,
5723 LARGE_INTEGER * pLength)
5725 if (LockType & LOCKING_ANDX_LARGE_FILES) {
5727 *ppid = *((USHORT *) *buf);
5728 pOffset->HighPart = *((LONG *)(*buf + 4));
5729 pOffset->LowPart = *((DWORD *)(*buf + 8));
5730 pLength->HighPart = *((LONG *)(*buf + 12));
5731 pLength->LowPart = *((DWORD *)(*buf + 16));
5735 /* Not Large Files */
5736 *ppid = *((USHORT *) *buf);
5737 pOffset->HighPart = 0;
5738 pOffset->LowPart = *((DWORD *)(*buf + 2));
5739 pLength->HighPart = 0;
5740 pLength->LowPart = *((DWORD *)(*buf + 6));
5745 long smb_ReceiveV3LockingX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5752 unsigned char LockType;
5753 unsigned short NumberOfUnlocks, NumberOfLocks;
5757 LARGE_INTEGER LOffset, LLength;
5758 smb_waitingLockRequest_t *wlRequest = NULL;
5759 cm_file_lock_t *lockp;
5767 fid = smb_GetSMBParm(inp, 2);
5768 fid = smb_ChainFID(fid, inp);
5770 fidp = smb_FindFID(vcp, fid, 0);
5772 return CM_ERROR_BADFD;
5774 lock_ObtainMutex(&fidp->mx);
5775 if (fidp->flags & SMB_FID_IOCTL) {
5776 osi_Log0(smb_logp, "smb_ReceiveV3Locking BadFD");
5777 lock_ReleaseMutex(&fidp->mx);
5778 smb_ReleaseFID(fidp);
5779 return CM_ERROR_BADFD;
5782 osi_Log2(smb_logp,"smb_ReceiveV3LockingX fidp 0x%p scp 0x%p", fidp, scp);
5784 lock_ReleaseMutex(&fidp->mx);
5786 /* set inp->fid so that later read calls in same msg can find fid */
5789 userp = smb_GetUserFromVCP(vcp, inp);
5792 lock_ObtainMutex(&scp->mx);
5793 code = cm_SyncOp(scp, NULL, userp, &req, 0,
5794 CM_SCACHESYNC_NEEDCALLBACK
5795 | CM_SCACHESYNC_GETSTATUS
5796 | CM_SCACHESYNC_LOCK);
5798 osi_Log1(smb_logp, "smb_ReceiveV3Locking SyncOp failure code 0x%x", code);
5802 LockType = smb_GetSMBParm(inp, 3) & 0xff;
5803 Timeout = (smb_GetSMBParm(inp, 5) << 16) + smb_GetSMBParm(inp, 4);
5804 NumberOfUnlocks = smb_GetSMBParm(inp, 6);
5805 NumberOfLocks = smb_GetSMBParm(inp, 7);
5807 if (!(fidp->flags & SMB_FID_OPENWRITE) &&
5808 !(LockType & LOCKING_ANDX_SHARED_LOCK)) {
5809 /* somebody wants exclusive locks on a file that they only
5810 opened for reading. We downgrade this to a shared lock. */
5811 osi_Log0(smb_logp, "smb_ReceiveV3Locking reinterpreting exclusive lock as shared for read-only fid");
5812 LockType |= LOCKING_ANDX_SHARED_LOCK;
5815 if ((LockType & LOCKING_ANDX_CANCEL_LOCK) ||
5816 (LockType & LOCKING_ANDX_CHANGE_LOCKTYPE)) {
5818 /* We don't support these requests. Apparently, we can safely
5819 not deal with them too. */
5820 osi_Log1(smb_logp, "smb_ReceiveV3Locking received unsupported request [%s]",
5821 ((LockType & LOCKING_ANDX_CANCEL_LOCK)?
5822 "LOCKING_ANDX_CANCEL_LOCK":
5823 "LOCKING_ANDX_CHANGE_LOCKTYPE"));
5824 /* No need to call osi_LogSaveString since these are string
5827 code = CM_ERROR_BADOP;
5832 op = smb_GetSMBData(inp, NULL);
5834 for (i=0; i<NumberOfUnlocks; i++) {
5835 smb_GetLockParams(LockType, &op, &pid, &LOffset, &LLength);
5837 key = cm_GenerateKey(vcp->vcID, pid, fidp->fid);
5839 code = cm_Unlock(scp, LockType, LOffset, LLength, key, userp, &req);
5847 for (i=0; i<NumberOfLocks; i++) {
5848 smb_GetLockParams(LockType, &op, &pid, &LOffset, &LLength);
5850 key = cm_GenerateKey(vcp->vcID, pid, fidp->fid);
5852 code = cm_Lock(scp, LockType, LOffset, LLength, key, (Timeout != 0),
5853 userp, &req, &lockp);
5855 if (code == CM_ERROR_NOACCESS && LockType == LockWrite &&
5856 (fidp->flags & (SMB_FID_OPENREAD_LISTDIR | SMB_FID_OPENWRITE)) == SMB_FID_OPENREAD_LISTDIR)
5858 code = cm_Lock(scp, LockRead, LOffset, LLength, key, (Timeout != 0),
5859 userp, &req, &lockp);
5862 if (code == CM_ERROR_WOULDBLOCK && Timeout != 0) {
5863 smb_waitingLock_t * wLock;
5865 /* Put on waiting list */
5866 if(wlRequest == NULL) {
5870 LARGE_INTEGER tOffset, tLength;
5872 wlRequest = malloc(sizeof(smb_waitingLockRequest_t));
5874 osi_assert(wlRequest != NULL);
5876 wlRequest->vcp = vcp;
5878 wlRequest->scp = scp;
5879 osi_Log2(smb_logp,"smb_ReceiveV3LockingX wlRequest 0x%p scp 0x%p", wlRequest, scp);
5881 wlRequest->inp = smb_CopyPacket(inp);
5882 wlRequest->outp = smb_CopyPacket(outp);
5883 wlRequest->lockType = LockType;
5884 wlRequest->timeRemaining = Timeout;
5885 wlRequest->locks = NULL;
5887 /* The waiting lock request needs to have enough
5888 information to undo all the locks in the request.
5889 We do the following to store info about locks that
5890 have already been granted. Sure, we can get most
5891 of the info from the packet, but the packet doesn't
5892 hold the result of cm_Lock call. In practice we
5893 only receive packets with one or two locks, so we
5894 are only wasting a few bytes here and there and
5895 only for a limited period of time until the waiting
5896 lock times out or is freed. */
5898 for(opt = op_locks, j=i; j > 0; j--) {
5899 smb_GetLockParams(LockType, &opt, &pid, &tOffset, &tLength);
5901 tkey = cm_GenerateKey(vcp->vcID, pid, fidp->fid);
5903 wLock = malloc(sizeof(smb_waitingLock_t));
5905 osi_assert(wLock != NULL);
5908 wLock->LOffset = tOffset;
5909 wLock->LLength = tLength;
5910 wLock->lockp = NULL;
5911 wLock->state = SMB_WAITINGLOCKSTATE_DONE;
5912 osi_QAdd((osi_queue_t **) &wlRequest->locks,
5917 wLock = malloc(sizeof(smb_waitingLock_t));
5919 osi_assert(wLock != NULL);
5922 wLock->LOffset = LOffset;
5923 wLock->LLength = LLength;
5924 wLock->lockp = lockp;
5925 wLock->state = SMB_WAITINGLOCKSTATE_WAITING;
5926 osi_QAdd((osi_queue_t **) &wlRequest->locks,
5929 osi_Log1(smb_logp, "smb_ReceiveV3Locking WaitingLock created 0x%p",
5937 osi_Log1(smb_logp, "smb_ReceiveV3Locking cm_Lock failure code 0x%x", code);
5944 /* Since something went wrong with the lock number i, we now
5945 have to go ahead and release any locks acquired before the
5946 failure. All locks before lock number i (of which there
5947 are i of them) have either been successful or are waiting.
5948 Either case requires calling cm_Unlock(). */
5950 /* And purge the waiting lock */
5951 if(wlRequest != NULL) {
5952 smb_waitingLock_t * wl;
5953 smb_waitingLock_t * wlNext;
5956 for(wl = wlRequest->locks; wl; wl = wlNext) {
5958 wlNext = (smb_waitingLock_t *) osi_QNext(&wl->q);
5960 ul_code = cm_Unlock(scp, LockType, wl->LOffset, wl->LLength, wl->key, userp, &req);
5963 osi_Log1(smb_logp, "smb_ReceiveV3Locking cm_Unlock returns code %d", ul_code);
5965 osi_Log0(smb_logp, "smb_ReceiveV3Locking cm_Unlock successful");
5968 osi_QRemove((osi_queue_t **) &wlRequest->locks, &wl->q);
5973 smb_ReleaseVC(wlRequest->vcp);
5974 cm_ReleaseSCache(wlRequest->scp);
5975 smb_FreePacket(wlRequest->inp);
5976 smb_FreePacket(wlRequest->outp);
5985 if (wlRequest != NULL) {
5987 lock_ObtainWrite(&smb_globalLock);
5988 osi_QAdd((osi_queue_t **)&smb_allWaitingLocks,
5990 osi_Wakeup((LONG_PTR)&smb_allWaitingLocks);
5991 lock_ReleaseWrite(&smb_globalLock);
5993 /* don't send reply immediately */
5994 outp->flags |= SMB_PACKETFLAG_NOSEND;
5997 smb_SetSMBDataLength(outp, 0);
6001 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_LOCK);
6004 lock_ReleaseMutex(&scp->mx);
6005 cm_ReleaseSCache(scp);
6006 cm_ReleaseUser(userp);
6007 smb_ReleaseFID(fidp);
6012 long smb_ReceiveV3GetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6018 afs_uint32 searchTime;
6024 fid = smb_GetSMBParm(inp, 0);
6025 fid = smb_ChainFID(fid, inp);
6027 fidp = smb_FindFID(vcp, fid, 0);
6029 return CM_ERROR_BADFD;
6031 lock_ObtainMutex(&fidp->mx);
6032 if (fidp->flags & SMB_FID_IOCTL) {
6033 lock_ReleaseMutex(&fidp->mx);
6034 smb_ReleaseFID(fidp);
6035 return CM_ERROR_BADFD;
6038 osi_Log2(smb_logp,"smb_ReceiveV3GetAttributes fidp 0x%p scp 0x%p", fidp, scp);
6040 lock_ReleaseMutex(&fidp->mx);
6042 userp = smb_GetUserFromVCP(vcp, inp);
6045 /* otherwise, stat the file */
6046 lock_ObtainMutex(&scp->mx);
6047 code = cm_SyncOp(scp, NULL, userp, &req, 0,
6048 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
6052 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
6054 /* decode times. We need a search time, but the response to this
6055 * call provides the date first, not the time, as returned in the
6056 * searchTime variable. So we take the high-order bits first.
6058 smb_SearchTimeFromUnixTime(&searchTime, scp->clientModTime);
6059 smb_SetSMBParm(outp, 0, (searchTime >> 16) & 0xffff); /* ctime */
6060 smb_SetSMBParm(outp, 1, searchTime & 0xffff);
6061 smb_SetSMBParm(outp, 2, (searchTime >> 16) & 0xffff); /* atime */
6062 smb_SetSMBParm(outp, 3, searchTime & 0xffff);
6063 smb_SetSMBParm(outp, 4, (searchTime >> 16) & 0xffff); /* mtime */
6064 smb_SetSMBParm(outp, 5, searchTime & 0xffff);
6066 /* now handle file size and allocation size */
6067 smb_SetSMBParm(outp, 6, scp->length.LowPart & 0xffff); /* file size */
6068 smb_SetSMBParm(outp, 7, (scp->length.LowPart >> 16) & 0xffff);
6069 smb_SetSMBParm(outp, 8, scp->length.LowPart & 0xffff); /* alloc size */
6070 smb_SetSMBParm(outp, 9, (scp->length.LowPart >> 16) & 0xffff);
6072 /* file attribute */
6073 smb_SetSMBParm(outp, 10, smb_Attributes(scp));
6075 /* and finalize stuff */
6076 smb_SetSMBDataLength(outp, 0);
6080 lock_ReleaseMutex(&scp->mx);
6081 cm_ReleaseSCache(scp);
6082 cm_ReleaseUser(userp);
6083 smb_ReleaseFID(fidp);
6087 long smb_ReceiveV3SetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6093 afs_uint32 searchTime;
6101 fid = smb_GetSMBParm(inp, 0);
6102 fid = smb_ChainFID(fid, inp);
6104 fidp = smb_FindFID(vcp, fid, 0);
6106 return CM_ERROR_BADFD;
6108 lock_ObtainMutex(&fidp->mx);
6109 if (fidp->flags & SMB_FID_IOCTL) {
6110 lock_ReleaseMutex(&fidp->mx);
6111 smb_ReleaseFID(fidp);
6112 return CM_ERROR_BADFD;
6115 osi_Log2(smb_logp,"smb_ReceiveV3SetAttributes fidp 0x%p scp 0x%p", fidp, scp);
6117 lock_ReleaseMutex(&fidp->mx);
6119 userp = smb_GetUserFromVCP(vcp, inp);
6122 /* now prepare to call cm_setattr. This message only sets various times,
6123 * and AFS only implements mtime, and we'll set the mtime if that's
6124 * requested. The others we'll ignore.
6126 searchTime = smb_GetSMBParm(inp, 5) | (smb_GetSMBParm(inp, 6) << 16);
6128 if (searchTime != 0) {
6129 smb_UnixTimeFromSearchTime(&unixTime, searchTime);
6131 if ( unixTime != -1 ) {
6132 attrs.mask = CM_ATTRMASK_CLIENTMODTIME;
6133 attrs.clientModTime = unixTime;
6134 code = cm_SetAttr(scp, &attrs, userp, &req);
6136 osi_Log1(smb_logp, "SMB receive V3SetAttributes [fid=%ld]", fid);
6138 osi_Log1(smb_logp, "**smb_UnixTimeFromSearchTime failed searchTime=%ld", searchTime);
6144 cm_ReleaseSCache(scp);
6145 cm_ReleaseUser(userp);
6146 smb_ReleaseFID(fidp);
6150 long smb_ReceiveV3WriteX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6153 long count, written = 0, total_written = 0;
6160 int inDataBlockCount;
6162 fd = smb_GetSMBParm(inp, 2);
6163 count = smb_GetSMBParm(inp, 10);
6165 offset.HighPart = 0;
6166 offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
6168 if (*inp->wctp == 14) {
6169 /* we have a request with 64-bit file offsets */
6170 #ifdef AFS_LARGEFILES
6171 offset.HighPart = smb_GetSMBParm(inp, 12) | (smb_GetSMBParm(inp, 13) << 16);
6173 if ((smb_GetSMBParm(inp, 12) | (smb_GetSMBParm(inp, 13) << 16)) != 0) {
6175 osi_Log0(smb_logp, "smb_ReceiveV3WriteX offset requires largefile support");
6176 /* we shouldn't have received this op if we didn't specify
6177 largefile support */
6178 return CM_ERROR_BADOP;
6183 op = inp->data + smb_GetSMBParm(inp, 11);
6184 inDataBlockCount = count;
6186 osi_Log4(smb_logp, "smb_ReceiveV3WriteX fid %d, off 0x%x:%08x, size 0x%x",
6187 fd, offset.HighPart, offset.LowPart, count);
6189 fd = smb_ChainFID(fd, inp);
6190 fidp = smb_FindFID(vcp, fd, 0);
6192 return CM_ERROR_BADFD;
6194 lock_ObtainMutex(&fidp->mx);
6195 if (fidp->flags & SMB_FID_IOCTL) {
6196 lock_ReleaseMutex(&fidp->mx);
6197 code = smb_IoctlV3Write(fidp, vcp, inp, outp);
6198 smb_ReleaseFID(fidp);
6201 lock_ReleaseMutex(&fidp->mx);
6202 userp = smb_GetUserFromVCP(vcp, inp);
6204 /* special case: 0 bytes transferred means there is no data
6205 transferred. A slight departure from SMB_COM_WRITE where this
6206 means that we are supposed to truncate the file at this
6211 LARGE_INTEGER LOffset;
6212 LARGE_INTEGER LLength;
6215 pid = ((smb_t *) inp)->pid;
6216 key = cm_GenerateKey(vcp->vcID, pid, fd);
6218 LOffset.HighPart = offset.HighPart;
6219 LOffset.LowPart = offset.LowPart;
6220 LLength.HighPart = 0;
6221 LLength.LowPart = count;
6224 lock_ObtainMutex(&scp->mx);
6225 code = cm_LockCheckWrite(scp, LOffset, LLength, key);
6226 lock_ReleaseMutex(&scp->mx);
6233 * Work around bug in NT client
6235 * When copying a file, the NT client should first copy the data,
6236 * then copy the last write time. But sometimes the NT client does
6237 * these in the wrong order, so the data copies would inadvertently
6238 * cause the last write time to be overwritten. We try to detect this,
6239 * and don't set client mod time if we think that would go against the
6242 lock_ObtainMutex(&fidp->mx);
6243 if ((fidp->flags & SMB_FID_MTIMESETDONE) != SMB_FID_MTIMESETDONE) {
6244 fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
6245 fidp->scp->clientModTime = time(NULL);
6247 lock_ReleaseMutex(&fidp->mx);
6250 while ( code == 0 && count > 0 ) {
6251 code = smb_WriteData(fidp, &offset, count, op, userp, &written);
6252 if (code == 0 && written == 0)
6253 code = CM_ERROR_PARTIALWRITE;
6255 offset = LargeIntegerAdd(offset,
6256 ConvertLongToLargeInteger(written));
6258 total_written += written;
6264 /* slots 0 and 1 are reserved for request chaining and will be
6265 filled in when we return. */
6266 smb_SetSMBParm(outp, 2, total_written);
6267 smb_SetSMBParm(outp, 3, 0); /* reserved */
6268 smb_SetSMBParm(outp, 4, 0); /* reserved */
6269 smb_SetSMBParm(outp, 5, 0); /* reserved */
6270 smb_SetSMBDataLength(outp, 0);
6273 cm_ReleaseUser(userp);
6274 smb_ReleaseFID(fidp);
6279 long smb_ReceiveV3ReadX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6283 long finalCount = 0;
6292 fd = smb_GetSMBParm(inp, 2);
6293 count = smb_GetSMBParm(inp, 5);
6294 offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
6296 if (*inp->wctp == 12) {
6297 /* a request with 64-bit offsets */
6298 #ifdef AFS_LARGEFILES
6299 offset.HighPart = smb_GetSMBParm(inp, 10) | (smb_GetSMBParm(inp, 11) << 16);
6301 if (LargeIntegerLessThanZero(offset)) {
6302 osi_Log2(smb_logp, "smb_ReceiveV3Read offset too large (0x%x:%08x)",
6303 offset.HighPart, offset.LowPart);
6304 return CM_ERROR_BADSMB;
6307 if ((smb_GetSMBParm(inp, 10) | (smb_GetSMBParm(inp, 11) << 16)) != 0) {
6308 osi_Log0(smb_logp, "smb_ReceiveV3Read offset is 64-bit. Dropping");
6309 return CM_ERROR_BADSMB;
6311 offset.HighPart = 0;
6315 offset.HighPart = 0;
6318 osi_Log4(smb_logp, "smb_ReceiveV3Read fd %d, off 0x%x:%08x, size 0x%x",
6319 fd, offset.HighPart, offset.LowPart, count);
6321 fd = smb_ChainFID(fd, inp);
6322 fidp = smb_FindFID(vcp, fd, 0);
6324 return CM_ERROR_BADFD;
6327 pid = ((smb_t *) inp)->pid;
6328 key = cm_GenerateKey(vcp->vcID, pid, fd);
6330 LARGE_INTEGER LOffset, LLength;
6333 LOffset.HighPart = offset.HighPart;
6334 LOffset.LowPart = offset.LowPart;
6335 LLength.HighPart = 0;
6336 LLength.LowPart = count;
6339 lock_ObtainMutex(&scp->mx);
6340 code = cm_LockCheckRead(scp, LOffset, LLength, key);
6341 lock_ReleaseMutex(&scp->mx);
6345 smb_ReleaseFID(fidp);
6349 /* set inp->fid so that later read calls in same msg can find fid */
6352 lock_ObtainMutex(&fidp->mx);
6353 if (fidp->flags & SMB_FID_IOCTL) {
6354 lock_ReleaseMutex(&fidp->mx);
6355 code = smb_IoctlV3Read(fidp, vcp, inp, outp);
6356 smb_ReleaseFID(fidp);
6359 lock_ReleaseMutex(&fidp->mx);
6361 userp = smb_GetUserFromVCP(vcp, inp);
6363 /* 0 and 1 are reserved for request chaining, were setup by our caller,
6364 * and will be further filled in after we return.
6366 smb_SetSMBParm(outp, 2, 0); /* remaining bytes, for pipes */
6367 smb_SetSMBParm(outp, 3, 0); /* resvd */
6368 smb_SetSMBParm(outp, 4, 0); /* resvd */
6369 smb_SetSMBParm(outp, 5, count); /* # of bytes we're going to read */
6370 /* fill in #6 when we have all the parameters' space reserved */
6371 smb_SetSMBParm(outp, 7, 0); /* resv'd */
6372 smb_SetSMBParm(outp, 8, 0); /* resv'd */
6373 smb_SetSMBParm(outp, 9, 0); /* resv'd */
6374 smb_SetSMBParm(outp, 10, 0); /* resv'd */
6375 smb_SetSMBParm(outp, 11, 0); /* reserved */
6377 /* get op ptr after putting in the parms, since otherwise we don't
6378 * know where the data really is.
6380 op = smb_GetSMBData(outp, NULL);
6382 /* now fill in offset from start of SMB header to first data byte (to op) */
6383 smb_SetSMBParm(outp, 6, ((int) (op - outp->data)));
6385 /* set the packet data length the count of the # of bytes */
6386 smb_SetSMBDataLength(outp, count);
6388 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount);
6390 /* fix some things up */
6391 smb_SetSMBParm(outp, 5, finalCount);
6392 smb_SetSMBDataLength(outp, finalCount);
6394 cm_ReleaseUser(userp);
6395 smb_ReleaseFID(fidp);
6400 * Values for createDisp, copied from NTDDK.H
6402 #define FILE_SUPERSEDE 0 // (???)
6403 #define FILE_OPEN 1 // (open)
6404 #define FILE_CREATE 2 // (exclusive)
6405 #define FILE_OPEN_IF 3 // (non-exclusive)
6406 #define FILE_OVERWRITE 4 // (open & truncate, but do not create)
6407 #define FILE_OVERWRITE_IF 5 // (open & truncate, or create)
6410 #define REQUEST_OPLOCK 2
6411 #define REQUEST_BATCH_OPLOCK 4
6412 #define OPEN_DIRECTORY 8
6413 #define EXTENDED_RESPONSE_REQUIRED 0x10
6415 /* CreateOptions field. */
6416 #define FILE_DIRECTORY_FILE 0x0001
6417 #define FILE_WRITE_THROUGH 0x0002
6418 #define FILE_SEQUENTIAL_ONLY 0x0004
6419 #define FILE_NON_DIRECTORY_FILE 0x0040
6420 #define FILE_NO_EA_KNOWLEDGE 0x0200
6421 #define FILE_EIGHT_DOT_THREE_ONLY 0x0400
6422 #define FILE_RANDOM_ACCESS 0x0800
6423 #define FILE_DELETE_ON_CLOSE 0x1000
6424 #define FILE_OPEN_BY_FILE_ID 0x2000
6426 long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6428 char *pathp, *realPathp;
6432 cm_scache_t *dscp; /* parent dir */
6433 cm_scache_t *scp; /* file to create or open */
6434 cm_scache_t *targetScp; /* if scp is a symlink */
6438 unsigned short nameLength;
6440 unsigned int requestOpLock;
6441 unsigned int requestBatchOpLock;
6442 unsigned int mustBeDir;
6443 unsigned int extendedRespRequired;
6444 unsigned int treeCreate;
6446 unsigned int desiredAccess;
6447 unsigned int extAttributes;
6448 unsigned int createDisp;
6449 unsigned int createOptions;
6450 unsigned int shareAccess;
6451 int initialModeBits;
6452 unsigned short baseFid;
6453 smb_fid_t *baseFidp;
6455 cm_scache_t *baseDirp;
6456 unsigned short openAction;
6465 cm_lock_data_t *ldp = NULL;
6469 /* This code is very long and has a lot of if-then-else clauses
6470 * scp and dscp get reused frequently and we need to ensure that
6471 * we don't lose a reference. Start by ensuring that they are NULL.
6478 nameLength = smb_GetSMBOffsetParm(inp, 2, 1);
6479 flags = smb_GetSMBOffsetParm(inp, 3, 1)
6480 | (smb_GetSMBOffsetParm(inp, 4, 1) << 16);
6481 requestOpLock = flags & REQUEST_OPLOCK;
6482 requestBatchOpLock = flags & REQUEST_BATCH_OPLOCK;
6483 mustBeDir = flags & OPEN_DIRECTORY;
6484 extendedRespRequired = flags & EXTENDED_RESPONSE_REQUIRED;
6487 * Why all of a sudden 32-bit FID?
6488 * We will reject all bits higher than 16.
6490 if (smb_GetSMBOffsetParm(inp, 6, 1) != 0)
6491 return CM_ERROR_INVAL;
6492 baseFid = smb_GetSMBOffsetParm(inp, 5, 1);
6493 desiredAccess = smb_GetSMBOffsetParm(inp, 7, 1)
6494 | (smb_GetSMBOffsetParm(inp, 8, 1) << 16);
6495 extAttributes = smb_GetSMBOffsetParm(inp, 13, 1)
6496 | (smb_GetSMBOffsetParm(inp, 14, 1) << 16);
6497 shareAccess = smb_GetSMBOffsetParm(inp, 15, 1)
6498 | (smb_GetSMBOffsetParm(inp, 16, 1) << 16);
6499 createDisp = smb_GetSMBOffsetParm(inp, 17, 1)
6500 | (smb_GetSMBOffsetParm(inp, 18, 1) << 16);
6501 createOptions = smb_GetSMBOffsetParm(inp, 19, 1)
6502 | (smb_GetSMBOffsetParm(inp, 20, 1) << 16);
6504 /* mustBeDir is never set; createOptions directory bit seems to be
6507 if (createOptions & FILE_DIRECTORY_FILE)
6509 else if (createOptions & FILE_NON_DIRECTORY_FILE)
6515 * compute initial mode bits based on read-only flag in
6516 * extended attributes
6518 initialModeBits = 0666;
6519 if (extAttributes & SMB_ATTR_READONLY)
6520 initialModeBits &= ~0222;
6522 pathp = smb_GetSMBData(inp, NULL);
6523 /* Sometimes path is not null-terminated, so we make a copy. */
6524 realPathp = malloc(nameLength+1);
6525 memcpy(realPathp, pathp, nameLength);
6526 realPathp[nameLength] = 0;
6527 if (smb_StoreAnsiFilenames)
6528 OemToChar(realPathp,realPathp);
6530 spacep = inp->spacep;
6531 smb_StripLastComponent(spacep->data, &lastNamep, realPathp);
6533 osi_Log1(smb_logp,"NTCreateX for [%s]",osi_LogSaveString(smb_logp,realPathp));
6534 osi_Log4(smb_logp,"... da=[%x] ea=[%x] cd=[%x] co=[%x]", desiredAccess, extAttributes, createDisp, createOptions);
6535 osi_Log3(smb_logp,"... share=[%x] flags=[%x] lastNamep=[%s]", shareAccess, flags, osi_LogSaveString(smb_logp,(lastNamep?lastNamep:"null")));
6537 if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
6538 /* special case magic file name for receiving IOCTL requests
6539 * (since IOCTL calls themselves aren't getting through).
6541 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
6542 smb_SetupIoctlFid(fidp, spacep);
6543 osi_Log1(smb_logp,"NTCreateX Setting up IOCTL on fid[%d]",fidp->fid);
6545 /* set inp->fid so that later read calls in same msg can find fid */
6546 inp->fid = fidp->fid;
6550 smb_SetSMBParmByte(outp, parmSlot, 0); /* oplock */
6551 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
6552 smb_SetSMBParmLong(outp, parmSlot, 1); parmSlot += 2; /* Action */
6554 memset(&ft, 0, sizeof(ft));
6555 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
6556 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
6557 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
6558 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
6559 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2; /* attr */
6560 sz.HighPart = 0x7fff; sz.LowPart = 0;
6561 smb_SetSMBParmDouble(outp, parmSlot, (char *)&sz); parmSlot += 4; /* alen */
6562 smb_SetSMBParmDouble(outp, parmSlot, (char *)&sz); parmSlot += 4; /* len */
6563 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* filetype */
6564 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* dev state */
6565 smb_SetSMBParmByte(outp, parmSlot, 0); /* is a dir? */
6566 smb_SetSMBDataLength(outp, 0);
6568 /* clean up fid reference */
6569 smb_ReleaseFID(fidp);
6574 #ifdef DEBUG_VERBOSE
6576 char *hexp, *asciip;
6577 asciip = (lastNamep? lastNamep : realPathp);
6578 hexp = osi_HexifyString( asciip );
6579 DEBUG_EVENT2("AFS", "NTCreateX H[%s] A[%s]", hexp, asciip);
6584 userp = smb_GetUserFromVCP(vcp, inp);
6586 osi_Log1(smb_logp, "NTCreateX Invalid user [%d]", ((smb_t *) inp)->uid);
6588 return CM_ERROR_INVAL;
6593 baseDirp = cm_data.rootSCachep;
6594 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
6595 if (code == CM_ERROR_TIDIPC) {
6596 /* Attempt to use a TID allocated for IPC. The client
6597 * is probably looking for DCE RPC end points which we
6598 * don't support OR it could be looking to make a DFS
6601 osi_Log0(smb_logp, "NTCreateX received IPC TID");
6604 cm_ReleaseUser(userp);
6605 return CM_ERROR_NOSUCHFILE;
6606 #endif /* DFS_SUPPORT */
6609 baseFidp = smb_FindFID(vcp, baseFid, 0);
6611 osi_Log1(smb_logp, "NTCreateX Invalid base fid [%d]", baseFid);
6613 cm_ReleaseUser(userp);
6614 return CM_ERROR_INVAL;
6616 baseDirp = baseFidp->scp;
6620 osi_Log1(smb_logp, "NTCreateX tidPathp=[%s]", (tidPathp==NULL)?"null": osi_LogSaveString(smb_logp,tidPathp));
6622 /* compute open mode */
6624 if (desiredAccess & DELETE)
6625 fidflags |= SMB_FID_OPENDELETE;
6626 if (desiredAccess & AFS_ACCESS_READ)
6627 fidflags |= SMB_FID_OPENREAD_LISTDIR;
6628 if (desiredAccess & AFS_ACCESS_WRITE)
6629 fidflags |= SMB_FID_OPENWRITE;
6630 if (createOptions & FILE_DELETE_ON_CLOSE)
6631 fidflags |= SMB_FID_DELONCLOSE;
6632 if (createOptions & FILE_SEQUENTIAL_ONLY && !(createOptions & FILE_RANDOM_ACCESS))
6633 fidflags |= SMB_FID_SEQUENTIAL;
6634 if (createOptions & FILE_RANDOM_ACCESS && !(createOptions & FILE_SEQUENTIAL_ONLY))
6635 fidflags |= SMB_FID_RANDOM;
6636 if (smb_IsExecutableFileName(lastNamep))
6637 fidflags |= SMB_FID_EXECUTABLE;
6639 /* and the share mode */
6640 if (shareAccess & FILE_SHARE_READ)
6641 fidflags |= SMB_FID_SHARE_READ;
6642 if (shareAccess & FILE_SHARE_WRITE)
6643 fidflags |= SMB_FID_SHARE_WRITE;
6645 osi_Log1(smb_logp, "NTCreateX fidflags 0x%x", fidflags);
6648 /* For an exclusive create, we want to do a case sensitive match for the last component. */
6649 if ( createDisp == FILE_CREATE ||
6650 createDisp == FILE_OVERWRITE ||
6651 createDisp == FILE_OVERWRITE_IF) {
6652 code = cm_NameI(baseDirp, spacep->data, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
6653 userp, tidPathp, &req, &dscp);
6656 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
6657 cm_ReleaseSCache(dscp);
6658 cm_ReleaseUser(userp);
6661 smb_ReleaseFID(baseFidp);
6662 if ( WANTS_DFS_PATHNAMES(inp) )
6663 return CM_ERROR_PATH_NOT_COVERED;
6665 return CM_ERROR_BADSHARENAME;
6667 #endif /* DFS_SUPPORT */
6668 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp, CM_FLAG_FOLLOW,
6670 if (code == CM_ERROR_NOSUCHFILE || code == CM_ERROR_BPLUS_NOMATCH) {
6671 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp,
6672 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, &req, &scp);
6673 if (code == 0 && realDirFlag == 1) {
6674 cm_ReleaseSCache(scp);
6675 cm_ReleaseSCache(dscp);
6676 cm_ReleaseUser(userp);
6679 smb_ReleaseFID(baseFidp);
6680 return CM_ERROR_EXISTS;
6684 /* we have both scp and dscp */
6686 code = cm_NameI(baseDirp, realPathp, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
6687 userp, tidPathp, &req, &scp);
6689 if (code == 0 && scp->fileType == CM_SCACHETYPE_DFSLINK) {
6690 cm_ReleaseSCache(scp);
6691 cm_ReleaseUser(userp);
6694 smb_ReleaseFID(baseFidp);
6695 if ( WANTS_DFS_PATHNAMES(inp) )
6696 return CM_ERROR_PATH_NOT_COVERED;
6698 return CM_ERROR_BADSHARENAME;
6700 #endif /* DFS_SUPPORT */
6701 /* we might have scp but not dscp */
6707 if (!foundscp || (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE))) {
6708 /* look up parent directory */
6709 /* If we are trying to create a path (i.e. multiple nested directories), then we don't *need*
6710 * the immediate parent. We have to work our way up realPathp until we hit something that we
6714 /* we might or might not have scp */
6720 code = cm_NameI(baseDirp, spacep->data,
6721 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
6722 userp, tidPathp, &req, &dscp);
6725 if (code == 0 && dscp->fileType == CM_SCACHETYPE_DFSLINK) {
6727 cm_ReleaseSCache(scp);
6728 cm_ReleaseSCache(dscp);
6729 cm_ReleaseUser(userp);
6732 smb_ReleaseFID(baseFidp);
6733 if ( WANTS_DFS_PATHNAMES(inp) )
6734 return CM_ERROR_PATH_NOT_COVERED;
6736 return CM_ERROR_BADSHARENAME;
6738 #endif /* DFS_SUPPORT */
6741 (tp = strrchr(spacep->data,'\\')) &&
6742 (createDisp == FILE_CREATE) &&
6743 (realDirFlag == 1)) {
6746 treeStartp = realPathp + (tp - spacep->data);
6748 if (*tp && !smb_IsLegalFilename(tp)) {
6749 cm_ReleaseUser(userp);
6751 smb_ReleaseFID(baseFidp);
6754 cm_ReleaseSCache(scp);
6755 return CM_ERROR_BADNTFILENAME;
6759 } while (dscp == NULL && code == 0);
6763 /* we might have scp and we might have dscp */
6766 smb_ReleaseFID(baseFidp);
6769 osi_Log0(smb_logp,"NTCreateX parent not found");
6771 cm_ReleaseSCache(scp);
6773 cm_ReleaseSCache(dscp);
6774 cm_ReleaseUser(userp);
6779 if (treeCreate && dscp->fileType == CM_SCACHETYPE_FILE) {
6780 /* A file exists where we want a directory. */
6782 cm_ReleaseSCache(scp);
6783 cm_ReleaseSCache(dscp);
6784 cm_ReleaseUser(userp);
6786 return CM_ERROR_EXISTS;
6790 lastNamep = realPathp;
6794 if (!smb_IsLegalFilename(lastNamep)) {
6796 cm_ReleaseSCache(scp);
6798 cm_ReleaseSCache(dscp);
6799 cm_ReleaseUser(userp);
6801 return CM_ERROR_BADNTFILENAME;
6804 if (!foundscp && !treeCreate) {
6805 if ( createDisp == FILE_CREATE ||
6806 createDisp == FILE_OVERWRITE ||
6807 createDisp == FILE_OVERWRITE_IF)
6809 code = cm_Lookup(dscp, lastNamep,
6810 CM_FLAG_FOLLOW, userp, &req, &scp);
6812 code = cm_Lookup(dscp, lastNamep,
6813 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
6816 if (code && (code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH)) {
6818 cm_ReleaseSCache(dscp);
6819 cm_ReleaseUser(userp);
6824 /* we have scp and dscp */
6826 /* we have scp but not dscp */
6828 smb_ReleaseFID(baseFidp);
6831 /* if we get here, if code is 0, the file exists and is represented by
6832 * scp. Otherwise, we have to create it. The dir may be represented
6833 * by dscp, or we may have found the file directly. If code is non-zero,
6836 if (code == 0 && !treeCreate) {
6837 code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp, &req, &ldp);
6840 cm_ReleaseSCache(dscp);
6842 cm_ReleaseSCache(scp);
6843 cm_ReleaseUser(userp);
6848 if (createDisp == FILE_CREATE) {
6849 /* oops, file shouldn't be there */
6850 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
6852 cm_ReleaseSCache(dscp);
6854 cm_ReleaseSCache(scp);
6855 cm_ReleaseUser(userp);
6857 return CM_ERROR_EXISTS;
6860 if ( createDisp == FILE_OVERWRITE ||
6861 createDisp == FILE_OVERWRITE_IF) {
6863 setAttr.mask = CM_ATTRMASK_LENGTH;
6864 setAttr.length.LowPart = 0;
6865 setAttr.length.HighPart = 0;
6866 /* now watch for a symlink */
6868 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
6870 osi_assert(dscp != NULL);
6871 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
6873 /* we have a more accurate file to use (the
6874 * target of the symbolic link). Otherwise,
6875 * we'll just use the symlink anyway.
6877 osi_Log2(smb_logp, "symlink vp %x to vp %x",
6879 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
6880 cm_ReleaseSCache(scp);
6882 code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp, &req, &ldp);
6885 cm_ReleaseSCache(dscp);
6887 cm_ReleaseSCache(scp);
6888 cm_ReleaseUser(userp);
6894 code = cm_SetAttr(scp, &setAttr, userp, &req);
6895 openAction = 3; /* truncated existing file */
6898 openAction = 1; /* found existing file */
6900 } else if (createDisp == FILE_OPEN || createDisp == FILE_OVERWRITE) {
6901 /* don't create if not found */
6903 cm_ReleaseSCache(dscp);
6905 cm_ReleaseSCache(scp);
6906 cm_ReleaseUser(userp);
6908 return CM_ERROR_NOSUCHFILE;
6909 } else if (realDirFlag == 0 || realDirFlag == -1) {
6910 osi_assert(dscp != NULL);
6911 osi_Log1(smb_logp, "smb_ReceiveNTCreateX creating file %s",
6912 osi_LogSaveString(smb_logp, lastNamep));
6913 openAction = 2; /* created file */
6914 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
6915 setAttr.clientModTime = time(NULL);
6916 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp, &req);
6919 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
6920 smb_NotifyChange(FILE_ACTION_ADDED,
6921 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
6922 dscp, lastNamep, NULL, TRUE);
6923 } else if (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE) {
6924 /* Not an exclusive create, and someone else tried
6925 * creating it already, then we open it anyway. We
6926 * don't bother retrying after this, since if this next
6927 * fails, that means that the file was deleted after we
6928 * started this call.
6930 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
6933 if (createDisp == FILE_OVERWRITE_IF) {
6934 setAttr.mask = CM_ATTRMASK_LENGTH;
6935 setAttr.length.LowPart = 0;
6936 setAttr.length.HighPart = 0;
6938 /* now watch for a symlink */
6940 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
6942 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
6944 /* we have a more accurate file to use (the
6945 * target of the symbolic link). Otherwise,
6946 * we'll just use the symlink anyway.
6948 osi_Log2(smb_logp, "symlink vp %x to vp %x",
6950 cm_ReleaseSCache(scp);
6954 code = cm_SetAttr(scp, &setAttr, userp, &req);
6956 } /* lookup succeeded */
6960 char *cp; /* This component */
6961 int clen = 0; /* length of component */
6962 cm_scache_t *tscp1, *tscp2;
6965 /* create directory */
6967 treeStartp = lastNamep;
6968 osi_assert(dscp != NULL);
6969 osi_Log1(smb_logp, "smb_ReceiveNTCreateX creating directory [%s]",
6970 osi_LogSaveString(smb_logp, treeStartp));
6971 openAction = 2; /* created directory */
6973 /* if the request is to create the root directory
6974 * it will appear as a directory name of the nul-string
6975 * and a code of CM_ERROR_NOSUCHFILE
6977 if ( !*treeStartp && (code == CM_ERROR_NOSUCHFILE || code == CM_ERROR_BPLUS_NOMATCH))
6978 code = CM_ERROR_EXISTS;
6980 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
6981 setAttr.clientModTime = time(NULL);
6986 cm_HoldSCache(tscp1);
6990 tp = strchr(pp, '\\');
6993 clen = (int)strlen(cp);
6994 isLast = 1; /* indicate last component. the supplied path never ends in a slash */
6996 clen = (int)(tp - pp);
6997 strncpy(cp,pp,clen);
7004 continue; /* the supplied path can't have consecutive slashes either , but */
7006 /* cp is the next component to be created. */
7007 code = cm_MakeDir(tscp1, cp, 0, &setAttr, userp, &req);
7008 if (code == 0 && (tscp1->flags & CM_SCACHEFLAG_ANYWATCH))
7009 smb_NotifyChange(FILE_ACTION_ADDED,
7010 FILE_NOTIFY_CHANGE_DIR_NAME,
7011 tscp1, cp, NULL, TRUE);
7013 (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE)) {
7014 /* Not an exclusive create, and someone else tried
7015 * creating it already, then we open it anyway. We
7016 * don't bother retrying after this, since if this next
7017 * fails, that means that the file was deleted after we
7018 * started this call.
7020 code = cm_Lookup(tscp1, cp, CM_FLAG_CASEFOLD,
7021 userp, &req, &tscp2);
7026 if (!isLast) { /* for anything other than dscp, release it unless it's the last one */
7027 cm_ReleaseSCache(tscp1);
7028 tscp1 = tscp2; /* Newly created directory will be next parent */
7029 /* the hold is transfered to tscp1 from tscp2 */
7034 cm_ReleaseSCache(dscp);
7037 cm_ReleaseSCache(scp);
7040 * if we get here and code == 0, then scp is the last directory created, and dscp is the
7046 /* something went wrong creating or truncating the file */
7048 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7050 cm_ReleaseSCache(scp);
7052 cm_ReleaseSCache(dscp);
7053 cm_ReleaseUser(userp);
7058 /* make sure we have file vs. dir right (only applies for single component case) */
7059 if (realDirFlag == 0 && scp->fileType != CM_SCACHETYPE_FILE) {
7060 /* now watch for a symlink */
7062 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
7063 cm_scache_t * targetScp = 0;
7064 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
7066 /* we have a more accurate file to use (the
7067 * target of the symbolic link). Otherwise,
7068 * we'll just use the symlink anyway.
7070 osi_Log2(smb_logp, "symlink vp %x to vp %x", scp, targetScp);
7072 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7073 cm_ReleaseSCache(scp);
7078 if (scp->fileType != CM_SCACHETYPE_FILE) {
7080 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7082 cm_ReleaseSCache(dscp);
7083 cm_ReleaseSCache(scp);
7084 cm_ReleaseUser(userp);
7086 return CM_ERROR_ISDIR;
7090 /* (only applies to single component case) */
7091 if (realDirFlag == 1 && scp->fileType == CM_SCACHETYPE_FILE) {
7093 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7094 cm_ReleaseSCache(scp);
7096 cm_ReleaseSCache(dscp);
7097 cm_ReleaseUser(userp);
7099 return CM_ERROR_NOTDIR;
7102 /* open the file itself */
7103 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
7106 /* save a reference to the user */
7108 fidp->userp = userp;
7110 /* If we are restricting sharing, we should do so with a suitable
7112 if (scp->fileType == CM_SCACHETYPE_FILE &&
7113 !(fidflags & SMB_FID_SHARE_WRITE)) {
7115 LARGE_INTEGER LOffset, LLength;
7118 LOffset.HighPart = SMB_FID_QLOCK_HIGH;
7119 LOffset.LowPart = SMB_FID_QLOCK_LOW;
7120 LLength.HighPart = 0;
7121 LLength.LowPart = SMB_FID_QLOCK_LENGTH;
7123 /* If we are not opening the file for writing, then we don't
7124 try to get an exclusive lock. Noone else should be able to
7125 get an exclusive lock on the file anyway, although someone
7126 else can get a shared lock. */
7127 if ((fidflags & SMB_FID_SHARE_READ) ||
7128 !(fidflags & SMB_FID_OPENWRITE)) {
7129 sLockType = LOCKING_ANDX_SHARED_LOCK;
7134 key = cm_GenerateKey(vcp->vcID, SMB_FID_QLOCK_PID, fidp->fid);
7136 lock_ObtainMutex(&scp->mx);
7137 code = cm_Lock(scp, sLockType, LOffset, LLength, key, 0, userp, &req, NULL);
7138 lock_ReleaseMutex(&scp->mx);
7142 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7143 cm_ReleaseSCache(scp);
7145 cm_ReleaseSCache(dscp);
7146 cm_ReleaseUser(userp);
7147 /* Shouldn't this be smb_CloseFID()? fidp->flags = SMB_FID_DELETE; */
7148 smb_CloseFID(vcp, fidp, NULL, 0);
7149 smb_ReleaseFID(fidp);
7155 /* Now its safe to release the file server lock obtained by cm_CheckNTOpen() */
7157 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7159 lock_ObtainMutex(&fidp->mx);
7160 /* save a pointer to the vnode */
7161 fidp->scp = scp; /* Hold transfered to fidp->scp and no longer needed */
7162 lock_ObtainMutex(&scp->mx);
7163 scp->flags |= CM_SCACHEFLAG_SMB_FID;
7164 lock_ReleaseMutex(&scp->mx);
7165 osi_Log2(smb_logp,"smb_ReceiveNTCreateX fidp 0x%p scp 0x%p", fidp, scp);
7167 fidp->flags = fidflags;
7169 /* remember if the file was newly created */
7171 fidp->flags |= SMB_FID_CREATED;
7173 /* save parent dir and pathname for delete or change notification */
7174 if (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE)) {
7175 osi_Log2(smb_logp,"smb_ReceiveNTCreateX fidp 0x%p dscp 0x%p", fidp, dscp);
7176 fidp->flags |= SMB_FID_NTOPEN;
7177 fidp->NTopen_dscp = dscp;
7179 fidp->NTopen_pathp = strdup(lastNamep);
7181 fidp->NTopen_wholepathp = realPathp;
7182 lock_ReleaseMutex(&fidp->mx);
7184 /* we don't need this any longer */
7186 cm_ReleaseSCache(dscp);
7190 cm_Open(scp, 0, userp);
7192 /* set inp->fid so that later read calls in same msg can find fid */
7193 inp->fid = fidp->fid;
7197 lock_ObtainMutex(&scp->mx);
7198 smb_SetSMBParmByte(outp, parmSlot, 0); /* oplock */
7199 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
7200 smb_SetSMBParmLong(outp, parmSlot, openAction); parmSlot += 2;
7201 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
7202 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
7203 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
7204 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
7205 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
7206 smb_SetSMBParmLong(outp, parmSlot, smb_ExtAttributes(scp));
7208 smb_SetSMBParmDouble(outp, parmSlot, (char *)&scp->length); parmSlot += 4;
7209 smb_SetSMBParmDouble(outp, parmSlot, (char *)&scp->length); parmSlot += 4;
7210 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* filetype */
7211 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* dev state */
7212 smb_SetSMBParmByte(outp, parmSlot,
7213 (scp->fileType == CM_SCACHETYPE_DIRECTORY ||
7214 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
7215 scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0); /* is a dir? */
7216 smb_SetSMBDataLength(outp, 0);
7218 if ((fidp->flags & SMB_FID_EXECUTABLE) &&
7219 LargeIntegerGreaterThanZero(fidp->scp->length) &&
7220 !(scp->flags & CM_SCACHEFLAG_PREFETCHING)) {
7221 cm_QueueBKGRequest(fidp->scp, cm_BkgPrefetch, 0, 0,
7222 fidp->scp->length.LowPart, fidp->scp->length.HighPart,
7225 lock_ReleaseMutex(&scp->mx);
7227 osi_Log2(smb_logp, "SMB NT CreateX opening fid %d path %s", fidp->fid,
7228 osi_LogSaveString(smb_logp, realPathp));
7230 cm_ReleaseUser(userp);
7231 smb_ReleaseFID(fidp);
7233 /* Can't free realPathp if we get here since
7234 fidp->NTopen_wholepathp is pointing there */
7236 /* leave scp held since we put it in fidp->scp */
7241 * A lot of stuff copied verbatim from NT Create&X to NT Tran Create.
7242 * Instead, ultimately, would like to use a subroutine for common code.
7244 long smb_ReceiveNTTranCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7246 char *pathp, *realPathp;
7250 cm_scache_t *dscp; /* parent dir */
7251 cm_scache_t *scp; /* file to create or open */
7252 cm_scache_t *targetScp; /* if scp is a symlink */
7255 unsigned long nameLength;
7257 unsigned int requestOpLock;
7258 unsigned int requestBatchOpLock;
7259 unsigned int mustBeDir;
7260 unsigned int extendedRespRequired;
7262 unsigned int desiredAccess;
7263 #ifdef DEBUG_VERBOSE
7264 unsigned int allocSize;
7266 unsigned int shareAccess;
7267 unsigned int extAttributes;
7268 unsigned int createDisp;
7269 #ifdef DEBUG_VERBOSE
7272 unsigned int createOptions;
7273 int initialModeBits;
7274 unsigned short baseFid;
7275 smb_fid_t *baseFidp;
7277 cm_scache_t *baseDirp;
7278 unsigned short openAction;
7284 int parmOffset, dataOffset;
7290 cm_lock_data_t *ldp = NULL;
7297 parmOffset = smb_GetSMBOffsetParm(inp, 11, 1)
7298 | (smb_GetSMBOffsetParm(inp, 12, 1) << 16);
7299 parmp = inp->data + parmOffset;
7300 lparmp = (ULONG *) parmp;
7303 requestOpLock = flags & REQUEST_OPLOCK;
7304 requestBatchOpLock = flags & REQUEST_BATCH_OPLOCK;
7305 mustBeDir = flags & OPEN_DIRECTORY;
7306 extendedRespRequired = flags & EXTENDED_RESPONSE_REQUIRED;
7309 * Why all of a sudden 32-bit FID?
7310 * We will reject all bits higher than 16.
7312 if (lparmp[1] & 0xFFFF0000)
7313 return CM_ERROR_INVAL;
7314 baseFid = (unsigned short)lparmp[1];
7315 desiredAccess = lparmp[2];
7316 #ifdef DEBUG_VERBOSE
7317 allocSize = lparmp[3];
7318 #endif /* DEBUG_VERSOSE */
7319 extAttributes = lparmp[5];
7320 shareAccess = lparmp[6];
7321 createDisp = lparmp[7];
7322 createOptions = lparmp[8];
7323 #ifdef DEBUG_VERBOSE
7326 nameLength = lparmp[11];
7328 #ifdef DEBUG_VERBOSE
7329 osi_Log4(smb_logp,"NTTranCreate with da[%x],ea[%x],sa[%x],cd[%x]",desiredAccess,extAttributes,shareAccess,createDisp);
7330 osi_Log3(smb_logp,"... co[%x],sdl[%x],as[%x]",createOptions,sdLen,allocSize);
7331 osi_Log1(smb_logp,"... flags[%x]",flags);
7334 /* mustBeDir is never set; createOptions directory bit seems to be
7337 if (createOptions & FILE_DIRECTORY_FILE)
7339 else if (createOptions & FILE_NON_DIRECTORY_FILE)
7345 * compute initial mode bits based on read-only flag in
7346 * extended attributes
7348 initialModeBits = 0666;
7349 if (extAttributes & SMB_ATTR_READONLY)
7350 initialModeBits &= ~0222;
7352 pathp = parmp + (13 * sizeof(ULONG)) + sizeof(UCHAR);
7353 /* Sometimes path is not null-terminated, so we make a copy. */
7354 realPathp = malloc(nameLength+1);
7355 memcpy(realPathp, pathp, nameLength);
7356 realPathp[nameLength] = 0;
7357 if (smb_StoreAnsiFilenames)
7358 OemToChar(realPathp,realPathp);
7360 spacep = cm_GetSpace();
7361 smb_StripLastComponent(spacep->data, &lastNamep, realPathp);
7364 * Nothing here to handle SMB_IOCTL_FILENAME.
7365 * Will add it if necessary.
7368 #ifdef DEBUG_VERBOSE
7370 char *hexp, *asciip;
7371 asciip = (lastNamep? lastNamep : realPathp);
7372 hexp = osi_HexifyString( asciip );
7373 DEBUG_EVENT2("AFS", "NTTranCreate H[%s] A[%s]", hexp, asciip);
7378 userp = smb_GetUserFromVCP(vcp, inp);
7380 osi_Log1(smb_logp, "NTTranCreate invalid user [%d]", ((smb_t *) inp)->uid);
7382 return CM_ERROR_INVAL;
7387 baseDirp = cm_data.rootSCachep;
7388 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
7389 if (code == CM_ERROR_TIDIPC) {
7390 /* Attempt to use a TID allocated for IPC. The client
7391 * is probably looking for DCE RPC end points which we
7392 * don't support OR it could be looking to make a DFS
7395 osi_Log0(smb_logp, "NTTranCreate received IPC TID");
7398 cm_ReleaseUser(userp);
7399 return CM_ERROR_NOSUCHPATH;
7403 baseFidp = smb_FindFID(vcp, baseFid, 0);
7405 osi_Log1(smb_logp, "NTTranCreate Invalid fid [%d]", baseFid);
7407 cm_ReleaseUser(userp);
7408 return CM_ERROR_INVAL;
7410 baseDirp = baseFidp->scp;
7414 /* compute open mode */
7416 if (desiredAccess & DELETE)
7417 fidflags |= SMB_FID_OPENDELETE;
7418 if (desiredAccess & AFS_ACCESS_READ)
7419 fidflags |= SMB_FID_OPENREAD_LISTDIR;
7420 if (desiredAccess & AFS_ACCESS_WRITE)
7421 fidflags |= SMB_FID_OPENWRITE;
7422 if (createOptions & FILE_DELETE_ON_CLOSE)
7423 fidflags |= SMB_FID_DELONCLOSE;
7424 if (createOptions & FILE_SEQUENTIAL_ONLY && !(createOptions & FILE_RANDOM_ACCESS))
7425 fidflags |= SMB_FID_SEQUENTIAL;
7426 if (createOptions & FILE_RANDOM_ACCESS && !(createOptions & FILE_SEQUENTIAL_ONLY))
7427 fidflags |= SMB_FID_RANDOM;
7428 if (smb_IsExecutableFileName(lastNamep))
7429 fidflags |= SMB_FID_EXECUTABLE;
7431 /* And the share mode */
7432 if (shareAccess & FILE_SHARE_READ)
7433 fidflags |= SMB_FID_SHARE_READ;
7434 if (shareAccess & FILE_SHARE_WRITE)
7435 fidflags |= SMB_FID_SHARE_WRITE;
7439 if ( createDisp == FILE_OPEN ||
7440 createDisp == FILE_OVERWRITE ||
7441 createDisp == FILE_OVERWRITE_IF) {
7442 code = cm_NameI(baseDirp, spacep->data, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
7443 userp, tidPathp, &req, &dscp);
7446 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
7447 cm_ReleaseSCache(dscp);
7448 cm_ReleaseUser(userp);
7451 smb_ReleaseFID(baseFidp);
7452 if ( WANTS_DFS_PATHNAMES(inp) )
7453 return CM_ERROR_PATH_NOT_COVERED;
7455 return CM_ERROR_BADSHARENAME;
7457 #endif /* DFS_SUPPORT */
7458 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp, CM_FLAG_FOLLOW,
7460 if (code == CM_ERROR_NOSUCHFILE || code == CM_ERROR_BPLUS_NOMATCH) {
7461 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp,
7462 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, &req, &scp);
7463 if (code == 0 && realDirFlag == 1) {
7464 cm_ReleaseSCache(scp);
7465 cm_ReleaseSCache(dscp);
7466 cm_ReleaseUser(userp);
7469 smb_ReleaseFID(baseFidp);
7470 return CM_ERROR_EXISTS;
7476 code = cm_NameI(baseDirp, realPathp, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
7477 userp, tidPathp, &req, &scp);
7479 if (code == 0 && scp->fileType == CM_SCACHETYPE_DFSLINK) {
7480 cm_ReleaseSCache(scp);
7481 cm_ReleaseUser(userp);
7484 smb_ReleaseFID(baseFidp);
7485 if ( WANTS_DFS_PATHNAMES(inp) )
7486 return CM_ERROR_PATH_NOT_COVERED;
7488 return CM_ERROR_BADSHARENAME;
7490 #endif /* DFS_SUPPORT */
7496 if (code != 0 || (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE))) {
7497 /* look up parent directory */
7499 code = cm_NameI(baseDirp, spacep->data,
7500 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
7501 userp, tidPathp, &req, &dscp);
7503 if (code == 0 && dscp->fileType == CM_SCACHETYPE_DFSLINK) {
7504 cm_ReleaseSCache(dscp);
7505 cm_ReleaseUser(userp);
7508 smb_ReleaseFID(baseFidp);
7509 if ( WANTS_DFS_PATHNAMES(inp) )
7510 return CM_ERROR_PATH_NOT_COVERED;
7512 return CM_ERROR_BADSHARENAME;
7514 #endif /* DFS_SUPPORT */
7518 cm_FreeSpace(spacep);
7521 smb_ReleaseFID(baseFidp);
7524 cm_ReleaseUser(userp);
7530 lastNamep = realPathp;
7534 if (!smb_IsLegalFilename(lastNamep))
7535 return CM_ERROR_BADNTFILENAME;
7538 if (createDisp == FILE_CREATE || createDisp == FILE_OVERWRITE_IF) {
7539 code = cm_Lookup(dscp, lastNamep,
7540 CM_FLAG_FOLLOW, userp, &req, &scp);
7542 code = cm_Lookup(dscp, lastNamep,
7543 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
7546 if (code && code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
7547 cm_ReleaseSCache(dscp);
7548 cm_ReleaseUser(userp);
7555 smb_ReleaseFID(baseFidp);
7556 cm_FreeSpace(spacep);
7559 /* if we get here, if code is 0, the file exists and is represented by
7560 * scp. Otherwise, we have to create it. The dir may be represented
7561 * by dscp, or we may have found the file directly. If code is non-zero,
7565 code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp, &req, &ldp);
7568 cm_ReleaseSCache(dscp);
7569 cm_ReleaseSCache(scp);
7570 cm_ReleaseUser(userp);
7575 if (createDisp == FILE_CREATE) {
7576 /* oops, file shouldn't be there */
7577 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7579 cm_ReleaseSCache(dscp);
7580 cm_ReleaseSCache(scp);
7581 cm_ReleaseUser(userp);
7583 return CM_ERROR_EXISTS;
7586 if (createDisp == FILE_OVERWRITE ||
7587 createDisp == FILE_OVERWRITE_IF) {
7588 setAttr.mask = CM_ATTRMASK_LENGTH;
7589 setAttr.length.LowPart = 0;
7590 setAttr.length.HighPart = 0;
7592 /* now watch for a symlink */
7594 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
7596 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
7598 /* we have a more accurate file to use (the
7599 * target of the symbolic link). Otherwise,
7600 * we'll just use the symlink anyway.
7602 osi_Log2(smb_logp, "symlink vp %x to vp %x",
7604 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7605 cm_ReleaseSCache(scp);
7607 code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp, &req, &ldp);
7610 cm_ReleaseSCache(dscp);
7612 cm_ReleaseSCache(scp);
7613 cm_ReleaseUser(userp);
7619 code = cm_SetAttr(scp, &setAttr, userp, &req);
7620 openAction = 3; /* truncated existing file */
7622 else openAction = 1; /* found existing file */
7624 else if (createDisp == FILE_OPEN || createDisp == FILE_OVERWRITE) {
7625 /* don't create if not found */
7627 cm_ReleaseSCache(dscp);
7628 cm_ReleaseUser(userp);
7630 return CM_ERROR_NOSUCHFILE;
7632 else if (realDirFlag == 0 || realDirFlag == -1) {
7633 osi_assert(dscp != NULL);
7634 osi_Log1(smb_logp, "smb_ReceiveNTTranCreate creating file %s",
7635 osi_LogSaveString(smb_logp, lastNamep));
7636 openAction = 2; /* created file */
7637 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
7638 setAttr.clientModTime = time(NULL);
7639 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
7643 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
7644 smb_NotifyChange(FILE_ACTION_ADDED,
7645 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
7646 dscp, lastNamep, NULL, TRUE);
7647 } else if (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE) {
7648 /* Not an exclusive create, and someone else tried
7649 * creating it already, then we open it anyway. We
7650 * don't bother retrying after this, since if this next
7651 * fails, that means that the file was deleted after we
7652 * started this call.
7654 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
7657 if (createDisp == FILE_OVERWRITE_IF) {
7658 setAttr.mask = CM_ATTRMASK_LENGTH;
7659 setAttr.length.LowPart = 0;
7660 setAttr.length.HighPart = 0;
7662 /* now watch for a symlink */
7664 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
7666 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
7668 /* we have a more accurate file to use (the
7669 * target of the symbolic link). Otherwise,
7670 * we'll just use the symlink anyway.
7672 osi_Log2(smb_logp, "symlink vp %x to vp %x",
7674 cm_ReleaseSCache(scp);
7678 code = cm_SetAttr(scp, &setAttr, userp, &req);
7680 } /* lookup succeeded */
7683 /* create directory */
7684 osi_assert(dscp != NULL);
7686 "smb_ReceiveNTTranCreate creating directory %s",
7687 osi_LogSaveString(smb_logp, lastNamep));
7688 openAction = 2; /* created directory */
7689 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
7690 setAttr.clientModTime = time(NULL);
7691 code = cm_MakeDir(dscp, lastNamep, 0, &setAttr, userp, &req);
7692 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
7693 smb_NotifyChange(FILE_ACTION_ADDED,
7694 FILE_NOTIFY_CHANGE_DIR_NAME,
7695 dscp, lastNamep, NULL, TRUE);
7697 (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE)) {
7698 /* Not an exclusive create, and someone else tried
7699 * creating it already, then we open it anyway. We
7700 * don't bother retrying after this, since if this next
7701 * fails, that means that the file was deleted after we
7702 * started this call.
7704 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
7710 /* something went wrong creating or truncating the file */
7712 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7714 cm_ReleaseSCache(scp);
7715 cm_ReleaseUser(userp);
7720 /* make sure we have file vs. dir right */
7721 if (realDirFlag == 0 && scp->fileType != CM_SCACHETYPE_FILE) {
7722 /* now watch for a symlink */
7724 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
7726 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
7728 /* we have a more accurate file to use (the
7729 * target of the symbolic link). Otherwise,
7730 * we'll just use the symlink anyway.
7732 osi_Log2(smb_logp, "symlink vp %x to vp %x",
7735 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7736 cm_ReleaseSCache(scp);
7741 if (scp->fileType != CM_SCACHETYPE_FILE) {
7743 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7744 cm_ReleaseSCache(scp);
7745 cm_ReleaseUser(userp);
7747 return CM_ERROR_ISDIR;
7751 if (realDirFlag == 1 && scp->fileType == CM_SCACHETYPE_FILE) {
7753 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7754 cm_ReleaseSCache(scp);
7755 cm_ReleaseUser(userp);
7757 return CM_ERROR_NOTDIR;
7760 /* open the file itself */
7761 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
7764 /* save a reference to the user */
7766 fidp->userp = userp;
7768 /* If we are restricting sharing, we should do so with a suitable
7770 if (scp->fileType == CM_SCACHETYPE_FILE &&
7771 !(fidflags & SMB_FID_SHARE_WRITE)) {
7773 LARGE_INTEGER LOffset, LLength;
7776 LOffset.HighPart = SMB_FID_QLOCK_HIGH;
7777 LOffset.LowPart = SMB_FID_QLOCK_LOW;
7778 LLength.HighPart = 0;
7779 LLength.LowPart = SMB_FID_QLOCK_LENGTH;
7781 /* Similar to what we do in handling NTCreateX. We get a
7782 shared lock if we are only opening the file for reading. */
7783 if ((fidflags & SMB_FID_SHARE_READ) ||
7784 !(fidflags & SMB_FID_OPENWRITE)) {
7785 sLockType = LOCKING_ANDX_SHARED_LOCK;
7790 key = cm_GenerateKey(vcp->vcID, SMB_FID_QLOCK_PID, fidp->fid);
7792 lock_ObtainMutex(&scp->mx);
7793 code = cm_Lock(scp, sLockType, LOffset, LLength, key, 0, userp, &req, NULL);
7794 lock_ReleaseMutex(&scp->mx);
7798 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7799 cm_ReleaseSCache(scp);
7800 cm_ReleaseUser(userp);
7801 /* Shouldn't this be smb_CloseFID()? fidp->flags = SMB_FID_DELETE; */
7802 smb_CloseFID(vcp, fidp, NULL, 0);
7803 smb_ReleaseFID(fidp);
7805 return CM_ERROR_SHARING_VIOLATION;
7809 /* Now its safe to drop the file server lock obtained by cm_CheckNTOpen() */
7811 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7813 lock_ObtainMutex(&fidp->mx);
7814 /* save a pointer to the vnode */
7816 lock_ObtainMutex(&scp->mx);
7817 scp->flags |= CM_SCACHEFLAG_SMB_FID;
7818 lock_ReleaseMutex(&scp->mx);
7819 osi_Log2(smb_logp,"smb_ReceiveNTTranCreate fidp 0x%p scp 0x%p", fidp, scp);
7821 fidp->flags = fidflags;
7823 /* remember if the file was newly created */
7825 fidp->flags |= SMB_FID_CREATED;
7827 /* save parent dir and pathname for deletion or change notification */
7828 if (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE)) {
7829 fidp->flags |= SMB_FID_NTOPEN;
7830 fidp->NTopen_dscp = dscp;
7831 osi_Log2(smb_logp,"smb_ReceiveNTTranCreate fidp 0x%p dscp 0x%p", fidp, dscp);
7833 fidp->NTopen_pathp = strdup(lastNamep);
7835 fidp->NTopen_wholepathp = realPathp;
7836 lock_ReleaseMutex(&fidp->mx);
7838 /* we don't need this any longer */
7840 cm_ReleaseSCache(dscp);
7842 cm_Open(scp, 0, userp);
7844 /* set inp->fid so that later read calls in same msg can find fid */
7845 inp->fid = fidp->fid;
7847 /* check whether we are required to send an extended response */
7848 if (!extendedRespRequired) {
7850 parmOffset = 8*4 + 39;
7851 parmOffset += 1; /* pad to 4 */
7852 dataOffset = parmOffset + 70;
7856 /* Total Parameter Count */
7857 smb_SetSMBParmLong(outp, parmSlot, 70); parmSlot += 2;
7858 /* Total Data Count */
7859 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
7860 /* Parameter Count */
7861 smb_SetSMBParmLong(outp, parmSlot, 70); parmSlot += 2;
7862 /* Parameter Offset */
7863 smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
7864 /* Parameter Displacement */
7865 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
7867 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
7869 smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
7870 /* Data Displacement */
7871 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
7872 smb_SetSMBParmByte(outp, parmSlot, 0); /* Setup Count */
7873 smb_SetSMBDataLength(outp, 70);
7875 lock_ObtainMutex(&scp->mx);
7876 outData = smb_GetSMBData(outp, NULL);
7877 outData++; /* round to get to parmOffset */
7878 *outData = 0; outData++; /* oplock */
7879 *outData = 0; outData++; /* reserved */
7880 *((USHORT *)outData) = fidp->fid; outData += 2; /* fid */
7881 *((ULONG *)outData) = openAction; outData += 4;
7882 *((ULONG *)outData) = 0; outData += 4; /* EA error offset */
7883 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
7884 *((FILETIME *)outData) = ft; outData += 8; /* creation time */
7885 *((FILETIME *)outData) = ft; outData += 8; /* last access time */
7886 *((FILETIME *)outData) = ft; outData += 8; /* last write time */
7887 *((FILETIME *)outData) = ft; outData += 8; /* change time */
7888 *((ULONG *)outData) = smb_ExtAttributes(scp); outData += 4;
7889 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* alloc sz */
7890 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* EOF */
7891 *((USHORT *)outData) = 0; outData += 2; /* filetype */
7892 *((USHORT *)outData) = 0; outData += 2; /* dev state */
7893 *((USHORT *)outData) = ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
7894 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
7895 scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0);
7896 outData += 2; /* is a dir? */
7897 lock_ReleaseMutex(&scp->mx);
7900 parmOffset = 8*4 + 39;
7901 parmOffset += 1; /* pad to 4 */
7902 dataOffset = parmOffset + 104;
7906 /* Total Parameter Count */
7907 smb_SetSMBParmLong(outp, parmSlot, 101); parmSlot += 2;
7908 /* Total Data Count */
7909 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
7910 /* Parameter Count */
7911 smb_SetSMBParmLong(outp, parmSlot, 101); parmSlot += 2;
7912 /* Parameter Offset */
7913 smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
7914 /* Parameter Displacement */
7915 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
7917 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
7919 smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
7920 /* Data Displacement */
7921 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
7922 smb_SetSMBParmByte(outp, parmSlot, 0); /* Setup Count */
7923 smb_SetSMBDataLength(outp, 105);
7925 lock_ObtainMutex(&scp->mx);
7926 outData = smb_GetSMBData(outp, NULL);
7927 outData++; /* round to get to parmOffset */
7928 *outData = 0; outData++; /* oplock */
7929 *outData = 1; outData++; /* response type */
7930 *((USHORT *)outData) = fidp->fid; outData += 2; /* fid */
7931 *((ULONG *)outData) = openAction; outData += 4;
7932 *((ULONG *)outData) = 0; outData += 4; /* EA error offset */
7933 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
7934 *((FILETIME *)outData) = ft; outData += 8; /* creation time */
7935 *((FILETIME *)outData) = ft; outData += 8; /* last access time */
7936 *((FILETIME *)outData) = ft; outData += 8; /* last write time */
7937 *((FILETIME *)outData) = ft; outData += 8; /* change time */
7938 *((ULONG *)outData) = smb_ExtAttributes(scp); outData += 4;
7939 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* alloc sz */
7940 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* EOF */
7941 *((USHORT *)outData) = 0; outData += 2; /* filetype */
7942 *((USHORT *)outData) = 0; outData += 2; /* dev state */
7943 *((USHORT *)outData) = ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
7944 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
7945 scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0);
7946 outData += 1; /* is a dir? */
7947 memset(outData,0,24); outData += 24; /* Volume ID and file ID */
7948 *((ULONG *)outData) = 0x001f01ffL; outData += 4; /* Maxmimal access rights */
7949 *((ULONG *)outData) = 0; outData += 4; /* Guest Access rights */
7950 lock_ReleaseMutex(&scp->mx);
7953 lock_ObtainMutex(&scp->mx);
7954 if ((fidp->flags & SMB_FID_EXECUTABLE) &&
7955 LargeIntegerGreaterThanZero(fidp->scp->length) &&
7956 !(scp->flags & CM_SCACHEFLAG_PREFETCHING)) {
7957 cm_QueueBKGRequest(fidp->scp, cm_BkgPrefetch, 0, 0,
7958 fidp->scp->length.LowPart, fidp->scp->length.HighPart,
7961 lock_ReleaseMutex(&scp->mx);
7963 osi_Log1(smb_logp, "SMB NTTranCreate opening fid %d", fidp->fid);
7965 cm_ReleaseUser(userp);
7966 smb_ReleaseFID(fidp);
7968 /* free(realPathp); Can't free realPathp here because fidp->NTopen_wholepathp points there */
7969 /* leave scp held since we put it in fidp->scp */
7973 long smb_ReceiveNTTranNotifyChange(smb_vc_t *vcp, smb_packet_t *inp,
7976 smb_packet_t *savedPacketp;
7978 USHORT fid, watchtree;
7982 filter = smb_GetSMBParm(inp, 19) |
7983 (smb_GetSMBParm(inp, 20) << 16);
7984 fid = smb_GetSMBParm(inp, 21);
7985 watchtree = (smb_GetSMBParm(inp, 22) & 0xff) ? 1 : 0;
7987 fidp = smb_FindFID(vcp, fid, 0);
7989 osi_Log1(smb_logp, "ERROR: NotifyChange given invalid fid [%d]", fid);
7990 return CM_ERROR_BADFD;
7993 /* Create a copy of the Directory Watch Packet to use when sending the
7994 * notification if in the future a matching change is detected.
7996 savedPacketp = smb_CopyPacket(inp);
7998 if (savedPacketp->vcp)
7999 smb_ReleaseVC(savedPacketp->vcp);
8000 savedPacketp->vcp = vcp;
8002 /* Add the watch to the list of events to send notifications for */
8003 lock_ObtainMutex(&smb_Dir_Watch_Lock);
8004 savedPacketp->nextp = smb_Directory_Watches;
8005 smb_Directory_Watches = savedPacketp;
8006 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
8009 osi_Log3(smb_logp,"smb_ReceiveNTTranNotifyChange fidp 0x%p scp 0x%p file \"%s\"",
8010 fidp, scp, osi_LogSaveString(smb_logp, fidp->NTopen_wholepathp));
8011 osi_Log3(smb_logp, "Request for NotifyChange filter 0x%x fid %d wtree %d",
8012 filter, fid, watchtree);
8013 if (filter & FILE_NOTIFY_CHANGE_FILE_NAME)
8014 osi_Log0(smb_logp, " Notify Change File Name");
8015 if (filter & FILE_NOTIFY_CHANGE_DIR_NAME)
8016 osi_Log0(smb_logp, " Notify Change Directory Name");
8017 if (filter & FILE_NOTIFY_CHANGE_ATTRIBUTES)
8018 osi_Log0(smb_logp, " Notify Change Attributes");
8019 if (filter & FILE_NOTIFY_CHANGE_SIZE)
8020 osi_Log0(smb_logp, " Notify Change Size");
8021 if (filter & FILE_NOTIFY_CHANGE_LAST_WRITE)
8022 osi_Log0(smb_logp, " Notify Change Last Write");
8023 if (filter & FILE_NOTIFY_CHANGE_LAST_ACCESS)
8024 osi_Log0(smb_logp, " Notify Change Last Access");
8025 if (filter & FILE_NOTIFY_CHANGE_CREATION)
8026 osi_Log0(smb_logp, " Notify Change Creation");
8027 if (filter & FILE_NOTIFY_CHANGE_EA)
8028 osi_Log0(smb_logp, " Notify Change Extended Attributes");
8029 if (filter & FILE_NOTIFY_CHANGE_SECURITY)
8030 osi_Log0(smb_logp, " Notify Change Security");
8031 if (filter & FILE_NOTIFY_CHANGE_STREAM_NAME)
8032 osi_Log0(smb_logp, " Notify Change Stream Name");
8033 if (filter & FILE_NOTIFY_CHANGE_STREAM_SIZE)
8034 osi_Log0(smb_logp, " Notify Change Stream Size");
8035 if (filter & FILE_NOTIFY_CHANGE_STREAM_WRITE)
8036 osi_Log0(smb_logp, " Notify Change Stream Write");
8038 lock_ObtainMutex(&scp->mx);
8040 scp->flags |= CM_SCACHEFLAG_WATCHEDSUBTREE;
8042 scp->flags |= CM_SCACHEFLAG_WATCHED;
8043 lock_ReleaseMutex(&scp->mx);
8044 smb_ReleaseFID(fidp);
8046 outp->flags |= SMB_PACKETFLAG_NOSEND;
8050 unsigned char nullSecurityDesc[36] = {
8051 0x01, /* security descriptor revision */
8052 0x00, /* reserved, should be zero */
8053 0x00, 0x80, /* security descriptor control;
8054 * 0x8000 : self-relative format */
8055 0x14, 0x00, 0x00, 0x00, /* offset of owner SID */
8056 0x1c, 0x00, 0x00, 0x00, /* offset of group SID */
8057 0x00, 0x00, 0x00, 0x00, /* offset of DACL would go here */
8058 0x00, 0x00, 0x00, 0x00, /* offset of SACL would go here */
8059 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
8060 /* "null SID" owner SID */
8061 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
8062 /* "null SID" group SID */
8065 long smb_ReceiveNTTranQuerySecurityDesc(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
8067 int parmOffset, parmCount, dataOffset, dataCount;
8075 ULONG securityInformation;
8077 parmOffset = smb_GetSMBOffsetParm(inp, 11, 1)
8078 | (smb_GetSMBOffsetParm(inp, 12, 1) << 16);
8079 parmp = inp->data + parmOffset;
8080 sparmp = (USHORT *) parmp;
8081 lparmp = (ULONG *) parmp;
8084 securityInformation = lparmp[1];
8086 maxData = smb_GetSMBOffsetParm(inp, 7, 1)
8087 | (smb_GetSMBOffsetParm(inp, 8, 1) << 16);
8095 parmOffset = 8*4 + 39;
8096 parmOffset += 1; /* pad to 4 */
8098 dataOffset = parmOffset + parmCount;
8102 /* Total Parameter Count */
8103 smb_SetSMBParmLong(outp, parmSlot, parmCount); parmSlot += 2;
8104 /* Total Data Count */
8105 smb_SetSMBParmLong(outp, parmSlot, dataCount); parmSlot += 2;
8106 /* Parameter Count */
8107 smb_SetSMBParmLong(outp, parmSlot, parmCount); parmSlot += 2;
8108 /* Parameter Offset */
8109 smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
8110 /* Parameter Displacement */
8111 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8113 smb_SetSMBParmLong(outp, parmSlot, dataCount); parmSlot += 2;
8115 smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
8116 /* Data Displacement */
8117 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8118 smb_SetSMBParmByte(outp, parmSlot, 0); /* Setup Count */
8119 smb_SetSMBDataLength(outp, 1 + parmCount + dataCount);
8121 outData = smb_GetSMBData(outp, NULL);
8122 outData++; /* round to get to parmOffset */
8123 *((ULONG *)outData) = 36; outData += 4; /* length */
8125 if (maxData >= 36) {
8126 memcpy(outData, nullSecurityDesc, 36);
8130 return CM_ERROR_BUFFERTOOSMALL;
8133 long smb_ReceiveNTTransact(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
8135 unsigned short function;
8137 function = smb_GetSMBParm(inp, 18);
8139 osi_Log1(smb_logp, "SMB NT Transact function %d", function);
8141 /* We can handle long names */
8142 if (vcp->flags & SMB_VCFLAG_USENT)
8143 ((smb_t *)outp)->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
8147 return smb_ReceiveNTTranCreate(vcp, inp, outp);
8149 osi_Log0(smb_logp, "SMB NT Transact Ioctl - not implemented");
8152 osi_Log0(smb_logp, "SMB NT Transact SetSecurityDesc - not implemented");
8155 return smb_ReceiveNTTranNotifyChange(vcp, inp, outp);
8157 osi_Log0(smb_logp, "SMB NT Transact Rename - not implemented");
8160 return smb_ReceiveNTTranQuerySecurityDesc(vcp, inp, outp);
8162 return CM_ERROR_INVAL;
8166 * smb_NotifyChange -- find relevant change notification messages and
8169 * If we don't know the file name (i.e. a callback break), filename is
8170 * NULL, and we return a zero-length list.
8172 * At present there is not a single call to smb_NotifyChange that
8173 * has the isDirectParent parameter set to FALSE.
8175 void smb_NotifyChange(DWORD action, DWORD notifyFilter,
8176 cm_scache_t *dscp, char *filename, char *otherFilename,
8177 BOOL isDirectParent)
8179 smb_packet_t *watch, *lastWatch, *nextWatch;
8180 ULONG parmSlot, parmCount, parmOffset, dataOffset, nameLen;
8181 char *outData, *oldOutData;
8185 BOOL twoEntries = FALSE;
8186 ULONG otherNameLen, oldParmCount = 0;
8190 /* Get ready for rename within directory */
8191 if (action == FILE_ACTION_RENAMED_OLD_NAME && otherFilename != NULL) {
8193 otherAction = FILE_ACTION_RENAMED_NEW_NAME;
8196 osi_Log4(smb_logp,"in smb_NotifyChange for file [%s] dscp [%p] notification 0x%x parent %d",
8197 osi_LogSaveString(smb_logp,filename),dscp, notifyFilter, isDirectParent);
8199 osi_Log0(smb_logp," FILE_ACTION_NONE");
8200 if (action == FILE_ACTION_ADDED)
8201 osi_Log0(smb_logp," FILE_ACTION_ADDED");
8202 if (action == FILE_ACTION_REMOVED)
8203 osi_Log0(smb_logp," FILE_ACTION_REMOVED");
8204 if (action == FILE_ACTION_MODIFIED)
8205 osi_Log0(smb_logp," FILE_ACTION_MODIFIED");
8206 if (action == FILE_ACTION_RENAMED_OLD_NAME)
8207 osi_Log0(smb_logp," FILE_ACTION_RENAMED_OLD_NAME");
8208 if (action == FILE_ACTION_RENAMED_NEW_NAME)
8209 osi_Log0(smb_logp," FILE_ACTION_RENAMED_NEW_NAME");
8211 lock_ObtainMutex(&smb_Dir_Watch_Lock);
8212 watch = smb_Directory_Watches;
8214 filter = smb_GetSMBParm(watch, 19)
8215 | (smb_GetSMBParm(watch, 20) << 16);
8216 fid = smb_GetSMBParm(watch, 21);
8217 wtree = (smb_GetSMBParm(watch, 22) & 0xff) ? 1 : 0;
8219 maxLen = smb_GetSMBOffsetParm(watch, 5, 1)
8220 | (smb_GetSMBOffsetParm(watch, 6, 1) << 16);
8223 * Strange hack - bug in NT Client and NT Server that we must emulate?
8225 if ((filter == (FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME)) && wtree)
8226 filter |= FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_ATTRIBUTES;
8228 fidp = smb_FindFID(watch->vcp, fid, 0);
8230 osi_Log2(smb_logp," no fidp for fid[%d] in vcp 0x%p",fid, watch->vcp);
8232 watch = watch->nextp;
8235 if (fidp->scp != dscp
8236 || (filter & notifyFilter) == 0
8237 || (!isDirectParent && !wtree)) {
8238 osi_Log1(smb_logp," skipping fidp->scp[%x]", fidp->scp);
8239 smb_ReleaseFID(fidp);
8241 watch = watch->nextp;
8244 smb_ReleaseFID(fidp);
8247 "Sending Change Notification for fid %d filter 0x%x wtree %d file %s",
8248 fid, filter, wtree, osi_LogSaveString(smb_logp, filename));
8249 if (filter & FILE_NOTIFY_CHANGE_FILE_NAME)
8250 osi_Log0(smb_logp, " Notify Change File Name");
8251 if (filter & FILE_NOTIFY_CHANGE_DIR_NAME)
8252 osi_Log0(smb_logp, " Notify Change Directory Name");
8253 if (filter & FILE_NOTIFY_CHANGE_ATTRIBUTES)
8254 osi_Log0(smb_logp, " Notify Change Attributes");
8255 if (filter & FILE_NOTIFY_CHANGE_SIZE)
8256 osi_Log0(smb_logp, " Notify Change Size");
8257 if (filter & FILE_NOTIFY_CHANGE_LAST_WRITE)
8258 osi_Log0(smb_logp, " Notify Change Last Write");
8259 if (filter & FILE_NOTIFY_CHANGE_LAST_ACCESS)
8260 osi_Log0(smb_logp, " Notify Change Last Access");
8261 if (filter & FILE_NOTIFY_CHANGE_CREATION)
8262 osi_Log0(smb_logp, " Notify Change Creation");
8263 if (filter & FILE_NOTIFY_CHANGE_EA)
8264 osi_Log0(smb_logp, " Notify Change Extended Attributes");
8265 if (filter & FILE_NOTIFY_CHANGE_SECURITY)
8266 osi_Log0(smb_logp, " Notify Change Security");
8267 if (filter & FILE_NOTIFY_CHANGE_STREAM_NAME)
8268 osi_Log0(smb_logp, " Notify Change Stream Name");
8269 if (filter & FILE_NOTIFY_CHANGE_STREAM_SIZE)
8270 osi_Log0(smb_logp, " Notify Change Stream Size");
8271 if (filter & FILE_NOTIFY_CHANGE_STREAM_WRITE)
8272 osi_Log0(smb_logp, " Notify Change Stream Write");
8274 /* A watch can only be notified once. Remove it from the list */
8275 nextWatch = watch->nextp;
8276 if (watch == smb_Directory_Watches)
8277 smb_Directory_Watches = nextWatch;
8279 lastWatch->nextp = nextWatch;
8281 /* Turn off WATCHED flag in dscp */
8282 lock_ObtainMutex(&dscp->mx);
8284 dscp->flags &= ~CM_SCACHEFLAG_WATCHEDSUBTREE;
8286 dscp->flags &= ~CM_SCACHEFLAG_WATCHED;
8287 lock_ReleaseMutex(&dscp->mx);
8289 /* Convert to response packet */
8290 ((smb_t *) watch)->reb = SMB_FLAGS_SERVER_TO_CLIENT | SMB_FLAGS_CANONICAL_PATHNAMES;
8291 ((smb_t *) watch)->wct = 0;
8294 if (filename == NULL)
8297 nameLen = (ULONG)strlen(filename);
8298 parmCount = 3*4 + nameLen*2;
8299 parmCount = (parmCount + 3) & ~3; /* pad to 4 */
8301 otherNameLen = (ULONG)strlen(otherFilename);
8302 oldParmCount = parmCount;
8303 parmCount += 3*4 + otherNameLen*2;
8304 parmCount = (parmCount + 3) & ~3; /* pad to 4 */
8306 if (maxLen < parmCount)
8307 parmCount = 0; /* not enough room */
8309 parmOffset = 8*4 + 39;
8310 parmOffset += 1; /* pad to 4 */
8311 dataOffset = parmOffset + parmCount;
8315 /* Total Parameter Count */
8316 smb_SetSMBParmLong(watch, parmSlot, parmCount); parmSlot += 2;
8317 /* Total Data Count */
8318 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
8319 /* Parameter Count */
8320 smb_SetSMBParmLong(watch, parmSlot, parmCount); parmSlot += 2;
8321 /* Parameter Offset */
8322 smb_SetSMBParmLong(watch, parmSlot, parmOffset); parmSlot += 2;
8323 /* Parameter Displacement */
8324 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
8326 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
8328 smb_SetSMBParmLong(watch, parmSlot, dataOffset); parmSlot += 2;
8329 /* Data Displacement */
8330 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
8331 smb_SetSMBParmByte(watch, parmSlot, 0); /* Setup Count */
8332 smb_SetSMBDataLength(watch, parmCount + 1);
8334 if (parmCount != 0) {
8336 outData = smb_GetSMBData(watch, NULL);
8337 outData++; /* round to get to parmOffset */
8338 oldOutData = outData;
8339 *((DWORD *)outData) = oldParmCount; outData += 4;
8340 /* Next Entry Offset */
8341 *((DWORD *)outData) = action; outData += 4;
8343 *((DWORD *)outData) = nameLen*2; outData += 4;
8344 /* File Name Length */
8345 p = strdup(filename);
8346 if (smb_StoreAnsiFilenames)
8348 mbstowcs((WCHAR *)outData, p, nameLen);
8352 outData = oldOutData + oldParmCount;
8353 *((DWORD *)outData) = 0; outData += 4;
8354 /* Next Entry Offset */
8355 *((DWORD *)outData) = otherAction; outData += 4;
8357 *((DWORD *)outData) = otherNameLen*2;
8358 outData += 4; /* File Name Length */
8359 p = strdup(otherFilename);
8360 if (smb_StoreAnsiFilenames)
8362 mbstowcs((WCHAR *)outData, p, otherNameLen); /* File Name */
8368 * If filename is null, we don't know the cause of the
8369 * change notification. We return zero data (see above),
8370 * and set error code to NT_STATUS_NOTIFY_ENUM_DIR
8371 * (= 0x010C). We set the error code here by hand, without
8372 * modifying wct and bcc.
8374 if (filename == NULL) {
8375 ((smb_t *) watch)->rcls = 0x0C;
8376 ((smb_t *) watch)->reh = 0x01;
8377 ((smb_t *) watch)->errLow = 0;
8378 ((smb_t *) watch)->errHigh = 0;
8379 /* Set NT Status codes flag */
8380 ((smb_t *) watch)->flg2 |= SMB_FLAGS2_32BIT_STATUS;
8383 smb_SendPacket(watch->vcp, watch);
8384 smb_FreePacket(watch);
8387 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
8390 long smb_ReceiveNTCancel(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
8392 unsigned char *replyWctp;
8393 smb_packet_t *watch, *lastWatch;
8394 USHORT fid, watchtree;
8398 osi_Log0(smb_logp, "SMB3 receive NT cancel");
8400 lock_ObtainMutex(&smb_Dir_Watch_Lock);
8401 watch = smb_Directory_Watches;
8403 if (((smb_t *)watch)->uid == ((smb_t *)inp)->uid
8404 && ((smb_t *)watch)->pid == ((smb_t *)inp)->pid
8405 && ((smb_t *)watch)->mid == ((smb_t *)inp)->mid
8406 && ((smb_t *)watch)->tid == ((smb_t *)inp)->tid) {
8407 if (watch == smb_Directory_Watches)
8408 smb_Directory_Watches = watch->nextp;
8410 lastWatch->nextp = watch->nextp;
8411 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
8413 /* Turn off WATCHED flag in scp */
8414 fid = smb_GetSMBParm(watch, 21);
8415 watchtree = smb_GetSMBParm(watch, 22) & 0xffff;
8417 if (vcp != watch->vcp)
8418 osi_Log2(smb_logp, "smb_ReceiveNTCancel: vcp %x not equal to watch vcp %x",
8421 fidp = smb_FindFID(vcp, fid, 0);
8423 osi_Log3(smb_logp, "Cancelling change notification for fid %d wtree %d file %s",
8425 osi_LogSaveString(smb_logp, (fidp)?fidp->NTopen_wholepathp:""));
8428 osi_Log2(smb_logp,"smb_ReceiveNTCancel fidp 0x%p scp 0x%p", fidp, scp);
8429 lock_ObtainMutex(&scp->mx);
8431 scp->flags &= ~CM_SCACHEFLAG_WATCHEDSUBTREE;
8433 scp->flags &= ~CM_SCACHEFLAG_WATCHED;
8434 lock_ReleaseMutex(&scp->mx);
8435 smb_ReleaseFID(fidp);
8437 osi_Log2(smb_logp,"NTCancel unable to resolve fid [%d] in vcp[%x]", fid,vcp);
8440 /* assume STATUS32; return 0xC0000120 (CANCELED) */
8441 replyWctp = watch->wctp;
8445 ((smb_t *)watch)->rcls = 0x20;
8446 ((smb_t *)watch)->reh = 0x1;
8447 ((smb_t *)watch)->errLow = 0;
8448 ((smb_t *)watch)->errHigh = 0xC0;
8449 ((smb_t *)watch)->flg2 |= SMB_FLAGS2_32BIT_STATUS;
8450 smb_SendPacket(vcp, watch);
8451 smb_FreePacket(watch);
8455 watch = watch->nextp;
8457 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
8463 * NT rename also does hard links.
8466 #define RENAME_FLAG_MOVE_CLUSTER_INFORMATION 0x102
8467 #define RENAME_FLAG_HARD_LINK 0x103
8468 #define RENAME_FLAG_RENAME 0x104
8469 #define RENAME_FLAG_COPY 0x105
8471 long smb_ReceiveNTRename(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
8473 char *oldPathp, *newPathp;
8479 attrs = smb_GetSMBParm(inp, 0);
8480 rename_type = smb_GetSMBParm(inp, 1);
8482 if (rename_type != RENAME_FLAG_RENAME && rename_type != RENAME_FLAG_HARD_LINK) {
8483 osi_Log1(smb_logp, "NTRename invalid rename_type [%x]", rename_type);
8484 return CM_ERROR_NOACCESS;
8487 tp = smb_GetSMBData(inp, NULL);
8488 oldPathp = smb_ParseASCIIBlock(tp, &tp);
8489 if (smb_StoreAnsiFilenames)
8490 OemToChar(oldPathp,oldPathp);
8491 newPathp = smb_ParseASCIIBlock(tp, &tp);
8492 if (smb_StoreAnsiFilenames)
8493 OemToChar(newPathp,newPathp);
8495 osi_Log3(smb_logp, "NTRename for [%s]->[%s] type [%s]",
8496 osi_LogSaveString(smb_logp, oldPathp),
8497 osi_LogSaveString(smb_logp, newPathp),
8498 ((rename_type==RENAME_FLAG_RENAME)?"rename":"hardlink"));
8500 if (rename_type == RENAME_FLAG_RENAME) {
8501 code = smb_Rename(vcp,inp,oldPathp,newPathp,attrs);
8502 } else { /* RENAME_FLAG_HARD_LINK */
8503 code = smb_Link(vcp,inp,oldPathp,newPathp);
8510 lock_InitializeMutex(&smb_Dir_Watch_Lock, "Directory Watch List Lock");
8513 cm_user_t *smb_FindCMUserByName(char *usern, char *machine, afs_uint32 flags)
8515 smb_username_t *unp;
8518 unp = smb_FindUserByName(usern, machine, flags);
8520 lock_ObtainMutex(&unp->mx);
8521 unp->userp = cm_NewUser();
8522 lock_ReleaseMutex(&unp->mx);
8523 osi_Log2(smb_logp,"smb_FindCMUserByName New user name[%s] machine[%s]",osi_LogSaveString(smb_logp,usern),osi_LogSaveString(smb_logp,machine));
8525 osi_Log2(smb_logp,"smb_FindCMUserByName Not found name[%s] machine[%s]",osi_LogSaveString(smb_logp,usern),osi_LogSaveString(smb_logp,machine));
8529 smb_ReleaseUsername(unp);