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);
1383 osi_LogEvent("AFS-Dispatch-RAP return",myCrt_RapDispatch(rapOp),"Code 0x%x",code);
1384 osi_Log4(smb_logp,"AFS Server - Dispatch-RAP return code 0x%x vcp[%x] lana[%d] lsn[%d]",code,vcp,vcp->lana,vcp->lsn);
1387 osi_LogEvent("AFS-Dispatch-RAP [invalid]", NULL, "op[%x] vcp[%x] lana[%d] lsn[%d]", rapOp, vcp, vcp->lana, vcp->lsn);
1388 osi_Log4(smb_logp,"AFS Server - Dispatch-RAP [INVALID] op[%x] vcp[%x] lana[%d] lsn[%d]", rapOp, vcp, vcp->lana, vcp->lsn);
1389 code = CM_ERROR_BADOP;
1392 /* if an error is returned, we're supposed to send an error packet,
1393 * otherwise the dispatched function already did the data sending.
1394 * We give dispatched proc the responsibility since it knows how much
1395 * space to allocate.
1398 smb_SendTran2Error(vcp, asp, outp, code);
1401 /* free the input tran 2 packet */
1402 lock_ObtainWrite(&smb_globalLock);
1403 smb_FreeTran2Packet(asp);
1404 lock_ReleaseWrite(&smb_globalLock);
1406 else if (firstPacket) {
1407 /* the first packet in a multi-packet request, we need to send an
1408 * ack to get more data.
1410 smb_SetSMBDataLength(outp, 0);
1411 smb_SendPacket(vcp, outp);
1417 /* ANSI versions. The unicode versions support arbitrary length
1418 share names, but we don't support unicode yet. */
1420 typedef struct smb_rap_share_info_0 {
1421 char shi0_netname[13];
1422 } smb_rap_share_info_0_t;
1424 typedef struct smb_rap_share_info_1 {
1425 char shi1_netname[13];
1428 DWORD shi1_remark; /* char *shi1_remark; data offset */
1429 } smb_rap_share_info_1_t;
1431 typedef struct smb_rap_share_info_2 {
1432 char shi2_netname[13];
1434 unsigned short shi2_type;
1435 DWORD shi2_remark; /* char *shi2_remark; data offset */
1436 unsigned short shi2_permissions;
1437 unsigned short shi2_max_uses;
1438 unsigned short shi2_current_uses;
1439 DWORD shi2_path; /* char *shi2_path; data offset */
1440 unsigned short shi2_passwd[9];
1441 unsigned short shi2_pad2;
1442 } smb_rap_share_info_2_t;
1444 #define SMB_RAP_MAX_SHARES 512
1446 typedef struct smb_rap_share_list {
1449 smb_rap_share_info_0_t * shares;
1450 } smb_rap_share_list_t;
1452 int smb_rapCollectSharesProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp) {
1453 smb_rap_share_list_t * sp;
1458 if (name[0] == '.' && (!name[1] || (name[1] == '.' && !name[2])))
1459 return 0; /* skip over '.' and '..' */
1461 sp = (smb_rap_share_list_t *) vrockp;
1463 strncpy(sp->shares[sp->cShare].shi0_netname, name, 12);
1464 sp->shares[sp->cShare].shi0_netname[12] = 0;
1468 if (sp->cShare >= sp->maxShares)
1469 return CM_ERROR_STOPNOW;
1474 long smb_ReceiveRAPNetShareEnum(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1476 smb_tran2Packet_t *outp;
1477 unsigned short * tp;
1481 int outParmsTotal; /* total parameter bytes */
1482 int outDataTotal; /* total data bytes */
1490 HKEY hkSubmount = NULL;
1491 smb_rap_share_info_1_t * shares;
1494 char thisShare[256];
1497 smb_rap_share_list_t rootShares;
1502 tp = p->parmsp + 1; /* skip over function number (always 0) */
1503 (void) smb_ParseString((char *) tp, (char **) &tp); /* skip over parm descriptor */
1504 (void) smb_ParseString((char *) tp, (char **) &tp); /* skip over data descriptor */
1508 if (infoLevel != 1) {
1509 return CM_ERROR_INVAL;
1512 /* first figure out how many shares there are */
1513 rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY, 0,
1514 KEY_QUERY_VALUE, &hkParam);
1515 if (rv == ERROR_SUCCESS) {
1516 len = sizeof(allSubmount);
1517 rv = RegQueryValueEx(hkParam, "AllSubmount", NULL, NULL,
1518 (BYTE *) &allSubmount, &len);
1519 if (rv != ERROR_SUCCESS || allSubmount != 0) {
1522 RegCloseKey (hkParam);
1525 rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_OPENAFS_SUBKEY "\\Submounts",
1526 0, KEY_QUERY_VALUE, &hkSubmount);
1527 if (rv == ERROR_SUCCESS) {
1528 rv = RegQueryInfoKey(hkSubmount, NULL, NULL, NULL, NULL,
1529 NULL, NULL, &nRegShares, NULL, NULL, NULL, NULL);
1530 if (rv != ERROR_SUCCESS)
1536 /* fetch the root shares */
1537 rootShares.maxShares = SMB_RAP_MAX_SHARES;
1538 rootShares.cShare = 0;
1539 rootShares.shares = malloc( sizeof(smb_rap_share_info_0_t) * SMB_RAP_MAX_SHARES );
1543 userp = smb_GetTran2User(vcp,p);
1545 thyper.HighPart = 0;
1548 cm_HoldSCache(cm_data.rootSCachep);
1549 cm_ApplyDir(cm_data.rootSCachep, smb_rapCollectSharesProc, &rootShares, &thyper, userp, &req, NULL);
1550 cm_ReleaseSCache(cm_data.rootSCachep);
1552 cm_ReleaseUser(userp);
1554 nShares = rootShares.cShare + nRegShares + allSubmount;
1556 #define REMARK_LEN 1
1557 outParmsTotal = 8; /* 4 dwords */
1558 outDataTotal = (sizeof(smb_rap_share_info_1_t) + REMARK_LEN) * nShares ;
1559 if(outDataTotal > bufsize) {
1560 nSharesRet = bufsize / (sizeof(smb_rap_share_info_1_t) + REMARK_LEN);
1561 outDataTotal = (sizeof(smb_rap_share_info_1_t) + REMARK_LEN) * nSharesRet;
1564 nSharesRet = nShares;
1567 outp = smb_GetTran2ResponsePacket(vcp, p, op, outParmsTotal, outDataTotal);
1569 /* now for the submounts */
1570 shares = (smb_rap_share_info_1_t *) outp->datap;
1571 cstrp = outp->datap + sizeof(smb_rap_share_info_1_t) * nSharesRet;
1573 memset(outp->datap, 0, (sizeof(smb_rap_share_info_1_t) + REMARK_LEN) * nSharesRet);
1576 strcpy( shares[cshare].shi1_netname, "all" );
1577 shares[cshare].shi1_remark = cstrp - outp->datap;
1578 /* type and pad are zero already */
1584 for (i=0; i < nRegShares && cshare < nSharesRet; i++) {
1585 len = sizeof(thisShare);
1586 rv = RegEnumValue(hkSubmount, i, thisShare, &len, NULL, NULL, NULL, NULL);
1587 if (rv == ERROR_SUCCESS && strlen(thisShare) && (!allSubmount || stricmp(thisShare,"all"))) {
1588 strncpy(shares[cshare].shi1_netname, thisShare, sizeof(shares->shi1_netname)-1);
1589 shares[cshare].shi1_netname[sizeof(shares->shi1_netname)-1] = 0; /* unfortunate truncation */
1590 shares[cshare].shi1_remark = cstrp - outp->datap;
1595 nShares--; /* uncount key */
1598 RegCloseKey(hkSubmount);
1601 nonrootShares = cshare;
1603 for (i=0; i < rootShares.cShare && cshare < nSharesRet; i++) {
1604 /* in case there are collisions with submounts, submounts have higher priority */
1605 for (j=0; j < nonrootShares; j++)
1606 if (!stricmp(shares[j].shi1_netname, rootShares.shares[i].shi0_netname))
1609 if (j < nonrootShares) {
1610 nShares--; /* uncount */
1614 strcpy(shares[cshare].shi1_netname, rootShares.shares[i].shi0_netname);
1615 shares[cshare].shi1_remark = cstrp - outp->datap;
1620 outp->parmsp[0] = ((cshare == nShares)? ERROR_SUCCESS : ERROR_MORE_DATA);
1621 outp->parmsp[1] = 0;
1622 outp->parmsp[2] = cshare;
1623 outp->parmsp[3] = nShares;
1625 outp->totalData = cstrp - outp->datap;
1626 outp->totalParms = outParmsTotal;
1628 smb_SendTran2Packet(vcp, outp, op);
1629 smb_FreeTran2Packet(outp);
1631 free(rootShares.shares);
1636 long smb_ReceiveRAPNetShareGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1638 smb_tran2Packet_t *outp;
1639 unsigned short * tp;
1641 BOOL shareFound = FALSE;
1642 unsigned short infoLevel;
1643 unsigned short bufsize;
1653 tp = p->parmsp + 1; /* skip over function number (always 1) */
1654 (void) smb_ParseString( (char *) tp, (char **) &tp); /* skip over param descriptor */
1655 (void) smb_ParseString( (char *) tp, (char **) &tp); /* skip over data descriptor */
1656 shareName = smb_ParseString( (char *) tp, (char **) &tp);
1663 totalData = sizeof(smb_rap_share_info_0_t);
1664 else if(infoLevel == SMB_INFO_STANDARD)
1665 totalData = sizeof(smb_rap_share_info_1_t) + 1; /* + empty string */
1666 else if(infoLevel == SMB_INFO_QUERY_EA_SIZE)
1667 totalData = sizeof(smb_rap_share_info_2_t) + 2; /* + two empty strings */
1669 return CM_ERROR_INVAL;
1671 outp = smb_GetTran2ResponsePacket(vcp, p, op, totalParam, totalData);
1673 if(!stricmp(shareName,"all")) {
1674 rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY, 0,
1675 KEY_QUERY_VALUE, &hkParam);
1676 if (rv == ERROR_SUCCESS) {
1677 len = sizeof(allSubmount);
1678 rv = RegQueryValueEx(hkParam, "AllSubmount", NULL, NULL,
1679 (BYTE *) &allSubmount, &len);
1680 if (rv != ERROR_SUCCESS || allSubmount != 0) {
1683 RegCloseKey (hkParam);
1690 rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY "\\Submounts", 0,
1691 KEY_QUERY_VALUE, &hkSubmount);
1692 if (rv == ERROR_SUCCESS) {
1693 rv = RegQueryValueEx(hkSubmount, shareName, NULL, NULL, NULL, NULL);
1694 if (rv == ERROR_SUCCESS) {
1697 RegCloseKey(hkSubmount);
1702 smb_FreeTran2Packet(outp);
1703 return CM_ERROR_BADSHARENAME;
1706 memset(outp->datap, 0, totalData);
1708 outp->parmsp[0] = 0;
1709 outp->parmsp[1] = 0;
1710 outp->parmsp[2] = totalData;
1712 if (infoLevel == 0) {
1713 smb_rap_share_info_0_t * info = (smb_rap_share_info_0_t *) outp->datap;
1714 strncpy(info->shi0_netname, shareName, sizeof(info->shi0_netname)-1);
1715 info->shi0_netname[sizeof(info->shi0_netname)-1] = 0;
1716 } else if(infoLevel == SMB_INFO_STANDARD) {
1717 smb_rap_share_info_1_t * info = (smb_rap_share_info_1_t *) outp->datap;
1718 strncpy(info->shi1_netname, shareName, sizeof(info->shi1_netname)-1);
1719 info->shi1_netname[sizeof(info->shi1_netname)-1] = 0;
1720 info->shi1_remark = ((unsigned char *) (info + 1)) - outp->datap;
1721 /* type and pad are already zero */
1722 } else { /* infoLevel==2 */
1723 smb_rap_share_info_2_t * info = (smb_rap_share_info_2_t *) outp->datap;
1724 strncpy(info->shi2_netname, shareName, sizeof(info->shi2_netname)-1);
1725 info->shi2_netname[sizeof(info->shi2_netname)-1] = 0;
1726 info->shi2_remark = ((unsigned char *) (info + 1)) - outp->datap;
1727 info->shi2_permissions = ACCESS_ALL;
1728 info->shi2_max_uses = (unsigned short) -1;
1729 info->shi2_path = 1 + (((unsigned char *) (info + 1)) - outp->datap);
1732 outp->totalData = totalData;
1733 outp->totalParms = totalParam;
1735 smb_SendTran2Packet(vcp, outp, op);
1736 smb_FreeTran2Packet(outp);
1741 typedef struct smb_rap_wksta_info_10 {
1742 DWORD wki10_computername; /*char *wki10_computername;*/
1743 DWORD wki10_username; /* char *wki10_username; */
1744 DWORD wki10_langroup; /* char *wki10_langroup;*/
1745 unsigned char wki10_ver_major;
1746 unsigned char wki10_ver_minor;
1747 DWORD wki10_logon_domain; /*char *wki10_logon_domain;*/
1748 DWORD wki10_oth_domains; /* char *wki10_oth_domains;*/
1749 } smb_rap_wksta_info_10_t;
1752 long smb_ReceiveRAPNetWkstaGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1754 smb_tran2Packet_t *outp;
1758 unsigned short * tp;
1761 smb_rap_wksta_info_10_t * info;
1765 tp = p->parmsp + 1; /* Skip over function number */
1766 (void) smb_ParseString((unsigned char*) tp, (char **) &tp); /* skip over param descriptor */
1767 (void) smb_ParseString((unsigned char*) tp, (char **) &tp); /* skip over data descriptor */
1771 if (infoLevel != 10) {
1772 return CM_ERROR_INVAL;
1778 totalData = sizeof(*info) + /* info */
1779 MAX_COMPUTERNAME_LENGTH + /* wki10_computername */
1780 SMB_MAX_USERNAME_LENGTH + /* wki10_username */
1781 MAX_COMPUTERNAME_LENGTH + /* wki10_langroup */
1782 MAX_COMPUTERNAME_LENGTH + /* wki10_logon_domain */
1783 1; /* wki10_oth_domains (null)*/
1785 outp = smb_GetTran2ResponsePacket(vcp, p, op, totalParams, totalData);
1787 memset(outp->parmsp,0,totalParams);
1788 memset(outp->datap,0,totalData);
1790 info = (smb_rap_wksta_info_10_t *) outp->datap;
1791 cstrp = (char *) (info + 1);
1793 info->wki10_computername = (DWORD) (cstrp - outp->datap);
1794 strcpy(cstrp, smb_localNamep);
1795 cstrp += strlen(cstrp) + 1;
1797 info->wki10_username = (DWORD) (cstrp - outp->datap);
1798 uidp = smb_FindUID(vcp, p->uid, 0);
1800 lock_ObtainMutex(&uidp->mx);
1801 if(uidp->unp && uidp->unp->name)
1802 strcpy(cstrp, uidp->unp->name);
1803 lock_ReleaseMutex(&uidp->mx);
1804 smb_ReleaseUID(uidp);
1806 cstrp += strlen(cstrp) + 1;
1808 info->wki10_langroup = (DWORD) (cstrp - outp->datap);
1809 strcpy(cstrp, "WORKGROUP");
1810 cstrp += strlen(cstrp) + 1;
1812 /* TODO: Not sure what values these should take, but these work */
1813 info->wki10_ver_major = 5;
1814 info->wki10_ver_minor = 1;
1816 info->wki10_logon_domain = (DWORD) (cstrp - outp->datap);
1817 strcpy(cstrp, smb_ServerDomainName);
1818 cstrp += strlen(cstrp) + 1;
1820 info->wki10_oth_domains = (DWORD) (cstrp - outp->datap);
1821 cstrp ++; /* no other domains */
1823 outp->totalData = (unsigned short) (cstrp - outp->datap); /* actual data size */
1824 outp->parmsp[2] = outp->totalData;
1825 outp->totalParms = totalParams;
1827 smb_SendTran2Packet(vcp,outp,op);
1828 smb_FreeTran2Packet(outp);
1833 typedef struct smb_rap_server_info_0 {
1835 } smb_rap_server_info_0_t;
1837 typedef struct smb_rap_server_info_1 {
1839 char sv1_version_major;
1840 char sv1_version_minor;
1841 unsigned long sv1_type;
1842 DWORD *sv1_comment_or_master_browser; /* char *sv1_comment_or_master_browser;*/
1843 } smb_rap_server_info_1_t;
1845 char smb_ServerComment[] = "OpenAFS Client";
1846 int smb_ServerCommentLen = sizeof(smb_ServerComment);
1848 #define SMB_SV_TYPE_SERVER 0x00000002L
1849 #define SMB_SV_TYPE_NT 0x00001000L
1850 #define SMB_SV_TYPE_SERVER_NT 0x00008000L
1852 long smb_ReceiveRAPNetServerGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1854 smb_tran2Packet_t *outp;
1858 unsigned short * tp;
1861 smb_rap_server_info_0_t * info0;
1862 smb_rap_server_info_1_t * info1;
1865 tp = p->parmsp + 1; /* Skip over function number */
1866 (void) smb_ParseString((unsigned char*) tp, (char **) &tp); /* skip over param descriptor */
1867 (void) smb_ParseString((unsigned char*) tp, (char **) &tp); /* skip over data descriptor */
1871 if (infoLevel != 0 && infoLevel != 1) {
1872 return CM_ERROR_INVAL;
1878 (infoLevel == 0) ? sizeof(smb_rap_server_info_0_t)
1879 : (sizeof(smb_rap_server_info_1_t) + smb_ServerCommentLen);
1881 outp = smb_GetTran2ResponsePacket(vcp, p, op, totalParams, totalData);
1883 memset(outp->parmsp,0,totalParams);
1884 memset(outp->datap,0,totalData);
1886 if (infoLevel == 0) {
1887 info0 = (smb_rap_server_info_0_t *) outp->datap;
1888 cstrp = (char *) (info0 + 1);
1889 strcpy(info0->sv0_name, "AFS");
1890 } else { /* infoLevel == SMB_INFO_STANDARD */
1891 info1 = (smb_rap_server_info_1_t *) outp->datap;
1892 cstrp = (char *) (info1 + 1);
1893 strcpy(info1->sv1_name, "AFS");
1896 SMB_SV_TYPE_SERVER |
1898 SMB_SV_TYPE_SERVER_NT;
1900 info1->sv1_version_major = 5;
1901 info1->sv1_version_minor = 1;
1902 info1->sv1_comment_or_master_browser = (DWORD *) (cstrp - outp->datap);
1904 strcpy(cstrp, smb_ServerComment);
1906 cstrp += smb_ServerCommentLen;
1909 totalData = cstrp - outp->datap;
1910 outp->totalData = min(bufsize,totalData); /* actual data size */
1911 outp->parmsp[0] = (outp->totalData == totalData)? 0 : ERROR_MORE_DATA;
1912 outp->parmsp[2] = totalData;
1913 outp->totalParms = totalParams;
1915 smb_SendTran2Packet(vcp,outp,op);
1916 smb_FreeTran2Packet(outp);
1921 long smb_ReceiveV3Tran2A(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
1923 smb_tran2Packet_t *asp;
1935 /* We sometimes see 0 word count. What to do? */
1936 if (*inp->wctp == 0) {
1941 osi_Log0(smb_logp, "TRANSACTION2 word count = 0");
1943 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
1944 ptbuf[0] = "Transaction2 word count = 0";
1945 ReportEvent(h, EVENTLOG_WARNING_TYPE, 0, 1003, NULL,
1946 1, inp->ncb_length, ptbuf, inp);
1947 DeregisterEventSource(h);
1949 osi_Log0(smb_logp, "TRANSACTION2 word count = 0");
1952 smb_SetSMBDataLength(outp, 0);
1953 smb_SendPacket(vcp, outp);
1957 totalParms = smb_GetSMBParm(inp, 0);
1958 totalData = smb_GetSMBParm(inp, 1);
1960 firstPacket = (inp->inCom == 0x32);
1962 /* find the packet we're reassembling */
1963 lock_ObtainWrite(&smb_globalLock);
1964 asp = smb_FindTran2Packet(vcp, inp);
1966 asp = smb_NewTran2Packet(vcp, inp, totalParms, totalData);
1968 lock_ReleaseWrite(&smb_globalLock);
1970 /* now merge in this latest packet; start by looking up offsets */
1972 parmDisp = dataDisp = 0;
1973 parmOffset = smb_GetSMBParm(inp, 10);
1974 dataOffset = smb_GetSMBParm(inp, 12);
1975 parmCount = smb_GetSMBParm(inp, 9);
1976 dataCount = smb_GetSMBParm(inp, 11);
1977 asp->maxReturnParms = smb_GetSMBParm(inp, 2);
1978 asp->maxReturnData = smb_GetSMBParm(inp, 3);
1980 osi_Log3(smb_logp, "SMB3 received T2 init packet total data %d, cur data %d, max return data %d",
1981 totalData, dataCount, asp->maxReturnData);
1984 parmDisp = smb_GetSMBParm(inp, 4);
1985 parmOffset = smb_GetSMBParm(inp, 3);
1986 dataDisp = smb_GetSMBParm(inp, 7);
1987 dataOffset = smb_GetSMBParm(inp, 6);
1988 parmCount = smb_GetSMBParm(inp, 2);
1989 dataCount = smb_GetSMBParm(inp, 5);
1991 osi_Log2(smb_logp, "SMB3 received T2 aux packet parms %d, data %d",
1992 parmCount, dataCount);
1995 /* now copy the parms and data */
1996 if ( asp->totalParms > 0 && parmCount != 0 )
1998 memcpy(((char *)asp->parmsp) + parmDisp, inp->data + parmOffset, parmCount);
2000 if ( asp->totalData > 0 && dataCount != 0 ) {
2001 memcpy(asp->datap + dataDisp, inp->data + dataOffset, dataCount);
2004 /* account for new bytes */
2005 asp->curData += dataCount;
2006 asp->curParms += parmCount;
2008 /* finally, if we're done, remove the packet from the queue and dispatch it */
2009 if (asp->totalParms > 0 &&
2010 asp->curParms > 0 &&
2011 asp->totalData <= asp->curData &&
2012 asp->totalParms <= asp->curParms) {
2013 /* we've received it all */
2014 lock_ObtainWrite(&smb_globalLock);
2015 osi_QRemove((osi_queue_t **) &smb_tran2AssemblyQueuep, &asp->q);
2016 lock_ReleaseWrite(&smb_globalLock);
2018 /* now dispatch it */
2019 if ( asp->opcode >= 0 && asp->opcode < 20 && smb_tran2DispatchTable[asp->opcode].procp) {
2020 osi_LogEvent("AFS-Dispatch-2[%s]",myCrt_2Dispatch(asp->opcode),"vcp[%x] lana[%d] lsn[%d]",(int)vcp,vcp->lana,vcp->lsn);
2021 osi_Log4(smb_logp,"AFS Server - Dispatch-2 %s vcp[%x] lana[%d] lsn[%d]",myCrt_2Dispatch(asp->opcode),vcp,vcp->lana,vcp->lsn);
2022 code = (*smb_tran2DispatchTable[asp->opcode].procp)(vcp, asp, outp);
2025 osi_LogEvent("AFS-Dispatch-2 [invalid]", NULL, "op[%x] vcp[%x] lana[%d] lsn[%d]", asp->opcode, vcp, vcp->lana, vcp->lsn);
2026 osi_Log4(smb_logp,"AFS Server - Dispatch-2 [INVALID] op[%x] vcp[%x] lana[%d] lsn[%d]", asp->opcode, vcp, vcp->lana, vcp->lsn);
2027 code = CM_ERROR_BADOP;
2030 /* if an error is returned, we're supposed to send an error packet,
2031 * otherwise the dispatched function already did the data sending.
2032 * We give dispatched proc the responsibility since it knows how much
2033 * space to allocate.
2036 smb_SendTran2Error(vcp, asp, outp, code);
2039 /* free the input tran 2 packet */
2040 lock_ObtainWrite(&smb_globalLock);
2041 smb_FreeTran2Packet(asp);
2042 lock_ReleaseWrite(&smb_globalLock);
2044 else if (firstPacket) {
2045 /* the first packet in a multi-packet request, we need to send an
2046 * ack to get more data.
2048 smb_SetSMBDataLength(outp, 0);
2049 smb_SendPacket(vcp, outp);
2055 long smb_ReceiveTran2Open(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
2058 smb_tran2Packet_t *outp;
2063 cm_scache_t *dscp; /* dir we're dealing with */
2064 cm_scache_t *scp; /* file we're creating */
2066 int initialModeBits;
2076 int parmSlot; /* which parm we're dealing with */
2077 long returnEALength;
2085 extraInfo = (p->parmsp[0] & 1); /* return extra info */
2086 returnEALength = (p->parmsp[0] & 8); /* return extended attr length */
2088 openFun = p->parmsp[6]; /* open function */
2089 excl = ((openFun & 3) == 0);
2090 trunc = ((openFun & 3) == 2); /* truncate it */
2091 openMode = (p->parmsp[1] & 0x7);
2092 openAction = 0; /* tracks what we did */
2094 attributes = p->parmsp[3];
2095 dosTime = p->parmsp[4] | (p->parmsp[5] << 16);
2097 /* compute initial mode bits based on read-only flag in attributes */
2098 initialModeBits = 0666;
2100 initialModeBits &= ~0222;
2102 pathp = (char *) (&p->parmsp[14]);
2103 if (smb_StoreAnsiFilenames)
2104 OemToChar(pathp,pathp);
2106 outp = smb_GetTran2ResponsePacket(vcp, p, op, 40, 0);
2108 spacep = cm_GetSpace();
2109 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
2111 if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
2112 /* special case magic file name for receiving IOCTL requests
2113 * (since IOCTL calls themselves aren't getting through).
2115 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
2116 smb_SetupIoctlFid(fidp, spacep);
2118 /* copy out remainder of the parms */
2120 outp->parmsp[parmSlot++] = fidp->fid;
2122 outp->parmsp[parmSlot++] = 0; /* attrs */
2123 outp->parmsp[parmSlot++] = 0; /* mod time */
2124 outp->parmsp[parmSlot++] = 0;
2125 outp->parmsp[parmSlot++] = 0; /* len */
2126 outp->parmsp[parmSlot++] = 0x7fff;
2127 outp->parmsp[parmSlot++] = openMode;
2128 outp->parmsp[parmSlot++] = 0; /* file type 0 ==> normal file or dir */
2129 outp->parmsp[parmSlot++] = 0; /* IPC junk */
2131 /* and the final "always present" stuff */
2132 outp->parmsp[parmSlot++] = 1; /* openAction found existing file */
2133 /* next write out the "unique" ID */
2134 outp->parmsp[parmSlot++] = 0x1234;
2135 outp->parmsp[parmSlot++] = 0x5678;
2136 outp->parmsp[parmSlot++] = 0;
2137 if (returnEALength) {
2138 outp->parmsp[parmSlot++] = 0;
2139 outp->parmsp[parmSlot++] = 0;
2142 outp->totalData = 0;
2143 outp->totalParms = parmSlot * 2;
2145 smb_SendTran2Packet(vcp, outp, op);
2147 smb_FreeTran2Packet(outp);
2149 /* and clean up fid reference */
2150 smb_ReleaseFID(fidp);
2154 #ifdef DEBUG_VERBOSE
2156 char *hexp, *asciip;
2157 asciip = (lastNamep ? lastNamep : pathp);
2158 hexp = osi_HexifyString( asciip );
2159 DEBUG_EVENT2("AFS","T2Open H[%s] A[%s]", hexp, asciip);
2164 userp = smb_GetTran2User(vcp, p);
2165 /* In the off chance that userp is NULL, we log and abandon */
2167 osi_Log1(smb_logp, "ReceiveTran2Open user [%d] not resolvable", p->uid);
2168 smb_FreeTran2Packet(outp);
2169 return CM_ERROR_BADSMB;
2172 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
2173 if (code == CM_ERROR_TIDIPC) {
2174 /* Attempt to use a TID allocated for IPC. The client
2175 * is probably looking for DCE RPC end points which we
2176 * don't support OR it could be looking to make a DFS
2179 osi_Log0(smb_logp, "Tran2Open received IPC TID");
2181 cm_ReleaseUser(userp);
2182 smb_FreeTran2Packet(outp);
2183 return CM_ERROR_NOSUCHPATH;
2188 code = cm_NameI(cm_data.rootSCachep, pathp,
2189 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
2190 userp, tidPathp, &req, &scp);
2192 code = cm_NameI(cm_data.rootSCachep, spacep->data,
2193 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
2194 userp, tidPathp, &req, &dscp);
2195 cm_FreeSpace(spacep);
2198 cm_ReleaseUser(userp);
2199 smb_FreeTran2Packet(outp);
2204 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
2205 cm_ReleaseSCache(dscp);
2206 cm_ReleaseUser(userp);
2207 smb_FreeTran2Packet(outp);
2208 if ( WANTS_DFS_PATHNAMES(p) )
2209 return CM_ERROR_PATH_NOT_COVERED;
2211 return CM_ERROR_BADSHARENAME;
2213 #endif /* DFS_SUPPORT */
2215 /* otherwise, scp points to the parent directory. Do a lookup,
2216 * and truncate the file if we find it, otherwise we create the
2223 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD, userp,
2225 if (code && code != CM_ERROR_NOSUCHFILE) {
2226 cm_ReleaseSCache(dscp);
2227 cm_ReleaseUser(userp);
2228 smb_FreeTran2Packet(outp);
2233 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
2234 cm_ReleaseSCache(scp);
2235 cm_ReleaseUser(userp);
2236 smb_FreeTran2Packet(outp);
2237 if ( WANTS_DFS_PATHNAMES(p) )
2238 return CM_ERROR_PATH_NOT_COVERED;
2240 return CM_ERROR_BADSHARENAME;
2242 #endif /* DFS_SUPPORT */
2244 /* macintosh is expensive to program for it */
2245 cm_FreeSpace(spacep);
2248 /* if we get here, if code is 0, the file exists and is represented by
2249 * scp. Otherwise, we have to create it.
2252 code = cm_CheckOpen(scp, openMode, trunc, userp, &req);
2255 cm_ReleaseSCache(dscp);
2256 cm_ReleaseSCache(scp);
2257 cm_ReleaseUser(userp);
2258 smb_FreeTran2Packet(outp);
2263 /* oops, file shouldn't be there */
2265 cm_ReleaseSCache(dscp);
2266 cm_ReleaseSCache(scp);
2267 cm_ReleaseUser(userp);
2268 smb_FreeTran2Packet(outp);
2269 return CM_ERROR_EXISTS;
2273 setAttr.mask = CM_ATTRMASK_LENGTH;
2274 setAttr.length.LowPart = 0;
2275 setAttr.length.HighPart = 0;
2276 code = cm_SetAttr(scp, &setAttr, userp, &req);
2277 openAction = 3; /* truncated existing file */
2280 openAction = 1; /* found existing file */
2282 else if (!(openFun & 0x10)) {
2283 /* don't create if not found */
2285 cm_ReleaseSCache(dscp);
2286 osi_assert(scp == NULL);
2287 cm_ReleaseUser(userp);
2288 smb_FreeTran2Packet(outp);
2289 return CM_ERROR_NOSUCHFILE;
2292 osi_assert(dscp != NULL && scp == NULL);
2293 openAction = 2; /* created file */
2294 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
2295 smb_UnixTimeFromSearchTime(&setAttr.clientModTime, dosTime);
2296 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
2298 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
2299 smb_NotifyChange(FILE_ACTION_ADDED,
2300 FILE_NOTIFY_CHANGE_FILE_NAME,
2301 dscp, lastNamep, NULL, TRUE);
2302 if (!excl && code == CM_ERROR_EXISTS) {
2303 /* not an exclusive create, and someone else tried
2304 * creating it already, then we open it anyway. We
2305 * don't bother retrying after this, since if this next
2306 * fails, that means that the file was deleted after we
2307 * started this call.
2309 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
2313 setAttr.mask = CM_ATTRMASK_LENGTH;
2314 setAttr.length.LowPart = 0;
2315 setAttr.length.HighPart = 0;
2316 code = cm_SetAttr(scp, &setAttr, userp,
2319 } /* lookup succeeded */
2323 /* we don't need this any longer */
2325 cm_ReleaseSCache(dscp);
2328 /* something went wrong creating or truncating the file */
2330 cm_ReleaseSCache(scp);
2331 cm_ReleaseUser(userp);
2332 smb_FreeTran2Packet(outp);
2336 /* make sure we're about to open a file */
2337 if (scp->fileType != CM_SCACHETYPE_FILE) {
2339 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
2340 cm_scache_t * targetScp = 0;
2341 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
2343 /* we have a more accurate file to use (the
2344 * target of the symbolic link). Otherwise,
2345 * we'll just use the symlink anyway.
2347 osi_Log2(smb_logp, "symlink vp %x to vp %x",
2349 cm_ReleaseSCache(scp);
2353 if (scp->fileType != CM_SCACHETYPE_FILE) {
2354 cm_ReleaseSCache(scp);
2355 cm_ReleaseUser(userp);
2356 smb_FreeTran2Packet(outp);
2357 return CM_ERROR_ISDIR;
2361 /* now all we have to do is open the file itself */
2362 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
2365 /* save a pointer to the vnode */
2368 /* compute open mode */
2369 if (openMode != 1) fidp->flags |= SMB_FID_OPENREAD;
2370 if (openMode == 1 || openMode == 2)
2371 fidp->flags |= SMB_FID_OPENWRITE;
2373 smb_ReleaseFID(fidp);
2375 cm_Open(scp, 0, userp);
2377 /* copy out remainder of the parms */
2379 outp->parmsp[parmSlot++] = fidp->fid;
2380 lock_ObtainMutex(&scp->mx);
2382 outp->parmsp[parmSlot++] = smb_Attributes(scp);
2383 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
2384 outp->parmsp[parmSlot++] = (unsigned short)(dosTime & 0xffff);
2385 outp->parmsp[parmSlot++] = (unsigned short)((dosTime>>16) & 0xffff);
2386 outp->parmsp[parmSlot++] = (unsigned short) (scp->length.LowPart & 0xffff);
2387 outp->parmsp[parmSlot++] = (unsigned short) ((scp->length.LowPart >> 16) & 0xffff);
2388 outp->parmsp[parmSlot++] = openMode;
2389 outp->parmsp[parmSlot++] = 0; /* file type 0 ==> normal file or dir */
2390 outp->parmsp[parmSlot++] = 0; /* IPC junk */
2392 /* and the final "always present" stuff */
2393 outp->parmsp[parmSlot++] = openAction;
2394 /* next write out the "unique" ID */
2395 outp->parmsp[parmSlot++] = (unsigned short) (scp->fid.vnode & 0xffff);
2396 outp->parmsp[parmSlot++] = (unsigned short) (scp->fid.volume & 0xffff);
2397 outp->parmsp[parmSlot++] = 0;
2398 if (returnEALength) {
2399 outp->parmsp[parmSlot++] = 0;
2400 outp->parmsp[parmSlot++] = 0;
2402 lock_ReleaseMutex(&scp->mx);
2403 outp->totalData = 0; /* total # of data bytes */
2404 outp->totalParms = parmSlot * 2; /* shorts are two bytes */
2406 smb_SendTran2Packet(vcp, outp, op);
2408 smb_FreeTran2Packet(outp);
2410 cm_ReleaseUser(userp);
2411 /* leave scp held since we put it in fidp->scp */
2415 long smb_ReceiveTran2FindFirst(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
2417 osi_Log0(smb_logp,"ReceiveTran2FindFirst - NOT_SUPPORTED");
2418 return CM_ERROR_BADOP;
2421 long smb_ReceiveTran2FindNext(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
2423 osi_Log0(smb_logp,"ReceiveTran2FindNext - NOT_SUPPORTED");
2424 return CM_ERROR_BADOP;
2427 long smb_ReceiveTran2QFSInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
2429 smb_tran2Packet_t *outp;
2430 smb_tran2QFSInfo_t qi;
2433 static char FSname[6] = {'A', 0, 'F', 0, 'S', 0};
2435 osi_Log1(smb_logp, "T2 QFSInfo type 0x%x", p->parmsp[0]);
2437 switch (p->parmsp[0]) {
2438 case 1: responseSize = sizeof(qi.u.allocInfo); break;
2439 case 2: responseSize = sizeof(qi.u.volumeInfo); break;
2440 case 0x102: responseSize = sizeof(qi.u.FSvolumeInfo); break;
2441 case 0x103: responseSize = sizeof(qi.u.FSsizeInfo); break;
2442 case 0x104: responseSize = sizeof(qi.u.FSdeviceInfo); break;
2443 case 0x105: responseSize = sizeof(qi.u.FSattributeInfo); break;
2444 case 0x200: /* CIFS Unix Info */
2445 case 0x301: /* Mac FS Info */
2446 default: return CM_ERROR_INVAL;
2449 outp = smb_GetTran2ResponsePacket(vcp, p, op, 0, responseSize);
2450 switch (p->parmsp[0]) {
2453 qi.u.allocInfo.FSID = 0;
2454 qi.u.allocInfo.sectorsPerAllocUnit = 1;
2455 qi.u.allocInfo.totalAllocUnits = 0x7fffffff;
2456 qi.u.allocInfo.availAllocUnits = 0x3fffffff;
2457 qi.u.allocInfo.bytesPerSector = 1024;
2462 qi.u.volumeInfo.vsn = 1234;
2463 qi.u.volumeInfo.vnCount = 4;
2464 /* we're supposed to pad it out with zeroes to the end */
2465 memset(&qi.u.volumeInfo.label, 0, sizeof(qi.u.volumeInfo.label));
2466 memcpy(qi.u.volumeInfo.label, "AFS", 4);
2470 /* FS volume info */
2471 memset((char *)&qi.u.FSvolumeInfo.vct, 0, sizeof(FILETIME));
2472 qi.u.FSvolumeInfo.vsn = 1234;
2473 qi.u.FSvolumeInfo.vnCount = 8;
2474 memcpy(qi.u.FSvolumeInfo.label, "A\0F\0S\0\0", 8);
2480 temp.LowPart = 0x7fffffff;
2481 qi.u.FSsizeInfo.totalAllocUnits = temp;
2482 temp.LowPart = 0x3fffffff;
2483 qi.u.FSsizeInfo.availAllocUnits = temp;
2484 qi.u.FSsizeInfo.sectorsPerAllocUnit = 1;
2485 qi.u.FSsizeInfo.bytesPerSector = 1024;
2489 /* FS device info */
2490 qi.u.FSdeviceInfo.devType = 0; /* don't have a number */
2491 qi.u.FSdeviceInfo.characteristics = 0x50; /* remote, virtual */
2495 /* FS attribute info */
2496 /* attributes, defined in WINNT.H:
2497 * FILE_CASE_SENSITIVE_SEARCH 0x1
2498 * FILE_CASE_PRESERVED_NAMES 0x2
2499 * <no name defined> 0x4000
2500 * If bit 0x4000 is not set, Windows 95 thinks
2501 * we can't handle long (non-8.3) names,
2502 * despite our protestations to the contrary.
2504 qi.u.FSattributeInfo.attributes = 0x4003;
2505 qi.u.FSattributeInfo.maxCompLength = 255;
2506 qi.u.FSattributeInfo.FSnameLength = 6;
2507 memcpy(qi.u.FSattributeInfo.FSname, FSname, 6);
2511 /* copy out return data, and set corresponding sizes */
2512 outp->totalParms = 0;
2513 outp->totalData = responseSize;
2514 memcpy(outp->datap, &qi, responseSize);
2516 /* send and free the packets */
2517 smb_SendTran2Packet(vcp, outp, op);
2518 smb_FreeTran2Packet(outp);
2523 long smb_ReceiveTran2SetFSInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
2525 osi_Log0(smb_logp,"ReceiveTran2SetFSInfo - NOT_SUPPORTED");
2526 return CM_ERROR_BADOP;
2529 struct smb_ShortNameRock {
2533 size_t shortNameLen;
2536 int cm_GetShortNameProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *vrockp,
2539 struct smb_ShortNameRock *rockp;
2543 /* compare both names and vnodes, though probably just comparing vnodes
2544 * would be safe enough.
2546 if (cm_stricmp(dep->name, rockp->maskp) != 0)
2548 if (ntohl(dep->fid.vnode) != rockp->vnode)
2550 /* This is the entry */
2551 cm_Gen8Dot3Name(dep, rockp->shortName, &shortNameEnd);
2552 rockp->shortNameLen = shortNameEnd - rockp->shortName;
2553 return CM_ERROR_STOPNOW;
2556 long cm_GetShortName(char *pathp, cm_user_t *userp, cm_req_t *reqp,
2557 char *tidPathp, int vnode, char *shortName, size_t *shortNameLenp)
2559 struct smb_ShortNameRock rock;
2563 int caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
2567 spacep = cm_GetSpace();
2568 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
2570 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold, userp, tidPathp,
2572 cm_FreeSpace(spacep);
2577 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
2578 cm_ReleaseSCache(dscp);
2579 cm_ReleaseUser(userp);
2580 return CM_ERROR_PATH_NOT_COVERED;
2582 #endif /* DFS_SUPPORT */
2584 if (!lastNamep) lastNamep = pathp;
2587 thyper.HighPart = 0;
2588 rock.shortName = shortName;
2590 rock.maskp = lastNamep;
2591 code = cm_ApplyDir(dscp, cm_GetShortNameProc, &rock, &thyper, userp, reqp, NULL);
2593 cm_ReleaseSCache(dscp);
2596 return CM_ERROR_NOSUCHFILE;
2597 if (code == CM_ERROR_STOPNOW) {
2598 *shortNameLenp = rock.shortNameLen;
2604 long smb_ReceiveTran2QPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
2606 smb_tran2Packet_t *outp;
2609 unsigned short infoLevel;
2611 unsigned short attributes;
2612 unsigned long extAttributes;
2617 cm_scache_t *scp, *dscp;
2626 infoLevel = p->parmsp[0];
2627 if (infoLevel == SMB_INFO_IS_NAME_VALID)
2629 else if (infoLevel == SMB_INFO_STANDARD)
2630 nbytesRequired = 22;
2631 else if (infoLevel == SMB_INFO_QUERY_EA_SIZE)
2632 nbytesRequired = 26;
2633 else if (infoLevel == SMB_QUERY_FILE_BASIC_INFO)
2634 nbytesRequired = 40;
2635 else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO)
2636 nbytesRequired = 24;
2637 else if (infoLevel == SMB_QUERY_FILE_EA_INFO)
2639 else if (infoLevel == SMB_QUERY_FILE_ALT_NAME_INFO)
2640 nbytesRequired = 30;
2642 osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
2643 p->opcode, infoLevel);
2644 smb_SendTran2Error(vcp, p, opx, CM_ERROR_INVAL);
2647 osi_Log2(smb_logp, "T2 QPathInfo type 0x%x path %s", infoLevel,
2648 osi_LogSaveString(smb_logp, (char *)(&p->parmsp[3])));
2650 outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, nbytesRequired);
2652 if (infoLevel > 0x100)
2653 outp->totalParms = 2;
2655 outp->totalParms = 0;
2656 outp->totalData = nbytesRequired;
2658 /* now, if we're at infoLevel 6, we're only being asked to check
2659 * the syntax, so we just OK things now. In particular, we're *not*
2660 * being asked to verify anything about the state of any parent dirs.
2662 if (infoLevel == SMB_INFO_IS_NAME_VALID) {
2663 smb_SendTran2Packet(vcp, outp, opx);
2664 smb_FreeTran2Packet(outp);
2668 userp = smb_GetTran2User(vcp, p);
2670 osi_Log1(smb_logp, "ReceiveTran2QPathInfo unable to resolve user [%d]", p->uid);
2671 smb_FreeTran2Packet(outp);
2672 return CM_ERROR_BADSMB;
2675 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
2677 cm_ReleaseUser(userp);
2678 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOSUCHPATH);
2679 smb_FreeTran2Packet(outp);
2684 * XXX Strange hack XXX
2686 * As of Patch 7 (13 January 98), we are having the following problem:
2687 * In NT Explorer 4.0, whenever we click on a directory, AFS gets
2688 * requests to look up "desktop.ini" in all the subdirectories.
2689 * This can cause zillions of timeouts looking up non-existent cells
2690 * and volumes, especially in the top-level directory.
2692 * We have not found any way to avoid this or work around it except
2693 * to explicitly ignore the requests for mount points that haven't
2694 * yet been evaluated and for directories that haven't yet been
2697 if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
2698 spacep = cm_GetSpace();
2699 smb_StripLastComponent(spacep->data, &lastComp,
2700 (char *)(&p->parmsp[3]));
2701 #ifndef SPECIAL_FOLDERS
2702 /* Make sure that lastComp is not NULL */
2704 if (stricmp(lastComp, "\\desktop.ini") == 0) {
2705 code = cm_NameI(cm_data.rootSCachep, spacep->data,
2709 userp, tidPathp, &req, &dscp);
2712 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
2713 if ( WANTS_DFS_PATHNAMES(p) )
2714 code = CM_ERROR_PATH_NOT_COVERED;
2716 code = CM_ERROR_BADSHARENAME;
2718 #endif /* DFS_SUPPORT */
2719 if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT && !dscp->mountRootFid.volume)
2720 code = CM_ERROR_NOSUCHFILE;
2721 else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
2722 cm_buf_t *bp = buf_Find(dscp, &hzero);
2726 code = CM_ERROR_NOSUCHFILE;
2728 cm_ReleaseSCache(dscp);
2730 cm_FreeSpace(spacep);
2731 cm_ReleaseUser(userp);
2732 smb_SendTran2Error(vcp, p, opx, code);
2733 smb_FreeTran2Packet(outp);
2739 #endif /* SPECIAL_FOLDERS */
2741 cm_FreeSpace(spacep);
2744 /* now do namei and stat, and copy out the info */
2745 code = cm_NameI(cm_data.rootSCachep, (char *)(&p->parmsp[3]),
2746 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, tidPathp, &req, &scp);
2749 cm_ReleaseUser(userp);
2750 smb_SendTran2Error(vcp, p, opx, code);
2751 smb_FreeTran2Packet(outp);
2756 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
2757 cm_ReleaseSCache(scp);
2758 cm_ReleaseUser(userp);
2759 if ( WANTS_DFS_PATHNAMES(p) )
2760 code = CM_ERROR_PATH_NOT_COVERED;
2762 code = CM_ERROR_BADSHARENAME;
2763 smb_SendTran2Error(vcp, p, opx, code);
2764 smb_FreeTran2Packet(outp);
2767 #endif /* DFS_SUPPORT */
2769 lock_ObtainMutex(&scp->mx);
2770 code = cm_SyncOp(scp, NULL, userp, &req, 0,
2771 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
2772 if (code) goto done;
2774 /* now we have the status in the cache entry, and everything is locked.
2775 * Marshall the output data.
2778 /* for info level 108, figure out short name */
2779 if (infoLevel == 0x108) {
2780 code = cm_GetShortName((char *)(&p->parmsp[3]), userp, &req,
2781 tidPathp, scp->fid.vnode, shortName,
2788 *((u_long *)op) = len * 2; op += 4;
2789 mbstowcs((unsigned short *)op, shortName, len);
2794 if (infoLevel == SMB_INFO_STANDARD || infoLevel == SMB_INFO_QUERY_EA_SIZE) {
2795 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
2796 *((u_long *)op) = dosTime; op += 4; /* creation time */
2797 *((u_long *)op) = dosTime; op += 4; /* access time */
2798 *((u_long *)op) = dosTime; op += 4; /* write time */
2799 *((u_long *)op) = scp->length.LowPart; op += 4; /* length */
2800 *((u_long *)op) = scp->length.LowPart; op += 4; /* alloc size */
2801 attributes = smb_Attributes(scp);
2802 *((u_short *)op) = attributes; op += 2; /* attributes */
2804 else if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
2805 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
2806 *((FILETIME *)op) = ft; op += 8; /* creation time */
2807 *((FILETIME *)op) = ft; op += 8; /* last access time */
2808 *((FILETIME *)op) = ft; op += 8; /* last write time */
2809 *((FILETIME *)op) = ft; op += 8; /* last change time */
2810 extAttributes = smb_ExtAttributes(scp);
2811 *((u_long *)op) = extAttributes; op += 4; /* extended attribs */
2812 *((u_long *)op) = 0; op += 4; /* don't know what this is */
2814 else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO) {
2815 *((LARGE_INTEGER *)op) = scp->length; op += 8; /* alloc size */
2816 *((LARGE_INTEGER *)op) = scp->length; op += 8; /* EOF */
2817 *((u_long *)op) = scp->linkCount; op += 4;
2820 *op++ = (scp->fileType == CM_SCACHETYPE_DIRECTORY ? 1 : 0);
2823 else if (infoLevel == SMB_QUERY_FILE_EA_INFO) {
2824 memset(op, 0, 4); op += 4; /* EA size */
2827 /* now, if we are being asked about extended attrs, return a 0 size */
2828 if (infoLevel == SMB_INFO_QUERY_EA_SIZE) {
2829 *((u_long *)op) = 0; op += 4;
2833 /* send and free the packets */
2835 lock_ReleaseMutex(&scp->mx);
2836 cm_ReleaseSCache(scp);
2837 cm_ReleaseUser(userp);
2839 smb_SendTran2Packet(vcp, outp, opx);
2841 smb_SendTran2Error(vcp, p, opx, code);
2842 smb_FreeTran2Packet(outp);
2847 long smb_ReceiveTran2SetPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
2849 osi_Log0(smb_logp,"ReceiveTran2SetPathInfo - NOT_SUPPORTED");
2850 return CM_ERROR_BADOP;
2853 long smb_ReceiveTran2QFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
2855 smb_tran2Packet_t *outp;
2857 unsigned long attributes;
2858 unsigned short infoLevel;
2871 fidp = smb_FindFID(vcp, fid, 0);
2874 smb_SendTran2Error(vcp, p, opx, CM_ERROR_BADFD);
2878 infoLevel = p->parmsp[1];
2879 if (infoLevel == SMB_QUERY_FILE_BASIC_INFO)
2880 nbytesRequired = 40;
2881 else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO)
2882 nbytesRequired = 24;
2883 else if (infoLevel == SMB_QUERY_FILE_EA_INFO)
2885 else if (infoLevel == SMB_QUERY_FILE_NAME_INFO)
2888 osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
2889 p->opcode, infoLevel);
2890 smb_SendTran2Error(vcp, p, opx, CM_ERROR_INVAL);
2891 smb_ReleaseFID(fidp);
2894 osi_Log2(smb_logp, "T2 QFileInfo type 0x%x fid %d", infoLevel, fid);
2896 outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, nbytesRequired);
2898 if (infoLevel > 0x100)
2899 outp->totalParms = 2;
2901 outp->totalParms = 0;
2902 outp->totalData = nbytesRequired;
2904 userp = smb_GetTran2User(vcp, p);
2906 osi_Log1(smb_logp, "ReceiveTran2QFileInfo unable to resolve user [%d]", p->uid);
2907 code = CM_ERROR_BADSMB;
2912 lock_ObtainMutex(&scp->mx);
2913 code = cm_SyncOp(scp, NULL, userp, &req, 0,
2914 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
2918 /* now we have the status in the cache entry, and everything is locked.
2919 * Marshall the output data.
2922 if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
2923 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
2924 *((FILETIME *)op) = ft; op += 8; /* creation time */
2925 *((FILETIME *)op) = ft; op += 8; /* last access time */
2926 *((FILETIME *)op) = ft; op += 8; /* last write time */
2927 *((FILETIME *)op) = ft; op += 8; /* last change time */
2928 attributes = smb_ExtAttributes(scp);
2929 *((u_long *)op) = attributes; op += 4;
2930 *((u_long *)op) = 0; op += 4;
2932 else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO) {
2933 *((LARGE_INTEGER *)op) = scp->length; op += 8; /* alloc size */
2934 *((LARGE_INTEGER *)op) = scp->length; op += 8; /* EOF */
2935 *((u_long *)op) = scp->linkCount; op += 4;
2936 *op++ = ((fidp->flags & SMB_FID_DELONCLOSE) ? 1 : 0);
2937 *op++ = (scp->fileType == CM_SCACHETYPE_DIRECTORY ? 1 : 0);
2941 else if (infoLevel == SMB_QUERY_FILE_EA_INFO) {
2942 *((u_long *)op) = 0; op += 4;
2944 else if (infoLevel == SMB_QUERY_FILE_NAME_INFO) {
2948 if (fidp->NTopen_wholepathp)
2949 name = fidp->NTopen_wholepathp;
2951 name = "\\"; /* probably can't happen */
2953 outp->totalData = (len*2) + 4; /* this is actually what we want to return */
2954 *((u_long *)op) = len * 2; op += 4;
2955 mbstowcs((unsigned short *)op, name, len); op += (len * 2);
2958 /* send and free the packets */
2960 lock_ReleaseMutex(&scp->mx);
2961 cm_ReleaseUser(userp);
2962 smb_ReleaseFID(fidp);
2964 smb_SendTran2Packet(vcp, outp, opx);
2966 smb_SendTran2Error(vcp, p, opx, code);
2967 smb_FreeTran2Packet(outp);
2972 long smb_ReceiveTran2SetFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
2977 unsigned short infoLevel;
2978 smb_tran2Packet_t *outp;
2986 fidp = smb_FindFID(vcp, fid, 0);
2989 smb_SendTran2Error(vcp, p, op, CM_ERROR_BADFD);
2993 infoLevel = p->parmsp[1];
2994 osi_Log2(smb_logp,"ReceiveTran2SetFileInfo type=[%x] fid=[%x]", infoLevel, fid);
2995 if (infoLevel > 0x104 || infoLevel < 0x101) {
2996 osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
2997 p->opcode, infoLevel);
2998 smb_SendTran2Error(vcp, p, op, CM_ERROR_INVAL);
2999 smb_ReleaseFID(fidp);
3003 if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO && !(fidp->flags & SMB_FID_OPENDELETE)) {
3004 smb_SendTran2Error(vcp, p, op, CM_ERROR_NOACCESS);
3005 smb_ReleaseFID(fidp);
3008 if ((infoLevel == SMB_QUERY_FILE_EA_INFO || infoLevel == SMB_QUERY_FILE_NAME_INFO)
3009 && !(fidp->flags & SMB_FID_OPENWRITE)) {
3010 smb_SendTran2Error(vcp, p, op, CM_ERROR_NOACCESS);
3011 smb_ReleaseFID(fidp);
3015 osi_Log1(smb_logp, "T2 SFileInfo type 0x%x", infoLevel);
3017 outp = smb_GetTran2ResponsePacket(vcp, p, op, 2, 0);
3019 outp->totalParms = 2;
3020 outp->totalData = 0;
3022 userp = smb_GetTran2User(vcp, p);
3024 osi_Log1(smb_logp,"ReceiveTran2SetFileInfo unable to resolve user [%d]", p->uid);
3025 code = CM_ERROR_BADSMB;
3031 if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
3033 unsigned int attribute;
3036 /* lock the vnode with a callback; we need the current status
3037 * to determine what the new status is, in some cases.
3039 lock_ObtainMutex(&scp->mx);
3040 code = cm_SyncOp(scp, NULL, userp, &req, 0,
3041 CM_SCACHESYNC_GETSTATUS
3042 | CM_SCACHESYNC_NEEDCALLBACK);
3044 lock_ReleaseMutex(&scp->mx);
3048 /* prepare for setattr call */
3051 lastMod = *((FILETIME *)(p->datap + 16));
3052 /* when called as result of move a b, lastMod is (-1, -1).
3053 * If the check for -1 is not present, timestamp
3054 * of the resulting file will be 1969 (-1)
3056 if (LargeIntegerNotEqualToZero(*((LARGE_INTEGER *)&lastMod)) &&
3057 lastMod.dwLowDateTime != -1 && lastMod.dwHighDateTime != -1) {
3058 attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
3059 smb_UnixTimeFromLargeSearchTime(&attr.clientModTime, &lastMod);
3060 fidp->flags |= SMB_FID_MTIMESETDONE;
3063 attribute = *((u_long *)(p->datap + 32));
3064 if (attribute != 0) {
3065 if ((scp->unixModeBits & 0222)
3066 && (attribute & 1) != 0) {
3067 /* make a writable file read-only */
3068 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
3069 attr.unixModeBits = scp->unixModeBits & ~0222;
3071 else if ((scp->unixModeBits & 0222) == 0
3072 && (attribute & 1) == 0) {
3073 /* make a read-only file writable */
3074 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
3075 attr.unixModeBits = scp->unixModeBits | 0222;
3078 lock_ReleaseMutex(&scp->mx);
3082 code = cm_SetAttr(scp, &attr, userp, &req);
3086 else if (infoLevel == SMB_QUERY_FILE_EA_INFO || infoLevel == SMB_QUERY_FILE_NAME_INFO) {
3087 LARGE_INTEGER size = *((LARGE_INTEGER *)(p->datap));
3090 attr.mask = CM_ATTRMASK_LENGTH;
3091 attr.length.LowPart = size.LowPart;
3092 attr.length.HighPart = size.HighPart;
3093 code = cm_SetAttr(scp, &attr, userp, &req);
3095 else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO) {
3096 if (*((char *)(p->datap))) {
3097 code = cm_CheckNTDelete(fidp->NTopen_dscp, scp, userp,
3100 fidp->flags |= SMB_FID_DELONCLOSE;
3104 fidp->flags &= ~SMB_FID_DELONCLOSE;
3109 cm_ReleaseUser(userp);
3110 smb_ReleaseFID(fidp);
3112 smb_SendTran2Packet(vcp, outp, op);
3114 smb_SendTran2Error(vcp, p, op, code);
3115 smb_FreeTran2Packet(outp);
3121 smb_ReceiveTran2FSCTL(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3123 osi_Log0(smb_logp,"ReceiveTran2FSCTL - NOT_SUPPORTED");
3124 return CM_ERROR_BADOP;
3128 smb_ReceiveTran2IOCTL(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3130 osi_Log0(smb_logp,"ReceiveTran2IOCTL - NOT_SUPPORTED");
3131 return CM_ERROR_BADOP;
3135 smb_ReceiveTran2FindNotifyFirst(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3137 osi_Log0(smb_logp,"ReceiveTran2FindNotifyFirst - NOT_SUPPORTED");
3138 return CM_ERROR_BADOP;
3142 smb_ReceiveTran2FindNotifyNext(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3144 osi_Log0(smb_logp,"ReceiveTran2FindNotifyNext - NOT_SUPPORTED");
3145 return CM_ERROR_BADOP;
3149 smb_ReceiveTran2CreateDirectory(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3151 osi_Log0(smb_logp,"ReceiveTran2CreateDirectory - NOT_SUPPORTED");
3152 return CM_ERROR_BADOP;
3156 smb_ReceiveTran2SessionSetup(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3158 osi_Log0(smb_logp,"ReceiveTran2SessionSetup - NOT_SUPPORTED");
3159 return CM_ERROR_BADOP;
3162 struct smb_v2_referral {
3164 USHORT ReferralFlags;
3167 USHORT DfsPathOffset;
3168 USHORT DfsAlternativePathOffset;
3169 USHORT NetworkAddressOffset;
3173 smb_ReceiveTran2GetDFSReferral(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
3175 /* This is a UNICODE only request (bit15 of Flags2) */
3176 /* The TID must be IPC$ */
3178 /* The documentation for the Flags response field is contradictory */
3180 /* Use Version 1 Referral Element Format */
3181 /* ServerType = 0; indicates the next server should be queried for the file */
3182 /* ReferralFlags = 0x01; PathConsumed characters should be stripped */
3183 /* Node = UnicodeString of UNC path of the next share name */
3186 int maxReferralLevel = 0;
3187 char requestFileName[1024] = "";
3188 smb_tran2Packet_t *outp = 0;
3189 cm_user_t *userp = 0;
3191 CPINFO CodePageInfo;
3192 int i, nbnLen, reqLen;
3197 maxReferralLevel = p->parmsp[0];
3199 GetCPInfo(CP_ACP, &CodePageInfo);
3200 WideCharToMultiByte(CP_ACP, 0, (LPCWSTR) &p->parmsp[1], -1,
3201 requestFileName, 1024, NULL, NULL);
3203 osi_Log2(smb_logp,"ReceiveTran2GetDfsReferral [%d][%s]",
3204 maxReferralLevel, osi_LogSaveString(smb_logp, requestFileName));
3206 nbnLen = strlen(cm_NetbiosName);
3207 reqLen = strlen(requestFileName);
3209 if (reqLen == nbnLen + 5 &&
3210 requestFileName[0] == '\\' &&
3211 !_strnicmp(cm_NetbiosName,&requestFileName[1],nbnLen) &&
3212 requestFileName[nbnLen+1] == '\\' &&
3213 !_strnicmp("all",&requestFileName[nbnLen+2],3))
3216 struct smb_v2_referral * v2ref;
3217 outp = smb_GetTran2ResponsePacket(vcp, p, op, 0, 2 * (reqLen + 8));
3219 sp = (USHORT *)outp->datap;
3221 sp[idx++] = reqLen; /* path consumed */
3222 sp[idx++] = 1; /* number of referrals */
3223 sp[idx++] = 0x03; /* flags */
3224 #ifdef DFS_VERSION_1
3225 sp[idx++] = 1; /* Version Number */
3226 sp[idx++] = reqLen + 4; /* Referral Size */
3227 sp[idx++] = 1; /* Type = SMB Server */
3228 sp[idx++] = 0; /* Do not strip path consumed */
3229 for ( i=0;i<=reqLen; i++ )
3230 sp[i+idx] = requestFileName[i];
3231 #else /* DFS_VERSION_2 */
3232 sp[idx++] = 2; /* Version Number */
3233 sp[idx++] = sizeof(struct smb_v2_referral); /* Referral Size */
3234 idx += (sizeof(struct smb_v2_referral) / 2);
3235 v2ref = (struct smb_v2_referral *) &sp[5];
3236 v2ref->ServerType = 1; /* SMB Server */
3237 v2ref->ReferralFlags = 0x03;
3238 v2ref->Proximity = 0; /* closest */
3239 v2ref->TimeToLive = 3600; /* seconds */
3240 v2ref->DfsPathOffset = idx * 2;
3241 v2ref->DfsAlternativePathOffset = idx * 2;
3242 v2ref->NetworkAddressOffset = 0;
3243 for ( i=0;i<=reqLen; i++ )
3244 sp[i+idx] = requestFileName[i];
3247 userp = smb_GetTran2User(vcp, p);
3249 osi_Log1(smb_logp,"ReceiveTran2GetDfsReferral unable to resolve user [%d]", p->uid);
3250 code = CM_ERROR_BADSMB;
3255 code = CM_ERROR_NOSUCHPATH;
3260 cm_ReleaseUser(userp);
3262 smb_SendTran2Packet(vcp, outp, op);
3264 smb_SendTran2Error(vcp, p, op, code);
3266 smb_FreeTran2Packet(outp);
3269 #else /* DFS_SUPPORT */
3270 osi_Log0(smb_logp,"ReceiveTran2GetDfsReferral - NOT_SUPPORTED");
3271 return CM_ERROR_BADOP;
3272 #endif /* DFS_SUPPORT */
3276 smb_ReceiveTran2ReportDFSInconsistency(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3278 /* This is a UNICODE only request (bit15 of Flags2) */
3280 /* There is nothing we can do about this operation. The client is going to
3281 * tell us that there is a Version 1 Referral Element for which there is a DFS Error.
3282 * Unfortunately, there is really nothing we can do about it other then log it
3283 * somewhere. Even then I don't think there is anything for us to do.
3284 * So let's return an error value.
3287 osi_Log0(smb_logp,"ReceiveTran2ReportDFSInconsistency - NOT_SUPPORTED");
3288 return CM_ERROR_BADOP;
3292 smb_ApplyV3DirListPatches(cm_scache_t *dscp,
3293 smb_dirListPatch_t **dirPatchespp, int infoLevel, cm_user_t *userp,
3298 cm_scache_t *targetScp; /* target if scp is a symlink */
3303 unsigned short attr;
3304 unsigned long lattr;
3305 smb_dirListPatch_t *patchp;
3306 smb_dirListPatch_t *npatchp;
3308 for(patchp = *dirPatchespp; patchp; patchp =
3309 (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
3310 code = cm_GetSCache(&patchp->fid, &scp, userp, reqp);
3312 lock_ObtainMutex(&scp->mx);
3313 code = cm_SyncOp(scp, NULL, userp, reqp, 0,
3314 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3316 lock_ReleaseMutex(&scp->mx);
3317 cm_ReleaseSCache(scp);
3319 dptr = patchp->dptr;
3321 /* Plug in fake timestamps. A time stamp of 0 causes 'invalid parameter'
3322 errors in the client. */
3323 if (infoLevel >= 0x101) {
3324 /* 1969-12-31 23:59:59 +00 */
3325 ft.dwHighDateTime = 0x19DB200;
3326 ft.dwLowDateTime = 0x5BB78980;
3328 /* copy to Creation Time */
3329 *((FILETIME *)dptr) = ft;
3332 /* copy to Last Access Time */
3333 *((FILETIME *)dptr) = ft;
3336 /* copy to Last Write Time */
3337 *((FILETIME *)dptr) = ft;
3340 /* copy to Change Time */
3341 *((FILETIME *)dptr) = ft;
3344 /* merge in hidden attribute */
3345 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
3346 *((u_long *)dptr) = SMB_ATTR_HIDDEN;
3350 /* 1969-12-31 23:59:58 +00*/
3351 dosTime = 0xEBBFBF7D;
3353 /* and copy out date */
3354 shortTemp = (dosTime>>16) & 0xffff;
3355 *((u_short *)dptr) = shortTemp;
3358 /* copy out creation time */
3359 shortTemp = dosTime & 0xffff;
3360 *((u_short *)dptr) = shortTemp;
3363 /* and copy out date */
3364 shortTemp = (dosTime>>16) & 0xffff;
3365 *((u_short *)dptr) = shortTemp;
3368 /* copy out access time */
3369 shortTemp = dosTime & 0xffff;
3370 *((u_short *)dptr) = shortTemp;
3373 /* and copy out date */
3374 shortTemp = (dosTime>>16) & 0xffff;
3375 *((u_short *)dptr) = shortTemp;
3378 /* copy out mod time */
3379 shortTemp = dosTime & 0xffff;
3380 *((u_short *)dptr) = shortTemp;
3383 /* merge in hidden (dot file) attribute */
3384 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
3385 attr = SMB_ATTR_HIDDEN;
3386 *dptr++ = attr & 0xff;
3387 *dptr++ = (attr >> 8) & 0xff;
3393 /* now watch for a symlink */
3395 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
3396 lock_ReleaseMutex(&scp->mx);
3397 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, reqp);
3399 /* we have a more accurate file to use (the
3400 * target of the symbolic link). Otherwise,
3401 * we'll just use the symlink anyway.
3403 osi_Log2(smb_logp, "symlink vp %x to vp %x",
3405 cm_ReleaseSCache(scp);
3408 lock_ObtainMutex(&scp->mx);
3411 dptr = patchp->dptr;
3413 if (infoLevel >= 0x101) {
3415 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
3417 /* copy to Creation Time */
3418 *((FILETIME *)dptr) = ft;
3421 /* copy to Last Access Time */
3422 *((FILETIME *)dptr) = ft;
3425 /* copy to Last Write Time */
3426 *((FILETIME *)dptr) = ft;
3429 /* copy to Change Time */
3430 *((FILETIME *)dptr) = ft;
3433 /* Use length for both file length and alloc length */
3434 *((LARGE_INTEGER *)dptr) = scp->length;
3436 *((LARGE_INTEGER *)dptr) = scp->length;
3439 /* Copy attributes */
3440 lattr = smb_ExtAttributes(scp);
3441 if (code == CM_ERROR_NOSUCHPATH && scp->fileType == CM_SCACHETYPE_SYMLINK) {
3442 if (lattr == SMB_ATTR_NORMAL)
3443 lattr = SMB_ATTR_DIRECTORY;
3445 lattr |= SMB_ATTR_DIRECTORY;
3447 /* merge in hidden (dot file) attribute */
3448 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
3449 if (lattr == SMB_ATTR_NORMAL)
3450 lattr = SMB_ATTR_HIDDEN;
3452 lattr |= SMB_ATTR_HIDDEN;
3454 *((u_long *)dptr) = lattr;
3458 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
3460 /* and copy out date */
3461 shortTemp = (dosTime>>16) & 0xffff;
3462 *((u_short *)dptr) = shortTemp;
3465 /* copy out creation time */
3466 shortTemp = dosTime & 0xffff;
3467 *((u_short *)dptr) = shortTemp;
3470 /* and copy out date */
3471 shortTemp = (dosTime>>16) & 0xffff;
3472 *((u_short *)dptr) = shortTemp;
3475 /* copy out access time */
3476 shortTemp = dosTime & 0xffff;
3477 *((u_short *)dptr) = shortTemp;
3480 /* and copy out date */
3481 shortTemp = (dosTime>>16) & 0xffff;
3482 *((u_short *)dptr) = shortTemp;
3485 /* copy out mod time */
3486 shortTemp = dosTime & 0xffff;
3487 *((u_short *)dptr) = shortTemp;
3490 /* copy out file length and alloc length,
3491 * using the same for both
3493 *((u_long *)dptr) = scp->length.LowPart;
3495 *((u_long *)dptr) = scp->length.LowPart;
3498 /* finally copy out attributes as short */
3499 attr = smb_Attributes(scp);
3500 /* merge in hidden (dot file) attribute */
3501 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
3502 if (lattr == SMB_ATTR_NORMAL)
3503 lattr = SMB_ATTR_HIDDEN;
3505 lattr |= SMB_ATTR_HIDDEN;
3507 *dptr++ = attr & 0xff;
3508 *dptr++ = (attr >> 8) & 0xff;
3511 lock_ReleaseMutex(&scp->mx);
3512 cm_ReleaseSCache(scp);
3515 /* now free the patches */
3516 for (patchp = *dirPatchespp; patchp; patchp = npatchp) {
3517 npatchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q);
3521 /* and mark the list as empty */
3522 *dirPatchespp = NULL;
3527 #ifndef USE_OLD_MATCHING
3528 // char table for case insensitive comparison
3529 char mapCaseTable[256];
3531 VOID initUpperCaseTable(VOID)
3534 for (i = 0; i < 256; ++i)
3535 mapCaseTable[i] = toupper(i);
3536 // make '"' match '.'
3537 mapCaseTable[(int)'"'] = toupper('.');
3538 // make '<' match '*'
3539 mapCaseTable[(int)'<'] = toupper('*');
3540 // make '>' match '?'
3541 mapCaseTable[(int)'>'] = toupper('?');
3544 // Compare 'pattern' (containing metacharacters '*' and '?') with the file
3546 // Note : this procedure works recursively calling itself.
3548 // PSZ pattern : string containing metacharacters.
3549 // PSZ name : file name to be compared with 'pattern'.
3551 // BOOL : TRUE/FALSE (match/mistmatch)
3554 szWildCardMatchFileName(PSZ pattern, PSZ name, int casefold)
3556 PSZ pename; // points to the last 'name' character
3558 pename = name + strlen(name) - 1;
3569 if (*pattern == '\0')
3571 for (p = pename; p >= name; --p) {
3572 if ((casefold && (mapCaseTable[*p] == mapCaseTable[*pattern]) ||
3573 !casefold && (*p == *pattern)) &&
3574 szWildCardMatchFileName(pattern + 1, p + 1, casefold))
3579 if ((casefold && mapCaseTable[*name] != mapCaseTable[*pattern]) ||
3580 (!casefold && *name != *pattern))
3587 /* if all we have left are wildcards, then we match */
3588 for (;*pattern; pattern++) {
3589 if (*pattern != '*' && *pattern != '?')
3595 /* do a case-folding search of the star name mask with the name in namep.
3596 * Return 1 if we match, otherwise 0.
3598 int smb_V3MatchMask(char *namep, char *maskp, int flags)
3601 int i, j, star, qmark, casefold, retval;
3603 /* make sure we only match 8.3 names, if requested */
3604 if ((flags & CM_FLAG_8DOT3) && !cm_Is8Dot3(namep))
3607 casefold = (flags & CM_FLAG_CASEFOLD) ? 1 : 0;
3609 /* optimize the pattern:
3610 * if there is a mixture of '?' and '*',
3611 * for example the sequence "*?*?*?*"
3612 * must be turned into the form "*"
3614 newmask = (char *)malloc(strlen(maskp)+1);
3615 for ( i=0, j=0, star=0, qmark=0; maskp[i]; i++) {
3616 switch ( maskp[i] ) {
3628 } else if ( qmark ) {
3632 newmask[j++] = maskp[i];
3639 } else if ( qmark ) {
3643 newmask[j++] = '\0';
3645 retval = szWildCardMatchFileName(newmask, namep, casefold) ? 1:0;
3651 #else /* USE_OLD_MATCHING */
3652 /* do a case-folding search of the star name mask with the name in namep.
3653 * Return 1 if we match, otherwise 0.
3655 int smb_V3MatchMask(char *namep, char *maskp, int flags)
3657 unsigned char tcp1, tcp2; /* Pattern characters */
3658 unsigned char tcn1; /* Name characters */
3659 int sawDot = 0, sawStar = 0, req8dot3 = 0;
3660 char *starNamep, *starMaskp;
3661 static char nullCharp[] = {0};
3662 int casefold = flags & CM_FLAG_CASEFOLD;
3664 /* make sure we only match 8.3 names, if requested */
3665 req8dot3 = (flags & CM_FLAG_8DOT3);
3666 if (req8dot3 && !cm_Is8Dot3(namep))
3671 /* Next pattern character */
3674 /* Next name character */
3678 /* 0 - end of pattern */
3684 else if (tcp1 == '.' || tcp1 == '"') {
3694 * first dot in pattern;
3695 * must match dot or end of name
3700 else if (tcn1 == '.') {
3709 else if (tcp1 == '?') {
3710 if (tcn1 == 0 || tcn1 == '.')
3715 else if (tcp1 == '>') {
3716 if (tcn1 != 0 && tcn1 != '.')
3720 else if (tcp1 == '*' || tcp1 == '<') {
3724 else if ((req8dot3 && tcp2 == '.') || tcp2 == '"') {
3725 while (req8dot3 && tcn1 != '.' && tcn1 != 0)
3740 * pattern character after '*' is not null or
3741 * period. If it is '?' or '>', we are not
3742 * going to understand it. If it is '*' or
3743 * '<', we are going to skip over it. None of
3744 * these are likely, I hope.
3746 /* skip over '*' and '<' */
3747 while (tcp2 == '*' || tcp2 == '<')
3750 /* skip over characters that don't match tcp2 */
3751 while (req8dot3 && tcn1 != '.' && tcn1 != 0 &&
3752 ((casefold && cm_foldUpper[tcn1] != cm_foldUpper[tcp2]) ||
3753 (!casefold && tcn1 != tcp2)))
3757 if ((req8dot3 && tcn1 == '.') || tcn1 == 0)
3760 /* Remember where we are */
3770 /* tcp1 is not a wildcard */
3771 if ((casefold && cm_foldUpper[tcn1] == cm_foldUpper[tcp1]) ||
3772 (!casefold && tcn1 == tcp1)) {
3777 /* if trying to match a star pattern, go back */
3779 maskp = starMaskp - 2;
3780 namep = starNamep + 1;
3789 #endif /* USE_OLD_MATCHING */
3791 long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
3796 long code = 0, code2 = 0;
3800 smb_dirListPatch_t *dirListPatchesp;
3801 smb_dirListPatch_t *curPatchp;
3804 long orbytes; /* # of bytes in this output record */
3805 long ohbytes; /* # of bytes, except file name */
3806 long onbytes; /* # of bytes in name, incl. term. null */
3807 osi_hyper_t dirLength;
3808 osi_hyper_t bufferOffset;
3809 osi_hyper_t curOffset;
3811 smb_dirSearch_t *dsp;
3815 cm_pageHeader_t *pageHeaderp;
3816 cm_user_t *userp = NULL;
3819 long nextEntryCookie;
3820 int numDirChunks; /* # of 32 byte dir chunks in this entry */
3821 char *op; /* output data ptr */
3822 char *origOp; /* original value of op */
3823 cm_space_t *spacep; /* for pathname buffer */
3824 long maxReturnData; /* max # of return data */
3825 long maxReturnParms; /* max # of return parms */
3826 long bytesInBuffer; /* # data bytes in the output buffer */
3828 char *maskp; /* mask part of path */
3832 smb_tran2Packet_t *outp; /* response packet */
3835 char shortName[13]; /* 8.3 name if needed */
3846 if (p->opcode == 1) {
3847 /* find first; obtain basic parameters from request */
3848 attribute = p->parmsp[0];
3849 maxCount = p->parmsp[1];
3850 infoLevel = p->parmsp[3];
3851 searchFlags = p->parmsp[2];
3852 dsp = smb_NewDirSearch(1);
3853 dsp->attribute = attribute;
3854 pathp = ((char *) p->parmsp) + 12; /* points to path */
3855 if (smb_StoreAnsiFilenames)
3856 OemToChar(pathp,pathp);
3858 maskp = strrchr(pathp, '\\');
3862 maskp++; /* skip over backslash */
3863 strcpy(dsp->mask, maskp); /* and save mask */
3864 /* track if this is likely to match a lot of entries */
3865 starPattern = smb_V3IsStarMask(maskp);
3868 osi_assert(p->opcode == 2);
3869 /* find next; obtain basic parameters from request or open dir file */
3870 dsp = smb_FindDirSearch(p->parmsp[0]);
3871 maxCount = p->parmsp[1];
3872 infoLevel = p->parmsp[2];
3873 nextCookie = p->parmsp[3] | (p->parmsp[4] << 16);
3874 searchFlags = p->parmsp[5];
3876 osi_Log2(smb_logp, "T2 search dir bad search ID: id %d nextCookie 0x%x",
3877 p->parmsp[0], nextCookie);
3878 return CM_ERROR_BADFD;
3880 attribute = dsp->attribute;
3883 starPattern = 1; /* assume, since required a Find Next */
3887 "T2 search dir attr 0x%x, info level %d, max count %d, flags 0x%x",
3888 attribute, infoLevel, maxCount, searchFlags);
3890 osi_Log3(smb_logp, "...T2 search op %d, id %d, nextCookie 0x%x",
3891 p->opcode, dsp->cookie, nextCookie);
3893 if (infoLevel >= 0x101)
3894 searchFlags &= ~4; /* no resume keys */
3896 dirListPatchesp = NULL;
3898 maxReturnData = p->maxReturnData;
3899 if (p->opcode == 1) /* find first */
3900 maxReturnParms = 10; /* bytes */
3902 maxReturnParms = 8; /* bytes */
3904 #ifndef CM_CONFIG_MULTITRAN2RESPONSES
3905 if (maxReturnData > 6000)
3906 maxReturnData = 6000;
3907 #endif /* CM_CONFIG_MULTITRAN2RESPONSES */
3909 outp = smb_GetTran2ResponsePacket(vcp, p, opx, maxReturnParms,
3912 osi_Log2(smb_logp, "T2 receive search dir count %d [%s]",
3913 maxCount, osi_LogSaveString(smb_logp, pathp));
3915 /* bail out if request looks bad */
3916 if (p->opcode == 1 && !pathp) {
3917 smb_ReleaseDirSearch(dsp);
3918 smb_FreeTran2Packet(outp);
3919 return CM_ERROR_BADSMB;
3922 osi_Log3(smb_logp, "T2 search dir id %d, nextCookie 0x%x, attr 0x%x",
3923 dsp->cookie, nextCookie, attribute);
3925 userp = smb_GetTran2User(vcp, p);
3927 osi_Log1(smb_logp, "T2 search dir unable to resolve user [%d]", p->uid);
3928 smb_ReleaseDirSearch(dsp);
3929 smb_FreeTran2Packet(outp);
3930 return CM_ERROR_BADSMB;
3933 /* try to get the vnode for the path name next */
3934 lock_ObtainMutex(&dsp->mx);
3940 spacep = cm_GetSpace();
3941 smb_StripLastComponent(spacep->data, NULL, pathp);
3942 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
3944 cm_ReleaseUser(userp);
3945 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOFILES);
3946 smb_FreeTran2Packet(outp);
3947 lock_ReleaseMutex(&dsp->mx);
3948 smb_DeleteDirSearch(dsp);
3949 smb_ReleaseDirSearch(dsp);
3952 code = cm_NameI(cm_data.rootSCachep, spacep->data,
3953 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
3954 userp, tidPathp, &req, &scp);
3955 cm_FreeSpace(spacep);
3958 #ifdef DFS_SUPPORT_BUT_NOT_FIND_FIRST
3959 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
3960 cm_ReleaseSCache(scp);
3961 cm_ReleaseUser(userp);
3962 if ( WANTS_DFS_PATHNAMES(p) )
3963 code = CM_ERROR_PATH_NOT_COVERED;
3965 code = CM_ERROR_BADSHARENAME;
3966 smb_SendTran2Error(vcp, p, opx, code);
3967 smb_FreeTran2Packet(outp);
3968 lock_ReleaseMutex(&dsp->mx);
3969 smb_DeleteDirSearch(dsp);
3970 smb_ReleaseDirSearch(dsp);
3973 #endif /* DFS_SUPPORT */
3975 /* we need one hold for the entry we just stored into,
3976 * and one for our own processing. When we're done
3977 * with this function, we'll drop the one for our own
3978 * processing. We held it once from the namei call,
3979 * and so we do another hold now.
3982 lock_ObtainMutex(&scp->mx);
3983 if ((scp->flags & CM_SCACHEFLAG_BULKSTATTING) == 0 &&
3984 LargeIntegerGreaterOrEqualToZero(scp->bulkStatProgress)) {
3985 scp->flags |= CM_SCACHEFLAG_BULKSTATTING;
3986 dsp->flags |= SMB_DIRSEARCH_BULKST;
3988 lock_ReleaseMutex(&scp->mx);
3991 lock_ReleaseMutex(&dsp->mx);
3993 cm_ReleaseUser(userp);
3994 smb_FreeTran2Packet(outp);
3995 smb_DeleteDirSearch(dsp);
3996 smb_ReleaseDirSearch(dsp);
4000 /* get the directory size */
4001 lock_ObtainMutex(&scp->mx);
4002 code = cm_SyncOp(scp, NULL, userp, &req, 0,
4003 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4005 lock_ReleaseMutex(&scp->mx);
4006 cm_ReleaseSCache(scp);
4007 cm_ReleaseUser(userp);
4008 smb_FreeTran2Packet(outp);
4009 smb_DeleteDirSearch(dsp);
4010 smb_ReleaseDirSearch(dsp);
4015 dirLength = scp->length;
4017 bufferOffset.LowPart = bufferOffset.HighPart = 0;
4018 curOffset.HighPart = 0;
4019 curOffset.LowPart = nextCookie;
4020 origOp = outp->datap;
4028 if (searchFlags & 4)
4029 /* skip over resume key */
4032 /* make sure that curOffset.LowPart doesn't point to the first
4033 * 32 bytes in the 2nd through last dir page, and that it doesn't
4034 * point at the first 13 32-byte chunks in the first dir page,
4035 * since those are dir and page headers, and don't contain useful
4038 temp = curOffset.LowPart & (2048-1);
4039 if (curOffset.HighPart == 0 && curOffset.LowPart < 2048) {
4040 /* we're in the first page */
4041 if (temp < 13*32) temp = 13*32;
4044 /* we're in a later dir page */
4045 if (temp < 32) temp = 32;
4048 /* make sure the low order 5 bits are zero */
4051 /* now put temp bits back ito curOffset.LowPart */
4052 curOffset.LowPart &= ~(2048-1);
4053 curOffset.LowPart |= temp;
4055 /* check if we've passed the dir's EOF */
4056 if (LargeIntegerGreaterThanOrEqualTo(curOffset, dirLength)) {
4057 osi_Log0(smb_logp, "T2 search dir passed eof");
4062 /* check if we've returned all the names that will fit in the
4063 * response packet; we check return count as well as the number
4064 * of bytes requested. We check the # of bytes after we find
4065 * the dir entry, since we'll need to check its size.
4067 if (returnedNames >= maxCount) {
4068 osi_Log2(smb_logp, "T2 search dir returnedNames %d >= maxCount %d",
4069 returnedNames, maxCount);
4073 /* see if we can use the bufferp we have now; compute in which
4074 * page the current offset would be, and check whether that's
4075 * the offset of the buffer we have. If not, get the buffer.
4077 thyper.HighPart = curOffset.HighPart;
4078 thyper.LowPart = curOffset.LowPart & ~(cm_data.buf_blockSize-1);
4079 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
4082 buf_Release(bufferp);
4085 lock_ReleaseMutex(&scp->mx);
4086 lock_ObtainRead(&scp->bufCreateLock);
4087 code = buf_Get(scp, &thyper, &bufferp);
4088 lock_ReleaseRead(&scp->bufCreateLock);
4089 lock_ObtainMutex(&dsp->mx);
4091 /* now, if we're doing a star match, do bulk fetching
4092 * of all of the status info for files in the dir.
4095 smb_ApplyV3DirListPatches(scp, &dirListPatchesp,
4098 lock_ObtainMutex(&scp->mx);
4099 if ((dsp->flags & SMB_DIRSEARCH_BULKST) &&
4100 LargeIntegerGreaterThanOrEqualTo(thyper, scp->bulkStatProgress)) {
4101 /* Don't bulk stat if risking timeout */
4102 int now = GetCurrentTime();
4103 if (now - req.startTime > 5000) {
4104 scp->bulkStatProgress = thyper;
4105 scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
4106 dsp->flags &= ~SMB_DIRSEARCH_BULKST;
4108 cm_TryBulkStat(scp, &thyper, userp, &req);
4111 lock_ObtainMutex(&scp->mx);
4113 lock_ReleaseMutex(&dsp->mx);
4115 osi_Log2(smb_logp, "T2 search dir buf_Get scp %x failed %d", scp, code);
4119 bufferOffset = thyper;
4121 /* now get the data in the cache */
4123 code = cm_SyncOp(scp, bufferp, userp, &req,
4125 CM_SCACHESYNC_NEEDCALLBACK
4126 | CM_SCACHESYNC_READ);
4128 osi_Log2(smb_logp, "T2 search dir cm_SyncOp scp %x failed %d", scp, code);
4132 if (cm_HaveBuffer(scp, bufferp, 0)) {
4133 osi_Log2(smb_logp, "T2 search dir !HaveBuffer scp %x bufferp %x", scp, bufferp);
4137 /* otherwise, load the buffer and try again */
4138 code = cm_GetBuffer(scp, bufferp, NULL, userp,
4141 osi_Log3(smb_logp, "T2 search dir cm_GetBuffer failed scp %x bufferp %x code %d",
4142 scp, bufferp, code);
4147 buf_Release(bufferp);
4151 } /* if (wrong buffer) ... */
4153 /* now we have the buffer containing the entry we're interested
4154 * in; copy it out if it represents a non-deleted entry.
4156 entryInDir = curOffset.LowPart & (2048-1);
4157 entryInBuffer = curOffset.LowPart & (cm_data.buf_blockSize - 1);
4159 /* page header will help tell us which entries are free. Page
4160 * header can change more often than once per buffer, since
4161 * AFS 3 dir page size may be less than (but not more than)
4162 * a buffer package buffer.
4164 /* only look intra-buffer */
4165 temp = curOffset.LowPart & (cm_data.buf_blockSize - 1);
4166 temp &= ~(2048 - 1); /* turn off intra-page bits */
4167 pageHeaderp = (cm_pageHeader_t *) (bufferp->datap + temp);
4169 /* now determine which entry we're looking at in the page.
4170 * If it is free (there's a free bitmap at the start of the
4171 * dir), we should skip these 32 bytes.
4173 slotInPage = (entryInDir & 0x7e0) >> 5;
4174 if (!(pageHeaderp->freeBitmap[slotInPage>>3] &
4175 (1 << (slotInPage & 0x7)))) {
4176 /* this entry is free */
4177 numDirChunks = 1; /* only skip this guy */
4181 tp = bufferp->datap + entryInBuffer;
4182 dep = (cm_dirEntry_t *) tp; /* now points to AFS3 dir entry */
4184 /* while we're here, compute the next entry's location, too,
4185 * since we'll need it when writing out the cookie into the dir
4188 * XXXX Probably should do more sanity checking.
4190 numDirChunks = cm_NameEntries(dep->name, &onbytes);
4192 /* compute offset of cookie representing next entry */
4193 nextEntryCookie = curOffset.LowPart + (CM_DIR_CHUNKSIZE * numDirChunks);
4195 /* Need 8.3 name? */
4197 if (infoLevel == SMB_QUERY_FILE_NAME_INFO
4198 && dep->fid.vnode != 0
4199 && !cm_Is8Dot3(dep->name)) {
4200 cm_Gen8Dot3Name(dep, shortName, &shortNameEnd);
4204 osi_Log3(smb_logp, "T2 search dir vn %u name %s (%s)",
4205 dep->fid.vnode, osi_LogSaveString(smb_logp, dep->name),
4206 NeedShortName ? osi_LogSaveString(smb_logp, shortName) : "");
4208 /* When matching, we are using doing a case fold if we have a wildcard mask.
4209 * If we get a non-wildcard match, it's a lookup for a specific file.
4211 if (dep->fid.vnode != 0 &&
4212 (smb_V3MatchMask(dep->name, maskp, (starPattern? CM_FLAG_CASEFOLD : 0)) ||
4214 smb_V3MatchMask(shortName, maskp, CM_FLAG_CASEFOLD)))) {
4216 /* Eliminate entries that don't match requested attributes */
4217 if (smb_hideDotFiles && !(dsp->attribute & SMB_ATTR_HIDDEN) &&
4218 smb_IsDotFile(dep->name)) {
4219 osi_Log0(smb_logp, "T2 search dir skipping hidden");
4220 goto nextEntry; /* no hidden files */
4222 if (!(dsp->attribute & SMB_ATTR_DIRECTORY)) /* no directories */
4224 /* We have already done the cm_TryBulkStat above */
4225 fid.cell = scp->fid.cell;
4226 fid.volume = scp->fid.volume;
4227 fid.vnode = ntohl(dep->fid.vnode);
4228 fid.unique = ntohl(dep->fid.unique);
4229 fileType = cm_FindFileType(&fid);
4230 /*osi_Log2(smb_logp, "smb_ReceiveTran2SearchDir: file %s "
4231 "has filetype %d", dep->name,
4233 if (fileType == CM_SCACHETYPE_DIRECTORY ||
4234 fileType == CM_SCACHETYPE_DFSLINK ||
4235 fileType == CM_SCACHETYPE_INVALID)
4236 osi_Log0(smb_logp, "T2 search dir skipping directory or bad link");
4240 /* finally check if this name will fit */
4242 /* standard dir entry stuff */
4243 if (infoLevel < 0x101)
4244 ohbytes = 23; /* pre-NT */
4245 else if (infoLevel == SMB_QUERY_FILE_EA_INFO)
4246 ohbytes = 12; /* NT names only */
4248 ohbytes = 64; /* NT */
4250 if (infoLevel == SMB_QUERY_FILE_NAME_INFO)
4251 ohbytes += 26; /* Short name & length */
4253 if (searchFlags & 4) {
4254 ohbytes += 4; /* if resume key required */
4258 && infoLevel != 0x101
4259 && infoLevel != 0x103)
4260 ohbytes += 4; /* EASIZE */
4262 /* add header to name & term. null */
4263 orbytes = onbytes + ohbytes + 1;
4265 /* now, we round up the record to a 4 byte alignment,
4266 * and we make sure that we have enough room here for
4267 * even the aligned version (so we don't have to worry
4268 * about an * overflow when we pad things out below).
4269 * That's the reason for the alignment arithmetic below.
4271 if (infoLevel >= 0x101)
4272 align = (4 - (orbytes & 3)) & 3;
4275 if (orbytes + bytesInBuffer + align > maxReturnData) {
4276 osi_Log1(smb_logp, "T2 dir search exceed max return data %d",
4281 /* this is one of the entries to use: it is not deleted
4282 * and it matches the star pattern we're looking for.
4283 * Put out the name, preceded by its length.
4285 /* First zero everything else */
4286 memset(origOp, 0, ohbytes);
4288 if (infoLevel <= 0x101)
4289 *(origOp + ohbytes - 1) = (unsigned char) onbytes;
4290 else if (infoLevel == SMB_QUERY_FILE_EA_INFO)
4291 *((u_long *)(op + 8)) = onbytes;
4293 *((u_long *)(op + 60)) = onbytes;
4294 strcpy(origOp+ohbytes, dep->name);
4295 if (smb_StoreAnsiFilenames)
4296 CharToOem(origOp+ohbytes, origOp+ohbytes);
4298 /* Short name if requested and needed */
4299 if (infoLevel == SMB_QUERY_FILE_NAME_INFO) {
4300 if (NeedShortName) {
4301 strcpy(op + 70, shortName);
4302 if (smb_StoreAnsiFilenames)
4303 CharToOem(op + 70, op + 70);
4304 *(op + 68) = shortNameEnd - shortName;
4308 /* now, adjust the # of entries copied */
4311 /* NextEntryOffset and FileIndex */
4312 if (infoLevel >= 101) {
4313 int entryOffset = orbytes + align;
4314 *((u_long *)op) = entryOffset;
4315 *((u_long *)(op+4)) = nextEntryCookie;
4318 /* now we emit the attribute. This is tricky, since
4319 * we need to really stat the file to find out what
4320 * type of entry we've got. Right now, we're copying
4321 * out data from a buffer, while holding the scp
4322 * locked, so it isn't really convenient to stat
4323 * something now. We'll put in a place holder
4324 * now, and make a second pass before returning this
4325 * to get the real attributes. So, we just skip the
4326 * data for now, and adjust it later. We allocate a
4327 * patch record to make it easy to find this point
4328 * later. The replay will happen at a time when it is
4329 * safe to unlock the directory.
4331 if (infoLevel != 0x103) {
4332 curPatchp = malloc(sizeof(*curPatchp));
4333 osi_QAdd((osi_queue_t **) &dirListPatchesp,
4335 curPatchp->dptr = op;
4336 if (infoLevel >= 0x101)
4337 curPatchp->dptr += 8;
4339 if (smb_hideDotFiles && smb_IsDotFile(dep->name)) {
4340 curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
4343 curPatchp->flags = 0;
4345 curPatchp->fid.cell = scp->fid.cell;
4346 curPatchp->fid.volume = scp->fid.volume;
4347 curPatchp->fid.vnode = ntohl(dep->fid.vnode);
4348 curPatchp->fid.unique = ntohl(dep->fid.unique);
4351 curPatchp->dep = dep;
4354 if (searchFlags & 4)
4355 /* put out resume key */
4356 *((u_long *)origOp) = nextEntryCookie;
4358 /* Adjust byte ptr and count */
4359 origOp += orbytes; /* skip entire record */
4360 bytesInBuffer += orbytes;
4362 /* and pad the record out */
4363 while (--align >= 0) {
4367 } /* if we're including this name */
4368 else if (!starPattern &&
4370 dep->fid.vnode != 0 &&
4371 smb_V3MatchMask(dep->name, maskp, CM_FLAG_CASEFOLD)) {
4372 /* We were looking for exact matches, but here's an inexact one*/
4377 /* and adjust curOffset to be where the new cookie is */
4378 thyper.HighPart = 0;
4379 thyper.LowPart = CM_DIR_CHUNKSIZE * numDirChunks;
4380 curOffset = LargeIntegerAdd(thyper, curOffset);
4381 } /* while copying data for dir listing */
4383 /* If we didn't get a star pattern, we did an exact match during the first pass.
4384 * If there were no exact matches found, we fail over to inexact matches by
4385 * marking the query as a star pattern (matches all case permutations), and
4386 * re-running the query.
4388 if (returnedNames == 0 && !starPattern && foundInexact) {
4389 osi_Log0(afsd_logp,"T2 Search: No exact matches. Re-running for inexact matches");
4394 /* release the mutex */
4395 lock_ReleaseMutex(&scp->mx);
4397 buf_Release(bufferp);
4399 /* apply and free last set of patches; if not doing a star match, this
4400 * will be empty, but better safe (and freeing everything) than sorry.
4402 code2 = smb_ApplyV3DirListPatches(scp, &dirListPatchesp, infoLevel, userp,
4405 /* now put out the final parameters */
4406 if (returnedNames == 0)
4408 if (p->opcode == 1) {
4410 outp->parmsp[0] = (unsigned short) dsp->cookie;
4411 outp->parmsp[1] = returnedNames;
4412 outp->parmsp[2] = eos;
4413 outp->parmsp[3] = 0; /* nothing wrong with EAS */
4414 outp->parmsp[4] = 0;
4415 /* don't need last name to continue
4416 * search, cookie is enough. Normally,
4417 * this is the offset of the file name
4418 * of the last entry returned.
4420 outp->totalParms = 10; /* in bytes */
4424 outp->parmsp[0] = returnedNames;
4425 outp->parmsp[1] = eos;
4426 outp->parmsp[2] = 0; /* EAS error */
4427 outp->parmsp[3] = 0; /* last name, as above */
4428 outp->totalParms = 8; /* in bytes */
4431 /* return # of bytes in the buffer */
4432 outp->totalData = bytesInBuffer;
4434 /* Return error code if unsuccessful on first request */
4435 if (code == 0 && p->opcode == 1 && returnedNames == 0)
4436 code = CM_ERROR_NOSUCHFILE;
4438 osi_Log4(smb_logp, "T2 search dir done, opcode %d, id %d, %d names, code %d",
4439 p->opcode, dsp->cookie, returnedNames, code);
4441 /* if we're supposed to close the search after this request, or if
4442 * we're supposed to close the search if we're done, and we're done,
4443 * or if something went wrong, close the search.
4445 /* ((searchFlags & 1) || ((searchFlags & 2) && eos) */
4446 if ((searchFlags & 1) || (returnedNames == 0) ||
4447 ((searchFlags & 2) && eos) || code != 0)
4448 smb_DeleteDirSearch(dsp);
4450 smb_SendTran2Error(vcp, p, opx, code);
4452 smb_SendTran2Packet(vcp, outp, opx);
4454 smb_FreeTran2Packet(outp);
4455 smb_ReleaseDirSearch(dsp);
4456 cm_ReleaseSCache(scp);
4457 cm_ReleaseUser(userp);
4461 long smb_ReceiveV3FindClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4464 smb_dirSearch_t *dsp;
4466 dirHandle = smb_GetSMBParm(inp, 0);
4468 osi_Log1(smb_logp, "SMB3 find close handle %d", dirHandle);
4470 dsp = smb_FindDirSearch(dirHandle);
4473 return CM_ERROR_BADFD;
4475 /* otherwise, we have an FD to destroy */
4476 smb_DeleteDirSearch(dsp);
4477 smb_ReleaseDirSearch(dsp);
4479 /* and return results */
4480 smb_SetSMBDataLength(outp, 0);
4485 long smb_ReceiveV3FindNotifyClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4487 smb_SetSMBDataLength(outp, 0);
4491 long smb_ReceiveV3OpenX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4498 cm_scache_t *dscp; /* dir we're dealing with */
4499 cm_scache_t *scp; /* file we're creating */
4501 int initialModeBits;
4511 int parmSlot; /* which parm we're dealing with */
4519 extraInfo = (smb_GetSMBParm(inp, 2) & 1); /* return extra info */
4520 openFun = smb_GetSMBParm(inp, 8); /* open function */
4521 excl = ((openFun & 3) == 0);
4522 trunc = ((openFun & 3) == 2); /* truncate it */
4523 openMode = (smb_GetSMBParm(inp, 3) & 0x7);
4524 openAction = 0; /* tracks what we did */
4526 attributes = smb_GetSMBParm(inp, 5);
4527 dosTime = smb_GetSMBParm(inp, 6) | (smb_GetSMBParm(inp, 7) << 16);
4529 /* compute initial mode bits based on read-only flag in attributes */
4530 initialModeBits = 0666;
4531 if (attributes & 1) initialModeBits &= ~0222;
4533 pathp = smb_GetSMBData(inp, NULL);
4534 if (smb_StoreAnsiFilenames)
4535 OemToChar(pathp,pathp);
4537 spacep = inp->spacep;
4538 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
4540 if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
4541 /* special case magic file name for receiving IOCTL requests
4542 * (since IOCTL calls themselves aren't getting through).
4545 osi_Log0(smb_logp, "IOCTL Open");
4548 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
4549 smb_SetupIoctlFid(fidp, spacep);
4551 /* set inp->fid so that later read calls in same msg can find fid */
4552 inp->fid = fidp->fid;
4554 /* copy out remainder of the parms */
4556 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
4558 smb_SetSMBParm(outp, parmSlot, /* attrs */ 0); parmSlot++;
4559 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* mod time */
4560 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
4561 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* len */
4562 smb_SetSMBParm(outp, parmSlot, 0x7fff); parmSlot++;
4563 smb_SetSMBParm(outp, parmSlot, openMode); parmSlot++;
4564 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* file type 0 ==> normal file or dir */
4565 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* IPC junk */
4567 /* and the final "always present" stuff */
4568 smb_SetSMBParm(outp, parmSlot, /* openAction found existing file */ 1); parmSlot++;
4569 /* next write out the "unique" ID */
4570 smb_SetSMBParm(outp, parmSlot, 0x1234); parmSlot++;
4571 smb_SetSMBParm(outp, parmSlot, 0x5678); parmSlot++;
4572 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
4573 smb_SetSMBDataLength(outp, 0);
4575 /* and clean up fid reference */
4576 smb_ReleaseFID(fidp);
4580 #ifdef DEBUG_VERBOSE
4582 char *hexp, *asciip;
4583 asciip = (lastNamep ? lastNamep : pathp );
4584 hexp = osi_HexifyString(asciip);
4585 DEBUG_EVENT2("AFS", "V3Open H[%s] A[%s]", hexp, asciip );
4589 userp = smb_GetUser(vcp, inp);
4592 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4594 cm_ReleaseUser(userp);
4595 return CM_ERROR_NOSUCHPATH;
4597 code = cm_NameI(cm_data.rootSCachep, pathp,
4598 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
4599 userp, tidPathp, &req, &scp);
4602 if (code == 0 && scp->fileType == CM_SCACHETYPE_DFSLINK) {
4603 cm_ReleaseSCache(scp);
4604 cm_ReleaseUser(userp);
4605 if ( WANTS_DFS_PATHNAMES(inp) )
4606 return CM_ERROR_PATH_NOT_COVERED;
4608 return CM_ERROR_BADSHARENAME;
4610 #endif /* DFS_SUPPORT */
4613 code = cm_NameI(cm_data.rootSCachep, spacep->data,
4614 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
4615 userp, tidPathp, &req, &dscp);
4617 cm_ReleaseUser(userp);
4622 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
4623 cm_ReleaseSCache(dscp);
4624 cm_ReleaseUser(userp);
4625 if ( WANTS_DFS_PATHNAMES(inp) )
4626 return CM_ERROR_PATH_NOT_COVERED;
4628 return CM_ERROR_BADSHARENAME;
4630 #endif /* DFS_SUPPORT */
4632 /* otherwise, scp points to the parent directory. Do a lookup,
4633 * and truncate the file if we find it, otherwise we create the
4640 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD, userp,
4642 if (code && code != CM_ERROR_NOSUCHFILE) {
4643 cm_ReleaseSCache(dscp);
4644 cm_ReleaseUser(userp);
4649 /* if we get here, if code is 0, the file exists and is represented by
4650 * scp. Otherwise, we have to create it. The dir may be represented
4651 * by dscp, or we may have found the file directly. If code is non-zero,
4655 code = cm_CheckOpen(scp, openMode, trunc, userp, &req);
4657 if (dscp) cm_ReleaseSCache(dscp);
4658 cm_ReleaseSCache(scp);
4659 cm_ReleaseUser(userp);
4664 /* oops, file shouldn't be there */
4666 cm_ReleaseSCache(dscp);
4667 cm_ReleaseSCache(scp);
4668 cm_ReleaseUser(userp);
4669 return CM_ERROR_EXISTS;
4673 setAttr.mask = CM_ATTRMASK_LENGTH;
4674 setAttr.length.LowPart = 0;
4675 setAttr.length.HighPart = 0;
4676 code = cm_SetAttr(scp, &setAttr, userp, &req);
4677 openAction = 3; /* truncated existing file */
4679 else openAction = 1; /* found existing file */
4681 else if (!(openFun & SMB_ATTR_DIRECTORY)) {
4682 /* don't create if not found */
4683 if (dscp) cm_ReleaseSCache(dscp);
4684 cm_ReleaseUser(userp);
4685 return CM_ERROR_NOSUCHFILE;
4688 osi_assert(dscp != NULL);
4689 osi_Log1(smb_logp, "smb_ReceiveV3OpenX creating file %s",
4690 osi_LogSaveString(smb_logp, lastNamep));
4691 openAction = 2; /* created file */
4692 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
4693 smb_UnixTimeFromDosUTime(&setAttr.clientModTime, dosTime);
4694 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
4696 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
4697 smb_NotifyChange(FILE_ACTION_ADDED,
4698 FILE_NOTIFY_CHANGE_FILE_NAME,
4699 dscp, lastNamep, NULL, TRUE);
4700 if (!excl && code == CM_ERROR_EXISTS) {
4701 /* not an exclusive create, and someone else tried
4702 * creating it already, then we open it anyway. We
4703 * don't bother retrying after this, since if this next
4704 * fails, that means that the file was deleted after we
4705 * started this call.
4707 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
4711 setAttr.mask = CM_ATTRMASK_LENGTH;
4712 setAttr.length.LowPart = 0;
4713 setAttr.length.HighPart = 0;
4714 code = cm_SetAttr(scp, &setAttr, userp, &req);
4716 } /* lookup succeeded */
4720 /* we don't need this any longer */
4722 cm_ReleaseSCache(dscp);
4725 /* something went wrong creating or truncating the file */
4727 cm_ReleaseSCache(scp);
4728 cm_ReleaseUser(userp);
4732 /* make sure we're about to open a file */
4733 if (scp->fileType != CM_SCACHETYPE_FILE) {
4734 cm_ReleaseSCache(scp);
4735 cm_ReleaseUser(userp);
4736 return CM_ERROR_ISDIR;
4739 /* now all we have to do is open the file itself */
4740 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
4743 /* save a pointer to the vnode */
4746 /* compute open mode */
4748 fidp->flags |= SMB_FID_OPENREAD;
4749 if (openMode == 1 || openMode == 2)
4750 fidp->flags |= SMB_FID_OPENWRITE;
4752 smb_ReleaseFID(fidp);
4754 cm_Open(scp, 0, userp);
4756 /* set inp->fid so that later read calls in same msg can find fid */
4757 inp->fid = fidp->fid;
4759 /* copy out remainder of the parms */
4761 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
4762 lock_ObtainMutex(&scp->mx);
4764 smb_SetSMBParm(outp, parmSlot, smb_Attributes(scp)); parmSlot++;
4765 smb_DosUTimeFromUnixTime(&dosTime, scp->clientModTime);
4766 smb_SetSMBParm(outp, parmSlot, dosTime & 0xffff); parmSlot++;
4767 smb_SetSMBParm(outp, parmSlot, (dosTime>>16) & 0xffff); parmSlot++;
4768 smb_SetSMBParm(outp, parmSlot, scp->length.LowPart & 0xffff); parmSlot++;
4769 smb_SetSMBParm(outp, parmSlot, (scp->length.LowPart >> 16) & 0xffff); parmSlot++;
4770 smb_SetSMBParm(outp, parmSlot, openMode); parmSlot++;
4771 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* file type 0 ==> normal file or dir */
4772 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* IPC junk */
4774 /* and the final "always present" stuff */
4775 smb_SetSMBParm(outp, parmSlot, openAction); parmSlot++;
4776 /* next write out the "unique" ID */
4777 smb_SetSMBParm(outp, parmSlot, scp->fid.vnode & 0xffff); parmSlot++;
4778 smb_SetSMBParm(outp, parmSlot, scp->fid.volume & 0xffff); parmSlot++;
4779 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
4780 lock_ReleaseMutex(&scp->mx);
4781 smb_SetSMBDataLength(outp, 0);
4783 osi_Log1(smb_logp, "SMB OpenX opening fid %d", fidp->fid);
4785 cm_ReleaseUser(userp);
4786 /* leave scp held since we put it in fidp->scp */
4790 static void smb_GetLockParams(unsigned char LockType,
4792 unsigned int * ppid,
4793 LARGE_INTEGER * pOffset,
4794 LARGE_INTEGER * pLength)
4796 if (LockType & LOCKING_ANDX_LARGE_FILES) {
4798 *ppid = *((USHORT *) *buf);
4799 pOffset->HighPart = *((LONG *)(*buf + 4));
4800 pOffset->LowPart = *((DWORD *)(*buf + 8));
4801 pLength->HighPart = *((LONG *)(*buf + 12));
4802 pLength->LowPart = *((DWORD *)(*buf + 16));
4806 /* Not Large Files */
4807 *ppid = *((USHORT *) *buf);
4808 pOffset->HighPart = 0;
4809 pOffset->LowPart = *((DWORD *)(*buf + 2));
4810 pLength->HighPart = 0;
4811 pLength->LowPart = *((DWORD *)(*buf + 6));
4816 long smb_ReceiveV3LockingX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4823 unsigned char LockType;
4824 unsigned short NumberOfUnlocks, NumberOfLocks;
4828 LARGE_INTEGER LOffset, LLength;
4829 smb_waitingLockRequest_t *wlRequest = NULL;
4830 cm_file_lock_t *lockp;
4838 fid = smb_GetSMBParm(inp, 2);
4839 fid = smb_ChainFID(fid, inp);
4841 fidp = smb_FindFID(vcp, fid, 0);
4842 if (!fidp || (fidp->flags & SMB_FID_IOCTL)) {
4843 osi_Log0(smb_logp, "smb_ReceiveV3Locking BadFD");
4844 return CM_ERROR_BADFD;
4846 /* set inp->fid so that later read calls in same msg can find fid */
4849 userp = smb_GetUser(vcp, inp);
4853 lock_ObtainMutex(&scp->mx);
4854 code = cm_SyncOp(scp, NULL, userp, &req, 0,
4855 CM_SCACHESYNC_NEEDCALLBACK
4856 | CM_SCACHESYNC_GETSTATUS
4857 | CM_SCACHESYNC_LOCK);
4859 osi_Log1(smb_logp, "smb_ReceiveV3Locking SyncOp failure code 0x%x", code);
4863 LockType = smb_GetSMBParm(inp, 3) & 0xff;
4864 Timeout = (smb_GetSMBParm(inp, 5) << 16) + smb_GetSMBParm(inp, 4);
4865 NumberOfUnlocks = smb_GetSMBParm(inp, 6);
4866 NumberOfLocks = smb_GetSMBParm(inp, 7);
4868 if ((LockType & LOCKING_ANDX_CANCEL_LOCK) ||
4869 (LockType & LOCKING_ANDX_CHANGE_LOCKTYPE)) {
4871 /* We don't support these requests. Apparently, we can safely
4872 not deal with them too. */
4873 osi_Log1(smb_logp, "smb_ReceiveV3Locking received unsupported request [%s]",
4874 ((LockType & LOCKING_ANDX_CANCEL_LOCK)?
4875 "LOCKING_ANDX_CANCEL_LOCK":
4876 "LOCKING_ANDX_CHANGE_LOCKTYPE"));
4877 /* No need to call osi_LogSaveString since these are string
4880 code = CM_ERROR_BADOP;
4885 op = smb_GetSMBData(inp, NULL);
4887 for (i=0; i<NumberOfUnlocks; i++) {
4888 smb_GetLockParams(LockType, &op, &pid, &LOffset, &LLength);
4890 key = cm_GenerateKey(vcp->vcID, pid, fidp->fid);
4892 code = cm_Unlock(scp, LockType, LOffset, LLength, key, userp, &req);
4900 for (i=0; i<NumberOfLocks; i++) {
4901 smb_GetLockParams(LockType, &op, &pid, &LOffset, &LLength);
4903 key = cm_GenerateKey(vcp->vcID, pid, fidp->fid);
4905 code = cm_Lock(scp, LockType, LOffset, LLength, key, (Timeout != 0),
4906 userp, &req, &lockp);
4908 if (code == CM_ERROR_WOULDBLOCK && Timeout != 0) {
4909 smb_waitingLock_t * wLock;
4911 /* Put on waiting list */
4912 if(wlRequest == NULL) {
4916 LARGE_INTEGER tOffset, tLength;
4918 wlRequest = malloc(sizeof(smb_waitingLockRequest_t));
4920 osi_assert(wlRequest != NULL);
4922 wlRequest->vcp = vcp;
4924 wlRequest->scp = scp;
4926 wlRequest->inp = smb_CopyPacket(inp);
4927 wlRequest->outp = smb_CopyPacket(outp);
4928 wlRequest->lockType = LockType;
4929 wlRequest->timeRemaining = Timeout;
4930 wlRequest->locks = NULL;
4932 /* The waiting lock request needs to have enough
4933 information to undo all the locks in the request.
4934 We do the following to store info about locks that
4935 have already been granted. Sure, we can get most
4936 of the info from the packet, but the packet doesn't
4937 hold the result of cm_Lock call. In practice we
4938 only receive packets with one or two locks, so we
4939 are only wasting a few bytes here and there and
4940 only for a limited period of time until the waiting
4941 lock times out or is freed. */
4943 for(opt = op_locks, j=i; j > 0; j--) {
4944 smb_GetLockParams(LockType, &opt, &pid, &tOffset, &tLength);
4946 tkey = cm_GenerateKey(vcp->vcID, pid, fidp->fid);
4948 wLock = malloc(sizeof(smb_waitingLock_t));
4950 osi_assert(wLock != NULL);
4953 wLock->LOffset = tOffset;
4954 wLock->LLength = tLength;
4955 wLock->lockp = NULL;
4956 wLock->state = SMB_WAITINGLOCKSTATE_DONE;
4957 osi_QAdd((osi_queue_t **) &wlRequest->locks,
4962 wLock = malloc(sizeof(smb_waitingLock_t));
4964 osi_assert(wLock != NULL);
4967 wLock->LOffset = LOffset;
4968 wLock->LLength = LLength;
4969 wLock->lockp = lockp;
4970 wLock->state = SMB_WAITINGLOCKSTATE_WAITING;
4971 osi_QAdd((osi_queue_t **) &wlRequest->locks,
4974 osi_Log1(smb_logp, "smb_ReceiveV3Locking WaitingLock created 0x%x",
4982 osi_Log1(smb_logp, "smb_ReceiveV3Locking cm_Lock failure code 0x%x", code);
4989 /* Since something went wrong with the lock number i, we now
4990 have to go ahead and release any locks acquired before the
4991 failure. All locks before lock number i (of which there
4992 are i of them) have either been successful or are waiting.
4993 Either case requires calling cm_Unlock(). */
4995 /* And purge the waiting lock */
4996 if(wlRequest != NULL) {
4997 smb_waitingLock_t * wl;
4998 smb_waitingLock_t * wlNext;
5001 for(wl = wlRequest->locks; wl; wl = wlNext) {
5003 wlNext = (smb_waitingLock_t *) osi_QNext(&wl->q);
5005 ul_code = cm_Unlock(scp, LockType, wl->LOffset, wl->LLength, wl->key, userp, &req);
5008 osi_Log1(smb_logp, "smb_ReceiveV3Locking cm_Unlock returns code %d", ul_code);
5010 osi_Log0(smb_logp, "smb_ReceiveV3Locking cm_Unlock successful");
5013 osi_QRemove((osi_queue_t **) &wlRequest->locks, &wl->q);
5018 smb_ReleaseVC(wlRequest->vcp);
5019 cm_ReleaseSCache(wlRequest->scp);
5020 smb_FreePacket(wlRequest->inp);
5021 smb_FreePacket(wlRequest->outp);
5030 if (wlRequest != NULL) {
5032 lock_ObtainWrite(&smb_globalLock);
5033 osi_QAdd((osi_queue_t **)&smb_allWaitingLocks,
5035 osi_Wakeup((long) &smb_allWaitingLocks);
5036 lock_ReleaseWrite(&smb_globalLock);
5038 /* don't send reply immediately */
5039 outp->flags |= SMB_PACKETFLAG_NOSEND;
5042 smb_SetSMBDataLength(outp, 0);
5046 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_LOCK);
5049 lock_ReleaseMutex(&scp->mx);
5050 cm_ReleaseUser(userp);
5051 smb_ReleaseFID(fidp);
5056 long smb_ReceiveV3GetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5062 afs_uint32 searchTime;
5068 fid = smb_GetSMBParm(inp, 0);
5069 fid = smb_ChainFID(fid, inp);
5071 fidp = smb_FindFID(vcp, fid, 0);
5072 if (!fidp || (fidp->flags & SMB_FID_IOCTL)) {
5073 return CM_ERROR_BADFD;
5076 userp = smb_GetUser(vcp, inp);
5080 /* otherwise, stat the file */
5081 lock_ObtainMutex(&scp->mx);
5082 code = cm_SyncOp(scp, NULL, userp, &req, 0,
5083 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5084 if (code) goto done;
5086 /* decode times. We need a search time, but the response to this
5087 * call provides the date first, not the time, as returned in the
5088 * searchTime variable. So we take the high-order bits first.
5090 smb_SearchTimeFromUnixTime(&searchTime, scp->clientModTime);
5091 smb_SetSMBParm(outp, 0, (searchTime >> 16) & 0xffff); /* ctime */
5092 smb_SetSMBParm(outp, 1, searchTime & 0xffff);
5093 smb_SetSMBParm(outp, 2, (searchTime >> 16) & 0xffff); /* atime */
5094 smb_SetSMBParm(outp, 3, searchTime & 0xffff);
5095 smb_SetSMBParm(outp, 4, (searchTime >> 16) & 0xffff); /* mtime */
5096 smb_SetSMBParm(outp, 5, searchTime & 0xffff);
5098 /* now handle file size and allocation size */
5099 smb_SetSMBParm(outp, 6, scp->length.LowPart & 0xffff); /* file size */
5100 smb_SetSMBParm(outp, 7, (scp->length.LowPart >> 16) & 0xffff);
5101 smb_SetSMBParm(outp, 8, scp->length.LowPart & 0xffff); /* alloc size */
5102 smb_SetSMBParm(outp, 9, (scp->length.LowPart >> 16) & 0xffff);
5104 /* file attribute */
5105 smb_SetSMBParm(outp, 10, smb_Attributes(scp));
5107 /* and finalize stuff */
5108 smb_SetSMBDataLength(outp, 0);
5112 lock_ReleaseMutex(&scp->mx);
5113 cm_ReleaseUser(userp);
5114 smb_ReleaseFID(fidp);
5118 long smb_ReceiveV3SetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5124 afs_uint32 searchTime;
5132 fid = smb_GetSMBParm(inp, 0);
5133 fid = smb_ChainFID(fid, inp);
5135 fidp = smb_FindFID(vcp, fid, 0);
5136 if (!fidp || (fidp->flags & SMB_FID_IOCTL)) {
5137 return CM_ERROR_BADFD;
5140 userp = smb_GetUser(vcp, inp);
5144 /* now prepare to call cm_setattr. This message only sets various times,
5145 * and AFS only implements mtime, and we'll set the mtime if that's
5146 * requested. The others we'll ignore.
5148 searchTime = smb_GetSMBParm(inp, 5) | (smb_GetSMBParm(inp, 6) << 16);
5150 if (searchTime != 0) {
5151 smb_UnixTimeFromSearchTime(&unixTime, searchTime);
5153 if ( unixTime != -1 ) {
5154 attrs.mask = CM_ATTRMASK_CLIENTMODTIME;
5155 attrs.clientModTime = unixTime;
5156 code = cm_SetAttr(scp, &attrs, userp, &req);
5158 osi_Log1(smb_logp, "SMB receive V3SetAttributes [fid=%ld]", fid);
5160 osi_Log1(smb_logp, "**smb_UnixTimeFromSearchTime failed searchTime=%ld", searchTime);
5165 cm_ReleaseUser(userp);
5166 smb_ReleaseFID(fidp);
5171 long smb_ReceiveV3ReadX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5175 long finalCount = 0;
5184 fd = smb_GetSMBParm(inp, 2);
5185 count = smb_GetSMBParm(inp, 5);
5186 offset.HighPart = 0; /* too bad */
5187 offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
5189 osi_Log3(smb_logp, "smb_ReceiveV3Read fd %d, off 0x%x, size 0x%x",
5190 fd, offset.LowPart, count);
5192 fd = smb_ChainFID(fd, inp);
5193 fidp = smb_FindFID(vcp, fd, 0);
5195 return CM_ERROR_BADFD;
5198 pid = ((smb_t *) inp)->pid;
5199 key = cm_GenerateKey(vcp->vcID, pid, fd);
5201 LARGE_INTEGER LOffset, LLength;
5203 LOffset.HighPart = offset.HighPart;
5204 LOffset.LowPart = offset.LowPart;
5205 LLength.HighPart = 0;
5206 LLength.LowPart = count;
5208 lock_ObtainMutex(&fidp->scp->mx);
5209 code = cm_LockCheckRead(fidp->scp, LOffset, LLength, key);
5210 lock_ReleaseMutex(&fidp->scp->mx);
5214 smb_ReleaseFID(fidp);
5218 /* set inp->fid so that later read calls in same msg can find fid */
5221 if (fidp->flags & SMB_FID_IOCTL) {
5222 return smb_IoctlV3Read(fidp, vcp, inp, outp);
5225 userp = smb_GetUser(vcp, inp);
5227 /* 0 and 1 are reserved for request chaining, were setup by our caller,
5228 * and will be further filled in after we return.
5230 smb_SetSMBParm(outp, 2, 0); /* remaining bytes, for pipes */
5231 smb_SetSMBParm(outp, 3, 0); /* resvd */
5232 smb_SetSMBParm(outp, 4, 0); /* resvd */
5233 smb_SetSMBParm(outp, 5, count); /* # of bytes we're going to read */
5234 /* fill in #6 when we have all the parameters' space reserved */
5235 smb_SetSMBParm(outp, 7, 0); /* resv'd */
5236 smb_SetSMBParm(outp, 8, 0); /* resv'd */
5237 smb_SetSMBParm(outp, 9, 0); /* resv'd */
5238 smb_SetSMBParm(outp, 10, 0); /* resv'd */
5239 smb_SetSMBParm(outp, 11, 0); /* reserved */
5241 /* get op ptr after putting in the parms, since otherwise we don't
5242 * know where the data really is.
5244 op = smb_GetSMBData(outp, NULL);
5246 /* now fill in offset from start of SMB header to first data byte (to op) */
5247 smb_SetSMBParm(outp, 6, ((int) (op - outp->data)));
5249 /* set the packet data length the count of the # of bytes */
5250 smb_SetSMBDataLength(outp, count);
5253 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount);
5255 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount, FALSE);
5258 /* fix some things up */
5259 smb_SetSMBParm(outp, 5, finalCount);
5260 smb_SetSMBDataLength(outp, finalCount);
5262 smb_ReleaseFID(fidp);
5264 cm_ReleaseUser(userp);
5269 * Values for createDisp, copied from NTDDK.H
5271 #define FILE_SUPERSEDE 0 // (???)
5272 #define FILE_OPEN 1 // (open)
5273 #define FILE_CREATE 2 // (exclusive)
5274 #define FILE_OPEN_IF 3 // (non-exclusive)
5275 #define FILE_OVERWRITE 4 // (open & truncate, but do not create)
5276 #define FILE_OVERWRITE_IF 5 // (open & truncate, or create)
5279 #define REQUEST_OPLOCK 2
5280 #define REQUEST_BATCH_OPLOCK 4
5281 #define OPEN_DIRECTORY 8
5282 #define EXTENDED_RESPONSE_REQUIRED 0x10
5284 /* CreateOptions field. */
5285 #define FILE_DIRECTORY_FILE 0x0001
5286 #define FILE_WRITE_THROUGH 0x0002
5287 #define FILE_SEQUENTIAL_ONLY 0x0004
5288 #define FILE_NON_DIRECTORY_FILE 0x0040
5289 #define FILE_NO_EA_KNOWLEDGE 0x0200
5290 #define FILE_EIGHT_DOT_THREE_ONLY 0x0400
5291 #define FILE_RANDOM_ACCESS 0x0800
5292 #define FILE_DELETE_ON_CLOSE 0x1000
5293 #define FILE_OPEN_BY_FILE_ID 0x2000
5295 long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5297 char *pathp, *realPathp;
5301 cm_scache_t *dscp; /* parent dir */
5302 cm_scache_t *scp; /* file to create or open */
5303 cm_scache_t *targetScp; /* if scp is a symlink */
5307 unsigned short nameLength;
5309 unsigned int requestOpLock;
5310 unsigned int requestBatchOpLock;
5311 unsigned int mustBeDir;
5312 unsigned int extendedRespRequired;
5313 unsigned int treeCreate;
5315 unsigned int desiredAccess;
5316 unsigned int extAttributes;
5317 unsigned int createDisp;
5318 unsigned int createOptions;
5319 unsigned int shareAccess;
5320 int initialModeBits;
5321 unsigned short baseFid;
5322 smb_fid_t *baseFidp;
5324 cm_scache_t *baseDirp;
5325 unsigned short openAction;
5336 /* This code is very long and has a lot of if-then-else clauses
5337 * scp and dscp get reused frequently and we need to ensure that
5338 * we don't lose a reference. Start by ensuring that they are NULL.
5345 nameLength = smb_GetSMBOffsetParm(inp, 2, 1);
5346 flags = smb_GetSMBOffsetParm(inp, 3, 1)
5347 | (smb_GetSMBOffsetParm(inp, 4, 1) << 16);
5348 requestOpLock = flags & REQUEST_OPLOCK;
5349 requestBatchOpLock = flags & REQUEST_BATCH_OPLOCK;
5350 mustBeDir = flags & OPEN_DIRECTORY;
5351 extendedRespRequired = flags & EXTENDED_RESPONSE_REQUIRED;
5354 * Why all of a sudden 32-bit FID?
5355 * We will reject all bits higher than 16.
5357 if (smb_GetSMBOffsetParm(inp, 6, 1) != 0)
5358 return CM_ERROR_INVAL;
5359 baseFid = smb_GetSMBOffsetParm(inp, 5, 1);
5360 desiredAccess = smb_GetSMBOffsetParm(inp, 7, 1)
5361 | (smb_GetSMBOffsetParm(inp, 8, 1) << 16);
5362 extAttributes = smb_GetSMBOffsetParm(inp, 13, 1)
5363 | (smb_GetSMBOffsetParm(inp, 14, 1) << 16);
5364 shareAccess = smb_GetSMBOffsetParm(inp, 15, 1)
5365 | (smb_GetSMBOffsetParm(inp, 16, 1) << 16);
5366 createDisp = smb_GetSMBOffsetParm(inp, 17, 1)
5367 | (smb_GetSMBOffsetParm(inp, 18, 1) << 16);
5368 createOptions = smb_GetSMBOffsetParm(inp, 19, 1)
5369 | (smb_GetSMBOffsetParm(inp, 20, 1) << 16);
5371 /* mustBeDir is never set; createOptions directory bit seems to be
5374 if (createOptions & FILE_DIRECTORY_FILE)
5376 else if (createOptions & FILE_NON_DIRECTORY_FILE)
5382 * compute initial mode bits based on read-only flag in
5383 * extended attributes
5385 initialModeBits = 0666;
5386 if (extAttributes & SMB_ATTR_READONLY)
5387 initialModeBits &= ~0222;
5389 pathp = smb_GetSMBData(inp, NULL);
5390 /* Sometimes path is not null-terminated, so we make a copy. */
5391 realPathp = malloc(nameLength+1);
5392 memcpy(realPathp, pathp, nameLength);
5393 realPathp[nameLength] = 0;
5394 if (smb_StoreAnsiFilenames)
5395 OemToChar(realPathp,realPathp);
5397 spacep = inp->spacep;
5398 smb_StripLastComponent(spacep->data, &lastNamep, realPathp);
5400 osi_Log1(smb_logp,"NTCreateX for [%s]",osi_LogSaveString(smb_logp,realPathp));
5401 osi_Log4(smb_logp,"... da=[%x] ea=[%x] cd=[%x] co=[%x]", desiredAccess, extAttributes, createDisp, createOptions);
5402 osi_Log3(smb_logp,"... share=[%x] flags=[%x] lastNamep=[%s]", shareAccess, flags, osi_LogSaveString(smb_logp,(lastNamep?lastNamep:"null")));
5404 if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
5405 /* special case magic file name for receiving IOCTL requests
5406 * (since IOCTL calls themselves aren't getting through).
5408 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
5409 smb_SetupIoctlFid(fidp, spacep);
5410 osi_Log1(smb_logp,"NTCreateX Setting up IOCTL on fid[%d]",fidp->fid);
5412 /* set inp->fid so that later read calls in same msg can find fid */
5413 inp->fid = fidp->fid;
5417 smb_SetSMBParmByte(outp, parmSlot, 0); /* oplock */
5418 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
5419 smb_SetSMBParmLong(outp, parmSlot, 1); parmSlot += 2; /* Action */
5421 memset(&ft, 0, sizeof(ft));
5422 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
5423 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
5424 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
5425 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
5426 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2; /* attr */
5427 sz.HighPart = 0x7fff; sz.LowPart = 0;
5428 smb_SetSMBParmDouble(outp, parmSlot, (char *)&sz); parmSlot += 4; /* alen */
5429 smb_SetSMBParmDouble(outp, parmSlot, (char *)&sz); parmSlot += 4; /* len */
5430 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* filetype */
5431 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* dev state */
5432 smb_SetSMBParmByte(outp, parmSlot, 0); /* is a dir? */
5433 smb_SetSMBDataLength(outp, 0);
5435 /* clean up fid reference */
5436 smb_ReleaseFID(fidp);
5441 #ifdef DEBUG_VERBOSE
5443 char *hexp, *asciip;
5444 asciip = (lastNamep? lastNamep : realPathp);
5445 hexp = osi_HexifyString( asciip );
5446 DEBUG_EVENT2("AFS", "NTCreateX H[%s] A[%s]", hexp, asciip);
5451 userp = smb_GetUser(vcp, inp);
5453 osi_Log1(smb_logp, "NTCreateX Invalid user [%d]", ((smb_t *) inp)->uid);
5455 return CM_ERROR_INVAL;
5459 baseDirp = cm_data.rootSCachep;
5460 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5461 if (code == CM_ERROR_TIDIPC) {
5462 /* Attempt to use a TID allocated for IPC. The client
5463 * is probably looking for DCE RPC end points which we
5464 * don't support OR it could be looking to make a DFS
5467 osi_Log0(smb_logp, "NTCreateX received IPC TID");
5470 cm_ReleaseUser(userp);
5471 return CM_ERROR_NOSUCHFILE;
5472 #endif /* DFS_SUPPORT */
5475 baseFidp = smb_FindFID(vcp, baseFid, 0);
5477 osi_Log1(smb_logp, "NTCreateX Invalid base fid [%d]", baseFid);
5479 cm_ReleaseUser(userp);
5480 return CM_ERROR_INVAL;
5482 baseDirp = baseFidp->scp;
5486 osi_Log1(smb_logp, "NTCreateX tidPathp=[%s]", (tidPathp==NULL)?"null": osi_LogSaveString(smb_logp,tidPathp));
5488 /* compute open mode */
5490 if (desiredAccess & DELETE)
5491 fidflags |= SMB_FID_OPENDELETE;
5492 if (desiredAccess & AFS_ACCESS_READ)
5493 fidflags |= SMB_FID_OPENREAD;
5494 if (desiredAccess & AFS_ACCESS_WRITE)
5495 fidflags |= SMB_FID_OPENWRITE;
5496 if (createOptions & FILE_DELETE_ON_CLOSE)
5497 fidflags |= SMB_FID_DELONCLOSE;
5499 /* and the share mode */
5500 if (shareAccess & FILE_SHARE_READ)
5501 fidflags |= SMB_FID_SHARE_READ;
5502 if (shareAccess & FILE_SHARE_WRITE)
5503 fidflags |= SMB_FID_SHARE_WRITE;
5507 /* For an exclusive create, we want to do a case sensitive match for the last component. */
5508 if ( createDisp == FILE_CREATE ||
5509 createDisp == FILE_OVERWRITE ||
5510 createDisp == FILE_OVERWRITE_IF) {
5511 code = cm_NameI(baseDirp, spacep->data, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
5512 userp, tidPathp, &req, &dscp);
5515 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
5516 cm_ReleaseSCache(dscp);
5517 cm_ReleaseUser(userp);
5519 if ( WANTS_DFS_PATHNAMES(inp) )
5520 return CM_ERROR_PATH_NOT_COVERED;
5522 return CM_ERROR_BADSHARENAME;
5524 #endif /* DFS_SUPPORT */
5525 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp, CM_FLAG_FOLLOW,
5527 if (code == CM_ERROR_NOSUCHFILE) {
5528 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp,
5529 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, &req, &scp);
5530 if (code == 0 && realDirFlag == 1) {
5531 cm_ReleaseSCache(scp);
5532 cm_ReleaseSCache(dscp);
5533 cm_ReleaseUser(userp);
5535 return CM_ERROR_EXISTS;
5539 /* we have both scp and dscp */
5541 code = cm_NameI(baseDirp, realPathp, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
5542 userp, tidPathp, &req, &scp);
5544 if (code == 0 && scp->fileType == CM_SCACHETYPE_DFSLINK) {
5545 cm_ReleaseSCache(scp);
5546 cm_ReleaseUser(userp);
5548 if ( WANTS_DFS_PATHNAMES(inp) )
5549 return CM_ERROR_PATH_NOT_COVERED;
5551 return CM_ERROR_BADSHARENAME;
5553 #endif /* DFS_SUPPORT */
5554 /* we might have scp but not dscp */
5560 if (!foundscp || (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE))) {
5561 /* look up parent directory */
5562 /* If we are trying to create a path (i.e. multiple nested directories), then we don't *need*
5563 * the immediate parent. We have to work our way up realPathp until we hit something that we
5567 /* we might or might not have scp */
5573 code = cm_NameI(baseDirp, spacep->data,
5574 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
5575 userp, tidPathp, &req, &dscp);
5578 if (code == 0 && dscp->fileType == CM_SCACHETYPE_DFSLINK) {
5580 cm_ReleaseSCache(scp);
5581 cm_ReleaseSCache(dscp);
5582 cm_ReleaseUser(userp);
5584 if ( WANTS_DFS_PATHNAMES(inp) )
5585 return CM_ERROR_PATH_NOT_COVERED;
5587 return CM_ERROR_BADSHARENAME;
5589 #endif /* DFS_SUPPORT */
5592 (tp = strrchr(spacep->data,'\\')) &&
5593 (createDisp == FILE_CREATE) &&
5594 (realDirFlag == 1)) {
5597 treeStartp = realPathp + (tp - spacep->data);
5599 if (*tp && !smb_IsLegalFilename(tp)) {
5601 smb_ReleaseFID(baseFidp);
5602 cm_ReleaseUser(userp);
5605 cm_ReleaseSCache(scp);
5606 return CM_ERROR_BADNTFILENAME;
5610 } while (dscp == NULL && code == 0);
5614 /* we might have scp and we might have dscp */
5617 smb_ReleaseFID(baseFidp);
5620 osi_Log0(smb_logp,"NTCreateX parent not found");
5622 cm_ReleaseSCache(scp);
5624 cm_ReleaseSCache(dscp);
5625 cm_ReleaseUser(userp);
5630 if (treeCreate && dscp->fileType == CM_SCACHETYPE_FILE) {
5631 /* A file exists where we want a directory. */
5633 cm_ReleaseSCache(scp);
5634 cm_ReleaseSCache(dscp);
5635 cm_ReleaseUser(userp);
5637 return CM_ERROR_EXISTS;
5641 lastNamep = realPathp;
5645 if (!smb_IsLegalFilename(lastNamep)) {
5647 cm_ReleaseSCache(scp);
5649 cm_ReleaseSCache(dscp);
5650 cm_ReleaseUser(userp);
5652 return CM_ERROR_BADNTFILENAME;
5655 if (!foundscp && !treeCreate) {
5656 if ( createDisp == FILE_CREATE ||
5657 createDisp == FILE_OVERWRITE ||
5658 createDisp == FILE_OVERWRITE_IF)
5660 code = cm_Lookup(dscp, lastNamep,
5661 CM_FLAG_FOLLOW, userp, &req, &scp);
5663 code = cm_Lookup(dscp, lastNamep,
5664 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
5667 if (code && code != CM_ERROR_NOSUCHFILE) {
5669 cm_ReleaseSCache(dscp);
5670 cm_ReleaseUser(userp);
5675 /* we have scp and dscp */
5677 /* we have scp but not dscp */
5679 smb_ReleaseFID(baseFidp);
5682 /* if we get here, if code is 0, the file exists and is represented by
5683 * scp. Otherwise, we have to create it. The dir may be represented
5684 * by dscp, or we may have found the file directly. If code is non-zero,
5687 if (code == 0 && !treeCreate) {
5688 if (createDisp == FILE_CREATE) {
5689 /* oops, file shouldn't be there */
5691 cm_ReleaseSCache(dscp);
5693 cm_ReleaseSCache(scp);
5694 cm_ReleaseUser(userp);
5696 return CM_ERROR_EXISTS;
5699 if ( createDisp == FILE_OVERWRITE ||
5700 createDisp == FILE_OVERWRITE_IF) {
5702 setAttr.mask = CM_ATTRMASK_LENGTH;
5703 setAttr.length.LowPart = 0;
5704 setAttr.length.HighPart = 0;
5705 /* now watch for a symlink */
5707 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
5709 osi_assert(dscp != NULL);
5710 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
5712 /* we have a more accurate file to use (the
5713 * target of the symbolic link). Otherwise,
5714 * we'll just use the symlink anyway.
5716 osi_Log2(smb_logp, "symlink vp %x to vp %x",
5718 cm_ReleaseSCache(scp);
5722 code = cm_SetAttr(scp, &setAttr, userp, &req);
5723 openAction = 3; /* truncated existing file */
5726 openAction = 1; /* found existing file */
5728 code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp, &req);
5731 cm_ReleaseSCache(dscp);
5733 cm_ReleaseSCache(scp);
5734 cm_ReleaseUser(userp);
5738 } else if (createDisp == FILE_OPEN || createDisp == FILE_OVERWRITE) {
5739 /* don't create if not found */
5741 cm_ReleaseSCache(dscp);
5743 cm_ReleaseSCache(scp);
5744 cm_ReleaseUser(userp);
5746 return CM_ERROR_NOSUCHFILE;
5747 } else if (realDirFlag == 0 || realDirFlag == -1) {
5748 osi_assert(dscp != NULL);
5749 osi_Log1(smb_logp, "smb_ReceiveNTCreateX creating file %s",
5750 osi_LogSaveString(smb_logp, lastNamep));
5751 openAction = 2; /* created file */
5752 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
5753 setAttr.clientModTime = time(NULL);
5754 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp, &req);
5755 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
5756 smb_NotifyChange(FILE_ACTION_ADDED,
5757 FILE_NOTIFY_CHANGE_FILE_NAME,
5758 dscp, lastNamep, NULL, TRUE);
5759 if (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE) {
5760 /* Not an exclusive create, and someone else tried
5761 * creating it already, then we open it anyway. We
5762 * don't bother retrying after this, since if this next
5763 * fails, that means that the file was deleted after we
5764 * started this call.
5766 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
5769 if (createDisp == FILE_OVERWRITE_IF) {
5770 setAttr.mask = CM_ATTRMASK_LENGTH;
5771 setAttr.length.LowPart = 0;
5772 setAttr.length.HighPart = 0;
5774 /* now watch for a symlink */
5776 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
5778 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
5780 /* we have a more accurate file to use (the
5781 * target of the symbolic link). Otherwise,
5782 * we'll just use the symlink anyway.
5784 osi_Log2(smb_logp, "symlink vp %x to vp %x",
5786 cm_ReleaseSCache(scp);
5790 code = cm_SetAttr(scp, &setAttr, userp, &req);
5792 } /* lookup succeeded */
5796 char *cp; /* This component */
5797 int clen = 0; /* length of component */
5798 cm_scache_t *tscp1, *tscp2;
5801 /* create directory */
5803 treeStartp = lastNamep;
5804 osi_assert(dscp != NULL);
5805 osi_Log1(smb_logp, "smb_ReceiveNTCreateX creating directory [%s]",
5806 osi_LogSaveString(smb_logp, treeStartp));
5807 openAction = 2; /* created directory */
5809 /* if the request is to create the root directory
5810 * it will appear as a directory name of the nul-string
5811 * and a code of CM_ERROR_NOSUCHFILE
5813 if ( !*treeStartp && code == CM_ERROR_NOSUCHFILE)
5814 code = CM_ERROR_EXISTS;
5816 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
5817 setAttr.clientModTime = time(NULL);
5822 cm_HoldSCache(tscp1);
5826 tp = strchr(pp, '\\');
5830 isLast = 1; /* indicate last component. the supplied path never ends in a slash */
5833 strncpy(cp,pp,clen);
5840 continue; /* the supplied path can't have consecutive slashes either , but */
5842 /* cp is the next component to be created. */
5843 code = cm_MakeDir(tscp1, cp, 0, &setAttr, userp, &req);
5844 if (code == 0 && (tscp1->flags & CM_SCACHEFLAG_ANYWATCH))
5845 smb_NotifyChange(FILE_ACTION_ADDED,
5846 FILE_NOTIFY_CHANGE_DIR_NAME,
5847 tscp1, cp, NULL, TRUE);
5849 (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE)) {
5850 /* Not an exclusive create, and someone else tried
5851 * creating it already, then we open it anyway. We
5852 * don't bother retrying after this, since if this next
5853 * fails, that means that the file was deleted after we
5854 * started this call.
5856 code = cm_Lookup(tscp1, cp, CM_FLAG_CASEFOLD,
5857 userp, &req, &tscp2);
5862 if (!isLast) { /* for anything other than dscp, release it unless it's the last one */
5863 cm_ReleaseSCache(tscp1);
5864 tscp1 = tscp2; /* Newly created directory will be next parent */
5865 /* the hold is transfered to tscp1 from tscp2 */
5870 cm_ReleaseSCache(dscp);
5873 cm_ReleaseSCache(scp);
5876 * if we get here and code == 0, then scp is the last directory created, and dscp is the
5882 /* something went wrong creating or truncating the file */
5884 cm_ReleaseSCache(scp);
5886 cm_ReleaseSCache(dscp);
5887 cm_ReleaseUser(userp);
5892 /* make sure we have file vs. dir right (only applies for single component case) */
5893 if (realDirFlag == 0 && scp->fileType != CM_SCACHETYPE_FILE) {
5894 /* now watch for a symlink */
5896 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
5897 cm_scache_t * targetScp = 0;
5898 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
5900 /* we have a more accurate file to use (the
5901 * target of the symbolic link). Otherwise,
5902 * we'll just use the symlink anyway.
5904 osi_Log2(smb_logp, "symlink vp %x to vp %x", scp, targetScp);
5905 cm_ReleaseSCache(scp);
5910 if (scp->fileType != CM_SCACHETYPE_FILE) {
5912 cm_ReleaseSCache(dscp);
5913 cm_ReleaseSCache(scp);
5914 cm_ReleaseUser(userp);
5916 return CM_ERROR_ISDIR;
5920 /* (only applies to single component case) */
5921 if (realDirFlag == 1 && scp->fileType == CM_SCACHETYPE_FILE) {
5922 cm_ReleaseSCache(scp);
5924 cm_ReleaseSCache(dscp);
5925 cm_ReleaseUser(userp);
5927 return CM_ERROR_NOTDIR;
5930 /* open the file itself */
5931 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
5934 /* If we are restricting sharing, we should do so with a suitable
5936 if (scp->fileType == CM_SCACHETYPE_FILE &&
5937 !(fidflags & SMB_FID_SHARE_WRITE)) {
5939 LARGE_INTEGER LOffset, LLength;
5942 LOffset.HighPart = SMB_FID_QLOCK_HIGH;
5943 LOffset.LowPart = SMB_FID_QLOCK_LOW;
5944 LLength.HighPart = 0;
5945 LLength.LowPart = SMB_FID_QLOCK_LENGTH;
5947 if (fidflags & SMB_FID_SHARE_READ) {
5948 sLockType = LOCKING_ANDX_SHARED_LOCK;
5953 key = cm_GenerateKey(vcp->vcID, SMB_FID_QLOCK_PID, fidp->fid);
5955 lock_ObtainMutex(&scp->mx);
5956 code = cm_Lock(scp, sLockType, LOffset, LLength, key, 0, userp, &req, NULL);
5957 lock_ReleaseMutex(&scp->mx);
5960 fidp->flags = SMB_FID_DELETE;
5961 smb_ReleaseFID(fidp);
5963 cm_ReleaseSCache(scp);
5965 cm_ReleaseSCache(dscp);
5966 cm_ReleaseUser(userp);
5973 /* save a pointer to the vnode */
5974 fidp->scp = scp; /* Hold transfered to fidp->scp and no longer needed */
5976 fidp->flags = fidflags;
5978 /* save parent dir and pathname for delete or change notification */
5979 if (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE)) {
5980 fidp->flags |= SMB_FID_NTOPEN;
5981 fidp->NTopen_dscp = dscp;
5982 cm_HoldSCache(dscp);
5983 fidp->NTopen_pathp = strdup(lastNamep);
5985 fidp->NTopen_wholepathp = realPathp;
5987 /* we don't need this any longer */
5989 cm_ReleaseSCache(dscp);
5993 cm_Open(scp, 0, userp);
5995 /* set inp->fid so that later read calls in same msg can find fid */
5996 inp->fid = fidp->fid;
6000 lock_ObtainMutex(&scp->mx);
6001 smb_SetSMBParmByte(outp, parmSlot, 0); /* oplock */
6002 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
6003 smb_SetSMBParmLong(outp, parmSlot, openAction); parmSlot += 2;
6004 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
6005 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
6006 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
6007 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
6008 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
6009 smb_SetSMBParmLong(outp, parmSlot, smb_ExtAttributes(scp));
6011 smb_SetSMBParmDouble(outp, parmSlot, (char *)&scp->length); parmSlot += 4;
6012 smb_SetSMBParmDouble(outp, parmSlot, (char *)&scp->length); parmSlot += 4;
6013 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* filetype */
6014 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* dev state */
6015 smb_SetSMBParmByte(outp, parmSlot,
6016 scp->fileType == CM_SCACHETYPE_DIRECTORY); /* is a dir? */
6017 lock_ReleaseMutex(&scp->mx);
6018 smb_SetSMBDataLength(outp, 0);
6020 osi_Log2(smb_logp, "SMB NT CreateX opening fid %d path %s", fidp->fid,
6021 osi_LogSaveString(smb_logp, realPathp));
6023 smb_ReleaseFID(fidp);
6025 cm_ReleaseUser(userp);
6027 /* Can't free realPathp if we get here since
6028 fidp->NTopen_wholepathp is pointing there */
6030 /* leave scp held since we put it in fidp->scp */
6035 * A lot of stuff copied verbatim from NT Create&X to NT Tran Create.
6036 * Instead, ultimately, would like to use a subroutine for common code.
6038 long smb_ReceiveNTTranCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6040 char *pathp, *realPathp;
6044 cm_scache_t *dscp; /* parent dir */
6045 cm_scache_t *scp; /* file to create or open */
6046 cm_scache_t *targetScp; /* if scp is a symlink */
6049 unsigned long nameLength;
6051 unsigned int requestOpLock;
6052 unsigned int requestBatchOpLock;
6053 unsigned int mustBeDir;
6054 unsigned int extendedRespRequired;
6056 unsigned int desiredAccess;
6057 #ifdef DEBUG_VERBOSE
6058 unsigned int allocSize;
6060 unsigned int shareAccess;
6061 unsigned int extAttributes;
6062 unsigned int createDisp;
6063 #ifdef DEBUG_VERBOSE
6066 unsigned int createOptions;
6067 int initialModeBits;
6068 unsigned short baseFid;
6069 smb_fid_t *baseFidp;
6071 cm_scache_t *baseDirp;
6072 unsigned short openAction;
6078 int parmOffset, dataOffset;
6089 parmOffset = smb_GetSMBOffsetParm(inp, 11, 1)
6090 | (smb_GetSMBOffsetParm(inp, 12, 1) << 16);
6091 parmp = inp->data + parmOffset;
6092 lparmp = (ULONG *) parmp;
6095 requestOpLock = flags & REQUEST_OPLOCK;
6096 requestBatchOpLock = flags & REQUEST_BATCH_OPLOCK;
6097 mustBeDir = flags & OPEN_DIRECTORY;
6098 extendedRespRequired = flags & EXTENDED_RESPONSE_REQUIRED;
6101 * Why all of a sudden 32-bit FID?
6102 * We will reject all bits higher than 16.
6104 if (lparmp[1] & 0xFFFF0000)
6105 return CM_ERROR_INVAL;
6106 baseFid = (unsigned short)lparmp[1];
6107 desiredAccess = lparmp[2];
6108 #ifdef DEBUG_VERBOSE
6109 allocSize = lparmp[3];
6110 #endif /* DEBUG_VERSOSE */
6111 extAttributes = lparmp[5];
6112 shareAccess = lparmp[6];
6113 createDisp = lparmp[7];
6114 createOptions = lparmp[8];
6115 #ifdef DEBUG_VERBOSE
6118 nameLength = lparmp[11];
6120 #ifdef DEBUG_VERBOSE
6121 osi_Log4(smb_logp,"NTTranCreate with da[%x],ea[%x],sa[%x],cd[%x]",desiredAccess,extAttributes,shareAccess,createDisp);
6122 osi_Log3(smb_logp,"... co[%x],sdl[%x],as[%x]",createOptions,sdLen,allocSize);
6123 osi_Log1(smb_logp,"... flags[%x]",flags);
6126 /* mustBeDir is never set; createOptions directory bit seems to be
6129 if (createOptions & FILE_DIRECTORY_FILE)
6131 else if (createOptions & FILE_NON_DIRECTORY_FILE)
6137 * compute initial mode bits based on read-only flag in
6138 * extended attributes
6140 initialModeBits = 0666;
6141 if (extAttributes & 1)
6142 initialModeBits &= ~0222;
6144 pathp = parmp + (13 * sizeof(ULONG)) + sizeof(UCHAR);
6145 /* Sometimes path is not null-terminated, so we make a copy. */
6146 realPathp = malloc(nameLength+1);
6147 memcpy(realPathp, pathp, nameLength);
6148 realPathp[nameLength] = 0;
6149 if (smb_StoreAnsiFilenames)
6150 OemToChar(realPathp,realPathp);
6152 spacep = cm_GetSpace();
6153 smb_StripLastComponent(spacep->data, &lastNamep, realPathp);
6156 * Nothing here to handle SMB_IOCTL_FILENAME.
6157 * Will add it if necessary.
6160 #ifdef DEBUG_VERBOSE
6162 char *hexp, *asciip;
6163 asciip = (lastNamep? lastNamep : realPathp);
6164 hexp = osi_HexifyString( asciip );
6165 DEBUG_EVENT2("AFS", "NTTranCreate H[%s] A[%s]", hexp, asciip);
6170 userp = smb_GetUser(vcp, inp);
6172 osi_Log1(smb_logp, "NTTranCreate invalid user [%d]", ((smb_t *) inp)->uid);
6174 return CM_ERROR_INVAL;
6178 baseDirp = cm_data.rootSCachep;
6179 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
6180 if (code == CM_ERROR_TIDIPC) {
6181 /* Attempt to use a TID allocated for IPC. The client
6182 * is probably looking for DCE RPC end points which we
6183 * don't support OR it could be looking to make a DFS
6186 osi_Log0(smb_logp, "NTTranCreate received IPC TID");
6189 cm_ReleaseUser(userp);
6190 return CM_ERROR_NOSUCHPATH;
6194 baseFidp = smb_FindFID(vcp, baseFid, 0);
6196 osi_Log1(smb_logp, "NTTranCreate Invalid fid [%d]", baseFid);
6198 cm_ReleaseUser(userp);
6199 return CM_ERROR_INVAL;
6201 baseDirp = baseFidp->scp;
6205 /* compute open mode */
6207 if (desiredAccess & DELETE)
6208 fidflags |= SMB_FID_OPENDELETE;
6209 if (desiredAccess & AFS_ACCESS_READ)
6210 fidflags |= SMB_FID_OPENREAD;
6211 if (desiredAccess & AFS_ACCESS_WRITE)
6212 fidflags |= SMB_FID_OPENWRITE;
6213 if (createOptions & FILE_DELETE_ON_CLOSE)
6214 fidflags |= SMB_FID_DELONCLOSE;
6216 /* And the share mode */
6217 if (shareAccess & FILE_SHARE_READ)
6218 fidflags |= SMB_FID_SHARE_READ;
6219 if (shareAccess & FILE_SHARE_WRITE)
6220 fidflags |= SMB_FID_SHARE_WRITE;
6224 if ( createDisp == FILE_OPEN ||
6225 createDisp == FILE_OVERWRITE ||
6226 createDisp == FILE_OVERWRITE_IF) {
6227 code = cm_NameI(baseDirp, spacep->data, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
6228 userp, tidPathp, &req, &dscp);
6231 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
6232 cm_ReleaseSCache(dscp);
6233 cm_ReleaseUser(userp);
6235 if ( WANTS_DFS_PATHNAMES(inp) )
6236 return CM_ERROR_PATH_NOT_COVERED;
6238 return CM_ERROR_BADSHARENAME;
6240 #endif /* DFS_SUPPORT */
6241 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp, CM_FLAG_FOLLOW,
6243 if (code == CM_ERROR_NOSUCHFILE) {
6244 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp,
6245 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, &req, &scp);
6246 if (code == 0 && realDirFlag == 1) {
6247 cm_ReleaseSCache(scp);
6248 cm_ReleaseSCache(dscp);
6249 cm_ReleaseUser(userp);
6251 return CM_ERROR_EXISTS;
6257 code = cm_NameI(baseDirp, realPathp, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
6258 userp, tidPathp, &req, &scp);
6260 if (code == 0 && scp->fileType == CM_SCACHETYPE_DFSLINK) {
6261 cm_ReleaseSCache(scp);
6262 cm_ReleaseUser(userp);
6264 if ( WANTS_DFS_PATHNAMES(inp) )
6265 return CM_ERROR_PATH_NOT_COVERED;
6267 return CM_ERROR_BADSHARENAME;
6269 #endif /* DFS_SUPPORT */
6275 if (code != 0 || (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE))) {
6276 /* look up parent directory */
6278 code = cm_NameI(baseDirp, spacep->data,
6279 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
6280 userp, tidPathp, &req, &dscp);
6282 if (code == 0 && dscp->fileType == CM_SCACHETYPE_DFSLINK) {
6283 cm_ReleaseSCache(dscp);
6284 cm_ReleaseUser(userp);
6286 if ( WANTS_DFS_PATHNAMES(inp) )
6287 return CM_ERROR_PATH_NOT_COVERED;
6289 return CM_ERROR_BADSHARENAME;
6291 #endif /* DFS_SUPPORT */
6295 cm_FreeSpace(spacep);
6298 smb_ReleaseFID(baseFidp);
6303 cm_ReleaseUser(userp);
6308 if (!lastNamep) lastNamep = realPathp;
6311 if (!smb_IsLegalFilename(lastNamep))
6312 return CM_ERROR_BADNTFILENAME;
6315 if (createDisp == FILE_CREATE || createDisp == FILE_OVERWRITE_IF) {
6316 code = cm_Lookup(dscp, lastNamep,
6317 CM_FLAG_FOLLOW, userp, &req, &scp);
6319 code = cm_Lookup(dscp, lastNamep,
6320 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
6323 if (code && code != CM_ERROR_NOSUCHFILE) {
6324 cm_ReleaseSCache(dscp);
6325 cm_ReleaseUser(userp);
6332 smb_ReleaseFID(baseFidp);
6335 cm_FreeSpace(spacep);
6338 /* if we get here, if code is 0, the file exists and is represented by
6339 * scp. Otherwise, we have to create it. The dir may be represented
6340 * by dscp, or we may have found the file directly. If code is non-zero,
6344 code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp,
6348 cm_ReleaseSCache(dscp);
6349 cm_ReleaseSCache(scp);
6350 cm_ReleaseUser(userp);
6355 if (createDisp == FILE_CREATE) {
6356 /* oops, file shouldn't be there */
6358 cm_ReleaseSCache(dscp);
6359 cm_ReleaseSCache(scp);
6360 cm_ReleaseUser(userp);
6362 return CM_ERROR_EXISTS;
6365 if (createDisp == FILE_OVERWRITE ||
6366 createDisp == FILE_OVERWRITE_IF) {
6367 setAttr.mask = CM_ATTRMASK_LENGTH;
6368 setAttr.length.LowPart = 0;
6369 setAttr.length.HighPart = 0;
6371 /* now watch for a symlink */
6373 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
6375 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
6377 /* we have a more accurate file to use (the
6378 * target of the symbolic link). Otherwise,
6379 * we'll just use the symlink anyway.
6381 osi_Log2(smb_logp, "symlink vp %x to vp %x",
6383 cm_ReleaseSCache(scp);
6387 code = cm_SetAttr(scp, &setAttr, userp, &req);
6388 openAction = 3; /* truncated existing file */
6390 else openAction = 1; /* found existing file */
6392 else if (createDisp == FILE_OPEN || createDisp == FILE_OVERWRITE) {
6393 /* don't create if not found */
6395 cm_ReleaseSCache(dscp);
6396 cm_ReleaseUser(userp);
6398 return CM_ERROR_NOSUCHFILE;
6400 else if (realDirFlag == 0 || realDirFlag == -1) {
6401 osi_assert(dscp != NULL);
6402 osi_Log1(smb_logp, "smb_ReceiveNTTranCreate creating file %s",
6403 osi_LogSaveString(smb_logp, lastNamep));
6404 openAction = 2; /* created file */
6405 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
6406 setAttr.clientModTime = time(NULL);
6407 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
6409 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
6410 smb_NotifyChange(FILE_ACTION_ADDED,
6411 FILE_NOTIFY_CHANGE_FILE_NAME,
6412 dscp, lastNamep, NULL, TRUE);
6413 if (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE) {
6414 /* Not an exclusive create, and someone else tried
6415 * creating it already, then we open it anyway. We
6416 * don't bother retrying after this, since if this next
6417 * fails, that means that the file was deleted after we
6418 * started this call.
6420 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
6423 if (createDisp == FILE_OVERWRITE_IF) {
6424 setAttr.mask = CM_ATTRMASK_LENGTH;
6425 setAttr.length.LowPart = 0;
6426 setAttr.length.HighPart = 0;
6428 /* now watch for a symlink */
6430 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
6432 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
6434 /* we have a more accurate file to use (the
6435 * target of the symbolic link). Otherwise,
6436 * we'll just use the symlink anyway.
6438 osi_Log2(smb_logp, "symlink vp %x to vp %x",
6440 cm_ReleaseSCache(scp);
6444 code = cm_SetAttr(scp, &setAttr, userp, &req);
6446 } /* lookup succeeded */
6449 /* create directory */
6450 osi_assert(dscp != NULL);
6452 "smb_ReceiveNTTranCreate creating directory %s",
6453 osi_LogSaveString(smb_logp, lastNamep));
6454 openAction = 2; /* created directory */
6455 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
6456 setAttr.clientModTime = time(NULL);
6457 code = cm_MakeDir(dscp, lastNamep, 0, &setAttr, userp, &req);
6458 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
6459 smb_NotifyChange(FILE_ACTION_ADDED,
6460 FILE_NOTIFY_CHANGE_DIR_NAME,
6461 dscp, lastNamep, NULL, TRUE);
6463 (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE)) {
6464 /* Not an exclusive create, and someone else tried
6465 * creating it already, then we open it anyway. We
6466 * don't bother retrying after this, since if this next
6467 * fails, that means that the file was deleted after we
6468 * started this call.
6470 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
6476 /* something went wrong creating or truncating the file */
6478 cm_ReleaseSCache(scp);
6479 cm_ReleaseUser(userp);
6484 /* make sure we have file vs. dir right */
6485 if (realDirFlag == 0 && scp->fileType != CM_SCACHETYPE_FILE) {
6486 /* now watch for a symlink */
6488 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
6490 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
6492 /* we have a more accurate file to use (the
6493 * target of the symbolic link). Otherwise,
6494 * we'll just use the symlink anyway.
6496 osi_Log2(smb_logp, "symlink vp %x to vp %x",
6498 cm_ReleaseSCache(scp);
6503 if (scp->fileType != CM_SCACHETYPE_FILE) {
6504 cm_ReleaseSCache(scp);
6505 cm_ReleaseUser(userp);
6507 return CM_ERROR_ISDIR;
6511 if (realDirFlag == 1 && scp->fileType == CM_SCACHETYPE_FILE) {
6512 cm_ReleaseSCache(scp);
6513 cm_ReleaseUser(userp);
6515 return CM_ERROR_NOTDIR;
6518 /* open the file itself */
6519 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
6522 /* If we are restricting sharing, we should do so with a suitable
6524 if (scp->fileType == CM_SCACHETYPE_FILE &&
6525 !(fidflags & SMB_FID_SHARE_WRITE)) {
6527 LARGE_INTEGER LOffset, LLength;
6530 LOffset.HighPart = SMB_FID_QLOCK_HIGH;
6531 LOffset.LowPart = SMB_FID_QLOCK_LOW;
6532 LLength.HighPart = 0;
6533 LLength.LowPart = SMB_FID_QLOCK_LENGTH;
6535 if (fidflags & SMB_FID_SHARE_READ) {
6536 sLockType = LOCKING_ANDX_SHARED_LOCK;
6541 key = cm_GenerateKey(vcp->vcID, SMB_FID_QLOCK_PID, fidp->fid);
6543 lock_ObtainMutex(&scp->mx);
6544 code = cm_Lock(scp, sLockType, LOffset, LLength, key, 0, userp, &req, NULL);
6545 lock_ReleaseMutex(&scp->mx);
6548 fidp->flags = SMB_FID_DELETE;
6549 smb_ReleaseFID(fidp);
6551 cm_ReleaseSCache(scp);
6552 cm_ReleaseUser(userp);
6555 return CM_ERROR_SHARING_VIOLATION;
6559 /* save a pointer to the vnode */
6562 fidp->flags = fidflags;
6564 /* save parent dir and pathname for deletion or change notification */
6565 if (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE)) {
6566 fidp->flags |= SMB_FID_NTOPEN;
6567 fidp->NTopen_dscp = dscp;
6568 cm_HoldSCache(dscp);
6569 fidp->NTopen_pathp = strdup(lastNamep);
6571 fidp->NTopen_wholepathp = realPathp;
6573 /* we don't need this any longer */
6575 cm_ReleaseSCache(dscp);
6577 cm_Open(scp, 0, userp);
6579 /* set inp->fid so that later read calls in same msg can find fid */
6580 inp->fid = fidp->fid;
6582 /* check whether we are required to send an extended response */
6583 if (!extendedRespRequired) {
6585 parmOffset = 8*4 + 39;
6586 parmOffset += 1; /* pad to 4 */
6587 dataOffset = parmOffset + 70;
6591 /* Total Parameter Count */
6592 smb_SetSMBParmLong(outp, parmSlot, 70); parmSlot += 2;
6593 /* Total Data Count */
6594 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
6595 /* Parameter Count */
6596 smb_SetSMBParmLong(outp, parmSlot, 70); parmSlot += 2;
6597 /* Parameter Offset */
6598 smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
6599 /* Parameter Displacement */
6600 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
6602 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
6604 smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
6605 /* Data Displacement */
6606 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
6607 smb_SetSMBParmByte(outp, parmSlot, 0); /* Setup Count */
6608 smb_SetSMBDataLength(outp, 70);
6610 lock_ObtainMutex(&scp->mx);
6611 outData = smb_GetSMBData(outp, NULL);
6612 outData++; /* round to get to parmOffset */
6613 *outData = 0; outData++; /* oplock */
6614 *outData = 0; outData++; /* reserved */
6615 *((USHORT *)outData) = fidp->fid; outData += 2; /* fid */
6616 *((ULONG *)outData) = openAction; outData += 4;
6617 *((ULONG *)outData) = 0; outData += 4; /* EA error offset */
6618 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
6619 *((FILETIME *)outData) = ft; outData += 8; /* creation time */
6620 *((FILETIME *)outData) = ft; outData += 8; /* last access time */
6621 *((FILETIME *)outData) = ft; outData += 8; /* last write time */
6622 *((FILETIME *)outData) = ft; outData += 8; /* change time */
6623 *((ULONG *)outData) = smb_ExtAttributes(scp); outData += 4;
6624 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* alloc sz */
6625 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* EOF */
6626 *((USHORT *)outData) = 0; outData += 2; /* filetype */
6627 *((USHORT *)outData) = 0; outData += 2; /* dev state */
6628 *((USHORT *)outData) = (scp->fileType == CM_SCACHETYPE_DIRECTORY);
6629 outData += 2; /* is a dir? */
6630 lock_ReleaseMutex(&scp->mx);
6633 parmOffset = 8*4 + 39;
6634 parmOffset += 1; /* pad to 4 */
6635 dataOffset = parmOffset + 104;
6639 /* Total Parameter Count */
6640 smb_SetSMBParmLong(outp, parmSlot, 101); parmSlot += 2;
6641 /* Total Data Count */
6642 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
6643 /* Parameter Count */
6644 smb_SetSMBParmLong(outp, parmSlot, 101); parmSlot += 2;
6645 /* Parameter Offset */
6646 smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
6647 /* Parameter Displacement */
6648 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
6650 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
6652 smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
6653 /* Data Displacement */
6654 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
6655 smb_SetSMBParmByte(outp, parmSlot, 0); /* Setup Count */
6656 smb_SetSMBDataLength(outp, 105);
6658 lock_ObtainMutex(&scp->mx);
6659 outData = smb_GetSMBData(outp, NULL);
6660 outData++; /* round to get to parmOffset */
6661 *outData = 0; outData++; /* oplock */
6662 *outData = 1; outData++; /* response type */
6663 *((USHORT *)outData) = fidp->fid; outData += 2; /* fid */
6664 *((ULONG *)outData) = openAction; outData += 4;
6665 *((ULONG *)outData) = 0; outData += 4; /* EA error offset */
6666 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
6667 *((FILETIME *)outData) = ft; outData += 8; /* creation time */
6668 *((FILETIME *)outData) = ft; outData += 8; /* last access time */
6669 *((FILETIME *)outData) = ft; outData += 8; /* last write time */
6670 *((FILETIME *)outData) = ft; outData += 8; /* change time */
6671 *((ULONG *)outData) = smb_ExtAttributes(scp); outData += 4;
6672 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* alloc sz */
6673 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* EOF */
6674 *((USHORT *)outData) = 0; outData += 2; /* filetype */
6675 *((USHORT *)outData) = 0; outData += 2; /* dev state */
6676 *((USHORT *)outData) = (scp->fileType == CM_SCACHETYPE_DIRECTORY);
6677 outData += 1; /* is a dir? */
6678 memset(outData,0,24); outData += 24; /* Volume ID and file ID */
6679 *((ULONG *)outData) = 0x001f01ffL; outData += 4; /* Maxmimal access rights */
6680 *((ULONG *)outData) = 0; outData += 4; /* Guest Access rights */
6681 lock_ReleaseMutex(&scp->mx);
6684 osi_Log1(smb_logp, "SMB NTTranCreate opening fid %d", fidp->fid);
6686 smb_ReleaseFID(fidp);
6688 cm_ReleaseUser(userp);
6690 /* free(realPathp); Can't free realPathp here because fidp->NTopen_wholepathp points there */
6691 /* leave scp held since we put it in fidp->scp */
6695 long smb_ReceiveNTTranNotifyChange(smb_vc_t *vcp, smb_packet_t *inp,
6698 smb_packet_t *savedPacketp;
6699 ULONG filter; USHORT fid, watchtree;
6703 filter = smb_GetSMBParm(inp, 19) |
6704 (smb_GetSMBParm(inp, 20) << 16);
6705 fid = smb_GetSMBParm(inp, 21);
6706 watchtree = smb_GetSMBParm(inp, 22) && 0xffff; /* TODO: should this be 0xff ? */
6708 fidp = smb_FindFID(vcp, fid, 0);
6710 osi_Log1(smb_logp, "ERROR: NotifyChange given invalid fid [%d]", fid);
6711 return CM_ERROR_BADFD;
6714 savedPacketp = smb_CopyPacket(inp);
6716 savedPacketp->vcp = vcp;
6717 lock_ObtainMutex(&smb_Dir_Watch_Lock);
6718 savedPacketp->nextp = smb_Directory_Watches;
6719 smb_Directory_Watches = savedPacketp;
6720 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
6722 osi_Log4(smb_logp, "Request for NotifyChange filter 0x%x fid %d wtree %d file %s",
6723 filter, fid, watchtree, osi_LogSaveString(smb_logp, fidp->NTopen_wholepathp));
6726 lock_ObtainMutex(&scp->mx);
6728 scp->flags |= CM_SCACHEFLAG_WATCHEDSUBTREE;
6730 scp->flags |= CM_SCACHEFLAG_WATCHED;
6731 lock_ReleaseMutex(&scp->mx);
6732 smb_ReleaseFID(fidp);
6734 outp->flags |= SMB_PACKETFLAG_NOSEND;
6738 unsigned char nullSecurityDesc[36] = {
6739 0x01, /* security descriptor revision */
6740 0x00, /* reserved, should be zero */
6741 0x00, 0x80, /* security descriptor control;
6742 * 0x8000 : self-relative format */
6743 0x14, 0x00, 0x00, 0x00, /* offset of owner SID */
6744 0x1c, 0x00, 0x00, 0x00, /* offset of group SID */
6745 0x00, 0x00, 0x00, 0x00, /* offset of DACL would go here */
6746 0x00, 0x00, 0x00, 0x00, /* offset of SACL would go here */
6747 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
6748 /* "null SID" owner SID */
6749 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
6750 /* "null SID" group SID */
6753 long smb_ReceiveNTTranQuerySecurityDesc(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6755 int parmOffset, parmCount, dataOffset, dataCount;
6763 ULONG securityInformation;
6765 parmOffset = smb_GetSMBOffsetParm(inp, 11, 1)
6766 | (smb_GetSMBOffsetParm(inp, 12, 1) << 16);
6767 parmp = inp->data + parmOffset;
6768 sparmp = (USHORT *) parmp;
6769 lparmp = (ULONG *) parmp;
6772 securityInformation = lparmp[1];
6774 maxData = smb_GetSMBOffsetParm(inp, 7, 1)
6775 | (smb_GetSMBOffsetParm(inp, 8, 1) << 16);
6783 parmOffset = 8*4 + 39;
6784 parmOffset += 1; /* pad to 4 */
6786 dataOffset = parmOffset + parmCount;
6790 /* Total Parameter Count */
6791 smb_SetSMBParmLong(outp, parmSlot, parmCount); parmSlot += 2;
6792 /* Total Data Count */
6793 smb_SetSMBParmLong(outp, parmSlot, dataCount); parmSlot += 2;
6794 /* Parameter Count */
6795 smb_SetSMBParmLong(outp, parmSlot, parmCount); parmSlot += 2;
6796 /* Parameter Offset */
6797 smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
6798 /* Parameter Displacement */
6799 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
6801 smb_SetSMBParmLong(outp, parmSlot, dataCount); parmSlot += 2;
6803 smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
6804 /* Data Displacement */
6805 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
6806 smb_SetSMBParmByte(outp, parmSlot, 0); /* Setup Count */
6807 smb_SetSMBDataLength(outp, 1 + parmCount + dataCount);
6809 outData = smb_GetSMBData(outp, NULL);
6810 outData++; /* round to get to parmOffset */
6811 *((ULONG *)outData) = 36; outData += 4; /* length */
6813 if (maxData >= 36) {
6814 memcpy(outData, nullSecurityDesc, 36);
6818 return CM_ERROR_BUFFERTOOSMALL;
6821 long smb_ReceiveNTTransact(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6823 unsigned short function;
6825 function = smb_GetSMBParm(inp, 18);
6827 osi_Log1(smb_logp, "SMB NT Transact function %d", function);
6829 /* We can handle long names */
6830 if (vcp->flags & SMB_VCFLAG_USENT)
6831 ((smb_t *)outp)->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
6835 return smb_ReceiveNTTranCreate(vcp, inp, outp);
6837 osi_Log0(smb_logp, "SMB NT Transact Ioctl - not implemented");
6840 osi_Log0(smb_logp, "SMB NT Transact SetSecurityDesc - not implemented");
6843 return smb_ReceiveNTTranNotifyChange(vcp, inp, outp);
6845 osi_Log0(smb_logp, "SMB NT Transact Rename - not implemented");
6848 return smb_ReceiveNTTranQuerySecurityDesc(vcp, inp, outp);
6850 return CM_ERROR_INVAL;
6854 * smb_NotifyChange -- find relevant change notification messages and
6857 * If we don't know the file name (i.e. a callback break), filename is
6858 * NULL, and we return a zero-length list.
6860 void smb_NotifyChange(DWORD action, DWORD notifyFilter,
6861 cm_scache_t *dscp, char *filename, char *otherFilename,
6862 BOOL isDirectParent)
6864 smb_packet_t *watch, *lastWatch, *nextWatch;
6865 ULONG parmSlot, parmCount, parmOffset, dataOffset, nameLen;
6866 char *outData, *oldOutData;
6870 BOOL twoEntries = FALSE;
6871 ULONG otherNameLen, oldParmCount = 0;
6876 /* Get ready for rename within directory */
6877 if (action == FILE_ACTION_RENAMED_OLD_NAME && otherFilename != NULL) {
6879 otherAction = FILE_ACTION_RENAMED_NEW_NAME;
6882 osi_Log2(smb_logp,"in smb_NotifyChange for file [%s] dscp [%x]",
6883 osi_LogSaveString(smb_logp,filename),dscp);
6885 lock_ObtainMutex(&smb_Dir_Watch_Lock);
6886 watch = smb_Directory_Watches;
6888 filter = smb_GetSMBParm(watch, 19)
6889 | (smb_GetSMBParm(watch, 20) << 16);
6890 fid = smb_GetSMBParm(watch, 21);
6891 wtree = smb_GetSMBParm(watch, 22) & 0xffff; /* TODO: should this be 0xff ? */
6892 maxLen = smb_GetSMBOffsetParm(watch, 5, 1)
6893 | (smb_GetSMBOffsetParm(watch, 6, 1) << 16);
6897 * Strange hack - bug in NT Client and NT Server that we
6900 if (filter == 3 && wtree)
6903 fidp = smb_FindFID(vcp, fid, 0);
6905 osi_Log1(smb_logp," no fidp for fid[%d]",fid);
6907 watch = watch->nextp;
6910 if (fidp->scp != dscp
6911 || (filter & notifyFilter) == 0
6912 || (!isDirectParent && !wtree)) {
6913 osi_Log1(smb_logp," passing fidp->scp[%x]", fidp->scp);
6914 smb_ReleaseFID(fidp);
6916 watch = watch->nextp;
6919 smb_ReleaseFID(fidp);
6922 "Sending Change Notification for fid %d filter 0x%x wtree %d file %s",
6923 fid, filter, wtree, osi_LogSaveString(smb_logp, filename));
6925 nextWatch = watch->nextp;
6926 if (watch == smb_Directory_Watches)
6927 smb_Directory_Watches = nextWatch;
6929 lastWatch->nextp = nextWatch;
6931 /* Turn off WATCHED flag in dscp */
6932 lock_ObtainMutex(&dscp->mx);
6934 dscp->flags &= ~CM_SCACHEFLAG_WATCHEDSUBTREE;
6936 dscp->flags &= ~CM_SCACHEFLAG_WATCHED;
6937 lock_ReleaseMutex(&dscp->mx);
6939 /* Convert to response packet */
6940 ((smb_t *) watch)->reb = SMB_FLAGS_SERVER_TO_CLIENT | SMB_FLAGS_CANONICAL_PATHNAMES;
6941 ((smb_t *) watch)->wct = 0;
6944 if (filename == NULL)
6947 nameLen = strlen(filename);
6948 parmCount = 3*4 + nameLen*2;
6949 parmCount = (parmCount + 3) & ~3; /* pad to 4 */
6951 otherNameLen = strlen(otherFilename);
6952 oldParmCount = parmCount;
6953 parmCount += 3*4 + otherNameLen*2;
6954 parmCount = (parmCount + 3) & ~3; /* pad to 4 */
6956 if (maxLen < parmCount)
6957 parmCount = 0; /* not enough room */
6959 parmOffset = 8*4 + 39;
6960 parmOffset += 1; /* pad to 4 */
6961 dataOffset = parmOffset + parmCount;
6965 /* Total Parameter Count */
6966 smb_SetSMBParmLong(watch, parmSlot, parmCount); parmSlot += 2;
6967 /* Total Data Count */
6968 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
6969 /* Parameter Count */
6970 smb_SetSMBParmLong(watch, parmSlot, parmCount); parmSlot += 2;
6971 /* Parameter Offset */
6972 smb_SetSMBParmLong(watch, parmSlot, parmOffset); parmSlot += 2;
6973 /* Parameter Displacement */
6974 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
6976 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
6978 smb_SetSMBParmLong(watch, parmSlot, dataOffset); parmSlot += 2;
6979 /* Data Displacement */
6980 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
6981 smb_SetSMBParmByte(watch, parmSlot, 0); /* Setup Count */
6982 smb_SetSMBDataLength(watch, parmCount + 1);
6984 if (parmCount != 0) {
6986 outData = smb_GetSMBData(watch, NULL);
6987 outData++; /* round to get to parmOffset */
6988 oldOutData = outData;
6989 *((DWORD *)outData) = oldParmCount; outData += 4;
6990 /* Next Entry Offset */
6991 *((DWORD *)outData) = action; outData += 4;
6993 *((DWORD *)outData) = nameLen*2; outData += 4;
6994 /* File Name Length */
6995 p = strdup(filename);
6996 if (smb_StoreAnsiFilenames)
6998 mbstowcs((WCHAR *)outData, p, nameLen);
7002 outData = oldOutData + oldParmCount;
7003 *((DWORD *)outData) = 0; outData += 4;
7004 /* Next Entry Offset */
7005 *((DWORD *)outData) = otherAction; outData += 4;
7007 *((DWORD *)outData) = otherNameLen*2;
7008 outData += 4; /* File Name Length */
7009 p = strdup(otherFilename);
7010 if (smb_StoreAnsiFilenames)
7012 mbstowcs((WCHAR *)outData, p, otherNameLen); /* File Name */
7018 * If filename is null, we don't know the cause of the
7019 * change notification. We return zero data (see above),
7020 * and set error code to NT_STATUS_NOTIFY_ENUM_DIR
7021 * (= 0x010C). We set the error code here by hand, without
7022 * modifying wct and bcc.
7024 if (filename == NULL) {
7025 ((smb_t *) watch)->rcls = 0x0C;
7026 ((smb_t *) watch)->reh = 0x01;
7027 ((smb_t *) watch)->errLow = 0;
7028 ((smb_t *) watch)->errHigh = 0;
7029 /* Set NT Status codes flag */
7030 ((smb_t *) watch)->flg2 |= SMB_FLAGS2_32BIT_STATUS;
7033 smb_SendPacket(vcp, watch);
7034 smb_FreePacket(watch);
7037 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
7040 long smb_ReceiveNTCancel(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7042 unsigned char *replyWctp;
7043 smb_packet_t *watch, *lastWatch;
7044 USHORT fid, watchtree;
7048 osi_Log0(smb_logp, "SMB3 receive NT cancel");
7050 lock_ObtainMutex(&smb_Dir_Watch_Lock);
7051 watch = smb_Directory_Watches;
7053 if (((smb_t *)watch)->uid == ((smb_t *)inp)->uid
7054 && ((smb_t *)watch)->pid == ((smb_t *)inp)->pid
7055 && ((smb_t *)watch)->mid == ((smb_t *)inp)->mid
7056 && ((smb_t *)watch)->tid == ((smb_t *)inp)->tid) {
7057 if (watch == smb_Directory_Watches)
7058 smb_Directory_Watches = watch->nextp;
7060 lastWatch->nextp = watch->nextp;
7061 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
7063 /* Turn off WATCHED flag in scp */
7064 fid = smb_GetSMBParm(watch, 21);
7065 watchtree = smb_GetSMBParm(watch, 22) & 0xffff;
7067 if (vcp != watch->vcp)
7068 osi_Log2(smb_logp, "smb_ReceiveNTCancel: vcp %x not equal to watch vcp %x",
7071 fidp = smb_FindFID(vcp, fid, 0);
7073 osi_Log3(smb_logp, "Cancelling change notification for fid %d wtree %d file %s",
7075 osi_LogSaveString(smb_logp, (fidp)?fidp->NTopen_wholepathp:""));
7078 lock_ObtainMutex(&scp->mx);
7080 scp->flags &= ~CM_SCACHEFLAG_WATCHEDSUBTREE;
7082 scp->flags &= ~CM_SCACHEFLAG_WATCHED;
7083 lock_ReleaseMutex(&scp->mx);
7084 smb_ReleaseFID(fidp);
7086 osi_Log2(smb_logp,"NTCancel unable to resolve fid [%d] in vcp[%x]", fid,vcp);
7089 /* assume STATUS32; return 0xC0000120 (CANCELED) */
7090 replyWctp = watch->wctp;
7094 ((smb_t *)watch)->rcls = 0x20;
7095 ((smb_t *)watch)->reh = 0x1;
7096 ((smb_t *)watch)->errLow = 0;
7097 ((smb_t *)watch)->errHigh = 0xC0;
7098 ((smb_t *)watch)->flg2 |= SMB_FLAGS2_32BIT_STATUS;
7099 smb_SendPacket(vcp, watch);
7100 smb_FreePacket(watch);
7104 watch = watch->nextp;
7106 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
7112 * NT rename also does hard links.
7115 #define RENAME_FLAG_MOVE_CLUSTER_INFORMATION 0x102
7116 #define RENAME_FLAG_HARD_LINK 0x103
7117 #define RENAME_FLAG_RENAME 0x104
7118 #define RENAME_FLAG_COPY 0x105
7120 long smb_ReceiveNTRename(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7122 char *oldPathp, *newPathp;
7128 attrs = smb_GetSMBParm(inp, 0);
7129 rename_type = smb_GetSMBParm(inp, 1);
7131 if (rename_type != RENAME_FLAG_RENAME && rename_type != RENAME_FLAG_HARD_LINK) {
7132 osi_Log1(smb_logp, "NTRename invalid infolevel [%x]", rename_type);
7133 return CM_ERROR_NOACCESS;
7136 tp = smb_GetSMBData(inp, NULL);
7137 oldPathp = smb_ParseASCIIBlock(tp, &tp);
7138 if (smb_StoreAnsiFilenames)
7139 OemToChar(oldPathp,oldPathp);
7140 newPathp = smb_ParseASCIIBlock(tp, &tp);
7141 if (smb_StoreAnsiFilenames)
7142 OemToChar(newPathp,newPathp);
7144 osi_Log3(smb_logp, "NTRename for [%s]->[%s] type [%s]",
7145 osi_LogSaveString(smb_logp, oldPathp),
7146 osi_LogSaveString(smb_logp, newPathp),
7147 ((rename_type==RENAME_FLAG_RENAME)?"rename":"hardlink"));
7149 if (rename_type == RENAME_FLAG_RENAME) {
7150 code = smb_Rename(vcp,inp,oldPathp,newPathp,attrs);
7151 } else { /* RENAME_FLAG_HARD_LINK */
7152 code = smb_Link(vcp,inp,oldPathp,newPathp);
7159 lock_InitializeMutex(&smb_Dir_Watch_Lock, "Directory Watch List Lock");
7162 cm_user_t *smb_FindCMUserByName(/*smb_vc_t *vcp,*/ char *usern, char *machine)
7165 smb_username_t *unp;
7167 unp = smb_FindUserByName(usern, machine, SMB_FLAG_CREATE);
7169 lock_ObtainMutex(&unp->mx);
7170 unp->userp = cm_NewUser();
7171 lock_ReleaseMutex(&unp->mx);
7172 osi_Log2(smb_logp,"smb_FindCMUserByName New user name[%s] machine[%s]",osi_LogSaveString(smb_logp,usern),osi_LogSaveString(smb_logp,machine));
7173 osi_LogEvent("AFS smb_FindCMUserByName : New User",NULL,"name[%s] machine[%s]",usern,machine);
7175 osi_Log2(smb_logp,"smb_FindCMUserByName Not found name[%s] machine[%s]",osi_LogSaveString(smb_logp,usern),osi_LogSaveString(smb_logp,machine));
7176 osi_LogEvent("AFS smb_FindCMUserByName : Found",NULL,"name[%s] machine[%s]",usern,machine);