2 * Copyright 2000, International Business Machines Corporation and others.
5 * This software has been released under the terms of the IBM Public
6 * License. For details, see the LICENSE file in the top-level source
7 * directory or online at http://www.openafs.org/dl/license10.html
10 #include <afs/param.h>
16 #define SECURITY_WIN32
28 #include <WINNT\afsreg.h>
32 extern osi_hyper_t hzero;
34 smb_packet_t *smb_Directory_Watches = NULL;
35 osi_mutex_t smb_Dir_Watch_Lock;
37 smb_tran2Dispatch_t smb_tran2DispatchTable[SMB_TRAN2_NOPCODES];
39 smb_tran2Dispatch_t smb_rapDispatchTable[SMB_RAP_NOPCODES];
41 /* protected by the smb_globalLock */
42 smb_tran2Packet_t *smb_tran2AssemblyQueuep;
44 /* retrieve a held reference to a user structure corresponding to an incoming
46 cm_user_t *smb_GetTran2User(smb_vc_t *vcp, smb_tran2Packet_t *inp)
51 uidp = smb_FindUID(vcp, inp->uid, 0);
52 if (!uidp) return NULL;
54 lock_ObtainMutex(&uidp->mx);
56 up = uidp->unp->userp;
59 lock_ReleaseMutex(&uidp->mx);
67 * Return extended attributes.
68 * Right now, we aren't using any of the "new" bits, so this looks exactly
69 * like smb_Attributes() (see smb.c).
71 unsigned long smb_ExtAttributes(cm_scache_t *scp)
75 if (scp->fileType == CM_SCACHETYPE_DIRECTORY ||
76 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
77 scp->fileType == CM_SCACHETYPE_INVALID)
79 attrs = SMB_ATTR_DIRECTORY;
80 #ifdef SPECIAL_FOLDERS
81 attrs |= SMB_ATTR_SYSTEM; /* FILE_ATTRIBUTE_SYSTEM */
82 #endif /* SPECIAL_FOLDERS */
83 } else if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
84 attrs = SMB_ATTR_DIRECTORY | SMB_ATTR_SPARSE_FILE;
88 * We used to mark a file RO if it was in an RO volume, but that
89 * turns out to be impolitic in NT. See defect 10007.
92 if ((scp->unixModeBits & 0222) == 0 || (scp->flags & CM_SCACHEFLAG_RO))
93 attrs |= SMB_ATTR_READONLY; /* Read-only */
95 if ((scp->unixModeBits & 0222) == 0)
96 attrs |= SMB_ATTR_READONLY; /* Read-only */
100 attrs = SMB_ATTR_NORMAL; /* FILE_ATTRIBUTE_NORMAL */
105 int smb_V3IsStarMask(char *maskp)
109 while (tc = *maskp++)
110 if (tc == '?' || tc == '*' || tc == '<' || tc == '>')
115 unsigned char *smb_ParseString(unsigned char *inp, char **chainpp)
118 /* skip over null-terminated string */
119 *chainpp = inp + strlen(inp) + 1;
124 void OutputDebugF(char * format, ...) {
129 va_start( args, format );
130 len = _vscprintf( format, args ) // _vscprintf doesn't count
131 + 3; // terminating '\0' + '\n'
132 buffer = malloc( len * sizeof(char) );
133 vsprintf( buffer, format, args );
134 osi_Log0(smb_logp, osi_LogSaveString(smb_logp, buffer));
135 strcat(buffer, "\n");
136 OutputDebugString(buffer);
140 void OutputDebugHexDump(unsigned char * buffer, int len) {
143 static char tr[16] = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
145 OutputDebugF("Hexdump length [%d]",len);
147 for (i=0;i<len;i++) {
150 osi_Log0(smb_logp, osi_LogSaveString(smb_logp, buf));
152 OutputDebugString(buf);
154 sprintf(buf,"%5x",i);
155 memset(buf+5,' ',80);
160 j = j*3 + 7 + ((j>7)?1:0);
163 buf[j] = tr[k / 16]; buf[j+1] = tr[k % 16];
166 j = j + 56 + ((j>7)?1:0);
168 buf[j] = (k>32 && k<127)?k:'.';
171 osi_Log0(smb_logp, osi_LogSaveString(smb_logp, buf));
173 OutputDebugString(buf);
177 #define SMB_EXT_SEC_PACKAGE_NAME "Negotiate"
179 void smb_NegotiateExtendedSecurity(void ** secBlob, int * secBlobLength) {
180 SECURITY_STATUS status, istatus;
181 CredHandle creds = {0,0};
183 SecBufferDesc secOut;
191 OutputDebugF("Negotiating Extended Security");
193 status = AcquireCredentialsHandle( NULL,
194 SMB_EXT_SEC_PACKAGE_NAME,
203 if (status != SEC_E_OK) {
204 /* Really bad. We return an empty security blob */
205 OutputDebugF("AcquireCredentialsHandle failed with %lX", status);
210 secOut.pBuffers = &secTok;
211 secOut.ulVersion = SECBUFFER_VERSION;
213 secTok.BufferType = SECBUFFER_TOKEN;
215 secTok.pvBuffer = NULL;
217 ctx.dwLower = ctx.dwUpper = 0;
219 status = AcceptSecurityContext( &creds,
222 ASC_REQ_CONNECTION | ASC_REQ_EXTENDED_ERROR | ASC_REQ_ALLOCATE_MEMORY,
223 SECURITY_NETWORK_DREP,
230 if (status == SEC_I_COMPLETE_NEEDED || status == SEC_I_COMPLETE_AND_CONTINUE) {
231 OutputDebugF("Completing token...");
232 istatus = CompleteAuthToken(&ctx, &secOut);
233 if ( istatus != SEC_E_OK )
234 OutputDebugF("Token completion failed: %x", istatus);
237 if (status == SEC_I_COMPLETE_AND_CONTINUE || status == SEC_I_CONTINUE_NEEDED) {
238 if (secTok.pvBuffer) {
239 *secBlobLength = secTok.cbBuffer;
240 *secBlob = malloc( secTok.cbBuffer );
241 memcpy(*secBlob, secTok.pvBuffer, secTok.cbBuffer );
244 if ( status != SEC_E_OK )
245 OutputDebugF("AcceptSecurityContext status != CONTINUE %lX", status);
248 /* Discard partial security context */
249 DeleteSecurityContext(&ctx);
251 if (secTok.pvBuffer) FreeContextBuffer( secTok.pvBuffer );
253 /* Discard credentials handle. We'll reacquire one when we get the session setup X */
254 FreeCredentialsHandle(&creds);
260 struct smb_ext_context {
267 long smb_AuthenticateUserExt(smb_vc_t * vcp, char * usern, char * secBlobIn, int secBlobInLength, char ** secBlobOut, int * secBlobOutLength) {
268 SECURITY_STATUS status, istatus;
272 SecBufferDesc secBufIn;
274 SecBufferDesc secBufOut;
277 struct smb_ext_context * secCtx = NULL;
278 struct smb_ext_context * newSecCtx = NULL;
279 void * assembledBlob = NULL;
280 int assembledBlobLength = 0;
283 OutputDebugF("In smb_AuthenticateUserExt");
286 *secBlobOutLength = 0;
288 if (vcp->flags & SMB_VCFLAG_AUTH_IN_PROGRESS) {
289 secCtx = vcp->secCtx;
290 lock_ObtainMutex(&vcp->mx);
291 vcp->flags &= ~SMB_VCFLAG_AUTH_IN_PROGRESS;
293 lock_ReleaseMutex(&vcp->mx);
297 OutputDebugF("Received incoming token:");
298 OutputDebugHexDump(secBlobIn,secBlobInLength);
302 OutputDebugF("Continuing with existing context.");
303 creds = secCtx->creds;
306 if (secCtx->partialToken) {
307 assembledBlobLength = secCtx->partialTokenLen + secBlobInLength;
308 assembledBlob = malloc(assembledBlobLength);
309 memcpy(assembledBlob,secCtx->partialToken, secCtx->partialTokenLen);
310 memcpy(((BYTE *)assembledBlob) + secCtx->partialTokenLen, secBlobIn, secBlobInLength);
313 status = AcquireCredentialsHandle( NULL,
314 SMB_EXT_SEC_PACKAGE_NAME,
323 if (status != SEC_E_OK) {
324 OutputDebugF("Can't acquire Credentials handle [%lX]", status);
325 code = CM_ERROR_BADPASSWORD; /* means "try again when I'm sober" */
333 secBufIn.cBuffers = 1;
334 secBufIn.pBuffers = &secTokIn;
335 secBufIn.ulVersion = SECBUFFER_VERSION;
337 secTokIn.BufferType = SECBUFFER_TOKEN;
339 secTokIn.cbBuffer = assembledBlobLength;
340 secTokIn.pvBuffer = assembledBlob;
342 secTokIn.cbBuffer = secBlobInLength;
343 secTokIn.pvBuffer = secBlobIn;
346 secBufOut.cBuffers = 1;
347 secBufOut.pBuffers = &secTokOut;
348 secBufOut.ulVersion = SECBUFFER_VERSION;
350 secTokOut.BufferType = SECBUFFER_TOKEN;
351 secTokOut.cbBuffer = 0;
352 secTokOut.pvBuffer = NULL;
354 status = AcceptSecurityContext( &creds,
355 ((secCtx)?&ctx:NULL),
357 ASC_REQ_CONNECTION | ASC_REQ_EXTENDED_ERROR | ASC_REQ_ALLOCATE_MEMORY,
358 SECURITY_NETWORK_DREP,
365 if (status == SEC_I_COMPLETE_NEEDED || status == SEC_I_COMPLETE_AND_CONTINUE) {
366 OutputDebugF("Completing token...");
367 istatus = CompleteAuthToken(&ctx, &secBufOut);
368 if ( istatus != SEC_E_OK )
369 OutputDebugF("Token completion failed: %lX", istatus);
372 if (status == SEC_I_COMPLETE_AND_CONTINUE || status == SEC_I_CONTINUE_NEEDED) {
373 OutputDebugF("Continue needed");
375 newSecCtx = malloc(sizeof(*newSecCtx));
377 newSecCtx->creds = creds;
378 newSecCtx->ctx = ctx;
379 newSecCtx->partialToken = NULL;
380 newSecCtx->partialTokenLen = 0;
382 lock_ObtainMutex( &vcp->mx );
383 vcp->flags |= SMB_VCFLAG_AUTH_IN_PROGRESS;
384 vcp->secCtx = newSecCtx;
385 lock_ReleaseMutex( &vcp->mx );
387 code = CM_ERROR_GSSCONTINUE;
390 if ((status == SEC_I_COMPLETE_NEEDED || status == SEC_E_OK ||
391 status == SEC_I_COMPLETE_AND_CONTINUE || status == SEC_I_CONTINUE_NEEDED) &&
392 secTokOut.pvBuffer) {
393 OutputDebugF("Need to send token back to client");
395 *secBlobOutLength = secTokOut.cbBuffer;
396 *secBlobOut = malloc(secTokOut.cbBuffer);
397 memcpy(*secBlobOut, secTokOut.pvBuffer, secTokOut.cbBuffer);
399 OutputDebugF("Outgoing token:");
400 OutputDebugHexDump(*secBlobOut,*secBlobOutLength);
401 } else if (status == SEC_E_INCOMPLETE_MESSAGE) {
402 OutputDebugF("Incomplete message");
404 newSecCtx = malloc(sizeof(*newSecCtx));
406 newSecCtx->creds = creds;
407 newSecCtx->ctx = ctx;
408 newSecCtx->partialToken = malloc(secTokOut.cbBuffer);
409 memcpy(newSecCtx->partialToken, secTokOut.pvBuffer, secTokOut.cbBuffer);
410 newSecCtx->partialTokenLen = secTokOut.cbBuffer;
412 lock_ObtainMutex( &vcp->mx );
413 vcp->flags |= SMB_VCFLAG_AUTH_IN_PROGRESS;
414 vcp->secCtx = newSecCtx;
415 lock_ReleaseMutex( &vcp->mx );
417 code = CM_ERROR_GSSCONTINUE;
420 if (status == SEC_E_OK || status == SEC_I_COMPLETE_NEEDED) {
422 SecPkgContext_Names names;
424 OutputDebugF("Authentication completed");
425 OutputDebugF("Returned flags : [%lX]", flags);
427 if (!QueryContextAttributes(&ctx, SECPKG_ATTR_NAMES, &names)) {
428 OutputDebugF("Received name [%s]", names.sUserName);
429 strcpy(usern, names.sUserName);
430 strlwr(usern); /* in tandem with smb_GetNormalizedUsername */
431 FreeContextBuffer(names.sUserName);
433 /* Force the user to retry if the context is invalid */
434 OutputDebugF("QueryContextAttributes Names failed [%x]", GetLastError());
435 code = CM_ERROR_BADPASSWORD;
439 case SEC_E_INVALID_TOKEN:
440 OutputDebugF("Returning bad password :: INVALID_TOKEN");
442 case SEC_E_INVALID_HANDLE:
443 OutputDebugF("Returning bad password :: INVALID_HANDLE");
445 case SEC_E_LOGON_DENIED:
446 OutputDebugF("Returning bad password :: LOGON_DENIED");
448 case SEC_E_UNKNOWN_CREDENTIALS:
449 OutputDebugF("Returning bad password :: UNKNOWN_CREDENTIALS");
451 case SEC_E_NO_CREDENTIALS:
452 OutputDebugF("Returning bad password :: NO_CREDENTIALS");
454 case SEC_E_CONTEXT_EXPIRED:
455 OutputDebugF("Returning bad password :: CONTEXT_EXPIRED");
457 case SEC_E_INCOMPLETE_CREDENTIALS:
458 OutputDebugF("Returning bad password :: INCOMPLETE_CREDENTIALS");
460 case SEC_E_WRONG_PRINCIPAL:
461 OutputDebugF("Returning bad password :: WRONG_PRINCIPAL");
463 case SEC_E_TIME_SKEW:
464 OutputDebugF("Returning bad password :: TIME_SKEW");
467 OutputDebugF("Returning bad password :: Status == %lX", status);
469 code = CM_ERROR_BADPASSWORD;
473 if (secCtx->partialToken) free(secCtx->partialToken);
481 if (secTokOut.pvBuffer)
482 FreeContextBuffer(secTokOut.pvBuffer);
484 if (code != CM_ERROR_GSSCONTINUE) {
485 DeleteSecurityContext(&ctx);
486 FreeCredentialsHandle(&creds);
494 #define P_RESP_LEN 128
496 /* LsaLogonUser expects input parameters to be in a contiguous block of memory.
497 So put stuff in a struct. */
498 struct Lm20AuthBlob {
499 MSV1_0_LM20_LOGON lmlogon;
500 BYTE ciResponse[P_RESP_LEN]; /* Unicode representation */
501 BYTE csResponse[P_RESP_LEN]; /* ANSI representation */
502 WCHAR accountNameW[P_LEN];
503 WCHAR primaryDomainW[P_LEN];
504 WCHAR workstationW[MAX_COMPUTERNAME_LENGTH + 1];
505 TOKEN_GROUPS tgroups;
506 TOKEN_SOURCE tsource;
509 long smb_AuthenticateUserLM(smb_vc_t *vcp, char * accountName, char * primaryDomain, char * ciPwd, unsigned ciPwdLength, char * csPwd, unsigned csPwdLength)
512 struct Lm20AuthBlob lmAuth;
513 PMSV1_0_LM20_LOGON_PROFILE lmprofilep;
514 QUOTA_LIMITS quotaLimits;
516 ULONG lmprofilepSize;
520 OutputDebugF("In smb_AuthenticateUser for user [%s] domain [%s]", accountName, primaryDomain);
521 OutputDebugF("ciPwdLength is %d and csPwdLength is %d", ciPwdLength, csPwdLength);
523 if (ciPwdLength > P_RESP_LEN || csPwdLength > P_RESP_LEN) {
524 OutputDebugF("ciPwdLength or csPwdLength is too long");
525 return CM_ERROR_BADPASSWORD;
528 memset(&lmAuth,0,sizeof(lmAuth));
530 lmAuth.lmlogon.MessageType = MsV1_0NetworkLogon;
532 lmAuth.lmlogon.LogonDomainName.Buffer = lmAuth.primaryDomainW;
533 mbstowcs(lmAuth.primaryDomainW, primaryDomain, P_LEN);
534 lmAuth.lmlogon.LogonDomainName.Length = wcslen(lmAuth.primaryDomainW) * sizeof(WCHAR);
535 lmAuth.lmlogon.LogonDomainName.MaximumLength = P_LEN * sizeof(WCHAR);
537 lmAuth.lmlogon.UserName.Buffer = lmAuth.accountNameW;
538 mbstowcs(lmAuth.accountNameW, accountName, P_LEN);
539 lmAuth.lmlogon.UserName.Length = wcslen(lmAuth.accountNameW) * sizeof(WCHAR);
540 lmAuth.lmlogon.UserName.MaximumLength = P_LEN * sizeof(WCHAR);
542 lmAuth.lmlogon.Workstation.Buffer = lmAuth.workstationW;
543 lmAuth.lmlogon.Workstation.MaximumLength = (MAX_COMPUTERNAME_LENGTH + 1) * sizeof(WCHAR);
544 size = MAX_COMPUTERNAME_LENGTH + 1;
545 GetComputerNameW(lmAuth.workstationW, &size);
546 lmAuth.lmlogon.Workstation.Length = wcslen(lmAuth.workstationW) * sizeof(WCHAR);
548 memcpy(lmAuth.lmlogon.ChallengeToClient, vcp->encKey, MSV1_0_CHALLENGE_LENGTH);
550 lmAuth.lmlogon.CaseInsensitiveChallengeResponse.Buffer = lmAuth.ciResponse;
551 lmAuth.lmlogon.CaseInsensitiveChallengeResponse.Length = ciPwdLength;
552 lmAuth.lmlogon.CaseInsensitiveChallengeResponse.MaximumLength = P_RESP_LEN;
553 memcpy(lmAuth.ciResponse, ciPwd, ciPwdLength);
555 lmAuth.lmlogon.CaseSensitiveChallengeResponse.Buffer = lmAuth.csResponse;
556 lmAuth.lmlogon.CaseSensitiveChallengeResponse.Length = csPwdLength;
557 lmAuth.lmlogon.CaseSensitiveChallengeResponse.MaximumLength = P_RESP_LEN;
558 memcpy(lmAuth.csResponse, csPwd, csPwdLength);
560 lmAuth.lmlogon.ParameterControl = 0;
562 lmAuth.tgroups.GroupCount = 0;
563 lmAuth.tgroups.Groups[0].Sid = NULL;
564 lmAuth.tgroups.Groups[0].Attributes = 0;
566 lmAuth.tsource.SourceIdentifier.HighPart = 0;
567 lmAuth.tsource.SourceIdentifier.LowPart = (DWORD) vcp;
568 strcpy(lmAuth.tsource.SourceName,"OpenAFS"); /* 8 char limit */
570 nts = LsaLogonUser( smb_lsaHandle,
585 if (nts != STATUS_SUCCESS || ntsEx != STATUS_SUCCESS)
586 osi_Log2(smb_logp,"LsaLogonUser failure: nts %u ntsEx %u",
589 OutputDebugF("Return from LsaLogonUser is 0x%lX", nts);
590 OutputDebugF("Extended status is 0x%lX", ntsEx);
592 if (nts == ERROR_SUCCESS) {
594 LsaFreeReturnBuffer(lmprofilep);
595 CloseHandle(lmToken);
599 if (nts == 0xC000015BL)
600 return CM_ERROR_BADLOGONTYPE;
601 else /* our catchall is a bad password though we could be more specific */
602 return CM_ERROR_BADPASSWORD;
606 /* The buffer pointed to by usern is assumed to be at least SMB_MAX_USERNAME_LENGTH bytes */
607 long smb_GetNormalizedUsername(char * usern, const char * accountName, const char * domainName)
612 /* check if we have sane input */
613 if ((strlen(accountName) + strlen(domainName) + 1) > SMB_MAX_USERNAME_LENGTH)
616 /* we could get : [accountName][domainName]
622 atsign = strchr(accountName, '@');
624 if (atsign) /* [user@domain][] -> [user@domain][domain] */
629 /* if for some reason the client doesn't know what domain to use,
630 it will either return an empty string or a '?' */
631 if (!domain[0] || domain[0] == '?')
632 /* Empty domains and empty usernames are usually sent from tokenless contexts.
633 This way such logins will get an empty username (easy to check). I don't know
634 when a non-empty username would be supplied with an anonymous domain, but *shrug* */
635 strcpy(usern,accountName);
637 /* TODO: what about WIN.MIT.EDU\user vs. WIN\user? */
638 strcpy(usern,domain);
641 strncat(usern,accountName,atsign - accountName);
643 strcat(usern,accountName);
651 /* When using SMB auth, all SMB sessions have to pass through here
652 * first to authenticate the user.
654 * Caveat: If not using SMB auth, the protocol does not require
655 * sending a session setup packet, which means that we can't rely on a
656 * UID in subsequent packets. Though in practice we get one anyway.
658 long smb_ReceiveV3SessionSetupX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
662 unsigned short newUid;
663 unsigned long caps = 0;
668 char usern[SMB_MAX_USERNAME_LENGTH];
669 char *secBlobOut = NULL;
670 int secBlobOutLength = 0;
672 /* Check for bad conns */
673 if (vcp->flags & SMB_VCFLAG_REMOTECONN)
674 return CM_ERROR_REMOTECONN;
676 if (vcp->flags & SMB_VCFLAG_USENT) {
677 if (smb_authType == SMB_AUTH_EXTENDED) {
678 /* extended authentication */
682 OutputDebugF("NT Session Setup: Extended");
684 if (!(vcp->flags & SMB_VCFLAG_SESSX_RCVD)) {
685 caps = smb_GetSMBParm(inp,10) | (((unsigned long) smb_GetSMBParm(inp,11)) << 16);
688 secBlobInLength = smb_GetSMBParm(inp, 7);
689 secBlobIn = smb_GetSMBData(inp, NULL);
691 code = smb_AuthenticateUserExt(vcp, usern, secBlobIn, secBlobInLength, &secBlobOut, &secBlobOutLength);
693 if (code == CM_ERROR_GSSCONTINUE) {
694 smb_SetSMBParm(outp, 2, 0);
695 smb_SetSMBParm(outp, 3, secBlobOutLength);
696 smb_SetSMBDataLength(outp, secBlobOutLength + smb_ServerOSLength + smb_ServerLanManagerLength + smb_ServerDomainNameLength);
697 tp = smb_GetSMBData(outp, NULL);
698 if (secBlobOutLength) {
699 memcpy(tp, secBlobOut, secBlobOutLength);
701 tp += secBlobOutLength;
703 memcpy(tp,smb_ServerOS,smb_ServerOSLength);
704 tp += smb_ServerOSLength;
705 memcpy(tp,smb_ServerLanManager,smb_ServerLanManagerLength);
706 tp += smb_ServerLanManagerLength;
707 memcpy(tp,smb_ServerDomainName,smb_ServerDomainNameLength);
708 tp += smb_ServerDomainNameLength;
711 /* TODO: handle return code and continue auth. Also free secBlobOut if applicable. */
713 unsigned ciPwdLength, csPwdLength;
719 if (smb_authType == SMB_AUTH_NTLM)
720 OutputDebugF("NT Session Setup: NTLM");
722 OutputDebugF("NT Session Setup: None");
724 /* TODO: parse for extended auth as well */
725 ciPwdLength = smb_GetSMBParm(inp, 7); /* case insensitive password length */
726 csPwdLength = smb_GetSMBParm(inp, 8); /* case sensitive password length */
728 tp = smb_GetSMBData(inp, &datalen);
730 OutputDebugF("Session packet data size [%d]",datalen);
737 accountName = smb_ParseString(tp, &tp);
738 primaryDomain = smb_ParseString(tp, NULL);
740 OutputDebugF("Account Name: %s",accountName);
741 OutputDebugF("Primary Domain: %s", primaryDomain);
742 OutputDebugF("Case Sensitive Password: %s", csPwd && csPwd[0] ? "yes" : "no");
743 OutputDebugF("Case Insensitive Password: %s", ciPwd && ciPwd[0] ? "yes" : "no");
745 if (smb_GetNormalizedUsername(usern, accountName, primaryDomain)) {
746 /* shouldn't happen */
747 code = CM_ERROR_BADSMB;
748 goto after_read_packet;
751 /* capabilities are only valid for first session packet */
752 if (!(vcp->flags & SMB_VCFLAG_SESSX_RCVD)) {
753 caps = smb_GetSMBParm(inp, 11) | (((unsigned long)smb_GetSMBParm(inp, 12)) << 16);
756 if (smb_authType == SMB_AUTH_NTLM) {
757 code = smb_AuthenticateUserLM(vcp, accountName, primaryDomain, ciPwd, ciPwdLength, csPwd, csPwdLength);
759 OutputDebugF("LM authentication failed [%d]", code);
761 OutputDebugF("LM authentication succeeded");
765 unsigned ciPwdLength;
770 switch ( smb_authType ) {
771 case SMB_AUTH_EXTENDED:
772 OutputDebugF("V3 Session Setup: Extended");
775 OutputDebugF("V3 Session Setup: NTLM");
778 OutputDebugF("V3 Session Setup: None");
780 ciPwdLength = smb_GetSMBParm(inp, 7);
781 tp = smb_GetSMBData(inp, NULL);
785 accountName = smb_ParseString(tp, &tp);
786 primaryDomain = smb_ParseString(tp, NULL);
788 OutputDebugF("Account Name: %s",accountName);
789 OutputDebugF("Primary Domain: %s", primaryDomain);
790 OutputDebugF("Case Insensitive Password: %s", ciPwd && ciPwd[0] ? "yes" : "no");
792 if ( smb_GetNormalizedUsername(usern, accountName, primaryDomain)) {
793 /* shouldn't happen */
794 code = CM_ERROR_BADSMB;
795 goto after_read_packet;
798 /* even if we wanted extended auth, if we only negotiated V3, we have to fallback
801 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
802 code = smb_AuthenticateUserLM(vcp,accountName,primaryDomain,ciPwd,ciPwdLength,"",0);
804 OutputDebugF("LM authentication failed [%d]", code);
806 OutputDebugF("LM authentication succeeded");
811 /* note down that we received a session setup X and set the capabilities flag */
812 if (!(vcp->flags & SMB_VCFLAG_SESSX_RCVD)) {
813 lock_ObtainMutex(&vcp->mx);
814 vcp->flags |= SMB_VCFLAG_SESSX_RCVD;
815 /* for the moment we can only deal with NTSTATUS */
816 if (caps & NTNEGOTIATE_CAPABILITY_NTSTATUS) {
817 vcp->flags |= SMB_VCFLAG_STATUS32;
819 lock_ReleaseMutex(&vcp->mx);
822 /* code would be non-zero if there was an authentication failure.
823 Ideally we would like to invalidate the uid for this session or break
824 early to avoid accidently stealing someone else's tokens. */
830 OutputDebugF("Received username=[%s]", usern);
832 /* On Windows 2000, this function appears to be called more often than
833 it is expected to be called. This resulted in multiple smb_user_t
834 records existing all for the same user session which results in all
835 of the users tokens disappearing.
837 To avoid this problem, we look for an existing smb_user_t record
838 based on the users name, and use that one if we find it.
841 uidp = smb_FindUserByNameThisSession(vcp, usern);
842 if (uidp) { /* already there, so don't create a new one */
845 newUid = (unsigned short)uidp->userID; /* For some reason these are different types!*/
846 osi_LogEvent("AFS smb_ReceiveV3SessionSetupX",NULL,"FindUserByName:Lana[%d],lsn[%d],userid[%d],name[%s]",vcp->lana,vcp->lsn,newUid,osi_LogSaveString(smb_logp, usern));
847 osi_Log3(smb_logp,"smb_ReceiveV3SessionSetupX FindUserByName:Lana[%d],lsn[%d],userid[%d]",vcp->lana,vcp->lsn,newUid);
848 smb_ReleaseUID(uidp);
851 /* do a global search for the username/machine name pair */
852 unp = smb_FindUserByName(usern, vcp->rname, SMB_FLAG_CREATE);
854 /* Create a new UID and cm_user_t structure */
857 userp = cm_NewUser();
858 lock_ObtainMutex(&vcp->mx);
859 if (!vcp->uidCounter)
860 vcp->uidCounter++; /* handle unlikely wraparounds */
861 newUid = (strlen(usern)==0)?0:vcp->uidCounter++;
862 lock_ReleaseMutex(&vcp->mx);
864 /* Create a new smb_user_t structure and connect them up */
865 lock_ObtainMutex(&unp->mx);
867 lock_ReleaseMutex(&unp->mx);
869 uidp = smb_FindUID(vcp, newUid, SMB_FLAG_CREATE);
870 lock_ObtainMutex(&uidp->mx);
872 osi_LogEvent("AFS smb_ReceiveV3SessionSetupX",NULL,"MakeNewUser:VCP[%x],Lana[%d],lsn[%d],userid[%d],TicketKTCName[%s]",(int)vcp,vcp->lana,vcp->lsn,newUid,osi_LogSaveString(smb_logp, usern));
873 osi_Log4(smb_logp,"smb_ReceiveV3SessionSetupX MakeNewUser:VCP[%x],Lana[%d],lsn[%d],userid[%d]",vcp,vcp->lana,vcp->lsn,newUid);
874 lock_ReleaseMutex(&uidp->mx);
875 smb_ReleaseUID(uidp);
878 /* Return UID to the client */
879 ((smb_t *)outp)->uid = newUid;
880 /* Also to the next chained message */
881 ((smb_t *)inp)->uid = newUid;
883 osi_Log3(smb_logp, "SMB3 session setup name %s creating ID %d%s",
884 osi_LogSaveString(smb_logp, usern), newUid, osi_LogSaveString(smb_logp, s1));
886 smb_SetSMBParm(outp, 2, 0);
888 if (vcp->flags & SMB_VCFLAG_USENT) {
889 if (smb_authType == SMB_AUTH_EXTENDED) {
890 smb_SetSMBParm(outp, 3, secBlobOutLength);
891 smb_SetSMBDataLength(outp, secBlobOutLength + smb_ServerOSLength + smb_ServerLanManagerLength + smb_ServerDomainNameLength);
892 tp = smb_GetSMBData(outp, NULL);
893 if (secBlobOutLength) {
894 memcpy(tp, secBlobOut, secBlobOutLength);
896 tp += secBlobOutLength;
898 memcpy(tp,smb_ServerOS,smb_ServerOSLength);
899 tp += smb_ServerOSLength;
900 memcpy(tp,smb_ServerLanManager,smb_ServerLanManagerLength);
901 tp += smb_ServerLanManagerLength;
902 memcpy(tp,smb_ServerDomainName,smb_ServerDomainNameLength);
903 tp += smb_ServerDomainNameLength;
905 smb_SetSMBDataLength(outp, 0);
908 if (smb_authType == SMB_AUTH_EXTENDED) {
909 smb_SetSMBDataLength(outp, smb_ServerOSLength + smb_ServerLanManagerLength + smb_ServerDomainNameLength);
910 tp = smb_GetSMBData(outp, NULL);
911 memcpy(tp,smb_ServerOS,smb_ServerOSLength);
912 tp += smb_ServerOSLength;
913 memcpy(tp,smb_ServerLanManager,smb_ServerLanManagerLength);
914 tp += smb_ServerLanManagerLength;
915 memcpy(tp,smb_ServerDomainName,smb_ServerDomainNameLength);
916 tp += smb_ServerDomainNameLength;
918 smb_SetSMBDataLength(outp, 0);
925 long smb_ReceiveV3UserLogoffX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
929 /* don't get tokens from this VC */
930 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
932 inp->flags |= SMB_PACKETFLAG_PROFILE_UPDATE_OK;
934 /* find the tree and free it */
935 uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
936 /* TODO: smb_ReleaseUID() ? */
938 char *s1 = NULL, *s2 = NULL;
940 if (s2 == NULL) s2 = " ";
941 if (s1 == NULL) {s1 = s2; s2 = " ";}
943 osi_Log4(smb_logp, "SMB3 user logoffX uid %d name %s%s%s", uidp->userID,
944 osi_LogSaveString(smb_logp, (uidp->unp) ? uidp->unp->name: " "),
945 osi_LogSaveString(smb_logp,s1), osi_LogSaveString(smb_logp,s2));
947 lock_ObtainMutex(&uidp->mx);
948 uidp->flags |= SMB_USERFLAG_DELETE;
950 * it doesn't get deleted right away
951 * because the vcp points to it
953 lock_ReleaseMutex(&uidp->mx);
956 osi_Log0(smb_logp, "SMB3 user logoffX");
958 smb_SetSMBDataLength(outp, 0);
962 #define SMB_SUPPORT_SEARCH_BITS 0x0001
963 #define SMB_SHARE_IS_IN_DFS 0x0002
965 long smb_ReceiveV3TreeConnectX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
969 unsigned short newTid;
980 osi_Log0(smb_logp, "SMB3 receive tree connect");
982 /* parse input parameters */
983 tp = smb_GetSMBData(inp, NULL);
984 passwordp = smb_ParseString(tp, &tp);
985 pathp = smb_ParseString(tp, &tp);
986 if (smb_StoreAnsiFilenames)
987 OemToChar(pathp,pathp);
988 servicep = smb_ParseString(tp, &tp);
990 tp = strrchr(pathp, '\\');
992 return CM_ERROR_BADSMB;
994 strcpy(shareName, tp+1);
996 osi_Log2(smb_logp, "Tree connect pathp[%s] shareName[%s]",
997 osi_LogSaveString(smb_logp, pathp),
998 osi_LogSaveString(smb_logp, shareName));
1000 if (strcmp(servicep, "IPC") == 0 || strcmp(shareName, "IPC$") == 0) {
1002 osi_Log0(smb_logp, "TreeConnectX connecting to IPC$");
1005 return CM_ERROR_NOIPC;
1009 userp = smb_GetUser(vcp, inp);
1011 lock_ObtainMutex(&vcp->mx);
1012 newTid = vcp->tidCounter++;
1013 lock_ReleaseMutex(&vcp->mx);
1015 tidp = smb_FindTID(vcp, newTid, SMB_FLAG_CREATE);
1018 uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
1019 shareFound = smb_FindShare(vcp, uidp, shareName, &sharePath);
1021 smb_ReleaseUID(uidp);
1023 smb_ReleaseTID(tidp);
1024 return CM_ERROR_BADSHARENAME;
1027 if (vcp->flags & SMB_VCFLAG_USENT)
1029 int policy = smb_FindShareCSCPolicy(shareName);
1030 smb_SetSMBParm(outp, 2, SMB_SUPPORT_SEARCH_BITS |
1032 SMB_SHARE_IS_IN_DFS |
1037 smb_SetSMBParm(outp, 2, 0);
1041 lock_ObtainMutex(&tidp->mx);
1042 tidp->userp = userp;
1043 tidp->pathname = sharePath;
1045 tidp->flags |= SMB_TIDFLAG_IPC;
1046 lock_ReleaseMutex(&tidp->mx);
1047 smb_ReleaseTID(tidp);
1049 ((smb_t *)outp)->tid = newTid;
1050 ((smb_t *)inp)->tid = newTid;
1051 tp = smb_GetSMBData(outp, NULL);
1053 /* XXX - why is this a drive letter? */
1062 smb_SetSMBDataLength(outp, 8);
1065 smb_SetSMBDataLength(outp, 4);
1068 osi_Log1(smb_logp, "SMB3 tree connect created ID %d", newTid);
1072 /* must be called with global tran lock held */
1073 smb_tran2Packet_t *smb_FindTran2Packet(smb_vc_t *vcp, smb_packet_t *inp)
1075 smb_tran2Packet_t *tp;
1078 smbp = (smb_t *) inp->data;
1079 for (tp = smb_tran2AssemblyQueuep; tp; tp = (smb_tran2Packet_t *) osi_QNext(&tp->q)) {
1080 if (tp->vcp == vcp && tp->mid == smbp->mid && tp->tid == smbp->tid)
1086 smb_tran2Packet_t *smb_NewTran2Packet(smb_vc_t *vcp, smb_packet_t *inp,
1087 int totalParms, int totalData)
1089 smb_tran2Packet_t *tp;
1092 smbp = (smb_t *) inp->data;
1093 tp = malloc(sizeof(*tp));
1094 memset(tp, 0, sizeof(*tp));
1097 tp->curData = tp->curParms = 0;
1098 tp->totalData = totalData;
1099 tp->totalParms = totalParms;
1100 tp->tid = smbp->tid;
1101 tp->mid = smbp->mid;
1102 tp->uid = smbp->uid;
1103 tp->pid = smbp->pid;
1104 tp->res[0] = smbp->res[0];
1105 osi_QAdd((osi_queue_t **)&smb_tran2AssemblyQueuep, &tp->q);
1106 if (totalParms != 0)
1107 tp->parmsp = malloc(totalParms);
1109 tp->datap = malloc(totalData);
1110 if (smbp->com == 0x25 || smbp->com == 0x26)
1113 tp->opcode = smb_GetSMBParm(inp, 14);
1116 tp->flags |= SMB_TRAN2PFLAG_ALLOC;
1120 smb_tran2Packet_t *smb_GetTran2ResponsePacket(smb_vc_t *vcp,
1121 smb_tran2Packet_t *inp, smb_packet_t *outp,
1122 int totalParms, int totalData)
1124 smb_tran2Packet_t *tp;
1125 unsigned short parmOffset;
1126 unsigned short dataOffset;
1127 unsigned short dataAlign;
1129 tp = malloc(sizeof(*tp));
1130 memset(tp, 0, sizeof(*tp));
1132 tp->curData = tp->curParms = 0;
1133 tp->totalData = totalData;
1134 tp->totalParms = totalParms;
1135 tp->oldTotalParms = totalParms;
1140 tp->res[0] = inp->res[0];
1141 tp->opcode = inp->opcode;
1145 * We calculate where the parameters and data will start.
1146 * This calculation must parallel the calculation in
1147 * smb_SendTran2Packet.
1150 parmOffset = 10*2 + 35;
1151 parmOffset++; /* round to even */
1152 tp->parmsp = (unsigned short *) (outp->data + parmOffset);
1154 dataOffset = parmOffset + totalParms;
1155 dataAlign = dataOffset & 2; /* quad-align */
1156 dataOffset += dataAlign;
1157 tp->datap = outp->data + dataOffset;
1162 /* free a tran2 packet; must be called with smb_globalLock held */
1163 void smb_FreeTran2Packet(smb_tran2Packet_t *t2p)
1166 smb_ReleaseVC(t2p->vcp);
1167 if (t2p->flags & SMB_TRAN2PFLAG_ALLOC) {
1176 /* called with a VC, an input packet to respond to, and an error code.
1177 * sends an error response.
1179 void smb_SendTran2Error(smb_vc_t *vcp, smb_tran2Packet_t *t2p,
1180 smb_packet_t *tp, long code)
1183 unsigned short errCode;
1184 unsigned char errClass;
1185 unsigned long NTStatus;
1187 if (vcp->flags & SMB_VCFLAG_STATUS32)
1188 smb_MapNTError(code, &NTStatus);
1190 smb_MapCoreError(code, vcp, &errCode, &errClass);
1192 smb_FormatResponsePacket(vcp, NULL, tp);
1193 smbp = (smb_t *) tp;
1195 /* We can handle long names */
1196 if (vcp->flags & SMB_VCFLAG_USENT)
1197 smbp->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
1199 /* now copy important fields from the tran 2 packet */
1200 smbp->com = t2p->com;
1201 smbp->tid = t2p->tid;
1202 smbp->mid = t2p->mid;
1203 smbp->pid = t2p->pid;
1204 smbp->uid = t2p->uid;
1205 smbp->res[0] = t2p->res[0];
1206 if (vcp->flags & SMB_VCFLAG_STATUS32) {
1207 smbp->rcls = (unsigned char) (NTStatus & 0xff);
1208 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
1209 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
1210 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
1211 smbp->flg2 |= SMB_FLAGS2_32BIT_STATUS;
1214 smbp->rcls = errClass;
1215 smbp->errLow = (unsigned char) (errCode & 0xff);
1216 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
1220 smb_SendPacket(vcp, tp);
1223 void smb_SendTran2Packet(smb_vc_t *vcp, smb_tran2Packet_t *t2p, smb_packet_t *tp)
1226 unsigned short parmOffset;
1227 unsigned short dataOffset;
1228 unsigned short totalLength;
1229 unsigned short dataAlign;
1232 smb_FormatResponsePacket(vcp, NULL, tp);
1233 smbp = (smb_t *) tp;
1235 /* We can handle long names */
1236 if (vcp->flags & SMB_VCFLAG_USENT)
1237 smbp->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
1239 /* now copy important fields from the tran 2 packet */
1240 smbp->com = t2p->com;
1241 smbp->tid = t2p->tid;
1242 smbp->mid = t2p->mid;
1243 smbp->pid = t2p->pid;
1244 smbp->uid = t2p->uid;
1245 smbp->res[0] = t2p->res[0];
1247 totalLength = 1 + t2p->totalData + t2p->totalParms;
1249 /* now add the core parameters (tran2 info) to the packet */
1250 smb_SetSMBParm(tp, 0, t2p->totalParms); /* parm bytes */
1251 smb_SetSMBParm(tp, 1, t2p->totalData); /* data bytes */
1252 smb_SetSMBParm(tp, 2, 0); /* reserved */
1253 smb_SetSMBParm(tp, 3, t2p->totalParms); /* parm bytes in this packet */
1254 parmOffset = 10*2 + 35; /* parm offset in packet */
1255 parmOffset++; /* round to even */
1256 smb_SetSMBParm(tp, 4, parmOffset); /* 11 parm words plus *
1257 * hdr, bcc and wct */
1258 smb_SetSMBParm(tp, 5, 0); /* parm displacement */
1259 smb_SetSMBParm(tp, 6, t2p->totalData); /* data in this packet */
1260 dataOffset = parmOffset + t2p->oldTotalParms;
1261 dataAlign = dataOffset & 2; /* quad-align */
1262 dataOffset += dataAlign;
1263 smb_SetSMBParm(tp, 7, dataOffset); /* offset of data */
1264 smb_SetSMBParm(tp, 8, 0); /* data displacement */
1265 smb_SetSMBParm(tp, 9, 0); /* low: setup word count *
1268 datap = smb_GetSMBData(tp, NULL);
1269 *datap++ = 0; /* we rounded to even */
1271 totalLength += dataAlign;
1272 smb_SetSMBDataLength(tp, totalLength);
1274 /* next, send the datagram */
1275 smb_SendPacket(vcp, tp);
1278 long smb_ReceiveV3Trans(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
1280 smb_tran2Packet_t *asp;
1293 /* We sometimes see 0 word count. What to do? */
1294 if (*inp->wctp == 0) {
1299 osi_Log0(smb_logp, "TRANSACTION word count = 0");
1301 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
1302 ptbuf[0] = "Transaction2 word count = 0";
1303 ReportEvent(h, EVENTLOG_WARNING_TYPE, 0, 1003, NULL,
1304 1, inp->ncb_length, ptbuf, inp);
1305 DeregisterEventSource(h);
1307 osi_Log0(smb_logp, "TRANSACTION word count = 0");
1310 smb_SetSMBDataLength(outp, 0);
1311 smb_SendPacket(vcp, outp);
1315 totalParms = smb_GetSMBParm(inp, 0);
1316 totalData = smb_GetSMBParm(inp, 1);
1318 firstPacket = (inp->inCom == 0x25);
1320 /* find the packet we're reassembling */
1321 lock_ObtainWrite(&smb_globalLock);
1322 asp = smb_FindTran2Packet(vcp, inp);
1324 asp = smb_NewTran2Packet(vcp, inp, totalParms, totalData);
1326 lock_ReleaseWrite(&smb_globalLock);
1328 /* now merge in this latest packet; start by looking up offsets */
1330 parmDisp = dataDisp = 0;
1331 parmOffset = smb_GetSMBParm(inp, 10);
1332 dataOffset = smb_GetSMBParm(inp, 12);
1333 parmCount = smb_GetSMBParm(inp, 9);
1334 dataCount = smb_GetSMBParm(inp, 11);
1335 asp->maxReturnParms = smb_GetSMBParm(inp, 2);
1336 asp->maxReturnData = smb_GetSMBParm(inp, 3);
1338 osi_Log3(smb_logp, "SMB3 received Trans init packet total data %d, cur data %d, max return data %d",
1339 totalData, dataCount, asp->maxReturnData);
1342 parmDisp = smb_GetSMBParm(inp, 4);
1343 parmOffset = smb_GetSMBParm(inp, 3);
1344 dataDisp = smb_GetSMBParm(inp, 7);
1345 dataOffset = smb_GetSMBParm(inp, 6);
1346 parmCount = smb_GetSMBParm(inp, 2);
1347 dataCount = smb_GetSMBParm(inp, 5);
1349 osi_Log2(smb_logp, "SMB3 received Trans aux packet parms %d, data %d",
1350 parmCount, dataCount);
1353 /* now copy the parms and data */
1354 if ( asp->totalParms > 0 && parmCount != 0 )
1356 memcpy(((char *)asp->parmsp) + parmDisp, inp->data + parmOffset, parmCount);
1358 if ( asp->totalData > 0 && dataCount != 0 ) {
1359 memcpy(asp->datap + dataDisp, inp->data + dataOffset, dataCount);
1362 /* account for new bytes */
1363 asp->curData += dataCount;
1364 asp->curParms += parmCount;
1366 /* finally, if we're done, remove the packet from the queue and dispatch it */
1367 if (asp->totalParms > 0 &&
1368 asp->curParms > 0 &&
1369 asp->totalData <= asp->curData &&
1370 asp->totalParms <= asp->curParms) {
1371 /* we've received it all */
1372 lock_ObtainWrite(&smb_globalLock);
1373 osi_QRemove((osi_queue_t **) &smb_tran2AssemblyQueuep, &asp->q);
1374 lock_ReleaseWrite(&smb_globalLock);
1376 /* now dispatch it */
1377 rapOp = asp->parmsp[0];
1379 if ( rapOp >= 0 && rapOp < SMB_RAP_NOPCODES && smb_rapDispatchTable[rapOp].procp) {
1380 osi_LogEvent("AFS-Dispatch-RAP[%s]",myCrt_RapDispatch(rapOp),"vcp[%x] lana[%d] lsn[%d]",(int)vcp,vcp->lana,vcp->lsn);
1381 osi_Log4(smb_logp,"AFS Server - Dispatch-RAP %s vcp[%x] lana[%d] lsn[%d]",myCrt_RapDispatch(rapOp),vcp,vcp->lana,vcp->lsn);
1382 code = (*smb_rapDispatchTable[rapOp].procp)(vcp, asp, outp);
1385 osi_LogEvent("AFS-Dispatch-RAP [invalid]", NULL, "op[%x] vcp[%x] lana[%d] lsn[%d]", rapOp, vcp, vcp->lana, vcp->lsn);
1386 osi_Log4(smb_logp,"AFS Server - Dispatch-RAP [INVALID] op[%x] vcp[%x] lana[%d] lsn[%d]", rapOp, vcp, vcp->lana, vcp->lsn);
1387 code = CM_ERROR_BADOP;
1390 /* if an error is returned, we're supposed to send an error packet,
1391 * otherwise the dispatched function already did the data sending.
1392 * We give dispatched proc the responsibility since it knows how much
1393 * space to allocate.
1396 smb_SendTran2Error(vcp, asp, outp, code);
1399 /* free the input tran 2 packet */
1400 lock_ObtainWrite(&smb_globalLock);
1401 smb_FreeTran2Packet(asp);
1402 lock_ReleaseWrite(&smb_globalLock);
1404 else if (firstPacket) {
1405 /* the first packet in a multi-packet request, we need to send an
1406 * ack to get more data.
1408 smb_SetSMBDataLength(outp, 0);
1409 smb_SendPacket(vcp, outp);
1415 /* ANSI versions. The unicode versions support arbitrary length
1416 share names, but we don't support unicode yet. */
1418 typedef struct smb_rap_share_info_0 {
1419 char shi0_netname[13];
1420 } smb_rap_share_info_0_t;
1422 typedef struct smb_rap_share_info_1 {
1423 char shi1_netname[13];
1426 DWORD shi1_remark; /* char *shi1_remark; data offset */
1427 } smb_rap_share_info_1_t;
1429 typedef struct smb_rap_share_info_2 {
1430 char shi2_netname[13];
1432 unsigned short shi2_type;
1433 DWORD shi2_remark; /* char *shi2_remark; data offset */
1434 unsigned short shi2_permissions;
1435 unsigned short shi2_max_uses;
1436 unsigned short shi2_current_uses;
1437 DWORD shi2_path; /* char *shi2_path; data offset */
1438 unsigned short shi2_passwd[9];
1439 unsigned short shi2_pad2;
1440 } smb_rap_share_info_2_t;
1442 #define SMB_RAP_MAX_SHARES 512
1444 typedef struct smb_rap_share_list {
1447 smb_rap_share_info_0_t * shares;
1448 } smb_rap_share_list_t;
1450 int smb_rapCollectSharesProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp) {
1451 smb_rap_share_list_t * sp;
1456 if (name[0] == '.' && (!name[1] || (name[1] == '.' && !name[2])))
1457 return 0; /* skip over '.' and '..' */
1459 sp = (smb_rap_share_list_t *) vrockp;
1461 strncpy(sp->shares[sp->cShare].shi0_netname, name, 12);
1462 sp->shares[sp->cShare].shi0_netname[12] = 0;
1466 if (sp->cShare >= sp->maxShares)
1467 return CM_ERROR_STOPNOW;
1472 long smb_ReceiveRAPNetShareEnum(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1474 smb_tran2Packet_t *outp;
1475 unsigned short * tp;
1479 int outParmsTotal; /* total parameter bytes */
1480 int outDataTotal; /* total data bytes */
1488 HKEY hkSubmount = NULL;
1489 smb_rap_share_info_1_t * shares;
1492 char thisShare[256];
1495 smb_rap_share_list_t rootShares;
1500 tp = p->parmsp + 1; /* skip over function number (always 0) */
1501 (void) smb_ParseString((char *) tp, (char **) &tp); /* skip over parm descriptor */
1502 (void) smb_ParseString((char *) tp, (char **) &tp); /* skip over data descriptor */
1506 if (infoLevel != 1) {
1507 return CM_ERROR_INVAL;
1510 /* first figure out how many shares there are */
1511 rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY, 0,
1512 KEY_QUERY_VALUE, &hkParam);
1513 if (rv == ERROR_SUCCESS) {
1514 len = sizeof(allSubmount);
1515 rv = RegQueryValueEx(hkParam, "AllSubmount", NULL, NULL,
1516 (BYTE *) &allSubmount, &len);
1517 if (rv != ERROR_SUCCESS || allSubmount != 0) {
1520 RegCloseKey (hkParam);
1523 rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_OPENAFS_SUBKEY "\\Submounts",
1524 0, KEY_QUERY_VALUE, &hkSubmount);
1525 if (rv == ERROR_SUCCESS) {
1526 rv = RegQueryInfoKey(hkSubmount, NULL, NULL, NULL, NULL,
1527 NULL, NULL, &nRegShares, NULL, NULL, NULL, NULL);
1528 if (rv != ERROR_SUCCESS)
1534 /* fetch the root shares */
1535 rootShares.maxShares = SMB_RAP_MAX_SHARES;
1536 rootShares.cShare = 0;
1537 rootShares.shares = malloc( sizeof(smb_rap_share_info_0_t) * SMB_RAP_MAX_SHARES );
1541 userp = smb_GetTran2User(vcp,p);
1543 thyper.HighPart = 0;
1546 cm_HoldSCache(cm_data.rootSCachep);
1547 cm_ApplyDir(cm_data.rootSCachep, smb_rapCollectSharesProc, &rootShares, &thyper, userp, &req, NULL);
1548 cm_ReleaseSCache(cm_data.rootSCachep);
1550 cm_ReleaseUser(userp);
1552 nShares = rootShares.cShare + nRegShares + allSubmount;
1554 #define REMARK_LEN 1
1555 outParmsTotal = 8; /* 4 dwords */
1556 outDataTotal = (sizeof(smb_rap_share_info_1_t) + REMARK_LEN) * nShares ;
1557 if(outDataTotal > bufsize) {
1558 nSharesRet = bufsize / (sizeof(smb_rap_share_info_1_t) + REMARK_LEN);
1559 outDataTotal = (sizeof(smb_rap_share_info_1_t) + REMARK_LEN) * nSharesRet;
1562 nSharesRet = nShares;
1565 outp = smb_GetTran2ResponsePacket(vcp, p, op, outParmsTotal, outDataTotal);
1567 /* now for the submounts */
1568 shares = (smb_rap_share_info_1_t *) outp->datap;
1569 cstrp = outp->datap + sizeof(smb_rap_share_info_1_t) * nSharesRet;
1571 memset(outp->datap, 0, (sizeof(smb_rap_share_info_1_t) + REMARK_LEN) * nSharesRet);
1574 strcpy( shares[cshare].shi1_netname, "all" );
1575 shares[cshare].shi1_remark = cstrp - outp->datap;
1576 /* type and pad are zero already */
1582 for (i=0; i < nRegShares && cshare < nSharesRet; i++) {
1583 len = sizeof(thisShare);
1584 rv = RegEnumValue(hkSubmount, i, thisShare, &len, NULL, NULL, NULL, NULL);
1585 if (rv == ERROR_SUCCESS && strlen(thisShare) && (!allSubmount || stricmp(thisShare,"all"))) {
1586 strncpy(shares[cshare].shi1_netname, thisShare, sizeof(shares->shi1_netname)-1);
1587 shares[cshare].shi1_netname[sizeof(shares->shi1_netname)-1] = 0; /* unfortunate truncation */
1588 shares[cshare].shi1_remark = cstrp - outp->datap;
1593 nShares--; /* uncount key */
1596 RegCloseKey(hkSubmount);
1599 nonrootShares = cshare;
1601 for (i=0; i < rootShares.cShare && cshare < nSharesRet; i++) {
1602 /* in case there are collisions with submounts, submounts have higher priority */
1603 for (j=0; j < nonrootShares; j++)
1604 if (!stricmp(shares[j].shi1_netname, rootShares.shares[i].shi0_netname))
1607 if (j < nonrootShares) {
1608 nShares--; /* uncount */
1612 strcpy(shares[cshare].shi1_netname, rootShares.shares[i].shi0_netname);
1613 shares[cshare].shi1_remark = cstrp - outp->datap;
1618 outp->parmsp[0] = ((cshare == nShares)? ERROR_SUCCESS : ERROR_MORE_DATA);
1619 outp->parmsp[1] = 0;
1620 outp->parmsp[2] = cshare;
1621 outp->parmsp[3] = nShares;
1623 outp->totalData = cstrp - outp->datap;
1624 outp->totalParms = outParmsTotal;
1626 smb_SendTran2Packet(vcp, outp, op);
1627 smb_FreeTran2Packet(outp);
1629 free(rootShares.shares);
1634 long smb_ReceiveRAPNetShareGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1636 smb_tran2Packet_t *outp;
1637 unsigned short * tp;
1639 BOOL shareFound = FALSE;
1640 unsigned short infoLevel;
1641 unsigned short bufsize;
1651 tp = p->parmsp + 1; /* skip over function number (always 1) */
1652 (void) smb_ParseString( (char *) tp, (char **) &tp); /* skip over param descriptor */
1653 (void) smb_ParseString( (char *) tp, (char **) &tp); /* skip over data descriptor */
1654 shareName = smb_ParseString( (char *) tp, (char **) &tp);
1661 totalData = sizeof(smb_rap_share_info_0_t);
1662 else if(infoLevel == SMB_INFO_STANDARD)
1663 totalData = sizeof(smb_rap_share_info_1_t) + 1; /* + empty string */
1664 else if(infoLevel == SMB_INFO_QUERY_EA_SIZE)
1665 totalData = sizeof(smb_rap_share_info_2_t) + 2; /* + two empty strings */
1667 return CM_ERROR_INVAL;
1669 outp = smb_GetTran2ResponsePacket(vcp, p, op, totalParam, totalData);
1671 if(!stricmp(shareName,"all")) {
1672 rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY, 0,
1673 KEY_QUERY_VALUE, &hkParam);
1674 if (rv == ERROR_SUCCESS) {
1675 len = sizeof(allSubmount);
1676 rv = RegQueryValueEx(hkParam, "AllSubmount", NULL, NULL,
1677 (BYTE *) &allSubmount, &len);
1678 if (rv != ERROR_SUCCESS || allSubmount != 0) {
1681 RegCloseKey (hkParam);
1688 rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY "\\Submounts", 0,
1689 KEY_QUERY_VALUE, &hkSubmount);
1690 if (rv == ERROR_SUCCESS) {
1691 rv = RegQueryValueEx(hkSubmount, shareName, NULL, NULL, NULL, NULL);
1692 if (rv == ERROR_SUCCESS) {
1695 RegCloseKey(hkSubmount);
1700 smb_FreeTran2Packet(outp);
1701 return CM_ERROR_BADSHARENAME;
1704 memset(outp->datap, 0, totalData);
1706 outp->parmsp[0] = 0;
1707 outp->parmsp[1] = 0;
1708 outp->parmsp[2] = totalData;
1710 if (infoLevel == 0) {
1711 smb_rap_share_info_0_t * info = (smb_rap_share_info_0_t *) outp->datap;
1712 strncpy(info->shi0_netname, shareName, sizeof(info->shi0_netname)-1);
1713 info->shi0_netname[sizeof(info->shi0_netname)-1] = 0;
1714 } else if(infoLevel == SMB_INFO_STANDARD) {
1715 smb_rap_share_info_1_t * info = (smb_rap_share_info_1_t *) outp->datap;
1716 strncpy(info->shi1_netname, shareName, sizeof(info->shi1_netname)-1);
1717 info->shi1_netname[sizeof(info->shi1_netname)-1] = 0;
1718 info->shi1_remark = ((unsigned char *) (info + 1)) - outp->datap;
1719 /* type and pad are already zero */
1720 } else { /* infoLevel==2 */
1721 smb_rap_share_info_2_t * info = (smb_rap_share_info_2_t *) outp->datap;
1722 strncpy(info->shi2_netname, shareName, sizeof(info->shi2_netname)-1);
1723 info->shi2_netname[sizeof(info->shi2_netname)-1] = 0;
1724 info->shi2_remark = ((unsigned char *) (info + 1)) - outp->datap;
1725 info->shi2_permissions = ACCESS_ALL;
1726 info->shi2_max_uses = (unsigned short) -1;
1727 info->shi2_path = 1 + (((unsigned char *) (info + 1)) - outp->datap);
1730 outp->totalData = totalData;
1731 outp->totalParms = totalParam;
1733 smb_SendTran2Packet(vcp, outp, op);
1734 smb_FreeTran2Packet(outp);
1739 typedef struct smb_rap_wksta_info_10 {
1740 DWORD wki10_computername; /*char *wki10_computername;*/
1741 DWORD wki10_username; /* char *wki10_username; */
1742 DWORD wki10_langroup; /* char *wki10_langroup;*/
1743 unsigned char wki10_ver_major;
1744 unsigned char wki10_ver_minor;
1745 DWORD wki10_logon_domain; /*char *wki10_logon_domain;*/
1746 DWORD wki10_oth_domains; /* char *wki10_oth_domains;*/
1747 } smb_rap_wksta_info_10_t;
1750 long smb_ReceiveRAPNetWkstaGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1752 smb_tran2Packet_t *outp;
1756 unsigned short * tp;
1759 smb_rap_wksta_info_10_t * info;
1763 tp = p->parmsp + 1; /* Skip over function number */
1764 (void) smb_ParseString((unsigned char*) tp, (char **) &tp); /* skip over param descriptor */
1765 (void) smb_ParseString((unsigned char*) tp, (char **) &tp); /* skip over data descriptor */
1769 if (infoLevel != 10) {
1770 return CM_ERROR_INVAL;
1776 totalData = sizeof(*info) + /* info */
1777 MAX_COMPUTERNAME_LENGTH + /* wki10_computername */
1778 SMB_MAX_USERNAME_LENGTH + /* wki10_username */
1779 MAX_COMPUTERNAME_LENGTH + /* wki10_langroup */
1780 MAX_COMPUTERNAME_LENGTH + /* wki10_logon_domain */
1781 1; /* wki10_oth_domains (null)*/
1783 outp = smb_GetTran2ResponsePacket(vcp, p, op, totalParams, totalData);
1785 memset(outp->parmsp,0,totalParams);
1786 memset(outp->datap,0,totalData);
1788 info = (smb_rap_wksta_info_10_t *) outp->datap;
1789 cstrp = (char *) (info + 1);
1791 info->wki10_computername = (DWORD) (cstrp - outp->datap);
1792 strcpy(cstrp, smb_localNamep);
1793 cstrp += strlen(cstrp) + 1;
1795 info->wki10_username = (DWORD) (cstrp - outp->datap);
1796 uidp = smb_FindUID(vcp, p->uid, 0);
1798 lock_ObtainMutex(&uidp->mx);
1799 if(uidp->unp && uidp->unp->name)
1800 strcpy(cstrp, uidp->unp->name);
1801 lock_ReleaseMutex(&uidp->mx);
1802 smb_ReleaseUID(uidp);
1804 cstrp += strlen(cstrp) + 1;
1806 info->wki10_langroup = (DWORD) (cstrp - outp->datap);
1807 strcpy(cstrp, "WORKGROUP");
1808 cstrp += strlen(cstrp) + 1;
1810 /* TODO: Not sure what values these should take, but these work */
1811 info->wki10_ver_major = 5;
1812 info->wki10_ver_minor = 1;
1814 info->wki10_logon_domain = (DWORD) (cstrp - outp->datap);
1815 strcpy(cstrp, smb_ServerDomainName);
1816 cstrp += strlen(cstrp) + 1;
1818 info->wki10_oth_domains = (DWORD) (cstrp - outp->datap);
1819 cstrp ++; /* no other domains */
1821 outp->totalData = (unsigned short) (cstrp - outp->datap); /* actual data size */
1822 outp->parmsp[2] = outp->totalData;
1823 outp->totalParms = totalParams;
1825 smb_SendTran2Packet(vcp,outp,op);
1826 smb_FreeTran2Packet(outp);
1831 typedef struct smb_rap_server_info_0 {
1833 } smb_rap_server_info_0_t;
1835 typedef struct smb_rap_server_info_1 {
1837 char sv1_version_major;
1838 char sv1_version_minor;
1839 unsigned long sv1_type;
1840 DWORD *sv1_comment_or_master_browser; /* char *sv1_comment_or_master_browser;*/
1841 } smb_rap_server_info_1_t;
1843 char smb_ServerComment[] = "OpenAFS Client";
1844 int smb_ServerCommentLen = sizeof(smb_ServerComment);
1846 #define SMB_SV_TYPE_SERVER 0x00000002L
1847 #define SMB_SV_TYPE_NT 0x00001000L
1848 #define SMB_SV_TYPE_SERVER_NT 0x00008000L
1850 long smb_ReceiveRAPNetServerGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1852 smb_tran2Packet_t *outp;
1856 unsigned short * tp;
1859 smb_rap_server_info_0_t * info0;
1860 smb_rap_server_info_1_t * info1;
1863 tp = p->parmsp + 1; /* Skip over function number */
1864 (void) smb_ParseString((unsigned char*) tp, (char **) &tp); /* skip over param descriptor */
1865 (void) smb_ParseString((unsigned char*) tp, (char **) &tp); /* skip over data descriptor */
1869 if (infoLevel != 0 && infoLevel != 1) {
1870 return CM_ERROR_INVAL;
1876 (infoLevel == 0) ? sizeof(smb_rap_server_info_0_t)
1877 : (sizeof(smb_rap_server_info_1_t) + smb_ServerCommentLen);
1879 outp = smb_GetTran2ResponsePacket(vcp, p, op, totalParams, totalData);
1881 memset(outp->parmsp,0,totalParams);
1882 memset(outp->datap,0,totalData);
1884 if (infoLevel == 0) {
1885 info0 = (smb_rap_server_info_0_t *) outp->datap;
1886 cstrp = (char *) (info0 + 1);
1887 strcpy(info0->sv0_name, "AFS");
1888 } else { /* infoLevel == SMB_INFO_STANDARD */
1889 info1 = (smb_rap_server_info_1_t *) outp->datap;
1890 cstrp = (char *) (info1 + 1);
1891 strcpy(info1->sv1_name, "AFS");
1894 SMB_SV_TYPE_SERVER |
1896 SMB_SV_TYPE_SERVER_NT;
1898 info1->sv1_version_major = 5;
1899 info1->sv1_version_minor = 1;
1900 info1->sv1_comment_or_master_browser = (DWORD *) (cstrp - outp->datap);
1902 strcpy(cstrp, smb_ServerComment);
1904 cstrp += smb_ServerCommentLen;
1907 totalData = cstrp - outp->datap;
1908 outp->totalData = min(bufsize,totalData); /* actual data size */
1909 outp->parmsp[0] = (outp->totalData == totalData)? 0 : ERROR_MORE_DATA;
1910 outp->parmsp[2] = totalData;
1911 outp->totalParms = totalParams;
1913 smb_SendTran2Packet(vcp,outp,op);
1914 smb_FreeTran2Packet(outp);
1919 long smb_ReceiveV3Tran2A(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
1921 smb_tran2Packet_t *asp;
1933 /* We sometimes see 0 word count. What to do? */
1934 if (*inp->wctp == 0) {
1939 osi_Log0(smb_logp, "TRANSACTION2 word count = 0");
1941 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
1942 ptbuf[0] = "Transaction2 word count = 0";
1943 ReportEvent(h, EVENTLOG_WARNING_TYPE, 0, 1003, NULL,
1944 1, inp->ncb_length, ptbuf, inp);
1945 DeregisterEventSource(h);
1947 osi_Log0(smb_logp, "TRANSACTION2 word count = 0");
1950 smb_SetSMBDataLength(outp, 0);
1951 smb_SendPacket(vcp, outp);
1955 totalParms = smb_GetSMBParm(inp, 0);
1956 totalData = smb_GetSMBParm(inp, 1);
1958 firstPacket = (inp->inCom == 0x32);
1960 /* find the packet we're reassembling */
1961 lock_ObtainWrite(&smb_globalLock);
1962 asp = smb_FindTran2Packet(vcp, inp);
1964 asp = smb_NewTran2Packet(vcp, inp, totalParms, totalData);
1966 lock_ReleaseWrite(&smb_globalLock);
1968 /* now merge in this latest packet; start by looking up offsets */
1970 parmDisp = dataDisp = 0;
1971 parmOffset = smb_GetSMBParm(inp, 10);
1972 dataOffset = smb_GetSMBParm(inp, 12);
1973 parmCount = smb_GetSMBParm(inp, 9);
1974 dataCount = smb_GetSMBParm(inp, 11);
1975 asp->maxReturnParms = smb_GetSMBParm(inp, 2);
1976 asp->maxReturnData = smb_GetSMBParm(inp, 3);
1978 osi_Log3(smb_logp, "SMB3 received T2 init packet total data %d, cur data %d, max return data %d",
1979 totalData, dataCount, asp->maxReturnData);
1982 parmDisp = smb_GetSMBParm(inp, 4);
1983 parmOffset = smb_GetSMBParm(inp, 3);
1984 dataDisp = smb_GetSMBParm(inp, 7);
1985 dataOffset = smb_GetSMBParm(inp, 6);
1986 parmCount = smb_GetSMBParm(inp, 2);
1987 dataCount = smb_GetSMBParm(inp, 5);
1989 osi_Log2(smb_logp, "SMB3 received T2 aux packet parms %d, data %d",
1990 parmCount, dataCount);
1993 /* now copy the parms and data */
1994 if ( asp->totalParms > 0 && parmCount != 0 )
1996 memcpy(((char *)asp->parmsp) + parmDisp, inp->data + parmOffset, parmCount);
1998 if ( asp->totalData > 0 && dataCount != 0 ) {
1999 memcpy(asp->datap + dataDisp, inp->data + dataOffset, dataCount);
2002 /* account for new bytes */
2003 asp->curData += dataCount;
2004 asp->curParms += parmCount;
2006 /* finally, if we're done, remove the packet from the queue and dispatch it */
2007 if (asp->totalParms > 0 &&
2008 asp->curParms > 0 &&
2009 asp->totalData <= asp->curData &&
2010 asp->totalParms <= asp->curParms) {
2011 /* we've received it all */
2012 lock_ObtainWrite(&smb_globalLock);
2013 osi_QRemove((osi_queue_t **) &smb_tran2AssemblyQueuep, &asp->q);
2014 lock_ReleaseWrite(&smb_globalLock);
2016 /* now dispatch it */
2017 if ( asp->opcode >= 0 && asp->opcode < 20 && smb_tran2DispatchTable[asp->opcode].procp) {
2018 osi_LogEvent("AFS-Dispatch-2[%s]",myCrt_2Dispatch(asp->opcode),"vcp[%x] lana[%d] lsn[%d]",(int)vcp,vcp->lana,vcp->lsn);
2019 osi_Log4(smb_logp,"AFS Server - Dispatch-2 %s vcp[%x] lana[%d] lsn[%d]",myCrt_2Dispatch(asp->opcode),vcp,vcp->lana,vcp->lsn);
2020 code = (*smb_tran2DispatchTable[asp->opcode].procp)(vcp, asp, outp);
2023 osi_LogEvent("AFS-Dispatch-2 [invalid]", NULL, "op[%x] vcp[%x] lana[%d] lsn[%d]", asp->opcode, vcp, vcp->lana, vcp->lsn);
2024 osi_Log4(smb_logp,"AFS Server - Dispatch-2 [INVALID] op[%x] vcp[%x] lana[%d] lsn[%d]", asp->opcode, vcp, vcp->lana, vcp->lsn);
2025 code = CM_ERROR_BADOP;
2028 /* if an error is returned, we're supposed to send an error packet,
2029 * otherwise the dispatched function already did the data sending.
2030 * We give dispatched proc the responsibility since it knows how much
2031 * space to allocate.
2034 smb_SendTran2Error(vcp, asp, outp, code);
2037 /* free the input tran 2 packet */
2038 lock_ObtainWrite(&smb_globalLock);
2039 smb_FreeTran2Packet(asp);
2040 lock_ReleaseWrite(&smb_globalLock);
2042 else if (firstPacket) {
2043 /* the first packet in a multi-packet request, we need to send an
2044 * ack to get more data.
2046 smb_SetSMBDataLength(outp, 0);
2047 smb_SendPacket(vcp, outp);
2053 long smb_ReceiveTran2Open(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
2056 smb_tran2Packet_t *outp;
2061 cm_scache_t *dscp; /* dir we're dealing with */
2062 cm_scache_t *scp; /* file we're creating */
2064 int initialModeBits;
2074 int parmSlot; /* which parm we're dealing with */
2075 long returnEALength;
2083 extraInfo = (p->parmsp[0] & 1); /* return extra info */
2084 returnEALength = (p->parmsp[0] & 8); /* return extended attr length */
2086 openFun = p->parmsp[6]; /* open function */
2087 excl = ((openFun & 3) == 0);
2088 trunc = ((openFun & 3) == 2); /* truncate it */
2089 openMode = (p->parmsp[1] & 0x7);
2090 openAction = 0; /* tracks what we did */
2092 attributes = p->parmsp[3];
2093 dosTime = p->parmsp[4] | (p->parmsp[5] << 16);
2095 /* compute initial mode bits based on read-only flag in attributes */
2096 initialModeBits = 0666;
2098 initialModeBits &= ~0222;
2100 pathp = (char *) (&p->parmsp[14]);
2101 if (smb_StoreAnsiFilenames)
2102 OemToChar(pathp,pathp);
2104 outp = smb_GetTran2ResponsePacket(vcp, p, op, 40, 0);
2106 spacep = cm_GetSpace();
2107 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
2109 if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
2110 /* special case magic file name for receiving IOCTL requests
2111 * (since IOCTL calls themselves aren't getting through).
2113 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
2114 smb_SetupIoctlFid(fidp, spacep);
2116 /* copy out remainder of the parms */
2118 outp->parmsp[parmSlot++] = fidp->fid;
2120 outp->parmsp[parmSlot++] = 0; /* attrs */
2121 outp->parmsp[parmSlot++] = 0; /* mod time */
2122 outp->parmsp[parmSlot++] = 0;
2123 outp->parmsp[parmSlot++] = 0; /* len */
2124 outp->parmsp[parmSlot++] = 0x7fff;
2125 outp->parmsp[parmSlot++] = openMode;
2126 outp->parmsp[parmSlot++] = 0; /* file type 0 ==> normal file or dir */
2127 outp->parmsp[parmSlot++] = 0; /* IPC junk */
2129 /* and the final "always present" stuff */
2130 outp->parmsp[parmSlot++] = 1; /* openAction found existing file */
2131 /* next write out the "unique" ID */
2132 outp->parmsp[parmSlot++] = 0x1234;
2133 outp->parmsp[parmSlot++] = 0x5678;
2134 outp->parmsp[parmSlot++] = 0;
2135 if (returnEALength) {
2136 outp->parmsp[parmSlot++] = 0;
2137 outp->parmsp[parmSlot++] = 0;
2140 outp->totalData = 0;
2141 outp->totalParms = parmSlot * 2;
2143 smb_SendTran2Packet(vcp, outp, op);
2145 smb_FreeTran2Packet(outp);
2147 /* and clean up fid reference */
2148 smb_ReleaseFID(fidp);
2152 #ifdef DEBUG_VERBOSE
2154 char *hexp, *asciip;
2155 asciip = (lastNamep ? lastNamep : pathp);
2156 hexp = osi_HexifyString( asciip );
2157 DEBUG_EVENT2("AFS","T2Open H[%s] A[%s]", hexp, asciip);
2162 userp = smb_GetTran2User(vcp, p);
2163 /* In the off chance that userp is NULL, we log and abandon */
2165 osi_Log1(smb_logp, "ReceiveTran2Open user [%d] not resolvable", p->uid);
2166 smb_FreeTran2Packet(outp);
2167 return CM_ERROR_BADSMB;
2170 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
2171 if (code == CM_ERROR_TIDIPC) {
2172 /* Attempt to use a TID allocated for IPC. The client
2173 * is probably looking for DCE RPC end points which we
2174 * don't support OR it could be looking to make a DFS
2177 osi_Log0(smb_logp, "Tran2Open received IPC TID");
2179 cm_ReleaseUser(userp);
2180 smb_FreeTran2Packet(outp);
2181 return CM_ERROR_NOSUCHPATH;
2186 code = cm_NameI(cm_data.rootSCachep, pathp,
2187 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
2188 userp, tidPathp, &req, &scp);
2190 code = cm_NameI(cm_data.rootSCachep, spacep->data,
2191 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
2192 userp, tidPathp, &req, &dscp);
2193 cm_FreeSpace(spacep);
2196 cm_ReleaseUser(userp);
2197 smb_FreeTran2Packet(outp);
2202 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
2203 cm_ReleaseSCache(dscp);
2204 cm_ReleaseUser(userp);
2205 smb_FreeTran2Packet(outp);
2206 if ( WANTS_DFS_PATHNAMES(p) )
2207 return CM_ERROR_PATH_NOT_COVERED;
2209 return CM_ERROR_BADSHARENAME;
2211 #endif /* DFS_SUPPORT */
2213 /* otherwise, scp points to the parent directory. Do a lookup,
2214 * and truncate the file if we find it, otherwise we create the
2221 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD, userp,
2223 if (code && code != CM_ERROR_NOSUCHFILE) {
2224 cm_ReleaseSCache(dscp);
2225 cm_ReleaseUser(userp);
2226 smb_FreeTran2Packet(outp);
2231 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
2232 cm_ReleaseSCache(scp);
2233 cm_ReleaseUser(userp);
2234 smb_FreeTran2Packet(outp);
2235 if ( WANTS_DFS_PATHNAMES(p) )
2236 return CM_ERROR_PATH_NOT_COVERED;
2238 return CM_ERROR_BADSHARENAME;
2240 #endif /* DFS_SUPPORT */
2242 /* macintosh is expensive to program for it */
2243 cm_FreeSpace(spacep);
2246 /* if we get here, if code is 0, the file exists and is represented by
2247 * scp. Otherwise, we have to create it.
2250 code = cm_CheckOpen(scp, openMode, trunc, userp, &req);
2253 cm_ReleaseSCache(dscp);
2254 cm_ReleaseSCache(scp);
2255 cm_ReleaseUser(userp);
2256 smb_FreeTran2Packet(outp);
2261 /* oops, file shouldn't be there */
2263 cm_ReleaseSCache(dscp);
2264 cm_ReleaseSCache(scp);
2265 cm_ReleaseUser(userp);
2266 smb_FreeTran2Packet(outp);
2267 return CM_ERROR_EXISTS;
2271 setAttr.mask = CM_ATTRMASK_LENGTH;
2272 setAttr.length.LowPart = 0;
2273 setAttr.length.HighPart = 0;
2274 code = cm_SetAttr(scp, &setAttr, userp, &req);
2275 openAction = 3; /* truncated existing file */
2278 openAction = 1; /* found existing file */
2280 else if (!(openFun & 0x10)) {
2281 /* don't create if not found */
2283 cm_ReleaseSCache(dscp);
2284 osi_assert(scp == NULL);
2285 cm_ReleaseUser(userp);
2286 smb_FreeTran2Packet(outp);
2287 return CM_ERROR_NOSUCHFILE;
2290 osi_assert(dscp != NULL && scp == NULL);
2291 openAction = 2; /* created file */
2292 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
2293 smb_UnixTimeFromSearchTime(&setAttr.clientModTime, dosTime);
2294 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
2296 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
2297 smb_NotifyChange(FILE_ACTION_ADDED,
2298 FILE_NOTIFY_CHANGE_FILE_NAME,
2299 dscp, lastNamep, NULL, TRUE);
2300 if (!excl && code == CM_ERROR_EXISTS) {
2301 /* not an exclusive create, and someone else tried
2302 * creating it already, then we open it anyway. We
2303 * don't bother retrying after this, since if this next
2304 * fails, that means that the file was deleted after we
2305 * started this call.
2307 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
2311 setAttr.mask = CM_ATTRMASK_LENGTH;
2312 setAttr.length.LowPart = 0;
2313 setAttr.length.HighPart = 0;
2314 code = cm_SetAttr(scp, &setAttr, userp,
2317 } /* lookup succeeded */
2321 /* we don't need this any longer */
2323 cm_ReleaseSCache(dscp);
2326 /* something went wrong creating or truncating the file */
2328 cm_ReleaseSCache(scp);
2329 cm_ReleaseUser(userp);
2330 smb_FreeTran2Packet(outp);
2334 /* make sure we're about to open a file */
2335 if (scp->fileType != CM_SCACHETYPE_FILE) {
2337 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
2338 cm_scache_t * targetScp = 0;
2339 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
2341 /* we have a more accurate file to use (the
2342 * target of the symbolic link). Otherwise,
2343 * we'll just use the symlink anyway.
2345 osi_Log2(smb_logp, "symlink vp %x to vp %x",
2347 cm_ReleaseSCache(scp);
2351 if (scp->fileType != CM_SCACHETYPE_FILE) {
2352 cm_ReleaseSCache(scp);
2353 cm_ReleaseUser(userp);
2354 smb_FreeTran2Packet(outp);
2355 return CM_ERROR_ISDIR;
2359 /* now all we have to do is open the file itself */
2360 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
2363 /* save a pointer to the vnode */
2366 /* compute open mode */
2367 if (openMode != 1) fidp->flags |= SMB_FID_OPENREAD;
2368 if (openMode == 1 || openMode == 2)
2369 fidp->flags |= SMB_FID_OPENWRITE;
2371 smb_ReleaseFID(fidp);
2373 cm_Open(scp, 0, userp);
2375 /* copy out remainder of the parms */
2377 outp->parmsp[parmSlot++] = fidp->fid;
2378 lock_ObtainMutex(&scp->mx);
2380 outp->parmsp[parmSlot++] = smb_Attributes(scp);
2381 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
2382 outp->parmsp[parmSlot++] = (unsigned short)(dosTime & 0xffff);
2383 outp->parmsp[parmSlot++] = (unsigned short)((dosTime>>16) & 0xffff);
2384 outp->parmsp[parmSlot++] = (unsigned short) (scp->length.LowPart & 0xffff);
2385 outp->parmsp[parmSlot++] = (unsigned short) ((scp->length.LowPart >> 16) & 0xffff);
2386 outp->parmsp[parmSlot++] = openMode;
2387 outp->parmsp[parmSlot++] = 0; /* file type 0 ==> normal file or dir */
2388 outp->parmsp[parmSlot++] = 0; /* IPC junk */
2390 /* and the final "always present" stuff */
2391 outp->parmsp[parmSlot++] = openAction;
2392 /* next write out the "unique" ID */
2393 outp->parmsp[parmSlot++] = (unsigned short) (scp->fid.vnode & 0xffff);
2394 outp->parmsp[parmSlot++] = (unsigned short) (scp->fid.volume & 0xffff);
2395 outp->parmsp[parmSlot++] = 0;
2396 if (returnEALength) {
2397 outp->parmsp[parmSlot++] = 0;
2398 outp->parmsp[parmSlot++] = 0;
2400 lock_ReleaseMutex(&scp->mx);
2401 outp->totalData = 0; /* total # of data bytes */
2402 outp->totalParms = parmSlot * 2; /* shorts are two bytes */
2404 smb_SendTran2Packet(vcp, outp, op);
2406 smb_FreeTran2Packet(outp);
2408 cm_ReleaseUser(userp);
2409 /* leave scp held since we put it in fidp->scp */
2413 long smb_ReceiveTran2FindFirst(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
2415 osi_Log0(smb_logp,"ReceiveTran2FindFirst - NOT_SUPPORTED");
2416 return CM_ERROR_BADOP;
2419 long smb_ReceiveTran2FindNext(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
2421 osi_Log0(smb_logp,"ReceiveTran2FindNext - NOT_SUPPORTED");
2422 return CM_ERROR_BADOP;
2425 long smb_ReceiveTran2QFSInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
2427 smb_tran2Packet_t *outp;
2428 smb_tran2QFSInfo_t qi;
2431 static char FSname[6] = {'A', 0, 'F', 0, 'S', 0};
2433 osi_Log1(smb_logp, "T2 QFSInfo type 0x%x", p->parmsp[0]);
2435 switch (p->parmsp[0]) {
2436 case 1: responseSize = sizeof(qi.u.allocInfo); break;
2437 case 2: responseSize = sizeof(qi.u.volumeInfo); break;
2438 case 0x102: responseSize = sizeof(qi.u.FSvolumeInfo); break;
2439 case 0x103: responseSize = sizeof(qi.u.FSsizeInfo); break;
2440 case 0x104: responseSize = sizeof(qi.u.FSdeviceInfo); break;
2441 case 0x105: responseSize = sizeof(qi.u.FSattributeInfo); break;
2442 case 0x200: /* CIFS Unix Info */
2443 case 0x301: /* Mac FS Info */
2444 default: return CM_ERROR_INVAL;
2447 outp = smb_GetTran2ResponsePacket(vcp, p, op, 0, responseSize);
2448 switch (p->parmsp[0]) {
2451 qi.u.allocInfo.FSID = 0;
2452 qi.u.allocInfo.sectorsPerAllocUnit = 1;
2453 qi.u.allocInfo.totalAllocUnits = 0x7fffffff;
2454 qi.u.allocInfo.availAllocUnits = 0x3fffffff;
2455 qi.u.allocInfo.bytesPerSector = 1024;
2460 qi.u.volumeInfo.vsn = 1234;
2461 qi.u.volumeInfo.vnCount = 4;
2462 /* we're supposed to pad it out with zeroes to the end */
2463 memset(&qi.u.volumeInfo.label, 0, sizeof(qi.u.volumeInfo.label));
2464 memcpy(qi.u.volumeInfo.label, "AFS", 4);
2468 /* FS volume info */
2469 memset((char *)&qi.u.FSvolumeInfo.vct, 0, sizeof(FILETIME));
2470 qi.u.FSvolumeInfo.vsn = 1234;
2471 qi.u.FSvolumeInfo.vnCount = 8;
2472 memcpy(qi.u.FSvolumeInfo.label, "A\0F\0S\0\0", 8);
2478 temp.LowPart = 0x7fffffff;
2479 qi.u.FSsizeInfo.totalAllocUnits = temp;
2480 temp.LowPart = 0x3fffffff;
2481 qi.u.FSsizeInfo.availAllocUnits = temp;
2482 qi.u.FSsizeInfo.sectorsPerAllocUnit = 1;
2483 qi.u.FSsizeInfo.bytesPerSector = 1024;
2487 /* FS device info */
2488 qi.u.FSdeviceInfo.devType = 0; /* don't have a number */
2489 qi.u.FSdeviceInfo.characteristics = 0x50; /* remote, virtual */
2493 /* FS attribute info */
2494 /* attributes, defined in WINNT.H:
2495 * FILE_CASE_SENSITIVE_SEARCH 0x1
2496 * FILE_CASE_PRESERVED_NAMES 0x2
2497 * <no name defined> 0x4000
2498 * If bit 0x4000 is not set, Windows 95 thinks
2499 * we can't handle long (non-8.3) names,
2500 * despite our protestations to the contrary.
2502 qi.u.FSattributeInfo.attributes = 0x4003;
2503 qi.u.FSattributeInfo.maxCompLength = 255;
2504 qi.u.FSattributeInfo.FSnameLength = 6;
2505 memcpy(qi.u.FSattributeInfo.FSname, FSname, 6);
2509 /* copy out return data, and set corresponding sizes */
2510 outp->totalParms = 0;
2511 outp->totalData = responseSize;
2512 memcpy(outp->datap, &qi, responseSize);
2514 /* send and free the packets */
2515 smb_SendTran2Packet(vcp, outp, op);
2516 smb_FreeTran2Packet(outp);
2521 long smb_ReceiveTran2SetFSInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
2523 osi_Log0(smb_logp,"ReceiveTran2SetFSInfo - NOT_SUPPORTED");
2524 return CM_ERROR_BADOP;
2527 struct smb_ShortNameRock {
2531 size_t shortNameLen;
2534 int cm_GetShortNameProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *vrockp,
2537 struct smb_ShortNameRock *rockp;
2541 /* compare both names and vnodes, though probably just comparing vnodes
2542 * would be safe enough.
2544 if (cm_stricmp(dep->name, rockp->maskp) != 0)
2546 if (ntohl(dep->fid.vnode) != rockp->vnode)
2548 /* This is the entry */
2549 cm_Gen8Dot3Name(dep, rockp->shortName, &shortNameEnd);
2550 rockp->shortNameLen = shortNameEnd - rockp->shortName;
2551 return CM_ERROR_STOPNOW;
2554 long cm_GetShortName(char *pathp, cm_user_t *userp, cm_req_t *reqp,
2555 char *tidPathp, int vnode, char *shortName, size_t *shortNameLenp)
2557 struct smb_ShortNameRock rock;
2561 int caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
2565 spacep = cm_GetSpace();
2566 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
2568 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold, userp, tidPathp,
2570 cm_FreeSpace(spacep);
2575 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
2576 cm_ReleaseSCache(dscp);
2577 cm_ReleaseUser(userp);
2578 return CM_ERROR_PATH_NOT_COVERED;
2580 #endif /* DFS_SUPPORT */
2582 if (!lastNamep) lastNamep = pathp;
2585 thyper.HighPart = 0;
2586 rock.shortName = shortName;
2588 rock.maskp = lastNamep;
2589 code = cm_ApplyDir(dscp, cm_GetShortNameProc, &rock, &thyper, userp, reqp, NULL);
2591 cm_ReleaseSCache(dscp);
2594 return CM_ERROR_NOSUCHFILE;
2595 if (code == CM_ERROR_STOPNOW) {
2596 *shortNameLenp = rock.shortNameLen;
2602 long smb_ReceiveTran2QPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
2604 smb_tran2Packet_t *outp;
2607 unsigned short infoLevel;
2609 unsigned short attributes;
2610 unsigned long extAttributes;
2615 cm_scache_t *scp, *dscp;
2624 infoLevel = p->parmsp[0];
2625 if (infoLevel == SMB_INFO_IS_NAME_VALID)
2627 else if (infoLevel == SMB_INFO_STANDARD)
2628 nbytesRequired = 22;
2629 else if (infoLevel == SMB_INFO_QUERY_EA_SIZE)
2630 nbytesRequired = 26;
2631 else if (infoLevel == SMB_QUERY_FILE_BASIC_INFO)
2632 nbytesRequired = 40;
2633 else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO)
2634 nbytesRequired = 24;
2635 else if (infoLevel == SMB_QUERY_FILE_EA_INFO)
2637 else if (infoLevel == SMB_QUERY_FILE_ALT_NAME_INFO)
2638 nbytesRequired = 30;
2640 osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
2641 p->opcode, infoLevel);
2642 smb_SendTran2Error(vcp, p, opx, CM_ERROR_INVAL);
2645 osi_Log2(smb_logp, "T2 QPathInfo type 0x%x path %s", infoLevel,
2646 osi_LogSaveString(smb_logp, (char *)(&p->parmsp[3])));
2648 outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, nbytesRequired);
2650 if (infoLevel > 0x100)
2651 outp->totalParms = 2;
2653 outp->totalParms = 0;
2654 outp->totalData = nbytesRequired;
2656 /* now, if we're at infoLevel 6, we're only being asked to check
2657 * the syntax, so we just OK things now. In particular, we're *not*
2658 * being asked to verify anything about the state of any parent dirs.
2660 if (infoLevel == SMB_INFO_IS_NAME_VALID) {
2661 smb_SendTran2Packet(vcp, outp, opx);
2662 smb_FreeTran2Packet(outp);
2666 userp = smb_GetTran2User(vcp, p);
2668 osi_Log1(smb_logp, "ReceiveTran2QPathInfo unable to resolve user [%d]", p->uid);
2669 smb_FreeTran2Packet(outp);
2670 return CM_ERROR_BADSMB;
2673 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
2675 cm_ReleaseUser(userp);
2676 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOSUCHPATH);
2677 smb_FreeTran2Packet(outp);
2682 * XXX Strange hack XXX
2684 * As of Patch 7 (13 January 98), we are having the following problem:
2685 * In NT Explorer 4.0, whenever we click on a directory, AFS gets
2686 * requests to look up "desktop.ini" in all the subdirectories.
2687 * This can cause zillions of timeouts looking up non-existent cells
2688 * and volumes, especially in the top-level directory.
2690 * We have not found any way to avoid this or work around it except
2691 * to explicitly ignore the requests for mount points that haven't
2692 * yet been evaluated and for directories that haven't yet been
2695 if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
2696 spacep = cm_GetSpace();
2697 smb_StripLastComponent(spacep->data, &lastComp,
2698 (char *)(&p->parmsp[3]));
2699 #ifndef SPECIAL_FOLDERS
2700 /* Make sure that lastComp is not NULL */
2702 if (stricmp(lastComp, "\\desktop.ini") == 0) {
2703 code = cm_NameI(cm_data.rootSCachep, spacep->data,
2707 userp, tidPathp, &req, &dscp);
2710 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
2711 if ( WANTS_DFS_PATHNAMES(p) )
2712 code = CM_ERROR_PATH_NOT_COVERED;
2714 code = CM_ERROR_BADSHARENAME;
2716 #endif /* DFS_SUPPORT */
2717 if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT && !dscp->mountRootFid.volume)
2718 code = CM_ERROR_NOSUCHFILE;
2719 else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
2720 cm_buf_t *bp = buf_Find(dscp, &hzero);
2724 code = CM_ERROR_NOSUCHFILE;
2726 cm_ReleaseSCache(dscp);
2728 cm_FreeSpace(spacep);
2729 cm_ReleaseUser(userp);
2730 smb_SendTran2Error(vcp, p, opx, code);
2731 smb_FreeTran2Packet(outp);
2737 #endif /* SPECIAL_FOLDERS */
2739 cm_FreeSpace(spacep);
2742 /* now do namei and stat, and copy out the info */
2743 code = cm_NameI(cm_data.rootSCachep, (char *)(&p->parmsp[3]),
2744 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, tidPathp, &req, &scp);
2747 cm_ReleaseUser(userp);
2748 smb_SendTran2Error(vcp, p, opx, code);
2749 smb_FreeTran2Packet(outp);
2754 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
2755 cm_ReleaseSCache(scp);
2756 cm_ReleaseUser(userp);
2757 if ( WANTS_DFS_PATHNAMES(p) )
2758 code = CM_ERROR_PATH_NOT_COVERED;
2760 code = CM_ERROR_BADSHARENAME;
2761 smb_SendTran2Error(vcp, p, opx, code);
2762 smb_FreeTran2Packet(outp);
2765 #endif /* DFS_SUPPORT */
2767 lock_ObtainMutex(&scp->mx);
2768 code = cm_SyncOp(scp, NULL, userp, &req, 0,
2769 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
2770 if (code) goto done;
2772 /* now we have the status in the cache entry, and everything is locked.
2773 * Marshall the output data.
2776 /* for info level 108, figure out short name */
2777 if (infoLevel == 0x108) {
2778 code = cm_GetShortName((char *)(&p->parmsp[3]), userp, &req,
2779 tidPathp, scp->fid.vnode, shortName,
2786 *((u_long *)op) = len * 2; op += 4;
2787 mbstowcs((unsigned short *)op, shortName, len);
2792 if (infoLevel == SMB_INFO_STANDARD || infoLevel == SMB_INFO_QUERY_EA_SIZE) {
2793 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
2794 *((u_long *)op) = dosTime; op += 4; /* creation time */
2795 *((u_long *)op) = dosTime; op += 4; /* access time */
2796 *((u_long *)op) = dosTime; op += 4; /* write time */
2797 *((u_long *)op) = scp->length.LowPart; op += 4; /* length */
2798 *((u_long *)op) = scp->length.LowPart; op += 4; /* alloc size */
2799 attributes = smb_Attributes(scp);
2800 *((u_short *)op) = attributes; op += 2; /* attributes */
2802 else if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
2803 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
2804 *((FILETIME *)op) = ft; op += 8; /* creation time */
2805 *((FILETIME *)op) = ft; op += 8; /* last access time */
2806 *((FILETIME *)op) = ft; op += 8; /* last write time */
2807 *((FILETIME *)op) = ft; op += 8; /* last change time */
2808 extAttributes = smb_ExtAttributes(scp);
2809 *((u_long *)op) = extAttributes; op += 4; /* extended attribs */
2810 *((u_long *)op) = 0; op += 4; /* don't know what this is */
2812 else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO) {
2813 *((LARGE_INTEGER *)op) = scp->length; op += 8; /* alloc size */
2814 *((LARGE_INTEGER *)op) = scp->length; op += 8; /* EOF */
2815 *((u_long *)op) = scp->linkCount; op += 4;
2818 *op++ = (scp->fileType == CM_SCACHETYPE_DIRECTORY ? 1 : 0);
2821 else if (infoLevel == SMB_QUERY_FILE_EA_INFO) {
2822 memset(op, 0, 4); op += 4; /* EA size */
2825 /* now, if we are being asked about extended attrs, return a 0 size */
2826 if (infoLevel == SMB_INFO_QUERY_EA_SIZE) {
2827 *((u_long *)op) = 0; op += 4;
2831 /* send and free the packets */
2833 lock_ReleaseMutex(&scp->mx);
2834 cm_ReleaseSCache(scp);
2835 cm_ReleaseUser(userp);
2837 smb_SendTran2Packet(vcp, outp, opx);
2839 smb_SendTran2Error(vcp, p, opx, code);
2840 smb_FreeTran2Packet(outp);
2845 long smb_ReceiveTran2SetPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
2847 osi_Log0(smb_logp,"ReceiveTran2SetPathInfo - NOT_SUPPORTED");
2848 return CM_ERROR_BADOP;
2851 long smb_ReceiveTran2QFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
2853 smb_tran2Packet_t *outp;
2855 unsigned long attributes;
2856 unsigned short infoLevel;
2869 fidp = smb_FindFID(vcp, fid, 0);
2872 smb_SendTran2Error(vcp, p, opx, CM_ERROR_BADFD);
2876 infoLevel = p->parmsp[1];
2877 if (infoLevel == SMB_QUERY_FILE_BASIC_INFO)
2878 nbytesRequired = 40;
2879 else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO)
2880 nbytesRequired = 24;
2881 else if (infoLevel == SMB_QUERY_FILE_EA_INFO)
2883 else if (infoLevel == SMB_QUERY_FILE_NAME_INFO)
2886 osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
2887 p->opcode, infoLevel);
2888 smb_SendTran2Error(vcp, p, opx, CM_ERROR_INVAL);
2889 smb_ReleaseFID(fidp);
2892 osi_Log2(smb_logp, "T2 QFileInfo type 0x%x fid %d", infoLevel, fid);
2894 outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, nbytesRequired);
2896 if (infoLevel > 0x100)
2897 outp->totalParms = 2;
2899 outp->totalParms = 0;
2900 outp->totalData = nbytesRequired;
2902 userp = smb_GetTran2User(vcp, p);
2904 osi_Log1(smb_logp, "ReceiveTran2QFileInfo unable to resolve user [%d]", p->uid);
2905 code = CM_ERROR_BADSMB;
2910 lock_ObtainMutex(&scp->mx);
2911 code = cm_SyncOp(scp, NULL, userp, &req, 0,
2912 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
2916 /* now we have the status in the cache entry, and everything is locked.
2917 * Marshall the output data.
2920 if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
2921 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
2922 *((FILETIME *)op) = ft; op += 8; /* creation time */
2923 *((FILETIME *)op) = ft; op += 8; /* last access time */
2924 *((FILETIME *)op) = ft; op += 8; /* last write time */
2925 *((FILETIME *)op) = ft; op += 8; /* last change time */
2926 attributes = smb_ExtAttributes(scp);
2927 *((u_long *)op) = attributes; op += 4;
2928 *((u_long *)op) = 0; op += 4;
2930 else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO) {
2931 *((LARGE_INTEGER *)op) = scp->length; op += 8; /* alloc size */
2932 *((LARGE_INTEGER *)op) = scp->length; op += 8; /* EOF */
2933 *((u_long *)op) = scp->linkCount; op += 4;
2934 *op++ = ((fidp->flags & SMB_FID_DELONCLOSE) ? 1 : 0);
2935 *op++ = (scp->fileType == CM_SCACHETYPE_DIRECTORY ? 1 : 0);
2939 else if (infoLevel == SMB_QUERY_FILE_EA_INFO) {
2940 *((u_long *)op) = 0; op += 4;
2942 else if (infoLevel == SMB_QUERY_FILE_NAME_INFO) {
2946 if (fidp->NTopen_wholepathp)
2947 name = fidp->NTopen_wholepathp;
2949 name = "\\"; /* probably can't happen */
2951 outp->totalData = (len*2) + 4; /* this is actually what we want to return */
2952 *((u_long *)op) = len * 2; op += 4;
2953 mbstowcs((unsigned short *)op, name, len); op += (len * 2);
2956 /* send and free the packets */
2958 lock_ReleaseMutex(&scp->mx);
2959 cm_ReleaseUser(userp);
2960 smb_ReleaseFID(fidp);
2962 smb_SendTran2Packet(vcp, outp, opx);
2964 smb_SendTran2Error(vcp, p, opx, code);
2965 smb_FreeTran2Packet(outp);
2970 long smb_ReceiveTran2SetFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
2975 unsigned short infoLevel;
2976 smb_tran2Packet_t *outp;
2984 fidp = smb_FindFID(vcp, fid, 0);
2987 smb_SendTran2Error(vcp, p, op, CM_ERROR_BADFD);
2991 infoLevel = p->parmsp[1];
2992 osi_Log2(smb_logp,"ReceiveTran2SetFileInfo type=[%x] fid=[%x]", infoLevel, fid);
2993 if (infoLevel > 0x104 || infoLevel < 0x101) {
2994 osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
2995 p->opcode, infoLevel);
2996 smb_SendTran2Error(vcp, p, op, CM_ERROR_INVAL);
2997 smb_ReleaseFID(fidp);
3001 if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO && !(fidp->flags & SMB_FID_OPENDELETE)) {
3002 smb_SendTran2Error(vcp, p, op, CM_ERROR_NOACCESS);
3003 smb_ReleaseFID(fidp);
3006 if ((infoLevel == SMB_QUERY_FILE_EA_INFO || infoLevel == SMB_QUERY_FILE_NAME_INFO)
3007 && !(fidp->flags & SMB_FID_OPENWRITE)) {
3008 smb_SendTran2Error(vcp, p, op, CM_ERROR_NOACCESS);
3009 smb_ReleaseFID(fidp);
3013 osi_Log1(smb_logp, "T2 SFileInfo type 0x%x", infoLevel);
3015 outp = smb_GetTran2ResponsePacket(vcp, p, op, 2, 0);
3017 outp->totalParms = 2;
3018 outp->totalData = 0;
3020 userp = smb_GetTran2User(vcp, p);
3022 osi_Log1(smb_logp,"ReceiveTran2SetFileInfo unable to resolve user [%d]", p->uid);
3023 code = CM_ERROR_BADSMB;
3029 if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
3031 unsigned int attribute;
3034 /* lock the vnode with a callback; we need the current status
3035 * to determine what the new status is, in some cases.
3037 lock_ObtainMutex(&scp->mx);
3038 code = cm_SyncOp(scp, NULL, userp, &req, 0,
3039 CM_SCACHESYNC_GETSTATUS
3040 | CM_SCACHESYNC_NEEDCALLBACK);
3042 lock_ReleaseMutex(&scp->mx);
3046 /* prepare for setattr call */
3049 lastMod = *((FILETIME *)(p->datap + 16));
3050 /* when called as result of move a b, lastMod is (-1, -1).
3051 * If the check for -1 is not present, timestamp
3052 * of the resulting file will be 1969 (-1)
3054 if (LargeIntegerNotEqualToZero(*((LARGE_INTEGER *)&lastMod)) &&
3055 lastMod.dwLowDateTime != -1 && lastMod.dwHighDateTime != -1) {
3056 attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
3057 smb_UnixTimeFromLargeSearchTime(&attr.clientModTime, &lastMod);
3058 fidp->flags |= SMB_FID_MTIMESETDONE;
3061 attribute = *((u_long *)(p->datap + 32));
3062 if (attribute != 0) {
3063 if ((scp->unixModeBits & 0222)
3064 && (attribute & 1) != 0) {
3065 /* make a writable file read-only */
3066 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
3067 attr.unixModeBits = scp->unixModeBits & ~0222;
3069 else if ((scp->unixModeBits & 0222) == 0
3070 && (attribute & 1) == 0) {
3071 /* make a read-only file writable */
3072 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
3073 attr.unixModeBits = scp->unixModeBits | 0222;
3076 lock_ReleaseMutex(&scp->mx);
3080 code = cm_SetAttr(scp, &attr, userp, &req);
3084 else if (infoLevel == SMB_QUERY_FILE_EA_INFO || infoLevel == SMB_QUERY_FILE_NAME_INFO) {
3085 LARGE_INTEGER size = *((LARGE_INTEGER *)(p->datap));
3088 attr.mask = CM_ATTRMASK_LENGTH;
3089 attr.length.LowPart = size.LowPart;
3090 attr.length.HighPart = size.HighPart;
3091 code = cm_SetAttr(scp, &attr, userp, &req);
3093 else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO) {
3094 if (*((char *)(p->datap))) {
3095 code = cm_CheckNTDelete(fidp->NTopen_dscp, scp, userp,
3098 fidp->flags |= SMB_FID_DELONCLOSE;
3102 fidp->flags &= ~SMB_FID_DELONCLOSE;
3107 cm_ReleaseUser(userp);
3108 smb_ReleaseFID(fidp);
3110 smb_SendTran2Packet(vcp, outp, op);
3112 smb_SendTran2Error(vcp, p, op, code);
3113 smb_FreeTran2Packet(outp);
3119 smb_ReceiveTran2FSCTL(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3121 osi_Log0(smb_logp,"ReceiveTran2FSCTL - NOT_SUPPORTED");
3122 return CM_ERROR_BADOP;
3126 smb_ReceiveTran2IOCTL(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3128 osi_Log0(smb_logp,"ReceiveTran2IOCTL - NOT_SUPPORTED");
3129 return CM_ERROR_BADOP;
3133 smb_ReceiveTran2FindNotifyFirst(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3135 osi_Log0(smb_logp,"ReceiveTran2FindNotifyFirst - NOT_SUPPORTED");
3136 return CM_ERROR_BADOP;
3140 smb_ReceiveTran2FindNotifyNext(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3142 osi_Log0(smb_logp,"ReceiveTran2FindNotifyNext - NOT_SUPPORTED");
3143 return CM_ERROR_BADOP;
3147 smb_ReceiveTran2CreateDirectory(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3149 osi_Log0(smb_logp,"ReceiveTran2CreateDirectory - NOT_SUPPORTED");
3150 return CM_ERROR_BADOP;
3154 smb_ReceiveTran2SessionSetup(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3156 osi_Log0(smb_logp,"ReceiveTran2SessionSetup - NOT_SUPPORTED");
3157 return CM_ERROR_BADOP;
3160 struct smb_v2_referral {
3162 USHORT ReferralFlags;
3165 USHORT DfsPathOffset;
3166 USHORT DfsAlternativePathOffset;
3167 USHORT NetworkAddressOffset;
3171 smb_ReceiveTran2GetDFSReferral(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
3173 /* This is a UNICODE only request (bit15 of Flags2) */
3174 /* The TID must be IPC$ */
3176 /* The documentation for the Flags response field is contradictory */
3178 /* Use Version 1 Referral Element Format */
3179 /* ServerType = 0; indicates the next server should be queried for the file */
3180 /* ReferralFlags = 0x01; PathConsumed characters should be stripped */
3181 /* Node = UnicodeString of UNC path of the next share name */
3184 int maxReferralLevel = 0;
3185 char requestFileName[1024] = "";
3186 smb_tran2Packet_t *outp = 0;
3187 cm_user_t *userp = 0;
3189 CPINFO CodePageInfo;
3190 int i, nbnLen, reqLen;
3195 maxReferralLevel = p->parmsp[0];
3197 GetCPInfo(CP_ACP, &CodePageInfo);
3198 WideCharToMultiByte(CP_ACP, 0, (LPCWSTR) &p->parmsp[1], -1,
3199 requestFileName, 1024, NULL, NULL);
3201 osi_Log2(smb_logp,"ReceiveTran2GetDfsReferral [%d][%s]",
3202 maxReferralLevel, osi_LogSaveString(smb_logp, requestFileName));
3204 nbnLen = strlen(cm_NetbiosName);
3205 reqLen = strlen(requestFileName);
3207 if (reqLen == nbnLen + 5 &&
3208 requestFileName[0] == '\\' &&
3209 !_strnicmp(cm_NetbiosName,&requestFileName[1],nbnLen) &&
3210 requestFileName[nbnLen+1] == '\\' &&
3211 !_strnicmp("all",&requestFileName[nbnLen+2],3))
3214 struct smb_v2_referral * v2ref;
3215 outp = smb_GetTran2ResponsePacket(vcp, p, op, 0, 2 * (reqLen + 8));
3217 sp = (USHORT *)outp->datap;
3219 sp[idx++] = reqLen; /* path consumed */
3220 sp[idx++] = 1; /* number of referrals */
3221 sp[idx++] = 0x03; /* flags */
3222 #ifdef DFS_VERSION_1
3223 sp[idx++] = 1; /* Version Number */
3224 sp[idx++] = reqLen + 4; /* Referral Size */
3225 sp[idx++] = 1; /* Type = SMB Server */
3226 sp[idx++] = 0; /* Do not strip path consumed */
3227 for ( i=0;i<=reqLen; i++ )
3228 sp[i+idx] = requestFileName[i];
3229 #else /* DFS_VERSION_2 */
3230 sp[idx++] = 2; /* Version Number */
3231 sp[idx++] = sizeof(struct smb_v2_referral); /* Referral Size */
3232 idx += (sizeof(struct smb_v2_referral) / 2);
3233 v2ref = (struct smb_v2_referral *) &sp[5];
3234 v2ref->ServerType = 1; /* SMB Server */
3235 v2ref->ReferralFlags = 0x03;
3236 v2ref->Proximity = 0; /* closest */
3237 v2ref->TimeToLive = 3600; /* seconds */
3238 v2ref->DfsPathOffset = idx * 2;
3239 v2ref->DfsAlternativePathOffset = idx * 2;
3240 v2ref->NetworkAddressOffset = 0;
3241 for ( i=0;i<=reqLen; i++ )
3242 sp[i+idx] = requestFileName[i];
3245 userp = smb_GetTran2User(vcp, p);
3247 osi_Log1(smb_logp,"ReceiveTran2GetDfsReferral unable to resolve user [%d]", p->uid);
3248 code = CM_ERROR_BADSMB;
3253 code = CM_ERROR_NOSUCHPATH;
3258 cm_ReleaseUser(userp);
3260 smb_SendTran2Packet(vcp, outp, op);
3262 smb_SendTran2Error(vcp, p, op, code);
3264 smb_FreeTran2Packet(outp);
3267 #else /* DFS_SUPPORT */
3268 osi_Log0(smb_logp,"ReceiveTran2GetDfsReferral - NOT_SUPPORTED");
3269 return CM_ERROR_BADOP;
3270 #endif /* DFS_SUPPORT */
3274 smb_ReceiveTran2ReportDFSInconsistency(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3276 /* This is a UNICODE only request (bit15 of Flags2) */
3278 /* There is nothing we can do about this operation. The client is going to
3279 * tell us that there is a Version 1 Referral Element for which there is a DFS Error.
3280 * Unfortunately, there is really nothing we can do about it other then log it
3281 * somewhere. Even then I don't think there is anything for us to do.
3282 * So let's return an error value.
3285 osi_Log0(smb_logp,"ReceiveTran2ReportDFSInconsistency - NOT_SUPPORTED");
3286 return CM_ERROR_BADOP;
3290 smb_ApplyV3DirListPatches(cm_scache_t *dscp,
3291 smb_dirListPatch_t **dirPatchespp, int infoLevel, cm_user_t *userp,
3296 cm_scache_t *targetScp; /* target if scp is a symlink */
3301 unsigned short attr;
3302 unsigned long lattr;
3303 smb_dirListPatch_t *patchp;
3304 smb_dirListPatch_t *npatchp;
3306 for(patchp = *dirPatchespp; patchp; patchp =
3307 (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
3308 code = cm_GetSCache(&patchp->fid, &scp, userp, reqp);
3310 lock_ObtainMutex(&scp->mx);
3311 code = cm_SyncOp(scp, NULL, userp, reqp, 0,
3312 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3314 lock_ReleaseMutex(&scp->mx);
3315 cm_ReleaseSCache(scp);
3317 dptr = patchp->dptr;
3319 /* Plug in fake timestamps. A time stamp of 0 causes 'invalid parameter'
3320 errors in the client. */
3321 if (infoLevel >= 0x101) {
3322 /* 1969-12-31 23:59:59 +00 */
3323 ft.dwHighDateTime = 0x19DB200;
3324 ft.dwLowDateTime = 0x5BB78980;
3326 /* copy to Creation Time */
3327 *((FILETIME *)dptr) = ft;
3330 /* copy to Last Access Time */
3331 *((FILETIME *)dptr) = ft;
3334 /* copy to Last Write Time */
3335 *((FILETIME *)dptr) = ft;
3338 /* copy to Change Time */
3339 *((FILETIME *)dptr) = ft;
3342 /* merge in hidden attribute */
3343 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
3344 *((u_long *)dptr) = SMB_ATTR_HIDDEN;
3348 /* 1969-12-31 23:59:58 +00*/
3349 dosTime = 0xEBBFBF7D;
3351 /* and copy out date */
3352 shortTemp = (dosTime>>16) & 0xffff;
3353 *((u_short *)dptr) = shortTemp;
3356 /* copy out creation time */
3357 shortTemp = dosTime & 0xffff;
3358 *((u_short *)dptr) = shortTemp;
3361 /* and copy out date */
3362 shortTemp = (dosTime>>16) & 0xffff;
3363 *((u_short *)dptr) = shortTemp;
3366 /* copy out access time */
3367 shortTemp = dosTime & 0xffff;
3368 *((u_short *)dptr) = shortTemp;
3371 /* and copy out date */
3372 shortTemp = (dosTime>>16) & 0xffff;
3373 *((u_short *)dptr) = shortTemp;
3376 /* copy out mod time */
3377 shortTemp = dosTime & 0xffff;
3378 *((u_short *)dptr) = shortTemp;
3381 /* merge in hidden (dot file) attribute */
3382 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
3383 attr = SMB_ATTR_HIDDEN;
3384 *dptr++ = attr & 0xff;
3385 *dptr++ = (attr >> 8) & 0xff;
3391 /* now watch for a symlink */
3393 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
3394 lock_ReleaseMutex(&scp->mx);
3395 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, reqp);
3397 /* we have a more accurate file to use (the
3398 * target of the symbolic link). Otherwise,
3399 * we'll just use the symlink anyway.
3401 osi_Log2(smb_logp, "symlink vp %x to vp %x",
3403 cm_ReleaseSCache(scp);
3406 lock_ObtainMutex(&scp->mx);
3409 dptr = patchp->dptr;
3411 if (infoLevel >= 0x101) {
3413 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
3415 /* copy to Creation Time */
3416 *((FILETIME *)dptr) = ft;
3419 /* copy to Last Access Time */
3420 *((FILETIME *)dptr) = ft;
3423 /* copy to Last Write Time */
3424 *((FILETIME *)dptr) = ft;
3427 /* copy to Change Time */
3428 *((FILETIME *)dptr) = ft;
3431 /* Use length for both file length and alloc length */
3432 *((LARGE_INTEGER *)dptr) = scp->length;
3434 *((LARGE_INTEGER *)dptr) = scp->length;
3437 /* Copy attributes */
3438 lattr = smb_ExtAttributes(scp);
3439 if (code == CM_ERROR_NOSUCHPATH && scp->fileType == CM_SCACHETYPE_SYMLINK) {
3440 if (lattr == SMB_ATTR_NORMAL)
3441 lattr = SMB_ATTR_DIRECTORY;
3443 lattr |= SMB_ATTR_DIRECTORY;
3445 /* merge in hidden (dot file) attribute */
3446 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
3447 if (lattr == SMB_ATTR_NORMAL)
3448 lattr = SMB_ATTR_HIDDEN;
3450 lattr |= SMB_ATTR_HIDDEN;
3452 *((u_long *)dptr) = lattr;
3456 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
3458 /* and copy out date */
3459 shortTemp = (dosTime>>16) & 0xffff;
3460 *((u_short *)dptr) = shortTemp;
3463 /* copy out creation time */
3464 shortTemp = dosTime & 0xffff;
3465 *((u_short *)dptr) = shortTemp;
3468 /* and copy out date */
3469 shortTemp = (dosTime>>16) & 0xffff;
3470 *((u_short *)dptr) = shortTemp;
3473 /* copy out access time */
3474 shortTemp = dosTime & 0xffff;
3475 *((u_short *)dptr) = shortTemp;
3478 /* and copy out date */
3479 shortTemp = (dosTime>>16) & 0xffff;
3480 *((u_short *)dptr) = shortTemp;
3483 /* copy out mod time */
3484 shortTemp = dosTime & 0xffff;
3485 *((u_short *)dptr) = shortTemp;
3488 /* copy out file length and alloc length,
3489 * using the same for both
3491 *((u_long *)dptr) = scp->length.LowPart;
3493 *((u_long *)dptr) = scp->length.LowPart;
3496 /* finally copy out attributes as short */
3497 attr = smb_Attributes(scp);
3498 /* merge in hidden (dot file) attribute */
3499 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
3500 if (lattr == SMB_ATTR_NORMAL)
3501 lattr = SMB_ATTR_HIDDEN;
3503 lattr |= SMB_ATTR_HIDDEN;
3505 *dptr++ = attr & 0xff;
3506 *dptr++ = (attr >> 8) & 0xff;
3509 lock_ReleaseMutex(&scp->mx);
3510 cm_ReleaseSCache(scp);
3513 /* now free the patches */
3514 for (patchp = *dirPatchespp; patchp; patchp = npatchp) {
3515 npatchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q);
3519 /* and mark the list as empty */
3520 *dirPatchespp = NULL;
3525 #ifndef USE_OLD_MATCHING
3526 // char table for case insensitive comparison
3527 char mapCaseTable[256];
3529 VOID initUpperCaseTable(VOID)
3532 for (i = 0; i < 256; ++i)
3533 mapCaseTable[i] = toupper(i);
3534 // make '"' match '.'
3535 mapCaseTable[(int)'"'] = toupper('.');
3536 // make '<' match '*'
3537 mapCaseTable[(int)'<'] = toupper('*');
3538 // make '>' match '?'
3539 mapCaseTable[(int)'>'] = toupper('?');
3542 // Compare 'pattern' (containing metacharacters '*' and '?') with the file
3544 // Note : this procedure works recursively calling itself.
3546 // PSZ pattern : string containing metacharacters.
3547 // PSZ name : file name to be compared with 'pattern'.
3549 // BOOL : TRUE/FALSE (match/mistmatch)
3552 szWildCardMatchFileName(PSZ pattern, PSZ name, int casefold)
3554 PSZ pename; // points to the last 'name' character
3556 pename = name + strlen(name) - 1;
3566 if (*pattern == '\0')
3568 for (p = pename; p >= name; --p) {
3569 if ((casefold && (mapCaseTable[*p] == mapCaseTable[*pattern]) ||
3570 !casefold && (*p == *pattern)) &&
3571 szWildCardMatchFileName(pattern + 1, p + 1, casefold))
3576 if ((casefold && mapCaseTable[*name] != mapCaseTable[*pattern]) ||
3577 (!casefold && *name != *pattern))
3584 if (*pattern == '\0' || *pattern == '*' && *(pattern+1) == '\0')
3590 /* do a case-folding search of the star name mask with the name in namep.
3591 * Return 1 if we match, otherwise 0.
3593 int smb_V3MatchMask(char *namep, char *maskp, int flags)
3596 int i, j, star, qmark, casefold, retval;
3598 /* make sure we only match 8.3 names, if requested */
3599 if ((flags & CM_FLAG_8DOT3) && !cm_Is8Dot3(namep))
3602 casefold = (flags & CM_FLAG_CASEFOLD) ? 1 : 0;
3604 /* optimize the pattern:
3605 * if there is a mixture of '?' and '*',
3606 * for example the sequence "*?*?*?*"
3607 * must be turned into the form "*"
3609 newmask = (char *)malloc(strlen(maskp)+1);
3610 for ( i=0, j=0, star=0, qmark=0; maskp[i]; i++) {
3611 switch ( maskp[i] ) {
3623 } else if ( qmark ) {
3627 newmask[j++] = maskp[i];
3634 } else if ( qmark ) {
3638 newmask[j++] = '\0';
3640 retval = szWildCardMatchFileName(newmask, namep, casefold) ? 1:0;
3646 #else /* USE_OLD_MATCHING */
3647 /* do a case-folding search of the star name mask with the name in namep.
3648 * Return 1 if we match, otherwise 0.
3650 int smb_V3MatchMask(char *namep, char *maskp, int flags)
3652 unsigned char tcp1, tcp2; /* Pattern characters */
3653 unsigned char tcn1; /* Name characters */
3654 int sawDot = 0, sawStar = 0, req8dot3 = 0;
3655 char *starNamep, *starMaskp;
3656 static char nullCharp[] = {0};
3657 int casefold = flags & CM_FLAG_CASEFOLD;
3659 /* make sure we only match 8.3 names, if requested */
3660 req8dot3 = (flags & CM_FLAG_8DOT3);
3661 if (req8dot3 && !cm_Is8Dot3(namep))
3666 /* Next pattern character */
3669 /* Next name character */
3673 /* 0 - end of pattern */
3679 else if (tcp1 == '.' || tcp1 == '"') {
3689 * first dot in pattern;
3690 * must match dot or end of name
3695 else if (tcn1 == '.') {
3704 else if (tcp1 == '?') {
3705 if (tcn1 == 0 || tcn1 == '.')
3710 else if (tcp1 == '>') {
3711 if (tcn1 != 0 && tcn1 != '.')
3715 else if (tcp1 == '*' || tcp1 == '<') {
3719 else if ((req8dot3 && tcp2 == '.') || tcp2 == '"') {
3720 while (req8dot3 && tcn1 != '.' && tcn1 != 0)
3735 * pattern character after '*' is not null or
3736 * period. If it is '?' or '>', we are not
3737 * going to understand it. If it is '*' or
3738 * '<', we are going to skip over it. None of
3739 * these are likely, I hope.
3741 /* skip over '*' and '<' */
3742 while (tcp2 == '*' || tcp2 == '<')
3745 /* skip over characters that don't match tcp2 */
3746 while (req8dot3 && tcn1 != '.' && tcn1 != 0 &&
3747 ((casefold && cm_foldUpper[tcn1] != cm_foldUpper[tcp2]) ||
3748 (!casefold && tcn1 != tcp2)))
3752 if ((req8dot3 && tcn1 == '.') || tcn1 == 0)
3755 /* Remember where we are */
3765 /* tcp1 is not a wildcard */
3766 if ((casefold && cm_foldUpper[tcn1] == cm_foldUpper[tcp1]) ||
3767 (!casefold && tcn1 == tcp1)) {
3772 /* if trying to match a star pattern, go back */
3774 maskp = starMaskp - 2;
3775 namep = starNamep + 1;
3784 #endif /* USE_OLD_MATCHING */
3786 long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
3791 long code = 0, code2 = 0;
3795 smb_dirListPatch_t *dirListPatchesp;
3796 smb_dirListPatch_t *curPatchp;
3799 long orbytes; /* # of bytes in this output record */
3800 long ohbytes; /* # of bytes, except file name */
3801 long onbytes; /* # of bytes in name, incl. term. null */
3802 osi_hyper_t dirLength;
3803 osi_hyper_t bufferOffset;
3804 osi_hyper_t curOffset;
3806 smb_dirSearch_t *dsp;
3810 cm_pageHeader_t *pageHeaderp;
3811 cm_user_t *userp = NULL;
3814 long nextEntryCookie;
3815 int numDirChunks; /* # of 32 byte dir chunks in this entry */
3816 char *op; /* output data ptr */
3817 char *origOp; /* original value of op */
3818 cm_space_t *spacep; /* for pathname buffer */
3819 long maxReturnData; /* max # of return data */
3820 long maxReturnParms; /* max # of return parms */
3821 long bytesInBuffer; /* # data bytes in the output buffer */
3823 char *maskp; /* mask part of path */
3827 smb_tran2Packet_t *outp; /* response packet */
3830 char shortName[13]; /* 8.3 name if needed */
3841 if (p->opcode == 1) {
3842 /* find first; obtain basic parameters from request */
3843 attribute = p->parmsp[0];
3844 maxCount = p->parmsp[1];
3845 infoLevel = p->parmsp[3];
3846 searchFlags = p->parmsp[2];
3847 dsp = smb_NewDirSearch(1);
3848 dsp->attribute = attribute;
3849 pathp = ((char *) p->parmsp) + 12; /* points to path */
3850 if (smb_StoreAnsiFilenames)
3851 OemToChar(pathp,pathp);
3853 maskp = strrchr(pathp, '\\');
3857 maskp++; /* skip over backslash */
3858 strcpy(dsp->mask, maskp); /* and save mask */
3859 /* track if this is likely to match a lot of entries */
3860 starPattern = smb_V3IsStarMask(maskp);
3863 osi_assert(p->opcode == 2);
3864 /* find next; obtain basic parameters from request or open dir file */
3865 dsp = smb_FindDirSearch(p->parmsp[0]);
3866 maxCount = p->parmsp[1];
3867 infoLevel = p->parmsp[2];
3868 nextCookie = p->parmsp[3] | (p->parmsp[4] << 16);
3869 searchFlags = p->parmsp[5];
3871 osi_Log2(smb_logp, "T2 search dir bad search ID: id %d nextCookie 0x%x",
3872 p->parmsp[0], nextCookie);
3873 return CM_ERROR_BADFD;
3875 attribute = dsp->attribute;
3878 starPattern = 1; /* assume, since required a Find Next */
3882 "T2 search dir attr 0x%x, info level %d, max count %d, flags 0x%x",
3883 attribute, infoLevel, maxCount, searchFlags);
3885 osi_Log3(smb_logp, "...T2 search op %d, id %d, nextCookie 0x%x",
3886 p->opcode, dsp->cookie, nextCookie);
3888 if (infoLevel >= 0x101)
3889 searchFlags &= ~4; /* no resume keys */
3891 dirListPatchesp = NULL;
3893 maxReturnData = p->maxReturnData;
3894 if (p->opcode == 1) /* find first */
3895 maxReturnParms = 10; /* bytes */
3897 maxReturnParms = 8; /* bytes */
3899 #ifndef CM_CONFIG_MULTITRAN2RESPONSES
3900 if (maxReturnData > 6000)
3901 maxReturnData = 6000;
3902 #endif /* CM_CONFIG_MULTITRAN2RESPONSES */
3904 outp = smb_GetTran2ResponsePacket(vcp, p, opx, maxReturnParms,
3907 osi_Log2(smb_logp, "T2 receive search dir count %d [%s]",
3908 maxCount, osi_LogSaveString(smb_logp, pathp));
3910 /* bail out if request looks bad */
3911 if (p->opcode == 1 && !pathp) {
3912 smb_ReleaseDirSearch(dsp);
3913 smb_FreeTran2Packet(outp);
3914 return CM_ERROR_BADSMB;
3917 osi_Log3(smb_logp, "T2 search dir id %d, nextCookie 0x%x, attr 0x%x",
3918 dsp->cookie, nextCookie, attribute);
3920 userp = smb_GetTran2User(vcp, p);
3922 osi_Log1(smb_logp, "T2 search dir unable to resolve user [%d]", p->uid);
3923 smb_ReleaseDirSearch(dsp);
3924 smb_FreeTran2Packet(outp);
3925 return CM_ERROR_BADSMB;
3928 /* try to get the vnode for the path name next */
3929 lock_ObtainMutex(&dsp->mx);
3935 spacep = cm_GetSpace();
3936 smb_StripLastComponent(spacep->data, NULL, pathp);
3937 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
3939 cm_ReleaseUser(userp);
3940 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOFILES);
3941 smb_FreeTran2Packet(outp);
3942 lock_ReleaseMutex(&dsp->mx);
3943 smb_DeleteDirSearch(dsp);
3944 smb_ReleaseDirSearch(dsp);
3947 code = cm_NameI(cm_data.rootSCachep, spacep->data,
3948 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
3949 userp, tidPathp, &req, &scp);
3950 cm_FreeSpace(spacep);
3953 #ifdef DFS_SUPPORT_BUT_NOT_FIND_FIRST
3954 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
3955 cm_ReleaseSCache(scp);
3956 cm_ReleaseUser(userp);
3957 if ( WANTS_DFS_PATHNAMES(p) )
3958 code = CM_ERROR_PATH_NOT_COVERED;
3960 code = CM_ERROR_BADSHARENAME;
3961 smb_SendTran2Error(vcp, p, opx, code);
3962 smb_FreeTran2Packet(outp);
3963 lock_ReleaseMutex(&dsp->mx);
3964 smb_DeleteDirSearch(dsp);
3965 smb_ReleaseDirSearch(dsp);
3968 #endif /* DFS_SUPPORT */
3970 /* we need one hold for the entry we just stored into,
3971 * and one for our own processing. When we're done
3972 * with this function, we'll drop the one for our own
3973 * processing. We held it once from the namei call,
3974 * and so we do another hold now.
3977 lock_ObtainMutex(&scp->mx);
3978 if ((scp->flags & CM_SCACHEFLAG_BULKSTATTING) == 0 &&
3979 LargeIntegerGreaterOrEqualToZero(scp->bulkStatProgress)) {
3980 scp->flags |= CM_SCACHEFLAG_BULKSTATTING;
3981 dsp->flags |= SMB_DIRSEARCH_BULKST;
3983 lock_ReleaseMutex(&scp->mx);
3986 lock_ReleaseMutex(&dsp->mx);
3988 cm_ReleaseUser(userp);
3989 smb_FreeTran2Packet(outp);
3990 smb_DeleteDirSearch(dsp);
3991 smb_ReleaseDirSearch(dsp);
3995 /* get the directory size */
3996 lock_ObtainMutex(&scp->mx);
3997 code = cm_SyncOp(scp, NULL, userp, &req, 0,
3998 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4000 lock_ReleaseMutex(&scp->mx);
4001 cm_ReleaseSCache(scp);
4002 cm_ReleaseUser(userp);
4003 smb_FreeTran2Packet(outp);
4004 smb_DeleteDirSearch(dsp);
4005 smb_ReleaseDirSearch(dsp);
4010 dirLength = scp->length;
4012 bufferOffset.LowPart = bufferOffset.HighPart = 0;
4013 curOffset.HighPart = 0;
4014 curOffset.LowPart = nextCookie;
4015 origOp = outp->datap;
4023 if (searchFlags & 4)
4024 /* skip over resume key */
4027 /* make sure that curOffset.LowPart doesn't point to the first
4028 * 32 bytes in the 2nd through last dir page, and that it doesn't
4029 * point at the first 13 32-byte chunks in the first dir page,
4030 * since those are dir and page headers, and don't contain useful
4033 temp = curOffset.LowPart & (2048-1);
4034 if (curOffset.HighPart == 0 && curOffset.LowPart < 2048) {
4035 /* we're in the first page */
4036 if (temp < 13*32) temp = 13*32;
4039 /* we're in a later dir page */
4040 if (temp < 32) temp = 32;
4043 /* make sure the low order 5 bits are zero */
4046 /* now put temp bits back ito curOffset.LowPart */
4047 curOffset.LowPart &= ~(2048-1);
4048 curOffset.LowPart |= temp;
4050 /* check if we've passed the dir's EOF */
4051 if (LargeIntegerGreaterThanOrEqualTo(curOffset, dirLength)) {
4052 osi_Log0(smb_logp, "T2 search dir passed eof");
4057 /* check if we've returned all the names that will fit in the
4058 * response packet; we check return count as well as the number
4059 * of bytes requested. We check the # of bytes after we find
4060 * the dir entry, since we'll need to check its size.
4062 if (returnedNames >= maxCount) {
4063 osi_Log2(smb_logp, "T2 search dir returnedNames %d >= maxCount %d",
4064 returnedNames, maxCount);
4068 /* see if we can use the bufferp we have now; compute in which
4069 * page the current offset would be, and check whether that's
4070 * the offset of the buffer we have. If not, get the buffer.
4072 thyper.HighPart = curOffset.HighPart;
4073 thyper.LowPart = curOffset.LowPart & ~(cm_data.buf_blockSize-1);
4074 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
4077 buf_Release(bufferp);
4080 lock_ReleaseMutex(&scp->mx);
4081 lock_ObtainRead(&scp->bufCreateLock);
4082 code = buf_Get(scp, &thyper, &bufferp);
4083 lock_ReleaseRead(&scp->bufCreateLock);
4084 lock_ObtainMutex(&dsp->mx);
4086 /* now, if we're doing a star match, do bulk fetching
4087 * of all of the status info for files in the dir.
4090 smb_ApplyV3DirListPatches(scp, &dirListPatchesp,
4093 lock_ObtainMutex(&scp->mx);
4094 if ((dsp->flags & SMB_DIRSEARCH_BULKST) &&
4095 LargeIntegerGreaterThanOrEqualTo(thyper, scp->bulkStatProgress)) {
4096 /* Don't bulk stat if risking timeout */
4097 int now = GetCurrentTime();
4098 if (now - req.startTime > 5000) {
4099 scp->bulkStatProgress = thyper;
4100 scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
4101 dsp->flags &= ~SMB_DIRSEARCH_BULKST;
4103 cm_TryBulkStat(scp, &thyper, userp, &req);
4106 lock_ObtainMutex(&scp->mx);
4108 lock_ReleaseMutex(&dsp->mx);
4110 osi_Log2(smb_logp, "T2 search dir buf_Get scp %x failed %d", scp, code);
4114 bufferOffset = thyper;
4116 /* now get the data in the cache */
4118 code = cm_SyncOp(scp, bufferp, userp, &req,
4120 CM_SCACHESYNC_NEEDCALLBACK
4121 | CM_SCACHESYNC_READ);
4123 osi_Log2(smb_logp, "T2 search dir cm_SyncOp scp %x failed %d", scp, code);
4127 if (cm_HaveBuffer(scp, bufferp, 0)) {
4128 osi_Log2(smb_logp, "T2 search dir !HaveBuffer scp %x bufferp %x", scp, bufferp);
4132 /* otherwise, load the buffer and try again */
4133 code = cm_GetBuffer(scp, bufferp, NULL, userp,
4136 osi_Log3(smb_logp, "T2 search dir cm_GetBuffer failed scp %x bufferp %x code %d",
4137 scp, bufferp, code);
4142 buf_Release(bufferp);
4146 } /* if (wrong buffer) ... */
4148 /* now we have the buffer containing the entry we're interested
4149 * in; copy it out if it represents a non-deleted entry.
4151 entryInDir = curOffset.LowPart & (2048-1);
4152 entryInBuffer = curOffset.LowPart & (cm_data.buf_blockSize - 1);
4154 /* page header will help tell us which entries are free. Page
4155 * header can change more often than once per buffer, since
4156 * AFS 3 dir page size may be less than (but not more than)
4157 * a buffer package buffer.
4159 /* only look intra-buffer */
4160 temp = curOffset.LowPart & (cm_data.buf_blockSize - 1);
4161 temp &= ~(2048 - 1); /* turn off intra-page bits */
4162 pageHeaderp = (cm_pageHeader_t *) (bufferp->datap + temp);
4164 /* now determine which entry we're looking at in the page.
4165 * If it is free (there's a free bitmap at the start of the
4166 * dir), we should skip these 32 bytes.
4168 slotInPage = (entryInDir & 0x7e0) >> 5;
4169 if (!(pageHeaderp->freeBitmap[slotInPage>>3] &
4170 (1 << (slotInPage & 0x7)))) {
4171 /* this entry is free */
4172 numDirChunks = 1; /* only skip this guy */
4176 tp = bufferp->datap + entryInBuffer;
4177 dep = (cm_dirEntry_t *) tp; /* now points to AFS3 dir entry */
4179 /* while we're here, compute the next entry's location, too,
4180 * since we'll need it when writing out the cookie into the dir
4183 * XXXX Probably should do more sanity checking.
4185 numDirChunks = cm_NameEntries(dep->name, &onbytes);
4187 /* compute offset of cookie representing next entry */
4188 nextEntryCookie = curOffset.LowPart + (CM_DIR_CHUNKSIZE * numDirChunks);
4190 /* Need 8.3 name? */
4192 if (infoLevel == SMB_QUERY_FILE_NAME_INFO
4193 && dep->fid.vnode != 0
4194 && !cm_Is8Dot3(dep->name)) {
4195 cm_Gen8Dot3Name(dep, shortName, &shortNameEnd);
4199 osi_Log3(smb_logp, "T2 search dir vn %u name %s (%s)",
4200 dep->fid.vnode, osi_LogSaveString(smb_logp, dep->name),
4201 NeedShortName ? osi_LogSaveString(smb_logp, shortName) : "");
4203 /* When matching, we are using doing a case fold if we have a wildcard mask.
4204 * If we get a non-wildcard match, it's a lookup for a specific file.
4206 if (dep->fid.vnode != 0 &&
4207 (smb_V3MatchMask(dep->name, maskp, (starPattern? CM_FLAG_CASEFOLD : 0)) ||
4209 smb_V3MatchMask(shortName, maskp, CM_FLAG_CASEFOLD)))) {
4211 /* Eliminate entries that don't match requested attributes */
4212 if (smb_hideDotFiles && !(dsp->attribute & SMB_ATTR_HIDDEN) &&
4213 smb_IsDotFile(dep->name)) {
4214 osi_Log0(smb_logp, "T2 search dir skipping hidden");
4215 goto nextEntry; /* no hidden files */
4217 if (!(dsp->attribute & SMB_ATTR_DIRECTORY)) /* no directories */
4219 /* We have already done the cm_TryBulkStat above */
4220 fid.cell = scp->fid.cell;
4221 fid.volume = scp->fid.volume;
4222 fid.vnode = ntohl(dep->fid.vnode);
4223 fid.unique = ntohl(dep->fid.unique);
4224 fileType = cm_FindFileType(&fid);
4225 /*osi_Log2(smb_logp, "smb_ReceiveTran2SearchDir: file %s "
4226 "has filetype %d", dep->name,
4228 if (fileType == CM_SCACHETYPE_DIRECTORY ||
4229 fileType == CM_SCACHETYPE_DFSLINK ||
4230 fileType == CM_SCACHETYPE_INVALID)
4231 osi_Log0(smb_logp, "T2 search dir skipping directory or bad link");
4235 /* finally check if this name will fit */
4237 /* standard dir entry stuff */
4238 if (infoLevel < 0x101)
4239 ohbytes = 23; /* pre-NT */
4240 else if (infoLevel == SMB_QUERY_FILE_EA_INFO)
4241 ohbytes = 12; /* NT names only */
4243 ohbytes = 64; /* NT */
4245 if (infoLevel == SMB_QUERY_FILE_NAME_INFO)
4246 ohbytes += 26; /* Short name & length */
4248 if (searchFlags & 4) {
4249 ohbytes += 4; /* if resume key required */
4253 && infoLevel != 0x101
4254 && infoLevel != 0x103)
4255 ohbytes += 4; /* EASIZE */
4257 /* add header to name & term. null */
4258 orbytes = onbytes + ohbytes + 1;
4260 /* now, we round up the record to a 4 byte alignment,
4261 * and we make sure that we have enough room here for
4262 * even the aligned version (so we don't have to worry
4263 * about an * overflow when we pad things out below).
4264 * That's the reason for the alignment arithmetic below.
4266 if (infoLevel >= 0x101)
4267 align = (4 - (orbytes & 3)) & 3;
4270 if (orbytes + bytesInBuffer + align > maxReturnData) {
4271 osi_Log1(smb_logp, "T2 dir search exceed max return data %d",
4276 /* this is one of the entries to use: it is not deleted
4277 * and it matches the star pattern we're looking for.
4278 * Put out the name, preceded by its length.
4280 /* First zero everything else */
4281 memset(origOp, 0, ohbytes);
4283 if (infoLevel <= 0x101)
4284 *(origOp + ohbytes - 1) = (unsigned char) onbytes;
4285 else if (infoLevel == SMB_QUERY_FILE_EA_INFO)
4286 *((u_long *)(op + 8)) = onbytes;
4288 *((u_long *)(op + 60)) = onbytes;
4289 strcpy(origOp+ohbytes, dep->name);
4290 if (smb_StoreAnsiFilenames)
4291 CharToOem(origOp+ohbytes, origOp+ohbytes);
4293 /* Short name if requested and needed */
4294 if (infoLevel == SMB_QUERY_FILE_NAME_INFO) {
4295 if (NeedShortName) {
4296 strcpy(op + 70, shortName);
4297 if (smb_StoreAnsiFilenames)
4298 CharToOem(op + 70, op + 70);
4299 *(op + 68) = shortNameEnd - shortName;
4303 /* now, adjust the # of entries copied */
4306 /* NextEntryOffset and FileIndex */
4307 if (infoLevel >= 101) {
4308 int entryOffset = orbytes + align;
4309 *((u_long *)op) = entryOffset;
4310 *((u_long *)(op+4)) = nextEntryCookie;
4313 /* now we emit the attribute. This is tricky, since
4314 * we need to really stat the file to find out what
4315 * type of entry we've got. Right now, we're copying
4316 * out data from a buffer, while holding the scp
4317 * locked, so it isn't really convenient to stat
4318 * something now. We'll put in a place holder
4319 * now, and make a second pass before returning this
4320 * to get the real attributes. So, we just skip the
4321 * data for now, and adjust it later. We allocate a
4322 * patch record to make it easy to find this point
4323 * later. The replay will happen at a time when it is
4324 * safe to unlock the directory.
4326 if (infoLevel != 0x103) {
4327 curPatchp = malloc(sizeof(*curPatchp));
4328 osi_QAdd((osi_queue_t **) &dirListPatchesp,
4330 curPatchp->dptr = op;
4331 if (infoLevel >= 0x101)
4332 curPatchp->dptr += 8;
4334 if (smb_hideDotFiles && smb_IsDotFile(dep->name)) {
4335 curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
4338 curPatchp->flags = 0;
4340 curPatchp->fid.cell = scp->fid.cell;
4341 curPatchp->fid.volume = scp->fid.volume;
4342 curPatchp->fid.vnode = ntohl(dep->fid.vnode);
4343 curPatchp->fid.unique = ntohl(dep->fid.unique);
4346 curPatchp->dep = dep;
4349 if (searchFlags & 4)
4350 /* put out resume key */
4351 *((u_long *)origOp) = nextEntryCookie;
4353 /* Adjust byte ptr and count */
4354 origOp += orbytes; /* skip entire record */
4355 bytesInBuffer += orbytes;
4357 /* and pad the record out */
4358 while (--align >= 0) {
4362 } /* if we're including this name */
4363 else if (!starPattern &&
4365 dep->fid.vnode != 0 &&
4366 smb_V3MatchMask(dep->name, maskp, CM_FLAG_CASEFOLD)) {
4367 /* We were looking for exact matches, but here's an inexact one*/
4372 /* and adjust curOffset to be where the new cookie is */
4373 thyper.HighPart = 0;
4374 thyper.LowPart = CM_DIR_CHUNKSIZE * numDirChunks;
4375 curOffset = LargeIntegerAdd(thyper, curOffset);
4376 } /* while copying data for dir listing */
4378 /* If we didn't get a star pattern, we did an exact match during the first pass.
4379 * If there were no exact matches found, we fail over to inexact matches by
4380 * marking the query as a star pattern (matches all case permutations), and
4381 * re-running the query.
4383 if (returnedNames == 0 && !starPattern && foundInexact) {
4384 osi_Log0(afsd_logp,"T2 Search: No exact matches. Re-running for inexact matches");
4389 /* release the mutex */
4390 lock_ReleaseMutex(&scp->mx);
4392 buf_Release(bufferp);
4394 /* apply and free last set of patches; if not doing a star match, this
4395 * will be empty, but better safe (and freeing everything) than sorry.
4397 code2 = smb_ApplyV3DirListPatches(scp, &dirListPatchesp, infoLevel, userp,
4400 /* now put out the final parameters */
4401 if (returnedNames == 0)
4403 if (p->opcode == 1) {
4405 outp->parmsp[0] = (unsigned short) dsp->cookie;
4406 outp->parmsp[1] = returnedNames;
4407 outp->parmsp[2] = eos;
4408 outp->parmsp[3] = 0; /* nothing wrong with EAS */
4409 outp->parmsp[4] = 0;
4410 /* don't need last name to continue
4411 * search, cookie is enough. Normally,
4412 * this is the offset of the file name
4413 * of the last entry returned.
4415 outp->totalParms = 10; /* in bytes */
4419 outp->parmsp[0] = returnedNames;
4420 outp->parmsp[1] = eos;
4421 outp->parmsp[2] = 0; /* EAS error */
4422 outp->parmsp[3] = 0; /* last name, as above */
4423 outp->totalParms = 8; /* in bytes */
4426 /* return # of bytes in the buffer */
4427 outp->totalData = bytesInBuffer;
4429 /* Return error code if unsuccessful on first request */
4430 if (code == 0 && p->opcode == 1 && returnedNames == 0)
4431 code = CM_ERROR_NOSUCHFILE;
4433 osi_Log4(smb_logp, "T2 search dir done, opcode %d, id %d, %d names, code %d",
4434 p->opcode, dsp->cookie, returnedNames, code);
4436 /* if we're supposed to close the search after this request, or if
4437 * we're supposed to close the search if we're done, and we're done,
4438 * or if something went wrong, close the search.
4440 /* ((searchFlags & 1) || ((searchFlags & 2) && eos) */
4441 if ((searchFlags & 1) || (returnedNames == 0) ||
4442 ((searchFlags & 2) && eos) || code != 0)
4443 smb_DeleteDirSearch(dsp);
4445 smb_SendTran2Error(vcp, p, opx, code);
4447 smb_SendTran2Packet(vcp, outp, opx);
4449 smb_FreeTran2Packet(outp);
4450 smb_ReleaseDirSearch(dsp);
4451 cm_ReleaseSCache(scp);
4452 cm_ReleaseUser(userp);
4456 long smb_ReceiveV3FindClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4459 smb_dirSearch_t *dsp;
4461 dirHandle = smb_GetSMBParm(inp, 0);
4463 osi_Log1(smb_logp, "SMB3 find close handle %d", dirHandle);
4465 dsp = smb_FindDirSearch(dirHandle);
4468 return CM_ERROR_BADFD;
4470 /* otherwise, we have an FD to destroy */
4471 smb_DeleteDirSearch(dsp);
4472 smb_ReleaseDirSearch(dsp);
4474 /* and return results */
4475 smb_SetSMBDataLength(outp, 0);
4480 long smb_ReceiveV3FindNotifyClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4482 smb_SetSMBDataLength(outp, 0);
4486 long smb_ReceiveV3OpenX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4493 cm_scache_t *dscp; /* dir we're dealing with */
4494 cm_scache_t *scp; /* file we're creating */
4496 int initialModeBits;
4506 int parmSlot; /* which parm we're dealing with */
4514 extraInfo = (smb_GetSMBParm(inp, 2) & 1); /* return extra info */
4515 openFun = smb_GetSMBParm(inp, 8); /* open function */
4516 excl = ((openFun & 3) == 0);
4517 trunc = ((openFun & 3) == 2); /* truncate it */
4518 openMode = (smb_GetSMBParm(inp, 3) & 0x7);
4519 openAction = 0; /* tracks what we did */
4521 attributes = smb_GetSMBParm(inp, 5);
4522 dosTime = smb_GetSMBParm(inp, 6) | (smb_GetSMBParm(inp, 7) << 16);
4524 /* compute initial mode bits based on read-only flag in attributes */
4525 initialModeBits = 0666;
4526 if (attributes & 1) initialModeBits &= ~0222;
4528 pathp = smb_GetSMBData(inp, NULL);
4529 if (smb_StoreAnsiFilenames)
4530 OemToChar(pathp,pathp);
4532 spacep = inp->spacep;
4533 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
4535 if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
4536 /* special case magic file name for receiving IOCTL requests
4537 * (since IOCTL calls themselves aren't getting through).
4540 osi_Log0(smb_logp, "IOCTL Open");
4543 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
4544 smb_SetupIoctlFid(fidp, spacep);
4546 /* set inp->fid so that later read calls in same msg can find fid */
4547 inp->fid = fidp->fid;
4549 /* copy out remainder of the parms */
4551 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
4553 smb_SetSMBParm(outp, parmSlot, /* attrs */ 0); parmSlot++;
4554 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* mod time */
4555 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
4556 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* len */
4557 smb_SetSMBParm(outp, parmSlot, 0x7fff); parmSlot++;
4558 smb_SetSMBParm(outp, parmSlot, openMode); parmSlot++;
4559 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* file type 0 ==> normal file or dir */
4560 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* IPC junk */
4562 /* and the final "always present" stuff */
4563 smb_SetSMBParm(outp, parmSlot, /* openAction found existing file */ 1); parmSlot++;
4564 /* next write out the "unique" ID */
4565 smb_SetSMBParm(outp, parmSlot, 0x1234); parmSlot++;
4566 smb_SetSMBParm(outp, parmSlot, 0x5678); parmSlot++;
4567 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
4568 smb_SetSMBDataLength(outp, 0);
4570 /* and clean up fid reference */
4571 smb_ReleaseFID(fidp);
4575 #ifdef DEBUG_VERBOSE
4577 char *hexp, *asciip;
4578 asciip = (lastNamep ? lastNamep : pathp );
4579 hexp = osi_HexifyString(asciip);
4580 DEBUG_EVENT2("AFS", "V3Open H[%s] A[%s]", hexp, asciip );
4584 userp = smb_GetUser(vcp, inp);
4587 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4589 cm_ReleaseUser(userp);
4590 return CM_ERROR_NOSUCHPATH;
4592 code = cm_NameI(cm_data.rootSCachep, pathp,
4593 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
4594 userp, tidPathp, &req, &scp);
4597 if (code == 0 && scp->fileType == CM_SCACHETYPE_DFSLINK) {
4598 cm_ReleaseSCache(scp);
4599 cm_ReleaseUser(userp);
4600 if ( WANTS_DFS_PATHNAMES(inp) )
4601 return CM_ERROR_PATH_NOT_COVERED;
4603 return CM_ERROR_BADSHARENAME;
4605 #endif /* DFS_SUPPORT */
4608 code = cm_NameI(cm_data.rootSCachep, spacep->data,
4609 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
4610 userp, tidPathp, &req, &dscp);
4612 cm_ReleaseUser(userp);
4617 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
4618 cm_ReleaseSCache(dscp);
4619 cm_ReleaseUser(userp);
4620 if ( WANTS_DFS_PATHNAMES(inp) )
4621 return CM_ERROR_PATH_NOT_COVERED;
4623 return CM_ERROR_BADSHARENAME;
4625 #endif /* DFS_SUPPORT */
4627 /* otherwise, scp points to the parent directory. Do a lookup,
4628 * and truncate the file if we find it, otherwise we create the
4635 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD, userp,
4637 if (code && code != CM_ERROR_NOSUCHFILE) {
4638 cm_ReleaseSCache(dscp);
4639 cm_ReleaseUser(userp);
4644 /* if we get here, if code is 0, the file exists and is represented by
4645 * scp. Otherwise, we have to create it. The dir may be represented
4646 * by dscp, or we may have found the file directly. If code is non-zero,
4650 code = cm_CheckOpen(scp, openMode, trunc, userp, &req);
4652 if (dscp) cm_ReleaseSCache(dscp);
4653 cm_ReleaseSCache(scp);
4654 cm_ReleaseUser(userp);
4659 /* oops, file shouldn't be there */
4661 cm_ReleaseSCache(dscp);
4662 cm_ReleaseSCache(scp);
4663 cm_ReleaseUser(userp);
4664 return CM_ERROR_EXISTS;
4668 setAttr.mask = CM_ATTRMASK_LENGTH;
4669 setAttr.length.LowPart = 0;
4670 setAttr.length.HighPart = 0;
4671 code = cm_SetAttr(scp, &setAttr, userp, &req);
4672 openAction = 3; /* truncated existing file */
4674 else openAction = 1; /* found existing file */
4676 else if (!(openFun & SMB_ATTR_DIRECTORY)) {
4677 /* don't create if not found */
4678 if (dscp) cm_ReleaseSCache(dscp);
4679 cm_ReleaseUser(userp);
4680 return CM_ERROR_NOSUCHFILE;
4683 osi_assert(dscp != NULL);
4684 osi_Log1(smb_logp, "smb_ReceiveV3OpenX creating file %s",
4685 osi_LogSaveString(smb_logp, lastNamep));
4686 openAction = 2; /* created file */
4687 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
4688 smb_UnixTimeFromDosUTime(&setAttr.clientModTime, dosTime);
4689 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
4691 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
4692 smb_NotifyChange(FILE_ACTION_ADDED,
4693 FILE_NOTIFY_CHANGE_FILE_NAME,
4694 dscp, lastNamep, NULL, TRUE);
4695 if (!excl && code == CM_ERROR_EXISTS) {
4696 /* not an exclusive create, and someone else tried
4697 * creating it already, then we open it anyway. We
4698 * don't bother retrying after this, since if this next
4699 * fails, that means that the file was deleted after we
4700 * started this call.
4702 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
4706 setAttr.mask = CM_ATTRMASK_LENGTH;
4707 setAttr.length.LowPart = 0;
4708 setAttr.length.HighPart = 0;
4709 code = cm_SetAttr(scp, &setAttr, userp, &req);
4711 } /* lookup succeeded */
4715 /* we don't need this any longer */
4717 cm_ReleaseSCache(dscp);
4720 /* something went wrong creating or truncating the file */
4722 cm_ReleaseSCache(scp);
4723 cm_ReleaseUser(userp);
4727 /* make sure we're about to open a file */
4728 if (scp->fileType != CM_SCACHETYPE_FILE) {
4729 cm_ReleaseSCache(scp);
4730 cm_ReleaseUser(userp);
4731 return CM_ERROR_ISDIR;
4734 /* now all we have to do is open the file itself */
4735 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
4738 /* save a pointer to the vnode */
4741 /* compute open mode */
4743 fidp->flags |= SMB_FID_OPENREAD;
4744 if (openMode == 1 || openMode == 2)
4745 fidp->flags |= SMB_FID_OPENWRITE;
4747 smb_ReleaseFID(fidp);
4749 cm_Open(scp, 0, userp);
4751 /* set inp->fid so that later read calls in same msg can find fid */
4752 inp->fid = fidp->fid;
4754 /* copy out remainder of the parms */
4756 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
4757 lock_ObtainMutex(&scp->mx);
4759 smb_SetSMBParm(outp, parmSlot, smb_Attributes(scp)); parmSlot++;
4760 smb_DosUTimeFromUnixTime(&dosTime, scp->clientModTime);
4761 smb_SetSMBParm(outp, parmSlot, dosTime & 0xffff); parmSlot++;
4762 smb_SetSMBParm(outp, parmSlot, (dosTime>>16) & 0xffff); parmSlot++;
4763 smb_SetSMBParm(outp, parmSlot, scp->length.LowPart & 0xffff); parmSlot++;
4764 smb_SetSMBParm(outp, parmSlot, (scp->length.LowPart >> 16) & 0xffff); parmSlot++;
4765 smb_SetSMBParm(outp, parmSlot, openMode); parmSlot++;
4766 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* file type 0 ==> normal file or dir */
4767 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* IPC junk */
4769 /* and the final "always present" stuff */
4770 smb_SetSMBParm(outp, parmSlot, openAction); parmSlot++;
4771 /* next write out the "unique" ID */
4772 smb_SetSMBParm(outp, parmSlot, scp->fid.vnode & 0xffff); parmSlot++;
4773 smb_SetSMBParm(outp, parmSlot, scp->fid.volume & 0xffff); parmSlot++;
4774 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
4775 lock_ReleaseMutex(&scp->mx);
4776 smb_SetSMBDataLength(outp, 0);
4778 osi_Log1(smb_logp, "SMB OpenX opening fid %d", fidp->fid);
4780 cm_ReleaseUser(userp);
4781 /* leave scp held since we put it in fidp->scp */
4785 static void smb_GetLockParams(unsigned char LockType,
4787 unsigned int * ppid,
4788 LARGE_INTEGER * pOffset,
4789 LARGE_INTEGER * pLength)
4791 if (LockType & LOCKING_ANDX_LARGE_FILES) {
4793 *ppid = *((USHORT *) *buf);
4794 pOffset->HighPart = *((LONG *)(*buf + 4));
4795 pOffset->LowPart = *((DWORD *)(*buf + 8));
4796 pLength->HighPart = *((LONG *)(*buf + 12));
4797 pLength->LowPart = *((DWORD *)(*buf + 16));
4801 /* Not Large Files */
4802 *ppid = *((USHORT *) *buf);
4803 pOffset->HighPart = 0;
4804 pOffset->LowPart = *((DWORD *)(*buf + 2));
4805 pLength->HighPart = 0;
4806 pLength->LowPart = *((DWORD *)(*buf + 6));
4811 long smb_ReceiveV3LockingX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4818 unsigned char LockType;
4819 unsigned short NumberOfUnlocks, NumberOfLocks;
4823 LARGE_INTEGER LOffset, LLength;
4824 smb_waitingLockRequest_t *wlRequest = NULL;
4825 cm_file_lock_t *lockp;
4833 fid = smb_GetSMBParm(inp, 2);
4834 fid = smb_ChainFID(fid, inp);
4836 fidp = smb_FindFID(vcp, fid, 0);
4837 if (!fidp || (fidp->flags & SMB_FID_IOCTL)) {
4838 osi_Log0(smb_logp, "smb_ReceiveV3Locking BadFD");
4839 return CM_ERROR_BADFD;
4841 /* set inp->fid so that later read calls in same msg can find fid */
4844 userp = smb_GetUser(vcp, inp);
4848 lock_ObtainMutex(&scp->mx);
4849 code = cm_SyncOp(scp, NULL, userp, &req, 0,
4850 CM_SCACHESYNC_NEEDCALLBACK
4851 | CM_SCACHESYNC_GETSTATUS
4852 | CM_SCACHESYNC_LOCK);
4854 osi_Log1(smb_logp, "smb_ReceiveV3Locking SyncOp failure code 0x%x", code);
4858 LockType = smb_GetSMBParm(inp, 3) & 0xff;
4859 Timeout = (smb_GetSMBParm(inp, 5) << 16) + smb_GetSMBParm(inp, 4);
4860 NumberOfUnlocks = smb_GetSMBParm(inp, 6);
4861 NumberOfLocks = smb_GetSMBParm(inp, 7);
4863 if ((LockType & LOCKING_ANDX_CANCEL_LOCK) ||
4864 (LockType & LOCKING_ANDX_CHANGE_LOCKTYPE)) {
4866 /* We don't support these requests. Apparently, we can safely
4867 not deal with them too. */
4868 osi_Log1(smb_logp, "smb_ReceiveV3Locking received unsupported request [%s]",
4869 ((LockType & LOCKING_ANDX_CANCEL_LOCK)?
4870 "LOCKING_ANDX_CANCEL_LOCK":
4871 "LOCKING_ANDX_CHANGE_LOCKTYPE"));
4872 /* No need to call osi_LogSaveString since these are string
4875 code = CM_ERROR_BADOP;
4880 op = smb_GetSMBData(inp, NULL);
4882 for (i=0; i<NumberOfUnlocks; i++) {
4883 smb_GetLockParams(LockType, &op, &pid, &LOffset, &LLength);
4885 key = cm_GenerateKey(vcp->vcID, pid, fidp->fid);
4887 code = cm_Unlock(scp, LockType, LOffset, LLength, key, userp, &req);
4895 for (i=0; i<NumberOfLocks; i++) {
4896 smb_GetLockParams(LockType, &op, &pid, &LOffset, &LLength);
4898 key = cm_GenerateKey(vcp->vcID, pid, fidp->fid);
4900 code = cm_Lock(scp, LockType, LOffset, LLength, key, (Timeout != 0),
4901 userp, &req, &lockp);
4903 if (code == CM_ERROR_WOULDBLOCK && Timeout != 0) {
4904 smb_waitingLock_t * wLock;
4906 /* Put on waiting list */
4907 if(wlRequest == NULL) {
4911 LARGE_INTEGER tOffset, tLength;
4913 wlRequest = malloc(sizeof(smb_waitingLockRequest_t));
4915 osi_assert(wlRequest != NULL);
4917 wlRequest->vcp = vcp;
4919 wlRequest->scp = scp;
4921 wlRequest->inp = smb_CopyPacket(inp);
4922 wlRequest->outp = smb_CopyPacket(outp);
4923 wlRequest->lockType = LockType;
4924 wlRequest->timeRemaining = Timeout;
4925 wlRequest->locks = NULL;
4927 /* The waiting lock request needs to have enough
4928 information to undo all the locks in the request.
4929 We do the following to store info about locks that
4930 have already been granted. Sure, we can get most
4931 of the info from the packet, but the packet doesn't
4932 hold the result of cm_Lock call. In practice we
4933 only receive packets with one or two locks, so we
4934 are only wasting a few bytes here and there and
4935 only for a limited period of time until the waiting
4936 lock times out or is freed. */
4938 for(opt = op_locks, j=i; j > 0; j--) {
4939 smb_GetLockParams(LockType, &opt, &pid, &tOffset, &tLength);
4941 tkey = cm_GenerateKey(vcp->vcID, pid, fidp->fid);
4943 wLock = malloc(sizeof(smb_waitingLock_t));
4945 osi_assert(wLock != NULL);
4948 wLock->LOffset = tOffset;
4949 wLock->LLength = tLength;
4950 wLock->lockp = NULL;
4951 wLock->state = SMB_WAITINGLOCKSTATE_DONE;
4952 osi_QAdd((osi_queue_t **) &wlRequest->locks,
4957 wLock = malloc(sizeof(smb_waitingLock_t));
4959 osi_assert(wLock != NULL);
4962 wLock->LOffset = LOffset;
4963 wLock->LLength = LLength;
4964 wLock->lockp = lockp;
4965 wLock->state = SMB_WAITINGLOCKSTATE_WAITING;
4966 osi_QAdd((osi_queue_t **) &wlRequest->locks,
4969 osi_Log1(smb_logp, "smb_ReceiveV3Locking WaitingLock created 0x%x",
4977 osi_Log1(smb_logp, "smb_ReceiveV3Locking cm_Lock failure code 0x%x", code);
4984 /* Since something went wrong with the lock number i, we now
4985 have to go ahead and release any locks acquired before the
4986 failure. All locks before lock number i (of which there
4987 are i of them) have either been successful or are waiting.
4988 Either case requires calling cm_Unlock(). */
4990 /* And purge the waiting lock */
4991 if(wlRequest != NULL) {
4992 smb_waitingLock_t * wl;
4993 smb_waitingLock_t * wlNext;
4996 for(wl = wlRequest->locks; wl; wl = wlNext) {
4998 wlNext = (smb_waitingLock_t *) osi_QNext(&wl->q);
5000 ul_code = cm_Unlock(scp, LockType, wl->LOffset, wl->LLength, wl->key, userp, &req);
5003 osi_Log1(smb_logp, "smb_ReceiveV3Locking cm_Unlock returns code %d", ul_code);
5005 osi_Log0(smb_logp, "smb_ReceiveV3Locking cm_Unlock successful");
5008 osi_QRemove((osi_queue_t **) &wlRequest->locks, &wl->q);
5013 smb_ReleaseVC(wlRequest->vcp);
5014 cm_ReleaseSCache(wlRequest->scp);
5015 smb_FreePacket(wlRequest->inp);
5016 smb_FreePacket(wlRequest->outp);
5025 if (wlRequest != NULL) {
5027 lock_ObtainWrite(&smb_globalLock);
5028 osi_QAdd((osi_queue_t **)&smb_allWaitingLocks,
5030 osi_Wakeup((long) &smb_allWaitingLocks);
5031 lock_ReleaseWrite(&smb_globalLock);
5033 /* don't send reply immediately */
5034 outp->flags |= SMB_PACKETFLAG_NOSEND;
5037 smb_SetSMBDataLength(outp, 0);
5041 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_LOCK);
5044 lock_ReleaseMutex(&scp->mx);
5045 cm_ReleaseUser(userp);
5046 smb_ReleaseFID(fidp);
5051 long smb_ReceiveV3GetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5057 afs_uint32 searchTime;
5063 fid = smb_GetSMBParm(inp, 0);
5064 fid = smb_ChainFID(fid, inp);
5066 fidp = smb_FindFID(vcp, fid, 0);
5067 if (!fidp || (fidp->flags & SMB_FID_IOCTL)) {
5068 return CM_ERROR_BADFD;
5071 userp = smb_GetUser(vcp, inp);
5075 /* otherwise, stat the file */
5076 lock_ObtainMutex(&scp->mx);
5077 code = cm_SyncOp(scp, NULL, userp, &req, 0,
5078 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5079 if (code) goto done;
5081 /* decode times. We need a search time, but the response to this
5082 * call provides the date first, not the time, as returned in the
5083 * searchTime variable. So we take the high-order bits first.
5085 smb_SearchTimeFromUnixTime(&searchTime, scp->clientModTime);
5086 smb_SetSMBParm(outp, 0, (searchTime >> 16) & 0xffff); /* ctime */
5087 smb_SetSMBParm(outp, 1, searchTime & 0xffff);
5088 smb_SetSMBParm(outp, 2, (searchTime >> 16) & 0xffff); /* atime */
5089 smb_SetSMBParm(outp, 3, searchTime & 0xffff);
5090 smb_SetSMBParm(outp, 4, (searchTime >> 16) & 0xffff); /* mtime */
5091 smb_SetSMBParm(outp, 5, searchTime & 0xffff);
5093 /* now handle file size and allocation size */
5094 smb_SetSMBParm(outp, 6, scp->length.LowPart & 0xffff); /* file size */
5095 smb_SetSMBParm(outp, 7, (scp->length.LowPart >> 16) & 0xffff);
5096 smb_SetSMBParm(outp, 8, scp->length.LowPart & 0xffff); /* alloc size */
5097 smb_SetSMBParm(outp, 9, (scp->length.LowPart >> 16) & 0xffff);
5099 /* file attribute */
5100 smb_SetSMBParm(outp, 10, smb_Attributes(scp));
5102 /* and finalize stuff */
5103 smb_SetSMBDataLength(outp, 0);
5107 lock_ReleaseMutex(&scp->mx);
5108 cm_ReleaseUser(userp);
5109 smb_ReleaseFID(fidp);
5113 long smb_ReceiveV3SetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5119 afs_uint32 searchTime;
5127 fid = smb_GetSMBParm(inp, 0);
5128 fid = smb_ChainFID(fid, inp);
5130 fidp = smb_FindFID(vcp, fid, 0);
5131 if (!fidp || (fidp->flags & SMB_FID_IOCTL)) {
5132 return CM_ERROR_BADFD;
5135 userp = smb_GetUser(vcp, inp);
5139 /* now prepare to call cm_setattr. This message only sets various times,
5140 * and AFS only implements mtime, and we'll set the mtime if that's
5141 * requested. The others we'll ignore.
5143 searchTime = smb_GetSMBParm(inp, 5) | (smb_GetSMBParm(inp, 6) << 16);
5145 if (searchTime != 0) {
5146 smb_UnixTimeFromSearchTime(&unixTime, searchTime);
5148 if ( unixTime != -1 ) {
5149 attrs.mask = CM_ATTRMASK_CLIENTMODTIME;
5150 attrs.clientModTime = unixTime;
5151 code = cm_SetAttr(scp, &attrs, userp, &req);
5153 osi_Log1(smb_logp, "SMB receive V3SetAttributes [fid=%ld]", fid);
5155 osi_Log1(smb_logp, "**smb_UnixTimeFromSearchTime failed searchTime=%ld", searchTime);
5160 cm_ReleaseUser(userp);
5161 smb_ReleaseFID(fidp);
5166 long smb_ReceiveV3ReadX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5170 long finalCount = 0;
5179 fd = smb_GetSMBParm(inp, 2);
5180 count = smb_GetSMBParm(inp, 5);
5181 offset.HighPart = 0; /* too bad */
5182 offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
5184 osi_Log3(smb_logp, "smb_ReceiveV3Read fd %d, off 0x%x, size 0x%x",
5185 fd, offset.LowPart, count);
5187 fd = smb_ChainFID(fd, inp);
5188 fidp = smb_FindFID(vcp, fd, 0);
5190 return CM_ERROR_BADFD;
5193 pid = ((smb_t *) inp)->pid;
5194 key = cm_GenerateKey(vcp->vcID, pid, fd);
5196 LARGE_INTEGER LOffset, LLength;
5198 LOffset.HighPart = offset.HighPart;
5199 LOffset.LowPart = offset.LowPart;
5200 LLength.HighPart = 0;
5201 LLength.LowPart = count;
5203 lock_ObtainMutex(&fidp->scp->mx);
5204 code = cm_LockCheckRead(fidp->scp, LOffset, LLength, key);
5205 lock_ReleaseMutex(&fidp->scp->mx);
5209 smb_ReleaseFID(fidp);
5213 /* set inp->fid so that later read calls in same msg can find fid */
5216 if (fidp->flags & SMB_FID_IOCTL) {
5217 return smb_IoctlV3Read(fidp, vcp, inp, outp);
5220 userp = smb_GetUser(vcp, inp);
5222 /* 0 and 1 are reserved for request chaining, were setup by our caller,
5223 * and will be further filled in after we return.
5225 smb_SetSMBParm(outp, 2, 0); /* remaining bytes, for pipes */
5226 smb_SetSMBParm(outp, 3, 0); /* resvd */
5227 smb_SetSMBParm(outp, 4, 0); /* resvd */
5228 smb_SetSMBParm(outp, 5, count); /* # of bytes we're going to read */
5229 /* fill in #6 when we have all the parameters' space reserved */
5230 smb_SetSMBParm(outp, 7, 0); /* resv'd */
5231 smb_SetSMBParm(outp, 8, 0); /* resv'd */
5232 smb_SetSMBParm(outp, 9, 0); /* resv'd */
5233 smb_SetSMBParm(outp, 10, 0); /* resv'd */
5234 smb_SetSMBParm(outp, 11, 0); /* reserved */
5236 /* get op ptr after putting in the parms, since otherwise we don't
5237 * know where the data really is.
5239 op = smb_GetSMBData(outp, NULL);
5241 /* now fill in offset from start of SMB header to first data byte (to op) */
5242 smb_SetSMBParm(outp, 6, ((int) (op - outp->data)));
5244 /* set the packet data length the count of the # of bytes */
5245 smb_SetSMBDataLength(outp, count);
5248 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount);
5250 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount, FALSE);
5253 /* fix some things up */
5254 smb_SetSMBParm(outp, 5, finalCount);
5255 smb_SetSMBDataLength(outp, finalCount);
5257 smb_ReleaseFID(fidp);
5259 cm_ReleaseUser(userp);
5264 * Values for createDisp, copied from NTDDK.H
5266 #define FILE_SUPERSEDE 0 // (???)
5267 #define FILE_OPEN 1 // (open)
5268 #define FILE_CREATE 2 // (exclusive)
5269 #define FILE_OPEN_IF 3 // (non-exclusive)
5270 #define FILE_OVERWRITE 4 // (open & truncate, but do not create)
5271 #define FILE_OVERWRITE_IF 5 // (open & truncate, or create)
5274 #define REQUEST_OPLOCK 2
5275 #define REQUEST_BATCH_OPLOCK 4
5276 #define OPEN_DIRECTORY 8
5277 #define EXTENDED_RESPONSE_REQUIRED 0x10
5279 /* CreateOptions field. */
5280 #define FILE_DIRECTORY_FILE 0x0001
5281 #define FILE_WRITE_THROUGH 0x0002
5282 #define FILE_SEQUENTIAL_ONLY 0x0004
5283 #define FILE_NON_DIRECTORY_FILE 0x0040
5284 #define FILE_NO_EA_KNOWLEDGE 0x0200
5285 #define FILE_EIGHT_DOT_THREE_ONLY 0x0400
5286 #define FILE_RANDOM_ACCESS 0x0800
5287 #define FILE_DELETE_ON_CLOSE 0x1000
5288 #define FILE_OPEN_BY_FILE_ID 0x2000
5290 long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5292 char *pathp, *realPathp;
5296 cm_scache_t *dscp; /* parent dir */
5297 cm_scache_t *scp; /* file to create or open */
5298 cm_scache_t *targetScp; /* if scp is a symlink */
5302 unsigned short nameLength;
5304 unsigned int requestOpLock;
5305 unsigned int requestBatchOpLock;
5306 unsigned int mustBeDir;
5307 unsigned int extendedRespRequired;
5308 unsigned int treeCreate;
5310 unsigned int desiredAccess;
5311 unsigned int extAttributes;
5312 unsigned int createDisp;
5313 unsigned int createOptions;
5314 unsigned int shareAccess;
5315 int initialModeBits;
5316 unsigned short baseFid;
5317 smb_fid_t *baseFidp;
5319 cm_scache_t *baseDirp;
5320 unsigned short openAction;
5331 /* This code is very long and has a lot of if-then-else clauses
5332 * scp and dscp get reused frequently and we need to ensure that
5333 * we don't lose a reference. Start by ensuring that they are NULL.
5340 nameLength = smb_GetSMBOffsetParm(inp, 2, 1);
5341 flags = smb_GetSMBOffsetParm(inp, 3, 1)
5342 | (smb_GetSMBOffsetParm(inp, 4, 1) << 16);
5343 requestOpLock = flags & REQUEST_OPLOCK;
5344 requestBatchOpLock = flags & REQUEST_BATCH_OPLOCK;
5345 mustBeDir = flags & OPEN_DIRECTORY;
5346 extendedRespRequired = flags & EXTENDED_RESPONSE_REQUIRED;
5349 * Why all of a sudden 32-bit FID?
5350 * We will reject all bits higher than 16.
5352 if (smb_GetSMBOffsetParm(inp, 6, 1) != 0)
5353 return CM_ERROR_INVAL;
5354 baseFid = smb_GetSMBOffsetParm(inp, 5, 1);
5355 desiredAccess = smb_GetSMBOffsetParm(inp, 7, 1)
5356 | (smb_GetSMBOffsetParm(inp, 8, 1) << 16);
5357 extAttributes = smb_GetSMBOffsetParm(inp, 13, 1)
5358 | (smb_GetSMBOffsetParm(inp, 14, 1) << 16);
5359 shareAccess = smb_GetSMBOffsetParm(inp, 15, 1)
5360 | (smb_GetSMBOffsetParm(inp, 16, 1) << 16);
5361 createDisp = smb_GetSMBOffsetParm(inp, 17, 1)
5362 | (smb_GetSMBOffsetParm(inp, 18, 1) << 16);
5363 createOptions = smb_GetSMBOffsetParm(inp, 19, 1)
5364 | (smb_GetSMBOffsetParm(inp, 20, 1) << 16);
5366 /* mustBeDir is never set; createOptions directory bit seems to be
5369 if (createOptions & FILE_DIRECTORY_FILE)
5371 else if (createOptions & FILE_NON_DIRECTORY_FILE)
5377 * compute initial mode bits based on read-only flag in
5378 * extended attributes
5380 initialModeBits = 0666;
5381 if (extAttributes & SMB_ATTR_READONLY)
5382 initialModeBits &= ~0222;
5384 pathp = smb_GetSMBData(inp, NULL);
5385 /* Sometimes path is not null-terminated, so we make a copy. */
5386 realPathp = malloc(nameLength+1);
5387 memcpy(realPathp, pathp, nameLength);
5388 realPathp[nameLength] = 0;
5389 if (smb_StoreAnsiFilenames)
5390 OemToChar(realPathp,realPathp);
5392 spacep = inp->spacep;
5393 smb_StripLastComponent(spacep->data, &lastNamep, realPathp);
5395 osi_Log1(smb_logp,"NTCreateX for [%s]",osi_LogSaveString(smb_logp,realPathp));
5396 osi_Log4(smb_logp,"... da=[%x] ea=[%x] cd=[%x] co=[%x]", desiredAccess, extAttributes, createDisp, createOptions);
5397 osi_Log3(smb_logp,"... share=[%x] flags=[%x] lastNamep=[%s]", shareAccess, flags, osi_LogSaveString(smb_logp,(lastNamep?lastNamep:"null")));
5399 if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
5400 /* special case magic file name for receiving IOCTL requests
5401 * (since IOCTL calls themselves aren't getting through).
5403 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
5404 smb_SetupIoctlFid(fidp, spacep);
5405 osi_Log1(smb_logp,"NTCreateX Setting up IOCTL on fid[%d]",fidp->fid);
5407 /* set inp->fid so that later read calls in same msg can find fid */
5408 inp->fid = fidp->fid;
5412 smb_SetSMBParmByte(outp, parmSlot, 0); /* oplock */
5413 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
5414 smb_SetSMBParmLong(outp, parmSlot, 1); parmSlot += 2; /* Action */
5416 memset(&ft, 0, sizeof(ft));
5417 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
5418 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
5419 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
5420 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
5421 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2; /* attr */
5422 sz.HighPart = 0x7fff; sz.LowPart = 0;
5423 smb_SetSMBParmDouble(outp, parmSlot, (char *)&sz); parmSlot += 4; /* alen */
5424 smb_SetSMBParmDouble(outp, parmSlot, (char *)&sz); parmSlot += 4; /* len */
5425 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* filetype */
5426 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* dev state */
5427 smb_SetSMBParmByte(outp, parmSlot, 0); /* is a dir? */
5428 smb_SetSMBDataLength(outp, 0);
5430 /* clean up fid reference */
5431 smb_ReleaseFID(fidp);
5436 #ifdef DEBUG_VERBOSE
5438 char *hexp, *asciip;
5439 asciip = (lastNamep? lastNamep : realPathp);
5440 hexp = osi_HexifyString( asciip );
5441 DEBUG_EVENT2("AFS", "NTCreateX H[%s] A[%s]", hexp, asciip);
5446 userp = smb_GetUser(vcp, inp);
5448 osi_Log1(smb_logp, "NTCreateX Invalid user [%d]", ((smb_t *) inp)->uid);
5450 return CM_ERROR_INVAL;
5454 baseDirp = cm_data.rootSCachep;
5455 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5456 if (code == CM_ERROR_TIDIPC) {
5457 /* Attempt to use a TID allocated for IPC. The client
5458 * is probably looking for DCE RPC end points which we
5459 * don't support OR it could be looking to make a DFS
5462 osi_Log0(smb_logp, "NTCreateX received IPC TID");
5465 cm_ReleaseUser(userp);
5466 return CM_ERROR_NOSUCHFILE;
5467 #endif /* DFS_SUPPORT */
5470 baseFidp = smb_FindFID(vcp, baseFid, 0);
5472 osi_Log1(smb_logp, "NTCreateX Invalid base fid [%d]", baseFid);
5474 cm_ReleaseUser(userp);
5475 return CM_ERROR_INVAL;
5477 baseDirp = baseFidp->scp;
5481 osi_Log1(smb_logp, "NTCreateX tidPathp=[%s]", (tidPathp==NULL)?"null": osi_LogSaveString(smb_logp,tidPathp));
5483 /* compute open mode */
5485 if (desiredAccess & DELETE)
5486 fidflags |= SMB_FID_OPENDELETE;
5487 if (desiredAccess & AFS_ACCESS_READ)
5488 fidflags |= SMB_FID_OPENREAD;
5489 if (desiredAccess & AFS_ACCESS_WRITE)
5490 fidflags |= SMB_FID_OPENWRITE;
5491 if (createOptions & FILE_DELETE_ON_CLOSE)
5492 fidflags |= SMB_FID_DELONCLOSE;
5494 /* and the share mode */
5495 if (shareAccess & FILE_SHARE_READ)
5496 fidflags |= SMB_FID_SHARE_READ;
5497 if (shareAccess & FILE_SHARE_WRITE)
5498 fidflags |= SMB_FID_SHARE_WRITE;
5502 /* For an exclusive create, we want to do a case sensitive match for the last component. */
5503 if ( createDisp == FILE_CREATE ||
5504 createDisp == FILE_OVERWRITE ||
5505 createDisp == FILE_OVERWRITE_IF) {
5506 code = cm_NameI(baseDirp, spacep->data, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
5507 userp, tidPathp, &req, &dscp);
5510 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
5511 cm_ReleaseSCache(dscp);
5512 cm_ReleaseUser(userp);
5514 if ( WANTS_DFS_PATHNAMES(inp) )
5515 return CM_ERROR_PATH_NOT_COVERED;
5517 return CM_ERROR_BADSHARENAME;
5519 #endif /* DFS_SUPPORT */
5520 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp, CM_FLAG_FOLLOW,
5522 if (code == CM_ERROR_NOSUCHFILE) {
5523 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp,
5524 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, &req, &scp);
5525 if (code == 0 && realDirFlag == 1) {
5526 cm_ReleaseSCache(scp);
5527 cm_ReleaseSCache(dscp);
5528 cm_ReleaseUser(userp);
5530 return CM_ERROR_EXISTS;
5534 /* we have both scp and dscp */
5536 code = cm_NameI(baseDirp, realPathp, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
5537 userp, tidPathp, &req, &scp);
5539 if (code == 0 && scp->fileType == CM_SCACHETYPE_DFSLINK) {
5540 cm_ReleaseSCache(scp);
5541 cm_ReleaseUser(userp);
5543 if ( WANTS_DFS_PATHNAMES(inp) )
5544 return CM_ERROR_PATH_NOT_COVERED;
5546 return CM_ERROR_BADSHARENAME;
5548 #endif /* DFS_SUPPORT */
5549 /* we might have scp but not dscp */
5555 if (!foundscp || (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE))) {
5556 /* look up parent directory */
5557 /* If we are trying to create a path (i.e. multiple nested directories), then we don't *need*
5558 * the immediate parent. We have to work our way up realPathp until we hit something that we
5562 /* we might or might not have scp */
5568 code = cm_NameI(baseDirp, spacep->data,
5569 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
5570 userp, tidPathp, &req, &dscp);
5573 if (code == 0 && dscp->fileType == CM_SCACHETYPE_DFSLINK) {
5575 cm_ReleaseSCache(scp);
5576 cm_ReleaseSCache(dscp);
5577 cm_ReleaseUser(userp);
5579 if ( WANTS_DFS_PATHNAMES(inp) )
5580 return CM_ERROR_PATH_NOT_COVERED;
5582 return CM_ERROR_BADSHARENAME;
5584 #endif /* DFS_SUPPORT */
5587 (tp = strrchr(spacep->data,'\\')) &&
5588 (createDisp == FILE_CREATE) &&
5589 (realDirFlag == 1)) {
5592 treeStartp = realPathp + (tp - spacep->data);
5594 if (*tp && !smb_IsLegalFilename(tp)) {
5596 smb_ReleaseFID(baseFidp);
5597 cm_ReleaseUser(userp);
5600 cm_ReleaseSCache(scp);
5601 return CM_ERROR_BADNTFILENAME;
5605 } while (dscp == NULL && code == 0);
5609 /* we might have scp and we might have dscp */
5612 smb_ReleaseFID(baseFidp);
5615 osi_Log0(smb_logp,"NTCreateX parent not found");
5617 cm_ReleaseSCache(scp);
5619 cm_ReleaseSCache(dscp);
5620 cm_ReleaseUser(userp);
5625 if (treeCreate && dscp->fileType == CM_SCACHETYPE_FILE) {
5626 /* A file exists where we want a directory. */
5628 cm_ReleaseSCache(scp);
5629 cm_ReleaseSCache(dscp);
5630 cm_ReleaseUser(userp);
5632 return CM_ERROR_EXISTS;
5636 lastNamep = realPathp;
5640 if (!smb_IsLegalFilename(lastNamep)) {
5642 cm_ReleaseSCache(scp);
5644 cm_ReleaseSCache(dscp);
5645 cm_ReleaseUser(userp);
5647 return CM_ERROR_BADNTFILENAME;
5650 if (!foundscp && !treeCreate) {
5651 if ( createDisp == FILE_CREATE ||
5652 createDisp == FILE_OVERWRITE ||
5653 createDisp == FILE_OVERWRITE_IF)
5655 code = cm_Lookup(dscp, lastNamep,
5656 CM_FLAG_FOLLOW, userp, &req, &scp);
5658 code = cm_Lookup(dscp, lastNamep,
5659 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
5662 if (code && code != CM_ERROR_NOSUCHFILE) {
5664 cm_ReleaseSCache(dscp);
5665 cm_ReleaseUser(userp);
5670 /* we have scp and dscp */
5672 /* we have scp but not dscp */
5674 smb_ReleaseFID(baseFidp);
5677 /* if we get here, if code is 0, the file exists and is represented by
5678 * scp. Otherwise, we have to create it. The dir may be represented
5679 * by dscp, or we may have found the file directly. If code is non-zero,
5682 if (code == 0 && !treeCreate) {
5683 if (createDisp == FILE_CREATE) {
5684 /* oops, file shouldn't be there */
5686 cm_ReleaseSCache(dscp);
5688 cm_ReleaseSCache(scp);
5689 cm_ReleaseUser(userp);
5691 return CM_ERROR_EXISTS;
5694 if ( createDisp == FILE_OVERWRITE ||
5695 createDisp == FILE_OVERWRITE_IF) {
5697 setAttr.mask = CM_ATTRMASK_LENGTH;
5698 setAttr.length.LowPart = 0;
5699 setAttr.length.HighPart = 0;
5700 /* now watch for a symlink */
5702 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
5704 osi_assert(dscp != NULL);
5705 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
5707 /* we have a more accurate file to use (the
5708 * target of the symbolic link). Otherwise,
5709 * we'll just use the symlink anyway.
5711 osi_Log2(smb_logp, "symlink vp %x to vp %x",
5713 cm_ReleaseSCache(scp);
5717 code = cm_SetAttr(scp, &setAttr, userp, &req);
5718 openAction = 3; /* truncated existing file */
5721 openAction = 1; /* found existing file */
5723 code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp, &req);
5726 cm_ReleaseSCache(dscp);
5728 cm_ReleaseSCache(scp);
5729 cm_ReleaseUser(userp);
5733 } else if (createDisp == FILE_OPEN || createDisp == FILE_OVERWRITE) {
5734 /* don't create if not found */
5736 cm_ReleaseSCache(dscp);
5738 cm_ReleaseSCache(scp);
5739 cm_ReleaseUser(userp);
5741 return CM_ERROR_NOSUCHFILE;
5742 } else if (realDirFlag == 0 || realDirFlag == -1) {
5743 osi_assert(dscp != NULL);
5744 osi_Log1(smb_logp, "smb_ReceiveNTCreateX creating file %s",
5745 osi_LogSaveString(smb_logp, lastNamep));
5746 openAction = 2; /* created file */
5747 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
5748 setAttr.clientModTime = time(NULL);
5749 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp, &req);
5750 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
5751 smb_NotifyChange(FILE_ACTION_ADDED,
5752 FILE_NOTIFY_CHANGE_FILE_NAME,
5753 dscp, lastNamep, NULL, TRUE);
5754 if (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE) {
5755 /* Not an exclusive create, and someone else tried
5756 * creating it already, then we open it anyway. We
5757 * don't bother retrying after this, since if this next
5758 * fails, that means that the file was deleted after we
5759 * started this call.
5761 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
5764 if (createDisp == FILE_OVERWRITE_IF) {
5765 setAttr.mask = CM_ATTRMASK_LENGTH;
5766 setAttr.length.LowPart = 0;
5767 setAttr.length.HighPart = 0;
5769 /* now watch for a symlink */
5771 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
5773 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
5775 /* we have a more accurate file to use (the
5776 * target of the symbolic link). Otherwise,
5777 * we'll just use the symlink anyway.
5779 osi_Log2(smb_logp, "symlink vp %x to vp %x",
5781 cm_ReleaseSCache(scp);
5785 code = cm_SetAttr(scp, &setAttr, userp, &req);
5787 } /* lookup succeeded */
5791 char *cp; /* This component */
5792 int clen = 0; /* length of component */
5793 cm_scache_t *tscp1, *tscp2;
5796 /* create directory */
5798 treeStartp = lastNamep;
5799 osi_assert(dscp != NULL);
5800 osi_Log1(smb_logp, "smb_ReceiveNTCreateX creating directory [%s]",
5801 osi_LogSaveString(smb_logp, treeStartp));
5802 openAction = 2; /* created directory */
5804 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
5805 setAttr.clientModTime = time(NULL);
5810 cm_HoldSCache(tscp1);
5814 tp = strchr(pp, '\\');
5818 isLast = 1; /* indicate last component. the supplied path never ends in a slash */
5821 strncpy(cp,pp,clen);
5828 continue; /* the supplied path can't have consecutive slashes either , but */
5830 /* cp is the next component to be created. */
5831 code = cm_MakeDir(tscp1, cp, 0, &setAttr, userp, &req);
5832 if (code == 0 && (tscp1->flags & CM_SCACHEFLAG_ANYWATCH))
5833 smb_NotifyChange(FILE_ACTION_ADDED,
5834 FILE_NOTIFY_CHANGE_DIR_NAME,
5835 tscp1, cp, NULL, TRUE);
5837 (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE)) {
5838 /* Not an exclusive create, and someone else tried
5839 * creating it already, then we open it anyway. We
5840 * don't bother retrying after this, since if this next
5841 * fails, that means that the file was deleted after we
5842 * started this call.
5844 code = cm_Lookup(tscp1, cp, CM_FLAG_CASEFOLD,
5845 userp, &req, &tscp2);
5850 if (!isLast) { /* for anything other than dscp, release it unless it's the last one */
5851 cm_ReleaseSCache(tscp1);
5852 tscp1 = tscp2; /* Newly created directory will be next parent */
5853 /* the hold is transfered to tscp1 from tscp2 */
5858 cm_ReleaseSCache(dscp);
5861 cm_ReleaseSCache(scp);
5864 * if we get here and code == 0, then scp is the last directory created, and dscp is the
5870 /* something went wrong creating or truncating the file */
5872 cm_ReleaseSCache(scp);
5874 cm_ReleaseSCache(dscp);
5875 cm_ReleaseUser(userp);
5880 /* make sure we have file vs. dir right (only applies for single component case) */
5881 if (realDirFlag == 0 && scp->fileType != CM_SCACHETYPE_FILE) {
5882 /* now watch for a symlink */
5884 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
5885 cm_scache_t * targetScp = 0;
5886 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
5888 /* we have a more accurate file to use (the
5889 * target of the symbolic link). Otherwise,
5890 * we'll just use the symlink anyway.
5892 osi_Log2(smb_logp, "symlink vp %x to vp %x", scp, targetScp);
5893 cm_ReleaseSCache(scp);
5898 if (scp->fileType != CM_SCACHETYPE_FILE) {
5900 cm_ReleaseSCache(dscp);
5901 cm_ReleaseSCache(scp);
5902 cm_ReleaseUser(userp);
5904 return CM_ERROR_ISDIR;
5908 /* (only applies to single component case) */
5909 if (realDirFlag == 1 && scp->fileType == CM_SCACHETYPE_FILE) {
5910 cm_ReleaseSCache(scp);
5912 cm_ReleaseSCache(dscp);
5913 cm_ReleaseUser(userp);
5915 return CM_ERROR_NOTDIR;
5918 /* open the file itself */
5919 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
5922 /* If we are restricting sharing, we should do so with a suitable
5924 if (scp->fileType == CM_SCACHETYPE_FILE &&
5925 !(fidflags & SMB_FID_SHARE_WRITE)) {
5927 LARGE_INTEGER LOffset, LLength;
5930 LOffset.HighPart = SMB_FID_QLOCK_HIGH;
5931 LOffset.LowPart = SMB_FID_QLOCK_LOW;
5932 LLength.HighPart = 0;
5933 LLength.LowPart = SMB_FID_QLOCK_LENGTH;
5935 if (fidflags & SMB_FID_SHARE_READ) {
5936 sLockType = LOCKING_ANDX_SHARED_LOCK;
5941 key = cm_GenerateKey(vcp->vcID, SMB_FID_QLOCK_PID, fidp->fid);
5943 lock_ObtainMutex(&scp->mx);
5944 code = cm_Lock(scp, sLockType, LOffset, LLength, key, 0, userp, &req, NULL);
5945 lock_ReleaseMutex(&scp->mx);
5948 fidp->flags = SMB_FID_DELETE;
5949 smb_ReleaseFID(fidp);
5951 cm_ReleaseSCache(scp);
5953 cm_ReleaseSCache(dscp);
5954 cm_ReleaseUser(userp);
5957 return CM_ERROR_SHARING_VIOLATION;
5961 /* save a pointer to the vnode */
5962 fidp->scp = scp; /* Hold transfered to fidp->scp and no longer needed */
5964 fidp->flags = fidflags;
5966 /* save parent dir and pathname for delete or change notification */
5967 if (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE)) {
5968 fidp->flags |= SMB_FID_NTOPEN;
5969 fidp->NTopen_dscp = dscp;
5970 cm_HoldSCache(dscp);
5971 fidp->NTopen_pathp = strdup(lastNamep);
5973 fidp->NTopen_wholepathp = realPathp;
5975 /* we don't need this any longer */
5977 cm_ReleaseSCache(dscp);
5981 cm_Open(scp, 0, userp);
5983 /* set inp->fid so that later read calls in same msg can find fid */
5984 inp->fid = fidp->fid;
5988 lock_ObtainMutex(&scp->mx);
5989 smb_SetSMBParmByte(outp, parmSlot, 0); /* oplock */
5990 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
5991 smb_SetSMBParmLong(outp, parmSlot, openAction); parmSlot += 2;
5992 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
5993 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
5994 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
5995 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
5996 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
5997 smb_SetSMBParmLong(outp, parmSlot, smb_ExtAttributes(scp));
5999 smb_SetSMBParmDouble(outp, parmSlot, (char *)&scp->length); parmSlot += 4;
6000 smb_SetSMBParmDouble(outp, parmSlot, (char *)&scp->length); parmSlot += 4;
6001 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* filetype */
6002 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* dev state */
6003 smb_SetSMBParmByte(outp, parmSlot,
6004 scp->fileType == CM_SCACHETYPE_DIRECTORY); /* is a dir? */
6005 lock_ReleaseMutex(&scp->mx);
6006 smb_SetSMBDataLength(outp, 0);
6008 osi_Log2(smb_logp, "SMB NT CreateX opening fid %d path %s", fidp->fid,
6009 osi_LogSaveString(smb_logp, realPathp));
6011 smb_ReleaseFID(fidp);
6013 cm_ReleaseUser(userp);
6015 /* Can't free realPathp if we get here since
6016 fidp->NTopen_wholepathp is pointing there */
6018 /* leave scp held since we put it in fidp->scp */
6023 * A lot of stuff copied verbatim from NT Create&X to NT Tran Create.
6024 * Instead, ultimately, would like to use a subroutine for common code.
6026 long smb_ReceiveNTTranCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6028 char *pathp, *realPathp;
6032 cm_scache_t *dscp; /* parent dir */
6033 cm_scache_t *scp; /* file to create or open */
6034 cm_scache_t *targetScp; /* if scp is a symlink */
6037 unsigned long nameLength;
6039 unsigned int requestOpLock;
6040 unsigned int requestBatchOpLock;
6041 unsigned int mustBeDir;
6042 unsigned int extendedRespRequired;
6044 unsigned int desiredAccess;
6045 #ifdef DEBUG_VERBOSE
6046 unsigned int allocSize;
6048 unsigned int shareAccess;
6049 unsigned int extAttributes;
6050 unsigned int createDisp;
6051 #ifdef DEBUG_VERBOSE
6054 unsigned int createOptions;
6055 int initialModeBits;
6056 unsigned short baseFid;
6057 smb_fid_t *baseFidp;
6059 cm_scache_t *baseDirp;
6060 unsigned short openAction;
6066 int parmOffset, dataOffset;
6077 parmOffset = smb_GetSMBOffsetParm(inp, 11, 1)
6078 | (smb_GetSMBOffsetParm(inp, 12, 1) << 16);
6079 parmp = inp->data + parmOffset;
6080 lparmp = (ULONG *) parmp;
6083 requestOpLock = flags & REQUEST_OPLOCK;
6084 requestBatchOpLock = flags & REQUEST_BATCH_OPLOCK;
6085 mustBeDir = flags & OPEN_DIRECTORY;
6086 extendedRespRequired = flags & EXTENDED_RESPONSE_REQUIRED;
6089 * Why all of a sudden 32-bit FID?
6090 * We will reject all bits higher than 16.
6092 if (lparmp[1] & 0xFFFF0000)
6093 return CM_ERROR_INVAL;
6094 baseFid = (unsigned short)lparmp[1];
6095 desiredAccess = lparmp[2];
6096 #ifdef DEBUG_VERBOSE
6097 allocSize = lparmp[3];
6098 #endif /* DEBUG_VERSOSE */
6099 extAttributes = lparmp[5];
6100 shareAccess = lparmp[6];
6101 createDisp = lparmp[7];
6102 createOptions = lparmp[8];
6103 #ifdef DEBUG_VERBOSE
6106 nameLength = lparmp[11];
6108 #ifdef DEBUG_VERBOSE
6109 osi_Log4(smb_logp,"NTTranCreate with da[%x],ea[%x],sa[%x],cd[%x]",desiredAccess,extAttributes,shareAccess,createDisp);
6110 osi_Log3(smb_logp,"... co[%x],sdl[%x],as[%x]",createOptions,sdLen,allocSize);
6111 osi_Log1(smb_logp,"... flags[%x]",flags);
6114 /* mustBeDir is never set; createOptions directory bit seems to be
6117 if (createOptions & FILE_DIRECTORY_FILE)
6119 else if (createOptions & FILE_NON_DIRECTORY_FILE)
6125 * compute initial mode bits based on read-only flag in
6126 * extended attributes
6128 initialModeBits = 0666;
6129 if (extAttributes & 1)
6130 initialModeBits &= ~0222;
6132 pathp = parmp + (13 * sizeof(ULONG)) + sizeof(UCHAR);
6133 /* Sometimes path is not null-terminated, so we make a copy. */
6134 realPathp = malloc(nameLength+1);
6135 memcpy(realPathp, pathp, nameLength);
6136 realPathp[nameLength] = 0;
6137 if (smb_StoreAnsiFilenames)
6138 OemToChar(realPathp,realPathp);
6140 spacep = cm_GetSpace();
6141 smb_StripLastComponent(spacep->data, &lastNamep, realPathp);
6144 * Nothing here to handle SMB_IOCTL_FILENAME.
6145 * Will add it if necessary.
6148 #ifdef DEBUG_VERBOSE
6150 char *hexp, *asciip;
6151 asciip = (lastNamep? lastNamep : realPathp);
6152 hexp = osi_HexifyString( asciip );
6153 DEBUG_EVENT2("AFS", "NTTranCreate H[%s] A[%s]", hexp, asciip);
6158 userp = smb_GetUser(vcp, inp);
6160 osi_Log1(smb_logp, "NTTranCreate invalid user [%d]", ((smb_t *) inp)->uid);
6162 return CM_ERROR_INVAL;
6166 baseDirp = cm_data.rootSCachep;
6167 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
6168 if (code == CM_ERROR_TIDIPC) {
6169 /* Attempt to use a TID allocated for IPC. The client
6170 * is probably looking for DCE RPC end points which we
6171 * don't support OR it could be looking to make a DFS
6174 osi_Log0(smb_logp, "NTTranCreate received IPC TID");
6177 cm_ReleaseUser(userp);
6178 return CM_ERROR_NOSUCHPATH;
6182 baseFidp = smb_FindFID(vcp, baseFid, 0);
6184 osi_Log1(smb_logp, "NTTranCreate Invalid fid [%d]", baseFid);
6186 cm_ReleaseUser(userp);
6187 return CM_ERROR_INVAL;
6189 baseDirp = baseFidp->scp;
6193 /* compute open mode */
6195 if (desiredAccess & DELETE)
6196 fidflags |= SMB_FID_OPENDELETE;
6197 if (desiredAccess & AFS_ACCESS_READ)
6198 fidflags |= SMB_FID_OPENREAD;
6199 if (desiredAccess & AFS_ACCESS_WRITE)
6200 fidflags |= SMB_FID_OPENWRITE;
6201 if (createOptions & FILE_DELETE_ON_CLOSE)
6202 fidflags |= SMB_FID_DELONCLOSE;
6204 /* And the share mode */
6205 if (shareAccess & FILE_SHARE_READ)
6206 fidflags |= SMB_FID_SHARE_READ;
6207 if (shareAccess & FILE_SHARE_WRITE)
6208 fidflags |= SMB_FID_SHARE_WRITE;
6212 if ( createDisp == FILE_OPEN ||
6213 createDisp == FILE_OVERWRITE ||
6214 createDisp == FILE_OVERWRITE_IF) {
6215 code = cm_NameI(baseDirp, spacep->data, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
6216 userp, tidPathp, &req, &dscp);
6219 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
6220 cm_ReleaseSCache(dscp);
6221 cm_ReleaseUser(userp);
6223 if ( WANTS_DFS_PATHNAMES(inp) )
6224 return CM_ERROR_PATH_NOT_COVERED;
6226 return CM_ERROR_BADSHARENAME;
6228 #endif /* DFS_SUPPORT */
6229 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp, CM_FLAG_FOLLOW,
6231 if (code == CM_ERROR_NOSUCHFILE) {
6232 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp,
6233 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, &req, &scp);
6234 if (code == 0 && realDirFlag == 1) {
6235 cm_ReleaseSCache(scp);
6236 cm_ReleaseSCache(dscp);
6237 cm_ReleaseUser(userp);
6239 return CM_ERROR_EXISTS;
6245 code = cm_NameI(baseDirp, realPathp, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
6246 userp, tidPathp, &req, &scp);
6248 if (code == 0 && scp->fileType == CM_SCACHETYPE_DFSLINK) {
6249 cm_ReleaseSCache(scp);
6250 cm_ReleaseUser(userp);
6252 if ( WANTS_DFS_PATHNAMES(inp) )
6253 return CM_ERROR_PATH_NOT_COVERED;
6255 return CM_ERROR_BADSHARENAME;
6257 #endif /* DFS_SUPPORT */
6263 if (code != 0 || (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE))) {
6264 /* look up parent directory */
6266 code = cm_NameI(baseDirp, spacep->data,
6267 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
6268 userp, tidPathp, &req, &dscp);
6270 if (code == 0 && dscp->fileType == CM_SCACHETYPE_DFSLINK) {
6271 cm_ReleaseSCache(dscp);
6272 cm_ReleaseUser(userp);
6274 if ( WANTS_DFS_PATHNAMES(inp) )
6275 return CM_ERROR_PATH_NOT_COVERED;
6277 return CM_ERROR_BADSHARENAME;
6279 #endif /* DFS_SUPPORT */
6283 cm_FreeSpace(spacep);
6286 smb_ReleaseFID(baseFidp);
6291 cm_ReleaseUser(userp);
6296 if (!lastNamep) lastNamep = realPathp;
6299 if (!smb_IsLegalFilename(lastNamep))
6300 return CM_ERROR_BADNTFILENAME;
6303 if (createDisp == FILE_CREATE || createDisp == FILE_OVERWRITE_IF) {
6304 code = cm_Lookup(dscp, lastNamep,
6305 CM_FLAG_FOLLOW, userp, &req, &scp);
6307 code = cm_Lookup(dscp, lastNamep,
6308 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
6311 if (code && code != CM_ERROR_NOSUCHFILE) {
6312 cm_ReleaseSCache(dscp);
6313 cm_ReleaseUser(userp);
6320 smb_ReleaseFID(baseFidp);
6323 cm_FreeSpace(spacep);
6326 /* if we get here, if code is 0, the file exists and is represented by
6327 * scp. Otherwise, we have to create it. The dir may be represented
6328 * by dscp, or we may have found the file directly. If code is non-zero,
6332 code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp,
6336 cm_ReleaseSCache(dscp);
6337 cm_ReleaseSCache(scp);
6338 cm_ReleaseUser(userp);
6343 if (createDisp == FILE_CREATE) {
6344 /* oops, file shouldn't be there */
6346 cm_ReleaseSCache(dscp);
6347 cm_ReleaseSCache(scp);
6348 cm_ReleaseUser(userp);
6350 return CM_ERROR_EXISTS;
6353 if (createDisp == FILE_OVERWRITE ||
6354 createDisp == FILE_OVERWRITE_IF) {
6355 setAttr.mask = CM_ATTRMASK_LENGTH;
6356 setAttr.length.LowPart = 0;
6357 setAttr.length.HighPart = 0;
6359 /* now watch for a symlink */
6361 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
6363 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
6365 /* we have a more accurate file to use (the
6366 * target of the symbolic link). Otherwise,
6367 * we'll just use the symlink anyway.
6369 osi_Log2(smb_logp, "symlink vp %x to vp %x",
6371 cm_ReleaseSCache(scp);
6375 code = cm_SetAttr(scp, &setAttr, userp, &req);
6376 openAction = 3; /* truncated existing file */
6378 else openAction = 1; /* found existing file */
6380 else if (createDisp == FILE_OPEN || createDisp == FILE_OVERWRITE) {
6381 /* don't create if not found */
6383 cm_ReleaseSCache(dscp);
6384 cm_ReleaseUser(userp);
6386 return CM_ERROR_NOSUCHFILE;
6388 else if (realDirFlag == 0 || realDirFlag == -1) {
6389 osi_assert(dscp != NULL);
6390 osi_Log1(smb_logp, "smb_ReceiveNTTranCreate creating file %s",
6391 osi_LogSaveString(smb_logp, lastNamep));
6392 openAction = 2; /* created file */
6393 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
6394 setAttr.clientModTime = time(NULL);
6395 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
6397 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
6398 smb_NotifyChange(FILE_ACTION_ADDED,
6399 FILE_NOTIFY_CHANGE_FILE_NAME,
6400 dscp, lastNamep, NULL, TRUE);
6401 if (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE) {
6402 /* Not an exclusive create, and someone else tried
6403 * creating it already, then we open it anyway. We
6404 * don't bother retrying after this, since if this next
6405 * fails, that means that the file was deleted after we
6406 * started this call.
6408 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
6411 if (createDisp == FILE_OVERWRITE_IF) {
6412 setAttr.mask = CM_ATTRMASK_LENGTH;
6413 setAttr.length.LowPart = 0;
6414 setAttr.length.HighPart = 0;
6416 /* now watch for a symlink */
6418 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
6420 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
6422 /* we have a more accurate file to use (the
6423 * target of the symbolic link). Otherwise,
6424 * we'll just use the symlink anyway.
6426 osi_Log2(smb_logp, "symlink vp %x to vp %x",
6428 cm_ReleaseSCache(scp);
6432 code = cm_SetAttr(scp, &setAttr, userp, &req);
6434 } /* lookup succeeded */
6437 /* create directory */
6438 osi_assert(dscp != NULL);
6440 "smb_ReceiveNTTranCreate creating directory %s",
6441 osi_LogSaveString(smb_logp, lastNamep));
6442 openAction = 2; /* created directory */
6443 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
6444 setAttr.clientModTime = time(NULL);
6445 code = cm_MakeDir(dscp, lastNamep, 0, &setAttr, userp, &req);
6446 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
6447 smb_NotifyChange(FILE_ACTION_ADDED,
6448 FILE_NOTIFY_CHANGE_DIR_NAME,
6449 dscp, lastNamep, NULL, TRUE);
6451 (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE)) {
6452 /* Not an exclusive create, and someone else tried
6453 * creating it already, then we open it anyway. We
6454 * don't bother retrying after this, since if this next
6455 * fails, that means that the file was deleted after we
6456 * started this call.
6458 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
6464 /* something went wrong creating or truncating the file */
6466 cm_ReleaseSCache(scp);
6467 cm_ReleaseUser(userp);
6472 /* make sure we have file vs. dir right */
6473 if (realDirFlag == 0 && scp->fileType != CM_SCACHETYPE_FILE) {
6474 /* now watch for a symlink */
6476 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
6478 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
6480 /* we have a more accurate file to use (the
6481 * target of the symbolic link). Otherwise,
6482 * we'll just use the symlink anyway.
6484 osi_Log2(smb_logp, "symlink vp %x to vp %x",
6486 cm_ReleaseSCache(scp);
6491 if (scp->fileType != CM_SCACHETYPE_FILE) {
6492 cm_ReleaseSCache(scp);
6493 cm_ReleaseUser(userp);
6495 return CM_ERROR_ISDIR;
6499 if (realDirFlag == 1 && scp->fileType == CM_SCACHETYPE_FILE) {
6500 cm_ReleaseSCache(scp);
6501 cm_ReleaseUser(userp);
6503 return CM_ERROR_NOTDIR;
6506 /* open the file itself */
6507 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
6510 /* If we are restricting sharing, we should do so with a suitable
6512 if (scp->fileType == CM_SCACHETYPE_FILE &&
6513 !(fidflags & SMB_FID_SHARE_WRITE)) {
6515 LARGE_INTEGER LOffset, LLength;
6518 LOffset.HighPart = SMB_FID_QLOCK_HIGH;
6519 LOffset.LowPart = SMB_FID_QLOCK_LOW;
6520 LLength.HighPart = 0;
6521 LLength.LowPart = SMB_FID_QLOCK_LENGTH;
6523 if (fidflags & SMB_FID_SHARE_READ) {
6524 sLockType = LOCKING_ANDX_SHARED_LOCK;
6529 key = cm_GenerateKey(vcp->vcID, SMB_FID_QLOCK_PID, fidp->fid);
6531 lock_ObtainMutex(&scp->mx);
6532 code = cm_Lock(scp, sLockType, LOffset, LLength, key, 0, userp, &req, NULL);
6533 lock_ReleaseMutex(&scp->mx);
6536 fidp->flags = SMB_FID_DELETE;
6537 smb_ReleaseFID(fidp);
6539 cm_ReleaseSCache(scp);
6540 cm_ReleaseUser(userp);
6543 return CM_ERROR_SHARING_VIOLATION;
6547 /* save a pointer to the vnode */
6550 fidp->flags = fidflags;
6552 /* save parent dir and pathname for deletion or change notification */
6553 if (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE)) {
6554 fidp->flags |= SMB_FID_NTOPEN;
6555 fidp->NTopen_dscp = dscp;
6556 cm_HoldSCache(dscp);
6557 fidp->NTopen_pathp = strdup(lastNamep);
6559 fidp->NTopen_wholepathp = realPathp;
6561 /* we don't need this any longer */
6563 cm_ReleaseSCache(dscp);
6565 cm_Open(scp, 0, userp);
6567 /* set inp->fid so that later read calls in same msg can find fid */
6568 inp->fid = fidp->fid;
6570 /* check whether we are required to send an extended response */
6571 if (!extendedRespRequired) {
6573 parmOffset = 8*4 + 39;
6574 parmOffset += 1; /* pad to 4 */
6575 dataOffset = parmOffset + 70;
6579 /* Total Parameter Count */
6580 smb_SetSMBParmLong(outp, parmSlot, 70); parmSlot += 2;
6581 /* Total Data Count */
6582 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
6583 /* Parameter Count */
6584 smb_SetSMBParmLong(outp, parmSlot, 70); parmSlot += 2;
6585 /* Parameter Offset */
6586 smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
6587 /* Parameter Displacement */
6588 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
6590 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
6592 smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
6593 /* Data Displacement */
6594 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
6595 smb_SetSMBParmByte(outp, parmSlot, 0); /* Setup Count */
6596 smb_SetSMBDataLength(outp, 70);
6598 lock_ObtainMutex(&scp->mx);
6599 outData = smb_GetSMBData(outp, NULL);
6600 outData++; /* round to get to parmOffset */
6601 *outData = 0; outData++; /* oplock */
6602 *outData = 0; outData++; /* reserved */
6603 *((USHORT *)outData) = fidp->fid; outData += 2; /* fid */
6604 *((ULONG *)outData) = openAction; outData += 4;
6605 *((ULONG *)outData) = 0; outData += 4; /* EA error offset */
6606 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
6607 *((FILETIME *)outData) = ft; outData += 8; /* creation time */
6608 *((FILETIME *)outData) = ft; outData += 8; /* last access time */
6609 *((FILETIME *)outData) = ft; outData += 8; /* last write time */
6610 *((FILETIME *)outData) = ft; outData += 8; /* change time */
6611 *((ULONG *)outData) = smb_ExtAttributes(scp); outData += 4;
6612 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* alloc sz */
6613 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* EOF */
6614 *((USHORT *)outData) = 0; outData += 2; /* filetype */
6615 *((USHORT *)outData) = 0; outData += 2; /* dev state */
6616 *((USHORT *)outData) = (scp->fileType == CM_SCACHETYPE_DIRECTORY);
6617 outData += 2; /* is a dir? */
6618 lock_ReleaseMutex(&scp->mx);
6621 parmOffset = 8*4 + 39;
6622 parmOffset += 1; /* pad to 4 */
6623 dataOffset = parmOffset + 104;
6627 /* Total Parameter Count */
6628 smb_SetSMBParmLong(outp, parmSlot, 101); parmSlot += 2;
6629 /* Total Data Count */
6630 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
6631 /* Parameter Count */
6632 smb_SetSMBParmLong(outp, parmSlot, 101); parmSlot += 2;
6633 /* Parameter Offset */
6634 smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
6635 /* Parameter Displacement */
6636 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
6638 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
6640 smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
6641 /* Data Displacement */
6642 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
6643 smb_SetSMBParmByte(outp, parmSlot, 0); /* Setup Count */
6644 smb_SetSMBDataLength(outp, 105);
6646 lock_ObtainMutex(&scp->mx);
6647 outData = smb_GetSMBData(outp, NULL);
6648 outData++; /* round to get to parmOffset */
6649 *outData = 0; outData++; /* oplock */
6650 *outData = 1; outData++; /* response type */
6651 *((USHORT *)outData) = fidp->fid; outData += 2; /* fid */
6652 *((ULONG *)outData) = openAction; outData += 4;
6653 *((ULONG *)outData) = 0; outData += 4; /* EA error offset */
6654 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
6655 *((FILETIME *)outData) = ft; outData += 8; /* creation time */
6656 *((FILETIME *)outData) = ft; outData += 8; /* last access time */
6657 *((FILETIME *)outData) = ft; outData += 8; /* last write time */
6658 *((FILETIME *)outData) = ft; outData += 8; /* change time */
6659 *((ULONG *)outData) = smb_ExtAttributes(scp); outData += 4;
6660 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* alloc sz */
6661 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* EOF */
6662 *((USHORT *)outData) = 0; outData += 2; /* filetype */
6663 *((USHORT *)outData) = 0; outData += 2; /* dev state */
6664 *((USHORT *)outData) = (scp->fileType == CM_SCACHETYPE_DIRECTORY);
6665 outData += 1; /* is a dir? */
6666 memset(outData,0,24); outData += 24; /* Volume ID and file ID */
6667 *((ULONG *)outData) = 0x001f01ffL; outData += 4; /* Maxmimal access rights */
6668 *((ULONG *)outData) = 0; outData += 4; /* Guest Access rights */
6669 lock_ReleaseMutex(&scp->mx);
6672 osi_Log1(smb_logp, "SMB NTTranCreate opening fid %d", fidp->fid);
6674 smb_ReleaseFID(fidp);
6676 cm_ReleaseUser(userp);
6678 /* free(realPathp); Can't free realPathp here because fidp->NTopen_wholepathp points there */
6679 /* leave scp held since we put it in fidp->scp */
6683 long smb_ReceiveNTTranNotifyChange(smb_vc_t *vcp, smb_packet_t *inp,
6686 smb_packet_t *savedPacketp;
6687 ULONG filter; USHORT fid, watchtree;
6691 filter = smb_GetSMBParm(inp, 19) |
6692 (smb_GetSMBParm(inp, 20) << 16);
6693 fid = smb_GetSMBParm(inp, 21);
6694 watchtree = smb_GetSMBParm(inp, 22) && 0xffff; /* TODO: should this be 0xff ? */
6696 fidp = smb_FindFID(vcp, fid, 0);
6698 osi_Log1(smb_logp, "ERROR: NotifyChange given invalid fid [%d]", fid);
6699 return CM_ERROR_BADFD;
6702 savedPacketp = smb_CopyPacket(inp);
6704 savedPacketp->vcp = vcp;
6705 lock_ObtainMutex(&smb_Dir_Watch_Lock);
6706 savedPacketp->nextp = smb_Directory_Watches;
6707 smb_Directory_Watches = savedPacketp;
6708 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
6710 osi_Log4(smb_logp, "Request for NotifyChange filter 0x%x fid %d wtree %d file %s",
6711 filter, fid, watchtree, osi_LogSaveString(smb_logp, fidp->NTopen_wholepathp));
6714 lock_ObtainMutex(&scp->mx);
6716 scp->flags |= CM_SCACHEFLAG_WATCHEDSUBTREE;
6718 scp->flags |= CM_SCACHEFLAG_WATCHED;
6719 lock_ReleaseMutex(&scp->mx);
6720 smb_ReleaseFID(fidp);
6722 outp->flags |= SMB_PACKETFLAG_NOSEND;
6726 unsigned char nullSecurityDesc[36] = {
6727 0x01, /* security descriptor revision */
6728 0x00, /* reserved, should be zero */
6729 0x00, 0x80, /* security descriptor control;
6730 * 0x8000 : self-relative format */
6731 0x14, 0x00, 0x00, 0x00, /* offset of owner SID */
6732 0x1c, 0x00, 0x00, 0x00, /* offset of group SID */
6733 0x00, 0x00, 0x00, 0x00, /* offset of DACL would go here */
6734 0x00, 0x00, 0x00, 0x00, /* offset of SACL would go here */
6735 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
6736 /* "null SID" owner SID */
6737 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
6738 /* "null SID" group SID */
6741 long smb_ReceiveNTTranQuerySecurityDesc(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6743 int parmOffset, parmCount, dataOffset, dataCount;
6751 ULONG securityInformation;
6753 parmOffset = smb_GetSMBOffsetParm(inp, 11, 1)
6754 | (smb_GetSMBOffsetParm(inp, 12, 1) << 16);
6755 parmp = inp->data + parmOffset;
6756 sparmp = (USHORT *) parmp;
6757 lparmp = (ULONG *) parmp;
6760 securityInformation = lparmp[1];
6762 maxData = smb_GetSMBOffsetParm(inp, 7, 1)
6763 | (smb_GetSMBOffsetParm(inp, 8, 1) << 16);
6771 parmOffset = 8*4 + 39;
6772 parmOffset += 1; /* pad to 4 */
6774 dataOffset = parmOffset + parmCount;
6778 /* Total Parameter Count */
6779 smb_SetSMBParmLong(outp, parmSlot, parmCount); parmSlot += 2;
6780 /* Total Data Count */
6781 smb_SetSMBParmLong(outp, parmSlot, dataCount); parmSlot += 2;
6782 /* Parameter Count */
6783 smb_SetSMBParmLong(outp, parmSlot, parmCount); parmSlot += 2;
6784 /* Parameter Offset */
6785 smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
6786 /* Parameter Displacement */
6787 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
6789 smb_SetSMBParmLong(outp, parmSlot, dataCount); parmSlot += 2;
6791 smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
6792 /* Data Displacement */
6793 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
6794 smb_SetSMBParmByte(outp, parmSlot, 0); /* Setup Count */
6795 smb_SetSMBDataLength(outp, 1 + parmCount + dataCount);
6797 outData = smb_GetSMBData(outp, NULL);
6798 outData++; /* round to get to parmOffset */
6799 *((ULONG *)outData) = 36; outData += 4; /* length */
6801 if (maxData >= 36) {
6802 memcpy(outData, nullSecurityDesc, 36);
6806 return CM_ERROR_BUFFERTOOSMALL;
6809 long smb_ReceiveNTTransact(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6811 unsigned short function;
6813 function = smb_GetSMBParm(inp, 18);
6815 osi_Log1(smb_logp, "SMB NT Transact function %d", function);
6817 /* We can handle long names */
6818 if (vcp->flags & SMB_VCFLAG_USENT)
6819 ((smb_t *)outp)->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
6823 return smb_ReceiveNTTranQuerySecurityDesc(vcp, inp, outp);
6825 return smb_ReceiveNTTranNotifyChange(vcp, inp, outp);
6827 return smb_ReceiveNTTranCreate(vcp, inp, outp);
6829 return CM_ERROR_INVAL;
6834 * smb_NotifyChange -- find relevant change notification messages and
6837 * If we don't know the file name (i.e. a callback break), filename is
6838 * NULL, and we return a zero-length list.
6840 void smb_NotifyChange(DWORD action, DWORD notifyFilter,
6841 cm_scache_t *dscp, char *filename, char *otherFilename,
6842 BOOL isDirectParent)
6844 smb_packet_t *watch, *lastWatch, *nextWatch;
6845 ULONG parmSlot, parmCount, parmOffset, dataOffset, nameLen;
6846 char *outData, *oldOutData;
6850 BOOL twoEntries = FALSE;
6851 ULONG otherNameLen, oldParmCount = 0;
6856 /* Get ready for rename within directory */
6857 if (action == FILE_ACTION_RENAMED_OLD_NAME && otherFilename != NULL) {
6859 otherAction = FILE_ACTION_RENAMED_NEW_NAME;
6862 osi_Log2(smb_logp,"in smb_NotifyChange for file [%s] dscp [%x]",
6863 osi_LogSaveString(smb_logp,filename),dscp);
6865 lock_ObtainMutex(&smb_Dir_Watch_Lock);
6866 watch = smb_Directory_Watches;
6868 filter = smb_GetSMBParm(watch, 19)
6869 | (smb_GetSMBParm(watch, 20) << 16);
6870 fid = smb_GetSMBParm(watch, 21);
6871 wtree = smb_GetSMBParm(watch, 22) & 0xffff; /* TODO: should this be 0xff ? */
6872 maxLen = smb_GetSMBOffsetParm(watch, 5, 1)
6873 | (smb_GetSMBOffsetParm(watch, 6, 1) << 16);
6877 * Strange hack - bug in NT Client and NT Server that we
6880 if (filter == 3 && wtree)
6883 fidp = smb_FindFID(vcp, fid, 0);
6885 osi_Log1(smb_logp," no fidp for fid[%d]",fid);
6887 watch = watch->nextp;
6890 if (fidp->scp != dscp
6891 || (filter & notifyFilter) == 0
6892 || (!isDirectParent && !wtree)) {
6893 osi_Log1(smb_logp," passing fidp->scp[%x]", fidp->scp);
6894 smb_ReleaseFID(fidp);
6896 watch = watch->nextp;
6899 smb_ReleaseFID(fidp);
6902 "Sending Change Notification for fid %d filter 0x%x wtree %d file %s",
6903 fid, filter, wtree, osi_LogSaveString(smb_logp, filename));
6905 nextWatch = watch->nextp;
6906 if (watch == smb_Directory_Watches)
6907 smb_Directory_Watches = nextWatch;
6909 lastWatch->nextp = nextWatch;
6911 /* Turn off WATCHED flag in dscp */
6912 lock_ObtainMutex(&dscp->mx);
6914 dscp->flags &= ~CM_SCACHEFLAG_WATCHEDSUBTREE;
6916 dscp->flags &= ~CM_SCACHEFLAG_WATCHED;
6917 lock_ReleaseMutex(&dscp->mx);
6919 /* Convert to response packet */
6920 ((smb_t *) watch)->reb = SMB_FLAGS_SERVER_TO_CLIENT | SMB_FLAGS_CANONICAL_PATHNAMES;
6921 ((smb_t *) watch)->wct = 0;
6924 if (filename == NULL)
6927 nameLen = strlen(filename);
6928 parmCount = 3*4 + nameLen*2;
6929 parmCount = (parmCount + 3) & ~3; /* pad to 4 */
6931 otherNameLen = strlen(otherFilename);
6932 oldParmCount = parmCount;
6933 parmCount += 3*4 + otherNameLen*2;
6934 parmCount = (parmCount + 3) & ~3; /* pad to 4 */
6936 if (maxLen < parmCount)
6937 parmCount = 0; /* not enough room */
6939 parmOffset = 8*4 + 39;
6940 parmOffset += 1; /* pad to 4 */
6941 dataOffset = parmOffset + parmCount;
6945 /* Total Parameter Count */
6946 smb_SetSMBParmLong(watch, parmSlot, parmCount); parmSlot += 2;
6947 /* Total Data Count */
6948 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
6949 /* Parameter Count */
6950 smb_SetSMBParmLong(watch, parmSlot, parmCount); parmSlot += 2;
6951 /* Parameter Offset */
6952 smb_SetSMBParmLong(watch, parmSlot, parmOffset); parmSlot += 2;
6953 /* Parameter Displacement */
6954 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
6956 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
6958 smb_SetSMBParmLong(watch, parmSlot, dataOffset); parmSlot += 2;
6959 /* Data Displacement */
6960 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
6961 smb_SetSMBParmByte(watch, parmSlot, 0); /* Setup Count */
6962 smb_SetSMBDataLength(watch, parmCount + 1);
6964 if (parmCount != 0) {
6966 outData = smb_GetSMBData(watch, NULL);
6967 outData++; /* round to get to parmOffset */
6968 oldOutData = outData;
6969 *((DWORD *)outData) = oldParmCount; outData += 4;
6970 /* Next Entry Offset */
6971 *((DWORD *)outData) = action; outData += 4;
6973 *((DWORD *)outData) = nameLen*2; outData += 4;
6974 /* File Name Length */
6975 p = strdup(filename);
6976 if (smb_StoreAnsiFilenames)
6978 mbstowcs((WCHAR *)outData, p, nameLen);
6982 outData = oldOutData + oldParmCount;
6983 *((DWORD *)outData) = 0; outData += 4;
6984 /* Next Entry Offset */
6985 *((DWORD *)outData) = otherAction; outData += 4;
6987 *((DWORD *)outData) = otherNameLen*2;
6988 outData += 4; /* File Name Length */
6989 p = strdup(otherFilename);
6990 if (smb_StoreAnsiFilenames)
6992 mbstowcs((WCHAR *)outData, p, otherNameLen); /* File Name */
6998 * If filename is null, we don't know the cause of the
6999 * change notification. We return zero data (see above),
7000 * and set error code to NT_STATUS_NOTIFY_ENUM_DIR
7001 * (= 0x010C). We set the error code here by hand, without
7002 * modifying wct and bcc.
7004 if (filename == NULL) {
7005 ((smb_t *) watch)->rcls = 0x0C;
7006 ((smb_t *) watch)->reh = 0x01;
7007 ((smb_t *) watch)->errLow = 0;
7008 ((smb_t *) watch)->errHigh = 0;
7009 /* Set NT Status codes flag */
7010 ((smb_t *) watch)->flg2 |= SMB_FLAGS2_32BIT_STATUS;
7013 smb_SendPacket(vcp, watch);
7014 smb_FreePacket(watch);
7017 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
7020 long smb_ReceiveNTCancel(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7022 unsigned char *replyWctp;
7023 smb_packet_t *watch, *lastWatch;
7024 USHORT fid, watchtree;
7028 osi_Log0(smb_logp, "SMB3 receive NT cancel");
7030 lock_ObtainMutex(&smb_Dir_Watch_Lock);
7031 watch = smb_Directory_Watches;
7033 if (((smb_t *)watch)->uid == ((smb_t *)inp)->uid
7034 && ((smb_t *)watch)->pid == ((smb_t *)inp)->pid
7035 && ((smb_t *)watch)->mid == ((smb_t *)inp)->mid
7036 && ((smb_t *)watch)->tid == ((smb_t *)inp)->tid) {
7037 if (watch == smb_Directory_Watches)
7038 smb_Directory_Watches = watch->nextp;
7040 lastWatch->nextp = watch->nextp;
7041 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
7043 /* Turn off WATCHED flag in scp */
7044 fid = smb_GetSMBParm(watch, 21);
7045 watchtree = smb_GetSMBParm(watch, 22) & 0xffff;
7047 if (vcp != watch->vcp)
7048 osi_Log2(smb_logp, "smb_ReceiveNTCancel: vcp %x not equal to watch vcp %x",
7051 fidp = smb_FindFID(vcp, fid, 0);
7053 osi_Log3(smb_logp, "Cancelling change notification for fid %d wtree %d file %s",
7055 osi_LogSaveString(smb_logp, (fidp)?fidp->NTopen_wholepathp:""));
7058 lock_ObtainMutex(&scp->mx);
7060 scp->flags &= ~CM_SCACHEFLAG_WATCHEDSUBTREE;
7062 scp->flags &= ~CM_SCACHEFLAG_WATCHED;
7063 lock_ReleaseMutex(&scp->mx);
7064 smb_ReleaseFID(fidp);
7066 osi_Log2(smb_logp,"NTCancel unable to resolve fid [%d] in vcp[%x]", fid,vcp);
7069 /* assume STATUS32; return 0xC0000120 (CANCELED) */
7070 replyWctp = watch->wctp;
7074 ((smb_t *)watch)->rcls = 0x20;
7075 ((smb_t *)watch)->reh = 0x1;
7076 ((smb_t *)watch)->errLow = 0;
7077 ((smb_t *)watch)->errHigh = 0xC0;
7078 ((smb_t *)watch)->flg2 |= SMB_FLAGS2_32BIT_STATUS;
7079 smb_SendPacket(vcp, watch);
7080 smb_FreePacket(watch);
7084 watch = watch->nextp;
7086 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
7092 * NT rename also does hard links.
7095 #define RENAME_FLAG_MOVE_CLUSTER_INFORMATION 0x102
7096 #define RENAME_FLAG_HARD_LINK 0x103
7097 #define RENAME_FLAG_RENAME 0x104
7098 #define RENAME_FLAG_COPY 0x105
7100 long smb_ReceiveNTRename(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7102 char *oldPathp, *newPathp;
7108 attrs = smb_GetSMBParm(inp, 0);
7109 rename_type = smb_GetSMBParm(inp, 1);
7111 if (rename_type != RENAME_FLAG_RENAME && rename_type != RENAME_FLAG_HARD_LINK) {
7112 osi_Log1(smb_logp, "NTRename invalid infolevel [%x]", rename_type);
7113 return CM_ERROR_NOACCESS;
7116 tp = smb_GetSMBData(inp, NULL);
7117 oldPathp = smb_ParseASCIIBlock(tp, &tp);
7118 if (smb_StoreAnsiFilenames)
7119 OemToChar(oldPathp,oldPathp);
7120 newPathp = smb_ParseASCIIBlock(tp, &tp);
7121 if (smb_StoreAnsiFilenames)
7122 OemToChar(newPathp,newPathp);
7124 osi_Log3(smb_logp, "NTRename for [%s]->[%s] type [%s]",
7125 osi_LogSaveString(smb_logp, oldPathp),
7126 osi_LogSaveString(smb_logp, newPathp),
7127 ((rename_type==RENAME_FLAG_RENAME)?"rename":"hardlink"));
7129 if (rename_type == RENAME_FLAG_RENAME) {
7130 code = smb_Rename(vcp,inp,oldPathp,newPathp,attrs);
7131 } else { /* RENAME_FLAG_HARD_LINK */
7132 code = smb_Link(vcp,inp,oldPathp,newPathp);
7139 lock_InitializeMutex(&smb_Dir_Watch_Lock, "Directory Watch List Lock");
7142 cm_user_t *smb_FindCMUserByName(/*smb_vc_t *vcp,*/ char *usern, char *machine)
7145 smb_username_t *unp;
7147 unp = smb_FindUserByName(usern, machine, SMB_FLAG_CREATE);
7149 lock_ObtainMutex(&unp->mx);
7150 unp->userp = cm_NewUser();
7151 lock_ReleaseMutex(&unp->mx);
7152 osi_Log2(smb_logp,"smb_FindCMUserByName New user name[%s] machine[%s]",osi_LogSaveString(smb_logp,usern),osi_LogSaveString(smb_logp,machine));
7153 osi_LogEvent("AFS smb_FindCMUserByName : New User",NULL,"name[%s] machine[%s]",usern,machine);
7155 osi_Log2(smb_logp,"smb_FindCMUserByName Not found name[%s] machine[%s]",osi_LogSaveString(smb_logp,usern),osi_LogSaveString(smb_logp,machine));
7156 osi_LogEvent("AFS smb_FindCMUserByName : Found",NULL,"name[%s] machine[%s]",usern,machine);