2 * Copyright 2000, International Business Machines Corporation and others.
5 * This software has been released under the terms of the IBM Public
6 * License. For details, see the LICENSE file in the top-level source
7 * directory or online at http://www.openafs.org/dl/license10.html
10 #include <afs/param.h>
16 #define SECURITY_WIN32
28 #include <WINNT\afsreg.h>
32 extern osi_hyper_t hzero;
34 smb_packet_t *smb_Directory_Watches = NULL;
35 osi_mutex_t smb_Dir_Watch_Lock;
37 smb_tran2Dispatch_t smb_tran2DispatchTable[SMB_TRAN2_NOPCODES];
39 smb_tran2Dispatch_t smb_rapDispatchTable[SMB_RAP_NOPCODES];
41 /* protected by the smb_globalLock */
42 smb_tran2Packet_t *smb_tran2AssemblyQueuep;
44 /* retrieve a held reference to a user structure corresponding to an incoming
46 cm_user_t *smb_GetTran2User(smb_vc_t *vcp, smb_tran2Packet_t *inp)
51 uidp = smb_FindUID(vcp, inp->uid, 0);
52 if (!uidp) return NULL;
54 lock_ObtainMutex(&uidp->mx);
56 up = uidp->unp->userp;
59 lock_ReleaseMutex(&uidp->mx);
67 * Return extended attributes.
68 * Right now, we aren't using any of the "new" bits, so this looks exactly
69 * like smb_Attributes() (see smb.c).
71 unsigned long smb_ExtAttributes(cm_scache_t *scp)
75 if (scp->fileType == CM_SCACHETYPE_DIRECTORY ||
76 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
77 scp->fileType == CM_SCACHETYPE_INVALID)
79 attrs = SMB_ATTR_DIRECTORY;
80 #ifdef SPECIAL_FOLDERS
81 attrs |= SMB_ATTR_SYSTEM; /* FILE_ATTRIBUTE_SYSTEM */
82 #endif /* SPECIAL_FOLDERS */
83 } else if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
84 attrs = SMB_ATTR_DIRECTORY | SMB_ATTR_SPARSE_FILE;
88 * We used to mark a file RO if it was in an RO volume, but that
89 * turns out to be impolitic in NT. See defect 10007.
92 if ((scp->unixModeBits & 0222) == 0 || (scp->flags & CM_SCACHEFLAG_RO))
93 attrs |= SMB_ATTR_READONLY; /* Read-only */
95 if ((scp->unixModeBits & 0222) == 0)
96 attrs |= SMB_ATTR_READONLY; /* Read-only */
100 attrs = SMB_ATTR_NORMAL; /* FILE_ATTRIBUTE_NORMAL */
105 int smb_V3IsStarMask(char *maskp)
109 while (tc = *maskp++)
110 if (tc == '?' || tc == '*' || tc == '<' || tc == '>')
115 unsigned char *smb_ParseString(unsigned char *inp, char **chainpp)
118 /* skip over null-terminated string */
119 *chainpp = inp + strlen(inp) + 1;
124 void OutputDebugF(char * format, ...) {
129 va_start( args, format );
130 len = _vscprintf( format, args ) // _vscprintf doesn't count
131 + 3; // terminating '\0' + '\n'
132 buffer = malloc( len * sizeof(char) );
133 vsprintf( buffer, format, args );
134 osi_Log0(smb_logp, osi_LogSaveString(smb_logp, buffer));
135 strcat(buffer, "\n");
136 OutputDebugString(buffer);
140 void OutputDebugHexDump(unsigned char * buffer, int len) {
143 static char tr[16] = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
145 OutputDebugF("Hexdump length [%d]",len);
147 for (i=0;i<len;i++) {
150 osi_Log0(smb_logp, osi_LogSaveString(smb_logp, buf));
152 OutputDebugString(buf);
154 sprintf(buf,"%5x",i);
155 memset(buf+5,' ',80);
160 j = j*3 + 7 + ((j>7)?1:0);
163 buf[j] = tr[k / 16]; buf[j+1] = tr[k % 16];
166 j = j + 56 + ((j>7)?1:0);
168 buf[j] = (k>32 && k<127)?k:'.';
171 osi_Log0(smb_logp, osi_LogSaveString(smb_logp, buf));
173 OutputDebugString(buf);
177 #define SMB_EXT_SEC_PACKAGE_NAME "Negotiate"
179 void smb_NegotiateExtendedSecurity(void ** secBlob, int * secBlobLength) {
180 SECURITY_STATUS status, istatus;
181 CredHandle creds = {0,0};
183 SecBufferDesc secOut;
191 OutputDebugF("Negotiating Extended Security");
193 status = AcquireCredentialsHandle( NULL,
194 SMB_EXT_SEC_PACKAGE_NAME,
203 if (status != SEC_E_OK) {
204 /* Really bad. We return an empty security blob */
205 OutputDebugF("AcquireCredentialsHandle failed with %lX", status);
210 secOut.pBuffers = &secTok;
211 secOut.ulVersion = SECBUFFER_VERSION;
213 secTok.BufferType = SECBUFFER_TOKEN;
215 secTok.pvBuffer = NULL;
217 ctx.dwLower = ctx.dwUpper = 0;
219 status = AcceptSecurityContext( &creds,
222 ASC_REQ_CONNECTION | ASC_REQ_EXTENDED_ERROR | ASC_REQ_ALLOCATE_MEMORY,
223 SECURITY_NETWORK_DREP,
230 if (status == SEC_I_COMPLETE_NEEDED || status == SEC_I_COMPLETE_AND_CONTINUE) {
231 OutputDebugF("Completing token...");
232 istatus = CompleteAuthToken(&ctx, &secOut);
233 if ( istatus != SEC_E_OK )
234 OutputDebugF("Token completion failed: %x", istatus);
237 if (status == SEC_I_COMPLETE_AND_CONTINUE || status == SEC_I_CONTINUE_NEEDED) {
238 if (secTok.pvBuffer) {
239 *secBlobLength = secTok.cbBuffer;
240 *secBlob = malloc( secTok.cbBuffer );
241 memcpy(*secBlob, secTok.pvBuffer, secTok.cbBuffer );
244 if ( status != SEC_E_OK )
245 OutputDebugF("AcceptSecurityContext status != CONTINUE %lX", status);
248 /* Discard partial security context */
249 DeleteSecurityContext(&ctx);
251 if (secTok.pvBuffer) FreeContextBuffer( secTok.pvBuffer );
253 /* Discard credentials handle. We'll reacquire one when we get the session setup X */
254 FreeCredentialsHandle(&creds);
260 struct smb_ext_context {
267 long smb_AuthenticateUserExt(smb_vc_t * vcp, char * usern, char * secBlobIn, int secBlobInLength, char ** secBlobOut, int * secBlobOutLength) {
268 SECURITY_STATUS status, istatus;
272 SecBufferDesc secBufIn;
274 SecBufferDesc secBufOut;
277 struct smb_ext_context * secCtx = NULL;
278 struct smb_ext_context * newSecCtx = NULL;
279 void * assembledBlob = NULL;
280 int assembledBlobLength = 0;
283 OutputDebugF("In smb_AuthenticateUserExt");
286 *secBlobOutLength = 0;
288 if (vcp->flags & SMB_VCFLAG_AUTH_IN_PROGRESS) {
289 secCtx = vcp->secCtx;
290 lock_ObtainMutex(&vcp->mx);
291 vcp->flags &= ~SMB_VCFLAG_AUTH_IN_PROGRESS;
293 lock_ReleaseMutex(&vcp->mx);
297 OutputDebugF("Received incoming token:");
298 OutputDebugHexDump(secBlobIn,secBlobInLength);
302 OutputDebugF("Continuing with existing context.");
303 creds = secCtx->creds;
306 if (secCtx->partialToken) {
307 assembledBlobLength = secCtx->partialTokenLen + secBlobInLength;
308 assembledBlob = malloc(assembledBlobLength);
309 memcpy(assembledBlob,secCtx->partialToken, secCtx->partialTokenLen);
310 memcpy(((BYTE *)assembledBlob) + secCtx->partialTokenLen, secBlobIn, secBlobInLength);
313 status = AcquireCredentialsHandle( NULL,
314 SMB_EXT_SEC_PACKAGE_NAME,
323 if (status != SEC_E_OK) {
324 OutputDebugF("Can't acquire Credentials handle [%lX]", status);
325 code = CM_ERROR_BADPASSWORD; /* means "try again when I'm sober" */
333 secBufIn.cBuffers = 1;
334 secBufIn.pBuffers = &secTokIn;
335 secBufIn.ulVersion = SECBUFFER_VERSION;
337 secTokIn.BufferType = SECBUFFER_TOKEN;
339 secTokIn.cbBuffer = assembledBlobLength;
340 secTokIn.pvBuffer = assembledBlob;
342 secTokIn.cbBuffer = secBlobInLength;
343 secTokIn.pvBuffer = secBlobIn;
346 secBufOut.cBuffers = 1;
347 secBufOut.pBuffers = &secTokOut;
348 secBufOut.ulVersion = SECBUFFER_VERSION;
350 secTokOut.BufferType = SECBUFFER_TOKEN;
351 secTokOut.cbBuffer = 0;
352 secTokOut.pvBuffer = NULL;
354 status = AcceptSecurityContext( &creds,
355 ((secCtx)?&ctx:NULL),
357 ASC_REQ_CONNECTION | ASC_REQ_EXTENDED_ERROR | ASC_REQ_ALLOCATE_MEMORY,
358 SECURITY_NETWORK_DREP,
365 if (status == SEC_I_COMPLETE_NEEDED || status == SEC_I_COMPLETE_AND_CONTINUE) {
366 OutputDebugF("Completing token...");
367 istatus = CompleteAuthToken(&ctx, &secBufOut);
368 if ( istatus != SEC_E_OK )
369 OutputDebugF("Token completion failed: %lX", istatus);
372 if (status == SEC_I_COMPLETE_AND_CONTINUE || status == SEC_I_CONTINUE_NEEDED) {
373 OutputDebugF("Continue needed");
375 newSecCtx = malloc(sizeof(*newSecCtx));
377 newSecCtx->creds = creds;
378 newSecCtx->ctx = ctx;
379 newSecCtx->partialToken = NULL;
380 newSecCtx->partialTokenLen = 0;
382 lock_ObtainMutex( &vcp->mx );
383 vcp->flags |= SMB_VCFLAG_AUTH_IN_PROGRESS;
384 vcp->secCtx = newSecCtx;
385 lock_ReleaseMutex( &vcp->mx );
387 code = CM_ERROR_GSSCONTINUE;
390 if ((status == SEC_I_COMPLETE_NEEDED || status == SEC_E_OK ||
391 status == SEC_I_COMPLETE_AND_CONTINUE || status == SEC_I_CONTINUE_NEEDED) &&
392 secTokOut.pvBuffer) {
393 OutputDebugF("Need to send token back to client");
395 *secBlobOutLength = secTokOut.cbBuffer;
396 *secBlobOut = malloc(secTokOut.cbBuffer);
397 memcpy(*secBlobOut, secTokOut.pvBuffer, secTokOut.cbBuffer);
399 OutputDebugF("Outgoing token:");
400 OutputDebugHexDump(*secBlobOut,*secBlobOutLength);
401 } else if (status == SEC_E_INCOMPLETE_MESSAGE) {
402 OutputDebugF("Incomplete message");
404 newSecCtx = malloc(sizeof(*newSecCtx));
406 newSecCtx->creds = creds;
407 newSecCtx->ctx = ctx;
408 newSecCtx->partialToken = malloc(secTokOut.cbBuffer);
409 memcpy(newSecCtx->partialToken, secTokOut.pvBuffer, secTokOut.cbBuffer);
410 newSecCtx->partialTokenLen = secTokOut.cbBuffer;
412 lock_ObtainMutex( &vcp->mx );
413 vcp->flags |= SMB_VCFLAG_AUTH_IN_PROGRESS;
414 vcp->secCtx = newSecCtx;
415 lock_ReleaseMutex( &vcp->mx );
417 code = CM_ERROR_GSSCONTINUE;
420 if (status == SEC_E_OK || status == SEC_I_COMPLETE_NEEDED) {
422 SecPkgContext_Names names;
424 OutputDebugF("Authentication completed");
425 OutputDebugF("Returned flags : [%lX]", flags);
427 if (!QueryContextAttributes(&ctx, SECPKG_ATTR_NAMES, &names)) {
428 OutputDebugF("Received name [%s]", names.sUserName);
429 strcpy(usern, names.sUserName);
430 strlwr(usern); /* in tandem with smb_GetNormalizedUsername */
431 FreeContextBuffer(names.sUserName);
433 /* Force the user to retry if the context is invalid */
434 OutputDebugF("QueryContextAttributes Names failed [%x]", GetLastError());
435 code = CM_ERROR_BADPASSWORD;
439 case SEC_E_INVALID_TOKEN:
440 OutputDebugF("Returning bad password :: INVALID_TOKEN");
442 case SEC_E_INVALID_HANDLE:
443 OutputDebugF("Returning bad password :: INVALID_HANDLE");
445 case SEC_E_LOGON_DENIED:
446 OutputDebugF("Returning bad password :: LOGON_DENIED");
448 case SEC_E_UNKNOWN_CREDENTIALS:
449 OutputDebugF("Returning bad password :: UNKNOWN_CREDENTIALS");
451 case SEC_E_NO_CREDENTIALS:
452 OutputDebugF("Returning bad password :: NO_CREDENTIALS");
454 case SEC_E_CONTEXT_EXPIRED:
455 OutputDebugF("Returning bad password :: CONTEXT_EXPIRED");
457 case SEC_E_INCOMPLETE_CREDENTIALS:
458 OutputDebugF("Returning bad password :: INCOMPLETE_CREDENTIALS");
460 case SEC_E_WRONG_PRINCIPAL:
461 OutputDebugF("Returning bad password :: WRONG_PRINCIPAL");
463 case SEC_E_TIME_SKEW:
464 OutputDebugF("Returning bad password :: TIME_SKEW");
467 OutputDebugF("Returning bad password :: Status == %lX", status);
469 code = CM_ERROR_BADPASSWORD;
473 if (secCtx->partialToken) free(secCtx->partialToken);
481 if (secTokOut.pvBuffer)
482 FreeContextBuffer(secTokOut.pvBuffer);
484 if (code != CM_ERROR_GSSCONTINUE) {
485 DeleteSecurityContext(&ctx);
486 FreeCredentialsHandle(&creds);
494 #define P_RESP_LEN 128
496 /* LsaLogonUser expects input parameters to be in a contiguous block of memory.
497 So put stuff in a struct. */
498 struct Lm20AuthBlob {
499 MSV1_0_LM20_LOGON lmlogon;
500 BYTE ciResponse[P_RESP_LEN]; /* Unicode representation */
501 BYTE csResponse[P_RESP_LEN]; /* ANSI representation */
502 WCHAR accountNameW[P_LEN];
503 WCHAR primaryDomainW[P_LEN];
504 WCHAR workstationW[MAX_COMPUTERNAME_LENGTH + 1];
505 TOKEN_GROUPS tgroups;
506 TOKEN_SOURCE tsource;
509 long smb_AuthenticateUserLM(smb_vc_t *vcp, char * accountName, char * primaryDomain, char * ciPwd, unsigned ciPwdLength, char * csPwd, unsigned csPwdLength)
512 struct Lm20AuthBlob lmAuth;
513 PMSV1_0_LM20_LOGON_PROFILE lmprofilep;
514 QUOTA_LIMITS quotaLimits;
516 ULONG lmprofilepSize;
520 OutputDebugF("In smb_AuthenticateUser for user [%s] domain [%s]", accountName, primaryDomain);
521 OutputDebugF("ciPwdLength is %d and csPwdLength is %d", ciPwdLength, csPwdLength);
523 if (ciPwdLength > P_RESP_LEN || csPwdLength > P_RESP_LEN) {
524 OutputDebugF("ciPwdLength or csPwdLength is too long");
525 return CM_ERROR_BADPASSWORD;
528 memset(&lmAuth,0,sizeof(lmAuth));
530 lmAuth.lmlogon.MessageType = MsV1_0NetworkLogon;
532 lmAuth.lmlogon.LogonDomainName.Buffer = lmAuth.primaryDomainW;
533 mbstowcs(lmAuth.primaryDomainW, primaryDomain, P_LEN);
534 lmAuth.lmlogon.LogonDomainName.Length = wcslen(lmAuth.primaryDomainW) * sizeof(WCHAR);
535 lmAuth.lmlogon.LogonDomainName.MaximumLength = P_LEN * sizeof(WCHAR);
537 lmAuth.lmlogon.UserName.Buffer = lmAuth.accountNameW;
538 mbstowcs(lmAuth.accountNameW, accountName, P_LEN);
539 lmAuth.lmlogon.UserName.Length = wcslen(lmAuth.accountNameW) * sizeof(WCHAR);
540 lmAuth.lmlogon.UserName.MaximumLength = P_LEN * sizeof(WCHAR);
542 lmAuth.lmlogon.Workstation.Buffer = lmAuth.workstationW;
543 lmAuth.lmlogon.Workstation.MaximumLength = (MAX_COMPUTERNAME_LENGTH + 1) * sizeof(WCHAR);
544 size = MAX_COMPUTERNAME_LENGTH + 1;
545 GetComputerNameW(lmAuth.workstationW, &size);
546 lmAuth.lmlogon.Workstation.Length = wcslen(lmAuth.workstationW) * sizeof(WCHAR);
548 memcpy(lmAuth.lmlogon.ChallengeToClient, vcp->encKey, MSV1_0_CHALLENGE_LENGTH);
550 lmAuth.lmlogon.CaseInsensitiveChallengeResponse.Buffer = lmAuth.ciResponse;
551 lmAuth.lmlogon.CaseInsensitiveChallengeResponse.Length = ciPwdLength;
552 lmAuth.lmlogon.CaseInsensitiveChallengeResponse.MaximumLength = P_RESP_LEN;
553 memcpy(lmAuth.ciResponse, ciPwd, ciPwdLength);
555 lmAuth.lmlogon.CaseSensitiveChallengeResponse.Buffer = lmAuth.csResponse;
556 lmAuth.lmlogon.CaseSensitiveChallengeResponse.Length = csPwdLength;
557 lmAuth.lmlogon.CaseSensitiveChallengeResponse.MaximumLength = P_RESP_LEN;
558 memcpy(lmAuth.csResponse, csPwd, csPwdLength);
560 lmAuth.lmlogon.ParameterControl = 0;
562 lmAuth.tgroups.GroupCount = 0;
563 lmAuth.tgroups.Groups[0].Sid = NULL;
564 lmAuth.tgroups.Groups[0].Attributes = 0;
566 lmAuth.tsource.SourceIdentifier.HighPart = 0;
567 lmAuth.tsource.SourceIdentifier.LowPart = (DWORD) vcp;
568 strcpy(lmAuth.tsource.SourceName,"OpenAFS"); /* 8 char limit */
570 nts = LsaLogonUser( smb_lsaHandle,
585 if (nts != STATUS_SUCCESS || ntsEx != STATUS_SUCCESS)
586 osi_Log2(smb_logp,"LsaLogonUser failure: nts %u ntsEx %u",
589 OutputDebugF("Return from LsaLogonUser is 0x%lX", nts);
590 OutputDebugF("Extended status is 0x%lX", ntsEx);
592 if (nts == ERROR_SUCCESS) {
594 LsaFreeReturnBuffer(lmprofilep);
595 CloseHandle(lmToken);
599 if (nts == 0xC000015BL)
600 return CM_ERROR_BADLOGONTYPE;
601 else /* our catchall is a bad password though we could be more specific */
602 return CM_ERROR_BADPASSWORD;
606 /* The buffer pointed to by usern is assumed to be at least SMB_MAX_USERNAME_LENGTH bytes */
607 long smb_GetNormalizedUsername(char * usern, const char * accountName, const char * domainName)
612 /* check if we have sane input */
613 if ((strlen(accountName) + strlen(domainName) + 1) > SMB_MAX_USERNAME_LENGTH)
616 /* we could get : [accountName][domainName]
622 atsign = strchr(accountName, '@');
624 if (atsign) /* [user@domain][] -> [user@domain][domain] */
629 /* if for some reason the client doesn't know what domain to use,
630 it will either return an empty string or a '?' */
631 if (!domain[0] || domain[0] == '?')
632 /* Empty domains and empty usernames are usually sent from tokenless contexts.
633 This way such logins will get an empty username (easy to check). I don't know
634 when a non-empty username would be supplied with an anonymous domain, but *shrug* */
635 strcpy(usern,accountName);
637 /* TODO: what about WIN.MIT.EDU\user vs. WIN\user? */
638 strcpy(usern,domain);
641 strncat(usern,accountName,atsign - accountName);
643 strcat(usern,accountName);
651 /* When using SMB auth, all SMB sessions have to pass through here
652 * first to authenticate the user.
654 * Caveat: If not using SMB auth, the protocol does not require
655 * sending a session setup packet, which means that we can't rely on a
656 * UID in subsequent packets. Though in practice we get one anyway.
658 long smb_ReceiveV3SessionSetupX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
662 unsigned short newUid;
663 unsigned long caps = 0;
668 char usern[SMB_MAX_USERNAME_LENGTH];
669 char *secBlobOut = NULL;
670 int secBlobOutLength = 0;
672 /* Check for bad conns */
673 if (vcp->flags & SMB_VCFLAG_REMOTECONN)
674 return CM_ERROR_REMOTECONN;
676 if (vcp->flags & SMB_VCFLAG_USENT) {
677 if (smb_authType == SMB_AUTH_EXTENDED) {
678 /* extended authentication */
682 OutputDebugF("NT Session Setup: Extended");
684 if (!(vcp->flags & SMB_VCFLAG_SESSX_RCVD)) {
685 caps = smb_GetSMBParm(inp,10) | (((unsigned long) smb_GetSMBParm(inp,11)) << 16);
688 secBlobInLength = smb_GetSMBParm(inp, 7);
689 secBlobIn = smb_GetSMBData(inp, NULL);
691 code = smb_AuthenticateUserExt(vcp, usern, secBlobIn, secBlobInLength, &secBlobOut, &secBlobOutLength);
693 if (code == CM_ERROR_GSSCONTINUE) {
694 smb_SetSMBParm(outp, 2, 0);
695 smb_SetSMBParm(outp, 3, secBlobOutLength);
696 smb_SetSMBDataLength(outp, secBlobOutLength + smb_ServerOSLength + smb_ServerLanManagerLength + smb_ServerDomainNameLength);
697 tp = smb_GetSMBData(outp, NULL);
698 if (secBlobOutLength) {
699 memcpy(tp, secBlobOut, secBlobOutLength);
701 tp += secBlobOutLength;
703 memcpy(tp,smb_ServerOS,smb_ServerOSLength);
704 tp += smb_ServerOSLength;
705 memcpy(tp,smb_ServerLanManager,smb_ServerLanManagerLength);
706 tp += smb_ServerLanManagerLength;
707 memcpy(tp,smb_ServerDomainName,smb_ServerDomainNameLength);
708 tp += smb_ServerDomainNameLength;
711 /* TODO: handle return code and continue auth. Also free secBlobOut if applicable. */
713 unsigned ciPwdLength, csPwdLength;
719 if (smb_authType == SMB_AUTH_NTLM)
720 OutputDebugF("NT Session Setup: NTLM");
722 OutputDebugF("NT Session Setup: None");
724 /* TODO: parse for extended auth as well */
725 ciPwdLength = smb_GetSMBParm(inp, 7); /* case insensitive password length */
726 csPwdLength = smb_GetSMBParm(inp, 8); /* case sensitive password length */
728 tp = smb_GetSMBData(inp, &datalen);
730 OutputDebugF("Session packet data size [%d]",datalen);
737 accountName = smb_ParseString(tp, &tp);
738 primaryDomain = smb_ParseString(tp, NULL);
740 OutputDebugF("Account Name: %s",accountName);
741 OutputDebugF("Primary Domain: %s", primaryDomain);
742 OutputDebugF("Case Sensitive Password: %s", csPwd && csPwd[0] ? "yes" : "no");
743 OutputDebugF("Case Insensitive Password: %s", ciPwd && ciPwd[0] ? "yes" : "no");
745 if (smb_GetNormalizedUsername(usern, accountName, primaryDomain)) {
746 /* shouldn't happen */
747 code = CM_ERROR_BADSMB;
748 goto after_read_packet;
751 /* capabilities are only valid for first session packet */
752 if (!(vcp->flags & SMB_VCFLAG_SESSX_RCVD)) {
753 caps = smb_GetSMBParm(inp, 11) | (((unsigned long)smb_GetSMBParm(inp, 12)) << 16);
756 if (smb_authType == SMB_AUTH_NTLM) {
757 code = smb_AuthenticateUserLM(vcp, accountName, primaryDomain, ciPwd, ciPwdLength, csPwd, csPwdLength);
759 OutputDebugF("LM authentication failed [%d]", code);
761 OutputDebugF("LM authentication succeeded");
765 unsigned ciPwdLength;
770 switch ( smb_authType ) {
771 case SMB_AUTH_EXTENDED:
772 OutputDebugF("V3 Session Setup: Extended");
775 OutputDebugF("V3 Session Setup: NTLM");
778 OutputDebugF("V3 Session Setup: None");
780 ciPwdLength = smb_GetSMBParm(inp, 7);
781 tp = smb_GetSMBData(inp, NULL);
785 accountName = smb_ParseString(tp, &tp);
786 primaryDomain = smb_ParseString(tp, NULL);
788 OutputDebugF("Account Name: %s",accountName);
789 OutputDebugF("Primary Domain: %s", primaryDomain);
790 OutputDebugF("Case Insensitive Password: %s", ciPwd && ciPwd[0] ? "yes" : "no");
792 if ( smb_GetNormalizedUsername(usern, accountName, primaryDomain)) {
793 /* shouldn't happen */
794 code = CM_ERROR_BADSMB;
795 goto after_read_packet;
798 /* even if we wanted extended auth, if we only negotiated V3, we have to fallback
801 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
802 code = smb_AuthenticateUserLM(vcp,accountName,primaryDomain,ciPwd,ciPwdLength,"",0);
804 OutputDebugF("LM authentication failed [%d]", code);
806 OutputDebugF("LM authentication succeeded");
811 /* note down that we received a session setup X and set the capabilities flag */
812 if (!(vcp->flags & SMB_VCFLAG_SESSX_RCVD)) {
813 lock_ObtainMutex(&vcp->mx);
814 vcp->flags |= SMB_VCFLAG_SESSX_RCVD;
815 /* for the moment we can only deal with NTSTATUS */
816 if (caps & NTNEGOTIATE_CAPABILITY_NTSTATUS) {
817 vcp->flags |= SMB_VCFLAG_STATUS32;
819 lock_ReleaseMutex(&vcp->mx);
822 /* code would be non-zero if there was an authentication failure.
823 Ideally we would like to invalidate the uid for this session or break
824 early to avoid accidently stealing someone else's tokens. */
830 OutputDebugF("Received username=[%s]", usern);
832 /* On Windows 2000, this function appears to be called more often than
833 it is expected to be called. This resulted in multiple smb_user_t
834 records existing all for the same user session which results in all
835 of the users tokens disappearing.
837 To avoid this problem, we look for an existing smb_user_t record
838 based on the users name, and use that one if we find it.
841 uidp = smb_FindUserByNameThisSession(vcp, usern);
842 if (uidp) { /* already there, so don't create a new one */
845 newUid = (unsigned short)uidp->userID; /* For some reason these are different types!*/
846 osi_LogEvent("AFS smb_ReceiveV3SessionSetupX",NULL,"FindUserByName:Lana[%d],lsn[%d],userid[%d],name[%s]",vcp->lana,vcp->lsn,newUid,osi_LogSaveString(smb_logp, usern));
847 osi_Log3(smb_logp,"smb_ReceiveV3SessionSetupX FindUserByName:Lana[%d],lsn[%d],userid[%d]",vcp->lana,vcp->lsn,newUid);
848 smb_ReleaseUID(uidp);
851 /* do a global search for the username/machine name pair */
852 unp = smb_FindUserByName(usern, vcp->rname, SMB_FLAG_CREATE);
854 /* Create a new UID and cm_user_t structure */
857 userp = cm_NewUser();
858 lock_ObtainMutex(&vcp->mx);
859 if (!vcp->uidCounter)
860 vcp->uidCounter++; /* handle unlikely wraparounds */
861 newUid = (strlen(usern)==0)?0:vcp->uidCounter++;
862 lock_ReleaseMutex(&vcp->mx);
864 /* Create a new smb_user_t structure and connect them up */
865 lock_ObtainMutex(&unp->mx);
867 lock_ReleaseMutex(&unp->mx);
869 uidp = smb_FindUID(vcp, newUid, SMB_FLAG_CREATE);
870 lock_ObtainMutex(&uidp->mx);
872 osi_LogEvent("AFS smb_ReceiveV3SessionSetupX",NULL,"MakeNewUser:VCP[%x],Lana[%d],lsn[%d],userid[%d],TicketKTCName[%s]",(int)vcp,vcp->lana,vcp->lsn,newUid,osi_LogSaveString(smb_logp, usern));
873 osi_Log4(smb_logp,"smb_ReceiveV3SessionSetupX MakeNewUser:VCP[%x],Lana[%d],lsn[%d],userid[%d]",vcp,vcp->lana,vcp->lsn,newUid);
874 lock_ReleaseMutex(&uidp->mx);
875 smb_ReleaseUID(uidp);
878 /* Return UID to the client */
879 ((smb_t *)outp)->uid = newUid;
880 /* Also to the next chained message */
881 ((smb_t *)inp)->uid = newUid;
883 osi_Log3(smb_logp, "SMB3 session setup name %s creating ID %d%s",
884 osi_LogSaveString(smb_logp, usern), newUid, osi_LogSaveString(smb_logp, s1));
886 smb_SetSMBParm(outp, 2, 0);
888 if (vcp->flags & SMB_VCFLAG_USENT) {
889 if (smb_authType == SMB_AUTH_EXTENDED) {
890 smb_SetSMBParm(outp, 3, secBlobOutLength);
891 smb_SetSMBDataLength(outp, secBlobOutLength + smb_ServerOSLength + smb_ServerLanManagerLength + smb_ServerDomainNameLength);
892 tp = smb_GetSMBData(outp, NULL);
893 if (secBlobOutLength) {
894 memcpy(tp, secBlobOut, secBlobOutLength);
896 tp += secBlobOutLength;
898 memcpy(tp,smb_ServerOS,smb_ServerOSLength);
899 tp += smb_ServerOSLength;
900 memcpy(tp,smb_ServerLanManager,smb_ServerLanManagerLength);
901 tp += smb_ServerLanManagerLength;
902 memcpy(tp,smb_ServerDomainName,smb_ServerDomainNameLength);
903 tp += smb_ServerDomainNameLength;
905 smb_SetSMBDataLength(outp, 0);
908 if (smb_authType == SMB_AUTH_EXTENDED) {
909 smb_SetSMBDataLength(outp, smb_ServerOSLength + smb_ServerLanManagerLength + smb_ServerDomainNameLength);
910 tp = smb_GetSMBData(outp, NULL);
911 memcpy(tp,smb_ServerOS,smb_ServerOSLength);
912 tp += smb_ServerOSLength;
913 memcpy(tp,smb_ServerLanManager,smb_ServerLanManagerLength);
914 tp += smb_ServerLanManagerLength;
915 memcpy(tp,smb_ServerDomainName,smb_ServerDomainNameLength);
916 tp += smb_ServerDomainNameLength;
918 smb_SetSMBDataLength(outp, 0);
925 long smb_ReceiveV3UserLogoffX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
929 /* don't get tokens from this VC */
930 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
932 inp->flags |= SMB_PACKETFLAG_PROFILE_UPDATE_OK;
934 /* find the tree and free it */
935 uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
936 /* TODO: smb_ReleaseUID() ? */
938 char *s1 = NULL, *s2 = NULL;
940 if (s2 == NULL) s2 = " ";
941 if (s1 == NULL) {s1 = s2; s2 = " ";}
943 osi_Log4(smb_logp, "SMB3 user logoffX uid %d name %s%s%s", uidp->userID,
944 osi_LogSaveString(smb_logp, (uidp->unp) ? uidp->unp->name: " "),
945 osi_LogSaveString(smb_logp,s1), osi_LogSaveString(smb_logp,s2));
947 lock_ObtainMutex(&uidp->mx);
948 uidp->flags |= SMB_USERFLAG_DELETE;
950 * it doesn't get deleted right away
951 * because the vcp points to it
953 lock_ReleaseMutex(&uidp->mx);
956 osi_Log0(smb_logp, "SMB3 user logoffX");
958 smb_SetSMBDataLength(outp, 0);
962 #define SMB_SUPPORT_SEARCH_BITS 0x0001
963 #define SMB_SHARE_IS_IN_DFS 0x0002
965 long smb_ReceiveV3TreeConnectX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
969 unsigned short newTid;
980 osi_Log0(smb_logp, "SMB3 receive tree connect");
982 /* parse input parameters */
983 tp = smb_GetSMBData(inp, NULL);
984 passwordp = smb_ParseString(tp, &tp);
985 pathp = smb_ParseString(tp, &tp);
986 if (smb_StoreAnsiFilenames)
987 OemToChar(pathp,pathp);
988 servicep = smb_ParseString(tp, &tp);
990 tp = strrchr(pathp, '\\');
992 return CM_ERROR_BADSMB;
994 strcpy(shareName, tp+1);
996 osi_Log2(smb_logp, "Tree connect pathp[%s] shareName[%s]",
997 osi_LogSaveString(smb_logp, pathp),
998 osi_LogSaveString(smb_logp, shareName));
1000 if (strcmp(servicep, "IPC") == 0 || strcmp(shareName, "IPC$") == 0) {
1002 osi_Log0(smb_logp, "TreeConnectX connecting to IPC$");
1005 return CM_ERROR_NOIPC;
1009 userp = smb_GetUser(vcp, inp);
1011 lock_ObtainMutex(&vcp->mx);
1012 newTid = vcp->tidCounter++;
1013 lock_ReleaseMutex(&vcp->mx);
1015 tidp = smb_FindTID(vcp, newTid, SMB_FLAG_CREATE);
1018 uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
1019 shareFound = smb_FindShare(vcp, uidp, shareName, &sharePath);
1021 smb_ReleaseUID(uidp);
1023 smb_ReleaseTID(tidp);
1024 return CM_ERROR_BADSHARENAME;
1027 if (vcp->flags & SMB_VCFLAG_USENT)
1029 int policy = smb_FindShareCSCPolicy(shareName);
1030 smb_SetSMBParm(outp, 2, SMB_SUPPORT_SEARCH_BITS |
1032 SMB_SHARE_IS_IN_DFS |
1037 smb_SetSMBParm(outp, 2, 0);
1041 lock_ObtainMutex(&tidp->mx);
1042 tidp->userp = userp;
1043 tidp->pathname = sharePath;
1045 tidp->flags |= SMB_TIDFLAG_IPC;
1046 lock_ReleaseMutex(&tidp->mx);
1047 smb_ReleaseTID(tidp);
1049 ((smb_t *)outp)->tid = newTid;
1050 ((smb_t *)inp)->tid = newTid;
1051 tp = smb_GetSMBData(outp, NULL);
1053 /* XXX - why is this a drive letter? */
1062 smb_SetSMBDataLength(outp, 8);
1065 smb_SetSMBDataLength(outp, 4);
1068 osi_Log1(smb_logp, "SMB3 tree connect created ID %d", newTid);
1072 /* must be called with global tran lock held */
1073 smb_tran2Packet_t *smb_FindTran2Packet(smb_vc_t *vcp, smb_packet_t *inp)
1075 smb_tran2Packet_t *tp;
1078 smbp = (smb_t *) inp->data;
1079 for (tp = smb_tran2AssemblyQueuep; tp; tp = (smb_tran2Packet_t *) osi_QNext(&tp->q)) {
1080 if (tp->vcp == vcp && tp->mid == smbp->mid && tp->tid == smbp->tid)
1086 smb_tran2Packet_t *smb_NewTran2Packet(smb_vc_t *vcp, smb_packet_t *inp,
1087 int totalParms, int totalData)
1089 smb_tran2Packet_t *tp;
1092 smbp = (smb_t *) inp->data;
1093 tp = malloc(sizeof(*tp));
1094 memset(tp, 0, sizeof(*tp));
1097 tp->curData = tp->curParms = 0;
1098 tp->totalData = totalData;
1099 tp->totalParms = totalParms;
1100 tp->tid = smbp->tid;
1101 tp->mid = smbp->mid;
1102 tp->uid = smbp->uid;
1103 tp->pid = smbp->pid;
1104 tp->res[0] = smbp->res[0];
1105 osi_QAdd((osi_queue_t **)&smb_tran2AssemblyQueuep, &tp->q);
1106 if (totalParms != 0)
1107 tp->parmsp = malloc(totalParms);
1109 tp->datap = malloc(totalData);
1110 if (smbp->com == 0x25 || smbp->com == 0x26)
1113 tp->opcode = smb_GetSMBParm(inp, 14);
1116 tp->flags |= SMB_TRAN2PFLAG_ALLOC;
1120 smb_tran2Packet_t *smb_GetTran2ResponsePacket(smb_vc_t *vcp,
1121 smb_tran2Packet_t *inp, smb_packet_t *outp,
1122 int totalParms, int totalData)
1124 smb_tran2Packet_t *tp;
1125 unsigned short parmOffset;
1126 unsigned short dataOffset;
1127 unsigned short dataAlign;
1129 tp = malloc(sizeof(*tp));
1130 memset(tp, 0, sizeof(*tp));
1132 tp->curData = tp->curParms = 0;
1133 tp->totalData = totalData;
1134 tp->totalParms = totalParms;
1135 tp->oldTotalParms = totalParms;
1140 tp->res[0] = inp->res[0];
1141 tp->opcode = inp->opcode;
1145 * We calculate where the parameters and data will start.
1146 * This calculation must parallel the calculation in
1147 * smb_SendTran2Packet.
1150 parmOffset = 10*2 + 35;
1151 parmOffset++; /* round to even */
1152 tp->parmsp = (unsigned short *) (outp->data + parmOffset);
1154 dataOffset = parmOffset + totalParms;
1155 dataAlign = dataOffset & 2; /* quad-align */
1156 dataOffset += dataAlign;
1157 tp->datap = outp->data + dataOffset;
1162 /* free a tran2 packet; must be called with smb_globalLock held */
1163 void smb_FreeTran2Packet(smb_tran2Packet_t *t2p)
1166 smb_ReleaseVC(t2p->vcp);
1167 if (t2p->flags & SMB_TRAN2PFLAG_ALLOC) {
1176 /* called with a VC, an input packet to respond to, and an error code.
1177 * sends an error response.
1179 void smb_SendTran2Error(smb_vc_t *vcp, smb_tran2Packet_t *t2p,
1180 smb_packet_t *tp, long code)
1183 unsigned short errCode;
1184 unsigned char errClass;
1185 unsigned long NTStatus;
1187 if (vcp->flags & SMB_VCFLAG_STATUS32)
1188 smb_MapNTError(code, &NTStatus);
1190 smb_MapCoreError(code, vcp, &errCode, &errClass);
1192 smb_FormatResponsePacket(vcp, NULL, tp);
1193 smbp = (smb_t *) tp;
1195 /* We can handle long names */
1196 if (vcp->flags & SMB_VCFLAG_USENT)
1197 smbp->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
1199 /* now copy important fields from the tran 2 packet */
1200 smbp->com = t2p->com;
1201 smbp->tid = t2p->tid;
1202 smbp->mid = t2p->mid;
1203 smbp->pid = t2p->pid;
1204 smbp->uid = t2p->uid;
1205 smbp->res[0] = t2p->res[0];
1206 if (vcp->flags & SMB_VCFLAG_STATUS32) {
1207 smbp->rcls = (unsigned char) (NTStatus & 0xff);
1208 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
1209 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
1210 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
1211 smbp->flg2 |= SMB_FLAGS2_32BIT_STATUS;
1214 smbp->rcls = errClass;
1215 smbp->errLow = (unsigned char) (errCode & 0xff);
1216 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
1220 smb_SendPacket(vcp, tp);
1223 void smb_SendTran2Packet(smb_vc_t *vcp, smb_tran2Packet_t *t2p, smb_packet_t *tp)
1226 unsigned short parmOffset;
1227 unsigned short dataOffset;
1228 unsigned short totalLength;
1229 unsigned short dataAlign;
1232 smb_FormatResponsePacket(vcp, NULL, tp);
1233 smbp = (smb_t *) tp;
1235 /* We can handle long names */
1236 if (vcp->flags & SMB_VCFLAG_USENT)
1237 smbp->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
1239 /* now copy important fields from the tran 2 packet */
1240 smbp->com = t2p->com;
1241 smbp->tid = t2p->tid;
1242 smbp->mid = t2p->mid;
1243 smbp->pid = t2p->pid;
1244 smbp->uid = t2p->uid;
1245 smbp->res[0] = t2p->res[0];
1247 totalLength = 1 + t2p->totalData + t2p->totalParms;
1249 /* now add the core parameters (tran2 info) to the packet */
1250 smb_SetSMBParm(tp, 0, t2p->totalParms); /* parm bytes */
1251 smb_SetSMBParm(tp, 1, t2p->totalData); /* data bytes */
1252 smb_SetSMBParm(tp, 2, 0); /* reserved */
1253 smb_SetSMBParm(tp, 3, t2p->totalParms); /* parm bytes in this packet */
1254 parmOffset = 10*2 + 35; /* parm offset in packet */
1255 parmOffset++; /* round to even */
1256 smb_SetSMBParm(tp, 4, parmOffset); /* 11 parm words plus *
1257 * hdr, bcc and wct */
1258 smb_SetSMBParm(tp, 5, 0); /* parm displacement */
1259 smb_SetSMBParm(tp, 6, t2p->totalData); /* data in this packet */
1260 dataOffset = parmOffset + t2p->oldTotalParms;
1261 dataAlign = dataOffset & 2; /* quad-align */
1262 dataOffset += dataAlign;
1263 smb_SetSMBParm(tp, 7, dataOffset); /* offset of data */
1264 smb_SetSMBParm(tp, 8, 0); /* data displacement */
1265 smb_SetSMBParm(tp, 9, 0); /* low: setup word count *
1268 datap = smb_GetSMBData(tp, NULL);
1269 *datap++ = 0; /* we rounded to even */
1271 totalLength += dataAlign;
1272 smb_SetSMBDataLength(tp, totalLength);
1274 /* next, send the datagram */
1275 smb_SendPacket(vcp, tp);
1278 long smb_ReceiveV3Trans(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
1280 smb_tran2Packet_t *asp;
1293 /* We sometimes see 0 word count. What to do? */
1294 if (*inp->wctp == 0) {
1299 osi_Log0(smb_logp, "TRANSACTION word count = 0");
1301 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
1302 ptbuf[0] = "Transaction2 word count = 0";
1303 ReportEvent(h, EVENTLOG_WARNING_TYPE, 0, 1003, NULL,
1304 1, inp->ncb_length, ptbuf, inp);
1305 DeregisterEventSource(h);
1307 osi_Log0(smb_logp, "TRANSACTION word count = 0");
1310 smb_SetSMBDataLength(outp, 0);
1311 smb_SendPacket(vcp, outp);
1315 totalParms = smb_GetSMBParm(inp, 0);
1316 totalData = smb_GetSMBParm(inp, 1);
1318 firstPacket = (inp->inCom == 0x25);
1320 /* find the packet we're reassembling */
1321 lock_ObtainWrite(&smb_globalLock);
1322 asp = smb_FindTran2Packet(vcp, inp);
1324 asp = smb_NewTran2Packet(vcp, inp, totalParms, totalData);
1326 lock_ReleaseWrite(&smb_globalLock);
1328 /* now merge in this latest packet; start by looking up offsets */
1330 parmDisp = dataDisp = 0;
1331 parmOffset = smb_GetSMBParm(inp, 10);
1332 dataOffset = smb_GetSMBParm(inp, 12);
1333 parmCount = smb_GetSMBParm(inp, 9);
1334 dataCount = smb_GetSMBParm(inp, 11);
1335 asp->maxReturnParms = smb_GetSMBParm(inp, 2);
1336 asp->maxReturnData = smb_GetSMBParm(inp, 3);
1338 osi_Log3(smb_logp, "SMB3 received Trans init packet total data %d, cur data %d, max return data %d",
1339 totalData, dataCount, asp->maxReturnData);
1342 parmDisp = smb_GetSMBParm(inp, 4);
1343 parmOffset = smb_GetSMBParm(inp, 3);
1344 dataDisp = smb_GetSMBParm(inp, 7);
1345 dataOffset = smb_GetSMBParm(inp, 6);
1346 parmCount = smb_GetSMBParm(inp, 2);
1347 dataCount = smb_GetSMBParm(inp, 5);
1349 osi_Log2(smb_logp, "SMB3 received Trans aux packet parms %d, data %d",
1350 parmCount, dataCount);
1353 /* now copy the parms and data */
1354 if ( asp->totalParms > 0 && parmCount != 0 )
1356 memcpy(((char *)asp->parmsp) + parmDisp, inp->data + parmOffset, parmCount);
1358 if ( asp->totalData > 0 && dataCount != 0 ) {
1359 memcpy(asp->datap + dataDisp, inp->data + dataOffset, dataCount);
1362 /* account for new bytes */
1363 asp->curData += dataCount;
1364 asp->curParms += parmCount;
1366 /* finally, if we're done, remove the packet from the queue and dispatch it */
1367 if (asp->totalParms > 0 &&
1368 asp->curParms > 0 &&
1369 asp->totalData <= asp->curData &&
1370 asp->totalParms <= asp->curParms) {
1371 /* we've received it all */
1372 lock_ObtainWrite(&smb_globalLock);
1373 osi_QRemove((osi_queue_t **) &smb_tran2AssemblyQueuep, &asp->q);
1374 lock_ReleaseWrite(&smb_globalLock);
1376 /* now dispatch it */
1377 rapOp = asp->parmsp[0];
1379 if ( rapOp >= 0 && rapOp < SMB_RAP_NOPCODES && smb_rapDispatchTable[rapOp].procp) {
1380 osi_LogEvent("AFS-Dispatch-RAP[%s]",myCrt_RapDispatch(rapOp),"vcp[%x] lana[%d] lsn[%d]",(int)vcp,vcp->lana,vcp->lsn);
1381 osi_Log4(smb_logp,"AFS Server - Dispatch-RAP %s vcp[%x] lana[%d] lsn[%d]",myCrt_RapDispatch(rapOp),vcp,vcp->lana,vcp->lsn);
1382 code = (*smb_rapDispatchTable[rapOp].procp)(vcp, asp, outp);
1385 osi_LogEvent("AFS-Dispatch-RAP [invalid]", NULL, "op[%x] vcp[%x] lana[%d] lsn[%d]", rapOp, vcp, vcp->lana, vcp->lsn);
1386 osi_Log4(smb_logp,"AFS Server - Dispatch-RAP [INVALID] op[%x] vcp[%x] lana[%d] lsn[%d]", rapOp, vcp, vcp->lana, vcp->lsn);
1387 code = CM_ERROR_BADOP;
1390 /* if an error is returned, we're supposed to send an error packet,
1391 * otherwise the dispatched function already did the data sending.
1392 * We give dispatched proc the responsibility since it knows how much
1393 * space to allocate.
1396 smb_SendTran2Error(vcp, asp, outp, code);
1399 /* free the input tran 2 packet */
1400 lock_ObtainWrite(&smb_globalLock);
1401 smb_FreeTran2Packet(asp);
1402 lock_ReleaseWrite(&smb_globalLock);
1404 else if (firstPacket) {
1405 /* the first packet in a multi-packet request, we need to send an
1406 * ack to get more data.
1408 smb_SetSMBDataLength(outp, 0);
1409 smb_SendPacket(vcp, outp);
1415 /* ANSI versions. The unicode versions support arbitrary length
1416 share names, but we don't support unicode yet. */
1418 typedef struct smb_rap_share_info_0 {
1419 char shi0_netname[13];
1420 } smb_rap_share_info_0_t;
1422 typedef struct smb_rap_share_info_1 {
1423 char shi1_netname[13];
1426 DWORD shi1_remark; /* char *shi1_remark; data offset */
1427 } smb_rap_share_info_1_t;
1429 typedef struct smb_rap_share_info_2 {
1430 char shi2_netname[13];
1432 unsigned short shi2_type;
1433 DWORD shi2_remark; /* char *shi2_remark; data offset */
1434 unsigned short shi2_permissions;
1435 unsigned short shi2_max_uses;
1436 unsigned short shi2_current_uses;
1437 DWORD shi2_path; /* char *shi2_path; data offset */
1438 unsigned short shi2_passwd[9];
1439 unsigned short shi2_pad2;
1440 } smb_rap_share_info_2_t;
1442 #define SMB_RAP_MAX_SHARES 512
1444 typedef struct smb_rap_share_list {
1447 smb_rap_share_info_0_t * shares;
1448 } smb_rap_share_list_t;
1450 int smb_rapCollectSharesProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp) {
1451 smb_rap_share_list_t * sp;
1456 if (name[0] == '.' && (!name[1] || (name[1] == '.' && !name[2])))
1457 return 0; /* skip over '.' and '..' */
1459 sp = (smb_rap_share_list_t *) vrockp;
1461 strncpy(sp->shares[sp->cShare].shi0_netname, name, 12);
1462 sp->shares[sp->cShare].shi0_netname[12] = 0;
1466 if (sp->cShare >= sp->maxShares)
1467 return CM_ERROR_STOPNOW;
1472 long smb_ReceiveRAPNetShareEnum(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1474 smb_tran2Packet_t *outp;
1475 unsigned short * tp;
1479 int outParmsTotal; /* total parameter bytes */
1480 int outDataTotal; /* total data bytes */
1488 HKEY hkSubmount = NULL;
1489 smb_rap_share_info_1_t * shares;
1492 char thisShare[256];
1495 smb_rap_share_list_t rootShares;
1500 tp = p->parmsp + 1; /* skip over function number (always 0) */
1501 (void) smb_ParseString((char *) tp, (char **) &tp); /* skip over parm descriptor */
1502 (void) smb_ParseString((char *) tp, (char **) &tp); /* skip over data descriptor */
1506 if (infoLevel != 1) {
1507 return CM_ERROR_INVAL;
1510 /* first figure out how many shares there are */
1511 rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY, 0,
1512 KEY_QUERY_VALUE, &hkParam);
1513 if (rv == ERROR_SUCCESS) {
1514 len = sizeof(allSubmount);
1515 rv = RegQueryValueEx(hkParam, "AllSubmount", NULL, NULL,
1516 (BYTE *) &allSubmount, &len);
1517 if (rv != ERROR_SUCCESS || allSubmount != 0) {
1520 RegCloseKey (hkParam);
1523 rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_OPENAFS_SUBKEY "\\Submounts",
1524 0, KEY_QUERY_VALUE, &hkSubmount);
1525 if (rv == ERROR_SUCCESS) {
1526 rv = RegQueryInfoKey(hkSubmount, NULL, NULL, NULL, NULL,
1527 NULL, NULL, &nRegShares, NULL, NULL, NULL, NULL);
1528 if (rv != ERROR_SUCCESS)
1534 /* fetch the root shares */
1535 rootShares.maxShares = SMB_RAP_MAX_SHARES;
1536 rootShares.cShare = 0;
1537 rootShares.shares = malloc( sizeof(smb_rap_share_info_0_t) * SMB_RAP_MAX_SHARES );
1541 userp = smb_GetTran2User(vcp,p);
1543 thyper.HighPart = 0;
1546 cm_HoldSCache(cm_data.rootSCachep);
1547 cm_ApplyDir(cm_data.rootSCachep, smb_rapCollectSharesProc, &rootShares, &thyper, userp, &req, NULL);
1548 cm_ReleaseSCache(cm_data.rootSCachep);
1550 cm_ReleaseUser(userp);
1552 nShares = rootShares.cShare + nRegShares + allSubmount;
1554 #define REMARK_LEN 1
1555 outParmsTotal = 8; /* 4 dwords */
1556 outDataTotal = (sizeof(smb_rap_share_info_1_t) + REMARK_LEN) * nShares ;
1557 if(outDataTotal > bufsize) {
1558 nSharesRet = bufsize / (sizeof(smb_rap_share_info_1_t) + REMARK_LEN);
1559 outDataTotal = (sizeof(smb_rap_share_info_1_t) + REMARK_LEN) * nSharesRet;
1562 nSharesRet = nShares;
1565 outp = smb_GetTran2ResponsePacket(vcp, p, op, outParmsTotal, outDataTotal);
1567 /* now for the submounts */
1568 shares = (smb_rap_share_info_1_t *) outp->datap;
1569 cstrp = outp->datap + sizeof(smb_rap_share_info_1_t) * nSharesRet;
1571 memset(outp->datap, 0, (sizeof(smb_rap_share_info_1_t) + REMARK_LEN) * nSharesRet);
1574 strcpy( shares[cshare].shi1_netname, "all" );
1575 shares[cshare].shi1_remark = cstrp - outp->datap;
1576 /* type and pad are zero already */
1582 for (i=0; i < nRegShares && cshare < nSharesRet; i++) {
1583 len = sizeof(thisShare);
1584 rv = RegEnumValue(hkSubmount, i, thisShare, &len, NULL, NULL, NULL, NULL);
1585 if (rv == ERROR_SUCCESS && strlen(thisShare) && (!allSubmount || stricmp(thisShare,"all"))) {
1586 strncpy(shares[cshare].shi1_netname, thisShare, sizeof(shares->shi1_netname)-1);
1587 shares[cshare].shi1_netname[sizeof(shares->shi1_netname)-1] = 0; /* unfortunate truncation */
1588 shares[cshare].shi1_remark = cstrp - outp->datap;
1593 nShares--; /* uncount key */
1596 RegCloseKey(hkSubmount);
1599 nonrootShares = cshare;
1601 for (i=0; i < rootShares.cShare && cshare < nSharesRet; i++) {
1602 /* in case there are collisions with submounts, submounts have higher priority */
1603 for (j=0; j < nonrootShares; j++)
1604 if (!stricmp(shares[j].shi1_netname, rootShares.shares[i].shi0_netname))
1607 if (j < nonrootShares) {
1608 nShares--; /* uncount */
1612 strcpy(shares[cshare].shi1_netname, rootShares.shares[i].shi0_netname);
1613 shares[cshare].shi1_remark = cstrp - outp->datap;
1618 outp->parmsp[0] = ((cshare == nShares)? ERROR_SUCCESS : ERROR_MORE_DATA);
1619 outp->parmsp[1] = 0;
1620 outp->parmsp[2] = cshare;
1621 outp->parmsp[3] = nShares;
1623 outp->totalData = cstrp - outp->datap;
1624 outp->totalParms = outParmsTotal;
1626 smb_SendTran2Packet(vcp, outp, op);
1627 smb_FreeTran2Packet(outp);
1629 free(rootShares.shares);
1634 long smb_ReceiveRAPNetShareGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1636 smb_tran2Packet_t *outp;
1637 unsigned short * tp;
1639 BOOL shareFound = FALSE;
1640 unsigned short infoLevel;
1641 unsigned short bufsize;
1651 tp = p->parmsp + 1; /* skip over function number (always 1) */
1652 (void) smb_ParseString( (char *) tp, (char **) &tp); /* skip over param descriptor */
1653 (void) smb_ParseString( (char *) tp, (char **) &tp); /* skip over data descriptor */
1654 shareName = smb_ParseString( (char *) tp, (char **) &tp);
1661 totalData = sizeof(smb_rap_share_info_0_t);
1662 else if(infoLevel == SMB_INFO_STANDARD)
1663 totalData = sizeof(smb_rap_share_info_1_t) + 1; /* + empty string */
1664 else if(infoLevel == SMB_INFO_QUERY_EA_SIZE)
1665 totalData = sizeof(smb_rap_share_info_2_t) + 2; /* + two empty strings */
1667 return CM_ERROR_INVAL;
1669 outp = smb_GetTran2ResponsePacket(vcp, p, op, totalParam, totalData);
1671 if(!stricmp(shareName,"all")) {
1672 rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY, 0,
1673 KEY_QUERY_VALUE, &hkParam);
1674 if (rv == ERROR_SUCCESS) {
1675 len = sizeof(allSubmount);
1676 rv = RegQueryValueEx(hkParam, "AllSubmount", NULL, NULL,
1677 (BYTE *) &allSubmount, &len);
1678 if (rv != ERROR_SUCCESS || allSubmount != 0) {
1681 RegCloseKey (hkParam);
1688 rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY "\\Submounts", 0,
1689 KEY_QUERY_VALUE, &hkSubmount);
1690 if (rv == ERROR_SUCCESS) {
1691 rv = RegQueryValueEx(hkSubmount, shareName, NULL, NULL, NULL, NULL);
1692 if (rv == ERROR_SUCCESS) {
1695 RegCloseKey(hkSubmount);
1700 smb_FreeTran2Packet(outp);
1701 return CM_ERROR_BADSHARENAME;
1704 memset(outp->datap, 0, totalData);
1706 outp->parmsp[0] = 0;
1707 outp->parmsp[1] = 0;
1708 outp->parmsp[2] = totalData;
1710 if (infoLevel == 0) {
1711 smb_rap_share_info_0_t * info = (smb_rap_share_info_0_t *) outp->datap;
1712 strncpy(info->shi0_netname, shareName, sizeof(info->shi0_netname)-1);
1713 info->shi0_netname[sizeof(info->shi0_netname)-1] = 0;
1714 } else if(infoLevel == SMB_INFO_STANDARD) {
1715 smb_rap_share_info_1_t * info = (smb_rap_share_info_1_t *) outp->datap;
1716 strncpy(info->shi1_netname, shareName, sizeof(info->shi1_netname)-1);
1717 info->shi1_netname[sizeof(info->shi1_netname)-1] = 0;
1718 info->shi1_remark = ((unsigned char *) (info + 1)) - outp->datap;
1719 /* type and pad are already zero */
1720 } else { /* infoLevel==2 */
1721 smb_rap_share_info_2_t * info = (smb_rap_share_info_2_t *) outp->datap;
1722 strncpy(info->shi2_netname, shareName, sizeof(info->shi2_netname)-1);
1723 info->shi2_netname[sizeof(info->shi2_netname)-1] = 0;
1724 info->shi2_remark = ((unsigned char *) (info + 1)) - outp->datap;
1725 info->shi2_permissions = ACCESS_ALL;
1726 info->shi2_max_uses = (unsigned short) -1;
1727 info->shi2_path = 1 + (((unsigned char *) (info + 1)) - outp->datap);
1730 outp->totalData = totalData;
1731 outp->totalParms = totalParam;
1733 smb_SendTran2Packet(vcp, outp, op);
1734 smb_FreeTran2Packet(outp);
1739 typedef struct smb_rap_wksta_info_10 {
1740 DWORD wki10_computername; /*char *wki10_computername;*/
1741 DWORD wki10_username; /* char *wki10_username; */
1742 DWORD wki10_langroup; /* char *wki10_langroup;*/
1743 unsigned char wki10_ver_major;
1744 unsigned char wki10_ver_minor;
1745 DWORD wki10_logon_domain; /*char *wki10_logon_domain;*/
1746 DWORD wki10_oth_domains; /* char *wki10_oth_domains;*/
1747 } smb_rap_wksta_info_10_t;
1750 long smb_ReceiveRAPNetWkstaGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1752 smb_tran2Packet_t *outp;
1756 unsigned short * tp;
1759 smb_rap_wksta_info_10_t * info;
1763 tp = p->parmsp + 1; /* Skip over function number */
1764 (void) smb_ParseString((unsigned char*) tp, (char **) &tp); /* skip over param descriptor */
1765 (void) smb_ParseString((unsigned char*) tp, (char **) &tp); /* skip over data descriptor */
1769 if (infoLevel != 10) {
1770 return CM_ERROR_INVAL;
1776 totalData = sizeof(*info) + /* info */
1777 MAX_COMPUTERNAME_LENGTH + /* wki10_computername */
1778 SMB_MAX_USERNAME_LENGTH + /* wki10_username */
1779 MAX_COMPUTERNAME_LENGTH + /* wki10_langroup */
1780 MAX_COMPUTERNAME_LENGTH + /* wki10_logon_domain */
1781 1; /* wki10_oth_domains (null)*/
1783 outp = smb_GetTran2ResponsePacket(vcp, p, op, totalParams, totalData);
1785 memset(outp->parmsp,0,totalParams);
1786 memset(outp->datap,0,totalData);
1788 info = (smb_rap_wksta_info_10_t *) outp->datap;
1789 cstrp = (char *) (info + 1);
1791 info->wki10_computername = (DWORD) (cstrp - outp->datap);
1792 strcpy(cstrp, smb_localNamep);
1793 cstrp += strlen(cstrp) + 1;
1795 info->wki10_username = (DWORD) (cstrp - outp->datap);
1796 uidp = smb_FindUID(vcp, p->uid, 0);
1798 lock_ObtainMutex(&uidp->mx);
1799 if(uidp->unp && uidp->unp->name)
1800 strcpy(cstrp, uidp->unp->name);
1801 lock_ReleaseMutex(&uidp->mx);
1802 smb_ReleaseUID(uidp);
1804 cstrp += strlen(cstrp) + 1;
1806 info->wki10_langroup = (DWORD) (cstrp - outp->datap);
1807 strcpy(cstrp, "WORKGROUP");
1808 cstrp += strlen(cstrp) + 1;
1810 /* TODO: Not sure what values these should take, but these work */
1811 info->wki10_ver_major = 5;
1812 info->wki10_ver_minor = 1;
1814 info->wki10_logon_domain = (DWORD) (cstrp - outp->datap);
1815 strcpy(cstrp, smb_ServerDomainName);
1816 cstrp += strlen(cstrp) + 1;
1818 info->wki10_oth_domains = (DWORD) (cstrp - outp->datap);
1819 cstrp ++; /* no other domains */
1821 outp->totalData = (unsigned short) (cstrp - outp->datap); /* actual data size */
1822 outp->parmsp[2] = outp->totalData;
1823 outp->totalParms = totalParams;
1825 smb_SendTran2Packet(vcp,outp,op);
1826 smb_FreeTran2Packet(outp);
1831 typedef struct smb_rap_server_info_0 {
1833 } smb_rap_server_info_0_t;
1835 typedef struct smb_rap_server_info_1 {
1837 char sv1_version_major;
1838 char sv1_version_minor;
1839 unsigned long sv1_type;
1840 DWORD *sv1_comment_or_master_browser; /* char *sv1_comment_or_master_browser;*/
1841 } smb_rap_server_info_1_t;
1843 char smb_ServerComment[] = "OpenAFS Client";
1844 int smb_ServerCommentLen = sizeof(smb_ServerComment);
1846 #define SMB_SV_TYPE_SERVER 0x00000002L
1847 #define SMB_SV_TYPE_NT 0x00001000L
1848 #define SMB_SV_TYPE_SERVER_NT 0x00008000L
1850 long smb_ReceiveRAPNetServerGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1852 smb_tran2Packet_t *outp;
1856 unsigned short * tp;
1859 smb_rap_server_info_0_t * info0;
1860 smb_rap_server_info_1_t * info1;
1863 tp = p->parmsp + 1; /* Skip over function number */
1864 (void) smb_ParseString((unsigned char*) tp, (char **) &tp); /* skip over param descriptor */
1865 (void) smb_ParseString((unsigned char*) tp, (char **) &tp); /* skip over data descriptor */
1869 if (infoLevel != 0 && infoLevel != 1) {
1870 return CM_ERROR_INVAL;
1876 (infoLevel == 0) ? sizeof(smb_rap_server_info_0_t)
1877 : (sizeof(smb_rap_server_info_1_t) + smb_ServerCommentLen);
1879 outp = smb_GetTran2ResponsePacket(vcp, p, op, totalParams, totalData);
1881 memset(outp->parmsp,0,totalParams);
1882 memset(outp->datap,0,totalData);
1884 if (infoLevel == 0) {
1885 info0 = (smb_rap_server_info_0_t *) outp->datap;
1886 cstrp = (char *) (info0 + 1);
1887 strcpy(info0->sv0_name, "AFS");
1888 } else { /* infoLevel == SMB_INFO_STANDARD */
1889 info1 = (smb_rap_server_info_1_t *) outp->datap;
1890 cstrp = (char *) (info1 + 1);
1891 strcpy(info1->sv1_name, "AFS");
1894 SMB_SV_TYPE_SERVER |
1896 SMB_SV_TYPE_SERVER_NT;
1898 info1->sv1_version_major = 5;
1899 info1->sv1_version_minor = 1;
1900 info1->sv1_comment_or_master_browser = (DWORD *) (cstrp - outp->datap);
1902 strcpy(cstrp, smb_ServerComment);
1904 cstrp += smb_ServerCommentLen;
1907 totalData = cstrp - outp->datap;
1908 outp->totalData = min(bufsize,totalData); /* actual data size */
1909 outp->parmsp[0] = (outp->totalData == totalData)? 0 : ERROR_MORE_DATA;
1910 outp->parmsp[2] = totalData;
1911 outp->totalParms = totalParams;
1913 smb_SendTran2Packet(vcp,outp,op);
1914 smb_FreeTran2Packet(outp);
1919 long smb_ReceiveV3Tran2A(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
1921 smb_tran2Packet_t *asp;
1933 /* We sometimes see 0 word count. What to do? */
1934 if (*inp->wctp == 0) {
1939 osi_Log0(smb_logp, "TRANSACTION2 word count = 0");
1941 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
1942 ptbuf[0] = "Transaction2 word count = 0";
1943 ReportEvent(h, EVENTLOG_WARNING_TYPE, 0, 1003, NULL,
1944 1, inp->ncb_length, ptbuf, inp);
1945 DeregisterEventSource(h);
1947 osi_Log0(smb_logp, "TRANSACTION2 word count = 0");
1950 smb_SetSMBDataLength(outp, 0);
1951 smb_SendPacket(vcp, outp);
1955 totalParms = smb_GetSMBParm(inp, 0);
1956 totalData = smb_GetSMBParm(inp, 1);
1958 firstPacket = (inp->inCom == 0x32);
1960 /* find the packet we're reassembling */
1961 lock_ObtainWrite(&smb_globalLock);
1962 asp = smb_FindTran2Packet(vcp, inp);
1964 asp = smb_NewTran2Packet(vcp, inp, totalParms, totalData);
1966 lock_ReleaseWrite(&smb_globalLock);
1968 /* now merge in this latest packet; start by looking up offsets */
1970 parmDisp = dataDisp = 0;
1971 parmOffset = smb_GetSMBParm(inp, 10);
1972 dataOffset = smb_GetSMBParm(inp, 12);
1973 parmCount = smb_GetSMBParm(inp, 9);
1974 dataCount = smb_GetSMBParm(inp, 11);
1975 asp->maxReturnParms = smb_GetSMBParm(inp, 2);
1976 asp->maxReturnData = smb_GetSMBParm(inp, 3);
1978 osi_Log3(smb_logp, "SMB3 received T2 init packet total data %d, cur data %d, max return data %d",
1979 totalData, dataCount, asp->maxReturnData);
1982 parmDisp = smb_GetSMBParm(inp, 4);
1983 parmOffset = smb_GetSMBParm(inp, 3);
1984 dataDisp = smb_GetSMBParm(inp, 7);
1985 dataOffset = smb_GetSMBParm(inp, 6);
1986 parmCount = smb_GetSMBParm(inp, 2);
1987 dataCount = smb_GetSMBParm(inp, 5);
1989 osi_Log2(smb_logp, "SMB3 received T2 aux packet parms %d, data %d",
1990 parmCount, dataCount);
1993 /* now copy the parms and data */
1994 if ( asp->totalParms > 0 && parmCount != 0 )
1996 memcpy(((char *)asp->parmsp) + parmDisp, inp->data + parmOffset, parmCount);
1998 if ( asp->totalData > 0 && dataCount != 0 ) {
1999 memcpy(asp->datap + dataDisp, inp->data + dataOffset, dataCount);
2002 /* account for new bytes */
2003 asp->curData += dataCount;
2004 asp->curParms += parmCount;
2006 /* finally, if we're done, remove the packet from the queue and dispatch it */
2007 if (asp->totalParms > 0 &&
2008 asp->curParms > 0 &&
2009 asp->totalData <= asp->curData &&
2010 asp->totalParms <= asp->curParms) {
2011 /* we've received it all */
2012 lock_ObtainWrite(&smb_globalLock);
2013 osi_QRemove((osi_queue_t **) &smb_tran2AssemblyQueuep, &asp->q);
2014 lock_ReleaseWrite(&smb_globalLock);
2016 /* now dispatch it */
2017 if ( asp->opcode >= 0 && asp->opcode < 20 && smb_tran2DispatchTable[asp->opcode].procp) {
2018 osi_LogEvent("AFS-Dispatch-2[%s]",myCrt_2Dispatch(asp->opcode),"vcp[%x] lana[%d] lsn[%d]",(int)vcp,vcp->lana,vcp->lsn);
2019 osi_Log4(smb_logp,"AFS Server - Dispatch-2 %s vcp[%x] lana[%d] lsn[%d]",myCrt_2Dispatch(asp->opcode),vcp,vcp->lana,vcp->lsn);
2020 code = (*smb_tran2DispatchTable[asp->opcode].procp)(vcp, asp, outp);
2023 osi_LogEvent("AFS-Dispatch-2 [invalid]", NULL, "op[%x] vcp[%x] lana[%d] lsn[%d]", asp->opcode, vcp, vcp->lana, vcp->lsn);
2024 osi_Log4(smb_logp,"AFS Server - Dispatch-2 [INVALID] op[%x] vcp[%x] lana[%d] lsn[%d]", asp->opcode, vcp, vcp->lana, vcp->lsn);
2025 code = CM_ERROR_BADOP;
2028 /* if an error is returned, we're supposed to send an error packet,
2029 * otherwise the dispatched function already did the data sending.
2030 * We give dispatched proc the responsibility since it knows how much
2031 * space to allocate.
2034 smb_SendTran2Error(vcp, asp, outp, code);
2037 /* free the input tran 2 packet */
2038 lock_ObtainWrite(&smb_globalLock);
2039 smb_FreeTran2Packet(asp);
2040 lock_ReleaseWrite(&smb_globalLock);
2042 else if (firstPacket) {
2043 /* the first packet in a multi-packet request, we need to send an
2044 * ack to get more data.
2046 smb_SetSMBDataLength(outp, 0);
2047 smb_SendPacket(vcp, outp);
2053 long smb_ReceiveTran2Open(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
2056 smb_tran2Packet_t *outp;
2061 cm_scache_t *dscp; /* dir we're dealing with */
2062 cm_scache_t *scp; /* file we're creating */
2064 int initialModeBits;
2074 int parmSlot; /* which parm we're dealing with */
2075 long returnEALength;
2083 extraInfo = (p->parmsp[0] & 1); /* return extra info */
2084 returnEALength = (p->parmsp[0] & 8); /* return extended attr length */
2086 openFun = p->parmsp[6]; /* open function */
2087 excl = ((openFun & 3) == 0);
2088 trunc = ((openFun & 3) == 2); /* truncate it */
2089 openMode = (p->parmsp[1] & 0x7);
2090 openAction = 0; /* tracks what we did */
2092 attributes = p->parmsp[3];
2093 dosTime = p->parmsp[4] | (p->parmsp[5] << 16);
2095 /* compute initial mode bits based on read-only flag in attributes */
2096 initialModeBits = 0666;
2098 initialModeBits &= ~0222;
2100 pathp = (char *) (&p->parmsp[14]);
2101 if (smb_StoreAnsiFilenames)
2102 OemToChar(pathp,pathp);
2104 outp = smb_GetTran2ResponsePacket(vcp, p, op, 40, 0);
2106 spacep = cm_GetSpace();
2107 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
2109 if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
2110 /* special case magic file name for receiving IOCTL requests
2111 * (since IOCTL calls themselves aren't getting through).
2113 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
2114 smb_SetupIoctlFid(fidp, spacep);
2116 /* copy out remainder of the parms */
2118 outp->parmsp[parmSlot++] = fidp->fid;
2120 outp->parmsp[parmSlot++] = 0; /* attrs */
2121 outp->parmsp[parmSlot++] = 0; /* mod time */
2122 outp->parmsp[parmSlot++] = 0;
2123 outp->parmsp[parmSlot++] = 0; /* len */
2124 outp->parmsp[parmSlot++] = 0x7fff;
2125 outp->parmsp[parmSlot++] = openMode;
2126 outp->parmsp[parmSlot++] = 0; /* file type 0 ==> normal file or dir */
2127 outp->parmsp[parmSlot++] = 0; /* IPC junk */
2129 /* and the final "always present" stuff */
2130 outp->parmsp[parmSlot++] = 1; /* openAction found existing file */
2131 /* next write out the "unique" ID */
2132 outp->parmsp[parmSlot++] = 0x1234;
2133 outp->parmsp[parmSlot++] = 0x5678;
2134 outp->parmsp[parmSlot++] = 0;
2135 if (returnEALength) {
2136 outp->parmsp[parmSlot++] = 0;
2137 outp->parmsp[parmSlot++] = 0;
2140 outp->totalData = 0;
2141 outp->totalParms = parmSlot * 2;
2143 smb_SendTran2Packet(vcp, outp, op);
2145 smb_FreeTran2Packet(outp);
2147 /* and clean up fid reference */
2148 smb_ReleaseFID(fidp);
2152 #ifdef DEBUG_VERBOSE
2154 char *hexp, *asciip;
2155 asciip = (lastNamep ? lastNamep : pathp);
2156 hexp = osi_HexifyString( asciip );
2157 DEBUG_EVENT2("AFS","T2Open H[%s] A[%s]", hexp, asciip);
2162 userp = smb_GetTran2User(vcp, p);
2163 /* In the off chance that userp is NULL, we log and abandon */
2165 osi_Log1(smb_logp, "ReceiveTran2Open user [%d] not resolvable", p->uid);
2166 smb_FreeTran2Packet(outp);
2167 return CM_ERROR_BADSMB;
2170 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
2171 if (code == CM_ERROR_TIDIPC) {
2172 /* Attempt to use a TID allocated for IPC. The client
2173 * is probably looking for DCE RPC end points which we
2174 * don't support OR it could be looking to make a DFS
2177 osi_Log0(smb_logp, "Tran2Open received IPC TID");
2179 cm_ReleaseUser(userp);
2180 smb_FreeTran2Packet(outp);
2181 return CM_ERROR_NOSUCHPATH;
2186 code = cm_NameI(cm_data.rootSCachep, pathp,
2187 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
2188 userp, tidPathp, &req, &scp);
2190 code = cm_NameI(cm_data.rootSCachep, spacep->data,
2191 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
2192 userp, tidPathp, &req, &dscp);
2193 cm_FreeSpace(spacep);
2196 cm_ReleaseUser(userp);
2197 smb_FreeTran2Packet(outp);
2202 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
2203 cm_ReleaseSCache(dscp);
2204 cm_ReleaseUser(userp);
2205 smb_FreeTran2Packet(outp);
2206 if ( WANTS_DFS_PATHNAMES(p) )
2207 return CM_ERROR_PATH_NOT_COVERED;
2209 return CM_ERROR_BADSHARENAME;
2211 #endif /* DFS_SUPPORT */
2213 /* otherwise, scp points to the parent directory. Do a lookup,
2214 * and truncate the file if we find it, otherwise we create the
2221 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD, userp,
2223 if (code && code != CM_ERROR_NOSUCHFILE) {
2224 cm_ReleaseSCache(dscp);
2225 cm_ReleaseUser(userp);
2226 smb_FreeTran2Packet(outp);
2231 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
2232 cm_ReleaseSCache(scp);
2233 cm_ReleaseUser(userp);
2234 smb_FreeTran2Packet(outp);
2235 if ( WANTS_DFS_PATHNAMES(p) )
2236 return CM_ERROR_PATH_NOT_COVERED;
2238 return CM_ERROR_BADSHARENAME;
2240 #endif /* DFS_SUPPORT */
2242 /* macintosh is expensive to program for it */
2243 cm_FreeSpace(spacep);
2246 /* if we get here, if code is 0, the file exists and is represented by
2247 * scp. Otherwise, we have to create it.
2250 code = cm_CheckOpen(scp, openMode, trunc, userp, &req);
2253 cm_ReleaseSCache(dscp);
2254 cm_ReleaseSCache(scp);
2255 cm_ReleaseUser(userp);
2256 smb_FreeTran2Packet(outp);
2261 /* oops, file shouldn't be there */
2263 cm_ReleaseSCache(dscp);
2264 cm_ReleaseSCache(scp);
2265 cm_ReleaseUser(userp);
2266 smb_FreeTran2Packet(outp);
2267 return CM_ERROR_EXISTS;
2271 setAttr.mask = CM_ATTRMASK_LENGTH;
2272 setAttr.length.LowPart = 0;
2273 setAttr.length.HighPart = 0;
2274 code = cm_SetAttr(scp, &setAttr, userp, &req);
2275 openAction = 3; /* truncated existing file */
2278 openAction = 1; /* found existing file */
2280 else if (!(openFun & 0x10)) {
2281 /* don't create if not found */
2283 cm_ReleaseSCache(dscp);
2284 osi_assert(scp == NULL);
2285 cm_ReleaseUser(userp);
2286 smb_FreeTran2Packet(outp);
2287 return CM_ERROR_NOSUCHFILE;
2290 osi_assert(dscp != NULL && scp == NULL);
2291 openAction = 2; /* created file */
2292 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
2293 smb_UnixTimeFromSearchTime(&setAttr.clientModTime, dosTime);
2294 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
2296 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
2297 smb_NotifyChange(FILE_ACTION_ADDED,
2298 FILE_NOTIFY_CHANGE_FILE_NAME,
2299 dscp, lastNamep, NULL, TRUE);
2300 if (!excl && code == CM_ERROR_EXISTS) {
2301 /* not an exclusive create, and someone else tried
2302 * creating it already, then we open it anyway. We
2303 * don't bother retrying after this, since if this next
2304 * fails, that means that the file was deleted after we
2305 * started this call.
2307 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
2311 setAttr.mask = CM_ATTRMASK_LENGTH;
2312 setAttr.length.LowPart = 0;
2313 setAttr.length.HighPart = 0;
2314 code = cm_SetAttr(scp, &setAttr, userp,
2317 } /* lookup succeeded */
2321 /* we don't need this any longer */
2323 cm_ReleaseSCache(dscp);
2326 /* something went wrong creating or truncating the file */
2328 cm_ReleaseSCache(scp);
2329 cm_ReleaseUser(userp);
2330 smb_FreeTran2Packet(outp);
2334 /* make sure we're about to open a file */
2335 if (scp->fileType != CM_SCACHETYPE_FILE) {
2337 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
2338 cm_scache_t * targetScp = 0;
2339 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
2341 /* we have a more accurate file to use (the
2342 * target of the symbolic link). Otherwise,
2343 * we'll just use the symlink anyway.
2345 osi_Log2(smb_logp, "symlink vp %x to vp %x",
2347 cm_ReleaseSCache(scp);
2351 if (scp->fileType != CM_SCACHETYPE_FILE) {
2352 cm_ReleaseSCache(scp);
2353 cm_ReleaseUser(userp);
2354 smb_FreeTran2Packet(outp);
2355 return CM_ERROR_ISDIR;
2359 /* now all we have to do is open the file itself */
2360 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
2363 /* save a pointer to the vnode */
2366 /* compute open mode */
2367 if (openMode != 1) fidp->flags |= SMB_FID_OPENREAD;
2368 if (openMode == 1 || openMode == 2)
2369 fidp->flags |= SMB_FID_OPENWRITE;
2371 smb_ReleaseFID(fidp);
2373 cm_Open(scp, 0, userp);
2375 /* copy out remainder of the parms */
2377 outp->parmsp[parmSlot++] = fidp->fid;
2378 lock_ObtainMutex(&scp->mx);
2380 outp->parmsp[parmSlot++] = smb_Attributes(scp);
2381 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
2382 outp->parmsp[parmSlot++] = (unsigned short)(dosTime & 0xffff);
2383 outp->parmsp[parmSlot++] = (unsigned short)((dosTime>>16) & 0xffff);
2384 outp->parmsp[parmSlot++] = (unsigned short) (scp->length.LowPart & 0xffff);
2385 outp->parmsp[parmSlot++] = (unsigned short) ((scp->length.LowPart >> 16) & 0xffff);
2386 outp->parmsp[parmSlot++] = openMode;
2387 outp->parmsp[parmSlot++] = 0; /* file type 0 ==> normal file or dir */
2388 outp->parmsp[parmSlot++] = 0; /* IPC junk */
2390 /* and the final "always present" stuff */
2391 outp->parmsp[parmSlot++] = openAction;
2392 /* next write out the "unique" ID */
2393 outp->parmsp[parmSlot++] = (unsigned short) (scp->fid.vnode & 0xffff);
2394 outp->parmsp[parmSlot++] = (unsigned short) (scp->fid.volume & 0xffff);
2395 outp->parmsp[parmSlot++] = 0;
2396 if (returnEALength) {
2397 outp->parmsp[parmSlot++] = 0;
2398 outp->parmsp[parmSlot++] = 0;
2400 lock_ReleaseMutex(&scp->mx);
2401 outp->totalData = 0; /* total # of data bytes */
2402 outp->totalParms = parmSlot * 2; /* shorts are two bytes */
2404 smb_SendTran2Packet(vcp, outp, op);
2406 smb_FreeTran2Packet(outp);
2408 cm_ReleaseUser(userp);
2409 /* leave scp held since we put it in fidp->scp */
2413 long smb_ReceiveTran2FindFirst(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
2415 osi_Log0(smb_logp,"ReceiveTran2FindFirst - NOT_SUPPORTED");
2416 return CM_ERROR_BADOP;
2419 long smb_ReceiveTran2FindNext(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
2421 osi_Log0(smb_logp,"ReceiveTran2FindNext - NOT_SUPPORTED");
2422 return CM_ERROR_BADOP;
2425 long smb_ReceiveTran2QFSInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
2427 smb_tran2Packet_t *outp;
2428 smb_tran2QFSInfo_t qi;
2431 static char FSname[6] = {'A', 0, 'F', 0, 'S', 0};
2433 osi_Log1(smb_logp, "T2 QFSInfo type 0x%x", p->parmsp[0]);
2435 switch (p->parmsp[0]) {
2436 case 1: responseSize = sizeof(qi.u.allocInfo); break;
2437 case 2: responseSize = sizeof(qi.u.volumeInfo); break;
2438 case 0x102: responseSize = sizeof(qi.u.FSvolumeInfo); break;
2439 case 0x103: responseSize = sizeof(qi.u.FSsizeInfo); break;
2440 case 0x104: responseSize = sizeof(qi.u.FSdeviceInfo); break;
2441 case 0x105: responseSize = sizeof(qi.u.FSattributeInfo); break;
2442 case 0x200: /* CIFS Unix Info */
2443 case 0x301: /* Mac FS Info */
2444 default: return CM_ERROR_INVAL;
2447 outp = smb_GetTran2ResponsePacket(vcp, p, op, 0, responseSize);
2448 switch (p->parmsp[0]) {
2451 qi.u.allocInfo.FSID = 0;
2452 qi.u.allocInfo.sectorsPerAllocUnit = 1;
2453 qi.u.allocInfo.totalAllocUnits = 0x7fffffff;
2454 qi.u.allocInfo.availAllocUnits = 0x3fffffff;
2455 qi.u.allocInfo.bytesPerSector = 1024;
2460 qi.u.volumeInfo.vsn = 1234;
2461 qi.u.volumeInfo.vnCount = 4;
2462 /* we're supposed to pad it out with zeroes to the end */
2463 memset(&qi.u.volumeInfo.label, 0, sizeof(qi.u.volumeInfo.label));
2464 memcpy(qi.u.volumeInfo.label, "AFS", 4);
2468 /* FS volume info */
2469 memset((char *)&qi.u.FSvolumeInfo.vct, 0, sizeof(FILETIME));
2470 qi.u.FSvolumeInfo.vsn = 1234;
2471 qi.u.FSvolumeInfo.vnCount = 8;
2472 memcpy(qi.u.FSvolumeInfo.label, "A\0F\0S\0\0", 8);
2478 temp.LowPart = 0x7fffffff;
2479 qi.u.FSsizeInfo.totalAllocUnits = temp;
2480 temp.LowPart = 0x3fffffff;
2481 qi.u.FSsizeInfo.availAllocUnits = temp;
2482 qi.u.FSsizeInfo.sectorsPerAllocUnit = 1;
2483 qi.u.FSsizeInfo.bytesPerSector = 1024;
2487 /* FS device info */
2488 qi.u.FSdeviceInfo.devType = 0; /* don't have a number */
2489 qi.u.FSdeviceInfo.characteristics = 0x50; /* remote, virtual */
2493 /* FS attribute info */
2494 /* attributes, defined in WINNT.H:
2495 * FILE_CASE_SENSITIVE_SEARCH 0x1
2496 * FILE_CASE_PRESERVED_NAMES 0x2
2497 * <no name defined> 0x4000
2498 * If bit 0x4000 is not set, Windows 95 thinks
2499 * we can't handle long (non-8.3) names,
2500 * despite our protestations to the contrary.
2502 qi.u.FSattributeInfo.attributes = 0x4003;
2503 qi.u.FSattributeInfo.maxCompLength = 255;
2504 qi.u.FSattributeInfo.FSnameLength = 6;
2505 memcpy(qi.u.FSattributeInfo.FSname, FSname, 6);
2509 /* copy out return data, and set corresponding sizes */
2510 outp->totalParms = 0;
2511 outp->totalData = responseSize;
2512 memcpy(outp->datap, &qi, responseSize);
2514 /* send and free the packets */
2515 smb_SendTran2Packet(vcp, outp, op);
2516 smb_FreeTran2Packet(outp);
2521 long smb_ReceiveTran2SetFSInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
2523 osi_Log0(smb_logp,"ReceiveTran2SetFSInfo - NOT_SUPPORTED");
2524 return CM_ERROR_BADOP;
2527 struct smb_ShortNameRock {
2531 size_t shortNameLen;
2534 int cm_GetShortNameProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *vrockp,
2537 struct smb_ShortNameRock *rockp;
2541 /* compare both names and vnodes, though probably just comparing vnodes
2542 * would be safe enough.
2544 if (cm_stricmp(dep->name, rockp->maskp) != 0)
2546 if (ntohl(dep->fid.vnode) != rockp->vnode)
2548 /* This is the entry */
2549 cm_Gen8Dot3Name(dep, rockp->shortName, &shortNameEnd);
2550 rockp->shortNameLen = shortNameEnd - rockp->shortName;
2551 return CM_ERROR_STOPNOW;
2554 long cm_GetShortName(char *pathp, cm_user_t *userp, cm_req_t *reqp,
2555 char *tidPathp, int vnode, char *shortName, size_t *shortNameLenp)
2557 struct smb_ShortNameRock rock;
2561 int caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
2565 spacep = cm_GetSpace();
2566 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
2568 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold, userp, tidPathp,
2570 cm_FreeSpace(spacep);
2575 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
2576 cm_ReleaseSCache(dscp);
2577 cm_ReleaseUser(userp);
2578 return CM_ERROR_PATH_NOT_COVERED;
2580 #endif /* DFS_SUPPORT */
2582 if (!lastNamep) lastNamep = pathp;
2585 thyper.HighPart = 0;
2586 rock.shortName = shortName;
2588 rock.maskp = lastNamep;
2589 code = cm_ApplyDir(dscp, cm_GetShortNameProc, &rock, &thyper, userp, reqp, NULL);
2591 cm_ReleaseSCache(dscp);
2594 return CM_ERROR_NOSUCHFILE;
2595 if (code == CM_ERROR_STOPNOW) {
2596 *shortNameLenp = rock.shortNameLen;
2602 long smb_ReceiveTran2QPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
2604 smb_tran2Packet_t *outp;
2607 unsigned short infoLevel;
2609 unsigned short attributes;
2610 unsigned long extAttributes;
2615 cm_scache_t *scp, *dscp;
2624 infoLevel = p->parmsp[0];
2625 if (infoLevel == SMB_INFO_IS_NAME_VALID)
2627 else if (infoLevel == SMB_INFO_STANDARD)
2628 nbytesRequired = 22;
2629 else if (infoLevel == SMB_INFO_QUERY_EA_SIZE)
2630 nbytesRequired = 26;
2631 else if (infoLevel == SMB_QUERY_FILE_BASIC_INFO)
2632 nbytesRequired = 40;
2633 else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO)
2634 nbytesRequired = 24;
2635 else if (infoLevel == SMB_QUERY_FILE_EA_INFO)
2637 else if (infoLevel == SMB_QUERY_FILE_ALT_NAME_INFO)
2638 nbytesRequired = 30;
2640 osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
2641 p->opcode, infoLevel);
2642 smb_SendTran2Error(vcp, p, opx, CM_ERROR_INVAL);
2645 osi_Log2(smb_logp, "T2 QPathInfo type 0x%x path %s", infoLevel,
2646 osi_LogSaveString(smb_logp, (char *)(&p->parmsp[3])));
2648 outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, nbytesRequired);
2650 if (infoLevel > 0x100)
2651 outp->totalParms = 2;
2653 outp->totalParms = 0;
2654 outp->totalData = nbytesRequired;
2656 /* now, if we're at infoLevel 6, we're only being asked to check
2657 * the syntax, so we just OK things now. In particular, we're *not*
2658 * being asked to verify anything about the state of any parent dirs.
2660 if (infoLevel == SMB_INFO_IS_NAME_VALID) {
2661 smb_SendTran2Packet(vcp, outp, opx);
2662 smb_FreeTran2Packet(outp);
2666 userp = smb_GetTran2User(vcp, p);
2668 osi_Log1(smb_logp, "ReceiveTran2QPathInfo unable to resolve user [%d]", p->uid);
2669 smb_FreeTran2Packet(outp);
2670 return CM_ERROR_BADSMB;
2673 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
2675 cm_ReleaseUser(userp);
2676 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOSUCHPATH);
2677 smb_FreeTran2Packet(outp);
2682 * XXX Strange hack XXX
2684 * As of Patch 7 (13 January 98), we are having the following problem:
2685 * In NT Explorer 4.0, whenever we click on a directory, AFS gets
2686 * requests to look up "desktop.ini" in all the subdirectories.
2687 * This can cause zillions of timeouts looking up non-existent cells
2688 * and volumes, especially in the top-level directory.
2690 * We have not found any way to avoid this or work around it except
2691 * to explicitly ignore the requests for mount points that haven't
2692 * yet been evaluated and for directories that haven't yet been
2695 if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
2696 spacep = cm_GetSpace();
2697 smb_StripLastComponent(spacep->data, &lastComp,
2698 (char *)(&p->parmsp[3]));
2699 #ifndef SPECIAL_FOLDERS
2700 /* Make sure that lastComp is not NULL */
2702 if (stricmp(lastComp, "\\desktop.ini") == 0) {
2703 code = cm_NameI(cm_data.rootSCachep, spacep->data,
2707 userp, tidPathp, &req, &dscp);
2710 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
2711 if ( WANTS_DFS_PATHNAMES(p) )
2712 code = CM_ERROR_PATH_NOT_COVERED;
2714 code = CM_ERROR_BADSHARENAME;
2716 #endif /* DFS_SUPPORT */
2717 if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT && !dscp->mountRootFid.volume)
2718 code = CM_ERROR_NOSUCHFILE;
2719 else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
2720 cm_buf_t *bp = buf_Find(dscp, &hzero);
2724 code = CM_ERROR_NOSUCHFILE;
2726 cm_ReleaseSCache(dscp);
2728 cm_FreeSpace(spacep);
2729 cm_ReleaseUser(userp);
2730 smb_SendTran2Error(vcp, p, opx, code);
2731 smb_FreeTran2Packet(outp);
2737 #endif /* SPECIAL_FOLDERS */
2739 cm_FreeSpace(spacep);
2742 /* now do namei and stat, and copy out the info */
2743 code = cm_NameI(cm_data.rootSCachep, (char *)(&p->parmsp[3]),
2744 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, tidPathp, &req, &scp);
2747 cm_ReleaseUser(userp);
2748 smb_SendTran2Error(vcp, p, opx, code);
2749 smb_FreeTran2Packet(outp);
2754 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
2755 cm_ReleaseSCache(scp);
2756 cm_ReleaseUser(userp);
2757 if ( WANTS_DFS_PATHNAMES(p) )
2758 code = CM_ERROR_PATH_NOT_COVERED;
2760 code = CM_ERROR_BADSHARENAME;
2761 smb_SendTran2Error(vcp, p, opx, code);
2762 smb_FreeTran2Packet(outp);
2765 #endif /* DFS_SUPPORT */
2767 lock_ObtainMutex(&scp->mx);
2768 code = cm_SyncOp(scp, NULL, userp, &req, 0,
2769 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
2770 if (code) goto done;
2772 /* now we have the status in the cache entry, and everything is locked.
2773 * Marshall the output data.
2776 /* for info level 108, figure out short name */
2777 if (infoLevel == 0x108) {
2778 code = cm_GetShortName((char *)(&p->parmsp[3]), userp, &req,
2779 tidPathp, scp->fid.vnode, shortName,
2786 *((u_long *)op) = len * 2; op += 4;
2787 mbstowcs((unsigned short *)op, shortName, len);
2792 if (infoLevel == SMB_INFO_STANDARD || infoLevel == SMB_INFO_QUERY_EA_SIZE) {
2793 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
2794 *((u_long *)op) = dosTime; op += 4; /* creation time */
2795 *((u_long *)op) = dosTime; op += 4; /* access time */
2796 *((u_long *)op) = dosTime; op += 4; /* write time */
2797 *((u_long *)op) = scp->length.LowPart; op += 4; /* length */
2798 *((u_long *)op) = scp->length.LowPart; op += 4; /* alloc size */
2799 attributes = smb_Attributes(scp);
2800 *((u_short *)op) = attributes; op += 2; /* attributes */
2802 else if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
2803 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
2804 *((FILETIME *)op) = ft; op += 8; /* creation time */
2805 *((FILETIME *)op) = ft; op += 8; /* last access time */
2806 *((FILETIME *)op) = ft; op += 8; /* last write time */
2807 *((FILETIME *)op) = ft; op += 8; /* last change time */
2808 extAttributes = smb_ExtAttributes(scp);
2809 *((u_long *)op) = extAttributes; op += 4; /* extended attribs */
2810 *((u_long *)op) = 0; op += 4; /* don't know what this is */
2812 else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO) {
2813 *((LARGE_INTEGER *)op) = scp->length; op += 8; /* alloc size */
2814 *((LARGE_INTEGER *)op) = scp->length; op += 8; /* EOF */
2815 *((u_long *)op) = scp->linkCount; op += 4;
2818 *op++ = (scp->fileType == CM_SCACHETYPE_DIRECTORY ? 1 : 0);
2821 else if (infoLevel == SMB_QUERY_FILE_EA_INFO) {
2822 memset(op, 0, 4); op += 4; /* EA size */
2825 /* now, if we are being asked about extended attrs, return a 0 size */
2826 if (infoLevel == SMB_INFO_QUERY_EA_SIZE) {
2827 *((u_long *)op) = 0; op += 4;
2831 /* send and free the packets */
2833 lock_ReleaseMutex(&scp->mx);
2834 cm_ReleaseSCache(scp);
2835 cm_ReleaseUser(userp);
2837 smb_SendTran2Packet(vcp, outp, opx);
2839 smb_SendTran2Error(vcp, p, opx, code);
2840 smb_FreeTran2Packet(outp);
2845 long smb_ReceiveTran2SetPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
2847 osi_Log0(smb_logp,"ReceiveTran2SetPathInfo - NOT_SUPPORTED");
2848 return CM_ERROR_BADOP;
2851 long smb_ReceiveTran2QFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
2853 smb_tran2Packet_t *outp;
2855 unsigned long attributes;
2856 unsigned short infoLevel;
2869 fidp = smb_FindFID(vcp, fid, 0);
2872 smb_SendTran2Error(vcp, p, opx, CM_ERROR_BADFD);
2876 infoLevel = p->parmsp[1];
2877 if (infoLevel == SMB_QUERY_FILE_BASIC_INFO)
2878 nbytesRequired = 40;
2879 else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO)
2880 nbytesRequired = 24;
2881 else if (infoLevel == SMB_QUERY_FILE_EA_INFO)
2883 else if (infoLevel == SMB_QUERY_FILE_NAME_INFO)
2886 osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
2887 p->opcode, infoLevel);
2888 smb_SendTran2Error(vcp, p, opx, CM_ERROR_INVAL);
2889 smb_ReleaseFID(fidp);
2892 osi_Log2(smb_logp, "T2 QFileInfo type 0x%x fid %d", infoLevel, fid);
2894 outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, nbytesRequired);
2896 if (infoLevel > 0x100)
2897 outp->totalParms = 2;
2899 outp->totalParms = 0;
2900 outp->totalData = nbytesRequired;
2902 userp = smb_GetTran2User(vcp, p);
2904 osi_Log1(smb_logp, "ReceiveTran2QFileInfo unable to resolve user [%d]", p->uid);
2905 code = CM_ERROR_BADSMB;
2910 lock_ObtainMutex(&scp->mx);
2911 code = cm_SyncOp(scp, NULL, userp, &req, 0,
2912 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
2916 /* now we have the status in the cache entry, and everything is locked.
2917 * Marshall the output data.
2920 if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
2921 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
2922 *((FILETIME *)op) = ft; op += 8; /* creation time */
2923 *((FILETIME *)op) = ft; op += 8; /* last access time */
2924 *((FILETIME *)op) = ft; op += 8; /* last write time */
2925 *((FILETIME *)op) = ft; op += 8; /* last change time */
2926 attributes = smb_ExtAttributes(scp);
2927 *((u_long *)op) = attributes; op += 4;
2928 *((u_long *)op) = 0; op += 4;
2930 else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO) {
2931 *((LARGE_INTEGER *)op) = scp->length; op += 8; /* alloc size */
2932 *((LARGE_INTEGER *)op) = scp->length; op += 8; /* EOF */
2933 *((u_long *)op) = scp->linkCount; op += 4;
2934 *op++ = ((fidp->flags & SMB_FID_DELONCLOSE) ? 1 : 0);
2935 *op++ = (scp->fileType == CM_SCACHETYPE_DIRECTORY ? 1 : 0);
2939 else if (infoLevel == SMB_QUERY_FILE_EA_INFO) {
2940 *((u_long *)op) = 0; op += 4;
2942 else if (infoLevel == SMB_QUERY_FILE_NAME_INFO) {
2946 if (fidp->NTopen_wholepathp)
2947 name = fidp->NTopen_wholepathp;
2949 name = "\\"; /* probably can't happen */
2951 outp->totalData = (len*2) + 4; /* this is actually what we want to return */
2952 *((u_long *)op) = len * 2; op += 4;
2953 mbstowcs((unsigned short *)op, name, len); op += (len * 2);
2956 /* send and free the packets */
2958 lock_ReleaseMutex(&scp->mx);
2959 cm_ReleaseUser(userp);
2960 smb_ReleaseFID(fidp);
2962 smb_SendTran2Packet(vcp, outp, opx);
2964 smb_SendTran2Error(vcp, p, opx, code);
2965 smb_FreeTran2Packet(outp);
2970 long smb_ReceiveTran2SetFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
2975 unsigned short infoLevel;
2976 smb_tran2Packet_t *outp;
2984 fidp = smb_FindFID(vcp, fid, 0);
2987 smb_SendTran2Error(vcp, p, op, CM_ERROR_BADFD);
2991 infoLevel = p->parmsp[1];
2992 osi_Log2(smb_logp,"ReceiveTran2SetFileInfo type=[%x] fid=[%x]", infoLevel, fid);
2993 if (infoLevel > 0x104 || infoLevel < 0x101) {
2994 osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
2995 p->opcode, infoLevel);
2996 smb_SendTran2Error(vcp, p, op, CM_ERROR_INVAL);
2997 smb_ReleaseFID(fidp);
3001 if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO && !(fidp->flags & SMB_FID_OPENDELETE)) {
3002 smb_SendTran2Error(vcp, p, op, CM_ERROR_NOACCESS);
3003 smb_ReleaseFID(fidp);
3006 if ((infoLevel == SMB_QUERY_FILE_EA_INFO || infoLevel == SMB_QUERY_FILE_NAME_INFO)
3007 && !(fidp->flags & SMB_FID_OPENWRITE)) {
3008 smb_SendTran2Error(vcp, p, op, CM_ERROR_NOACCESS);
3009 smb_ReleaseFID(fidp);
3013 osi_Log1(smb_logp, "T2 SFileInfo type 0x%x", infoLevel);
3015 outp = smb_GetTran2ResponsePacket(vcp, p, op, 2, 0);
3017 outp->totalParms = 2;
3018 outp->totalData = 0;
3020 userp = smb_GetTran2User(vcp, p);
3022 osi_Log1(smb_logp,"ReceiveTran2SetFileInfo unable to resolve user [%d]", p->uid);
3023 code = CM_ERROR_BADSMB;
3029 if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
3031 unsigned int attribute;
3034 /* lock the vnode with a callback; we need the current status
3035 * to determine what the new status is, in some cases.
3037 lock_ObtainMutex(&scp->mx);
3038 code = cm_SyncOp(scp, NULL, userp, &req, 0,
3039 CM_SCACHESYNC_GETSTATUS
3040 | CM_SCACHESYNC_NEEDCALLBACK);
3042 lock_ReleaseMutex(&scp->mx);
3046 /* prepare for setattr call */
3049 lastMod = *((FILETIME *)(p->datap + 16));
3050 /* when called as result of move a b, lastMod is (-1, -1).
3051 * If the check for -1 is not present, timestamp
3052 * of the resulting file will be 1969 (-1)
3054 if (LargeIntegerNotEqualToZero(*((LARGE_INTEGER *)&lastMod)) &&
3055 lastMod.dwLowDateTime != -1 && lastMod.dwHighDateTime != -1) {
3056 attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
3057 smb_UnixTimeFromLargeSearchTime(&attr.clientModTime, &lastMod);
3058 fidp->flags |= SMB_FID_MTIMESETDONE;
3061 attribute = *((u_long *)(p->datap + 32));
3062 if (attribute != 0) {
3063 if ((scp->unixModeBits & 0222)
3064 && (attribute & 1) != 0) {
3065 /* make a writable file read-only */
3066 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
3067 attr.unixModeBits = scp->unixModeBits & ~0222;
3069 else if ((scp->unixModeBits & 0222) == 0
3070 && (attribute & 1) == 0) {
3071 /* make a read-only file writable */
3072 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
3073 attr.unixModeBits = scp->unixModeBits | 0222;
3076 lock_ReleaseMutex(&scp->mx);
3080 code = cm_SetAttr(scp, &attr, userp, &req);
3084 else if (infoLevel == SMB_QUERY_FILE_EA_INFO || infoLevel == SMB_QUERY_FILE_NAME_INFO) {
3085 LARGE_INTEGER size = *((LARGE_INTEGER *)(p->datap));
3088 attr.mask = CM_ATTRMASK_LENGTH;
3089 attr.length.LowPart = size.LowPart;
3090 attr.length.HighPart = size.HighPart;
3091 code = cm_SetAttr(scp, &attr, userp, &req);
3093 else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO) {
3094 if (*((char *)(p->datap))) {
3095 code = cm_CheckNTDelete(fidp->NTopen_dscp, scp, userp,
3098 fidp->flags |= SMB_FID_DELONCLOSE;
3102 fidp->flags &= ~SMB_FID_DELONCLOSE;
3107 cm_ReleaseUser(userp);
3108 smb_ReleaseFID(fidp);
3110 smb_SendTran2Packet(vcp, outp, op);
3112 smb_SendTran2Error(vcp, p, op, code);
3113 smb_FreeTran2Packet(outp);
3119 smb_ReceiveTran2FSCTL(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3121 osi_Log0(smb_logp,"ReceiveTran2FSCTL - NOT_SUPPORTED");
3122 return CM_ERROR_BADOP;
3126 smb_ReceiveTran2IOCTL(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3128 osi_Log0(smb_logp,"ReceiveTran2IOCTL - NOT_SUPPORTED");
3129 return CM_ERROR_BADOP;
3133 smb_ReceiveTran2FindNotifyFirst(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3135 osi_Log0(smb_logp,"ReceiveTran2FindNotifyFirst - NOT_SUPPORTED");
3136 return CM_ERROR_BADOP;
3140 smb_ReceiveTran2FindNotifyNext(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3142 osi_Log0(smb_logp,"ReceiveTran2FindNotifyNext - NOT_SUPPORTED");
3143 return CM_ERROR_BADOP;
3147 smb_ReceiveTran2CreateDirectory(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3149 osi_Log0(smb_logp,"ReceiveTran2CreateDirectory - NOT_SUPPORTED");
3150 return CM_ERROR_BADOP;
3154 smb_ReceiveTran2SessionSetup(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3156 osi_Log0(smb_logp,"ReceiveTran2SessionSetup - NOT_SUPPORTED");
3157 return CM_ERROR_BADOP;
3160 struct smb_v2_referral {
3162 USHORT ReferralFlags;
3165 USHORT DfsPathOffset;
3166 USHORT DfsAlternativePathOffset;
3167 USHORT NetworkAddressOffset;
3171 smb_ReceiveTran2GetDFSReferral(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
3173 /* This is a UNICODE only request (bit15 of Flags2) */
3174 /* The TID must be IPC$ */
3176 /* The documentation for the Flags response field is contradictory */
3178 /* Use Version 1 Referral Element Format */
3179 /* ServerType = 0; indicates the next server should be queried for the file */
3180 /* ReferralFlags = 0x01; PathConsumed characters should be stripped */
3181 /* Node = UnicodeString of UNC path of the next share name */
3184 int maxReferralLevel = 0;
3185 char requestFileName[1024] = "";
3186 smb_tran2Packet_t *outp = 0;
3187 cm_user_t *userp = 0;
3189 CPINFO CodePageInfo;
3190 int i, nbnLen, reqLen;
3195 maxReferralLevel = p->parmsp[0];
3197 GetCPInfo(CP_ACP, &CodePageInfo);
3198 WideCharToMultiByte(CP_ACP, 0, (LPCWSTR) &p->parmsp[1], -1,
3199 requestFileName, 1024, NULL, NULL);
3201 osi_Log2(smb_logp,"ReceiveTran2GetDfsReferral [%d][%s]",
3202 maxReferralLevel, osi_LogSaveString(smb_logp, requestFileName));
3204 nbnLen = strlen(cm_NetbiosName);
3205 reqLen = strlen(requestFileName);
3207 if (reqLen == nbnLen + 5 &&
3208 requestFileName[0] == '\\' &&
3209 !_strnicmp(cm_NetbiosName,&requestFileName[1],nbnLen) &&
3210 requestFileName[nbnLen+1] == '\\' &&
3211 !_strnicmp("all",&requestFileName[nbnLen+2],3))
3214 struct smb_v2_referral * v2ref;
3215 outp = smb_GetTran2ResponsePacket(vcp, p, op, 0, 2 * (reqLen + 8));
3217 sp = (USHORT *)outp->datap;
3219 sp[idx++] = reqLen; /* path consumed */
3220 sp[idx++] = 1; /* number of referrals */
3221 sp[idx++] = 0x03; /* flags */
3222 #ifdef DFS_VERSION_1
3223 sp[idx++] = 1; /* Version Number */
3224 sp[idx++] = reqLen + 4; /* Referral Size */
3225 sp[idx++] = 1; /* Type = SMB Server */
3226 sp[idx++] = 0; /* Do not strip path consumed */
3227 for ( i=0;i<=reqLen; i++ )
3228 sp[i+idx] = requestFileName[i];
3229 #else /* DFS_VERSION_2 */
3230 sp[idx++] = 2; /* Version Number */
3231 sp[idx++] = sizeof(struct smb_v2_referral); /* Referral Size */
3232 idx += (sizeof(struct smb_v2_referral) / 2);
3233 v2ref = (struct smb_v2_referral *) &sp[5];
3234 v2ref->ServerType = 1; /* SMB Server */
3235 v2ref->ReferralFlags = 0x03;
3236 v2ref->Proximity = 0; /* closest */
3237 v2ref->TimeToLive = 3600; /* seconds */
3238 v2ref->DfsPathOffset = idx * 2;
3239 v2ref->DfsAlternativePathOffset = idx * 2;
3240 v2ref->NetworkAddressOffset = 0;
3241 for ( i=0;i<=reqLen; i++ )
3242 sp[i+idx] = requestFileName[i];
3245 userp = smb_GetTran2User(vcp, p);
3247 osi_Log1(smb_logp,"ReceiveTran2GetDfsReferral unable to resolve user [%d]", p->uid);
3248 code = CM_ERROR_BADSMB;
3253 code = CM_ERROR_NOSUCHPATH;
3258 cm_ReleaseUser(userp);
3260 smb_SendTran2Packet(vcp, outp, op);
3262 smb_SendTran2Error(vcp, p, op, code);
3264 smb_FreeTran2Packet(outp);
3267 #else /* DFS_SUPPORT */
3268 osi_Log0(smb_logp,"ReceiveTran2GetDfsReferral - NOT_SUPPORTED");
3269 return CM_ERROR_BADOP;
3270 #endif /* DFS_SUPPORT */
3274 smb_ReceiveTran2ReportDFSInconsistency(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3276 /* This is a UNICODE only request (bit15 of Flags2) */
3278 /* There is nothing we can do about this operation. The client is going to
3279 * tell us that there is a Version 1 Referral Element for which there is a DFS Error.
3280 * Unfortunately, there is really nothing we can do about it other then log it
3281 * somewhere. Even then I don't think there is anything for us to do.
3282 * So let's return an error value.
3285 osi_Log0(smb_logp,"ReceiveTran2ReportDFSInconsistency - NOT_SUPPORTED");
3286 return CM_ERROR_BADOP;
3290 smb_ApplyV3DirListPatches(cm_scache_t *dscp,
3291 smb_dirListPatch_t **dirPatchespp, int infoLevel, cm_user_t *userp,
3296 cm_scache_t *targetScp; /* target if scp is a symlink */
3301 unsigned short attr;
3302 unsigned long lattr;
3303 smb_dirListPatch_t *patchp;
3304 smb_dirListPatch_t *npatchp;
3306 for(patchp = *dirPatchespp; patchp; patchp =
3307 (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
3308 code = cm_GetSCache(&patchp->fid, &scp, userp, reqp);
3310 lock_ObtainMutex(&scp->mx);
3311 code = cm_SyncOp(scp, NULL, userp, reqp, 0,
3312 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3314 lock_ReleaseMutex(&scp->mx);
3315 cm_ReleaseSCache(scp);
3317 dptr = patchp->dptr;
3319 /* Plug in fake timestamps. A time stamp of 0 causes 'invalid parameter'
3320 errors in the client. */
3321 if (infoLevel >= 0x101) {
3322 /* 1969-12-31 23:59:59 +00 */
3323 ft.dwHighDateTime = 0x19DB200;
3324 ft.dwLowDateTime = 0x5BB78980;
3326 /* copy to Creation Time */
3327 *((FILETIME *)dptr) = ft;
3330 /* copy to Last Access Time */
3331 *((FILETIME *)dptr) = ft;
3334 /* copy to Last Write Time */
3335 *((FILETIME *)dptr) = ft;
3338 /* copy to Change Time */
3339 *((FILETIME *)dptr) = ft;
3342 /* merge in hidden attribute */
3343 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
3344 *((u_long *)dptr) = SMB_ATTR_HIDDEN;
3348 /* 1969-12-31 23:59:58 +00*/
3349 dosTime = 0xEBBFBF7D;
3351 /* and copy out date */
3352 shortTemp = (dosTime>>16) & 0xffff;
3353 *((u_short *)dptr) = shortTemp;
3356 /* copy out creation time */
3357 shortTemp = dosTime & 0xffff;
3358 *((u_short *)dptr) = shortTemp;
3361 /* and copy out date */
3362 shortTemp = (dosTime>>16) & 0xffff;
3363 *((u_short *)dptr) = shortTemp;
3366 /* copy out access time */
3367 shortTemp = dosTime & 0xffff;
3368 *((u_short *)dptr) = shortTemp;
3371 /* and copy out date */
3372 shortTemp = (dosTime>>16) & 0xffff;
3373 *((u_short *)dptr) = shortTemp;
3376 /* copy out mod time */
3377 shortTemp = dosTime & 0xffff;
3378 *((u_short *)dptr) = shortTemp;
3381 /* merge in hidden (dot file) attribute */
3382 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
3383 attr = SMB_ATTR_HIDDEN;
3384 *dptr++ = attr & 0xff;
3385 *dptr++ = (attr >> 8) & 0xff;
3391 /* now watch for a symlink */
3393 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
3394 lock_ReleaseMutex(&scp->mx);
3395 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, reqp);
3397 /* we have a more accurate file to use (the
3398 * target of the symbolic link). Otherwise,
3399 * we'll just use the symlink anyway.
3401 osi_Log2(smb_logp, "symlink vp %x to vp %x",
3403 cm_ReleaseSCache(scp);
3406 lock_ObtainMutex(&scp->mx);
3409 dptr = patchp->dptr;
3411 if (infoLevel >= 0x101) {
3413 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
3415 /* copy to Creation Time */
3416 *((FILETIME *)dptr) = ft;
3419 /* copy to Last Access Time */
3420 *((FILETIME *)dptr) = ft;
3423 /* copy to Last Write Time */
3424 *((FILETIME *)dptr) = ft;
3427 /* copy to Change Time */
3428 *((FILETIME *)dptr) = ft;
3431 /* Use length for both file length and alloc length */
3432 *((LARGE_INTEGER *)dptr) = scp->length;
3434 *((LARGE_INTEGER *)dptr) = scp->length;
3437 /* Copy attributes */
3438 lattr = smb_ExtAttributes(scp);
3439 if (code == CM_ERROR_NOSUCHPATH && scp->fileType == CM_SCACHETYPE_SYMLINK) {
3440 if (lattr == SMB_ATTR_NORMAL)
3441 lattr = SMB_ATTR_DIRECTORY;
3443 lattr |= SMB_ATTR_DIRECTORY;
3445 /* merge in hidden (dot file) attribute */
3446 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
3447 if (lattr == SMB_ATTR_NORMAL)
3448 lattr = SMB_ATTR_HIDDEN;
3450 lattr |= SMB_ATTR_HIDDEN;
3452 *((u_long *)dptr) = lattr;
3456 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
3458 /* and copy out date */
3459 shortTemp = (dosTime>>16) & 0xffff;
3460 *((u_short *)dptr) = shortTemp;
3463 /* copy out creation time */
3464 shortTemp = dosTime & 0xffff;
3465 *((u_short *)dptr) = shortTemp;
3468 /* and copy out date */
3469 shortTemp = (dosTime>>16) & 0xffff;
3470 *((u_short *)dptr) = shortTemp;
3473 /* copy out access time */
3474 shortTemp = dosTime & 0xffff;
3475 *((u_short *)dptr) = shortTemp;
3478 /* and copy out date */
3479 shortTemp = (dosTime>>16) & 0xffff;
3480 *((u_short *)dptr) = shortTemp;
3483 /* copy out mod time */
3484 shortTemp = dosTime & 0xffff;
3485 *((u_short *)dptr) = shortTemp;
3488 /* copy out file length and alloc length,
3489 * using the same for both
3491 *((u_long *)dptr) = scp->length.LowPart;
3493 *((u_long *)dptr) = scp->length.LowPart;
3496 /* finally copy out attributes as short */
3497 attr = smb_Attributes(scp);
3498 /* merge in hidden (dot file) attribute */
3499 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
3500 if (lattr == SMB_ATTR_NORMAL)
3501 lattr = SMB_ATTR_HIDDEN;
3503 lattr |= SMB_ATTR_HIDDEN;
3505 *dptr++ = attr & 0xff;
3506 *dptr++ = (attr >> 8) & 0xff;
3509 lock_ReleaseMutex(&scp->mx);
3510 cm_ReleaseSCache(scp);
3513 /* now free the patches */
3514 for (patchp = *dirPatchespp; patchp; patchp = npatchp) {
3515 npatchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q);
3519 /* and mark the list as empty */
3520 *dirPatchespp = NULL;
3525 #ifndef USE_OLD_MATCHING
3526 // char table for case insensitive comparison
3527 char mapCaseTable[256];
3529 VOID initUpperCaseTable(VOID)
3532 for (i = 0; i < 256; ++i)
3533 mapCaseTable[i] = toupper(i);
3534 // make '"' match '.'
3535 mapCaseTable[(int)'"'] = toupper('.');
3536 // make '<' match '*'
3537 mapCaseTable[(int)'<'] = toupper('*');
3538 // make '>' match '?'
3539 mapCaseTable[(int)'>'] = toupper('?');
3542 // Compare 'pattern' (containing metacharacters '*' and '?') with the file
3544 // Note : this procedure works recursively calling itself.
3546 // PSZ pattern : string containing metacharacters.
3547 // PSZ name : file name to be compared with 'pattern'.
3549 // BOOL : TRUE/FALSE (match/mistmatch)
3552 szWildCardMatchFileName(PSZ pattern, PSZ name, int casefold)
3554 PSZ pename; // points to the last 'name' character
3556 pename = name + strlen(name) - 1;
3567 if (*pattern == '\0')
3569 for (p = pename; p >= name; --p) {
3570 if ((casefold && (mapCaseTable[*p] == mapCaseTable[*pattern]) ||
3571 !casefold && (*p == *pattern)) &&
3572 szWildCardMatchFileName(pattern + 1, p + 1, casefold))
3577 if ((casefold && mapCaseTable[*name] != mapCaseTable[*pattern]) ||
3578 (!casefold && *name != *pattern))
3585 /* if all we have left are wildcards, then we match */
3586 for (;*pattern; pattern++) {
3587 if (*pattern != '*' && *pattern != '?')
3593 /* do a case-folding search of the star name mask with the name in namep.
3594 * Return 1 if we match, otherwise 0.
3596 int smb_V3MatchMask(char *namep, char *maskp, int flags)
3599 int i, j, star, qmark, casefold, retval;
3601 /* make sure we only match 8.3 names, if requested */
3602 if ((flags & CM_FLAG_8DOT3) && !cm_Is8Dot3(namep))
3605 casefold = (flags & CM_FLAG_CASEFOLD) ? 1 : 0;
3607 /* optimize the pattern:
3608 * if there is a mixture of '?' and '*',
3609 * for example the sequence "*?*?*?*"
3610 * must be turned into the form "*"
3612 newmask = (char *)malloc(strlen(maskp)+1);
3613 for ( i=0, j=0, star=0, qmark=0; maskp[i]; i++) {
3614 switch ( maskp[i] ) {
3626 } else if ( qmark ) {
3630 newmask[j++] = maskp[i];
3637 } else if ( qmark ) {
3641 newmask[j++] = '\0';
3643 retval = szWildCardMatchFileName(newmask, namep, casefold) ? 1:0;
3649 #else /* USE_OLD_MATCHING */
3650 /* do a case-folding search of the star name mask with the name in namep.
3651 * Return 1 if we match, otherwise 0.
3653 int smb_V3MatchMask(char *namep, char *maskp, int flags)
3655 unsigned char tcp1, tcp2; /* Pattern characters */
3656 unsigned char tcn1; /* Name characters */
3657 int sawDot = 0, sawStar = 0, req8dot3 = 0;
3658 char *starNamep, *starMaskp;
3659 static char nullCharp[] = {0};
3660 int casefold = flags & CM_FLAG_CASEFOLD;
3662 /* make sure we only match 8.3 names, if requested */
3663 req8dot3 = (flags & CM_FLAG_8DOT3);
3664 if (req8dot3 && !cm_Is8Dot3(namep))
3669 /* Next pattern character */
3672 /* Next name character */
3676 /* 0 - end of pattern */
3682 else if (tcp1 == '.' || tcp1 == '"') {
3692 * first dot in pattern;
3693 * must match dot or end of name
3698 else if (tcn1 == '.') {
3707 else if (tcp1 == '?') {
3708 if (tcn1 == 0 || tcn1 == '.')
3713 else if (tcp1 == '>') {
3714 if (tcn1 != 0 && tcn1 != '.')
3718 else if (tcp1 == '*' || tcp1 == '<') {
3722 else if ((req8dot3 && tcp2 == '.') || tcp2 == '"') {
3723 while (req8dot3 && tcn1 != '.' && tcn1 != 0)
3738 * pattern character after '*' is not null or
3739 * period. If it is '?' or '>', we are not
3740 * going to understand it. If it is '*' or
3741 * '<', we are going to skip over it. None of
3742 * these are likely, I hope.
3744 /* skip over '*' and '<' */
3745 while (tcp2 == '*' || tcp2 == '<')
3748 /* skip over characters that don't match tcp2 */
3749 while (req8dot3 && tcn1 != '.' && tcn1 != 0 &&
3750 ((casefold && cm_foldUpper[tcn1] != cm_foldUpper[tcp2]) ||
3751 (!casefold && tcn1 != tcp2)))
3755 if ((req8dot3 && tcn1 == '.') || tcn1 == 0)
3758 /* Remember where we are */
3768 /* tcp1 is not a wildcard */
3769 if ((casefold && cm_foldUpper[tcn1] == cm_foldUpper[tcp1]) ||
3770 (!casefold && tcn1 == tcp1)) {
3775 /* if trying to match a star pattern, go back */
3777 maskp = starMaskp - 2;
3778 namep = starNamep + 1;
3787 #endif /* USE_OLD_MATCHING */
3789 long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
3794 long code = 0, code2 = 0;
3798 smb_dirListPatch_t *dirListPatchesp;
3799 smb_dirListPatch_t *curPatchp;
3802 long orbytes; /* # of bytes in this output record */
3803 long ohbytes; /* # of bytes, except file name */
3804 long onbytes; /* # of bytes in name, incl. term. null */
3805 osi_hyper_t dirLength;
3806 osi_hyper_t bufferOffset;
3807 osi_hyper_t curOffset;
3809 smb_dirSearch_t *dsp;
3813 cm_pageHeader_t *pageHeaderp;
3814 cm_user_t *userp = NULL;
3817 long nextEntryCookie;
3818 int numDirChunks; /* # of 32 byte dir chunks in this entry */
3819 char *op; /* output data ptr */
3820 char *origOp; /* original value of op */
3821 cm_space_t *spacep; /* for pathname buffer */
3822 long maxReturnData; /* max # of return data */
3823 long maxReturnParms; /* max # of return parms */
3824 long bytesInBuffer; /* # data bytes in the output buffer */
3826 char *maskp; /* mask part of path */
3830 smb_tran2Packet_t *outp; /* response packet */
3833 char shortName[13]; /* 8.3 name if needed */
3844 if (p->opcode == 1) {
3845 /* find first; obtain basic parameters from request */
3846 attribute = p->parmsp[0];
3847 maxCount = p->parmsp[1];
3848 infoLevel = p->parmsp[3];
3849 searchFlags = p->parmsp[2];
3850 dsp = smb_NewDirSearch(1);
3851 dsp->attribute = attribute;
3852 pathp = ((char *) p->parmsp) + 12; /* points to path */
3853 if (smb_StoreAnsiFilenames)
3854 OemToChar(pathp,pathp);
3856 maskp = strrchr(pathp, '\\');
3860 maskp++; /* skip over backslash */
3861 strcpy(dsp->mask, maskp); /* and save mask */
3862 /* track if this is likely to match a lot of entries */
3863 starPattern = smb_V3IsStarMask(maskp);
3866 osi_assert(p->opcode == 2);
3867 /* find next; obtain basic parameters from request or open dir file */
3868 dsp = smb_FindDirSearch(p->parmsp[0]);
3869 maxCount = p->parmsp[1];
3870 infoLevel = p->parmsp[2];
3871 nextCookie = p->parmsp[3] | (p->parmsp[4] << 16);
3872 searchFlags = p->parmsp[5];
3874 osi_Log2(smb_logp, "T2 search dir bad search ID: id %d nextCookie 0x%x",
3875 p->parmsp[0], nextCookie);
3876 return CM_ERROR_BADFD;
3878 attribute = dsp->attribute;
3881 starPattern = 1; /* assume, since required a Find Next */
3885 "T2 search dir attr 0x%x, info level %d, max count %d, flags 0x%x",
3886 attribute, infoLevel, maxCount, searchFlags);
3888 osi_Log3(smb_logp, "...T2 search op %d, id %d, nextCookie 0x%x",
3889 p->opcode, dsp->cookie, nextCookie);
3891 if (infoLevel >= 0x101)
3892 searchFlags &= ~4; /* no resume keys */
3894 dirListPatchesp = NULL;
3896 maxReturnData = p->maxReturnData;
3897 if (p->opcode == 1) /* find first */
3898 maxReturnParms = 10; /* bytes */
3900 maxReturnParms = 8; /* bytes */
3902 #ifndef CM_CONFIG_MULTITRAN2RESPONSES
3903 if (maxReturnData > 6000)
3904 maxReturnData = 6000;
3905 #endif /* CM_CONFIG_MULTITRAN2RESPONSES */
3907 outp = smb_GetTran2ResponsePacket(vcp, p, opx, maxReturnParms,
3910 osi_Log2(smb_logp, "T2 receive search dir count %d [%s]",
3911 maxCount, osi_LogSaveString(smb_logp, pathp));
3913 /* bail out if request looks bad */
3914 if (p->opcode == 1 && !pathp) {
3915 smb_ReleaseDirSearch(dsp);
3916 smb_FreeTran2Packet(outp);
3917 return CM_ERROR_BADSMB;
3920 osi_Log3(smb_logp, "T2 search dir id %d, nextCookie 0x%x, attr 0x%x",
3921 dsp->cookie, nextCookie, attribute);
3923 userp = smb_GetTran2User(vcp, p);
3925 osi_Log1(smb_logp, "T2 search dir unable to resolve user [%d]", p->uid);
3926 smb_ReleaseDirSearch(dsp);
3927 smb_FreeTran2Packet(outp);
3928 return CM_ERROR_BADSMB;
3931 /* try to get the vnode for the path name next */
3932 lock_ObtainMutex(&dsp->mx);
3938 spacep = cm_GetSpace();
3939 smb_StripLastComponent(spacep->data, NULL, pathp);
3940 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
3942 cm_ReleaseUser(userp);
3943 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOFILES);
3944 smb_FreeTran2Packet(outp);
3945 lock_ReleaseMutex(&dsp->mx);
3946 smb_DeleteDirSearch(dsp);
3947 smb_ReleaseDirSearch(dsp);
3950 code = cm_NameI(cm_data.rootSCachep, spacep->data,
3951 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
3952 userp, tidPathp, &req, &scp);
3953 cm_FreeSpace(spacep);
3956 #ifdef DFS_SUPPORT_BUT_NOT_FIND_FIRST
3957 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
3958 cm_ReleaseSCache(scp);
3959 cm_ReleaseUser(userp);
3960 if ( WANTS_DFS_PATHNAMES(p) )
3961 code = CM_ERROR_PATH_NOT_COVERED;
3963 code = CM_ERROR_BADSHARENAME;
3964 smb_SendTran2Error(vcp, p, opx, code);
3965 smb_FreeTran2Packet(outp);
3966 lock_ReleaseMutex(&dsp->mx);
3967 smb_DeleteDirSearch(dsp);
3968 smb_ReleaseDirSearch(dsp);
3971 #endif /* DFS_SUPPORT */
3973 /* we need one hold for the entry we just stored into,
3974 * and one for our own processing. When we're done
3975 * with this function, we'll drop the one for our own
3976 * processing. We held it once from the namei call,
3977 * and so we do another hold now.
3980 lock_ObtainMutex(&scp->mx);
3981 if ((scp->flags & CM_SCACHEFLAG_BULKSTATTING) == 0 &&
3982 LargeIntegerGreaterOrEqualToZero(scp->bulkStatProgress)) {
3983 scp->flags |= CM_SCACHEFLAG_BULKSTATTING;
3984 dsp->flags |= SMB_DIRSEARCH_BULKST;
3986 lock_ReleaseMutex(&scp->mx);
3989 lock_ReleaseMutex(&dsp->mx);
3991 cm_ReleaseUser(userp);
3992 smb_FreeTran2Packet(outp);
3993 smb_DeleteDirSearch(dsp);
3994 smb_ReleaseDirSearch(dsp);
3998 /* get the directory size */
3999 lock_ObtainMutex(&scp->mx);
4000 code = cm_SyncOp(scp, NULL, userp, &req, 0,
4001 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4003 lock_ReleaseMutex(&scp->mx);
4004 cm_ReleaseSCache(scp);
4005 cm_ReleaseUser(userp);
4006 smb_FreeTran2Packet(outp);
4007 smb_DeleteDirSearch(dsp);
4008 smb_ReleaseDirSearch(dsp);
4013 dirLength = scp->length;
4015 bufferOffset.LowPart = bufferOffset.HighPart = 0;
4016 curOffset.HighPart = 0;
4017 curOffset.LowPart = nextCookie;
4018 origOp = outp->datap;
4026 if (searchFlags & 4)
4027 /* skip over resume key */
4030 /* make sure that curOffset.LowPart doesn't point to the first
4031 * 32 bytes in the 2nd through last dir page, and that it doesn't
4032 * point at the first 13 32-byte chunks in the first dir page,
4033 * since those are dir and page headers, and don't contain useful
4036 temp = curOffset.LowPart & (2048-1);
4037 if (curOffset.HighPart == 0 && curOffset.LowPart < 2048) {
4038 /* we're in the first page */
4039 if (temp < 13*32) temp = 13*32;
4042 /* we're in a later dir page */
4043 if (temp < 32) temp = 32;
4046 /* make sure the low order 5 bits are zero */
4049 /* now put temp bits back ito curOffset.LowPart */
4050 curOffset.LowPart &= ~(2048-1);
4051 curOffset.LowPart |= temp;
4053 /* check if we've passed the dir's EOF */
4054 if (LargeIntegerGreaterThanOrEqualTo(curOffset, dirLength)) {
4055 osi_Log0(smb_logp, "T2 search dir passed eof");
4060 /* check if we've returned all the names that will fit in the
4061 * response packet; we check return count as well as the number
4062 * of bytes requested. We check the # of bytes after we find
4063 * the dir entry, since we'll need to check its size.
4065 if (returnedNames >= maxCount) {
4066 osi_Log2(smb_logp, "T2 search dir returnedNames %d >= maxCount %d",
4067 returnedNames, maxCount);
4071 /* see if we can use the bufferp we have now; compute in which
4072 * page the current offset would be, and check whether that's
4073 * the offset of the buffer we have. If not, get the buffer.
4075 thyper.HighPart = curOffset.HighPart;
4076 thyper.LowPart = curOffset.LowPart & ~(cm_data.buf_blockSize-1);
4077 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
4080 buf_Release(bufferp);
4083 lock_ReleaseMutex(&scp->mx);
4084 lock_ObtainRead(&scp->bufCreateLock);
4085 code = buf_Get(scp, &thyper, &bufferp);
4086 lock_ReleaseRead(&scp->bufCreateLock);
4087 lock_ObtainMutex(&dsp->mx);
4089 /* now, if we're doing a star match, do bulk fetching
4090 * of all of the status info for files in the dir.
4093 smb_ApplyV3DirListPatches(scp, &dirListPatchesp,
4096 lock_ObtainMutex(&scp->mx);
4097 if ((dsp->flags & SMB_DIRSEARCH_BULKST) &&
4098 LargeIntegerGreaterThanOrEqualTo(thyper, scp->bulkStatProgress)) {
4099 /* Don't bulk stat if risking timeout */
4100 int now = GetCurrentTime();
4101 if (now - req.startTime > 5000) {
4102 scp->bulkStatProgress = thyper;
4103 scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
4104 dsp->flags &= ~SMB_DIRSEARCH_BULKST;
4106 cm_TryBulkStat(scp, &thyper, userp, &req);
4109 lock_ObtainMutex(&scp->mx);
4111 lock_ReleaseMutex(&dsp->mx);
4113 osi_Log2(smb_logp, "T2 search dir buf_Get scp %x failed %d", scp, code);
4117 bufferOffset = thyper;
4119 /* now get the data in the cache */
4121 code = cm_SyncOp(scp, bufferp, userp, &req,
4123 CM_SCACHESYNC_NEEDCALLBACK
4124 | CM_SCACHESYNC_READ);
4126 osi_Log2(smb_logp, "T2 search dir cm_SyncOp scp %x failed %d", scp, code);
4130 if (cm_HaveBuffer(scp, bufferp, 0)) {
4131 osi_Log2(smb_logp, "T2 search dir !HaveBuffer scp %x bufferp %x", scp, bufferp);
4135 /* otherwise, load the buffer and try again */
4136 code = cm_GetBuffer(scp, bufferp, NULL, userp,
4139 osi_Log3(smb_logp, "T2 search dir cm_GetBuffer failed scp %x bufferp %x code %d",
4140 scp, bufferp, code);
4145 buf_Release(bufferp);
4149 } /* if (wrong buffer) ... */
4151 /* now we have the buffer containing the entry we're interested
4152 * in; copy it out if it represents a non-deleted entry.
4154 entryInDir = curOffset.LowPart & (2048-1);
4155 entryInBuffer = curOffset.LowPart & (cm_data.buf_blockSize - 1);
4157 /* page header will help tell us which entries are free. Page
4158 * header can change more often than once per buffer, since
4159 * AFS 3 dir page size may be less than (but not more than)
4160 * a buffer package buffer.
4162 /* only look intra-buffer */
4163 temp = curOffset.LowPart & (cm_data.buf_blockSize - 1);
4164 temp &= ~(2048 - 1); /* turn off intra-page bits */
4165 pageHeaderp = (cm_pageHeader_t *) (bufferp->datap + temp);
4167 /* now determine which entry we're looking at in the page.
4168 * If it is free (there's a free bitmap at the start of the
4169 * dir), we should skip these 32 bytes.
4171 slotInPage = (entryInDir & 0x7e0) >> 5;
4172 if (!(pageHeaderp->freeBitmap[slotInPage>>3] &
4173 (1 << (slotInPage & 0x7)))) {
4174 /* this entry is free */
4175 numDirChunks = 1; /* only skip this guy */
4179 tp = bufferp->datap + entryInBuffer;
4180 dep = (cm_dirEntry_t *) tp; /* now points to AFS3 dir entry */
4182 /* while we're here, compute the next entry's location, too,
4183 * since we'll need it when writing out the cookie into the dir
4186 * XXXX Probably should do more sanity checking.
4188 numDirChunks = cm_NameEntries(dep->name, &onbytes);
4190 /* compute offset of cookie representing next entry */
4191 nextEntryCookie = curOffset.LowPart + (CM_DIR_CHUNKSIZE * numDirChunks);
4193 /* Need 8.3 name? */
4195 if (infoLevel == SMB_QUERY_FILE_NAME_INFO
4196 && dep->fid.vnode != 0
4197 && !cm_Is8Dot3(dep->name)) {
4198 cm_Gen8Dot3Name(dep, shortName, &shortNameEnd);
4202 osi_Log3(smb_logp, "T2 search dir vn %u name %s (%s)",
4203 dep->fid.vnode, osi_LogSaveString(smb_logp, dep->name),
4204 NeedShortName ? osi_LogSaveString(smb_logp, shortName) : "");
4206 /* When matching, we are using doing a case fold if we have a wildcard mask.
4207 * If we get a non-wildcard match, it's a lookup for a specific file.
4209 if (dep->fid.vnode != 0 &&
4210 (smb_V3MatchMask(dep->name, maskp, (starPattern? CM_FLAG_CASEFOLD : 0)) ||
4212 smb_V3MatchMask(shortName, maskp, CM_FLAG_CASEFOLD)))) {
4214 /* Eliminate entries that don't match requested attributes */
4215 if (smb_hideDotFiles && !(dsp->attribute & SMB_ATTR_HIDDEN) &&
4216 smb_IsDotFile(dep->name)) {
4217 osi_Log0(smb_logp, "T2 search dir skipping hidden");
4218 goto nextEntry; /* no hidden files */
4220 if (!(dsp->attribute & SMB_ATTR_DIRECTORY)) /* no directories */
4222 /* We have already done the cm_TryBulkStat above */
4223 fid.cell = scp->fid.cell;
4224 fid.volume = scp->fid.volume;
4225 fid.vnode = ntohl(dep->fid.vnode);
4226 fid.unique = ntohl(dep->fid.unique);
4227 fileType = cm_FindFileType(&fid);
4228 /*osi_Log2(smb_logp, "smb_ReceiveTran2SearchDir: file %s "
4229 "has filetype %d", dep->name,
4231 if (fileType == CM_SCACHETYPE_DIRECTORY ||
4232 fileType == CM_SCACHETYPE_DFSLINK ||
4233 fileType == CM_SCACHETYPE_INVALID)
4234 osi_Log0(smb_logp, "T2 search dir skipping directory or bad link");
4238 /* finally check if this name will fit */
4240 /* standard dir entry stuff */
4241 if (infoLevel < 0x101)
4242 ohbytes = 23; /* pre-NT */
4243 else if (infoLevel == SMB_QUERY_FILE_EA_INFO)
4244 ohbytes = 12; /* NT names only */
4246 ohbytes = 64; /* NT */
4248 if (infoLevel == SMB_QUERY_FILE_NAME_INFO)
4249 ohbytes += 26; /* Short name & length */
4251 if (searchFlags & 4) {
4252 ohbytes += 4; /* if resume key required */
4256 && infoLevel != 0x101
4257 && infoLevel != 0x103)
4258 ohbytes += 4; /* EASIZE */
4260 /* add header to name & term. null */
4261 orbytes = onbytes + ohbytes + 1;
4263 /* now, we round up the record to a 4 byte alignment,
4264 * and we make sure that we have enough room here for
4265 * even the aligned version (so we don't have to worry
4266 * about an * overflow when we pad things out below).
4267 * That's the reason for the alignment arithmetic below.
4269 if (infoLevel >= 0x101)
4270 align = (4 - (orbytes & 3)) & 3;
4273 if (orbytes + bytesInBuffer + align > maxReturnData) {
4274 osi_Log1(smb_logp, "T2 dir search exceed max return data %d",
4279 /* this is one of the entries to use: it is not deleted
4280 * and it matches the star pattern we're looking for.
4281 * Put out the name, preceded by its length.
4283 /* First zero everything else */
4284 memset(origOp, 0, ohbytes);
4286 if (infoLevel <= 0x101)
4287 *(origOp + ohbytes - 1) = (unsigned char) onbytes;
4288 else if (infoLevel == SMB_QUERY_FILE_EA_INFO)
4289 *((u_long *)(op + 8)) = onbytes;
4291 *((u_long *)(op + 60)) = onbytes;
4292 strcpy(origOp+ohbytes, dep->name);
4293 if (smb_StoreAnsiFilenames)
4294 CharToOem(origOp+ohbytes, origOp+ohbytes);
4296 /* Short name if requested and needed */
4297 if (infoLevel == SMB_QUERY_FILE_NAME_INFO) {
4298 if (NeedShortName) {
4299 strcpy(op + 70, shortName);
4300 if (smb_StoreAnsiFilenames)
4301 CharToOem(op + 70, op + 70);
4302 *(op + 68) = shortNameEnd - shortName;
4306 /* now, adjust the # of entries copied */
4309 /* NextEntryOffset and FileIndex */
4310 if (infoLevel >= 101) {
4311 int entryOffset = orbytes + align;
4312 *((u_long *)op) = entryOffset;
4313 *((u_long *)(op+4)) = nextEntryCookie;
4316 /* now we emit the attribute. This is tricky, since
4317 * we need to really stat the file to find out what
4318 * type of entry we've got. Right now, we're copying
4319 * out data from a buffer, while holding the scp
4320 * locked, so it isn't really convenient to stat
4321 * something now. We'll put in a place holder
4322 * now, and make a second pass before returning this
4323 * to get the real attributes. So, we just skip the
4324 * data for now, and adjust it later. We allocate a
4325 * patch record to make it easy to find this point
4326 * later. The replay will happen at a time when it is
4327 * safe to unlock the directory.
4329 if (infoLevel != 0x103) {
4330 curPatchp = malloc(sizeof(*curPatchp));
4331 osi_QAdd((osi_queue_t **) &dirListPatchesp,
4333 curPatchp->dptr = op;
4334 if (infoLevel >= 0x101)
4335 curPatchp->dptr += 8;
4337 if (smb_hideDotFiles && smb_IsDotFile(dep->name)) {
4338 curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
4341 curPatchp->flags = 0;
4343 curPatchp->fid.cell = scp->fid.cell;
4344 curPatchp->fid.volume = scp->fid.volume;
4345 curPatchp->fid.vnode = ntohl(dep->fid.vnode);
4346 curPatchp->fid.unique = ntohl(dep->fid.unique);
4349 curPatchp->dep = dep;
4352 if (searchFlags & 4)
4353 /* put out resume key */
4354 *((u_long *)origOp) = nextEntryCookie;
4356 /* Adjust byte ptr and count */
4357 origOp += orbytes; /* skip entire record */
4358 bytesInBuffer += orbytes;
4360 /* and pad the record out */
4361 while (--align >= 0) {
4365 } /* if we're including this name */
4366 else if (!starPattern &&
4368 dep->fid.vnode != 0 &&
4369 smb_V3MatchMask(dep->name, maskp, CM_FLAG_CASEFOLD)) {
4370 /* We were looking for exact matches, but here's an inexact one*/
4375 /* and adjust curOffset to be where the new cookie is */
4376 thyper.HighPart = 0;
4377 thyper.LowPart = CM_DIR_CHUNKSIZE * numDirChunks;
4378 curOffset = LargeIntegerAdd(thyper, curOffset);
4379 } /* while copying data for dir listing */
4381 /* If we didn't get a star pattern, we did an exact match during the first pass.
4382 * If there were no exact matches found, we fail over to inexact matches by
4383 * marking the query as a star pattern (matches all case permutations), and
4384 * re-running the query.
4386 if (returnedNames == 0 && !starPattern && foundInexact) {
4387 osi_Log0(afsd_logp,"T2 Search: No exact matches. Re-running for inexact matches");
4392 /* release the mutex */
4393 lock_ReleaseMutex(&scp->mx);
4395 buf_Release(bufferp);
4397 /* apply and free last set of patches; if not doing a star match, this
4398 * will be empty, but better safe (and freeing everything) than sorry.
4400 code2 = smb_ApplyV3DirListPatches(scp, &dirListPatchesp, infoLevel, userp,
4403 /* now put out the final parameters */
4404 if (returnedNames == 0)
4406 if (p->opcode == 1) {
4408 outp->parmsp[0] = (unsigned short) dsp->cookie;
4409 outp->parmsp[1] = returnedNames;
4410 outp->parmsp[2] = eos;
4411 outp->parmsp[3] = 0; /* nothing wrong with EAS */
4412 outp->parmsp[4] = 0;
4413 /* don't need last name to continue
4414 * search, cookie is enough. Normally,
4415 * this is the offset of the file name
4416 * of the last entry returned.
4418 outp->totalParms = 10; /* in bytes */
4422 outp->parmsp[0] = returnedNames;
4423 outp->parmsp[1] = eos;
4424 outp->parmsp[2] = 0; /* EAS error */
4425 outp->parmsp[3] = 0; /* last name, as above */
4426 outp->totalParms = 8; /* in bytes */
4429 /* return # of bytes in the buffer */
4430 outp->totalData = bytesInBuffer;
4432 /* Return error code if unsuccessful on first request */
4433 if (code == 0 && p->opcode == 1 && returnedNames == 0)
4434 code = CM_ERROR_NOSUCHFILE;
4436 osi_Log4(smb_logp, "T2 search dir done, opcode %d, id %d, %d names, code %d",
4437 p->opcode, dsp->cookie, returnedNames, code);
4439 /* if we're supposed to close the search after this request, or if
4440 * we're supposed to close the search if we're done, and we're done,
4441 * or if something went wrong, close the search.
4443 /* ((searchFlags & 1) || ((searchFlags & 2) && eos) */
4444 if ((searchFlags & 1) || (returnedNames == 0) ||
4445 ((searchFlags & 2) && eos) || code != 0)
4446 smb_DeleteDirSearch(dsp);
4448 smb_SendTran2Error(vcp, p, opx, code);
4450 smb_SendTran2Packet(vcp, outp, opx);
4452 smb_FreeTran2Packet(outp);
4453 smb_ReleaseDirSearch(dsp);
4454 cm_ReleaseSCache(scp);
4455 cm_ReleaseUser(userp);
4459 long smb_ReceiveV3FindClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4462 smb_dirSearch_t *dsp;
4464 dirHandle = smb_GetSMBParm(inp, 0);
4466 osi_Log1(smb_logp, "SMB3 find close handle %d", dirHandle);
4468 dsp = smb_FindDirSearch(dirHandle);
4471 return CM_ERROR_BADFD;
4473 /* otherwise, we have an FD to destroy */
4474 smb_DeleteDirSearch(dsp);
4475 smb_ReleaseDirSearch(dsp);
4477 /* and return results */
4478 smb_SetSMBDataLength(outp, 0);
4483 long smb_ReceiveV3FindNotifyClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4485 smb_SetSMBDataLength(outp, 0);
4489 long smb_ReceiveV3OpenX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4496 cm_scache_t *dscp; /* dir we're dealing with */
4497 cm_scache_t *scp; /* file we're creating */
4499 int initialModeBits;
4509 int parmSlot; /* which parm we're dealing with */
4517 extraInfo = (smb_GetSMBParm(inp, 2) & 1); /* return extra info */
4518 openFun = smb_GetSMBParm(inp, 8); /* open function */
4519 excl = ((openFun & 3) == 0);
4520 trunc = ((openFun & 3) == 2); /* truncate it */
4521 openMode = (smb_GetSMBParm(inp, 3) & 0x7);
4522 openAction = 0; /* tracks what we did */
4524 attributes = smb_GetSMBParm(inp, 5);
4525 dosTime = smb_GetSMBParm(inp, 6) | (smb_GetSMBParm(inp, 7) << 16);
4527 /* compute initial mode bits based on read-only flag in attributes */
4528 initialModeBits = 0666;
4529 if (attributes & 1) initialModeBits &= ~0222;
4531 pathp = smb_GetSMBData(inp, NULL);
4532 if (smb_StoreAnsiFilenames)
4533 OemToChar(pathp,pathp);
4535 spacep = inp->spacep;
4536 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
4538 if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
4539 /* special case magic file name for receiving IOCTL requests
4540 * (since IOCTL calls themselves aren't getting through).
4543 osi_Log0(smb_logp, "IOCTL Open");
4546 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
4547 smb_SetupIoctlFid(fidp, spacep);
4549 /* set inp->fid so that later read calls in same msg can find fid */
4550 inp->fid = fidp->fid;
4552 /* copy out remainder of the parms */
4554 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
4556 smb_SetSMBParm(outp, parmSlot, /* attrs */ 0); parmSlot++;
4557 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* mod time */
4558 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
4559 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* len */
4560 smb_SetSMBParm(outp, parmSlot, 0x7fff); parmSlot++;
4561 smb_SetSMBParm(outp, parmSlot, openMode); parmSlot++;
4562 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* file type 0 ==> normal file or dir */
4563 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* IPC junk */
4565 /* and the final "always present" stuff */
4566 smb_SetSMBParm(outp, parmSlot, /* openAction found existing file */ 1); parmSlot++;
4567 /* next write out the "unique" ID */
4568 smb_SetSMBParm(outp, parmSlot, 0x1234); parmSlot++;
4569 smb_SetSMBParm(outp, parmSlot, 0x5678); parmSlot++;
4570 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
4571 smb_SetSMBDataLength(outp, 0);
4573 /* and clean up fid reference */
4574 smb_ReleaseFID(fidp);
4578 #ifdef DEBUG_VERBOSE
4580 char *hexp, *asciip;
4581 asciip = (lastNamep ? lastNamep : pathp );
4582 hexp = osi_HexifyString(asciip);
4583 DEBUG_EVENT2("AFS", "V3Open H[%s] A[%s]", hexp, asciip );
4587 userp = smb_GetUser(vcp, inp);
4590 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4592 cm_ReleaseUser(userp);
4593 return CM_ERROR_NOSUCHPATH;
4595 code = cm_NameI(cm_data.rootSCachep, pathp,
4596 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
4597 userp, tidPathp, &req, &scp);
4600 if (code == 0 && scp->fileType == CM_SCACHETYPE_DFSLINK) {
4601 cm_ReleaseSCache(scp);
4602 cm_ReleaseUser(userp);
4603 if ( WANTS_DFS_PATHNAMES(inp) )
4604 return CM_ERROR_PATH_NOT_COVERED;
4606 return CM_ERROR_BADSHARENAME;
4608 #endif /* DFS_SUPPORT */
4611 code = cm_NameI(cm_data.rootSCachep, spacep->data,
4612 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
4613 userp, tidPathp, &req, &dscp);
4615 cm_ReleaseUser(userp);
4620 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
4621 cm_ReleaseSCache(dscp);
4622 cm_ReleaseUser(userp);
4623 if ( WANTS_DFS_PATHNAMES(inp) )
4624 return CM_ERROR_PATH_NOT_COVERED;
4626 return CM_ERROR_BADSHARENAME;
4628 #endif /* DFS_SUPPORT */
4630 /* otherwise, scp points to the parent directory. Do a lookup,
4631 * and truncate the file if we find it, otherwise we create the
4638 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD, userp,
4640 if (code && code != CM_ERROR_NOSUCHFILE) {
4641 cm_ReleaseSCache(dscp);
4642 cm_ReleaseUser(userp);
4647 /* if we get here, if code is 0, the file exists and is represented by
4648 * scp. Otherwise, we have to create it. The dir may be represented
4649 * by dscp, or we may have found the file directly. If code is non-zero,
4653 code = cm_CheckOpen(scp, openMode, trunc, userp, &req);
4655 if (dscp) cm_ReleaseSCache(dscp);
4656 cm_ReleaseSCache(scp);
4657 cm_ReleaseUser(userp);
4662 /* oops, file shouldn't be there */
4664 cm_ReleaseSCache(dscp);
4665 cm_ReleaseSCache(scp);
4666 cm_ReleaseUser(userp);
4667 return CM_ERROR_EXISTS;
4671 setAttr.mask = CM_ATTRMASK_LENGTH;
4672 setAttr.length.LowPart = 0;
4673 setAttr.length.HighPart = 0;
4674 code = cm_SetAttr(scp, &setAttr, userp, &req);
4675 openAction = 3; /* truncated existing file */
4677 else openAction = 1; /* found existing file */
4679 else if (!(openFun & SMB_ATTR_DIRECTORY)) {
4680 /* don't create if not found */
4681 if (dscp) cm_ReleaseSCache(dscp);
4682 cm_ReleaseUser(userp);
4683 return CM_ERROR_NOSUCHFILE;
4686 osi_assert(dscp != NULL);
4687 osi_Log1(smb_logp, "smb_ReceiveV3OpenX creating file %s",
4688 osi_LogSaveString(smb_logp, lastNamep));
4689 openAction = 2; /* created file */
4690 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
4691 smb_UnixTimeFromDosUTime(&setAttr.clientModTime, dosTime);
4692 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
4694 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
4695 smb_NotifyChange(FILE_ACTION_ADDED,
4696 FILE_NOTIFY_CHANGE_FILE_NAME,
4697 dscp, lastNamep, NULL, TRUE);
4698 if (!excl && code == CM_ERROR_EXISTS) {
4699 /* not an exclusive create, and someone else tried
4700 * creating it already, then we open it anyway. We
4701 * don't bother retrying after this, since if this next
4702 * fails, that means that the file was deleted after we
4703 * started this call.
4705 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
4709 setAttr.mask = CM_ATTRMASK_LENGTH;
4710 setAttr.length.LowPart = 0;
4711 setAttr.length.HighPart = 0;
4712 code = cm_SetAttr(scp, &setAttr, userp, &req);
4714 } /* lookup succeeded */
4718 /* we don't need this any longer */
4720 cm_ReleaseSCache(dscp);
4723 /* something went wrong creating or truncating the file */
4725 cm_ReleaseSCache(scp);
4726 cm_ReleaseUser(userp);
4730 /* make sure we're about to open a file */
4731 if (scp->fileType != CM_SCACHETYPE_FILE) {
4732 cm_ReleaseSCache(scp);
4733 cm_ReleaseUser(userp);
4734 return CM_ERROR_ISDIR;
4737 /* now all we have to do is open the file itself */
4738 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
4741 /* save a pointer to the vnode */
4744 /* compute open mode */
4746 fidp->flags |= SMB_FID_OPENREAD;
4747 if (openMode == 1 || openMode == 2)
4748 fidp->flags |= SMB_FID_OPENWRITE;
4750 smb_ReleaseFID(fidp);
4752 cm_Open(scp, 0, userp);
4754 /* set inp->fid so that later read calls in same msg can find fid */
4755 inp->fid = fidp->fid;
4757 /* copy out remainder of the parms */
4759 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
4760 lock_ObtainMutex(&scp->mx);
4762 smb_SetSMBParm(outp, parmSlot, smb_Attributes(scp)); parmSlot++;
4763 smb_DosUTimeFromUnixTime(&dosTime, scp->clientModTime);
4764 smb_SetSMBParm(outp, parmSlot, dosTime & 0xffff); parmSlot++;
4765 smb_SetSMBParm(outp, parmSlot, (dosTime>>16) & 0xffff); parmSlot++;
4766 smb_SetSMBParm(outp, parmSlot, scp->length.LowPart & 0xffff); parmSlot++;
4767 smb_SetSMBParm(outp, parmSlot, (scp->length.LowPart >> 16) & 0xffff); parmSlot++;
4768 smb_SetSMBParm(outp, parmSlot, openMode); parmSlot++;
4769 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* file type 0 ==> normal file or dir */
4770 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* IPC junk */
4772 /* and the final "always present" stuff */
4773 smb_SetSMBParm(outp, parmSlot, openAction); parmSlot++;
4774 /* next write out the "unique" ID */
4775 smb_SetSMBParm(outp, parmSlot, scp->fid.vnode & 0xffff); parmSlot++;
4776 smb_SetSMBParm(outp, parmSlot, scp->fid.volume & 0xffff); parmSlot++;
4777 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
4778 lock_ReleaseMutex(&scp->mx);
4779 smb_SetSMBDataLength(outp, 0);
4781 osi_Log1(smb_logp, "SMB OpenX opening fid %d", fidp->fid);
4783 cm_ReleaseUser(userp);
4784 /* leave scp held since we put it in fidp->scp */
4788 static void smb_GetLockParams(unsigned char LockType,
4790 unsigned int * ppid,
4791 LARGE_INTEGER * pOffset,
4792 LARGE_INTEGER * pLength)
4794 if (LockType & LOCKING_ANDX_LARGE_FILES) {
4796 *ppid = *((USHORT *) *buf);
4797 pOffset->HighPart = *((LONG *)(*buf + 4));
4798 pOffset->LowPart = *((DWORD *)(*buf + 8));
4799 pLength->HighPart = *((LONG *)(*buf + 12));
4800 pLength->LowPart = *((DWORD *)(*buf + 16));
4804 /* Not Large Files */
4805 *ppid = *((USHORT *) *buf);
4806 pOffset->HighPart = 0;
4807 pOffset->LowPart = *((DWORD *)(*buf + 2));
4808 pLength->HighPart = 0;
4809 pLength->LowPart = *((DWORD *)(*buf + 6));
4814 long smb_ReceiveV3LockingX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4821 unsigned char LockType;
4822 unsigned short NumberOfUnlocks, NumberOfLocks;
4826 LARGE_INTEGER LOffset, LLength;
4827 smb_waitingLockRequest_t *wlRequest = NULL;
4828 cm_file_lock_t *lockp;
4836 fid = smb_GetSMBParm(inp, 2);
4837 fid = smb_ChainFID(fid, inp);
4839 fidp = smb_FindFID(vcp, fid, 0);
4840 if (!fidp || (fidp->flags & SMB_FID_IOCTL)) {
4841 osi_Log0(smb_logp, "smb_ReceiveV3Locking BadFD");
4842 return CM_ERROR_BADFD;
4844 /* set inp->fid so that later read calls in same msg can find fid */
4847 userp = smb_GetUser(vcp, inp);
4851 lock_ObtainMutex(&scp->mx);
4852 code = cm_SyncOp(scp, NULL, userp, &req, 0,
4853 CM_SCACHESYNC_NEEDCALLBACK
4854 | CM_SCACHESYNC_GETSTATUS
4855 | CM_SCACHESYNC_LOCK);
4857 osi_Log1(smb_logp, "smb_ReceiveV3Locking SyncOp failure code 0x%x", code);
4861 LockType = smb_GetSMBParm(inp, 3) & 0xff;
4862 Timeout = (smb_GetSMBParm(inp, 5) << 16) + smb_GetSMBParm(inp, 4);
4863 NumberOfUnlocks = smb_GetSMBParm(inp, 6);
4864 NumberOfLocks = smb_GetSMBParm(inp, 7);
4866 if ((LockType & LOCKING_ANDX_CANCEL_LOCK) ||
4867 (LockType & LOCKING_ANDX_CHANGE_LOCKTYPE)) {
4869 /* We don't support these requests. Apparently, we can safely
4870 not deal with them too. */
4871 osi_Log1(smb_logp, "smb_ReceiveV3Locking received unsupported request [%s]",
4872 ((LockType & LOCKING_ANDX_CANCEL_LOCK)?
4873 "LOCKING_ANDX_CANCEL_LOCK":
4874 "LOCKING_ANDX_CHANGE_LOCKTYPE"));
4875 /* No need to call osi_LogSaveString since these are string
4878 code = CM_ERROR_BADOP;
4883 op = smb_GetSMBData(inp, NULL);
4885 for (i=0; i<NumberOfUnlocks; i++) {
4886 smb_GetLockParams(LockType, &op, &pid, &LOffset, &LLength);
4888 key = cm_GenerateKey(vcp->vcID, pid, fidp->fid);
4890 code = cm_Unlock(scp, LockType, LOffset, LLength, key, userp, &req);
4898 for (i=0; i<NumberOfLocks; i++) {
4899 smb_GetLockParams(LockType, &op, &pid, &LOffset, &LLength);
4901 key = cm_GenerateKey(vcp->vcID, pid, fidp->fid);
4903 code = cm_Lock(scp, LockType, LOffset, LLength, key, (Timeout != 0),
4904 userp, &req, &lockp);
4906 if (code == CM_ERROR_WOULDBLOCK && Timeout != 0) {
4907 smb_waitingLock_t * wLock;
4909 /* Put on waiting list */
4910 if(wlRequest == NULL) {
4914 LARGE_INTEGER tOffset, tLength;
4916 wlRequest = malloc(sizeof(smb_waitingLockRequest_t));
4918 osi_assert(wlRequest != NULL);
4920 wlRequest->vcp = vcp;
4922 wlRequest->scp = scp;
4924 wlRequest->inp = smb_CopyPacket(inp);
4925 wlRequest->outp = smb_CopyPacket(outp);
4926 wlRequest->lockType = LockType;
4927 wlRequest->timeRemaining = Timeout;
4928 wlRequest->locks = NULL;
4930 /* The waiting lock request needs to have enough
4931 information to undo all the locks in the request.
4932 We do the following to store info about locks that
4933 have already been granted. Sure, we can get most
4934 of the info from the packet, but the packet doesn't
4935 hold the result of cm_Lock call. In practice we
4936 only receive packets with one or two locks, so we
4937 are only wasting a few bytes here and there and
4938 only for a limited period of time until the waiting
4939 lock times out or is freed. */
4941 for(opt = op_locks, j=i; j > 0; j--) {
4942 smb_GetLockParams(LockType, &opt, &pid, &tOffset, &tLength);
4944 tkey = cm_GenerateKey(vcp->vcID, pid, fidp->fid);
4946 wLock = malloc(sizeof(smb_waitingLock_t));
4948 osi_assert(wLock != NULL);
4951 wLock->LOffset = tOffset;
4952 wLock->LLength = tLength;
4953 wLock->lockp = NULL;
4954 wLock->state = SMB_WAITINGLOCKSTATE_DONE;
4955 osi_QAdd((osi_queue_t **) &wlRequest->locks,
4960 wLock = malloc(sizeof(smb_waitingLock_t));
4962 osi_assert(wLock != NULL);
4965 wLock->LOffset = LOffset;
4966 wLock->LLength = LLength;
4967 wLock->lockp = lockp;
4968 wLock->state = SMB_WAITINGLOCKSTATE_WAITING;
4969 osi_QAdd((osi_queue_t **) &wlRequest->locks,
4972 osi_Log1(smb_logp, "smb_ReceiveV3Locking WaitingLock created 0x%x",
4980 osi_Log1(smb_logp, "smb_ReceiveV3Locking cm_Lock failure code 0x%x", code);
4987 /* Since something went wrong with the lock number i, we now
4988 have to go ahead and release any locks acquired before the
4989 failure. All locks before lock number i (of which there
4990 are i of them) have either been successful or are waiting.
4991 Either case requires calling cm_Unlock(). */
4993 /* And purge the waiting lock */
4994 if(wlRequest != NULL) {
4995 smb_waitingLock_t * wl;
4996 smb_waitingLock_t * wlNext;
4999 for(wl = wlRequest->locks; wl; wl = wlNext) {
5001 wlNext = (smb_waitingLock_t *) osi_QNext(&wl->q);
5003 ul_code = cm_Unlock(scp, LockType, wl->LOffset, wl->LLength, wl->key, userp, &req);
5006 osi_Log1(smb_logp, "smb_ReceiveV3Locking cm_Unlock returns code %d", ul_code);
5008 osi_Log0(smb_logp, "smb_ReceiveV3Locking cm_Unlock successful");
5011 osi_QRemove((osi_queue_t **) &wlRequest->locks, &wl->q);
5016 smb_ReleaseVC(wlRequest->vcp);
5017 cm_ReleaseSCache(wlRequest->scp);
5018 smb_FreePacket(wlRequest->inp);
5019 smb_FreePacket(wlRequest->outp);
5028 if (wlRequest != NULL) {
5030 lock_ObtainWrite(&smb_globalLock);
5031 osi_QAdd((osi_queue_t **)&smb_allWaitingLocks,
5033 osi_Wakeup((long) &smb_allWaitingLocks);
5034 lock_ReleaseWrite(&smb_globalLock);
5036 /* don't send reply immediately */
5037 outp->flags |= SMB_PACKETFLAG_NOSEND;
5040 smb_SetSMBDataLength(outp, 0);
5044 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_LOCK);
5047 lock_ReleaseMutex(&scp->mx);
5048 cm_ReleaseUser(userp);
5049 smb_ReleaseFID(fidp);
5054 long smb_ReceiveV3GetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5060 afs_uint32 searchTime;
5066 fid = smb_GetSMBParm(inp, 0);
5067 fid = smb_ChainFID(fid, inp);
5069 fidp = smb_FindFID(vcp, fid, 0);
5070 if (!fidp || (fidp->flags & SMB_FID_IOCTL)) {
5071 return CM_ERROR_BADFD;
5074 userp = smb_GetUser(vcp, inp);
5078 /* otherwise, stat the file */
5079 lock_ObtainMutex(&scp->mx);
5080 code = cm_SyncOp(scp, NULL, userp, &req, 0,
5081 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5082 if (code) goto done;
5084 /* decode times. We need a search time, but the response to this
5085 * call provides the date first, not the time, as returned in the
5086 * searchTime variable. So we take the high-order bits first.
5088 smb_SearchTimeFromUnixTime(&searchTime, scp->clientModTime);
5089 smb_SetSMBParm(outp, 0, (searchTime >> 16) & 0xffff); /* ctime */
5090 smb_SetSMBParm(outp, 1, searchTime & 0xffff);
5091 smb_SetSMBParm(outp, 2, (searchTime >> 16) & 0xffff); /* atime */
5092 smb_SetSMBParm(outp, 3, searchTime & 0xffff);
5093 smb_SetSMBParm(outp, 4, (searchTime >> 16) & 0xffff); /* mtime */
5094 smb_SetSMBParm(outp, 5, searchTime & 0xffff);
5096 /* now handle file size and allocation size */
5097 smb_SetSMBParm(outp, 6, scp->length.LowPart & 0xffff); /* file size */
5098 smb_SetSMBParm(outp, 7, (scp->length.LowPart >> 16) & 0xffff);
5099 smb_SetSMBParm(outp, 8, scp->length.LowPart & 0xffff); /* alloc size */
5100 smb_SetSMBParm(outp, 9, (scp->length.LowPart >> 16) & 0xffff);
5102 /* file attribute */
5103 smb_SetSMBParm(outp, 10, smb_Attributes(scp));
5105 /* and finalize stuff */
5106 smb_SetSMBDataLength(outp, 0);
5110 lock_ReleaseMutex(&scp->mx);
5111 cm_ReleaseUser(userp);
5112 smb_ReleaseFID(fidp);
5116 long smb_ReceiveV3SetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5122 afs_uint32 searchTime;
5130 fid = smb_GetSMBParm(inp, 0);
5131 fid = smb_ChainFID(fid, inp);
5133 fidp = smb_FindFID(vcp, fid, 0);
5134 if (!fidp || (fidp->flags & SMB_FID_IOCTL)) {
5135 return CM_ERROR_BADFD;
5138 userp = smb_GetUser(vcp, inp);
5142 /* now prepare to call cm_setattr. This message only sets various times,
5143 * and AFS only implements mtime, and we'll set the mtime if that's
5144 * requested. The others we'll ignore.
5146 searchTime = smb_GetSMBParm(inp, 5) | (smb_GetSMBParm(inp, 6) << 16);
5148 if (searchTime != 0) {
5149 smb_UnixTimeFromSearchTime(&unixTime, searchTime);
5151 if ( unixTime != -1 ) {
5152 attrs.mask = CM_ATTRMASK_CLIENTMODTIME;
5153 attrs.clientModTime = unixTime;
5154 code = cm_SetAttr(scp, &attrs, userp, &req);
5156 osi_Log1(smb_logp, "SMB receive V3SetAttributes [fid=%ld]", fid);
5158 osi_Log1(smb_logp, "**smb_UnixTimeFromSearchTime failed searchTime=%ld", searchTime);
5163 cm_ReleaseUser(userp);
5164 smb_ReleaseFID(fidp);
5169 long smb_ReceiveV3ReadX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5173 long finalCount = 0;
5182 fd = smb_GetSMBParm(inp, 2);
5183 count = smb_GetSMBParm(inp, 5);
5184 offset.HighPart = 0; /* too bad */
5185 offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
5187 osi_Log3(smb_logp, "smb_ReceiveV3Read fd %d, off 0x%x, size 0x%x",
5188 fd, offset.LowPart, count);
5190 fd = smb_ChainFID(fd, inp);
5191 fidp = smb_FindFID(vcp, fd, 0);
5193 return CM_ERROR_BADFD;
5196 pid = ((smb_t *) inp)->pid;
5197 key = cm_GenerateKey(vcp->vcID, pid, fd);
5199 LARGE_INTEGER LOffset, LLength;
5201 LOffset.HighPart = offset.HighPart;
5202 LOffset.LowPart = offset.LowPart;
5203 LLength.HighPart = 0;
5204 LLength.LowPart = count;
5206 lock_ObtainMutex(&fidp->scp->mx);
5207 code = cm_LockCheckRead(fidp->scp, LOffset, LLength, key);
5208 lock_ReleaseMutex(&fidp->scp->mx);
5212 smb_ReleaseFID(fidp);
5216 /* set inp->fid so that later read calls in same msg can find fid */
5219 if (fidp->flags & SMB_FID_IOCTL) {
5220 return smb_IoctlV3Read(fidp, vcp, inp, outp);
5223 userp = smb_GetUser(vcp, inp);
5225 /* 0 and 1 are reserved for request chaining, were setup by our caller,
5226 * and will be further filled in after we return.
5228 smb_SetSMBParm(outp, 2, 0); /* remaining bytes, for pipes */
5229 smb_SetSMBParm(outp, 3, 0); /* resvd */
5230 smb_SetSMBParm(outp, 4, 0); /* resvd */
5231 smb_SetSMBParm(outp, 5, count); /* # of bytes we're going to read */
5232 /* fill in #6 when we have all the parameters' space reserved */
5233 smb_SetSMBParm(outp, 7, 0); /* resv'd */
5234 smb_SetSMBParm(outp, 8, 0); /* resv'd */
5235 smb_SetSMBParm(outp, 9, 0); /* resv'd */
5236 smb_SetSMBParm(outp, 10, 0); /* resv'd */
5237 smb_SetSMBParm(outp, 11, 0); /* reserved */
5239 /* get op ptr after putting in the parms, since otherwise we don't
5240 * know where the data really is.
5242 op = smb_GetSMBData(outp, NULL);
5244 /* now fill in offset from start of SMB header to first data byte (to op) */
5245 smb_SetSMBParm(outp, 6, ((int) (op - outp->data)));
5247 /* set the packet data length the count of the # of bytes */
5248 smb_SetSMBDataLength(outp, count);
5251 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount);
5253 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount, FALSE);
5256 /* fix some things up */
5257 smb_SetSMBParm(outp, 5, finalCount);
5258 smb_SetSMBDataLength(outp, finalCount);
5260 smb_ReleaseFID(fidp);
5262 cm_ReleaseUser(userp);
5267 * Values for createDisp, copied from NTDDK.H
5269 #define FILE_SUPERSEDE 0 // (???)
5270 #define FILE_OPEN 1 // (open)
5271 #define FILE_CREATE 2 // (exclusive)
5272 #define FILE_OPEN_IF 3 // (non-exclusive)
5273 #define FILE_OVERWRITE 4 // (open & truncate, but do not create)
5274 #define FILE_OVERWRITE_IF 5 // (open & truncate, or create)
5277 #define REQUEST_OPLOCK 2
5278 #define REQUEST_BATCH_OPLOCK 4
5279 #define OPEN_DIRECTORY 8
5280 #define EXTENDED_RESPONSE_REQUIRED 0x10
5282 /* CreateOptions field. */
5283 #define FILE_DIRECTORY_FILE 0x0001
5284 #define FILE_WRITE_THROUGH 0x0002
5285 #define FILE_SEQUENTIAL_ONLY 0x0004
5286 #define FILE_NON_DIRECTORY_FILE 0x0040
5287 #define FILE_NO_EA_KNOWLEDGE 0x0200
5288 #define FILE_EIGHT_DOT_THREE_ONLY 0x0400
5289 #define FILE_RANDOM_ACCESS 0x0800
5290 #define FILE_DELETE_ON_CLOSE 0x1000
5291 #define FILE_OPEN_BY_FILE_ID 0x2000
5293 long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5295 char *pathp, *realPathp;
5299 cm_scache_t *dscp; /* parent dir */
5300 cm_scache_t *scp; /* file to create or open */
5301 cm_scache_t *targetScp; /* if scp is a symlink */
5305 unsigned short nameLength;
5307 unsigned int requestOpLock;
5308 unsigned int requestBatchOpLock;
5309 unsigned int mustBeDir;
5310 unsigned int extendedRespRequired;
5311 unsigned int treeCreate;
5313 unsigned int desiredAccess;
5314 unsigned int extAttributes;
5315 unsigned int createDisp;
5316 unsigned int createOptions;
5317 unsigned int shareAccess;
5318 int initialModeBits;
5319 unsigned short baseFid;
5320 smb_fid_t *baseFidp;
5322 cm_scache_t *baseDirp;
5323 unsigned short openAction;
5334 /* This code is very long and has a lot of if-then-else clauses
5335 * scp and dscp get reused frequently and we need to ensure that
5336 * we don't lose a reference. Start by ensuring that they are NULL.
5343 nameLength = smb_GetSMBOffsetParm(inp, 2, 1);
5344 flags = smb_GetSMBOffsetParm(inp, 3, 1)
5345 | (smb_GetSMBOffsetParm(inp, 4, 1) << 16);
5346 requestOpLock = flags & REQUEST_OPLOCK;
5347 requestBatchOpLock = flags & REQUEST_BATCH_OPLOCK;
5348 mustBeDir = flags & OPEN_DIRECTORY;
5349 extendedRespRequired = flags & EXTENDED_RESPONSE_REQUIRED;
5352 * Why all of a sudden 32-bit FID?
5353 * We will reject all bits higher than 16.
5355 if (smb_GetSMBOffsetParm(inp, 6, 1) != 0)
5356 return CM_ERROR_INVAL;
5357 baseFid = smb_GetSMBOffsetParm(inp, 5, 1);
5358 desiredAccess = smb_GetSMBOffsetParm(inp, 7, 1)
5359 | (smb_GetSMBOffsetParm(inp, 8, 1) << 16);
5360 extAttributes = smb_GetSMBOffsetParm(inp, 13, 1)
5361 | (smb_GetSMBOffsetParm(inp, 14, 1) << 16);
5362 shareAccess = smb_GetSMBOffsetParm(inp, 15, 1)
5363 | (smb_GetSMBOffsetParm(inp, 16, 1) << 16);
5364 createDisp = smb_GetSMBOffsetParm(inp, 17, 1)
5365 | (smb_GetSMBOffsetParm(inp, 18, 1) << 16);
5366 createOptions = smb_GetSMBOffsetParm(inp, 19, 1)
5367 | (smb_GetSMBOffsetParm(inp, 20, 1) << 16);
5369 /* mustBeDir is never set; createOptions directory bit seems to be
5372 if (createOptions & FILE_DIRECTORY_FILE)
5374 else if (createOptions & FILE_NON_DIRECTORY_FILE)
5380 * compute initial mode bits based on read-only flag in
5381 * extended attributes
5383 initialModeBits = 0666;
5384 if (extAttributes & SMB_ATTR_READONLY)
5385 initialModeBits &= ~0222;
5387 pathp = smb_GetSMBData(inp, NULL);
5388 /* Sometimes path is not null-terminated, so we make a copy. */
5389 realPathp = malloc(nameLength+1);
5390 memcpy(realPathp, pathp, nameLength);
5391 realPathp[nameLength] = 0;
5392 if (smb_StoreAnsiFilenames)
5393 OemToChar(realPathp,realPathp);
5395 spacep = inp->spacep;
5396 smb_StripLastComponent(spacep->data, &lastNamep, realPathp);
5398 osi_Log1(smb_logp,"NTCreateX for [%s]",osi_LogSaveString(smb_logp,realPathp));
5399 osi_Log4(smb_logp,"... da=[%x] ea=[%x] cd=[%x] co=[%x]", desiredAccess, extAttributes, createDisp, createOptions);
5400 osi_Log3(smb_logp,"... share=[%x] flags=[%x] lastNamep=[%s]", shareAccess, flags, osi_LogSaveString(smb_logp,(lastNamep?lastNamep:"null")));
5402 if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
5403 /* special case magic file name for receiving IOCTL requests
5404 * (since IOCTL calls themselves aren't getting through).
5406 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
5407 smb_SetupIoctlFid(fidp, spacep);
5408 osi_Log1(smb_logp,"NTCreateX Setting up IOCTL on fid[%d]",fidp->fid);
5410 /* set inp->fid so that later read calls in same msg can find fid */
5411 inp->fid = fidp->fid;
5415 smb_SetSMBParmByte(outp, parmSlot, 0); /* oplock */
5416 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
5417 smb_SetSMBParmLong(outp, parmSlot, 1); parmSlot += 2; /* Action */
5419 memset(&ft, 0, sizeof(ft));
5420 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
5421 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
5422 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
5423 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
5424 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2; /* attr */
5425 sz.HighPart = 0x7fff; sz.LowPart = 0;
5426 smb_SetSMBParmDouble(outp, parmSlot, (char *)&sz); parmSlot += 4; /* alen */
5427 smb_SetSMBParmDouble(outp, parmSlot, (char *)&sz); parmSlot += 4; /* len */
5428 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* filetype */
5429 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* dev state */
5430 smb_SetSMBParmByte(outp, parmSlot, 0); /* is a dir? */
5431 smb_SetSMBDataLength(outp, 0);
5433 /* clean up fid reference */
5434 smb_ReleaseFID(fidp);
5439 #ifdef DEBUG_VERBOSE
5441 char *hexp, *asciip;
5442 asciip = (lastNamep? lastNamep : realPathp);
5443 hexp = osi_HexifyString( asciip );
5444 DEBUG_EVENT2("AFS", "NTCreateX H[%s] A[%s]", hexp, asciip);
5449 userp = smb_GetUser(vcp, inp);
5451 osi_Log1(smb_logp, "NTCreateX Invalid user [%d]", ((smb_t *) inp)->uid);
5453 return CM_ERROR_INVAL;
5457 baseDirp = cm_data.rootSCachep;
5458 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5459 if (code == CM_ERROR_TIDIPC) {
5460 /* Attempt to use a TID allocated for IPC. The client
5461 * is probably looking for DCE RPC end points which we
5462 * don't support OR it could be looking to make a DFS
5465 osi_Log0(smb_logp, "NTCreateX received IPC TID");
5468 cm_ReleaseUser(userp);
5469 return CM_ERROR_NOSUCHFILE;
5470 #endif /* DFS_SUPPORT */
5473 baseFidp = smb_FindFID(vcp, baseFid, 0);
5475 osi_Log1(smb_logp, "NTCreateX Invalid base fid [%d]", baseFid);
5477 cm_ReleaseUser(userp);
5478 return CM_ERROR_INVAL;
5480 baseDirp = baseFidp->scp;
5484 osi_Log1(smb_logp, "NTCreateX tidPathp=[%s]", (tidPathp==NULL)?"null": osi_LogSaveString(smb_logp,tidPathp));
5486 /* compute open mode */
5488 if (desiredAccess & DELETE)
5489 fidflags |= SMB_FID_OPENDELETE;
5490 if (desiredAccess & AFS_ACCESS_READ)
5491 fidflags |= SMB_FID_OPENREAD;
5492 if (desiredAccess & AFS_ACCESS_WRITE)
5493 fidflags |= SMB_FID_OPENWRITE;
5494 if (createOptions & FILE_DELETE_ON_CLOSE)
5495 fidflags |= SMB_FID_DELONCLOSE;
5497 /* and the share mode */
5498 if (shareAccess & FILE_SHARE_READ)
5499 fidflags |= SMB_FID_SHARE_READ;
5500 if (shareAccess & FILE_SHARE_WRITE)
5501 fidflags |= SMB_FID_SHARE_WRITE;
5505 /* For an exclusive create, we want to do a case sensitive match for the last component. */
5506 if ( createDisp == FILE_CREATE ||
5507 createDisp == FILE_OVERWRITE ||
5508 createDisp == FILE_OVERWRITE_IF) {
5509 code = cm_NameI(baseDirp, spacep->data, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
5510 userp, tidPathp, &req, &dscp);
5513 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
5514 cm_ReleaseSCache(dscp);
5515 cm_ReleaseUser(userp);
5517 if ( WANTS_DFS_PATHNAMES(inp) )
5518 return CM_ERROR_PATH_NOT_COVERED;
5520 return CM_ERROR_BADSHARENAME;
5522 #endif /* DFS_SUPPORT */
5523 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp, CM_FLAG_FOLLOW,
5525 if (code == CM_ERROR_NOSUCHFILE) {
5526 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp,
5527 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, &req, &scp);
5528 if (code == 0 && realDirFlag == 1) {
5529 cm_ReleaseSCache(scp);
5530 cm_ReleaseSCache(dscp);
5531 cm_ReleaseUser(userp);
5533 return CM_ERROR_EXISTS;
5537 /* we have both scp and dscp */
5539 code = cm_NameI(baseDirp, realPathp, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
5540 userp, tidPathp, &req, &scp);
5542 if (code == 0 && scp->fileType == CM_SCACHETYPE_DFSLINK) {
5543 cm_ReleaseSCache(scp);
5544 cm_ReleaseUser(userp);
5546 if ( WANTS_DFS_PATHNAMES(inp) )
5547 return CM_ERROR_PATH_NOT_COVERED;
5549 return CM_ERROR_BADSHARENAME;
5551 #endif /* DFS_SUPPORT */
5552 /* we might have scp but not dscp */
5558 if (!foundscp || (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE))) {
5559 /* look up parent directory */
5560 /* If we are trying to create a path (i.e. multiple nested directories), then we don't *need*
5561 * the immediate parent. We have to work our way up realPathp until we hit something that we
5565 /* we might or might not have scp */
5571 code = cm_NameI(baseDirp, spacep->data,
5572 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
5573 userp, tidPathp, &req, &dscp);
5576 if (code == 0 && dscp->fileType == CM_SCACHETYPE_DFSLINK) {
5578 cm_ReleaseSCache(scp);
5579 cm_ReleaseSCache(dscp);
5580 cm_ReleaseUser(userp);
5582 if ( WANTS_DFS_PATHNAMES(inp) )
5583 return CM_ERROR_PATH_NOT_COVERED;
5585 return CM_ERROR_BADSHARENAME;
5587 #endif /* DFS_SUPPORT */
5590 (tp = strrchr(spacep->data,'\\')) &&
5591 (createDisp == FILE_CREATE) &&
5592 (realDirFlag == 1)) {
5595 treeStartp = realPathp + (tp - spacep->data);
5597 if (*tp && !smb_IsLegalFilename(tp)) {
5599 smb_ReleaseFID(baseFidp);
5600 cm_ReleaseUser(userp);
5603 cm_ReleaseSCache(scp);
5604 return CM_ERROR_BADNTFILENAME;
5608 } while (dscp == NULL && code == 0);
5612 /* we might have scp and we might have dscp */
5615 smb_ReleaseFID(baseFidp);
5618 osi_Log0(smb_logp,"NTCreateX parent not found");
5620 cm_ReleaseSCache(scp);
5622 cm_ReleaseSCache(dscp);
5623 cm_ReleaseUser(userp);
5628 if (treeCreate && dscp->fileType == CM_SCACHETYPE_FILE) {
5629 /* A file exists where we want a directory. */
5631 cm_ReleaseSCache(scp);
5632 cm_ReleaseSCache(dscp);
5633 cm_ReleaseUser(userp);
5635 return CM_ERROR_EXISTS;
5639 lastNamep = realPathp;
5643 if (!smb_IsLegalFilename(lastNamep)) {
5645 cm_ReleaseSCache(scp);
5647 cm_ReleaseSCache(dscp);
5648 cm_ReleaseUser(userp);
5650 return CM_ERROR_BADNTFILENAME;
5653 if (!foundscp && !treeCreate) {
5654 if ( createDisp == FILE_CREATE ||
5655 createDisp == FILE_OVERWRITE ||
5656 createDisp == FILE_OVERWRITE_IF)
5658 code = cm_Lookup(dscp, lastNamep,
5659 CM_FLAG_FOLLOW, userp, &req, &scp);
5661 code = cm_Lookup(dscp, lastNamep,
5662 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
5665 if (code && code != CM_ERROR_NOSUCHFILE) {
5667 cm_ReleaseSCache(dscp);
5668 cm_ReleaseUser(userp);
5673 /* we have scp and dscp */
5675 /* we have scp but not dscp */
5677 smb_ReleaseFID(baseFidp);
5680 /* if we get here, if code is 0, the file exists and is represented by
5681 * scp. Otherwise, we have to create it. The dir may be represented
5682 * by dscp, or we may have found the file directly. If code is non-zero,
5685 if (code == 0 && !treeCreate) {
5686 if (createDisp == FILE_CREATE) {
5687 /* oops, file shouldn't be there */
5689 cm_ReleaseSCache(dscp);
5691 cm_ReleaseSCache(scp);
5692 cm_ReleaseUser(userp);
5694 return CM_ERROR_EXISTS;
5697 if ( createDisp == FILE_OVERWRITE ||
5698 createDisp == FILE_OVERWRITE_IF) {
5700 setAttr.mask = CM_ATTRMASK_LENGTH;
5701 setAttr.length.LowPart = 0;
5702 setAttr.length.HighPart = 0;
5703 /* now watch for a symlink */
5705 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
5707 osi_assert(dscp != NULL);
5708 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
5710 /* we have a more accurate file to use (the
5711 * target of the symbolic link). Otherwise,
5712 * we'll just use the symlink anyway.
5714 osi_Log2(smb_logp, "symlink vp %x to vp %x",
5716 cm_ReleaseSCache(scp);
5720 code = cm_SetAttr(scp, &setAttr, userp, &req);
5721 openAction = 3; /* truncated existing file */
5724 openAction = 1; /* found existing file */
5726 code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp, &req);
5729 cm_ReleaseSCache(dscp);
5731 cm_ReleaseSCache(scp);
5732 cm_ReleaseUser(userp);
5736 } else if (createDisp == FILE_OPEN || createDisp == FILE_OVERWRITE) {
5737 /* don't create if not found */
5739 cm_ReleaseSCache(dscp);
5741 cm_ReleaseSCache(scp);
5742 cm_ReleaseUser(userp);
5744 return CM_ERROR_NOSUCHFILE;
5745 } else if (realDirFlag == 0 || realDirFlag == -1) {
5746 osi_assert(dscp != NULL);
5747 osi_Log1(smb_logp, "smb_ReceiveNTCreateX creating file %s",
5748 osi_LogSaveString(smb_logp, lastNamep));
5749 openAction = 2; /* created file */
5750 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
5751 setAttr.clientModTime = time(NULL);
5752 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp, &req);
5753 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
5754 smb_NotifyChange(FILE_ACTION_ADDED,
5755 FILE_NOTIFY_CHANGE_FILE_NAME,
5756 dscp, lastNamep, NULL, TRUE);
5757 if (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE) {
5758 /* Not an exclusive create, and someone else tried
5759 * creating it already, then we open it anyway. We
5760 * don't bother retrying after this, since if this next
5761 * fails, that means that the file was deleted after we
5762 * started this call.
5764 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
5767 if (createDisp == FILE_OVERWRITE_IF) {
5768 setAttr.mask = CM_ATTRMASK_LENGTH;
5769 setAttr.length.LowPart = 0;
5770 setAttr.length.HighPart = 0;
5772 /* now watch for a symlink */
5774 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
5776 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
5778 /* we have a more accurate file to use (the
5779 * target of the symbolic link). Otherwise,
5780 * we'll just use the symlink anyway.
5782 osi_Log2(smb_logp, "symlink vp %x to vp %x",
5784 cm_ReleaseSCache(scp);
5788 code = cm_SetAttr(scp, &setAttr, userp, &req);
5790 } /* lookup succeeded */
5794 char *cp; /* This component */
5795 int clen = 0; /* length of component */
5796 cm_scache_t *tscp1, *tscp2;
5799 /* create directory */
5801 treeStartp = lastNamep;
5802 osi_assert(dscp != NULL);
5803 osi_Log1(smb_logp, "smb_ReceiveNTCreateX creating directory [%s]",
5804 osi_LogSaveString(smb_logp, treeStartp));
5805 openAction = 2; /* created directory */
5807 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
5808 setAttr.clientModTime = time(NULL);
5813 cm_HoldSCache(tscp1);
5817 tp = strchr(pp, '\\');
5821 isLast = 1; /* indicate last component. the supplied path never ends in a slash */
5824 strncpy(cp,pp,clen);
5831 continue; /* the supplied path can't have consecutive slashes either , but */
5833 /* cp is the next component to be created. */
5834 code = cm_MakeDir(tscp1, cp, 0, &setAttr, userp, &req);
5835 if (code == 0 && (tscp1->flags & CM_SCACHEFLAG_ANYWATCH))
5836 smb_NotifyChange(FILE_ACTION_ADDED,
5837 FILE_NOTIFY_CHANGE_DIR_NAME,
5838 tscp1, cp, NULL, TRUE);
5840 (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE)) {
5841 /* Not an exclusive create, and someone else tried
5842 * creating it already, then we open it anyway. We
5843 * don't bother retrying after this, since if this next
5844 * fails, that means that the file was deleted after we
5845 * started this call.
5847 code = cm_Lookup(tscp1, cp, CM_FLAG_CASEFOLD,
5848 userp, &req, &tscp2);
5853 if (!isLast) { /* for anything other than dscp, release it unless it's the last one */
5854 cm_ReleaseSCache(tscp1);
5855 tscp1 = tscp2; /* Newly created directory will be next parent */
5856 /* the hold is transfered to tscp1 from tscp2 */
5861 cm_ReleaseSCache(dscp);
5864 cm_ReleaseSCache(scp);
5867 * if we get here and code == 0, then scp is the last directory created, and dscp is the
5873 /* something went wrong creating or truncating the file */
5875 cm_ReleaseSCache(scp);
5877 cm_ReleaseSCache(dscp);
5878 cm_ReleaseUser(userp);
5883 /* make sure we have file vs. dir right (only applies for single component case) */
5884 if (realDirFlag == 0 && scp->fileType != CM_SCACHETYPE_FILE) {
5885 /* now watch for a symlink */
5887 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
5888 cm_scache_t * targetScp = 0;
5889 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
5891 /* we have a more accurate file to use (the
5892 * target of the symbolic link). Otherwise,
5893 * we'll just use the symlink anyway.
5895 osi_Log2(smb_logp, "symlink vp %x to vp %x", scp, targetScp);
5896 cm_ReleaseSCache(scp);
5901 if (scp->fileType != CM_SCACHETYPE_FILE) {
5903 cm_ReleaseSCache(dscp);
5904 cm_ReleaseSCache(scp);
5905 cm_ReleaseUser(userp);
5907 return CM_ERROR_ISDIR;
5911 /* (only applies to single component case) */
5912 if (realDirFlag == 1 && scp->fileType == CM_SCACHETYPE_FILE) {
5913 cm_ReleaseSCache(scp);
5915 cm_ReleaseSCache(dscp);
5916 cm_ReleaseUser(userp);
5918 return CM_ERROR_NOTDIR;
5921 /* open the file itself */
5922 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
5925 /* If we are restricting sharing, we should do so with a suitable
5927 if (scp->fileType == CM_SCACHETYPE_FILE &&
5928 !(fidflags & SMB_FID_SHARE_WRITE)) {
5930 LARGE_INTEGER LOffset, LLength;
5933 LOffset.HighPart = SMB_FID_QLOCK_HIGH;
5934 LOffset.LowPart = SMB_FID_QLOCK_LOW;
5935 LLength.HighPart = 0;
5936 LLength.LowPart = SMB_FID_QLOCK_LENGTH;
5938 if (fidflags & SMB_FID_SHARE_READ) {
5939 sLockType = LOCKING_ANDX_SHARED_LOCK;
5944 key = cm_GenerateKey(vcp->vcID, SMB_FID_QLOCK_PID, fidp->fid);
5946 lock_ObtainMutex(&scp->mx);
5947 code = cm_Lock(scp, sLockType, LOffset, LLength, key, 0, userp, &req, NULL);
5948 lock_ReleaseMutex(&scp->mx);
5951 fidp->flags = SMB_FID_DELETE;
5952 smb_ReleaseFID(fidp);
5954 cm_ReleaseSCache(scp);
5956 cm_ReleaseSCache(dscp);
5957 cm_ReleaseUser(userp);
5964 /* save a pointer to the vnode */
5965 fidp->scp = scp; /* Hold transfered to fidp->scp and no longer needed */
5967 fidp->flags = fidflags;
5969 /* save parent dir and pathname for delete or change notification */
5970 if (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE)) {
5971 fidp->flags |= SMB_FID_NTOPEN;
5972 fidp->NTopen_dscp = dscp;
5973 cm_HoldSCache(dscp);
5974 fidp->NTopen_pathp = strdup(lastNamep);
5976 fidp->NTopen_wholepathp = realPathp;
5978 /* we don't need this any longer */
5980 cm_ReleaseSCache(dscp);
5984 cm_Open(scp, 0, userp);
5986 /* set inp->fid so that later read calls in same msg can find fid */
5987 inp->fid = fidp->fid;
5991 lock_ObtainMutex(&scp->mx);
5992 smb_SetSMBParmByte(outp, parmSlot, 0); /* oplock */
5993 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
5994 smb_SetSMBParmLong(outp, parmSlot, openAction); parmSlot += 2;
5995 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
5996 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
5997 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
5998 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
5999 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
6000 smb_SetSMBParmLong(outp, parmSlot, smb_ExtAttributes(scp));
6002 smb_SetSMBParmDouble(outp, parmSlot, (char *)&scp->length); parmSlot += 4;
6003 smb_SetSMBParmDouble(outp, parmSlot, (char *)&scp->length); parmSlot += 4;
6004 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* filetype */
6005 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* dev state */
6006 smb_SetSMBParmByte(outp, parmSlot,
6007 scp->fileType == CM_SCACHETYPE_DIRECTORY); /* is a dir? */
6008 lock_ReleaseMutex(&scp->mx);
6009 smb_SetSMBDataLength(outp, 0);
6011 osi_Log2(smb_logp, "SMB NT CreateX opening fid %d path %s", fidp->fid,
6012 osi_LogSaveString(smb_logp, realPathp));
6014 smb_ReleaseFID(fidp);
6016 cm_ReleaseUser(userp);
6018 /* Can't free realPathp if we get here since
6019 fidp->NTopen_wholepathp is pointing there */
6021 /* leave scp held since we put it in fidp->scp */
6026 * A lot of stuff copied verbatim from NT Create&X to NT Tran Create.
6027 * Instead, ultimately, would like to use a subroutine for common code.
6029 long smb_ReceiveNTTranCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6031 char *pathp, *realPathp;
6035 cm_scache_t *dscp; /* parent dir */
6036 cm_scache_t *scp; /* file to create or open */
6037 cm_scache_t *targetScp; /* if scp is a symlink */
6040 unsigned long nameLength;
6042 unsigned int requestOpLock;
6043 unsigned int requestBatchOpLock;
6044 unsigned int mustBeDir;
6045 unsigned int extendedRespRequired;
6047 unsigned int desiredAccess;
6048 #ifdef DEBUG_VERBOSE
6049 unsigned int allocSize;
6051 unsigned int shareAccess;
6052 unsigned int extAttributes;
6053 unsigned int createDisp;
6054 #ifdef DEBUG_VERBOSE
6057 unsigned int createOptions;
6058 int initialModeBits;
6059 unsigned short baseFid;
6060 smb_fid_t *baseFidp;
6062 cm_scache_t *baseDirp;
6063 unsigned short openAction;
6069 int parmOffset, dataOffset;
6080 parmOffset = smb_GetSMBOffsetParm(inp, 11, 1)
6081 | (smb_GetSMBOffsetParm(inp, 12, 1) << 16);
6082 parmp = inp->data + parmOffset;
6083 lparmp = (ULONG *) parmp;
6086 requestOpLock = flags & REQUEST_OPLOCK;
6087 requestBatchOpLock = flags & REQUEST_BATCH_OPLOCK;
6088 mustBeDir = flags & OPEN_DIRECTORY;
6089 extendedRespRequired = flags & EXTENDED_RESPONSE_REQUIRED;
6092 * Why all of a sudden 32-bit FID?
6093 * We will reject all bits higher than 16.
6095 if (lparmp[1] & 0xFFFF0000)
6096 return CM_ERROR_INVAL;
6097 baseFid = (unsigned short)lparmp[1];
6098 desiredAccess = lparmp[2];
6099 #ifdef DEBUG_VERBOSE
6100 allocSize = lparmp[3];
6101 #endif /* DEBUG_VERSOSE */
6102 extAttributes = lparmp[5];
6103 shareAccess = lparmp[6];
6104 createDisp = lparmp[7];
6105 createOptions = lparmp[8];
6106 #ifdef DEBUG_VERBOSE
6109 nameLength = lparmp[11];
6111 #ifdef DEBUG_VERBOSE
6112 osi_Log4(smb_logp,"NTTranCreate with da[%x],ea[%x],sa[%x],cd[%x]",desiredAccess,extAttributes,shareAccess,createDisp);
6113 osi_Log3(smb_logp,"... co[%x],sdl[%x],as[%x]",createOptions,sdLen,allocSize);
6114 osi_Log1(smb_logp,"... flags[%x]",flags);
6117 /* mustBeDir is never set; createOptions directory bit seems to be
6120 if (createOptions & FILE_DIRECTORY_FILE)
6122 else if (createOptions & FILE_NON_DIRECTORY_FILE)
6128 * compute initial mode bits based on read-only flag in
6129 * extended attributes
6131 initialModeBits = 0666;
6132 if (extAttributes & 1)
6133 initialModeBits &= ~0222;
6135 pathp = parmp + (13 * sizeof(ULONG)) + sizeof(UCHAR);
6136 /* Sometimes path is not null-terminated, so we make a copy. */
6137 realPathp = malloc(nameLength+1);
6138 memcpy(realPathp, pathp, nameLength);
6139 realPathp[nameLength] = 0;
6140 if (smb_StoreAnsiFilenames)
6141 OemToChar(realPathp,realPathp);
6143 spacep = cm_GetSpace();
6144 smb_StripLastComponent(spacep->data, &lastNamep, realPathp);
6147 * Nothing here to handle SMB_IOCTL_FILENAME.
6148 * Will add it if necessary.
6151 #ifdef DEBUG_VERBOSE
6153 char *hexp, *asciip;
6154 asciip = (lastNamep? lastNamep : realPathp);
6155 hexp = osi_HexifyString( asciip );
6156 DEBUG_EVENT2("AFS", "NTTranCreate H[%s] A[%s]", hexp, asciip);
6161 userp = smb_GetUser(vcp, inp);
6163 osi_Log1(smb_logp, "NTTranCreate invalid user [%d]", ((smb_t *) inp)->uid);
6165 return CM_ERROR_INVAL;
6169 baseDirp = cm_data.rootSCachep;
6170 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
6171 if (code == CM_ERROR_TIDIPC) {
6172 /* Attempt to use a TID allocated for IPC. The client
6173 * is probably looking for DCE RPC end points which we
6174 * don't support OR it could be looking to make a DFS
6177 osi_Log0(smb_logp, "NTTranCreate received IPC TID");
6180 cm_ReleaseUser(userp);
6181 return CM_ERROR_NOSUCHPATH;
6185 baseFidp = smb_FindFID(vcp, baseFid, 0);
6187 osi_Log1(smb_logp, "NTTranCreate Invalid fid [%d]", baseFid);
6189 cm_ReleaseUser(userp);
6190 return CM_ERROR_INVAL;
6192 baseDirp = baseFidp->scp;
6196 /* compute open mode */
6198 if (desiredAccess & DELETE)
6199 fidflags |= SMB_FID_OPENDELETE;
6200 if (desiredAccess & AFS_ACCESS_READ)
6201 fidflags |= SMB_FID_OPENREAD;
6202 if (desiredAccess & AFS_ACCESS_WRITE)
6203 fidflags |= SMB_FID_OPENWRITE;
6204 if (createOptions & FILE_DELETE_ON_CLOSE)
6205 fidflags |= SMB_FID_DELONCLOSE;
6207 /* And the share mode */
6208 if (shareAccess & FILE_SHARE_READ)
6209 fidflags |= SMB_FID_SHARE_READ;
6210 if (shareAccess & FILE_SHARE_WRITE)
6211 fidflags |= SMB_FID_SHARE_WRITE;
6215 if ( createDisp == FILE_OPEN ||
6216 createDisp == FILE_OVERWRITE ||
6217 createDisp == FILE_OVERWRITE_IF) {
6218 code = cm_NameI(baseDirp, spacep->data, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
6219 userp, tidPathp, &req, &dscp);
6222 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
6223 cm_ReleaseSCache(dscp);
6224 cm_ReleaseUser(userp);
6226 if ( WANTS_DFS_PATHNAMES(inp) )
6227 return CM_ERROR_PATH_NOT_COVERED;
6229 return CM_ERROR_BADSHARENAME;
6231 #endif /* DFS_SUPPORT */
6232 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp, CM_FLAG_FOLLOW,
6234 if (code == CM_ERROR_NOSUCHFILE) {
6235 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp,
6236 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, &req, &scp);
6237 if (code == 0 && realDirFlag == 1) {
6238 cm_ReleaseSCache(scp);
6239 cm_ReleaseSCache(dscp);
6240 cm_ReleaseUser(userp);
6242 return CM_ERROR_EXISTS;
6248 code = cm_NameI(baseDirp, realPathp, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
6249 userp, tidPathp, &req, &scp);
6251 if (code == 0 && scp->fileType == CM_SCACHETYPE_DFSLINK) {
6252 cm_ReleaseSCache(scp);
6253 cm_ReleaseUser(userp);
6255 if ( WANTS_DFS_PATHNAMES(inp) )
6256 return CM_ERROR_PATH_NOT_COVERED;
6258 return CM_ERROR_BADSHARENAME;
6260 #endif /* DFS_SUPPORT */
6266 if (code != 0 || (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE))) {
6267 /* look up parent directory */
6269 code = cm_NameI(baseDirp, spacep->data,
6270 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
6271 userp, tidPathp, &req, &dscp);
6273 if (code == 0 && dscp->fileType == CM_SCACHETYPE_DFSLINK) {
6274 cm_ReleaseSCache(dscp);
6275 cm_ReleaseUser(userp);
6277 if ( WANTS_DFS_PATHNAMES(inp) )
6278 return CM_ERROR_PATH_NOT_COVERED;
6280 return CM_ERROR_BADSHARENAME;
6282 #endif /* DFS_SUPPORT */
6286 cm_FreeSpace(spacep);
6289 smb_ReleaseFID(baseFidp);
6294 cm_ReleaseUser(userp);
6299 if (!lastNamep) lastNamep = realPathp;
6302 if (!smb_IsLegalFilename(lastNamep))
6303 return CM_ERROR_BADNTFILENAME;
6306 if (createDisp == FILE_CREATE || createDisp == FILE_OVERWRITE_IF) {
6307 code = cm_Lookup(dscp, lastNamep,
6308 CM_FLAG_FOLLOW, userp, &req, &scp);
6310 code = cm_Lookup(dscp, lastNamep,
6311 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
6314 if (code && code != CM_ERROR_NOSUCHFILE) {
6315 cm_ReleaseSCache(dscp);
6316 cm_ReleaseUser(userp);
6323 smb_ReleaseFID(baseFidp);
6326 cm_FreeSpace(spacep);
6329 /* if we get here, if code is 0, the file exists and is represented by
6330 * scp. Otherwise, we have to create it. The dir may be represented
6331 * by dscp, or we may have found the file directly. If code is non-zero,
6335 code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp,
6339 cm_ReleaseSCache(dscp);
6340 cm_ReleaseSCache(scp);
6341 cm_ReleaseUser(userp);
6346 if (createDisp == FILE_CREATE) {
6347 /* oops, file shouldn't be there */
6349 cm_ReleaseSCache(dscp);
6350 cm_ReleaseSCache(scp);
6351 cm_ReleaseUser(userp);
6353 return CM_ERROR_EXISTS;
6356 if (createDisp == FILE_OVERWRITE ||
6357 createDisp == FILE_OVERWRITE_IF) {
6358 setAttr.mask = CM_ATTRMASK_LENGTH;
6359 setAttr.length.LowPart = 0;
6360 setAttr.length.HighPart = 0;
6362 /* now watch for a symlink */
6364 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
6366 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
6368 /* we have a more accurate file to use (the
6369 * target of the symbolic link). Otherwise,
6370 * we'll just use the symlink anyway.
6372 osi_Log2(smb_logp, "symlink vp %x to vp %x",
6374 cm_ReleaseSCache(scp);
6378 code = cm_SetAttr(scp, &setAttr, userp, &req);
6379 openAction = 3; /* truncated existing file */
6381 else openAction = 1; /* found existing file */
6383 else if (createDisp == FILE_OPEN || createDisp == FILE_OVERWRITE) {
6384 /* don't create if not found */
6386 cm_ReleaseSCache(dscp);
6387 cm_ReleaseUser(userp);
6389 return CM_ERROR_NOSUCHFILE;
6391 else if (realDirFlag == 0 || realDirFlag == -1) {
6392 osi_assert(dscp != NULL);
6393 osi_Log1(smb_logp, "smb_ReceiveNTTranCreate creating file %s",
6394 osi_LogSaveString(smb_logp, lastNamep));
6395 openAction = 2; /* created file */
6396 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
6397 setAttr.clientModTime = time(NULL);
6398 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
6400 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
6401 smb_NotifyChange(FILE_ACTION_ADDED,
6402 FILE_NOTIFY_CHANGE_FILE_NAME,
6403 dscp, lastNamep, NULL, TRUE);
6404 if (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE) {
6405 /* Not an exclusive create, and someone else tried
6406 * creating it already, then we open it anyway. We
6407 * don't bother retrying after this, since if this next
6408 * fails, that means that the file was deleted after we
6409 * started this call.
6411 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
6414 if (createDisp == FILE_OVERWRITE_IF) {
6415 setAttr.mask = CM_ATTRMASK_LENGTH;
6416 setAttr.length.LowPart = 0;
6417 setAttr.length.HighPart = 0;
6419 /* now watch for a symlink */
6421 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
6423 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
6425 /* we have a more accurate file to use (the
6426 * target of the symbolic link). Otherwise,
6427 * we'll just use the symlink anyway.
6429 osi_Log2(smb_logp, "symlink vp %x to vp %x",
6431 cm_ReleaseSCache(scp);
6435 code = cm_SetAttr(scp, &setAttr, userp, &req);
6437 } /* lookup succeeded */
6440 /* create directory */
6441 osi_assert(dscp != NULL);
6443 "smb_ReceiveNTTranCreate creating directory %s",
6444 osi_LogSaveString(smb_logp, lastNamep));
6445 openAction = 2; /* created directory */
6446 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
6447 setAttr.clientModTime = time(NULL);
6448 code = cm_MakeDir(dscp, lastNamep, 0, &setAttr, userp, &req);
6449 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
6450 smb_NotifyChange(FILE_ACTION_ADDED,
6451 FILE_NOTIFY_CHANGE_DIR_NAME,
6452 dscp, lastNamep, NULL, TRUE);
6454 (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE)) {
6455 /* Not an exclusive create, and someone else tried
6456 * creating it already, then we open it anyway. We
6457 * don't bother retrying after this, since if this next
6458 * fails, that means that the file was deleted after we
6459 * started this call.
6461 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
6467 /* something went wrong creating or truncating the file */
6469 cm_ReleaseSCache(scp);
6470 cm_ReleaseUser(userp);
6475 /* make sure we have file vs. dir right */
6476 if (realDirFlag == 0 && scp->fileType != CM_SCACHETYPE_FILE) {
6477 /* now watch for a symlink */
6479 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
6481 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
6483 /* we have a more accurate file to use (the
6484 * target of the symbolic link). Otherwise,
6485 * we'll just use the symlink anyway.
6487 osi_Log2(smb_logp, "symlink vp %x to vp %x",
6489 cm_ReleaseSCache(scp);
6494 if (scp->fileType != CM_SCACHETYPE_FILE) {
6495 cm_ReleaseSCache(scp);
6496 cm_ReleaseUser(userp);
6498 return CM_ERROR_ISDIR;
6502 if (realDirFlag == 1 && scp->fileType == CM_SCACHETYPE_FILE) {
6503 cm_ReleaseSCache(scp);
6504 cm_ReleaseUser(userp);
6506 return CM_ERROR_NOTDIR;
6509 /* open the file itself */
6510 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
6513 /* If we are restricting sharing, we should do so with a suitable
6515 if (scp->fileType == CM_SCACHETYPE_FILE &&
6516 !(fidflags & SMB_FID_SHARE_WRITE)) {
6518 LARGE_INTEGER LOffset, LLength;
6521 LOffset.HighPart = SMB_FID_QLOCK_HIGH;
6522 LOffset.LowPart = SMB_FID_QLOCK_LOW;
6523 LLength.HighPart = 0;
6524 LLength.LowPart = SMB_FID_QLOCK_LENGTH;
6526 if (fidflags & SMB_FID_SHARE_READ) {
6527 sLockType = LOCKING_ANDX_SHARED_LOCK;
6532 key = cm_GenerateKey(vcp->vcID, SMB_FID_QLOCK_PID, fidp->fid);
6534 lock_ObtainMutex(&scp->mx);
6535 code = cm_Lock(scp, sLockType, LOffset, LLength, key, 0, userp, &req, NULL);
6536 lock_ReleaseMutex(&scp->mx);
6539 fidp->flags = SMB_FID_DELETE;
6540 smb_ReleaseFID(fidp);
6542 cm_ReleaseSCache(scp);
6543 cm_ReleaseUser(userp);
6546 return CM_ERROR_SHARING_VIOLATION;
6550 /* save a pointer to the vnode */
6553 fidp->flags = fidflags;
6555 /* save parent dir and pathname for deletion or change notification */
6556 if (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE)) {
6557 fidp->flags |= SMB_FID_NTOPEN;
6558 fidp->NTopen_dscp = dscp;
6559 cm_HoldSCache(dscp);
6560 fidp->NTopen_pathp = strdup(lastNamep);
6562 fidp->NTopen_wholepathp = realPathp;
6564 /* we don't need this any longer */
6566 cm_ReleaseSCache(dscp);
6568 cm_Open(scp, 0, userp);
6570 /* set inp->fid so that later read calls in same msg can find fid */
6571 inp->fid = fidp->fid;
6573 /* check whether we are required to send an extended response */
6574 if (!extendedRespRequired) {
6576 parmOffset = 8*4 + 39;
6577 parmOffset += 1; /* pad to 4 */
6578 dataOffset = parmOffset + 70;
6582 /* Total Parameter Count */
6583 smb_SetSMBParmLong(outp, parmSlot, 70); parmSlot += 2;
6584 /* Total Data Count */
6585 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
6586 /* Parameter Count */
6587 smb_SetSMBParmLong(outp, parmSlot, 70); parmSlot += 2;
6588 /* Parameter Offset */
6589 smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
6590 /* Parameter Displacement */
6591 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
6593 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
6595 smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
6596 /* Data Displacement */
6597 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
6598 smb_SetSMBParmByte(outp, parmSlot, 0); /* Setup Count */
6599 smb_SetSMBDataLength(outp, 70);
6601 lock_ObtainMutex(&scp->mx);
6602 outData = smb_GetSMBData(outp, NULL);
6603 outData++; /* round to get to parmOffset */
6604 *outData = 0; outData++; /* oplock */
6605 *outData = 0; outData++; /* reserved */
6606 *((USHORT *)outData) = fidp->fid; outData += 2; /* fid */
6607 *((ULONG *)outData) = openAction; outData += 4;
6608 *((ULONG *)outData) = 0; outData += 4; /* EA error offset */
6609 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
6610 *((FILETIME *)outData) = ft; outData += 8; /* creation time */
6611 *((FILETIME *)outData) = ft; outData += 8; /* last access time */
6612 *((FILETIME *)outData) = ft; outData += 8; /* last write time */
6613 *((FILETIME *)outData) = ft; outData += 8; /* change time */
6614 *((ULONG *)outData) = smb_ExtAttributes(scp); outData += 4;
6615 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* alloc sz */
6616 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* EOF */
6617 *((USHORT *)outData) = 0; outData += 2; /* filetype */
6618 *((USHORT *)outData) = 0; outData += 2; /* dev state */
6619 *((USHORT *)outData) = (scp->fileType == CM_SCACHETYPE_DIRECTORY);
6620 outData += 2; /* is a dir? */
6621 lock_ReleaseMutex(&scp->mx);
6624 parmOffset = 8*4 + 39;
6625 parmOffset += 1; /* pad to 4 */
6626 dataOffset = parmOffset + 104;
6630 /* Total Parameter Count */
6631 smb_SetSMBParmLong(outp, parmSlot, 101); parmSlot += 2;
6632 /* Total Data Count */
6633 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
6634 /* Parameter Count */
6635 smb_SetSMBParmLong(outp, parmSlot, 101); parmSlot += 2;
6636 /* Parameter Offset */
6637 smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
6638 /* Parameter Displacement */
6639 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
6641 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
6643 smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
6644 /* Data Displacement */
6645 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
6646 smb_SetSMBParmByte(outp, parmSlot, 0); /* Setup Count */
6647 smb_SetSMBDataLength(outp, 105);
6649 lock_ObtainMutex(&scp->mx);
6650 outData = smb_GetSMBData(outp, NULL);
6651 outData++; /* round to get to parmOffset */
6652 *outData = 0; outData++; /* oplock */
6653 *outData = 1; outData++; /* response type */
6654 *((USHORT *)outData) = fidp->fid; outData += 2; /* fid */
6655 *((ULONG *)outData) = openAction; outData += 4;
6656 *((ULONG *)outData) = 0; outData += 4; /* EA error offset */
6657 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
6658 *((FILETIME *)outData) = ft; outData += 8; /* creation time */
6659 *((FILETIME *)outData) = ft; outData += 8; /* last access time */
6660 *((FILETIME *)outData) = ft; outData += 8; /* last write time */
6661 *((FILETIME *)outData) = ft; outData += 8; /* change time */
6662 *((ULONG *)outData) = smb_ExtAttributes(scp); outData += 4;
6663 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* alloc sz */
6664 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* EOF */
6665 *((USHORT *)outData) = 0; outData += 2; /* filetype */
6666 *((USHORT *)outData) = 0; outData += 2; /* dev state */
6667 *((USHORT *)outData) = (scp->fileType == CM_SCACHETYPE_DIRECTORY);
6668 outData += 1; /* is a dir? */
6669 memset(outData,0,24); outData += 24; /* Volume ID and file ID */
6670 *((ULONG *)outData) = 0x001f01ffL; outData += 4; /* Maxmimal access rights */
6671 *((ULONG *)outData) = 0; outData += 4; /* Guest Access rights */
6672 lock_ReleaseMutex(&scp->mx);
6675 osi_Log1(smb_logp, "SMB NTTranCreate opening fid %d", fidp->fid);
6677 smb_ReleaseFID(fidp);
6679 cm_ReleaseUser(userp);
6681 /* free(realPathp); Can't free realPathp here because fidp->NTopen_wholepathp points there */
6682 /* leave scp held since we put it in fidp->scp */
6686 long smb_ReceiveNTTranNotifyChange(smb_vc_t *vcp, smb_packet_t *inp,
6689 smb_packet_t *savedPacketp;
6690 ULONG filter; USHORT fid, watchtree;
6694 filter = smb_GetSMBParm(inp, 19) |
6695 (smb_GetSMBParm(inp, 20) << 16);
6696 fid = smb_GetSMBParm(inp, 21);
6697 watchtree = smb_GetSMBParm(inp, 22) && 0xffff; /* TODO: should this be 0xff ? */
6699 fidp = smb_FindFID(vcp, fid, 0);
6701 osi_Log1(smb_logp, "ERROR: NotifyChange given invalid fid [%d]", fid);
6702 return CM_ERROR_BADFD;
6705 savedPacketp = smb_CopyPacket(inp);
6707 savedPacketp->vcp = vcp;
6708 lock_ObtainMutex(&smb_Dir_Watch_Lock);
6709 savedPacketp->nextp = smb_Directory_Watches;
6710 smb_Directory_Watches = savedPacketp;
6711 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
6713 osi_Log4(smb_logp, "Request for NotifyChange filter 0x%x fid %d wtree %d file %s",
6714 filter, fid, watchtree, osi_LogSaveString(smb_logp, fidp->NTopen_wholepathp));
6717 lock_ObtainMutex(&scp->mx);
6719 scp->flags |= CM_SCACHEFLAG_WATCHEDSUBTREE;
6721 scp->flags |= CM_SCACHEFLAG_WATCHED;
6722 lock_ReleaseMutex(&scp->mx);
6723 smb_ReleaseFID(fidp);
6725 outp->flags |= SMB_PACKETFLAG_NOSEND;
6729 unsigned char nullSecurityDesc[36] = {
6730 0x01, /* security descriptor revision */
6731 0x00, /* reserved, should be zero */
6732 0x00, 0x80, /* security descriptor control;
6733 * 0x8000 : self-relative format */
6734 0x14, 0x00, 0x00, 0x00, /* offset of owner SID */
6735 0x1c, 0x00, 0x00, 0x00, /* offset of group SID */
6736 0x00, 0x00, 0x00, 0x00, /* offset of DACL would go here */
6737 0x00, 0x00, 0x00, 0x00, /* offset of SACL would go here */
6738 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
6739 /* "null SID" owner SID */
6740 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
6741 /* "null SID" group SID */
6744 long smb_ReceiveNTTranQuerySecurityDesc(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6746 int parmOffset, parmCount, dataOffset, dataCount;
6754 ULONG securityInformation;
6756 parmOffset = smb_GetSMBOffsetParm(inp, 11, 1)
6757 | (smb_GetSMBOffsetParm(inp, 12, 1) << 16);
6758 parmp = inp->data + parmOffset;
6759 sparmp = (USHORT *) parmp;
6760 lparmp = (ULONG *) parmp;
6763 securityInformation = lparmp[1];
6765 maxData = smb_GetSMBOffsetParm(inp, 7, 1)
6766 | (smb_GetSMBOffsetParm(inp, 8, 1) << 16);
6774 parmOffset = 8*4 + 39;
6775 parmOffset += 1; /* pad to 4 */
6777 dataOffset = parmOffset + parmCount;
6781 /* Total Parameter Count */
6782 smb_SetSMBParmLong(outp, parmSlot, parmCount); parmSlot += 2;
6783 /* Total Data Count */
6784 smb_SetSMBParmLong(outp, parmSlot, dataCount); parmSlot += 2;
6785 /* Parameter Count */
6786 smb_SetSMBParmLong(outp, parmSlot, parmCount); parmSlot += 2;
6787 /* Parameter Offset */
6788 smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
6789 /* Parameter Displacement */
6790 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
6792 smb_SetSMBParmLong(outp, parmSlot, dataCount); parmSlot += 2;
6794 smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
6795 /* Data Displacement */
6796 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
6797 smb_SetSMBParmByte(outp, parmSlot, 0); /* Setup Count */
6798 smb_SetSMBDataLength(outp, 1 + parmCount + dataCount);
6800 outData = smb_GetSMBData(outp, NULL);
6801 outData++; /* round to get to parmOffset */
6802 *((ULONG *)outData) = 36; outData += 4; /* length */
6804 if (maxData >= 36) {
6805 memcpy(outData, nullSecurityDesc, 36);
6809 return CM_ERROR_BUFFERTOOSMALL;
6812 long smb_ReceiveNTTransact(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6814 unsigned short function;
6816 function = smb_GetSMBParm(inp, 18);
6818 osi_Log1(smb_logp, "SMB NT Transact function %d", function);
6820 /* We can handle long names */
6821 if (vcp->flags & SMB_VCFLAG_USENT)
6822 ((smb_t *)outp)->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
6826 return smb_ReceiveNTTranQuerySecurityDesc(vcp, inp, outp);
6828 return smb_ReceiveNTTranNotifyChange(vcp, inp, outp);
6830 return smb_ReceiveNTTranCreate(vcp, inp, outp);
6832 return CM_ERROR_INVAL;
6837 * smb_NotifyChange -- find relevant change notification messages and
6840 * If we don't know the file name (i.e. a callback break), filename is
6841 * NULL, and we return a zero-length list.
6843 void smb_NotifyChange(DWORD action, DWORD notifyFilter,
6844 cm_scache_t *dscp, char *filename, char *otherFilename,
6845 BOOL isDirectParent)
6847 smb_packet_t *watch, *lastWatch, *nextWatch;
6848 ULONG parmSlot, parmCount, parmOffset, dataOffset, nameLen;
6849 char *outData, *oldOutData;
6853 BOOL twoEntries = FALSE;
6854 ULONG otherNameLen, oldParmCount = 0;
6859 /* Get ready for rename within directory */
6860 if (action == FILE_ACTION_RENAMED_OLD_NAME && otherFilename != NULL) {
6862 otherAction = FILE_ACTION_RENAMED_NEW_NAME;
6865 osi_Log2(smb_logp,"in smb_NotifyChange for file [%s] dscp [%x]",
6866 osi_LogSaveString(smb_logp,filename),dscp);
6868 lock_ObtainMutex(&smb_Dir_Watch_Lock);
6869 watch = smb_Directory_Watches;
6871 filter = smb_GetSMBParm(watch, 19)
6872 | (smb_GetSMBParm(watch, 20) << 16);
6873 fid = smb_GetSMBParm(watch, 21);
6874 wtree = smb_GetSMBParm(watch, 22) & 0xffff; /* TODO: should this be 0xff ? */
6875 maxLen = smb_GetSMBOffsetParm(watch, 5, 1)
6876 | (smb_GetSMBOffsetParm(watch, 6, 1) << 16);
6880 * Strange hack - bug in NT Client and NT Server that we
6883 if (filter == 3 && wtree)
6886 fidp = smb_FindFID(vcp, fid, 0);
6888 osi_Log1(smb_logp," no fidp for fid[%d]",fid);
6890 watch = watch->nextp;
6893 if (fidp->scp != dscp
6894 || (filter & notifyFilter) == 0
6895 || (!isDirectParent && !wtree)) {
6896 osi_Log1(smb_logp," passing fidp->scp[%x]", fidp->scp);
6897 smb_ReleaseFID(fidp);
6899 watch = watch->nextp;
6902 smb_ReleaseFID(fidp);
6905 "Sending Change Notification for fid %d filter 0x%x wtree %d file %s",
6906 fid, filter, wtree, osi_LogSaveString(smb_logp, filename));
6908 nextWatch = watch->nextp;
6909 if (watch == smb_Directory_Watches)
6910 smb_Directory_Watches = nextWatch;
6912 lastWatch->nextp = nextWatch;
6914 /* Turn off WATCHED flag in dscp */
6915 lock_ObtainMutex(&dscp->mx);
6917 dscp->flags &= ~CM_SCACHEFLAG_WATCHEDSUBTREE;
6919 dscp->flags &= ~CM_SCACHEFLAG_WATCHED;
6920 lock_ReleaseMutex(&dscp->mx);
6922 /* Convert to response packet */
6923 ((smb_t *) watch)->reb = SMB_FLAGS_SERVER_TO_CLIENT | SMB_FLAGS_CANONICAL_PATHNAMES;
6924 ((smb_t *) watch)->wct = 0;
6927 if (filename == NULL)
6930 nameLen = strlen(filename);
6931 parmCount = 3*4 + nameLen*2;
6932 parmCount = (parmCount + 3) & ~3; /* pad to 4 */
6934 otherNameLen = strlen(otherFilename);
6935 oldParmCount = parmCount;
6936 parmCount += 3*4 + otherNameLen*2;
6937 parmCount = (parmCount + 3) & ~3; /* pad to 4 */
6939 if (maxLen < parmCount)
6940 parmCount = 0; /* not enough room */
6942 parmOffset = 8*4 + 39;
6943 parmOffset += 1; /* pad to 4 */
6944 dataOffset = parmOffset + parmCount;
6948 /* Total Parameter Count */
6949 smb_SetSMBParmLong(watch, parmSlot, parmCount); parmSlot += 2;
6950 /* Total Data Count */
6951 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
6952 /* Parameter Count */
6953 smb_SetSMBParmLong(watch, parmSlot, parmCount); parmSlot += 2;
6954 /* Parameter Offset */
6955 smb_SetSMBParmLong(watch, parmSlot, parmOffset); parmSlot += 2;
6956 /* Parameter Displacement */
6957 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
6959 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
6961 smb_SetSMBParmLong(watch, parmSlot, dataOffset); parmSlot += 2;
6962 /* Data Displacement */
6963 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
6964 smb_SetSMBParmByte(watch, parmSlot, 0); /* Setup Count */
6965 smb_SetSMBDataLength(watch, parmCount + 1);
6967 if (parmCount != 0) {
6969 outData = smb_GetSMBData(watch, NULL);
6970 outData++; /* round to get to parmOffset */
6971 oldOutData = outData;
6972 *((DWORD *)outData) = oldParmCount; outData += 4;
6973 /* Next Entry Offset */
6974 *((DWORD *)outData) = action; outData += 4;
6976 *((DWORD *)outData) = nameLen*2; outData += 4;
6977 /* File Name Length */
6978 p = strdup(filename);
6979 if (smb_StoreAnsiFilenames)
6981 mbstowcs((WCHAR *)outData, p, nameLen);
6985 outData = oldOutData + oldParmCount;
6986 *((DWORD *)outData) = 0; outData += 4;
6987 /* Next Entry Offset */
6988 *((DWORD *)outData) = otherAction; outData += 4;
6990 *((DWORD *)outData) = otherNameLen*2;
6991 outData += 4; /* File Name Length */
6992 p = strdup(otherFilename);
6993 if (smb_StoreAnsiFilenames)
6995 mbstowcs((WCHAR *)outData, p, otherNameLen); /* File Name */
7001 * If filename is null, we don't know the cause of the
7002 * change notification. We return zero data (see above),
7003 * and set error code to NT_STATUS_NOTIFY_ENUM_DIR
7004 * (= 0x010C). We set the error code here by hand, without
7005 * modifying wct and bcc.
7007 if (filename == NULL) {
7008 ((smb_t *) watch)->rcls = 0x0C;
7009 ((smb_t *) watch)->reh = 0x01;
7010 ((smb_t *) watch)->errLow = 0;
7011 ((smb_t *) watch)->errHigh = 0;
7012 /* Set NT Status codes flag */
7013 ((smb_t *) watch)->flg2 |= SMB_FLAGS2_32BIT_STATUS;
7016 smb_SendPacket(vcp, watch);
7017 smb_FreePacket(watch);
7020 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
7023 long smb_ReceiveNTCancel(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7025 unsigned char *replyWctp;
7026 smb_packet_t *watch, *lastWatch;
7027 USHORT fid, watchtree;
7031 osi_Log0(smb_logp, "SMB3 receive NT cancel");
7033 lock_ObtainMutex(&smb_Dir_Watch_Lock);
7034 watch = smb_Directory_Watches;
7036 if (((smb_t *)watch)->uid == ((smb_t *)inp)->uid
7037 && ((smb_t *)watch)->pid == ((smb_t *)inp)->pid
7038 && ((smb_t *)watch)->mid == ((smb_t *)inp)->mid
7039 && ((smb_t *)watch)->tid == ((smb_t *)inp)->tid) {
7040 if (watch == smb_Directory_Watches)
7041 smb_Directory_Watches = watch->nextp;
7043 lastWatch->nextp = watch->nextp;
7044 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
7046 /* Turn off WATCHED flag in scp */
7047 fid = smb_GetSMBParm(watch, 21);
7048 watchtree = smb_GetSMBParm(watch, 22) & 0xffff;
7050 if (vcp != watch->vcp)
7051 osi_Log2(smb_logp, "smb_ReceiveNTCancel: vcp %x not equal to watch vcp %x",
7054 fidp = smb_FindFID(vcp, fid, 0);
7056 osi_Log3(smb_logp, "Cancelling change notification for fid %d wtree %d file %s",
7058 osi_LogSaveString(smb_logp, (fidp)?fidp->NTopen_wholepathp:""));
7061 lock_ObtainMutex(&scp->mx);
7063 scp->flags &= ~CM_SCACHEFLAG_WATCHEDSUBTREE;
7065 scp->flags &= ~CM_SCACHEFLAG_WATCHED;
7066 lock_ReleaseMutex(&scp->mx);
7067 smb_ReleaseFID(fidp);
7069 osi_Log2(smb_logp,"NTCancel unable to resolve fid [%d] in vcp[%x]", fid,vcp);
7072 /* assume STATUS32; return 0xC0000120 (CANCELED) */
7073 replyWctp = watch->wctp;
7077 ((smb_t *)watch)->rcls = 0x20;
7078 ((smb_t *)watch)->reh = 0x1;
7079 ((smb_t *)watch)->errLow = 0;
7080 ((smb_t *)watch)->errHigh = 0xC0;
7081 ((smb_t *)watch)->flg2 |= SMB_FLAGS2_32BIT_STATUS;
7082 smb_SendPacket(vcp, watch);
7083 smb_FreePacket(watch);
7087 watch = watch->nextp;
7089 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
7095 * NT rename also does hard links.
7098 #define RENAME_FLAG_MOVE_CLUSTER_INFORMATION 0x102
7099 #define RENAME_FLAG_HARD_LINK 0x103
7100 #define RENAME_FLAG_RENAME 0x104
7101 #define RENAME_FLAG_COPY 0x105
7103 long smb_ReceiveNTRename(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7105 char *oldPathp, *newPathp;
7111 attrs = smb_GetSMBParm(inp, 0);
7112 rename_type = smb_GetSMBParm(inp, 1);
7114 if (rename_type != RENAME_FLAG_RENAME && rename_type != RENAME_FLAG_HARD_LINK) {
7115 osi_Log1(smb_logp, "NTRename invalid infolevel [%x]", rename_type);
7116 return CM_ERROR_NOACCESS;
7119 tp = smb_GetSMBData(inp, NULL);
7120 oldPathp = smb_ParseASCIIBlock(tp, &tp);
7121 if (smb_StoreAnsiFilenames)
7122 OemToChar(oldPathp,oldPathp);
7123 newPathp = smb_ParseASCIIBlock(tp, &tp);
7124 if (smb_StoreAnsiFilenames)
7125 OemToChar(newPathp,newPathp);
7127 osi_Log3(smb_logp, "NTRename for [%s]->[%s] type [%s]",
7128 osi_LogSaveString(smb_logp, oldPathp),
7129 osi_LogSaveString(smb_logp, newPathp),
7130 ((rename_type==RENAME_FLAG_RENAME)?"rename":"hardlink"));
7132 if (rename_type == RENAME_FLAG_RENAME) {
7133 code = smb_Rename(vcp,inp,oldPathp,newPathp,attrs);
7134 } else { /* RENAME_FLAG_HARD_LINK */
7135 code = smb_Link(vcp,inp,oldPathp,newPathp);
7142 lock_InitializeMutex(&smb_Dir_Watch_Lock, "Directory Watch List Lock");
7145 cm_user_t *smb_FindCMUserByName(/*smb_vc_t *vcp,*/ char *usern, char *machine)
7148 smb_username_t *unp;
7150 unp = smb_FindUserByName(usern, machine, SMB_FLAG_CREATE);
7152 lock_ObtainMutex(&unp->mx);
7153 unp->userp = cm_NewUser();
7154 lock_ReleaseMutex(&unp->mx);
7155 osi_Log2(smb_logp,"smb_FindCMUserByName New user name[%s] machine[%s]",osi_LogSaveString(smb_logp,usern),osi_LogSaveString(smb_logp,machine));
7156 osi_LogEvent("AFS smb_FindCMUserByName : New User",NULL,"name[%s] machine[%s]",usern,machine);
7158 osi_Log2(smb_logp,"smb_FindCMUserByName Not found name[%s] machine[%s]",osi_LogSaveString(smb_logp,usern),osi_LogSaveString(smb_logp,machine));
7159 osi_LogEvent("AFS smb_FindCMUserByName : Found",NULL,"name[%s] machine[%s]",usern,machine);