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);
55 lock_ObtainMutex(&uidp->mx);
57 up = uidp->unp->userp;
60 lock_ReleaseMutex(&uidp->mx);
68 * Return extended attributes.
69 * Right now, we aren't using any of the "new" bits, so this looks exactly
70 * like smb_Attributes() (see smb.c).
72 unsigned long smb_ExtAttributes(cm_scache_t *scp)
76 if (scp->fileType == CM_SCACHETYPE_DIRECTORY ||
77 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
78 scp->fileType == CM_SCACHETYPE_INVALID)
80 attrs = SMB_ATTR_DIRECTORY;
81 #ifdef SPECIAL_FOLDERS
82 attrs |= SMB_ATTR_SYSTEM; /* FILE_ATTRIBUTE_SYSTEM */
83 #endif /* SPECIAL_FOLDERS */
84 } else if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
85 attrs = SMB_ATTR_DIRECTORY | SMB_ATTR_SPARSE_FILE;
89 * We used to mark a file RO if it was in an RO volume, but that
90 * turns out to be impolitic in NT. See defect 10007.
93 if ((scp->unixModeBits & 0222) == 0 || (scp->flags & CM_SCACHEFLAG_RO))
94 attrs |= SMB_ATTR_READONLY; /* Read-only */
96 if ((scp->unixModeBits & 0222) == 0)
97 attrs |= SMB_ATTR_READONLY; /* Read-only */
101 attrs = SMB_ATTR_NORMAL; /* FILE_ATTRIBUTE_NORMAL */
106 int smb_V3IsStarMask(char *maskp)
110 while (tc = *maskp++)
111 if (tc == '?' || tc == '*' || tc == '<' || tc == '>')
116 unsigned char *smb_ParseString(unsigned char *inp, char **chainpp)
119 /* skip over null-terminated string */
120 *chainpp = inp + strlen(inp) + 1;
125 void OutputDebugF(char * format, ...) {
130 va_start( args, format );
131 len = _vscprintf( format, args ) // _vscprintf doesn't count
132 + 3; // terminating '\0' + '\n'
133 buffer = malloc( len * sizeof(char) );
134 vsprintf( buffer, format, args );
135 osi_Log0(smb_logp, osi_LogSaveString(smb_logp, buffer));
136 strcat(buffer, "\n");
137 OutputDebugString(buffer);
141 void OutputDebugHexDump(unsigned char * buffer, int len) {
144 static char tr[16] = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
146 OutputDebugF("Hexdump length [%d]",len);
148 for (i=0;i<len;i++) {
151 osi_Log0(smb_logp, osi_LogSaveString(smb_logp, buf));
153 OutputDebugString(buf);
155 sprintf(buf,"%5x",i);
156 memset(buf+5,' ',80);
161 j = j*3 + 7 + ((j>7)?1:0);
164 buf[j] = tr[k / 16]; buf[j+1] = tr[k % 16];
167 j = j + 56 + ((j>7)?1:0);
169 buf[j] = (k>32 && k<127)?k:'.';
172 osi_Log0(smb_logp, osi_LogSaveString(smb_logp, buf));
174 OutputDebugString(buf);
178 #define SMB_EXT_SEC_PACKAGE_NAME "Negotiate"
180 void smb_NegotiateExtendedSecurity(void ** secBlob, int * secBlobLength) {
181 SECURITY_STATUS status, istatus;
182 CredHandle creds = {0,0};
184 SecBufferDesc secOut;
192 OutputDebugF("Negotiating Extended Security");
194 status = AcquireCredentialsHandle( NULL,
195 SMB_EXT_SEC_PACKAGE_NAME,
204 if (status != SEC_E_OK) {
205 /* Really bad. We return an empty security blob */
206 OutputDebugF("AcquireCredentialsHandle failed with %lX", status);
211 secOut.pBuffers = &secTok;
212 secOut.ulVersion = SECBUFFER_VERSION;
214 secTok.BufferType = SECBUFFER_TOKEN;
216 secTok.pvBuffer = NULL;
218 ctx.dwLower = ctx.dwUpper = 0;
220 status = AcceptSecurityContext( &creds,
223 ASC_REQ_CONNECTION | ASC_REQ_EXTENDED_ERROR | ASC_REQ_ALLOCATE_MEMORY,
224 SECURITY_NETWORK_DREP,
231 if (status == SEC_I_COMPLETE_NEEDED || status == SEC_I_COMPLETE_AND_CONTINUE) {
232 OutputDebugF("Completing token...");
233 istatus = CompleteAuthToken(&ctx, &secOut);
234 if ( istatus != SEC_E_OK )
235 OutputDebugF("Token completion failed: %x", istatus);
238 if (status == SEC_I_COMPLETE_AND_CONTINUE || status == SEC_I_CONTINUE_NEEDED) {
239 if (secTok.pvBuffer) {
240 *secBlobLength = secTok.cbBuffer;
241 *secBlob = malloc( secTok.cbBuffer );
242 memcpy(*secBlob, secTok.pvBuffer, secTok.cbBuffer );
245 if ( status != SEC_E_OK )
246 OutputDebugF("AcceptSecurityContext status != CONTINUE %lX", status);
249 /* Discard partial security context */
250 DeleteSecurityContext(&ctx);
252 if (secTok.pvBuffer) FreeContextBuffer( secTok.pvBuffer );
254 /* Discard credentials handle. We'll reacquire one when we get the session setup X */
255 FreeCredentialsHandle(&creds);
261 struct smb_ext_context {
268 long smb_AuthenticateUserExt(smb_vc_t * vcp, char * usern, char * secBlobIn, int secBlobInLength, char ** secBlobOut, int * secBlobOutLength) {
269 SECURITY_STATUS status, istatus;
273 SecBufferDesc secBufIn;
275 SecBufferDesc secBufOut;
278 struct smb_ext_context * secCtx = NULL;
279 struct smb_ext_context * newSecCtx = NULL;
280 void * assembledBlob = NULL;
281 int assembledBlobLength = 0;
284 OutputDebugF("In smb_AuthenticateUserExt");
287 *secBlobOutLength = 0;
289 if (vcp->flags & SMB_VCFLAG_AUTH_IN_PROGRESS) {
290 secCtx = vcp->secCtx;
291 lock_ObtainMutex(&vcp->mx);
292 vcp->flags &= ~SMB_VCFLAG_AUTH_IN_PROGRESS;
294 lock_ReleaseMutex(&vcp->mx);
298 OutputDebugF("Received incoming token:");
299 OutputDebugHexDump(secBlobIn,secBlobInLength);
303 OutputDebugF("Continuing with existing context.");
304 creds = secCtx->creds;
307 if (secCtx->partialToken) {
308 assembledBlobLength = secCtx->partialTokenLen + secBlobInLength;
309 assembledBlob = malloc(assembledBlobLength);
310 memcpy(assembledBlob,secCtx->partialToken, secCtx->partialTokenLen);
311 memcpy(((BYTE *)assembledBlob) + secCtx->partialTokenLen, secBlobIn, secBlobInLength);
314 status = AcquireCredentialsHandle( NULL,
315 SMB_EXT_SEC_PACKAGE_NAME,
324 if (status != SEC_E_OK) {
325 OutputDebugF("Can't acquire Credentials handle [%lX]", status);
326 code = CM_ERROR_BADPASSWORD; /* means "try again when I'm sober" */
334 secBufIn.cBuffers = 1;
335 secBufIn.pBuffers = &secTokIn;
336 secBufIn.ulVersion = SECBUFFER_VERSION;
338 secTokIn.BufferType = SECBUFFER_TOKEN;
340 secTokIn.cbBuffer = assembledBlobLength;
341 secTokIn.pvBuffer = assembledBlob;
343 secTokIn.cbBuffer = secBlobInLength;
344 secTokIn.pvBuffer = secBlobIn;
347 secBufOut.cBuffers = 1;
348 secBufOut.pBuffers = &secTokOut;
349 secBufOut.ulVersion = SECBUFFER_VERSION;
351 secTokOut.BufferType = SECBUFFER_TOKEN;
352 secTokOut.cbBuffer = 0;
353 secTokOut.pvBuffer = NULL;
355 status = AcceptSecurityContext( &creds,
356 ((secCtx)?&ctx:NULL),
358 ASC_REQ_CONNECTION | ASC_REQ_EXTENDED_ERROR | ASC_REQ_ALLOCATE_MEMORY,
359 SECURITY_NETWORK_DREP,
366 if (status == SEC_I_COMPLETE_NEEDED || status == SEC_I_COMPLETE_AND_CONTINUE) {
367 OutputDebugF("Completing token...");
368 istatus = CompleteAuthToken(&ctx, &secBufOut);
369 if ( istatus != SEC_E_OK )
370 OutputDebugF("Token completion failed: %lX", istatus);
373 if (status == SEC_I_COMPLETE_AND_CONTINUE || status == SEC_I_CONTINUE_NEEDED) {
374 OutputDebugF("Continue needed");
376 newSecCtx = malloc(sizeof(*newSecCtx));
378 newSecCtx->creds = creds;
379 newSecCtx->ctx = ctx;
380 newSecCtx->partialToken = NULL;
381 newSecCtx->partialTokenLen = 0;
383 lock_ObtainMutex( &vcp->mx );
384 vcp->flags |= SMB_VCFLAG_AUTH_IN_PROGRESS;
385 vcp->secCtx = newSecCtx;
386 lock_ReleaseMutex( &vcp->mx );
388 code = CM_ERROR_GSSCONTINUE;
391 if ((status == SEC_I_COMPLETE_NEEDED || status == SEC_E_OK ||
392 status == SEC_I_COMPLETE_AND_CONTINUE || status == SEC_I_CONTINUE_NEEDED) &&
393 secTokOut.pvBuffer) {
394 OutputDebugF("Need to send token back to client");
396 *secBlobOutLength = secTokOut.cbBuffer;
397 *secBlobOut = malloc(secTokOut.cbBuffer);
398 memcpy(*secBlobOut, secTokOut.pvBuffer, secTokOut.cbBuffer);
400 OutputDebugF("Outgoing token:");
401 OutputDebugHexDump(*secBlobOut,*secBlobOutLength);
402 } else if (status == SEC_E_INCOMPLETE_MESSAGE) {
403 OutputDebugF("Incomplete message");
405 newSecCtx = malloc(sizeof(*newSecCtx));
407 newSecCtx->creds = creds;
408 newSecCtx->ctx = ctx;
409 newSecCtx->partialToken = malloc(secTokOut.cbBuffer);
410 memcpy(newSecCtx->partialToken, secTokOut.pvBuffer, secTokOut.cbBuffer);
411 newSecCtx->partialTokenLen = secTokOut.cbBuffer;
413 lock_ObtainMutex( &vcp->mx );
414 vcp->flags |= SMB_VCFLAG_AUTH_IN_PROGRESS;
415 vcp->secCtx = newSecCtx;
416 lock_ReleaseMutex( &vcp->mx );
418 code = CM_ERROR_GSSCONTINUE;
421 if (status == SEC_E_OK || status == SEC_I_COMPLETE_NEEDED) {
423 SecPkgContext_Names names;
425 OutputDebugF("Authentication completed");
426 OutputDebugF("Returned flags : [%lX]", flags);
428 if (!QueryContextAttributes(&ctx, SECPKG_ATTR_NAMES, &names)) {
429 OutputDebugF("Received name [%s]", names.sUserName);
430 strcpy(usern, names.sUserName);
431 strlwr(usern); /* in tandem with smb_GetNormalizedUsername */
432 FreeContextBuffer(names.sUserName);
434 /* Force the user to retry if the context is invalid */
435 OutputDebugF("QueryContextAttributes Names failed [%x]", GetLastError());
436 code = CM_ERROR_BADPASSWORD;
440 case SEC_E_INVALID_TOKEN:
441 OutputDebugF("Returning bad password :: INVALID_TOKEN");
443 case SEC_E_INVALID_HANDLE:
444 OutputDebugF("Returning bad password :: INVALID_HANDLE");
446 case SEC_E_LOGON_DENIED:
447 OutputDebugF("Returning bad password :: LOGON_DENIED");
449 case SEC_E_UNKNOWN_CREDENTIALS:
450 OutputDebugF("Returning bad password :: UNKNOWN_CREDENTIALS");
452 case SEC_E_NO_CREDENTIALS:
453 OutputDebugF("Returning bad password :: NO_CREDENTIALS");
455 case SEC_E_CONTEXT_EXPIRED:
456 OutputDebugF("Returning bad password :: CONTEXT_EXPIRED");
458 case SEC_E_INCOMPLETE_CREDENTIALS:
459 OutputDebugF("Returning bad password :: INCOMPLETE_CREDENTIALS");
461 case SEC_E_WRONG_PRINCIPAL:
462 OutputDebugF("Returning bad password :: WRONG_PRINCIPAL");
464 case SEC_E_TIME_SKEW:
465 OutputDebugF("Returning bad password :: TIME_SKEW");
468 OutputDebugF("Returning bad password :: Status == %lX", status);
470 code = CM_ERROR_BADPASSWORD;
474 if (secCtx->partialToken) free(secCtx->partialToken);
482 if (secTokOut.pvBuffer)
483 FreeContextBuffer(secTokOut.pvBuffer);
485 if (code != CM_ERROR_GSSCONTINUE) {
486 DeleteSecurityContext(&ctx);
487 FreeCredentialsHandle(&creds);
495 #define P_RESP_LEN 128
497 /* LsaLogonUser expects input parameters to be in a contiguous block of memory.
498 So put stuff in a struct. */
499 struct Lm20AuthBlob {
500 MSV1_0_LM20_LOGON lmlogon;
501 BYTE ciResponse[P_RESP_LEN]; /* Unicode representation */
502 BYTE csResponse[P_RESP_LEN]; /* ANSI representation */
503 WCHAR accountNameW[P_LEN];
504 WCHAR primaryDomainW[P_LEN];
505 WCHAR workstationW[MAX_COMPUTERNAME_LENGTH + 1];
506 TOKEN_GROUPS tgroups;
507 TOKEN_SOURCE tsource;
510 long smb_AuthenticateUserLM(smb_vc_t *vcp, char * accountName, char * primaryDomain, char * ciPwd, unsigned ciPwdLength, char * csPwd, unsigned csPwdLength)
513 struct Lm20AuthBlob lmAuth;
514 PMSV1_0_LM20_LOGON_PROFILE lmprofilep;
515 QUOTA_LIMITS quotaLimits;
517 ULONG lmprofilepSize;
521 OutputDebugF("In smb_AuthenticateUser for user [%s] domain [%s]", accountName, primaryDomain);
522 OutputDebugF("ciPwdLength is %d and csPwdLength is %d", ciPwdLength, csPwdLength);
524 if (ciPwdLength > P_RESP_LEN || csPwdLength > P_RESP_LEN) {
525 OutputDebugF("ciPwdLength or csPwdLength is too long");
526 return CM_ERROR_BADPASSWORD;
529 memset(&lmAuth,0,sizeof(lmAuth));
531 lmAuth.lmlogon.MessageType = MsV1_0NetworkLogon;
533 lmAuth.lmlogon.LogonDomainName.Buffer = lmAuth.primaryDomainW;
534 mbstowcs(lmAuth.primaryDomainW, primaryDomain, P_LEN);
535 lmAuth.lmlogon.LogonDomainName.Length = (USHORT)(wcslen(lmAuth.primaryDomainW) * sizeof(WCHAR));
536 lmAuth.lmlogon.LogonDomainName.MaximumLength = P_LEN * sizeof(WCHAR);
538 lmAuth.lmlogon.UserName.Buffer = lmAuth.accountNameW;
539 mbstowcs(lmAuth.accountNameW, accountName, P_LEN);
540 lmAuth.lmlogon.UserName.Length = (USHORT)(wcslen(lmAuth.accountNameW) * sizeof(WCHAR));
541 lmAuth.lmlogon.UserName.MaximumLength = P_LEN * sizeof(WCHAR);
543 lmAuth.lmlogon.Workstation.Buffer = lmAuth.workstationW;
544 lmAuth.lmlogon.Workstation.MaximumLength = (MAX_COMPUTERNAME_LENGTH + 1) * sizeof(WCHAR);
545 size = MAX_COMPUTERNAME_LENGTH + 1;
546 GetComputerNameW(lmAuth.workstationW, &size);
547 lmAuth.lmlogon.Workstation.Length = (USHORT)(wcslen(lmAuth.workstationW) * sizeof(WCHAR));
549 memcpy(lmAuth.lmlogon.ChallengeToClient, vcp->encKey, MSV1_0_CHALLENGE_LENGTH);
551 lmAuth.lmlogon.CaseInsensitiveChallengeResponse.Buffer = lmAuth.ciResponse;
552 lmAuth.lmlogon.CaseInsensitiveChallengeResponse.Length = ciPwdLength;
553 lmAuth.lmlogon.CaseInsensitiveChallengeResponse.MaximumLength = P_RESP_LEN;
554 memcpy(lmAuth.ciResponse, ciPwd, ciPwdLength);
556 lmAuth.lmlogon.CaseSensitiveChallengeResponse.Buffer = lmAuth.csResponse;
557 lmAuth.lmlogon.CaseSensitiveChallengeResponse.Length = csPwdLength;
558 lmAuth.lmlogon.CaseSensitiveChallengeResponse.MaximumLength = P_RESP_LEN;
559 memcpy(lmAuth.csResponse, csPwd, csPwdLength);
561 lmAuth.lmlogon.ParameterControl = 0;
563 lmAuth.tgroups.GroupCount = 0;
564 lmAuth.tgroups.Groups[0].Sid = NULL;
565 lmAuth.tgroups.Groups[0].Attributes = 0;
567 lmAuth.tsource.SourceIdentifier.HighPart = (DWORD)((LONG_PTR)vcp << 32);
568 lmAuth.tsource.SourceIdentifier.LowPart = (DWORD)((LONG_PTR)vcp & _UI32_MAX);
569 strcpy(lmAuth.tsource.SourceName,"OpenAFS"); /* 8 char limit */
571 nts = LsaLogonUser( smb_lsaHandle,
586 if (nts != STATUS_SUCCESS || ntsEx != STATUS_SUCCESS)
587 osi_Log2(smb_logp,"LsaLogonUser failure: nts %u ntsEx %u",
590 OutputDebugF("Return from LsaLogonUser is 0x%lX", nts);
591 OutputDebugF("Extended status is 0x%lX", ntsEx);
593 if (nts == ERROR_SUCCESS) {
595 LsaFreeReturnBuffer(lmprofilep);
596 CloseHandle(lmToken);
600 if (nts == 0xC000015BL)
601 return CM_ERROR_BADLOGONTYPE;
602 else /* our catchall is a bad password though we could be more specific */
603 return CM_ERROR_BADPASSWORD;
607 /* The buffer pointed to by usern is assumed to be at least SMB_MAX_USERNAME_LENGTH bytes */
608 long smb_GetNormalizedUsername(char * usern, const char * accountName, const char * domainName)
613 /* check if we have sane input */
614 if ((strlen(accountName) + strlen(domainName) + 1) > SMB_MAX_USERNAME_LENGTH)
617 /* we could get : [accountName][domainName]
623 atsign = strchr(accountName, '@');
625 if (atsign) /* [user@domain][] -> [user@domain][domain] */
630 /* if for some reason the client doesn't know what domain to use,
631 it will either return an empty string or a '?' */
632 if (!domain[0] || domain[0] == '?')
633 /* Empty domains and empty usernames are usually sent from tokenless contexts.
634 This way such logins will get an empty username (easy to check). I don't know
635 when a non-empty username would be supplied with an anonymous domain, but *shrug* */
636 strcpy(usern,accountName);
638 /* TODO: what about WIN.MIT.EDU\user vs. WIN\user? */
639 strcpy(usern,domain);
642 strncat(usern,accountName,atsign - accountName);
644 strcat(usern,accountName);
652 /* When using SMB auth, all SMB sessions have to pass through here
653 * first to authenticate the user.
655 * Caveat: If not using SMB auth, the protocol does not require
656 * sending a session setup packet, which means that we can't rely on a
657 * UID in subsequent packets. Though in practice we get one anyway.
659 long smb_ReceiveV3SessionSetupX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
663 unsigned short newUid;
664 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 */
844 newUid = uidp->userID;
845 osi_Log3(smb_logp,"smb_ReceiveV3SessionSetupX FindUserByName:Lana[%d],lsn[%d],userid[%d]",
846 vcp->lana,vcp->lsn,newUid);
847 smb_ReleaseUID(uidp);
852 /* do a global search for the username/machine name pair */
853 unp = smb_FindUserByName(usern, vcp->rname, SMB_FLAG_CREATE);
854 lock_ObtainMutex(&unp->mx);
855 if (unp->flags & SMB_USERFLAG_AFSLOGON) {
856 /* clear the afslogon flag so that the tickets can now
857 * be freed when the refCount returns to zero.
859 unp->flags &= ~SMB_USERFLAG_AFSLOGON;
861 lock_ReleaseMutex(&unp->mx);
863 /* Create a new UID and cm_user_t structure */
866 userp = cm_NewUser();
867 cm_HoldUserVCRef(userp);
868 lock_ObtainMutex(&vcp->mx);
869 if (!vcp->uidCounter)
870 vcp->uidCounter++; /* handle unlikely wraparounds */
871 newUid = (strlen(usern)==0)?0:vcp->uidCounter++;
872 lock_ReleaseMutex(&vcp->mx);
874 /* Create a new smb_user_t structure and connect them up */
875 lock_ObtainMutex(&unp->mx);
877 lock_ReleaseMutex(&unp->mx);
879 uidp = smb_FindUID(vcp, newUid, SMB_FLAG_CREATE);
880 lock_ObtainMutex(&uidp->mx);
882 osi_Log4(smb_logp,"smb_ReceiveV3SessionSetupX MakeNewUser:VCP[%p],Lana[%d],lsn[%d],userid[%d]",vcp,vcp->lana,vcp->lsn,newUid);
883 lock_ReleaseMutex(&uidp->mx);
884 smb_ReleaseUID(uidp);
887 /* Return UID to the client */
888 ((smb_t *)outp)->uid = newUid;
889 /* Also to the next chained message */
890 ((smb_t *)inp)->uid = newUid;
892 osi_Log3(smb_logp, "SMB3 session setup name %s creating ID %d%s",
893 osi_LogSaveString(smb_logp, usern), newUid, osi_LogSaveString(smb_logp, s1));
895 smb_SetSMBParm(outp, 2, 0);
897 if (vcp->flags & SMB_VCFLAG_USENT) {
898 if (smb_authType == SMB_AUTH_EXTENDED) {
899 smb_SetSMBParm(outp, 3, secBlobOutLength);
900 smb_SetSMBDataLength(outp, secBlobOutLength + smb_ServerOSLength + smb_ServerLanManagerLength + smb_ServerDomainNameLength);
901 tp = smb_GetSMBData(outp, NULL);
902 if (secBlobOutLength) {
903 memcpy(tp, secBlobOut, secBlobOutLength);
905 tp += secBlobOutLength;
907 memcpy(tp,smb_ServerOS,smb_ServerOSLength);
908 tp += smb_ServerOSLength;
909 memcpy(tp,smb_ServerLanManager,smb_ServerLanManagerLength);
910 tp += smb_ServerLanManagerLength;
911 memcpy(tp,smb_ServerDomainName,smb_ServerDomainNameLength);
912 tp += smb_ServerDomainNameLength;
914 smb_SetSMBDataLength(outp, 0);
917 if (smb_authType == SMB_AUTH_EXTENDED) {
918 smb_SetSMBDataLength(outp, smb_ServerOSLength + smb_ServerLanManagerLength + smb_ServerDomainNameLength);
919 tp = smb_GetSMBData(outp, NULL);
920 memcpy(tp,smb_ServerOS,smb_ServerOSLength);
921 tp += smb_ServerOSLength;
922 memcpy(tp,smb_ServerLanManager,smb_ServerLanManagerLength);
923 tp += smb_ServerLanManagerLength;
924 memcpy(tp,smb_ServerDomainName,smb_ServerDomainNameLength);
925 tp += smb_ServerDomainNameLength;
927 smb_SetSMBDataLength(outp, 0);
934 long smb_ReceiveV3UserLogoffX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
938 /* don't get tokens from this VC */
939 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
941 inp->flags |= SMB_PACKETFLAG_PROFILE_UPDATE_OK;
943 /* find the tree and free it */
944 uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
946 char *s1 = NULL, *s2 = NULL;
948 if (s2 == NULL) s2 = " ";
949 if (s1 == NULL) {s1 = s2; s2 = " ";}
951 osi_Log4(smb_logp, "SMB3 user logoffX uid %d name %s%s%s", uidp->userID,
952 osi_LogSaveString(smb_logp, (uidp->unp) ? uidp->unp->name: " "),
953 osi_LogSaveString(smb_logp,s1), osi_LogSaveString(smb_logp,s2));
955 lock_ObtainMutex(&uidp->mx);
956 uidp->flags |= SMB_USERFLAG_DELETE;
958 * it doesn't get deleted right away
959 * because the vcp points to it
961 lock_ReleaseMutex(&uidp->mx);
962 smb_ReleaseUID(uidp);
965 osi_Log0(smb_logp, "SMB3 user logoffX");
967 smb_SetSMBDataLength(outp, 0);
971 #define SMB_SUPPORT_SEARCH_BITS 0x0001
972 #define SMB_SHARE_IS_IN_DFS 0x0002
974 long smb_ReceiveV3TreeConnectX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
978 unsigned short newTid;
989 osi_Log0(smb_logp, "SMB3 receive tree connect");
991 /* parse input parameters */
992 tp = smb_GetSMBData(inp, NULL);
993 passwordp = smb_ParseString(tp, &tp);
994 pathp = smb_ParseString(tp, &tp);
995 if (smb_StoreAnsiFilenames)
996 OemToChar(pathp,pathp);
997 servicep = smb_ParseString(tp, &tp);
999 tp = strrchr(pathp, '\\');
1001 return CM_ERROR_BADSMB;
1003 strcpy(shareName, tp+1);
1005 osi_Log2(smb_logp, "Tree connect pathp[%s] shareName[%s]",
1006 osi_LogSaveString(smb_logp, pathp),
1007 osi_LogSaveString(smb_logp, shareName));
1009 if (strcmp(servicep, "IPC") == 0 || strcmp(shareName, "IPC$") == 0) {
1011 osi_Log0(smb_logp, "TreeConnectX connecting to IPC$");
1014 return CM_ERROR_NOIPC;
1018 userp = smb_GetUser(vcp, inp);
1020 lock_ObtainMutex(&vcp->mx);
1021 newTid = vcp->tidCounter++;
1022 lock_ReleaseMutex(&vcp->mx);
1024 tidp = smb_FindTID(vcp, newTid, SMB_FLAG_CREATE);
1027 uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
1028 shareFound = smb_FindShare(vcp, uidp, shareName, &sharePath);
1030 smb_ReleaseUID(uidp);
1032 smb_ReleaseTID(tidp);
1033 return CM_ERROR_BADSHARENAME;
1036 if (vcp->flags & SMB_VCFLAG_USENT)
1038 int policy = smb_FindShareCSCPolicy(shareName);
1039 smb_SetSMBParm(outp, 2, SMB_SUPPORT_SEARCH_BITS |
1041 SMB_SHARE_IS_IN_DFS |
1046 smb_SetSMBParm(outp, 2, 0);
1050 lock_ObtainMutex(&tidp->mx);
1051 tidp->userp = userp;
1052 tidp->pathname = sharePath;
1054 tidp->flags |= SMB_TIDFLAG_IPC;
1055 lock_ReleaseMutex(&tidp->mx);
1056 smb_ReleaseTID(tidp);
1058 ((smb_t *)outp)->tid = newTid;
1059 ((smb_t *)inp)->tid = newTid;
1060 tp = smb_GetSMBData(outp, NULL);
1062 /* XXX - why is this a drive letter? */
1071 smb_SetSMBDataLength(outp, 8);
1074 smb_SetSMBDataLength(outp, 4);
1077 osi_Log1(smb_logp, "SMB3 tree connect created ID %d", newTid);
1081 /* must be called with global tran lock held */
1082 smb_tran2Packet_t *smb_FindTran2Packet(smb_vc_t *vcp, smb_packet_t *inp)
1084 smb_tran2Packet_t *tp;
1087 smbp = (smb_t *) inp->data;
1088 for (tp = smb_tran2AssemblyQueuep; tp; tp = (smb_tran2Packet_t *) osi_QNext(&tp->q)) {
1089 if (tp->vcp == vcp && tp->mid == smbp->mid && tp->tid == smbp->tid)
1095 smb_tran2Packet_t *smb_NewTran2Packet(smb_vc_t *vcp, smb_packet_t *inp,
1096 int totalParms, int totalData)
1098 smb_tran2Packet_t *tp;
1101 smbp = (smb_t *) inp->data;
1102 tp = malloc(sizeof(*tp));
1103 memset(tp, 0, sizeof(*tp));
1106 tp->curData = tp->curParms = 0;
1107 tp->totalData = totalData;
1108 tp->totalParms = totalParms;
1109 tp->tid = smbp->tid;
1110 tp->mid = smbp->mid;
1111 tp->uid = smbp->uid;
1112 tp->pid = smbp->pid;
1113 tp->res[0] = smbp->res[0];
1114 osi_QAdd((osi_queue_t **)&smb_tran2AssemblyQueuep, &tp->q);
1115 if (totalParms != 0)
1116 tp->parmsp = malloc(totalParms);
1118 tp->datap = malloc(totalData);
1119 if (smbp->com == 0x25 || smbp->com == 0x26)
1122 tp->opcode = smb_GetSMBParm(inp, 14);
1125 tp->flags |= SMB_TRAN2PFLAG_ALLOC;
1129 smb_tran2Packet_t *smb_GetTran2ResponsePacket(smb_vc_t *vcp,
1130 smb_tran2Packet_t *inp, smb_packet_t *outp,
1131 int totalParms, int totalData)
1133 smb_tran2Packet_t *tp;
1134 unsigned short parmOffset;
1135 unsigned short dataOffset;
1136 unsigned short dataAlign;
1138 tp = malloc(sizeof(*tp));
1139 memset(tp, 0, sizeof(*tp));
1142 tp->curData = tp->curParms = 0;
1143 tp->totalData = totalData;
1144 tp->totalParms = totalParms;
1145 tp->oldTotalParms = totalParms;
1150 tp->res[0] = inp->res[0];
1151 tp->opcode = inp->opcode;
1155 * We calculate where the parameters and data will start.
1156 * This calculation must parallel the calculation in
1157 * smb_SendTran2Packet.
1160 parmOffset = 10*2 + 35;
1161 parmOffset++; /* round to even */
1162 tp->parmsp = (unsigned short *) (outp->data + parmOffset);
1164 dataOffset = parmOffset + totalParms;
1165 dataAlign = dataOffset & 2; /* quad-align */
1166 dataOffset += dataAlign;
1167 tp->datap = outp->data + dataOffset;
1172 /* free a tran2 packet; must be called with smb_globalLock held */
1173 void smb_FreeTran2Packet(smb_tran2Packet_t *t2p)
1176 smb_ReleaseVC(t2p->vcp);
1177 if (t2p->flags & SMB_TRAN2PFLAG_ALLOC) {
1186 /* called with a VC, an input packet to respond to, and an error code.
1187 * sends an error response.
1189 void smb_SendTran2Error(smb_vc_t *vcp, smb_tran2Packet_t *t2p,
1190 smb_packet_t *tp, long code)
1193 unsigned short errCode;
1194 unsigned char errClass;
1195 unsigned long NTStatus;
1197 if (vcp->flags & SMB_VCFLAG_STATUS32)
1198 smb_MapNTError(code, &NTStatus);
1200 smb_MapCoreError(code, vcp, &errCode, &errClass);
1202 smb_FormatResponsePacket(vcp, NULL, tp);
1203 smbp = (smb_t *) tp;
1205 /* We can handle long names */
1206 if (vcp->flags & SMB_VCFLAG_USENT)
1207 smbp->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
1209 /* now copy important fields from the tran 2 packet */
1210 smbp->com = t2p->com;
1211 smbp->tid = t2p->tid;
1212 smbp->mid = t2p->mid;
1213 smbp->pid = t2p->pid;
1214 smbp->uid = t2p->uid;
1215 smbp->res[0] = t2p->res[0];
1216 if (vcp->flags & SMB_VCFLAG_STATUS32) {
1217 smbp->rcls = (unsigned char) (NTStatus & 0xff);
1218 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
1219 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
1220 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
1221 smbp->flg2 |= SMB_FLAGS2_32BIT_STATUS;
1224 smbp->rcls = errClass;
1225 smbp->errLow = (unsigned char) (errCode & 0xff);
1226 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
1230 smb_SendPacket(vcp, tp);
1233 void smb_SendTran2Packet(smb_vc_t *vcp, smb_tran2Packet_t *t2p, smb_packet_t *tp)
1236 unsigned short parmOffset;
1237 unsigned short dataOffset;
1238 unsigned short totalLength;
1239 unsigned short dataAlign;
1242 smb_FormatResponsePacket(vcp, NULL, tp);
1243 smbp = (smb_t *) tp;
1245 /* We can handle long names */
1246 if (vcp->flags & SMB_VCFLAG_USENT)
1247 smbp->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
1249 /* now copy important fields from the tran 2 packet */
1250 smbp->com = t2p->com;
1251 smbp->tid = t2p->tid;
1252 smbp->mid = t2p->mid;
1253 smbp->pid = t2p->pid;
1254 smbp->uid = t2p->uid;
1255 smbp->res[0] = t2p->res[0];
1257 totalLength = 1 + t2p->totalData + t2p->totalParms;
1259 /* now add the core parameters (tran2 info) to the packet */
1260 smb_SetSMBParm(tp, 0, t2p->totalParms); /* parm bytes */
1261 smb_SetSMBParm(tp, 1, t2p->totalData); /* data bytes */
1262 smb_SetSMBParm(tp, 2, 0); /* reserved */
1263 smb_SetSMBParm(tp, 3, t2p->totalParms); /* parm bytes in this packet */
1264 parmOffset = 10*2 + 35; /* parm offset in packet */
1265 parmOffset++; /* round to even */
1266 smb_SetSMBParm(tp, 4, parmOffset); /* 11 parm words plus *
1267 * hdr, bcc and wct */
1268 smb_SetSMBParm(tp, 5, 0); /* parm displacement */
1269 smb_SetSMBParm(tp, 6, t2p->totalData); /* data in this packet */
1270 dataOffset = parmOffset + t2p->oldTotalParms;
1271 dataAlign = dataOffset & 2; /* quad-align */
1272 dataOffset += dataAlign;
1273 smb_SetSMBParm(tp, 7, dataOffset); /* offset of data */
1274 smb_SetSMBParm(tp, 8, 0); /* data displacement */
1275 smb_SetSMBParm(tp, 9, 0); /* low: setup word count *
1278 datap = smb_GetSMBData(tp, NULL);
1279 *datap++ = 0; /* we rounded to even */
1281 totalLength += dataAlign;
1282 smb_SetSMBDataLength(tp, totalLength);
1284 /* next, send the datagram */
1285 smb_SendPacket(vcp, tp);
1288 long smb_ReceiveV3Trans(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
1290 smb_tran2Packet_t *asp;
1303 /* We sometimes see 0 word count. What to do? */
1304 if (*inp->wctp == 0) {
1305 osi_Log0(smb_logp, "Transaction2 word count = 0");
1307 LogEvent(EVENTLOG_WARNING_TYPE, MSG_SMB_ZERO_TRANSACTION_COUNT);
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_Log4(smb_logp,"AFS Server - Dispatch-RAP %s vcp[%p] lana[%d] lsn[%d]",myCrt_RapDispatch(rapOp),vcp,vcp->lana,vcp->lsn);
1381 code = (*smb_rapDispatchTable[rapOp].procp)(vcp, asp, outp);
1382 osi_Log4(smb_logp,"AFS Server - Dispatch-RAP return code 0x%x vcp[%x] lana[%d] lsn[%d]",code,vcp,vcp->lana,vcp->lsn);
1385 osi_Log4(smb_logp,"AFS Server - Dispatch-RAP [INVALID] op[%x] vcp[%p] lana[%d] lsn[%d]", rapOp, vcp, vcp->lana, vcp->lsn);
1386 code = CM_ERROR_BADOP;
1389 /* if an error is returned, we're supposed to send an error packet,
1390 * otherwise the dispatched function already did the data sending.
1391 * We give dispatched proc the responsibility since it knows how much
1392 * space to allocate.
1395 smb_SendTran2Error(vcp, asp, outp, code);
1398 /* free the input tran 2 packet */
1399 lock_ObtainWrite(&smb_globalLock);
1400 smb_FreeTran2Packet(asp);
1401 lock_ReleaseWrite(&smb_globalLock);
1403 else if (firstPacket) {
1404 /* the first packet in a multi-packet request, we need to send an
1405 * ack to get more data.
1407 smb_SetSMBDataLength(outp, 0);
1408 smb_SendPacket(vcp, outp);
1414 /* ANSI versions. The unicode versions support arbitrary length
1415 share names, but we don't support unicode yet. */
1417 typedef struct smb_rap_share_info_0 {
1418 char shi0_netname[13];
1419 } smb_rap_share_info_0_t;
1421 typedef struct smb_rap_share_info_1 {
1422 char shi1_netname[13];
1425 DWORD shi1_remark; /* char *shi1_remark; data offset */
1426 } smb_rap_share_info_1_t;
1428 typedef struct smb_rap_share_info_2 {
1429 char shi2_netname[13];
1431 unsigned short shi2_type;
1432 DWORD shi2_remark; /* char *shi2_remark; data offset */
1433 unsigned short shi2_permissions;
1434 unsigned short shi2_max_uses;
1435 unsigned short shi2_current_uses;
1436 DWORD shi2_path; /* char *shi2_path; data offset */
1437 unsigned short shi2_passwd[9];
1438 unsigned short shi2_pad2;
1439 } smb_rap_share_info_2_t;
1441 #define SMB_RAP_MAX_SHARES 512
1443 typedef struct smb_rap_share_list {
1446 smb_rap_share_info_0_t * shares;
1447 } smb_rap_share_list_t;
1449 int smb_rapCollectSharesProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp) {
1450 smb_rap_share_list_t * sp;
1455 if (name[0] == '.' && (!name[1] || (name[1] == '.' && !name[2])))
1456 return 0; /* skip over '.' and '..' */
1458 sp = (smb_rap_share_list_t *) vrockp;
1460 strncpy(sp->shares[sp->cShare].shi0_netname, name, 12);
1461 sp->shares[sp->cShare].shi0_netname[12] = 0;
1465 if (sp->cShare >= sp->maxShares)
1466 return CM_ERROR_STOPNOW;
1471 long smb_ReceiveRAPNetShareEnum(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1473 smb_tran2Packet_t *outp;
1474 unsigned short * tp;
1478 int outParmsTotal; /* total parameter bytes */
1479 int outDataTotal; /* total data bytes */
1487 HKEY hkSubmount = NULL;
1488 smb_rap_share_info_1_t * shares;
1491 char thisShare[256];
1494 smb_rap_share_list_t rootShares;
1499 tp = p->parmsp + 1; /* skip over function number (always 0) */
1500 (void) smb_ParseString((char *) tp, (char **) &tp); /* skip over parm descriptor */
1501 (void) smb_ParseString((char *) tp, (char **) &tp); /* skip over data descriptor */
1505 if (infoLevel != 1) {
1506 return CM_ERROR_INVAL;
1509 /* first figure out how many shares there are */
1510 rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY, 0,
1511 KEY_QUERY_VALUE, &hkParam);
1512 if (rv == ERROR_SUCCESS) {
1513 len = sizeof(allSubmount);
1514 rv = RegQueryValueEx(hkParam, "AllSubmount", NULL, NULL,
1515 (BYTE *) &allSubmount, &len);
1516 if (rv != ERROR_SUCCESS || allSubmount != 0) {
1519 RegCloseKey (hkParam);
1522 rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_OPENAFS_SUBKEY "\\Submounts",
1523 0, KEY_QUERY_VALUE, &hkSubmount);
1524 if (rv == ERROR_SUCCESS) {
1525 rv = RegQueryInfoKey(hkSubmount, NULL, NULL, NULL, NULL,
1526 NULL, NULL, &nRegShares, NULL, NULL, NULL, NULL);
1527 if (rv != ERROR_SUCCESS)
1533 /* fetch the root shares */
1534 rootShares.maxShares = SMB_RAP_MAX_SHARES;
1535 rootShares.cShare = 0;
1536 rootShares.shares = malloc( sizeof(smb_rap_share_info_0_t) * SMB_RAP_MAX_SHARES );
1540 userp = smb_GetTran2User(vcp,p);
1542 thyper.HighPart = 0;
1545 cm_HoldSCache(cm_data.rootSCachep);
1546 cm_ApplyDir(cm_data.rootSCachep, smb_rapCollectSharesProc, &rootShares, &thyper, userp, &req, NULL);
1547 cm_ReleaseSCache(cm_data.rootSCachep);
1549 cm_ReleaseUser(userp);
1551 nShares = (USHORT)(rootShares.cShare + nRegShares + allSubmount);
1553 #define REMARK_LEN 1
1554 outParmsTotal = 8; /* 4 dwords */
1555 outDataTotal = (sizeof(smb_rap_share_info_1_t) + REMARK_LEN) * nShares ;
1556 if(outDataTotal > bufsize) {
1557 nSharesRet = bufsize / (sizeof(smb_rap_share_info_1_t) + REMARK_LEN);
1558 outDataTotal = (sizeof(smb_rap_share_info_1_t) + REMARK_LEN) * nSharesRet;
1561 nSharesRet = nShares;
1564 outp = smb_GetTran2ResponsePacket(vcp, p, op, outParmsTotal, outDataTotal);
1566 /* now for the submounts */
1567 shares = (smb_rap_share_info_1_t *) outp->datap;
1568 cstrp = outp->datap + sizeof(smb_rap_share_info_1_t) * nSharesRet;
1570 memset(outp->datap, 0, (sizeof(smb_rap_share_info_1_t) + REMARK_LEN) * nSharesRet);
1573 strcpy( shares[cshare].shi1_netname, "all" );
1574 shares[cshare].shi1_remark = (DWORD)(cstrp - outp->datap);
1575 /* type and pad are zero already */
1581 for (i=0; i < nRegShares && cshare < nSharesRet; i++) {
1582 len = sizeof(thisShare);
1583 rv = RegEnumValue(hkSubmount, i, thisShare, &len, NULL, NULL, NULL, NULL);
1584 if (rv == ERROR_SUCCESS && strlen(thisShare) && (!allSubmount || stricmp(thisShare,"all"))) {
1585 strncpy(shares[cshare].shi1_netname, thisShare, sizeof(shares->shi1_netname)-1);
1586 shares[cshare].shi1_netname[sizeof(shares->shi1_netname)-1] = 0; /* unfortunate truncation */
1587 shares[cshare].shi1_remark = (DWORD)(cstrp - outp->datap);
1592 nShares--; /* uncount key */
1595 RegCloseKey(hkSubmount);
1598 nonrootShares = cshare;
1600 for (i=0; i < rootShares.cShare && cshare < nSharesRet; i++) {
1601 /* in case there are collisions with submounts, submounts have higher priority */
1602 for (j=0; j < nonrootShares; j++)
1603 if (!stricmp(shares[j].shi1_netname, rootShares.shares[i].shi0_netname))
1606 if (j < nonrootShares) {
1607 nShares--; /* uncount */
1611 strcpy(shares[cshare].shi1_netname, rootShares.shares[i].shi0_netname);
1612 shares[cshare].shi1_remark = (DWORD)(cstrp - outp->datap);
1617 outp->parmsp[0] = ((cshare == nShares)? ERROR_SUCCESS : ERROR_MORE_DATA);
1618 outp->parmsp[1] = 0;
1619 outp->parmsp[2] = cshare;
1620 outp->parmsp[3] = nShares;
1622 outp->totalData = (int)(cstrp - outp->datap);
1623 outp->totalParms = outParmsTotal;
1625 smb_SendTran2Packet(vcp, outp, op);
1626 smb_FreeTran2Packet(outp);
1628 free(rootShares.shares);
1633 long smb_ReceiveRAPNetShareGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1635 smb_tran2Packet_t *outp;
1636 unsigned short * tp;
1638 BOOL shareFound = FALSE;
1639 unsigned short infoLevel;
1640 unsigned short bufsize;
1650 tp = p->parmsp + 1; /* skip over function number (always 1) */
1651 (void) smb_ParseString( (char *) tp, (char **) &tp); /* skip over param descriptor */
1652 (void) smb_ParseString( (char *) tp, (char **) &tp); /* skip over data descriptor */
1653 shareName = smb_ParseString( (char *) tp, (char **) &tp);
1660 totalData = sizeof(smb_rap_share_info_0_t);
1661 else if(infoLevel == SMB_INFO_STANDARD)
1662 totalData = sizeof(smb_rap_share_info_1_t) + 1; /* + empty string */
1663 else if(infoLevel == SMB_INFO_QUERY_EA_SIZE)
1664 totalData = sizeof(smb_rap_share_info_2_t) + 2; /* + two empty strings */
1666 return CM_ERROR_INVAL;
1668 outp = smb_GetTran2ResponsePacket(vcp, p, op, totalParam, totalData);
1670 if(!stricmp(shareName,"all")) {
1671 rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY, 0,
1672 KEY_QUERY_VALUE, &hkParam);
1673 if (rv == ERROR_SUCCESS) {
1674 len = sizeof(allSubmount);
1675 rv = RegQueryValueEx(hkParam, "AllSubmount", NULL, NULL,
1676 (BYTE *) &allSubmount, &len);
1677 if (rv != ERROR_SUCCESS || allSubmount != 0) {
1680 RegCloseKey (hkParam);
1687 rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY "\\Submounts", 0,
1688 KEY_QUERY_VALUE, &hkSubmount);
1689 if (rv == ERROR_SUCCESS) {
1690 rv = RegQueryValueEx(hkSubmount, shareName, NULL, NULL, NULL, NULL);
1691 if (rv == ERROR_SUCCESS) {
1694 RegCloseKey(hkSubmount);
1699 smb_FreeTran2Packet(outp);
1700 return CM_ERROR_BADSHARENAME;
1703 memset(outp->datap, 0, totalData);
1705 outp->parmsp[0] = 0;
1706 outp->parmsp[1] = 0;
1707 outp->parmsp[2] = totalData;
1709 if (infoLevel == 0) {
1710 smb_rap_share_info_0_t * info = (smb_rap_share_info_0_t *) outp->datap;
1711 strncpy(info->shi0_netname, shareName, sizeof(info->shi0_netname)-1);
1712 info->shi0_netname[sizeof(info->shi0_netname)-1] = 0;
1713 } else if(infoLevel == SMB_INFO_STANDARD) {
1714 smb_rap_share_info_1_t * info = (smb_rap_share_info_1_t *) outp->datap;
1715 strncpy(info->shi1_netname, shareName, sizeof(info->shi1_netname)-1);
1716 info->shi1_netname[sizeof(info->shi1_netname)-1] = 0;
1717 info->shi1_remark = (DWORD)(((unsigned char *) (info + 1)) - outp->datap);
1718 /* type and pad are already zero */
1719 } else { /* infoLevel==2 */
1720 smb_rap_share_info_2_t * info = (smb_rap_share_info_2_t *) outp->datap;
1721 strncpy(info->shi2_netname, shareName, sizeof(info->shi2_netname)-1);
1722 info->shi2_netname[sizeof(info->shi2_netname)-1] = 0;
1723 info->shi2_remark = (DWORD)(((unsigned char *) (info + 1)) - outp->datap);
1724 info->shi2_permissions = ACCESS_ALL;
1725 info->shi2_max_uses = (unsigned short) -1;
1726 info->shi2_path = (DWORD)(1 + (((unsigned char *) (info + 1)) - outp->datap));
1729 outp->totalData = totalData;
1730 outp->totalParms = totalParam;
1732 smb_SendTran2Packet(vcp, outp, op);
1733 smb_FreeTran2Packet(outp);
1738 typedef struct smb_rap_wksta_info_10 {
1739 DWORD wki10_computername; /*char *wki10_computername;*/
1740 DWORD wki10_username; /* char *wki10_username; */
1741 DWORD wki10_langroup; /* char *wki10_langroup;*/
1742 unsigned char wki10_ver_major;
1743 unsigned char wki10_ver_minor;
1744 DWORD wki10_logon_domain; /*char *wki10_logon_domain;*/
1745 DWORD wki10_oth_domains; /* char *wki10_oth_domains;*/
1746 } smb_rap_wksta_info_10_t;
1749 long smb_ReceiveRAPNetWkstaGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1751 smb_tran2Packet_t *outp;
1755 unsigned short * tp;
1758 smb_rap_wksta_info_10_t * info;
1762 tp = p->parmsp + 1; /* Skip over function number */
1763 (void) smb_ParseString((unsigned char*) tp, (char **) &tp); /* skip over param descriptor */
1764 (void) smb_ParseString((unsigned char*) tp, (char **) &tp); /* skip over data descriptor */
1768 if (infoLevel != 10) {
1769 return CM_ERROR_INVAL;
1775 totalData = sizeof(*info) + /* info */
1776 MAX_COMPUTERNAME_LENGTH + /* wki10_computername */
1777 SMB_MAX_USERNAME_LENGTH + /* wki10_username */
1778 MAX_COMPUTERNAME_LENGTH + /* wki10_langroup */
1779 MAX_COMPUTERNAME_LENGTH + /* wki10_logon_domain */
1780 1; /* wki10_oth_domains (null)*/
1782 outp = smb_GetTran2ResponsePacket(vcp, p, op, totalParams, totalData);
1784 memset(outp->parmsp,0,totalParams);
1785 memset(outp->datap,0,totalData);
1787 info = (smb_rap_wksta_info_10_t *) outp->datap;
1788 cstrp = (char *) (info + 1);
1790 info->wki10_computername = (DWORD) (cstrp - outp->datap);
1791 strcpy(cstrp, smb_localNamep);
1792 cstrp += strlen(cstrp) + 1;
1794 info->wki10_username = (DWORD) (cstrp - outp->datap);
1795 uidp = smb_FindUID(vcp, p->uid, 0);
1797 lock_ObtainMutex(&uidp->mx);
1798 if(uidp->unp && uidp->unp->name)
1799 strcpy(cstrp, uidp->unp->name);
1800 lock_ReleaseMutex(&uidp->mx);
1801 smb_ReleaseUID(uidp);
1803 cstrp += strlen(cstrp) + 1;
1805 info->wki10_langroup = (DWORD) (cstrp - outp->datap);
1806 strcpy(cstrp, "WORKGROUP");
1807 cstrp += strlen(cstrp) + 1;
1809 /* TODO: Not sure what values these should take, but these work */
1810 info->wki10_ver_major = 5;
1811 info->wki10_ver_minor = 1;
1813 info->wki10_logon_domain = (DWORD) (cstrp - outp->datap);
1814 strcpy(cstrp, smb_ServerDomainName);
1815 cstrp += strlen(cstrp) + 1;
1817 info->wki10_oth_domains = (DWORD) (cstrp - outp->datap);
1818 cstrp ++; /* no other domains */
1820 outp->totalData = (unsigned short) (cstrp - outp->datap); /* actual data size */
1821 outp->parmsp[2] = outp->totalData;
1822 outp->totalParms = totalParams;
1824 smb_SendTran2Packet(vcp,outp,op);
1825 smb_FreeTran2Packet(outp);
1830 typedef struct smb_rap_server_info_0 {
1832 } smb_rap_server_info_0_t;
1834 typedef struct smb_rap_server_info_1 {
1836 char sv1_version_major;
1837 char sv1_version_minor;
1838 unsigned long sv1_type;
1839 DWORD *sv1_comment_or_master_browser; /* char *sv1_comment_or_master_browser;*/
1840 } smb_rap_server_info_1_t;
1842 char smb_ServerComment[] = "OpenAFS Client";
1843 int smb_ServerCommentLen = sizeof(smb_ServerComment);
1845 #define SMB_SV_TYPE_SERVER 0x00000002L
1846 #define SMB_SV_TYPE_NT 0x00001000L
1847 #define SMB_SV_TYPE_SERVER_NT 0x00008000L
1849 long smb_ReceiveRAPNetServerGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1851 smb_tran2Packet_t *outp;
1855 unsigned short * tp;
1858 smb_rap_server_info_0_t * info0;
1859 smb_rap_server_info_1_t * info1;
1862 tp = p->parmsp + 1; /* Skip over function number */
1863 (void) smb_ParseString((unsigned char*) tp, (char **) &tp); /* skip over param descriptor */
1864 (void) smb_ParseString((unsigned char*) tp, (char **) &tp); /* skip over data descriptor */
1868 if (infoLevel != 0 && infoLevel != 1) {
1869 return CM_ERROR_INVAL;
1875 (infoLevel == 0) ? sizeof(smb_rap_server_info_0_t)
1876 : (sizeof(smb_rap_server_info_1_t) + smb_ServerCommentLen);
1878 outp = smb_GetTran2ResponsePacket(vcp, p, op, totalParams, totalData);
1880 memset(outp->parmsp,0,totalParams);
1881 memset(outp->datap,0,totalData);
1883 if (infoLevel == 0) {
1884 info0 = (smb_rap_server_info_0_t *) outp->datap;
1885 cstrp = (char *) (info0 + 1);
1886 strcpy(info0->sv0_name, "AFS");
1887 } else { /* infoLevel == SMB_INFO_STANDARD */
1888 info1 = (smb_rap_server_info_1_t *) outp->datap;
1889 cstrp = (char *) (info1 + 1);
1890 strcpy(info1->sv1_name, "AFS");
1893 SMB_SV_TYPE_SERVER |
1895 SMB_SV_TYPE_SERVER_NT;
1897 info1->sv1_version_major = 5;
1898 info1->sv1_version_minor = 1;
1899 info1->sv1_comment_or_master_browser = (DWORD *) (cstrp - outp->datap);
1901 strcpy(cstrp, smb_ServerComment);
1903 cstrp += smb_ServerCommentLen;
1906 totalData = (DWORD)(cstrp - outp->datap);
1907 outp->totalData = min(bufsize,totalData); /* actual data size */
1908 outp->parmsp[0] = (outp->totalData == totalData)? 0 : ERROR_MORE_DATA;
1909 outp->parmsp[2] = totalData;
1910 outp->totalParms = totalParams;
1912 smb_SendTran2Packet(vcp,outp,op);
1913 smb_FreeTran2Packet(outp);
1918 long smb_ReceiveV3Tran2A(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
1920 smb_tran2Packet_t *asp;
1932 /* We sometimes see 0 word count. What to do? */
1933 if (*inp->wctp == 0) {
1934 osi_Log0(smb_logp, "Transaction2 word count = 0");
1936 LogEvent(EVENTLOG_WARNING_TYPE, MSG_SMB_ZERO_TRANSACTION_COUNT);
1939 smb_SetSMBDataLength(outp, 0);
1940 smb_SendPacket(vcp, outp);
1944 totalParms = smb_GetSMBParm(inp, 0);
1945 totalData = smb_GetSMBParm(inp, 1);
1947 firstPacket = (inp->inCom == 0x32);
1949 /* find the packet we're reassembling */
1950 lock_ObtainWrite(&smb_globalLock);
1951 asp = smb_FindTran2Packet(vcp, inp);
1953 asp = smb_NewTran2Packet(vcp, inp, totalParms, totalData);
1955 lock_ReleaseWrite(&smb_globalLock);
1957 /* now merge in this latest packet; start by looking up offsets */
1959 parmDisp = dataDisp = 0;
1960 parmOffset = smb_GetSMBParm(inp, 10);
1961 dataOffset = smb_GetSMBParm(inp, 12);
1962 parmCount = smb_GetSMBParm(inp, 9);
1963 dataCount = smb_GetSMBParm(inp, 11);
1964 asp->maxReturnParms = smb_GetSMBParm(inp, 2);
1965 asp->maxReturnData = smb_GetSMBParm(inp, 3);
1967 osi_Log3(smb_logp, "SMB3 received T2 init packet total data %d, cur data %d, max return data %d",
1968 totalData, dataCount, asp->maxReturnData);
1971 parmDisp = smb_GetSMBParm(inp, 4);
1972 parmOffset = smb_GetSMBParm(inp, 3);
1973 dataDisp = smb_GetSMBParm(inp, 7);
1974 dataOffset = smb_GetSMBParm(inp, 6);
1975 parmCount = smb_GetSMBParm(inp, 2);
1976 dataCount = smb_GetSMBParm(inp, 5);
1978 osi_Log2(smb_logp, "SMB3 received T2 aux packet parms %d, data %d",
1979 parmCount, dataCount);
1982 /* now copy the parms and data */
1983 if ( asp->totalParms > 0 && parmCount != 0 )
1985 memcpy(((char *)asp->parmsp) + parmDisp, inp->data + parmOffset, parmCount);
1987 if ( asp->totalData > 0 && dataCount != 0 ) {
1988 memcpy(asp->datap + dataDisp, inp->data + dataOffset, dataCount);
1991 /* account for new bytes */
1992 asp->curData += dataCount;
1993 asp->curParms += parmCount;
1995 /* finally, if we're done, remove the packet from the queue and dispatch it */
1996 if (asp->totalParms > 0 &&
1997 asp->curParms > 0 &&
1998 asp->totalData <= asp->curData &&
1999 asp->totalParms <= asp->curParms) {
2000 /* we've received it all */
2001 lock_ObtainWrite(&smb_globalLock);
2002 osi_QRemove((osi_queue_t **) &smb_tran2AssemblyQueuep, &asp->q);
2003 lock_ReleaseWrite(&smb_globalLock);
2005 /* now dispatch it */
2006 if ( asp->opcode >= 0 && asp->opcode < 20 && smb_tran2DispatchTable[asp->opcode].procp) {
2007 osi_Log4(smb_logp,"AFS Server - Dispatch-2 %s vcp[%p] lana[%d] lsn[%d]",myCrt_2Dispatch(asp->opcode),vcp,vcp->lana,vcp->lsn);
2008 code = (*smb_tran2DispatchTable[asp->opcode].procp)(vcp, asp, outp);
2011 osi_Log4(smb_logp,"AFS Server - Dispatch-2 [INVALID] op[%x] vcp[%p] lana[%d] lsn[%d]", asp->opcode, vcp, vcp->lana, vcp->lsn);
2012 code = CM_ERROR_BADOP;
2015 /* if an error is returned, we're supposed to send an error packet,
2016 * otherwise the dispatched function already did the data sending.
2017 * We give dispatched proc the responsibility since it knows how much
2018 * space to allocate.
2021 smb_SendTran2Error(vcp, asp, outp, code);
2024 /* free the input tran 2 packet */
2025 lock_ObtainWrite(&smb_globalLock);
2026 smb_FreeTran2Packet(asp);
2027 lock_ReleaseWrite(&smb_globalLock);
2029 else if (firstPacket) {
2030 /* the first packet in a multi-packet request, we need to send an
2031 * ack to get more data.
2033 smb_SetSMBDataLength(outp, 0);
2034 smb_SendPacket(vcp, outp);
2040 long smb_ReceiveTran2Open(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
2043 smb_tran2Packet_t *outp;
2048 cm_scache_t *dscp; /* dir we're dealing with */
2049 cm_scache_t *scp; /* file we're creating */
2051 int initialModeBits;
2061 int parmSlot; /* which parm we're dealing with */
2062 long returnEALength;
2070 extraInfo = (p->parmsp[0] & 1); /* return extra info */
2071 returnEALength = (p->parmsp[0] & 8); /* return extended attr length */
2073 openFun = p->parmsp[6]; /* open function */
2074 excl = ((openFun & 3) == 0);
2075 trunc = ((openFun & 3) == 2); /* truncate it */
2076 openMode = (p->parmsp[1] & 0x7);
2077 openAction = 0; /* tracks what we did */
2079 attributes = p->parmsp[3];
2080 dosTime = p->parmsp[4] | (p->parmsp[5] << 16);
2082 /* compute initial mode bits based on read-only flag in attributes */
2083 initialModeBits = 0666;
2085 initialModeBits &= ~0222;
2087 pathp = (char *) (&p->parmsp[14]);
2088 if (smb_StoreAnsiFilenames)
2089 OemToChar(pathp,pathp);
2091 outp = smb_GetTran2ResponsePacket(vcp, p, op, 40, 0);
2093 spacep = cm_GetSpace();
2094 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
2096 if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
2097 /* special case magic file name for receiving IOCTL requests
2098 * (since IOCTL calls themselves aren't getting through).
2100 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
2101 smb_SetupIoctlFid(fidp, spacep);
2103 /* copy out remainder of the parms */
2105 outp->parmsp[parmSlot++] = fidp->fid;
2107 outp->parmsp[parmSlot++] = 0; /* attrs */
2108 outp->parmsp[parmSlot++] = 0; /* mod time */
2109 outp->parmsp[parmSlot++] = 0;
2110 outp->parmsp[parmSlot++] = 0; /* len */
2111 outp->parmsp[parmSlot++] = 0x7fff;
2112 outp->parmsp[parmSlot++] = openMode;
2113 outp->parmsp[parmSlot++] = 0; /* file type 0 ==> normal file or dir */
2114 outp->parmsp[parmSlot++] = 0; /* IPC junk */
2116 /* and the final "always present" stuff */
2117 outp->parmsp[parmSlot++] = 1; /* openAction found existing file */
2118 /* next write out the "unique" ID */
2119 outp->parmsp[parmSlot++] = 0x1234;
2120 outp->parmsp[parmSlot++] = 0x5678;
2121 outp->parmsp[parmSlot++] = 0;
2122 if (returnEALength) {
2123 outp->parmsp[parmSlot++] = 0;
2124 outp->parmsp[parmSlot++] = 0;
2127 outp->totalData = 0;
2128 outp->totalParms = parmSlot * 2;
2130 smb_SendTran2Packet(vcp, outp, op);
2132 smb_FreeTran2Packet(outp);
2134 /* and clean up fid reference */
2135 smb_ReleaseFID(fidp);
2139 #ifdef DEBUG_VERBOSE
2141 char *hexp, *asciip;
2142 asciip = (lastNamep ? lastNamep : pathp);
2143 hexp = osi_HexifyString( asciip );
2144 DEBUG_EVENT2("AFS","T2Open H[%s] A[%s]", hexp, asciip);
2149 userp = smb_GetTran2User(vcp, p);
2150 /* In the off chance that userp is NULL, we log and abandon */
2152 osi_Log1(smb_logp, "ReceiveTran2Open user [%d] not resolvable", p->uid);
2153 smb_FreeTran2Packet(outp);
2154 return CM_ERROR_BADSMB;
2157 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
2158 if (code == CM_ERROR_TIDIPC) {
2159 /* Attempt to use a TID allocated for IPC. The client
2160 * is probably looking for DCE RPC end points which we
2161 * don't support OR it could be looking to make a DFS
2164 osi_Log0(smb_logp, "Tran2Open received IPC TID");
2166 cm_ReleaseUser(userp);
2167 smb_FreeTran2Packet(outp);
2168 return CM_ERROR_NOSUCHPATH;
2173 code = cm_NameI(cm_data.rootSCachep, pathp,
2174 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
2175 userp, tidPathp, &req, &scp);
2177 code = cm_NameI(cm_data.rootSCachep, spacep->data,
2178 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
2179 userp, tidPathp, &req, &dscp);
2180 cm_FreeSpace(spacep);
2183 cm_ReleaseUser(userp);
2184 smb_FreeTran2Packet(outp);
2189 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
2190 cm_ReleaseSCache(dscp);
2191 cm_ReleaseUser(userp);
2192 smb_FreeTran2Packet(outp);
2193 if ( WANTS_DFS_PATHNAMES(p) )
2194 return CM_ERROR_PATH_NOT_COVERED;
2196 return CM_ERROR_BADSHARENAME;
2198 #endif /* DFS_SUPPORT */
2200 /* otherwise, scp points to the parent directory. Do a lookup,
2201 * and truncate the file if we find it, otherwise we create the
2208 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD, userp,
2210 if (code && code != CM_ERROR_NOSUCHFILE) {
2211 cm_ReleaseSCache(dscp);
2212 cm_ReleaseUser(userp);
2213 smb_FreeTran2Packet(outp);
2218 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
2219 cm_ReleaseSCache(scp);
2220 cm_ReleaseUser(userp);
2221 smb_FreeTran2Packet(outp);
2222 if ( WANTS_DFS_PATHNAMES(p) )
2223 return CM_ERROR_PATH_NOT_COVERED;
2225 return CM_ERROR_BADSHARENAME;
2227 #endif /* DFS_SUPPORT */
2229 /* macintosh is expensive to program for it */
2230 cm_FreeSpace(spacep);
2233 /* if we get here, if code is 0, the file exists and is represented by
2234 * scp. Otherwise, we have to create it.
2237 code = cm_CheckOpen(scp, openMode, trunc, userp, &req);
2240 cm_ReleaseSCache(dscp);
2241 cm_ReleaseSCache(scp);
2242 cm_ReleaseUser(userp);
2243 smb_FreeTran2Packet(outp);
2248 /* oops, file shouldn't be there */
2250 cm_ReleaseSCache(dscp);
2251 cm_ReleaseSCache(scp);
2252 cm_ReleaseUser(userp);
2253 smb_FreeTran2Packet(outp);
2254 return CM_ERROR_EXISTS;
2258 setAttr.mask = CM_ATTRMASK_LENGTH;
2259 setAttr.length.LowPart = 0;
2260 setAttr.length.HighPart = 0;
2261 code = cm_SetAttr(scp, &setAttr, userp, &req);
2262 openAction = 3; /* truncated existing file */
2265 openAction = 1; /* found existing file */
2267 else if (!(openFun & 0x10)) {
2268 /* don't create if not found */
2270 cm_ReleaseSCache(dscp);
2271 osi_assert(scp == NULL);
2272 cm_ReleaseUser(userp);
2273 smb_FreeTran2Packet(outp);
2274 return CM_ERROR_NOSUCHFILE;
2277 osi_assert(dscp != NULL && scp == NULL);
2278 openAction = 2; /* created file */
2279 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
2280 smb_UnixTimeFromSearchTime(&setAttr.clientModTime, dosTime);
2281 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
2283 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
2284 smb_NotifyChange(FILE_ACTION_ADDED,
2285 FILE_NOTIFY_CHANGE_FILE_NAME,
2286 dscp, lastNamep, NULL, TRUE);
2287 if (!excl && code == CM_ERROR_EXISTS) {
2288 /* not an exclusive create, and someone else tried
2289 * creating it already, then we open it anyway. We
2290 * don't bother retrying after this, since if this next
2291 * fails, that means that the file was deleted after we
2292 * started this call.
2294 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
2298 setAttr.mask = CM_ATTRMASK_LENGTH;
2299 setAttr.length.LowPart = 0;
2300 setAttr.length.HighPart = 0;
2301 code = cm_SetAttr(scp, &setAttr, userp,
2304 } /* lookup succeeded */
2308 /* we don't need this any longer */
2310 cm_ReleaseSCache(dscp);
2313 /* something went wrong creating or truncating the file */
2315 cm_ReleaseSCache(scp);
2316 cm_ReleaseUser(userp);
2317 smb_FreeTran2Packet(outp);
2321 /* make sure we're about to open a file */
2322 if (scp->fileType != CM_SCACHETYPE_FILE) {
2324 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
2325 cm_scache_t * targetScp = 0;
2326 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
2328 /* we have a more accurate file to use (the
2329 * target of the symbolic link). Otherwise,
2330 * we'll just use the symlink anyway.
2332 osi_Log2(smb_logp, "symlink vp %x to vp %x",
2334 cm_ReleaseSCache(scp);
2338 if (scp->fileType != CM_SCACHETYPE_FILE) {
2339 cm_ReleaseSCache(scp);
2340 cm_ReleaseUser(userp);
2341 smb_FreeTran2Packet(outp);
2342 return CM_ERROR_ISDIR;
2346 /* now all we have to do is open the file itself */
2347 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
2350 /* save a pointer to the vnode */
2354 fidp->userp = userp;
2356 /* compute open mode */
2357 if (openMode != 1) fidp->flags |= SMB_FID_OPENREAD;
2358 if (openMode == 1 || openMode == 2)
2359 fidp->flags |= SMB_FID_OPENWRITE;
2361 smb_ReleaseFID(fidp);
2363 cm_Open(scp, 0, userp);
2365 /* copy out remainder of the parms */
2367 outp->parmsp[parmSlot++] = fidp->fid;
2368 lock_ObtainMutex(&scp->mx);
2370 outp->parmsp[parmSlot++] = smb_Attributes(scp);
2371 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
2372 outp->parmsp[parmSlot++] = (unsigned short)(dosTime & 0xffff);
2373 outp->parmsp[parmSlot++] = (unsigned short)((dosTime>>16) & 0xffff);
2374 outp->parmsp[parmSlot++] = (unsigned short) (scp->length.LowPart & 0xffff);
2375 outp->parmsp[parmSlot++] = (unsigned short) ((scp->length.LowPart >> 16) & 0xffff);
2376 outp->parmsp[parmSlot++] = openMode;
2377 outp->parmsp[parmSlot++] = 0; /* file type 0 ==> normal file or dir */
2378 outp->parmsp[parmSlot++] = 0; /* IPC junk */
2380 /* and the final "always present" stuff */
2381 outp->parmsp[parmSlot++] = openAction;
2382 /* next write out the "unique" ID */
2383 outp->parmsp[parmSlot++] = (unsigned short) (scp->fid.vnode & 0xffff);
2384 outp->parmsp[parmSlot++] = (unsigned short) (scp->fid.volume & 0xffff);
2385 outp->parmsp[parmSlot++] = 0;
2386 if (returnEALength) {
2387 outp->parmsp[parmSlot++] = 0;
2388 outp->parmsp[parmSlot++] = 0;
2390 lock_ReleaseMutex(&scp->mx);
2391 outp->totalData = 0; /* total # of data bytes */
2392 outp->totalParms = parmSlot * 2; /* shorts are two bytes */
2394 smb_SendTran2Packet(vcp, outp, op);
2396 smb_FreeTran2Packet(outp);
2398 cm_ReleaseUser(userp);
2399 /* leave scp held since we put it in fidp->scp */
2403 long smb_ReceiveTran2FindFirst(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
2405 osi_Log0(smb_logp,"ReceiveTran2FindFirst - NOT_SUPPORTED");
2406 return CM_ERROR_BADOP;
2409 long smb_ReceiveTran2FindNext(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
2411 osi_Log0(smb_logp,"ReceiveTran2FindNext - NOT_SUPPORTED");
2412 return CM_ERROR_BADOP;
2415 long smb_ReceiveTran2QFSInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
2417 smb_tran2Packet_t *outp;
2418 smb_tran2QFSInfo_t qi;
2421 static char FSname[6] = {'A', 0, 'F', 0, 'S', 0};
2423 osi_Log1(smb_logp, "T2 QFSInfo type 0x%x", p->parmsp[0]);
2425 switch (p->parmsp[0]) {
2426 case 1: responseSize = sizeof(qi.u.allocInfo); break;
2427 case 2: responseSize = sizeof(qi.u.volumeInfo); break;
2428 case 0x102: responseSize = sizeof(qi.u.FSvolumeInfo); break;
2429 case 0x103: responseSize = sizeof(qi.u.FSsizeInfo); break;
2430 case 0x104: responseSize = sizeof(qi.u.FSdeviceInfo); break;
2431 case 0x105: responseSize = sizeof(qi.u.FSattributeInfo); break;
2432 case 0x200: /* CIFS Unix Info */
2433 case 0x301: /* Mac FS Info */
2434 default: return CM_ERROR_INVAL;
2437 outp = smb_GetTran2ResponsePacket(vcp, p, op, 0, responseSize);
2438 switch (p->parmsp[0]) {
2441 qi.u.allocInfo.FSID = 0;
2442 qi.u.allocInfo.sectorsPerAllocUnit = 1;
2443 qi.u.allocInfo.totalAllocUnits = 0x7fffffff;
2444 qi.u.allocInfo.availAllocUnits = 0x3fffffff;
2445 qi.u.allocInfo.bytesPerSector = 1024;
2450 qi.u.volumeInfo.vsn = 1234;
2451 qi.u.volumeInfo.vnCount = 4;
2452 /* we're supposed to pad it out with zeroes to the end */
2453 memset(&qi.u.volumeInfo.label, 0, sizeof(qi.u.volumeInfo.label));
2454 memcpy(qi.u.volumeInfo.label, "AFS", 4);
2458 /* FS volume info */
2459 memset((char *)&qi.u.FSvolumeInfo.vct, 0, sizeof(FILETIME));
2460 qi.u.FSvolumeInfo.vsn = 1234;
2461 qi.u.FSvolumeInfo.vnCount = 8;
2462 memcpy(qi.u.FSvolumeInfo.label, "A\0F\0S\0\0", 8);
2468 temp.LowPart = 0x7fffffff;
2469 qi.u.FSsizeInfo.totalAllocUnits = temp;
2470 temp.LowPart = 0x3fffffff;
2471 qi.u.FSsizeInfo.availAllocUnits = temp;
2472 qi.u.FSsizeInfo.sectorsPerAllocUnit = 1;
2473 qi.u.FSsizeInfo.bytesPerSector = 1024;
2477 /* FS device info */
2478 qi.u.FSdeviceInfo.devType = 0; /* don't have a number */
2479 qi.u.FSdeviceInfo.characteristics = 0x50; /* remote, virtual */
2483 /* FS attribute info */
2484 /* attributes, defined in WINNT.H:
2485 * FILE_CASE_SENSITIVE_SEARCH 0x1
2486 * FILE_CASE_PRESERVED_NAMES 0x2
2487 * <no name defined> 0x4000
2488 * If bit 0x4000 is not set, Windows 95 thinks
2489 * we can't handle long (non-8.3) names,
2490 * despite our protestations to the contrary.
2492 qi.u.FSattributeInfo.attributes = 0x4003;
2493 qi.u.FSattributeInfo.maxCompLength = 255;
2494 qi.u.FSattributeInfo.FSnameLength = 6;
2495 memcpy(qi.u.FSattributeInfo.FSname, FSname, 6);
2499 /* copy out return data, and set corresponding sizes */
2500 outp->totalParms = 0;
2501 outp->totalData = responseSize;
2502 memcpy(outp->datap, &qi, responseSize);
2504 /* send and free the packets */
2505 smb_SendTran2Packet(vcp, outp, op);
2506 smb_FreeTran2Packet(outp);
2511 long smb_ReceiveTran2SetFSInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
2513 osi_Log0(smb_logp,"ReceiveTran2SetFSInfo - NOT_SUPPORTED");
2514 return CM_ERROR_BADOP;
2517 struct smb_ShortNameRock {
2521 size_t shortNameLen;
2524 int cm_GetShortNameProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *vrockp,
2527 struct smb_ShortNameRock *rockp;
2531 /* compare both names and vnodes, though probably just comparing vnodes
2532 * would be safe enough.
2534 if (cm_stricmp(dep->name, rockp->maskp) != 0)
2536 if (ntohl(dep->fid.vnode) != rockp->vnode)
2538 /* This is the entry */
2539 cm_Gen8Dot3Name(dep, rockp->shortName, &shortNameEnd);
2540 rockp->shortNameLen = shortNameEnd - rockp->shortName;
2541 return CM_ERROR_STOPNOW;
2544 long cm_GetShortName(char *pathp, cm_user_t *userp, cm_req_t *reqp,
2545 char *tidPathp, int vnode, char *shortName, size_t *shortNameLenp)
2547 struct smb_ShortNameRock rock;
2551 int caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
2555 spacep = cm_GetSpace();
2556 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
2558 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold, userp, tidPathp,
2560 cm_FreeSpace(spacep);
2565 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
2566 cm_ReleaseSCache(dscp);
2567 cm_ReleaseUser(userp);
2568 return CM_ERROR_PATH_NOT_COVERED;
2570 #endif /* DFS_SUPPORT */
2572 if (!lastNamep) lastNamep = pathp;
2575 thyper.HighPart = 0;
2576 rock.shortName = shortName;
2578 rock.maskp = lastNamep;
2579 code = cm_ApplyDir(dscp, cm_GetShortNameProc, &rock, &thyper, userp, reqp, NULL);
2581 cm_ReleaseSCache(dscp);
2584 return CM_ERROR_NOSUCHFILE;
2585 if (code == CM_ERROR_STOPNOW) {
2586 *shortNameLenp = rock.shortNameLen;
2592 long smb_ReceiveTran2QPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
2594 smb_tran2Packet_t *outp;
2597 unsigned short infoLevel;
2599 unsigned short attributes;
2600 unsigned long extAttributes;
2605 cm_scache_t *scp, *dscp;
2614 infoLevel = p->parmsp[0];
2615 if (infoLevel == SMB_INFO_IS_NAME_VALID)
2617 else if (infoLevel == SMB_INFO_STANDARD)
2618 nbytesRequired = 22;
2619 else if (infoLevel == SMB_INFO_QUERY_EA_SIZE)
2620 nbytesRequired = 26;
2621 else if (infoLevel == SMB_QUERY_FILE_BASIC_INFO)
2622 nbytesRequired = 40;
2623 else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO)
2624 nbytesRequired = 24;
2625 else if (infoLevel == SMB_QUERY_FILE_EA_INFO)
2627 else if (infoLevel == SMB_QUERY_FILE_ALT_NAME_INFO)
2628 nbytesRequired = 30;
2630 osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
2631 p->opcode, infoLevel);
2632 smb_SendTran2Error(vcp, p, opx, CM_ERROR_INVAL);
2635 osi_Log2(smb_logp, "T2 QPathInfo type 0x%x path %s", infoLevel,
2636 osi_LogSaveString(smb_logp, (char *)(&p->parmsp[3])));
2638 outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, nbytesRequired);
2640 if (infoLevel > 0x100)
2641 outp->totalParms = 2;
2643 outp->totalParms = 0;
2644 outp->totalData = nbytesRequired;
2646 /* now, if we're at infoLevel 6, we're only being asked to check
2647 * the syntax, so we just OK things now. In particular, we're *not*
2648 * being asked to verify anything about the state of any parent dirs.
2650 if (infoLevel == SMB_INFO_IS_NAME_VALID) {
2651 smb_SendTran2Packet(vcp, outp, opx);
2652 smb_FreeTran2Packet(outp);
2656 userp = smb_GetTran2User(vcp, p);
2658 osi_Log1(smb_logp, "ReceiveTran2QPathInfo unable to resolve user [%d]", p->uid);
2659 smb_FreeTran2Packet(outp);
2660 return CM_ERROR_BADSMB;
2663 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
2665 cm_ReleaseUser(userp);
2666 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOSUCHPATH);
2667 smb_FreeTran2Packet(outp);
2672 * XXX Strange hack XXX
2674 * As of Patch 7 (13 January 98), we are having the following problem:
2675 * In NT Explorer 4.0, whenever we click on a directory, AFS gets
2676 * requests to look up "desktop.ini" in all the subdirectories.
2677 * This can cause zillions of timeouts looking up non-existent cells
2678 * and volumes, especially in the top-level directory.
2680 * We have not found any way to avoid this or work around it except
2681 * to explicitly ignore the requests for mount points that haven't
2682 * yet been evaluated and for directories that haven't yet been
2685 if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
2686 spacep = cm_GetSpace();
2687 smb_StripLastComponent(spacep->data, &lastComp,
2688 (char *)(&p->parmsp[3]));
2689 #ifndef SPECIAL_FOLDERS
2690 /* Make sure that lastComp is not NULL */
2692 if (stricmp(lastComp, "\\desktop.ini") == 0) {
2693 code = cm_NameI(cm_data.rootSCachep, spacep->data,
2697 userp, tidPathp, &req, &dscp);
2700 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
2701 if ( WANTS_DFS_PATHNAMES(p) )
2702 code = CM_ERROR_PATH_NOT_COVERED;
2704 code = CM_ERROR_BADSHARENAME;
2706 #endif /* DFS_SUPPORT */
2707 if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT && !dscp->mountRootFid.volume)
2708 code = CM_ERROR_NOSUCHFILE;
2709 else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
2710 cm_buf_t *bp = buf_Find(dscp, &hzero);
2714 code = CM_ERROR_NOSUCHFILE;
2716 cm_ReleaseSCache(dscp);
2718 cm_FreeSpace(spacep);
2719 cm_ReleaseUser(userp);
2720 smb_SendTran2Error(vcp, p, opx, code);
2721 smb_FreeTran2Packet(outp);
2727 #endif /* SPECIAL_FOLDERS */
2729 cm_FreeSpace(spacep);
2732 /* now do namei and stat, and copy out the info */
2733 code = cm_NameI(cm_data.rootSCachep, (char *)(&p->parmsp[3]),
2734 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, tidPathp, &req, &scp);
2737 cm_ReleaseUser(userp);
2738 smb_SendTran2Error(vcp, p, opx, code);
2739 smb_FreeTran2Packet(outp);
2744 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
2745 cm_ReleaseSCache(scp);
2746 cm_ReleaseUser(userp);
2747 if ( WANTS_DFS_PATHNAMES(p) )
2748 code = CM_ERROR_PATH_NOT_COVERED;
2750 code = CM_ERROR_BADSHARENAME;
2751 smb_SendTran2Error(vcp, p, opx, code);
2752 smb_FreeTran2Packet(outp);
2755 #endif /* DFS_SUPPORT */
2757 lock_ObtainMutex(&scp->mx);
2758 code = cm_SyncOp(scp, NULL, userp, &req, 0,
2759 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
2760 if (code) goto done;
2762 /* now we have the status in the cache entry, and everything is locked.
2763 * Marshall the output data.
2766 /* for info level 108, figure out short name */
2767 if (infoLevel == 0x108) {
2768 code = cm_GetShortName((char *)(&p->parmsp[3]), userp, &req,
2769 tidPathp, scp->fid.vnode, shortName,
2776 *((u_long *)op) = len * 2; op += 4;
2777 mbstowcs((unsigned short *)op, shortName, len);
2782 if (infoLevel == SMB_INFO_STANDARD || infoLevel == SMB_INFO_QUERY_EA_SIZE) {
2783 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
2784 *((u_long *)op) = dosTime; op += 4; /* creation time */
2785 *((u_long *)op) = dosTime; op += 4; /* access time */
2786 *((u_long *)op) = dosTime; op += 4; /* write time */
2787 *((u_long *)op) = scp->length.LowPart; op += 4; /* length */
2788 *((u_long *)op) = scp->length.LowPart; op += 4; /* alloc size */
2789 attributes = smb_Attributes(scp);
2790 *((u_short *)op) = attributes; op += 2; /* attributes */
2792 else if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
2793 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
2794 *((FILETIME *)op) = ft; op += 8; /* creation time */
2795 *((FILETIME *)op) = ft; op += 8; /* last access time */
2796 *((FILETIME *)op) = ft; op += 8; /* last write time */
2797 *((FILETIME *)op) = ft; op += 8; /* last change time */
2798 extAttributes = smb_ExtAttributes(scp);
2799 *((u_long *)op) = extAttributes; op += 4; /* extended attribs */
2800 *((u_long *)op) = 0; op += 4; /* don't know what this is */
2802 else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO) {
2803 *((LARGE_INTEGER *)op) = scp->length; op += 8; /* alloc size */
2804 *((LARGE_INTEGER *)op) = scp->length; op += 8; /* EOF */
2805 *((u_long *)op) = scp->linkCount; op += 4;
2808 *op++ = (scp->fileType == CM_SCACHETYPE_DIRECTORY ? 1 : 0);
2811 else if (infoLevel == SMB_QUERY_FILE_EA_INFO) {
2812 memset(op, 0, 4); op += 4; /* EA size */
2815 /* now, if we are being asked about extended attrs, return a 0 size */
2816 if (infoLevel == SMB_INFO_QUERY_EA_SIZE) {
2817 *((u_long *)op) = 0; op += 4;
2821 /* send and free the packets */
2823 lock_ReleaseMutex(&scp->mx);
2824 cm_ReleaseSCache(scp);
2825 cm_ReleaseUser(userp);
2827 smb_SendTran2Packet(vcp, outp, opx);
2829 smb_SendTran2Error(vcp, p, opx, code);
2830 smb_FreeTran2Packet(outp);
2835 long smb_ReceiveTran2SetPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
2837 osi_Log0(smb_logp,"ReceiveTran2SetPathInfo - NOT_SUPPORTED");
2838 return CM_ERROR_BADOP;
2841 long smb_ReceiveTran2QFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
2843 smb_tran2Packet_t *outp;
2845 unsigned long attributes;
2846 unsigned short infoLevel;
2859 fidp = smb_FindFID(vcp, fid, 0);
2862 smb_SendTran2Error(vcp, p, opx, CM_ERROR_BADFD);
2866 infoLevel = p->parmsp[1];
2867 if (infoLevel == SMB_QUERY_FILE_BASIC_INFO)
2868 nbytesRequired = 40;
2869 else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO)
2870 nbytesRequired = 24;
2871 else if (infoLevel == SMB_QUERY_FILE_EA_INFO)
2873 else if (infoLevel == SMB_QUERY_FILE_NAME_INFO)
2876 osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
2877 p->opcode, infoLevel);
2878 smb_SendTran2Error(vcp, p, opx, CM_ERROR_INVAL);
2879 smb_ReleaseFID(fidp);
2882 osi_Log2(smb_logp, "T2 QFileInfo type 0x%x fid %d", infoLevel, fid);
2884 outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, nbytesRequired);
2886 if (infoLevel > 0x100)
2887 outp->totalParms = 2;
2889 outp->totalParms = 0;
2890 outp->totalData = nbytesRequired;
2892 userp = smb_GetTran2User(vcp, p);
2894 osi_Log1(smb_logp, "ReceiveTran2QFileInfo unable to resolve user [%d]", p->uid);
2895 code = CM_ERROR_BADSMB;
2900 lock_ObtainMutex(&scp->mx);
2901 code = cm_SyncOp(scp, NULL, userp, &req, 0,
2902 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
2906 /* now we have the status in the cache entry, and everything is locked.
2907 * Marshall the output data.
2910 if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
2911 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
2912 *((FILETIME *)op) = ft; op += 8; /* creation time */
2913 *((FILETIME *)op) = ft; op += 8; /* last access time */
2914 *((FILETIME *)op) = ft; op += 8; /* last write time */
2915 *((FILETIME *)op) = ft; op += 8; /* last change time */
2916 attributes = smb_ExtAttributes(scp);
2917 *((u_long *)op) = attributes; op += 4;
2918 *((u_long *)op) = 0; op += 4;
2920 else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO) {
2921 *((LARGE_INTEGER *)op) = scp->length; op += 8; /* alloc size */
2922 *((LARGE_INTEGER *)op) = scp->length; op += 8; /* EOF */
2923 *((u_long *)op) = scp->linkCount; op += 4;
2924 *op++ = ((fidp->flags & SMB_FID_DELONCLOSE) ? 1 : 0);
2925 *op++ = (scp->fileType == CM_SCACHETYPE_DIRECTORY ? 1 : 0);
2929 else if (infoLevel == SMB_QUERY_FILE_EA_INFO) {
2930 *((u_long *)op) = 0; op += 4;
2932 else if (infoLevel == SMB_QUERY_FILE_NAME_INFO) {
2936 if (fidp->NTopen_wholepathp)
2937 name = fidp->NTopen_wholepathp;
2939 name = "\\"; /* probably can't happen */
2940 len = (unsigned long)strlen(name);
2941 outp->totalData = (len*2) + 4; /* this is actually what we want to return */
2942 *((u_long *)op) = len * 2; op += 4;
2943 mbstowcs((unsigned short *)op, name, len); op += (len * 2);
2946 /* send and free the packets */
2948 lock_ReleaseMutex(&scp->mx);
2949 cm_ReleaseUser(userp);
2950 smb_ReleaseFID(fidp);
2952 smb_SendTran2Packet(vcp, outp, opx);
2954 smb_SendTran2Error(vcp, p, opx, code);
2955 smb_FreeTran2Packet(outp);
2960 long smb_ReceiveTran2SetFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
2965 unsigned short infoLevel;
2966 smb_tran2Packet_t *outp;
2974 fidp = smb_FindFID(vcp, fid, 0);
2977 smb_SendTran2Error(vcp, p, op, CM_ERROR_BADFD);
2981 infoLevel = p->parmsp[1];
2982 osi_Log2(smb_logp,"ReceiveTran2SetFileInfo type=[%x] fid=[%x]", infoLevel, fid);
2983 if (infoLevel > 0x104 || infoLevel < 0x101) {
2984 osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
2985 p->opcode, infoLevel);
2986 smb_SendTran2Error(vcp, p, op, CM_ERROR_INVAL);
2987 smb_ReleaseFID(fidp);
2991 if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO && !(fidp->flags & SMB_FID_OPENDELETE)) {
2992 smb_SendTran2Error(vcp, p, op, CM_ERROR_NOACCESS);
2993 smb_ReleaseFID(fidp);
2996 if ((infoLevel == SMB_QUERY_FILE_EA_INFO || infoLevel == SMB_QUERY_FILE_NAME_INFO)
2997 && !(fidp->flags & SMB_FID_OPENWRITE)) {
2998 smb_SendTran2Error(vcp, p, op, CM_ERROR_NOACCESS);
2999 smb_ReleaseFID(fidp);
3003 osi_Log1(smb_logp, "T2 SFileInfo type 0x%x", infoLevel);
3005 outp = smb_GetTran2ResponsePacket(vcp, p, op, 2, 0);
3007 outp->totalParms = 2;
3008 outp->totalData = 0;
3010 userp = smb_GetTran2User(vcp, p);
3012 osi_Log1(smb_logp,"ReceiveTran2SetFileInfo unable to resolve user [%d]", p->uid);
3013 code = CM_ERROR_BADSMB;
3019 if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
3021 unsigned int attribute;
3024 /* lock the vnode with a callback; we need the current status
3025 * to determine what the new status is, in some cases.
3027 lock_ObtainMutex(&scp->mx);
3028 code = cm_SyncOp(scp, NULL, userp, &req, 0,
3029 CM_SCACHESYNC_GETSTATUS
3030 | CM_SCACHESYNC_NEEDCALLBACK);
3032 lock_ReleaseMutex(&scp->mx);
3036 /* prepare for setattr call */
3039 lastMod = *((FILETIME *)(p->datap + 16));
3040 /* when called as result of move a b, lastMod is (-1, -1).
3041 * If the check for -1 is not present, timestamp
3042 * of the resulting file will be 1969 (-1)
3044 if (LargeIntegerNotEqualToZero(*((LARGE_INTEGER *)&lastMod)) &&
3045 lastMod.dwLowDateTime != -1 && lastMod.dwHighDateTime != -1) {
3046 attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
3047 smb_UnixTimeFromLargeSearchTime(&attr.clientModTime, &lastMod);
3048 fidp->flags |= SMB_FID_MTIMESETDONE;
3051 attribute = *((u_long *)(p->datap + 32));
3052 if (attribute != 0) {
3053 if ((scp->unixModeBits & 0222)
3054 && (attribute & 1) != 0) {
3055 /* make a writable file read-only */
3056 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
3057 attr.unixModeBits = scp->unixModeBits & ~0222;
3059 else if ((scp->unixModeBits & 0222) == 0
3060 && (attribute & 1) == 0) {
3061 /* make a read-only file writable */
3062 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
3063 attr.unixModeBits = scp->unixModeBits | 0222;
3066 lock_ReleaseMutex(&scp->mx);
3070 code = cm_SetAttr(scp, &attr, userp, &req);
3074 else if (infoLevel == SMB_QUERY_FILE_EA_INFO || infoLevel == SMB_QUERY_FILE_NAME_INFO) {
3075 LARGE_INTEGER size = *((LARGE_INTEGER *)(p->datap));
3078 attr.mask = CM_ATTRMASK_LENGTH;
3079 attr.length.LowPart = size.LowPart;
3080 attr.length.HighPart = size.HighPart;
3081 code = cm_SetAttr(scp, &attr, userp, &req);
3083 else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO) {
3084 if (*((char *)(p->datap))) {
3085 code = cm_CheckNTDelete(fidp->NTopen_dscp, scp, userp,
3088 fidp->flags |= SMB_FID_DELONCLOSE;
3092 fidp->flags &= ~SMB_FID_DELONCLOSE;
3097 cm_ReleaseUser(userp);
3098 smb_ReleaseFID(fidp);
3100 smb_SendTran2Packet(vcp, outp, op);
3102 smb_SendTran2Error(vcp, p, op, code);
3103 smb_FreeTran2Packet(outp);
3109 smb_ReceiveTran2FSCTL(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3111 osi_Log0(smb_logp,"ReceiveTran2FSCTL - NOT_SUPPORTED");
3112 return CM_ERROR_BADOP;
3116 smb_ReceiveTran2IOCTL(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3118 osi_Log0(smb_logp,"ReceiveTran2IOCTL - NOT_SUPPORTED");
3119 return CM_ERROR_BADOP;
3123 smb_ReceiveTran2FindNotifyFirst(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3125 osi_Log0(smb_logp,"ReceiveTran2FindNotifyFirst - NOT_SUPPORTED");
3126 return CM_ERROR_BADOP;
3130 smb_ReceiveTran2FindNotifyNext(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3132 osi_Log0(smb_logp,"ReceiveTran2FindNotifyNext - NOT_SUPPORTED");
3133 return CM_ERROR_BADOP;
3137 smb_ReceiveTran2CreateDirectory(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3139 osi_Log0(smb_logp,"ReceiveTran2CreateDirectory - NOT_SUPPORTED");
3140 return CM_ERROR_BADOP;
3144 smb_ReceiveTran2SessionSetup(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3146 osi_Log0(smb_logp,"ReceiveTran2SessionSetup - NOT_SUPPORTED");
3147 return CM_ERROR_BADOP;
3150 struct smb_v2_referral {
3152 USHORT ReferralFlags;
3155 USHORT DfsPathOffset;
3156 USHORT DfsAlternativePathOffset;
3157 USHORT NetworkAddressOffset;
3161 smb_ReceiveTran2GetDFSReferral(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
3163 /* This is a UNICODE only request (bit15 of Flags2) */
3164 /* The TID must be IPC$ */
3166 /* The documentation for the Flags response field is contradictory */
3168 /* Use Version 1 Referral Element Format */
3169 /* ServerType = 0; indicates the next server should be queried for the file */
3170 /* ReferralFlags = 0x01; PathConsumed characters should be stripped */
3171 /* Node = UnicodeString of UNC path of the next share name */
3174 int maxReferralLevel = 0;
3175 char requestFileName[1024] = "";
3176 smb_tran2Packet_t *outp = 0;
3177 cm_user_t *userp = 0;
3179 CPINFO CodePageInfo;
3180 int i, nbnLen, reqLen;
3185 maxReferralLevel = p->parmsp[0];
3187 GetCPInfo(CP_ACP, &CodePageInfo);
3188 WideCharToMultiByte(CP_ACP, 0, (LPCWSTR) &p->parmsp[1], -1,
3189 requestFileName, 1024, NULL, NULL);
3191 osi_Log2(smb_logp,"ReceiveTran2GetDfsReferral [%d][%s]",
3192 maxReferralLevel, osi_LogSaveString(smb_logp, requestFileName));
3194 nbnLen = strlen(cm_NetbiosName);
3195 reqLen = strlen(requestFileName);
3197 if (reqLen == nbnLen + 5 &&
3198 requestFileName[0] == '\\' &&
3199 !_strnicmp(cm_NetbiosName,&requestFileName[1],nbnLen) &&
3200 requestFileName[nbnLen+1] == '\\' &&
3201 !_strnicmp("all",&requestFileName[nbnLen+2],3))
3204 struct smb_v2_referral * v2ref;
3205 outp = smb_GetTran2ResponsePacket(vcp, p, op, 0, 2 * (reqLen + 8));
3207 sp = (USHORT *)outp->datap;
3209 sp[idx++] = reqLen; /* path consumed */
3210 sp[idx++] = 1; /* number of referrals */
3211 sp[idx++] = 0x03; /* flags */
3212 #ifdef DFS_VERSION_1
3213 sp[idx++] = 1; /* Version Number */
3214 sp[idx++] = reqLen + 4; /* Referral Size */
3215 sp[idx++] = 1; /* Type = SMB Server */
3216 sp[idx++] = 0; /* Do not strip path consumed */
3217 for ( i=0;i<=reqLen; i++ )
3218 sp[i+idx] = requestFileName[i];
3219 #else /* DFS_VERSION_2 */
3220 sp[idx++] = 2; /* Version Number */
3221 sp[idx++] = sizeof(struct smb_v2_referral); /* Referral Size */
3222 idx += (sizeof(struct smb_v2_referral) / 2);
3223 v2ref = (struct smb_v2_referral *) &sp[5];
3224 v2ref->ServerType = 1; /* SMB Server */
3225 v2ref->ReferralFlags = 0x03;
3226 v2ref->Proximity = 0; /* closest */
3227 v2ref->TimeToLive = 3600; /* seconds */
3228 v2ref->DfsPathOffset = idx * 2;
3229 v2ref->DfsAlternativePathOffset = idx * 2;
3230 v2ref->NetworkAddressOffset = 0;
3231 for ( i=0;i<=reqLen; i++ )
3232 sp[i+idx] = requestFileName[i];
3235 userp = smb_GetTran2User(vcp, p);
3237 osi_Log1(smb_logp,"ReceiveTran2GetDfsReferral unable to resolve user [%d]", p->uid);
3238 code = CM_ERROR_BADSMB;
3243 code = CM_ERROR_NOSUCHPATH;
3248 cm_ReleaseUser(userp);
3250 smb_SendTran2Packet(vcp, outp, op);
3252 smb_SendTran2Error(vcp, p, op, code);
3254 smb_FreeTran2Packet(outp);
3257 #else /* DFS_SUPPORT */
3258 osi_Log0(smb_logp,"ReceiveTran2GetDfsReferral - NOT_SUPPORTED");
3259 return CM_ERROR_BADOP;
3260 #endif /* DFS_SUPPORT */
3264 smb_ReceiveTran2ReportDFSInconsistency(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3266 /* This is a UNICODE only request (bit15 of Flags2) */
3268 /* There is nothing we can do about this operation. The client is going to
3269 * tell us that there is a Version 1 Referral Element for which there is a DFS Error.
3270 * Unfortunately, there is really nothing we can do about it other then log it
3271 * somewhere. Even then I don't think there is anything for us to do.
3272 * So let's return an error value.
3275 osi_Log0(smb_logp,"ReceiveTran2ReportDFSInconsistency - NOT_SUPPORTED");
3276 return CM_ERROR_BADOP;
3280 smb_ApplyV3DirListPatches(cm_scache_t *dscp,
3281 smb_dirListPatch_t **dirPatchespp, int infoLevel, cm_user_t *userp,
3286 cm_scache_t *targetScp; /* target if scp is a symlink */
3291 unsigned short attr;
3292 unsigned long lattr;
3293 smb_dirListPatch_t *patchp;
3294 smb_dirListPatch_t *npatchp;
3296 for(patchp = *dirPatchespp; patchp; patchp =
3297 (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
3298 code = cm_GetSCache(&patchp->fid, &scp, userp, reqp);
3300 lock_ObtainMutex(&scp->mx);
3301 code = cm_SyncOp(scp, NULL, userp, reqp, 0,
3302 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3304 lock_ReleaseMutex(&scp->mx);
3305 cm_ReleaseSCache(scp);
3307 dptr = patchp->dptr;
3309 /* Plug in fake timestamps. A time stamp of 0 causes 'invalid parameter'
3310 errors in the client. */
3311 if (infoLevel >= 0x101) {
3312 /* 1969-12-31 23:59:59 +00 */
3313 ft.dwHighDateTime = 0x19DB200;
3314 ft.dwLowDateTime = 0x5BB78980;
3316 /* copy to Creation Time */
3317 *((FILETIME *)dptr) = ft;
3320 /* copy to Last Access Time */
3321 *((FILETIME *)dptr) = ft;
3324 /* copy to Last Write Time */
3325 *((FILETIME *)dptr) = ft;
3328 /* copy to Change Time */
3329 *((FILETIME *)dptr) = ft;
3332 /* merge in hidden attribute */
3333 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
3334 *((u_long *)dptr) = SMB_ATTR_HIDDEN;
3338 /* 1969-12-31 23:59:58 +00*/
3339 dosTime = 0xEBBFBF7D;
3341 /* and copy out date */
3342 shortTemp = (dosTime>>16) & 0xffff;
3343 *((u_short *)dptr) = shortTemp;
3346 /* copy out creation time */
3347 shortTemp = dosTime & 0xffff;
3348 *((u_short *)dptr) = shortTemp;
3351 /* and copy out date */
3352 shortTemp = (dosTime>>16) & 0xffff;
3353 *((u_short *)dptr) = shortTemp;
3356 /* copy out access 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 mod time */
3367 shortTemp = dosTime & 0xffff;
3368 *((u_short *)dptr) = shortTemp;
3371 /* merge in hidden (dot file) attribute */
3372 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
3373 attr = SMB_ATTR_HIDDEN;
3374 *dptr++ = attr & 0xff;
3375 *dptr++ = (attr >> 8) & 0xff;
3381 /* now watch for a symlink */
3383 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
3384 lock_ReleaseMutex(&scp->mx);
3385 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, reqp);
3387 /* we have a more accurate file to use (the
3388 * target of the symbolic link). Otherwise,
3389 * we'll just use the symlink anyway.
3391 osi_Log2(smb_logp, "symlink vp %x to vp %x",
3393 cm_ReleaseSCache(scp);
3396 lock_ObtainMutex(&scp->mx);
3399 dptr = patchp->dptr;
3401 if (infoLevel >= 0x101) {
3403 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
3405 /* copy to Creation Time */
3406 *((FILETIME *)dptr) = ft;
3409 /* copy to Last Access Time */
3410 *((FILETIME *)dptr) = ft;
3413 /* copy to Last Write Time */
3414 *((FILETIME *)dptr) = ft;
3417 /* copy to Change Time */
3418 *((FILETIME *)dptr) = ft;
3421 /* Use length for both file length and alloc length */
3422 *((LARGE_INTEGER *)dptr) = scp->length;
3424 *((LARGE_INTEGER *)dptr) = scp->length;
3427 /* Copy attributes */
3428 lattr = smb_ExtAttributes(scp);
3429 if (code == CM_ERROR_NOSUCHPATH && scp->fileType == CM_SCACHETYPE_SYMLINK) {
3430 if (lattr == SMB_ATTR_NORMAL)
3431 lattr = SMB_ATTR_DIRECTORY;
3433 lattr |= SMB_ATTR_DIRECTORY;
3435 /* merge in hidden (dot file) attribute */
3436 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
3437 if (lattr == SMB_ATTR_NORMAL)
3438 lattr = SMB_ATTR_HIDDEN;
3440 lattr |= SMB_ATTR_HIDDEN;
3442 *((u_long *)dptr) = lattr;
3446 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
3448 /* and copy out date */
3449 shortTemp = (dosTime>>16) & 0xffff;
3450 *((u_short *)dptr) = shortTemp;
3453 /* copy out creation time */
3454 shortTemp = dosTime & 0xffff;
3455 *((u_short *)dptr) = shortTemp;
3458 /* and copy out date */
3459 shortTemp = (dosTime>>16) & 0xffff;
3460 *((u_short *)dptr) = shortTemp;
3463 /* copy out access 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 mod time */
3474 shortTemp = dosTime & 0xffff;
3475 *((u_short *)dptr) = shortTemp;
3478 /* copy out file length and alloc length,
3479 * using the same for both
3481 *((u_long *)dptr) = scp->length.LowPart;
3483 *((u_long *)dptr) = scp->length.LowPart;
3486 /* finally copy out attributes as short */
3487 attr = smb_Attributes(scp);
3488 /* merge in hidden (dot file) attribute */
3489 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
3490 if (lattr == SMB_ATTR_NORMAL)
3491 lattr = SMB_ATTR_HIDDEN;
3493 lattr |= SMB_ATTR_HIDDEN;
3495 *dptr++ = attr & 0xff;
3496 *dptr++ = (attr >> 8) & 0xff;
3499 lock_ReleaseMutex(&scp->mx);
3500 cm_ReleaseSCache(scp);
3503 /* now free the patches */
3504 for (patchp = *dirPatchespp; patchp; patchp = npatchp) {
3505 npatchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q);
3509 /* and mark the list as empty */
3510 *dirPatchespp = NULL;
3515 #ifndef USE_OLD_MATCHING
3516 // char table for case insensitive comparison
3517 char mapCaseTable[256];
3519 VOID initUpperCaseTable(VOID)
3522 for (i = 0; i < 256; ++i)
3523 mapCaseTable[i] = toupper(i);
3524 // make '"' match '.'
3525 mapCaseTable[(int)'"'] = toupper('.');
3526 // make '<' match '*'
3527 mapCaseTable[(int)'<'] = toupper('*');
3528 // make '>' match '?'
3529 mapCaseTable[(int)'>'] = toupper('?');
3532 // Compare 'pattern' (containing metacharacters '*' and '?') with the file
3534 // Note : this procedure works recursively calling itself.
3536 // PSZ pattern : string containing metacharacters.
3537 // PSZ name : file name to be compared with 'pattern'.
3539 // BOOL : TRUE/FALSE (match/mistmatch)
3542 szWildCardMatchFileName(PSZ pattern, PSZ name, int casefold)
3544 PSZ pename; // points to the last 'name' character
3546 pename = name + strlen(name) - 1;
3557 if (*pattern == '\0')
3559 for (p = pename; p >= name; --p) {
3560 if ((casefold && (mapCaseTable[*p] == mapCaseTable[*pattern]) ||
3561 !casefold && (*p == *pattern)) &&
3562 szWildCardMatchFileName(pattern + 1, p + 1, casefold))
3567 if ((casefold && mapCaseTable[*name] != mapCaseTable[*pattern]) ||
3568 (!casefold && *name != *pattern))
3575 /* if all we have left are wildcards, then we match */
3576 for (;*pattern; pattern++) {
3577 if (*pattern != '*' && *pattern != '?')
3583 /* do a case-folding search of the star name mask with the name in namep.
3584 * Return 1 if we match, otherwise 0.
3586 int smb_V3MatchMask(char *namep, char *maskp, int flags)
3589 int i, j, star, qmark, casefold, retval;
3591 /* make sure we only match 8.3 names, if requested */
3592 if ((flags & CM_FLAG_8DOT3) && !cm_Is8Dot3(namep))
3595 casefold = (flags & CM_FLAG_CASEFOLD) ? 1 : 0;
3597 /* optimize the pattern:
3598 * if there is a mixture of '?' and '*',
3599 * for example the sequence "*?*?*?*"
3600 * must be turned into the form "*"
3602 newmask = (char *)malloc(strlen(maskp)+1);
3603 for ( i=0, j=0, star=0, qmark=0; maskp[i]; i++) {
3604 switch ( maskp[i] ) {
3616 } else if ( qmark ) {
3620 newmask[j++] = maskp[i];
3627 } else if ( qmark ) {
3631 newmask[j++] = '\0';
3633 retval = szWildCardMatchFileName(newmask, namep, casefold) ? 1:0;
3639 #else /* USE_OLD_MATCHING */
3640 /* do a case-folding search of the star name mask with the name in namep.
3641 * Return 1 if we match, otherwise 0.
3643 int smb_V3MatchMask(char *namep, char *maskp, int flags)
3645 unsigned char tcp1, tcp2; /* Pattern characters */
3646 unsigned char tcn1; /* Name characters */
3647 int sawDot = 0, sawStar = 0, req8dot3 = 0;
3648 char *starNamep, *starMaskp;
3649 static char nullCharp[] = {0};
3650 int casefold = flags & CM_FLAG_CASEFOLD;
3652 /* make sure we only match 8.3 names, if requested */
3653 req8dot3 = (flags & CM_FLAG_8DOT3);
3654 if (req8dot3 && !cm_Is8Dot3(namep))
3659 /* Next pattern character */
3662 /* Next name character */
3666 /* 0 - end of pattern */
3672 else if (tcp1 == '.' || tcp1 == '"') {
3682 * first dot in pattern;
3683 * must match dot or end of name
3688 else if (tcn1 == '.') {
3697 else if (tcp1 == '?') {
3698 if (tcn1 == 0 || tcn1 == '.')
3703 else if (tcp1 == '>') {
3704 if (tcn1 != 0 && tcn1 != '.')
3708 else if (tcp1 == '*' || tcp1 == '<') {
3712 else if ((req8dot3 && tcp2 == '.') || tcp2 == '"') {
3713 while (req8dot3 && tcn1 != '.' && tcn1 != 0)
3728 * pattern character after '*' is not null or
3729 * period. If it is '?' or '>', we are not
3730 * going to understand it. If it is '*' or
3731 * '<', we are going to skip over it. None of
3732 * these are likely, I hope.
3734 /* skip over '*' and '<' */
3735 while (tcp2 == '*' || tcp2 == '<')
3738 /* skip over characters that don't match tcp2 */
3739 while (req8dot3 && tcn1 != '.' && tcn1 != 0 &&
3740 ((casefold && cm_foldUpper[tcn1] != cm_foldUpper[tcp2]) ||
3741 (!casefold && tcn1 != tcp2)))
3745 if ((req8dot3 && tcn1 == '.') || tcn1 == 0)
3748 /* Remember where we are */
3758 /* tcp1 is not a wildcard */
3759 if ((casefold && cm_foldUpper[tcn1] == cm_foldUpper[tcp1]) ||
3760 (!casefold && tcn1 == tcp1)) {
3765 /* if trying to match a star pattern, go back */
3767 maskp = starMaskp - 2;
3768 namep = starNamep + 1;
3777 #endif /* USE_OLD_MATCHING */
3779 long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
3784 long code = 0, code2 = 0;
3788 smb_dirListPatch_t *dirListPatchesp;
3789 smb_dirListPatch_t *curPatchp;
3792 long orbytes; /* # of bytes in this output record */
3793 long ohbytes; /* # of bytes, except file name */
3794 long onbytes; /* # of bytes in name, incl. term. null */
3795 osi_hyper_t dirLength;
3796 osi_hyper_t bufferOffset;
3797 osi_hyper_t curOffset;
3799 smb_dirSearch_t *dsp;
3803 cm_pageHeader_t *pageHeaderp;
3804 cm_user_t *userp = NULL;
3807 long nextEntryCookie;
3808 int numDirChunks; /* # of 32 byte dir chunks in this entry */
3809 char *op; /* output data ptr */
3810 char *origOp; /* original value of op */
3811 cm_space_t *spacep; /* for pathname buffer */
3812 long maxReturnData; /* max # of return data */
3813 long maxReturnParms; /* max # of return parms */
3814 long bytesInBuffer; /* # data bytes in the output buffer */
3816 char *maskp; /* mask part of path */
3820 smb_tran2Packet_t *outp; /* response packet */
3823 char shortName[13]; /* 8.3 name if needed */
3834 if (p->opcode == 1) {
3835 /* find first; obtain basic parameters from request */
3836 attribute = p->parmsp[0];
3837 maxCount = p->parmsp[1];
3838 infoLevel = p->parmsp[3];
3839 searchFlags = p->parmsp[2];
3840 dsp = smb_NewDirSearch(1);
3841 dsp->attribute = attribute;
3842 pathp = ((char *) p->parmsp) + 12; /* points to path */
3843 if (smb_StoreAnsiFilenames)
3844 OemToChar(pathp,pathp);
3846 maskp = strrchr(pathp, '\\');
3850 maskp++; /* skip over backslash */
3851 strcpy(dsp->mask, maskp); /* and save mask */
3852 /* track if this is likely to match a lot of entries */
3853 starPattern = smb_V3IsStarMask(maskp);
3856 osi_assert(p->opcode == 2);
3857 /* find next; obtain basic parameters from request or open dir file */
3858 dsp = smb_FindDirSearch(p->parmsp[0]);
3859 maxCount = p->parmsp[1];
3860 infoLevel = p->parmsp[2];
3861 nextCookie = p->parmsp[3] | (p->parmsp[4] << 16);
3862 searchFlags = p->parmsp[5];
3864 osi_Log2(smb_logp, "T2 search dir bad search ID: id %d nextCookie 0x%x",
3865 p->parmsp[0], nextCookie);
3866 return CM_ERROR_BADFD;
3868 attribute = dsp->attribute;
3871 starPattern = 1; /* assume, since required a Find Next */
3875 "T2 search dir attr 0x%x, info level %d, max count %d, flags 0x%x",
3876 attribute, infoLevel, maxCount, searchFlags);
3878 osi_Log3(smb_logp, "...T2 search op %d, id %d, nextCookie 0x%x",
3879 p->opcode, dsp->cookie, nextCookie);
3881 if (infoLevel >= 0x101)
3882 searchFlags &= ~4; /* no resume keys */
3884 dirListPatchesp = NULL;
3886 maxReturnData = p->maxReturnData;
3887 if (p->opcode == 1) /* find first */
3888 maxReturnParms = 10; /* bytes */
3890 maxReturnParms = 8; /* bytes */
3892 #ifndef CM_CONFIG_MULTITRAN2RESPONSES
3893 if (maxReturnData > 6000)
3894 maxReturnData = 6000;
3895 #endif /* CM_CONFIG_MULTITRAN2RESPONSES */
3897 outp = smb_GetTran2ResponsePacket(vcp, p, opx, maxReturnParms,
3900 osi_Log2(smb_logp, "T2 receive search dir count %d [%s]",
3901 maxCount, osi_LogSaveString(smb_logp, pathp));
3903 /* bail out if request looks bad */
3904 if (p->opcode == 1 && !pathp) {
3905 smb_ReleaseDirSearch(dsp);
3906 smb_FreeTran2Packet(outp);
3907 return CM_ERROR_BADSMB;
3910 osi_Log3(smb_logp, "T2 search dir id %d, nextCookie 0x%x, attr 0x%x",
3911 dsp->cookie, nextCookie, attribute);
3913 userp = smb_GetTran2User(vcp, p);
3915 osi_Log1(smb_logp, "T2 search dir unable to resolve user [%d]", p->uid);
3916 smb_ReleaseDirSearch(dsp);
3917 smb_FreeTran2Packet(outp);
3918 return CM_ERROR_BADSMB;
3921 /* try to get the vnode for the path name next */
3922 lock_ObtainMutex(&dsp->mx);
3928 spacep = cm_GetSpace();
3929 smb_StripLastComponent(spacep->data, NULL, pathp);
3930 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
3932 cm_ReleaseUser(userp);
3933 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOFILES);
3934 smb_FreeTran2Packet(outp);
3935 lock_ReleaseMutex(&dsp->mx);
3936 smb_DeleteDirSearch(dsp);
3937 smb_ReleaseDirSearch(dsp);
3940 code = cm_NameI(cm_data.rootSCachep, spacep->data,
3941 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
3942 userp, tidPathp, &req, &scp);
3943 cm_FreeSpace(spacep);
3946 #ifdef DFS_SUPPORT_BUT_NOT_FIND_FIRST
3947 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
3948 cm_ReleaseSCache(scp);
3949 cm_ReleaseUser(userp);
3950 if ( WANTS_DFS_PATHNAMES(p) )
3951 code = CM_ERROR_PATH_NOT_COVERED;
3953 code = CM_ERROR_BADSHARENAME;
3954 smb_SendTran2Error(vcp, p, opx, code);
3955 smb_FreeTran2Packet(outp);
3956 lock_ReleaseMutex(&dsp->mx);
3957 smb_DeleteDirSearch(dsp);
3958 smb_ReleaseDirSearch(dsp);
3961 #endif /* DFS_SUPPORT */
3963 /* we need one hold for the entry we just stored into,
3964 * and one for our own processing. When we're done
3965 * with this function, we'll drop the one for our own
3966 * processing. We held it once from the namei call,
3967 * and so we do another hold now.
3970 lock_ObtainMutex(&scp->mx);
3971 if ((scp->flags & CM_SCACHEFLAG_BULKSTATTING) == 0 &&
3972 LargeIntegerGreaterOrEqualToZero(scp->bulkStatProgress)) {
3973 scp->flags |= CM_SCACHEFLAG_BULKSTATTING;
3974 dsp->flags |= SMB_DIRSEARCH_BULKST;
3976 lock_ReleaseMutex(&scp->mx);
3979 lock_ReleaseMutex(&dsp->mx);
3981 cm_ReleaseUser(userp);
3982 smb_FreeTran2Packet(outp);
3983 smb_DeleteDirSearch(dsp);
3984 smb_ReleaseDirSearch(dsp);
3988 /* get the directory size */
3989 lock_ObtainMutex(&scp->mx);
3990 code = cm_SyncOp(scp, NULL, userp, &req, 0,
3991 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3993 lock_ReleaseMutex(&scp->mx);
3994 cm_ReleaseSCache(scp);
3995 cm_ReleaseUser(userp);
3996 smb_FreeTran2Packet(outp);
3997 smb_DeleteDirSearch(dsp);
3998 smb_ReleaseDirSearch(dsp);
4003 dirLength = scp->length;
4005 bufferOffset.LowPart = bufferOffset.HighPart = 0;
4006 curOffset.HighPart = 0;
4007 curOffset.LowPart = nextCookie;
4008 origOp = outp->datap;
4016 if (searchFlags & 4)
4017 /* skip over resume key */
4020 /* make sure that curOffset.LowPart doesn't point to the first
4021 * 32 bytes in the 2nd through last dir page, and that it doesn't
4022 * point at the first 13 32-byte chunks in the first dir page,
4023 * since those are dir and page headers, and don't contain useful
4026 temp = curOffset.LowPart & (2048-1);
4027 if (curOffset.HighPart == 0 && curOffset.LowPart < 2048) {
4028 /* we're in the first page */
4029 if (temp < 13*32) temp = 13*32;
4032 /* we're in a later dir page */
4033 if (temp < 32) temp = 32;
4036 /* make sure the low order 5 bits are zero */
4039 /* now put temp bits back ito curOffset.LowPart */
4040 curOffset.LowPart &= ~(2048-1);
4041 curOffset.LowPart |= temp;
4043 /* check if we've passed the dir's EOF */
4044 if (LargeIntegerGreaterThanOrEqualTo(curOffset, dirLength)) {
4045 osi_Log0(smb_logp, "T2 search dir passed eof");
4050 /* check if we've returned all the names that will fit in the
4051 * response packet; we check return count as well as the number
4052 * of bytes requested. We check the # of bytes after we find
4053 * the dir entry, since we'll need to check its size.
4055 if (returnedNames >= maxCount) {
4056 osi_Log2(smb_logp, "T2 search dir returnedNames %d >= maxCount %d",
4057 returnedNames, maxCount);
4061 /* see if we can use the bufferp we have now; compute in which
4062 * page the current offset would be, and check whether that's
4063 * the offset of the buffer we have. If not, get the buffer.
4065 thyper.HighPart = curOffset.HighPart;
4066 thyper.LowPart = curOffset.LowPart & ~(cm_data.buf_blockSize-1);
4067 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
4070 buf_Release(bufferp);
4073 lock_ReleaseMutex(&scp->mx);
4074 lock_ObtainRead(&scp->bufCreateLock);
4075 code = buf_Get(scp, &thyper, &bufferp);
4076 lock_ReleaseRead(&scp->bufCreateLock);
4077 lock_ObtainMutex(&dsp->mx);
4079 /* now, if we're doing a star match, do bulk fetching
4080 * of all of the status info for files in the dir.
4083 smb_ApplyV3DirListPatches(scp, &dirListPatchesp,
4086 lock_ObtainMutex(&scp->mx);
4087 if ((dsp->flags & SMB_DIRSEARCH_BULKST) &&
4088 LargeIntegerGreaterThanOrEqualTo(thyper, scp->bulkStatProgress)) {
4089 /* Don't bulk stat if risking timeout */
4090 int now = GetTickCount();
4091 if (now - req.startTime > 5000) {
4092 scp->bulkStatProgress = thyper;
4093 scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
4094 dsp->flags &= ~SMB_DIRSEARCH_BULKST;
4096 cm_TryBulkStat(scp, &thyper, userp, &req);
4099 lock_ObtainMutex(&scp->mx);
4101 lock_ReleaseMutex(&dsp->mx);
4103 osi_Log2(smb_logp, "T2 search dir buf_Get scp %x failed %d", scp, code);
4107 bufferOffset = thyper;
4109 /* now get the data in the cache */
4111 code = cm_SyncOp(scp, bufferp, userp, &req,
4113 CM_SCACHESYNC_NEEDCALLBACK
4114 | CM_SCACHESYNC_READ);
4116 osi_Log2(smb_logp, "T2 search dir cm_SyncOp scp %x failed %d", scp, code);
4120 if (cm_HaveBuffer(scp, bufferp, 0)) {
4121 osi_Log2(smb_logp, "T2 search dir !HaveBuffer scp %x bufferp %x", scp, bufferp);
4125 /* otherwise, load the buffer and try again */
4126 code = cm_GetBuffer(scp, bufferp, NULL, userp,
4129 osi_Log3(smb_logp, "T2 search dir cm_GetBuffer failed scp %x bufferp %x code %d",
4130 scp, bufferp, code);
4135 buf_Release(bufferp);
4139 } /* if (wrong buffer) ... */
4141 /* now we have the buffer containing the entry we're interested
4142 * in; copy it out if it represents a non-deleted entry.
4144 entryInDir = curOffset.LowPart & (2048-1);
4145 entryInBuffer = curOffset.LowPart & (cm_data.buf_blockSize - 1);
4147 /* page header will help tell us which entries are free. Page
4148 * header can change more often than once per buffer, since
4149 * AFS 3 dir page size may be less than (but not more than)
4150 * a buffer package buffer.
4152 /* only look intra-buffer */
4153 temp = curOffset.LowPart & (cm_data.buf_blockSize - 1);
4154 temp &= ~(2048 - 1); /* turn off intra-page bits */
4155 pageHeaderp = (cm_pageHeader_t *) (bufferp->datap + temp);
4157 /* now determine which entry we're looking at in the page.
4158 * If it is free (there's a free bitmap at the start of the
4159 * dir), we should skip these 32 bytes.
4161 slotInPage = (entryInDir & 0x7e0) >> 5;
4162 if (!(pageHeaderp->freeBitmap[slotInPage>>3] &
4163 (1 << (slotInPage & 0x7)))) {
4164 /* this entry is free */
4165 numDirChunks = 1; /* only skip this guy */
4169 tp = bufferp->datap + entryInBuffer;
4170 dep = (cm_dirEntry_t *) tp; /* now points to AFS3 dir entry */
4172 /* while we're here, compute the next entry's location, too,
4173 * since we'll need it when writing out the cookie into the dir
4176 * XXXX Probably should do more sanity checking.
4178 numDirChunks = cm_NameEntries(dep->name, &onbytes);
4180 /* compute offset of cookie representing next entry */
4181 nextEntryCookie = curOffset.LowPart + (CM_DIR_CHUNKSIZE * numDirChunks);
4183 /* Need 8.3 name? */
4185 if (infoLevel == SMB_QUERY_FILE_NAME_INFO
4186 && dep->fid.vnode != 0
4187 && !cm_Is8Dot3(dep->name)) {
4188 cm_Gen8Dot3Name(dep, shortName, &shortNameEnd);
4192 osi_Log3(smb_logp, "T2 search dir vn %u name %s (%s)",
4193 dep->fid.vnode, osi_LogSaveString(smb_logp, dep->name),
4194 NeedShortName ? osi_LogSaveString(smb_logp, shortName) : "");
4196 /* When matching, we are using doing a case fold if we have a wildcard mask.
4197 * If we get a non-wildcard match, it's a lookup for a specific file.
4199 if (dep->fid.vnode != 0 &&
4200 (smb_V3MatchMask(dep->name, maskp, (starPattern? CM_FLAG_CASEFOLD : 0)) ||
4202 smb_V3MatchMask(shortName, maskp, CM_FLAG_CASEFOLD)))) {
4204 /* Eliminate entries that don't match requested attributes */
4205 if (smb_hideDotFiles && !(dsp->attribute & SMB_ATTR_HIDDEN) &&
4206 smb_IsDotFile(dep->name)) {
4207 osi_Log0(smb_logp, "T2 search dir skipping hidden");
4208 goto nextEntry; /* no hidden files */
4210 if (!(dsp->attribute & SMB_ATTR_DIRECTORY)) /* no directories */
4212 /* We have already done the cm_TryBulkStat above */
4213 fid.cell = scp->fid.cell;
4214 fid.volume = scp->fid.volume;
4215 fid.vnode = ntohl(dep->fid.vnode);
4216 fid.unique = ntohl(dep->fid.unique);
4217 fileType = cm_FindFileType(&fid);
4218 /*osi_Log2(smb_logp, "smb_ReceiveTran2SearchDir: file %s "
4219 "has filetype %d", dep->name,
4221 if (fileType == CM_SCACHETYPE_DIRECTORY ||
4222 fileType == CM_SCACHETYPE_DFSLINK ||
4223 fileType == CM_SCACHETYPE_INVALID)
4224 osi_Log0(smb_logp, "T2 search dir skipping directory or bad link");
4228 /* finally check if this name will fit */
4230 /* standard dir entry stuff */
4231 if (infoLevel < 0x101)
4232 ohbytes = 23; /* pre-NT */
4233 else if (infoLevel == SMB_QUERY_FILE_EA_INFO)
4234 ohbytes = 12; /* NT names only */
4236 ohbytes = 64; /* NT */
4238 if (infoLevel == SMB_QUERY_FILE_NAME_INFO)
4239 ohbytes += 26; /* Short name & length */
4241 if (searchFlags & 4) {
4242 ohbytes += 4; /* if resume key required */
4246 && infoLevel != 0x101
4247 && infoLevel != 0x103)
4248 ohbytes += 4; /* EASIZE */
4250 /* add header to name & term. null */
4251 orbytes = onbytes + ohbytes + 1;
4253 /* now, we round up the record to a 4 byte alignment,
4254 * and we make sure that we have enough room here for
4255 * even the aligned version (so we don't have to worry
4256 * about an * overflow when we pad things out below).
4257 * That's the reason for the alignment arithmetic below.
4259 if (infoLevel >= 0x101)
4260 align = (4 - (orbytes & 3)) & 3;
4263 if (orbytes + bytesInBuffer + align > maxReturnData) {
4264 osi_Log1(smb_logp, "T2 dir search exceed max return data %d",
4269 /* this is one of the entries to use: it is not deleted
4270 * and it matches the star pattern we're looking for.
4271 * Put out the name, preceded by its length.
4273 /* First zero everything else */
4274 memset(origOp, 0, ohbytes);
4276 if (infoLevel <= 0x101)
4277 *(origOp + ohbytes - 1) = (unsigned char) onbytes;
4278 else if (infoLevel == SMB_QUERY_FILE_EA_INFO)
4279 *((u_long *)(op + 8)) = onbytes;
4281 *((u_long *)(op + 60)) = onbytes;
4282 strcpy(origOp+ohbytes, dep->name);
4283 if (smb_StoreAnsiFilenames)
4284 CharToOem(origOp+ohbytes, origOp+ohbytes);
4286 /* Short name if requested and needed */
4287 if (infoLevel == SMB_QUERY_FILE_NAME_INFO) {
4288 if (NeedShortName) {
4289 strcpy(op + 70, shortName);
4290 if (smb_StoreAnsiFilenames)
4291 CharToOem(op + 70, op + 70);
4292 *(op + 68) = (char)(shortNameEnd - shortName);
4296 /* now, adjust the # of entries copied */
4299 /* NextEntryOffset and FileIndex */
4300 if (infoLevel >= 101) {
4301 int entryOffset = orbytes + align;
4302 *((u_long *)op) = entryOffset;
4303 *((u_long *)(op+4)) = nextEntryCookie;
4306 /* now we emit the attribute. This is tricky, since
4307 * we need to really stat the file to find out what
4308 * type of entry we've got. Right now, we're copying
4309 * out data from a buffer, while holding the scp
4310 * locked, so it isn't really convenient to stat
4311 * something now. We'll put in a place holder
4312 * now, and make a second pass before returning this
4313 * to get the real attributes. So, we just skip the
4314 * data for now, and adjust it later. We allocate a
4315 * patch record to make it easy to find this point
4316 * later. The replay will happen at a time when it is
4317 * safe to unlock the directory.
4319 if (infoLevel != 0x103) {
4320 curPatchp = malloc(sizeof(*curPatchp));
4321 osi_QAdd((osi_queue_t **) &dirListPatchesp,
4323 curPatchp->dptr = op;
4324 if (infoLevel >= 0x101)
4325 curPatchp->dptr += 8;
4327 if (smb_hideDotFiles && smb_IsDotFile(dep->name)) {
4328 curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
4331 curPatchp->flags = 0;
4333 curPatchp->fid.cell = scp->fid.cell;
4334 curPatchp->fid.volume = scp->fid.volume;
4335 curPatchp->fid.vnode = ntohl(dep->fid.vnode);
4336 curPatchp->fid.unique = ntohl(dep->fid.unique);
4339 curPatchp->dep = dep;
4342 if (searchFlags & 4)
4343 /* put out resume key */
4344 *((u_long *)origOp) = nextEntryCookie;
4346 /* Adjust byte ptr and count */
4347 origOp += orbytes; /* skip entire record */
4348 bytesInBuffer += orbytes;
4350 /* and pad the record out */
4351 while (--align >= 0) {
4355 } /* if we're including this name */
4356 else if (!starPattern &&
4358 dep->fid.vnode != 0 &&
4359 smb_V3MatchMask(dep->name, maskp, CM_FLAG_CASEFOLD)) {
4360 /* We were looking for exact matches, but here's an inexact one*/
4365 /* and adjust curOffset to be where the new cookie is */
4366 thyper.HighPart = 0;
4367 thyper.LowPart = CM_DIR_CHUNKSIZE * numDirChunks;
4368 curOffset = LargeIntegerAdd(thyper, curOffset);
4369 } /* while copying data for dir listing */
4371 /* If we didn't get a star pattern, we did an exact match during the first pass.
4372 * If there were no exact matches found, we fail over to inexact matches by
4373 * marking the query as a star pattern (matches all case permutations), and
4374 * re-running the query.
4376 if (returnedNames == 0 && !starPattern && foundInexact) {
4377 osi_Log0(afsd_logp,"T2 Search: No exact matches. Re-running for inexact matches");
4382 /* release the mutex */
4383 lock_ReleaseMutex(&scp->mx);
4385 buf_Release(bufferp);
4387 /* apply and free last set of patches; if not doing a star match, this
4388 * will be empty, but better safe (and freeing everything) than sorry.
4390 code2 = smb_ApplyV3DirListPatches(scp, &dirListPatchesp, infoLevel, userp,
4393 /* now put out the final parameters */
4394 if (returnedNames == 0)
4396 if (p->opcode == 1) {
4398 outp->parmsp[0] = (unsigned short) dsp->cookie;
4399 outp->parmsp[1] = returnedNames;
4400 outp->parmsp[2] = eos;
4401 outp->parmsp[3] = 0; /* nothing wrong with EAS */
4402 outp->parmsp[4] = 0;
4403 /* don't need last name to continue
4404 * search, cookie is enough. Normally,
4405 * this is the offset of the file name
4406 * of the last entry returned.
4408 outp->totalParms = 10; /* in bytes */
4412 outp->parmsp[0] = returnedNames;
4413 outp->parmsp[1] = eos;
4414 outp->parmsp[2] = 0; /* EAS error */
4415 outp->parmsp[3] = 0; /* last name, as above */
4416 outp->totalParms = 8; /* in bytes */
4419 /* return # of bytes in the buffer */
4420 outp->totalData = bytesInBuffer;
4422 /* Return error code if unsuccessful on first request */
4423 if (code == 0 && p->opcode == 1 && returnedNames == 0)
4424 code = CM_ERROR_NOSUCHFILE;
4426 osi_Log4(smb_logp, "T2 search dir done, opcode %d, id %d, %d names, code %d",
4427 p->opcode, dsp->cookie, returnedNames, code);
4429 /* if we're supposed to close the search after this request, or if
4430 * we're supposed to close the search if we're done, and we're done,
4431 * or if something went wrong, close the search.
4433 /* ((searchFlags & 1) || ((searchFlags & 2) && eos) */
4434 if ((searchFlags & 1) || (returnedNames == 0) ||
4435 ((searchFlags & 2) && eos) || code != 0)
4436 smb_DeleteDirSearch(dsp);
4438 smb_SendTran2Error(vcp, p, opx, code);
4440 smb_SendTran2Packet(vcp, outp, opx);
4442 smb_FreeTran2Packet(outp);
4443 smb_ReleaseDirSearch(dsp);
4444 cm_ReleaseSCache(scp);
4445 cm_ReleaseUser(userp);
4449 long smb_ReceiveV3FindClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4452 smb_dirSearch_t *dsp;
4454 dirHandle = smb_GetSMBParm(inp, 0);
4456 osi_Log1(smb_logp, "SMB3 find close handle %d", dirHandle);
4458 dsp = smb_FindDirSearch(dirHandle);
4461 return CM_ERROR_BADFD;
4463 /* otherwise, we have an FD to destroy */
4464 smb_DeleteDirSearch(dsp);
4465 smb_ReleaseDirSearch(dsp);
4467 /* and return results */
4468 smb_SetSMBDataLength(outp, 0);
4473 long smb_ReceiveV3FindNotifyClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4475 smb_SetSMBDataLength(outp, 0);
4479 long smb_ReceiveV3OpenX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4486 cm_scache_t *dscp; /* dir we're dealing with */
4487 cm_scache_t *scp; /* file we're creating */
4489 int initialModeBits;
4499 int parmSlot; /* which parm we're dealing with */
4507 extraInfo = (smb_GetSMBParm(inp, 2) & 1); /* return extra info */
4508 openFun = smb_GetSMBParm(inp, 8); /* open function */
4509 excl = ((openFun & 3) == 0);
4510 trunc = ((openFun & 3) == 2); /* truncate it */
4511 openMode = (smb_GetSMBParm(inp, 3) & 0x7);
4512 openAction = 0; /* tracks what we did */
4514 attributes = smb_GetSMBParm(inp, 5);
4515 dosTime = smb_GetSMBParm(inp, 6) | (smb_GetSMBParm(inp, 7) << 16);
4517 /* compute initial mode bits based on read-only flag in attributes */
4518 initialModeBits = 0666;
4519 if (attributes & 1) initialModeBits &= ~0222;
4521 pathp = smb_GetSMBData(inp, NULL);
4522 if (smb_StoreAnsiFilenames)
4523 OemToChar(pathp,pathp);
4525 spacep = inp->spacep;
4526 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
4528 if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
4529 /* special case magic file name for receiving IOCTL requests
4530 * (since IOCTL calls themselves aren't getting through).
4533 osi_Log0(smb_logp, "IOCTL Open");
4536 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
4537 smb_SetupIoctlFid(fidp, spacep);
4539 /* set inp->fid so that later read calls in same msg can find fid */
4540 inp->fid = fidp->fid;
4542 /* copy out remainder of the parms */
4544 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
4546 smb_SetSMBParm(outp, parmSlot, /* attrs */ 0); parmSlot++;
4547 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* mod time */
4548 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
4549 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* len */
4550 smb_SetSMBParm(outp, parmSlot, 0x7fff); parmSlot++;
4551 smb_SetSMBParm(outp, parmSlot, openMode); parmSlot++;
4552 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* file type 0 ==> normal file or dir */
4553 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* IPC junk */
4555 /* and the final "always present" stuff */
4556 smb_SetSMBParm(outp, parmSlot, /* openAction found existing file */ 1); parmSlot++;
4557 /* next write out the "unique" ID */
4558 smb_SetSMBParm(outp, parmSlot, 0x1234); parmSlot++;
4559 smb_SetSMBParm(outp, parmSlot, 0x5678); parmSlot++;
4560 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
4561 smb_SetSMBDataLength(outp, 0);
4563 /* and clean up fid reference */
4564 smb_ReleaseFID(fidp);
4568 #ifdef DEBUG_VERBOSE
4570 char *hexp, *asciip;
4571 asciip = (lastNamep ? lastNamep : pathp );
4572 hexp = osi_HexifyString(asciip);
4573 DEBUG_EVENT2("AFS", "V3Open H[%s] A[%s]", hexp, asciip );
4577 userp = smb_GetUser(vcp, inp);
4580 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4582 cm_ReleaseUser(userp);
4583 return CM_ERROR_NOSUCHPATH;
4585 code = cm_NameI(cm_data.rootSCachep, pathp,
4586 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
4587 userp, tidPathp, &req, &scp);
4590 if (code == 0 && scp->fileType == CM_SCACHETYPE_DFSLINK) {
4591 cm_ReleaseSCache(scp);
4592 cm_ReleaseUser(userp);
4593 if ( WANTS_DFS_PATHNAMES(inp) )
4594 return CM_ERROR_PATH_NOT_COVERED;
4596 return CM_ERROR_BADSHARENAME;
4598 #endif /* DFS_SUPPORT */
4601 code = cm_NameI(cm_data.rootSCachep, spacep->data,
4602 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
4603 userp, tidPathp, &req, &dscp);
4605 cm_ReleaseUser(userp);
4610 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
4611 cm_ReleaseSCache(dscp);
4612 cm_ReleaseUser(userp);
4613 if ( WANTS_DFS_PATHNAMES(inp) )
4614 return CM_ERROR_PATH_NOT_COVERED;
4616 return CM_ERROR_BADSHARENAME;
4618 #endif /* DFS_SUPPORT */
4620 /* otherwise, scp points to the parent directory. Do a lookup,
4621 * and truncate the file if we find it, otherwise we create the
4628 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD, userp,
4630 if (code && code != CM_ERROR_NOSUCHFILE) {
4631 cm_ReleaseSCache(dscp);
4632 cm_ReleaseUser(userp);
4637 /* if we get here, if code is 0, the file exists and is represented by
4638 * scp. Otherwise, we have to create it. The dir may be represented
4639 * by dscp, or we may have found the file directly. If code is non-zero,
4643 code = cm_CheckOpen(scp, openMode, trunc, userp, &req);
4645 if (dscp) cm_ReleaseSCache(dscp);
4646 cm_ReleaseSCache(scp);
4647 cm_ReleaseUser(userp);
4652 /* oops, file shouldn't be there */
4654 cm_ReleaseSCache(dscp);
4655 cm_ReleaseSCache(scp);
4656 cm_ReleaseUser(userp);
4657 return CM_ERROR_EXISTS;
4661 setAttr.mask = CM_ATTRMASK_LENGTH;
4662 setAttr.length.LowPart = 0;
4663 setAttr.length.HighPart = 0;
4664 code = cm_SetAttr(scp, &setAttr, userp, &req);
4665 openAction = 3; /* truncated existing file */
4667 else openAction = 1; /* found existing file */
4669 else if (!(openFun & SMB_ATTR_DIRECTORY)) {
4670 /* don't create if not found */
4671 if (dscp) cm_ReleaseSCache(dscp);
4672 cm_ReleaseUser(userp);
4673 return CM_ERROR_NOSUCHFILE;
4676 osi_assert(dscp != NULL);
4677 osi_Log1(smb_logp, "smb_ReceiveV3OpenX creating file %s",
4678 osi_LogSaveString(smb_logp, lastNamep));
4679 openAction = 2; /* created file */
4680 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
4681 smb_UnixTimeFromDosUTime(&setAttr.clientModTime, dosTime);
4682 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
4684 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
4685 smb_NotifyChange(FILE_ACTION_ADDED,
4686 FILE_NOTIFY_CHANGE_FILE_NAME,
4687 dscp, lastNamep, NULL, TRUE);
4688 if (!excl && code == CM_ERROR_EXISTS) {
4689 /* not an exclusive create, and someone else tried
4690 * creating it already, then we open it anyway. We
4691 * don't bother retrying after this, since if this next
4692 * fails, that means that the file was deleted after we
4693 * started this call.
4695 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
4699 setAttr.mask = CM_ATTRMASK_LENGTH;
4700 setAttr.length.LowPart = 0;
4701 setAttr.length.HighPart = 0;
4702 code = cm_SetAttr(scp, &setAttr, userp, &req);
4704 } /* lookup succeeded */
4708 /* we don't need this any longer */
4710 cm_ReleaseSCache(dscp);
4713 /* something went wrong creating or truncating the file */
4715 cm_ReleaseSCache(scp);
4716 cm_ReleaseUser(userp);
4720 /* make sure we're about to open a file */
4721 if (scp->fileType != CM_SCACHETYPE_FILE) {
4722 cm_ReleaseSCache(scp);
4723 cm_ReleaseUser(userp);
4724 return CM_ERROR_ISDIR;
4727 /* now all we have to do is open the file itself */
4728 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
4731 /* save a pointer to the vnode */
4735 fidp->userp = userp;
4737 /* compute open mode */
4739 fidp->flags |= SMB_FID_OPENREAD;
4740 if (openMode == 1 || openMode == 2)
4741 fidp->flags |= SMB_FID_OPENWRITE;
4743 smb_ReleaseFID(fidp);
4745 cm_Open(scp, 0, userp);
4747 /* set inp->fid so that later read calls in same msg can find fid */
4748 inp->fid = fidp->fid;
4750 /* copy out remainder of the parms */
4752 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
4753 lock_ObtainMutex(&scp->mx);
4755 smb_SetSMBParm(outp, parmSlot, smb_Attributes(scp)); parmSlot++;
4756 smb_DosUTimeFromUnixTime(&dosTime, scp->clientModTime);
4757 smb_SetSMBParm(outp, parmSlot, dosTime & 0xffff); parmSlot++;
4758 smb_SetSMBParm(outp, parmSlot, (dosTime>>16) & 0xffff); parmSlot++;
4759 smb_SetSMBParm(outp, parmSlot, scp->length.LowPart & 0xffff); parmSlot++;
4760 smb_SetSMBParm(outp, parmSlot, (scp->length.LowPart >> 16) & 0xffff); parmSlot++;
4761 smb_SetSMBParm(outp, parmSlot, openMode); parmSlot++;
4762 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* file type 0 ==> normal file or dir */
4763 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* IPC junk */
4765 /* and the final "always present" stuff */
4766 smb_SetSMBParm(outp, parmSlot, openAction); parmSlot++;
4767 /* next write out the "unique" ID */
4768 smb_SetSMBParm(outp, parmSlot, scp->fid.vnode & 0xffff); parmSlot++;
4769 smb_SetSMBParm(outp, parmSlot, scp->fid.volume & 0xffff); parmSlot++;
4770 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
4771 lock_ReleaseMutex(&scp->mx);
4772 smb_SetSMBDataLength(outp, 0);
4774 osi_Log1(smb_logp, "SMB OpenX opening fid %d", fidp->fid);
4776 cm_ReleaseUser(userp);
4777 /* leave scp held since we put it in fidp->scp */
4781 static void smb_GetLockParams(unsigned char LockType,
4783 unsigned int * ppid,
4784 LARGE_INTEGER * pOffset,
4785 LARGE_INTEGER * pLength)
4787 if (LockType & LOCKING_ANDX_LARGE_FILES) {
4789 *ppid = *((USHORT *) *buf);
4790 pOffset->HighPart = *((LONG *)(*buf + 4));
4791 pOffset->LowPart = *((DWORD *)(*buf + 8));
4792 pLength->HighPart = *((LONG *)(*buf + 12));
4793 pLength->LowPart = *((DWORD *)(*buf + 16));
4797 /* Not Large Files */
4798 *ppid = *((USHORT *) *buf);
4799 pOffset->HighPart = 0;
4800 pOffset->LowPart = *((DWORD *)(*buf + 2));
4801 pLength->HighPart = 0;
4802 pLength->LowPart = *((DWORD *)(*buf + 6));
4807 long smb_ReceiveV3LockingX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4814 unsigned char LockType;
4815 unsigned short NumberOfUnlocks, NumberOfLocks;
4819 LARGE_INTEGER LOffset, LLength;
4820 smb_waitingLockRequest_t *wlRequest = NULL;
4821 cm_file_lock_t *lockp;
4829 fid = smb_GetSMBParm(inp, 2);
4830 fid = smb_ChainFID(fid, inp);
4832 fidp = smb_FindFID(vcp, fid, 0);
4833 if (!fidp || (fidp->flags & SMB_FID_IOCTL)) {
4834 osi_Log0(smb_logp, "smb_ReceiveV3Locking BadFD");
4835 return CM_ERROR_BADFD;
4837 /* set inp->fid so that later read calls in same msg can find fid */
4840 userp = smb_GetUser(vcp, inp);
4844 lock_ObtainMutex(&scp->mx);
4845 code = cm_SyncOp(scp, NULL, userp, &req, 0,
4846 CM_SCACHESYNC_NEEDCALLBACK
4847 | CM_SCACHESYNC_GETSTATUS
4848 | CM_SCACHESYNC_LOCK);
4850 osi_Log1(smb_logp, "smb_ReceiveV3Locking SyncOp failure code 0x%x", code);
4854 LockType = smb_GetSMBParm(inp, 3) & 0xff;
4855 Timeout = (smb_GetSMBParm(inp, 5) << 16) + smb_GetSMBParm(inp, 4);
4856 NumberOfUnlocks = smb_GetSMBParm(inp, 6);
4857 NumberOfLocks = smb_GetSMBParm(inp, 7);
4859 if ((LockType & LOCKING_ANDX_CANCEL_LOCK) ||
4860 (LockType & LOCKING_ANDX_CHANGE_LOCKTYPE)) {
4862 /* We don't support these requests. Apparently, we can safely
4863 not deal with them too. */
4864 osi_Log1(smb_logp, "smb_ReceiveV3Locking received unsupported request [%s]",
4865 ((LockType & LOCKING_ANDX_CANCEL_LOCK)?
4866 "LOCKING_ANDX_CANCEL_LOCK":
4867 "LOCKING_ANDX_CHANGE_LOCKTYPE"));
4868 /* No need to call osi_LogSaveString since these are string
4871 code = CM_ERROR_BADOP;
4876 op = smb_GetSMBData(inp, NULL);
4878 for (i=0; i<NumberOfUnlocks; i++) {
4879 smb_GetLockParams(LockType, &op, &pid, &LOffset, &LLength);
4881 key = cm_GenerateKey(vcp->vcID, pid, fidp->fid);
4883 code = cm_Unlock(scp, LockType, LOffset, LLength, key, userp, &req);
4891 for (i=0; i<NumberOfLocks; i++) {
4892 smb_GetLockParams(LockType, &op, &pid, &LOffset, &LLength);
4894 key = cm_GenerateKey(vcp->vcID, pid, fidp->fid);
4896 code = cm_Lock(scp, LockType, LOffset, LLength, key, (Timeout != 0),
4897 userp, &req, &lockp);
4899 if (code == CM_ERROR_WOULDBLOCK && Timeout != 0) {
4900 smb_waitingLock_t * wLock;
4902 /* Put on waiting list */
4903 if(wlRequest == NULL) {
4907 LARGE_INTEGER tOffset, tLength;
4909 wlRequest = malloc(sizeof(smb_waitingLockRequest_t));
4911 osi_assert(wlRequest != NULL);
4913 wlRequest->vcp = vcp;
4915 wlRequest->scp = scp;
4917 wlRequest->inp = smb_CopyPacket(inp);
4918 wlRequest->outp = smb_CopyPacket(outp);
4919 wlRequest->lockType = LockType;
4920 wlRequest->timeRemaining = Timeout;
4921 wlRequest->locks = NULL;
4923 /* The waiting lock request needs to have enough
4924 information to undo all the locks in the request.
4925 We do the following to store info about locks that
4926 have already been granted. Sure, we can get most
4927 of the info from the packet, but the packet doesn't
4928 hold the result of cm_Lock call. In practice we
4929 only receive packets with one or two locks, so we
4930 are only wasting a few bytes here and there and
4931 only for a limited period of time until the waiting
4932 lock times out or is freed. */
4934 for(opt = op_locks, j=i; j > 0; j--) {
4935 smb_GetLockParams(LockType, &opt, &pid, &tOffset, &tLength);
4937 tkey = cm_GenerateKey(vcp->vcID, pid, fidp->fid);
4939 wLock = malloc(sizeof(smb_waitingLock_t));
4941 osi_assert(wLock != NULL);
4944 wLock->LOffset = tOffset;
4945 wLock->LLength = tLength;
4946 wLock->lockp = NULL;
4947 wLock->state = SMB_WAITINGLOCKSTATE_DONE;
4948 osi_QAdd((osi_queue_t **) &wlRequest->locks,
4953 wLock = malloc(sizeof(smb_waitingLock_t));
4955 osi_assert(wLock != NULL);
4958 wLock->LOffset = LOffset;
4959 wLock->LLength = LLength;
4960 wLock->lockp = lockp;
4961 wLock->state = SMB_WAITINGLOCKSTATE_WAITING;
4962 osi_QAdd((osi_queue_t **) &wlRequest->locks,
4965 osi_Log1(smb_logp, "smb_ReceiveV3Locking WaitingLock created 0x%p",
4973 osi_Log1(smb_logp, "smb_ReceiveV3Locking cm_Lock failure code 0x%x", code);
4980 /* Since something went wrong with the lock number i, we now
4981 have to go ahead and release any locks acquired before the
4982 failure. All locks before lock number i (of which there
4983 are i of them) have either been successful or are waiting.
4984 Either case requires calling cm_Unlock(). */
4986 /* And purge the waiting lock */
4987 if(wlRequest != NULL) {
4988 smb_waitingLock_t * wl;
4989 smb_waitingLock_t * wlNext;
4992 for(wl = wlRequest->locks; wl; wl = wlNext) {
4994 wlNext = (smb_waitingLock_t *) osi_QNext(&wl->q);
4996 ul_code = cm_Unlock(scp, LockType, wl->LOffset, wl->LLength, wl->key, userp, &req);
4999 osi_Log1(smb_logp, "smb_ReceiveV3Locking cm_Unlock returns code %d", ul_code);
5001 osi_Log0(smb_logp, "smb_ReceiveV3Locking cm_Unlock successful");
5004 osi_QRemove((osi_queue_t **) &wlRequest->locks, &wl->q);
5009 smb_ReleaseVC(wlRequest->vcp);
5010 cm_ReleaseSCache(wlRequest->scp);
5011 smb_FreePacket(wlRequest->inp);
5012 smb_FreePacket(wlRequest->outp);
5021 if (wlRequest != NULL) {
5023 lock_ObtainWrite(&smb_globalLock);
5024 osi_QAdd((osi_queue_t **)&smb_allWaitingLocks,
5026 osi_Wakeup((LONG_PTR)&smb_allWaitingLocks);
5027 lock_ReleaseWrite(&smb_globalLock);
5029 /* don't send reply immediately */
5030 outp->flags |= SMB_PACKETFLAG_NOSEND;
5033 smb_SetSMBDataLength(outp, 0);
5037 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_LOCK);
5040 lock_ReleaseMutex(&scp->mx);
5041 cm_ReleaseUser(userp);
5042 smb_ReleaseFID(fidp);
5047 long smb_ReceiveV3GetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5053 afs_uint32 searchTime;
5059 fid = smb_GetSMBParm(inp, 0);
5060 fid = smb_ChainFID(fid, inp);
5062 fidp = smb_FindFID(vcp, fid, 0);
5063 if (!fidp || (fidp->flags & SMB_FID_IOCTL)) {
5064 return CM_ERROR_BADFD;
5067 userp = smb_GetUser(vcp, inp);
5071 /* otherwise, stat the file */
5072 lock_ObtainMutex(&scp->mx);
5073 code = cm_SyncOp(scp, NULL, userp, &req, 0,
5074 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5075 if (code) goto done;
5077 /* decode times. We need a search time, but the response to this
5078 * call provides the date first, not the time, as returned in the
5079 * searchTime variable. So we take the high-order bits first.
5081 smb_SearchTimeFromUnixTime(&searchTime, scp->clientModTime);
5082 smb_SetSMBParm(outp, 0, (searchTime >> 16) & 0xffff); /* ctime */
5083 smb_SetSMBParm(outp, 1, searchTime & 0xffff);
5084 smb_SetSMBParm(outp, 2, (searchTime >> 16) & 0xffff); /* atime */
5085 smb_SetSMBParm(outp, 3, searchTime & 0xffff);
5086 smb_SetSMBParm(outp, 4, (searchTime >> 16) & 0xffff); /* mtime */
5087 smb_SetSMBParm(outp, 5, searchTime & 0xffff);
5089 /* now handle file size and allocation size */
5090 smb_SetSMBParm(outp, 6, scp->length.LowPart & 0xffff); /* file size */
5091 smb_SetSMBParm(outp, 7, (scp->length.LowPart >> 16) & 0xffff);
5092 smb_SetSMBParm(outp, 8, scp->length.LowPart & 0xffff); /* alloc size */
5093 smb_SetSMBParm(outp, 9, (scp->length.LowPart >> 16) & 0xffff);
5095 /* file attribute */
5096 smb_SetSMBParm(outp, 10, smb_Attributes(scp));
5098 /* and finalize stuff */
5099 smb_SetSMBDataLength(outp, 0);
5103 lock_ReleaseMutex(&scp->mx);
5104 cm_ReleaseUser(userp);
5105 smb_ReleaseFID(fidp);
5109 long smb_ReceiveV3SetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5115 afs_uint32 searchTime;
5123 fid = smb_GetSMBParm(inp, 0);
5124 fid = smb_ChainFID(fid, inp);
5126 fidp = smb_FindFID(vcp, fid, 0);
5127 if (!fidp || (fidp->flags & SMB_FID_IOCTL)) {
5128 return CM_ERROR_BADFD;
5131 userp = smb_GetUser(vcp, inp);
5135 /* now prepare to call cm_setattr. This message only sets various times,
5136 * and AFS only implements mtime, and we'll set the mtime if that's
5137 * requested. The others we'll ignore.
5139 searchTime = smb_GetSMBParm(inp, 5) | (smb_GetSMBParm(inp, 6) << 16);
5141 if (searchTime != 0) {
5142 smb_UnixTimeFromSearchTime(&unixTime, searchTime);
5144 if ( unixTime != -1 ) {
5145 attrs.mask = CM_ATTRMASK_CLIENTMODTIME;
5146 attrs.clientModTime = unixTime;
5147 code = cm_SetAttr(scp, &attrs, userp, &req);
5149 osi_Log1(smb_logp, "SMB receive V3SetAttributes [fid=%ld]", fid);
5151 osi_Log1(smb_logp, "**smb_UnixTimeFromSearchTime failed searchTime=%ld", searchTime);
5156 cm_ReleaseUser(userp);
5157 smb_ReleaseFID(fidp);
5162 long smb_ReceiveV3ReadX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5166 long finalCount = 0;
5175 fd = smb_GetSMBParm(inp, 2);
5176 count = smb_GetSMBParm(inp, 5);
5177 offset.HighPart = 0; /* too bad */
5178 offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
5180 osi_Log3(smb_logp, "smb_ReceiveV3Read fd %d, off 0x%x, size 0x%x",
5181 fd, offset.LowPart, count);
5183 fd = smb_ChainFID(fd, inp);
5184 fidp = smb_FindFID(vcp, fd, 0);
5186 return CM_ERROR_BADFD;
5189 pid = ((smb_t *) inp)->pid;
5190 key = cm_GenerateKey(vcp->vcID, pid, fd);
5192 LARGE_INTEGER LOffset, LLength;
5194 LOffset.HighPart = offset.HighPart;
5195 LOffset.LowPart = offset.LowPart;
5196 LLength.HighPart = 0;
5197 LLength.LowPart = count;
5199 lock_ObtainMutex(&fidp->scp->mx);
5200 code = cm_LockCheckRead(fidp->scp, LOffset, LLength, key);
5201 lock_ReleaseMutex(&fidp->scp->mx);
5205 smb_ReleaseFID(fidp);
5209 /* set inp->fid so that later read calls in same msg can find fid */
5212 if (fidp->flags & SMB_FID_IOCTL) {
5213 return smb_IoctlV3Read(fidp, vcp, inp, outp);
5216 userp = smb_GetUser(vcp, inp);
5218 /* 0 and 1 are reserved for request chaining, were setup by our caller,
5219 * and will be further filled in after we return.
5221 smb_SetSMBParm(outp, 2, 0); /* remaining bytes, for pipes */
5222 smb_SetSMBParm(outp, 3, 0); /* resvd */
5223 smb_SetSMBParm(outp, 4, 0); /* resvd */
5224 smb_SetSMBParm(outp, 5, count); /* # of bytes we're going to read */
5225 /* fill in #6 when we have all the parameters' space reserved */
5226 smb_SetSMBParm(outp, 7, 0); /* resv'd */
5227 smb_SetSMBParm(outp, 8, 0); /* resv'd */
5228 smb_SetSMBParm(outp, 9, 0); /* resv'd */
5229 smb_SetSMBParm(outp, 10, 0); /* resv'd */
5230 smb_SetSMBParm(outp, 11, 0); /* reserved */
5232 /* get op ptr after putting in the parms, since otherwise we don't
5233 * know where the data really is.
5235 op = smb_GetSMBData(outp, NULL);
5237 /* now fill in offset from start of SMB header to first data byte (to op) */
5238 smb_SetSMBParm(outp, 6, ((int) (op - outp->data)));
5240 /* set the packet data length the count of the # of bytes */
5241 smb_SetSMBDataLength(outp, count);
5244 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount);
5246 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount, FALSE);
5249 /* fix some things up */
5250 smb_SetSMBParm(outp, 5, finalCount);
5251 smb_SetSMBDataLength(outp, finalCount);
5253 smb_ReleaseFID(fidp);
5255 cm_ReleaseUser(userp);
5260 * Values for createDisp, copied from NTDDK.H
5262 #define FILE_SUPERSEDE 0 // (???)
5263 #define FILE_OPEN 1 // (open)
5264 #define FILE_CREATE 2 // (exclusive)
5265 #define FILE_OPEN_IF 3 // (non-exclusive)
5266 #define FILE_OVERWRITE 4 // (open & truncate, but do not create)
5267 #define FILE_OVERWRITE_IF 5 // (open & truncate, or create)
5270 #define REQUEST_OPLOCK 2
5271 #define REQUEST_BATCH_OPLOCK 4
5272 #define OPEN_DIRECTORY 8
5273 #define EXTENDED_RESPONSE_REQUIRED 0x10
5275 /* CreateOptions field. */
5276 #define FILE_DIRECTORY_FILE 0x0001
5277 #define FILE_WRITE_THROUGH 0x0002
5278 #define FILE_SEQUENTIAL_ONLY 0x0004
5279 #define FILE_NON_DIRECTORY_FILE 0x0040
5280 #define FILE_NO_EA_KNOWLEDGE 0x0200
5281 #define FILE_EIGHT_DOT_THREE_ONLY 0x0400
5282 #define FILE_RANDOM_ACCESS 0x0800
5283 #define FILE_DELETE_ON_CLOSE 0x1000
5284 #define FILE_OPEN_BY_FILE_ID 0x2000
5286 long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5288 char *pathp, *realPathp;
5292 cm_scache_t *dscp; /* parent dir */
5293 cm_scache_t *scp; /* file to create or open */
5294 cm_scache_t *targetScp; /* if scp is a symlink */
5298 unsigned short nameLength;
5300 unsigned int requestOpLock;
5301 unsigned int requestBatchOpLock;
5302 unsigned int mustBeDir;
5303 unsigned int extendedRespRequired;
5304 unsigned int treeCreate;
5306 unsigned int desiredAccess;
5307 unsigned int extAttributes;
5308 unsigned int createDisp;
5309 unsigned int createOptions;
5310 unsigned int shareAccess;
5311 int initialModeBits;
5312 unsigned short baseFid;
5313 smb_fid_t *baseFidp;
5315 cm_scache_t *baseDirp;
5316 unsigned short openAction;
5327 /* This code is very long and has a lot of if-then-else clauses
5328 * scp and dscp get reused frequently and we need to ensure that
5329 * we don't lose a reference. Start by ensuring that they are NULL.
5336 nameLength = smb_GetSMBOffsetParm(inp, 2, 1);
5337 flags = smb_GetSMBOffsetParm(inp, 3, 1)
5338 | (smb_GetSMBOffsetParm(inp, 4, 1) << 16);
5339 requestOpLock = flags & REQUEST_OPLOCK;
5340 requestBatchOpLock = flags & REQUEST_BATCH_OPLOCK;
5341 mustBeDir = flags & OPEN_DIRECTORY;
5342 extendedRespRequired = flags & EXTENDED_RESPONSE_REQUIRED;
5345 * Why all of a sudden 32-bit FID?
5346 * We will reject all bits higher than 16.
5348 if (smb_GetSMBOffsetParm(inp, 6, 1) != 0)
5349 return CM_ERROR_INVAL;
5350 baseFid = smb_GetSMBOffsetParm(inp, 5, 1);
5351 desiredAccess = smb_GetSMBOffsetParm(inp, 7, 1)
5352 | (smb_GetSMBOffsetParm(inp, 8, 1) << 16);
5353 extAttributes = smb_GetSMBOffsetParm(inp, 13, 1)
5354 | (smb_GetSMBOffsetParm(inp, 14, 1) << 16);
5355 shareAccess = smb_GetSMBOffsetParm(inp, 15, 1)
5356 | (smb_GetSMBOffsetParm(inp, 16, 1) << 16);
5357 createDisp = smb_GetSMBOffsetParm(inp, 17, 1)
5358 | (smb_GetSMBOffsetParm(inp, 18, 1) << 16);
5359 createOptions = smb_GetSMBOffsetParm(inp, 19, 1)
5360 | (smb_GetSMBOffsetParm(inp, 20, 1) << 16);
5362 /* mustBeDir is never set; createOptions directory bit seems to be
5365 if (createOptions & FILE_DIRECTORY_FILE)
5367 else if (createOptions & FILE_NON_DIRECTORY_FILE)
5373 * compute initial mode bits based on read-only flag in
5374 * extended attributes
5376 initialModeBits = 0666;
5377 if (extAttributes & SMB_ATTR_READONLY)
5378 initialModeBits &= ~0222;
5380 pathp = smb_GetSMBData(inp, NULL);
5381 /* Sometimes path is not null-terminated, so we make a copy. */
5382 realPathp = malloc(nameLength+1);
5383 memcpy(realPathp, pathp, nameLength);
5384 realPathp[nameLength] = 0;
5385 if (smb_StoreAnsiFilenames)
5386 OemToChar(realPathp,realPathp);
5388 spacep = inp->spacep;
5389 smb_StripLastComponent(spacep->data, &lastNamep, realPathp);
5391 osi_Log1(smb_logp,"NTCreateX for [%s]",osi_LogSaveString(smb_logp,realPathp));
5392 osi_Log4(smb_logp,"... da=[%x] ea=[%x] cd=[%x] co=[%x]", desiredAccess, extAttributes, createDisp, createOptions);
5393 osi_Log3(smb_logp,"... share=[%x] flags=[%x] lastNamep=[%s]", shareAccess, flags, osi_LogSaveString(smb_logp,(lastNamep?lastNamep:"null")));
5395 if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
5396 /* special case magic file name for receiving IOCTL requests
5397 * (since IOCTL calls themselves aren't getting through).
5399 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
5400 smb_SetupIoctlFid(fidp, spacep);
5401 osi_Log1(smb_logp,"NTCreateX Setting up IOCTL on fid[%d]",fidp->fid);
5403 /* set inp->fid so that later read calls in same msg can find fid */
5404 inp->fid = fidp->fid;
5408 smb_SetSMBParmByte(outp, parmSlot, 0); /* oplock */
5409 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
5410 smb_SetSMBParmLong(outp, parmSlot, 1); parmSlot += 2; /* Action */
5412 memset(&ft, 0, sizeof(ft));
5413 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
5414 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
5415 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
5416 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
5417 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2; /* attr */
5418 sz.HighPart = 0x7fff; sz.LowPart = 0;
5419 smb_SetSMBParmDouble(outp, parmSlot, (char *)&sz); parmSlot += 4; /* alen */
5420 smb_SetSMBParmDouble(outp, parmSlot, (char *)&sz); parmSlot += 4; /* len */
5421 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* filetype */
5422 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* dev state */
5423 smb_SetSMBParmByte(outp, parmSlot, 0); /* is a dir? */
5424 smb_SetSMBDataLength(outp, 0);
5426 /* clean up fid reference */
5427 smb_ReleaseFID(fidp);
5432 #ifdef DEBUG_VERBOSE
5434 char *hexp, *asciip;
5435 asciip = (lastNamep? lastNamep : realPathp);
5436 hexp = osi_HexifyString( asciip );
5437 DEBUG_EVENT2("AFS", "NTCreateX H[%s] A[%s]", hexp, asciip);
5442 userp = smb_GetUser(vcp, inp);
5444 osi_Log1(smb_logp, "NTCreateX Invalid user [%d]", ((smb_t *) inp)->uid);
5446 return CM_ERROR_INVAL;
5450 baseDirp = cm_data.rootSCachep;
5451 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5452 if (code == CM_ERROR_TIDIPC) {
5453 /* Attempt to use a TID allocated for IPC. The client
5454 * is probably looking for DCE RPC end points which we
5455 * don't support OR it could be looking to make a DFS
5458 osi_Log0(smb_logp, "NTCreateX received IPC TID");
5461 cm_ReleaseUser(userp);
5462 return CM_ERROR_NOSUCHFILE;
5463 #endif /* DFS_SUPPORT */
5466 baseFidp = smb_FindFID(vcp, baseFid, 0);
5468 osi_Log1(smb_logp, "NTCreateX Invalid base fid [%d]", baseFid);
5470 cm_ReleaseUser(userp);
5471 return CM_ERROR_INVAL;
5473 baseDirp = baseFidp->scp;
5477 osi_Log1(smb_logp, "NTCreateX tidPathp=[%s]", (tidPathp==NULL)?"null": osi_LogSaveString(smb_logp,tidPathp));
5479 /* compute open mode */
5481 if (desiredAccess & DELETE)
5482 fidflags |= SMB_FID_OPENDELETE;
5483 if (desiredAccess & AFS_ACCESS_READ)
5484 fidflags |= SMB_FID_OPENREAD;
5485 if (desiredAccess & AFS_ACCESS_WRITE)
5486 fidflags |= SMB_FID_OPENWRITE;
5487 if (createOptions & FILE_DELETE_ON_CLOSE)
5488 fidflags |= SMB_FID_DELONCLOSE;
5490 /* and the share mode */
5491 if (shareAccess & FILE_SHARE_READ)
5492 fidflags |= SMB_FID_SHARE_READ;
5493 if (shareAccess & FILE_SHARE_WRITE)
5494 fidflags |= SMB_FID_SHARE_WRITE;
5498 /* For an exclusive create, we want to do a case sensitive match for the last component. */
5499 if ( createDisp == FILE_CREATE ||
5500 createDisp == FILE_OVERWRITE ||
5501 createDisp == FILE_OVERWRITE_IF) {
5502 code = cm_NameI(baseDirp, spacep->data, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
5503 userp, tidPathp, &req, &dscp);
5506 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
5507 cm_ReleaseSCache(dscp);
5508 cm_ReleaseUser(userp);
5510 if ( WANTS_DFS_PATHNAMES(inp) )
5511 return CM_ERROR_PATH_NOT_COVERED;
5513 return CM_ERROR_BADSHARENAME;
5515 #endif /* DFS_SUPPORT */
5516 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp, CM_FLAG_FOLLOW,
5518 if (code == CM_ERROR_NOSUCHFILE) {
5519 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp,
5520 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, &req, &scp);
5521 if (code == 0 && realDirFlag == 1) {
5522 cm_ReleaseSCache(scp);
5523 cm_ReleaseSCache(dscp);
5524 cm_ReleaseUser(userp);
5526 return CM_ERROR_EXISTS;
5530 /* we have both scp and dscp */
5532 code = cm_NameI(baseDirp, realPathp, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
5533 userp, tidPathp, &req, &scp);
5535 if (code == 0 && scp->fileType == CM_SCACHETYPE_DFSLINK) {
5536 cm_ReleaseSCache(scp);
5537 cm_ReleaseUser(userp);
5539 if ( WANTS_DFS_PATHNAMES(inp) )
5540 return CM_ERROR_PATH_NOT_COVERED;
5542 return CM_ERROR_BADSHARENAME;
5544 #endif /* DFS_SUPPORT */
5545 /* we might have scp but not dscp */
5551 if (!foundscp || (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE))) {
5552 /* look up parent directory */
5553 /* If we are trying to create a path (i.e. multiple nested directories), then we don't *need*
5554 * the immediate parent. We have to work our way up realPathp until we hit something that we
5558 /* we might or might not have scp */
5564 code = cm_NameI(baseDirp, spacep->data,
5565 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
5566 userp, tidPathp, &req, &dscp);
5569 if (code == 0 && dscp->fileType == CM_SCACHETYPE_DFSLINK) {
5571 cm_ReleaseSCache(scp);
5572 cm_ReleaseSCache(dscp);
5573 cm_ReleaseUser(userp);
5575 if ( WANTS_DFS_PATHNAMES(inp) )
5576 return CM_ERROR_PATH_NOT_COVERED;
5578 return CM_ERROR_BADSHARENAME;
5580 #endif /* DFS_SUPPORT */
5583 (tp = strrchr(spacep->data,'\\')) &&
5584 (createDisp == FILE_CREATE) &&
5585 (realDirFlag == 1)) {
5588 treeStartp = realPathp + (tp - spacep->data);
5590 if (*tp && !smb_IsLegalFilename(tp)) {
5592 smb_ReleaseFID(baseFidp);
5593 cm_ReleaseUser(userp);
5596 cm_ReleaseSCache(scp);
5597 return CM_ERROR_BADNTFILENAME;
5601 } while (dscp == NULL && code == 0);
5605 /* we might have scp and we might have dscp */
5608 smb_ReleaseFID(baseFidp);
5611 osi_Log0(smb_logp,"NTCreateX parent not found");
5613 cm_ReleaseSCache(scp);
5615 cm_ReleaseSCache(dscp);
5616 cm_ReleaseUser(userp);
5621 if (treeCreate && dscp->fileType == CM_SCACHETYPE_FILE) {
5622 /* A file exists where we want a directory. */
5624 cm_ReleaseSCache(scp);
5625 cm_ReleaseSCache(dscp);
5626 cm_ReleaseUser(userp);
5628 return CM_ERROR_EXISTS;
5632 lastNamep = realPathp;
5636 if (!smb_IsLegalFilename(lastNamep)) {
5638 cm_ReleaseSCache(scp);
5640 cm_ReleaseSCache(dscp);
5641 cm_ReleaseUser(userp);
5643 return CM_ERROR_BADNTFILENAME;
5646 if (!foundscp && !treeCreate) {
5647 if ( createDisp == FILE_CREATE ||
5648 createDisp == FILE_OVERWRITE ||
5649 createDisp == FILE_OVERWRITE_IF)
5651 code = cm_Lookup(dscp, lastNamep,
5652 CM_FLAG_FOLLOW, userp, &req, &scp);
5654 code = cm_Lookup(dscp, lastNamep,
5655 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
5658 if (code && code != CM_ERROR_NOSUCHFILE) {
5660 cm_ReleaseSCache(dscp);
5661 cm_ReleaseUser(userp);
5666 /* we have scp and dscp */
5668 /* we have scp but not dscp */
5670 smb_ReleaseFID(baseFidp);
5673 /* if we get here, if code is 0, the file exists and is represented by
5674 * scp. Otherwise, we have to create it. The dir may be represented
5675 * by dscp, or we may have found the file directly. If code is non-zero,
5678 if (code == 0 && !treeCreate) {
5679 code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp, &req);
5682 cm_ReleaseSCache(dscp);
5684 cm_ReleaseSCache(scp);
5685 cm_ReleaseUser(userp);
5690 if (createDisp == FILE_CREATE) {
5691 /* oops, file shouldn't be there */
5693 cm_ReleaseSCache(dscp);
5695 cm_ReleaseSCache(scp);
5696 cm_ReleaseUser(userp);
5698 return CM_ERROR_EXISTS;
5701 if ( createDisp == FILE_OVERWRITE ||
5702 createDisp == FILE_OVERWRITE_IF) {
5704 setAttr.mask = CM_ATTRMASK_LENGTH;
5705 setAttr.length.LowPart = 0;
5706 setAttr.length.HighPart = 0;
5707 /* now watch for a symlink */
5709 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
5711 osi_assert(dscp != NULL);
5712 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
5714 /* we have a more accurate file to use (the
5715 * target of the symbolic link). Otherwise,
5716 * we'll just use the symlink anyway.
5718 osi_Log2(smb_logp, "symlink vp %x to vp %x",
5720 cm_ReleaseSCache(scp);
5724 code = cm_SetAttr(scp, &setAttr, userp, &req);
5725 openAction = 3; /* truncated existing file */
5728 openAction = 1; /* found existing file */
5730 } else if (createDisp == FILE_OPEN || createDisp == FILE_OVERWRITE) {
5731 /* don't create if not found */
5733 cm_ReleaseSCache(dscp);
5735 cm_ReleaseSCache(scp);
5736 cm_ReleaseUser(userp);
5738 return CM_ERROR_NOSUCHFILE;
5739 } else if (realDirFlag == 0 || realDirFlag == -1) {
5740 osi_assert(dscp != NULL);
5741 osi_Log1(smb_logp, "smb_ReceiveNTCreateX creating file %s",
5742 osi_LogSaveString(smb_logp, lastNamep));
5743 openAction = 2; /* created file */
5744 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
5745 setAttr.clientModTime = time(NULL);
5746 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp, &req);
5747 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
5748 smb_NotifyChange(FILE_ACTION_ADDED,
5749 FILE_NOTIFY_CHANGE_FILE_NAME,
5750 dscp, lastNamep, NULL, TRUE);
5751 if (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE) {
5752 /* Not an exclusive create, and someone else tried
5753 * creating it already, then we open it anyway. We
5754 * don't bother retrying after this, since if this next
5755 * fails, that means that the file was deleted after we
5756 * started this call.
5758 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
5761 if (createDisp == FILE_OVERWRITE_IF) {
5762 setAttr.mask = CM_ATTRMASK_LENGTH;
5763 setAttr.length.LowPart = 0;
5764 setAttr.length.HighPart = 0;
5766 /* now watch for a symlink */
5768 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
5770 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
5772 /* we have a more accurate file to use (the
5773 * target of the symbolic link). Otherwise,
5774 * we'll just use the symlink anyway.
5776 osi_Log2(smb_logp, "symlink vp %x to vp %x",
5778 cm_ReleaseSCache(scp);
5782 code = cm_SetAttr(scp, &setAttr, userp, &req);
5784 } /* lookup succeeded */
5788 char *cp; /* This component */
5789 int clen = 0; /* length of component */
5790 cm_scache_t *tscp1, *tscp2;
5793 /* create directory */
5795 treeStartp = lastNamep;
5796 osi_assert(dscp != NULL);
5797 osi_Log1(smb_logp, "smb_ReceiveNTCreateX creating directory [%s]",
5798 osi_LogSaveString(smb_logp, treeStartp));
5799 openAction = 2; /* created directory */
5801 /* if the request is to create the root directory
5802 * it will appear as a directory name of the nul-string
5803 * and a code of CM_ERROR_NOSUCHFILE
5805 if ( !*treeStartp && code == CM_ERROR_NOSUCHFILE)
5806 code = CM_ERROR_EXISTS;
5808 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
5809 setAttr.clientModTime = time(NULL);
5814 cm_HoldSCache(tscp1);
5818 tp = strchr(pp, '\\');
5821 clen = (int)strlen(cp);
5822 isLast = 1; /* indicate last component. the supplied path never ends in a slash */
5824 clen = (int)(tp - pp);
5825 strncpy(cp,pp,clen);
5832 continue; /* the supplied path can't have consecutive slashes either , but */
5834 /* cp is the next component to be created. */
5835 code = cm_MakeDir(tscp1, cp, 0, &setAttr, userp, &req);
5836 if (code == 0 && (tscp1->flags & CM_SCACHEFLAG_ANYWATCH))
5837 smb_NotifyChange(FILE_ACTION_ADDED,
5838 FILE_NOTIFY_CHANGE_DIR_NAME,
5839 tscp1, cp, NULL, TRUE);
5841 (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE)) {
5842 /* Not an exclusive create, and someone else tried
5843 * creating it already, then we open it anyway. We
5844 * don't bother retrying after this, since if this next
5845 * fails, that means that the file was deleted after we
5846 * started this call.
5848 code = cm_Lookup(tscp1, cp, CM_FLAG_CASEFOLD,
5849 userp, &req, &tscp2);
5854 if (!isLast) { /* for anything other than dscp, release it unless it's the last one */
5855 cm_ReleaseSCache(tscp1);
5856 tscp1 = tscp2; /* Newly created directory will be next parent */
5857 /* the hold is transfered to tscp1 from tscp2 */
5862 cm_ReleaseSCache(dscp);
5865 cm_ReleaseSCache(scp);
5868 * if we get here and code == 0, then scp is the last directory created, and dscp is the
5874 /* something went wrong creating or truncating the file */
5876 cm_ReleaseSCache(scp);
5878 cm_ReleaseSCache(dscp);
5879 cm_ReleaseUser(userp);
5884 /* make sure we have file vs. dir right (only applies for single component case) */
5885 if (realDirFlag == 0 && scp->fileType != CM_SCACHETYPE_FILE) {
5886 /* now watch for a symlink */
5888 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
5889 cm_scache_t * targetScp = 0;
5890 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
5892 /* we have a more accurate file to use (the
5893 * target of the symbolic link). Otherwise,
5894 * we'll just use the symlink anyway.
5896 osi_Log2(smb_logp, "symlink vp %x to vp %x", scp, targetScp);
5897 cm_ReleaseSCache(scp);
5902 if (scp->fileType != CM_SCACHETYPE_FILE) {
5904 cm_ReleaseSCache(dscp);
5905 cm_ReleaseSCache(scp);
5906 cm_ReleaseUser(userp);
5908 return CM_ERROR_ISDIR;
5912 /* (only applies to single component case) */
5913 if (realDirFlag == 1 && scp->fileType == CM_SCACHETYPE_FILE) {
5914 cm_ReleaseSCache(scp);
5916 cm_ReleaseSCache(dscp);
5917 cm_ReleaseUser(userp);
5919 return CM_ERROR_NOTDIR;
5922 /* open the file itself */
5923 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
5926 /* save a reference to the user */
5928 fidp->userp = userp;
5930 /* If we are restricting sharing, we should do so with a suitable
5932 if (scp->fileType == CM_SCACHETYPE_FILE &&
5933 !(fidflags & SMB_FID_SHARE_WRITE)) {
5935 LARGE_INTEGER LOffset, LLength;
5938 LOffset.HighPart = SMB_FID_QLOCK_HIGH;
5939 LOffset.LowPart = SMB_FID_QLOCK_LOW;
5940 LLength.HighPart = 0;
5941 LLength.LowPart = SMB_FID_QLOCK_LENGTH;
5943 if (fidflags & SMB_FID_SHARE_READ) {
5944 sLockType = LOCKING_ANDX_SHARED_LOCK;
5949 key = cm_GenerateKey(vcp->vcID, SMB_FID_QLOCK_PID, fidp->fid);
5951 lock_ObtainMutex(&scp->mx);
5952 code = cm_Lock(scp, sLockType, LOffset, LLength, key, 0, userp, &req, NULL);
5953 lock_ReleaseMutex(&scp->mx);
5956 fidp->flags = SMB_FID_DELETE;
5957 smb_ReleaseFID(fidp);
5959 cm_ReleaseSCache(scp);
5961 cm_ReleaseSCache(dscp);
5962 cm_ReleaseUser(userp);
5969 /* save a pointer to the vnode */
5970 fidp->scp = scp; /* Hold transfered to fidp->scp and no longer needed */
5972 fidp->flags = fidflags;
5974 /* save parent dir and pathname for delete or change notification */
5975 if (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE)) {
5976 fidp->flags |= SMB_FID_NTOPEN;
5977 fidp->NTopen_dscp = dscp;
5978 cm_HoldSCache(dscp);
5979 fidp->NTopen_pathp = strdup(lastNamep);
5981 fidp->NTopen_wholepathp = realPathp;
5983 /* we don't need this any longer */
5985 cm_ReleaseSCache(dscp);
5989 cm_Open(scp, 0, userp);
5991 /* set inp->fid so that later read calls in same msg can find fid */
5992 inp->fid = fidp->fid;
5996 lock_ObtainMutex(&scp->mx);
5997 smb_SetSMBParmByte(outp, parmSlot, 0); /* oplock */
5998 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
5999 smb_SetSMBParmLong(outp, parmSlot, openAction); parmSlot += 2;
6000 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
6001 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
6002 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
6003 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
6004 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
6005 smb_SetSMBParmLong(outp, parmSlot, smb_ExtAttributes(scp));
6007 smb_SetSMBParmDouble(outp, parmSlot, (char *)&scp->length); parmSlot += 4;
6008 smb_SetSMBParmDouble(outp, parmSlot, (char *)&scp->length); parmSlot += 4;
6009 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* filetype */
6010 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* dev state */
6011 smb_SetSMBParmByte(outp, parmSlot,
6012 scp->fileType == CM_SCACHETYPE_DIRECTORY); /* is a dir? */
6013 lock_ReleaseMutex(&scp->mx);
6014 smb_SetSMBDataLength(outp, 0);
6016 osi_Log2(smb_logp, "SMB NT CreateX opening fid %d path %s", fidp->fid,
6017 osi_LogSaveString(smb_logp, realPathp));
6019 smb_ReleaseFID(fidp);
6021 cm_ReleaseUser(userp);
6023 /* Can't free realPathp if we get here since
6024 fidp->NTopen_wholepathp is pointing there */
6026 /* leave scp held since we put it in fidp->scp */
6031 * A lot of stuff copied verbatim from NT Create&X to NT Tran Create.
6032 * Instead, ultimately, would like to use a subroutine for common code.
6034 long smb_ReceiveNTTranCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6036 char *pathp, *realPathp;
6040 cm_scache_t *dscp; /* parent dir */
6041 cm_scache_t *scp; /* file to create or open */
6042 cm_scache_t *targetScp; /* if scp is a symlink */
6045 unsigned long nameLength;
6047 unsigned int requestOpLock;
6048 unsigned int requestBatchOpLock;
6049 unsigned int mustBeDir;
6050 unsigned int extendedRespRequired;
6052 unsigned int desiredAccess;
6053 #ifdef DEBUG_VERBOSE
6054 unsigned int allocSize;
6056 unsigned int shareAccess;
6057 unsigned int extAttributes;
6058 unsigned int createDisp;
6059 #ifdef DEBUG_VERBOSE
6062 unsigned int createOptions;
6063 int initialModeBits;
6064 unsigned short baseFid;
6065 smb_fid_t *baseFidp;
6067 cm_scache_t *baseDirp;
6068 unsigned short openAction;
6074 int parmOffset, dataOffset;
6085 parmOffset = smb_GetSMBOffsetParm(inp, 11, 1)
6086 | (smb_GetSMBOffsetParm(inp, 12, 1) << 16);
6087 parmp = inp->data + parmOffset;
6088 lparmp = (ULONG *) parmp;
6091 requestOpLock = flags & REQUEST_OPLOCK;
6092 requestBatchOpLock = flags & REQUEST_BATCH_OPLOCK;
6093 mustBeDir = flags & OPEN_DIRECTORY;
6094 extendedRespRequired = flags & EXTENDED_RESPONSE_REQUIRED;
6097 * Why all of a sudden 32-bit FID?
6098 * We will reject all bits higher than 16.
6100 if (lparmp[1] & 0xFFFF0000)
6101 return CM_ERROR_INVAL;
6102 baseFid = (unsigned short)lparmp[1];
6103 desiredAccess = lparmp[2];
6104 #ifdef DEBUG_VERBOSE
6105 allocSize = lparmp[3];
6106 #endif /* DEBUG_VERSOSE */
6107 extAttributes = lparmp[5];
6108 shareAccess = lparmp[6];
6109 createDisp = lparmp[7];
6110 createOptions = lparmp[8];
6111 #ifdef DEBUG_VERBOSE
6114 nameLength = lparmp[11];
6116 #ifdef DEBUG_VERBOSE
6117 osi_Log4(smb_logp,"NTTranCreate with da[%x],ea[%x],sa[%x],cd[%x]",desiredAccess,extAttributes,shareAccess,createDisp);
6118 osi_Log3(smb_logp,"... co[%x],sdl[%x],as[%x]",createOptions,sdLen,allocSize);
6119 osi_Log1(smb_logp,"... flags[%x]",flags);
6122 /* mustBeDir is never set; createOptions directory bit seems to be
6125 if (createOptions & FILE_DIRECTORY_FILE)
6127 else if (createOptions & FILE_NON_DIRECTORY_FILE)
6133 * compute initial mode bits based on read-only flag in
6134 * extended attributes
6136 initialModeBits = 0666;
6137 if (extAttributes & 1)
6138 initialModeBits &= ~0222;
6140 pathp = parmp + (13 * sizeof(ULONG)) + sizeof(UCHAR);
6141 /* Sometimes path is not null-terminated, so we make a copy. */
6142 realPathp = malloc(nameLength+1);
6143 memcpy(realPathp, pathp, nameLength);
6144 realPathp[nameLength] = 0;
6145 if (smb_StoreAnsiFilenames)
6146 OemToChar(realPathp,realPathp);
6148 spacep = cm_GetSpace();
6149 smb_StripLastComponent(spacep->data, &lastNamep, realPathp);
6152 * Nothing here to handle SMB_IOCTL_FILENAME.
6153 * Will add it if necessary.
6156 #ifdef DEBUG_VERBOSE
6158 char *hexp, *asciip;
6159 asciip = (lastNamep? lastNamep : realPathp);
6160 hexp = osi_HexifyString( asciip );
6161 DEBUG_EVENT2("AFS", "NTTranCreate H[%s] A[%s]", hexp, asciip);
6166 userp = smb_GetUser(vcp, inp);
6168 osi_Log1(smb_logp, "NTTranCreate invalid user [%d]", ((smb_t *) inp)->uid);
6170 return CM_ERROR_INVAL;
6174 baseDirp = cm_data.rootSCachep;
6175 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
6176 if (code == CM_ERROR_TIDIPC) {
6177 /* Attempt to use a TID allocated for IPC. The client
6178 * is probably looking for DCE RPC end points which we
6179 * don't support OR it could be looking to make a DFS
6182 osi_Log0(smb_logp, "NTTranCreate received IPC TID");
6185 cm_ReleaseUser(userp);
6186 return CM_ERROR_NOSUCHPATH;
6190 baseFidp = smb_FindFID(vcp, baseFid, 0);
6192 osi_Log1(smb_logp, "NTTranCreate Invalid fid [%d]", baseFid);
6194 cm_ReleaseUser(userp);
6195 return CM_ERROR_INVAL;
6197 baseDirp = baseFidp->scp;
6201 /* compute open mode */
6203 if (desiredAccess & DELETE)
6204 fidflags |= SMB_FID_OPENDELETE;
6205 if (desiredAccess & AFS_ACCESS_READ)
6206 fidflags |= SMB_FID_OPENREAD;
6207 if (desiredAccess & AFS_ACCESS_WRITE)
6208 fidflags |= SMB_FID_OPENWRITE;
6209 if (createOptions & FILE_DELETE_ON_CLOSE)
6210 fidflags |= SMB_FID_DELONCLOSE;
6212 /* And the share mode */
6213 if (shareAccess & FILE_SHARE_READ)
6214 fidflags |= SMB_FID_SHARE_READ;
6215 if (shareAccess & FILE_SHARE_WRITE)
6216 fidflags |= SMB_FID_SHARE_WRITE;
6220 if ( createDisp == FILE_OPEN ||
6221 createDisp == FILE_OVERWRITE ||
6222 createDisp == FILE_OVERWRITE_IF) {
6223 code = cm_NameI(baseDirp, spacep->data, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
6224 userp, tidPathp, &req, &dscp);
6227 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
6228 cm_ReleaseSCache(dscp);
6229 cm_ReleaseUser(userp);
6231 if ( WANTS_DFS_PATHNAMES(inp) )
6232 return CM_ERROR_PATH_NOT_COVERED;
6234 return CM_ERROR_BADSHARENAME;
6236 #endif /* DFS_SUPPORT */
6237 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp, CM_FLAG_FOLLOW,
6239 if (code == CM_ERROR_NOSUCHFILE) {
6240 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp,
6241 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, &req, &scp);
6242 if (code == 0 && realDirFlag == 1) {
6243 cm_ReleaseSCache(scp);
6244 cm_ReleaseSCache(dscp);
6245 cm_ReleaseUser(userp);
6247 return CM_ERROR_EXISTS;
6253 code = cm_NameI(baseDirp, realPathp, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
6254 userp, tidPathp, &req, &scp);
6256 if (code == 0 && scp->fileType == CM_SCACHETYPE_DFSLINK) {
6257 cm_ReleaseSCache(scp);
6258 cm_ReleaseUser(userp);
6260 if ( WANTS_DFS_PATHNAMES(inp) )
6261 return CM_ERROR_PATH_NOT_COVERED;
6263 return CM_ERROR_BADSHARENAME;
6265 #endif /* DFS_SUPPORT */
6271 if (code != 0 || (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE))) {
6272 /* look up parent directory */
6274 code = cm_NameI(baseDirp, spacep->data,
6275 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
6276 userp, tidPathp, &req, &dscp);
6278 if (code == 0 && dscp->fileType == CM_SCACHETYPE_DFSLINK) {
6279 cm_ReleaseSCache(dscp);
6280 cm_ReleaseUser(userp);
6282 if ( WANTS_DFS_PATHNAMES(inp) )
6283 return CM_ERROR_PATH_NOT_COVERED;
6285 return CM_ERROR_BADSHARENAME;
6287 #endif /* DFS_SUPPORT */
6291 cm_FreeSpace(spacep);
6294 smb_ReleaseFID(baseFidp);
6299 cm_ReleaseUser(userp);
6304 if (!lastNamep) lastNamep = realPathp;
6307 if (!smb_IsLegalFilename(lastNamep))
6308 return CM_ERROR_BADNTFILENAME;
6311 if (createDisp == FILE_CREATE || createDisp == FILE_OVERWRITE_IF) {
6312 code = cm_Lookup(dscp, lastNamep,
6313 CM_FLAG_FOLLOW, userp, &req, &scp);
6315 code = cm_Lookup(dscp, lastNamep,
6316 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
6319 if (code && code != CM_ERROR_NOSUCHFILE) {
6320 cm_ReleaseSCache(dscp);
6321 cm_ReleaseUser(userp);
6328 smb_ReleaseFID(baseFidp);
6331 cm_FreeSpace(spacep);
6334 /* if we get here, if code is 0, the file exists and is represented by
6335 * scp. Otherwise, we have to create it. The dir may be represented
6336 * by dscp, or we may have found the file directly. If code is non-zero,
6340 code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp,
6344 cm_ReleaseSCache(dscp);
6345 cm_ReleaseSCache(scp);
6346 cm_ReleaseUser(userp);
6351 if (createDisp == FILE_CREATE) {
6352 /* oops, file shouldn't be there */
6354 cm_ReleaseSCache(dscp);
6355 cm_ReleaseSCache(scp);
6356 cm_ReleaseUser(userp);
6358 return CM_ERROR_EXISTS;
6361 if (createDisp == FILE_OVERWRITE ||
6362 createDisp == FILE_OVERWRITE_IF) {
6363 setAttr.mask = CM_ATTRMASK_LENGTH;
6364 setAttr.length.LowPart = 0;
6365 setAttr.length.HighPart = 0;
6367 /* now watch for a symlink */
6369 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
6371 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
6373 /* we have a more accurate file to use (the
6374 * target of the symbolic link). Otherwise,
6375 * we'll just use the symlink anyway.
6377 osi_Log2(smb_logp, "symlink vp %x to vp %x",
6379 cm_ReleaseSCache(scp);
6383 code = cm_SetAttr(scp, &setAttr, userp, &req);
6384 openAction = 3; /* truncated existing file */
6386 else openAction = 1; /* found existing file */
6388 else if (createDisp == FILE_OPEN || createDisp == FILE_OVERWRITE) {
6389 /* don't create if not found */
6391 cm_ReleaseSCache(dscp);
6392 cm_ReleaseUser(userp);
6394 return CM_ERROR_NOSUCHFILE;
6396 else if (realDirFlag == 0 || realDirFlag == -1) {
6397 osi_assert(dscp != NULL);
6398 osi_Log1(smb_logp, "smb_ReceiveNTTranCreate creating file %s",
6399 osi_LogSaveString(smb_logp, lastNamep));
6400 openAction = 2; /* created file */
6401 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
6402 setAttr.clientModTime = time(NULL);
6403 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
6405 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
6406 smb_NotifyChange(FILE_ACTION_ADDED,
6407 FILE_NOTIFY_CHANGE_FILE_NAME,
6408 dscp, lastNamep, NULL, TRUE);
6409 if (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE) {
6410 /* Not an exclusive create, and someone else tried
6411 * creating it already, then we open it anyway. We
6412 * don't bother retrying after this, since if this next
6413 * fails, that means that the file was deleted after we
6414 * started this call.
6416 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
6419 if (createDisp == FILE_OVERWRITE_IF) {
6420 setAttr.mask = CM_ATTRMASK_LENGTH;
6421 setAttr.length.LowPart = 0;
6422 setAttr.length.HighPart = 0;
6424 /* now watch for a symlink */
6426 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
6428 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
6430 /* we have a more accurate file to use (the
6431 * target of the symbolic link). Otherwise,
6432 * we'll just use the symlink anyway.
6434 osi_Log2(smb_logp, "symlink vp %x to vp %x",
6436 cm_ReleaseSCache(scp);
6440 code = cm_SetAttr(scp, &setAttr, userp, &req);
6442 } /* lookup succeeded */
6445 /* create directory */
6446 osi_assert(dscp != NULL);
6448 "smb_ReceiveNTTranCreate creating directory %s",
6449 osi_LogSaveString(smb_logp, lastNamep));
6450 openAction = 2; /* created directory */
6451 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
6452 setAttr.clientModTime = time(NULL);
6453 code = cm_MakeDir(dscp, lastNamep, 0, &setAttr, userp, &req);
6454 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
6455 smb_NotifyChange(FILE_ACTION_ADDED,
6456 FILE_NOTIFY_CHANGE_DIR_NAME,
6457 dscp, lastNamep, NULL, TRUE);
6459 (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE)) {
6460 /* Not an exclusive create, and someone else tried
6461 * creating it already, then we open it anyway. We
6462 * don't bother retrying after this, since if this next
6463 * fails, that means that the file was deleted after we
6464 * started this call.
6466 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
6472 /* something went wrong creating or truncating the file */
6474 cm_ReleaseSCache(scp);
6475 cm_ReleaseUser(userp);
6480 /* make sure we have file vs. dir right */
6481 if (realDirFlag == 0 && scp->fileType != CM_SCACHETYPE_FILE) {
6482 /* now watch for a symlink */
6484 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
6486 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
6488 /* we have a more accurate file to use (the
6489 * target of the symbolic link). Otherwise,
6490 * we'll just use the symlink anyway.
6492 osi_Log2(smb_logp, "symlink vp %x to vp %x",
6494 cm_ReleaseSCache(scp);
6499 if (scp->fileType != CM_SCACHETYPE_FILE) {
6500 cm_ReleaseSCache(scp);
6501 cm_ReleaseUser(userp);
6503 return CM_ERROR_ISDIR;
6507 if (realDirFlag == 1 && scp->fileType == CM_SCACHETYPE_FILE) {
6508 cm_ReleaseSCache(scp);
6509 cm_ReleaseUser(userp);
6511 return CM_ERROR_NOTDIR;
6514 /* open the file itself */
6515 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
6518 /* save a reference to the user */
6520 fidp->userp = userp;
6522 /* If we are restricting sharing, we should do so with a suitable
6524 if (scp->fileType == CM_SCACHETYPE_FILE &&
6525 !(fidflags & SMB_FID_SHARE_WRITE)) {
6527 LARGE_INTEGER LOffset, LLength;
6530 LOffset.HighPart = SMB_FID_QLOCK_HIGH;
6531 LOffset.LowPart = SMB_FID_QLOCK_LOW;
6532 LLength.HighPart = 0;
6533 LLength.LowPart = SMB_FID_QLOCK_LENGTH;
6535 if (fidflags & SMB_FID_SHARE_READ) {
6536 sLockType = LOCKING_ANDX_SHARED_LOCK;
6541 key = cm_GenerateKey(vcp->vcID, SMB_FID_QLOCK_PID, fidp->fid);
6543 lock_ObtainMutex(&scp->mx);
6544 code = cm_Lock(scp, sLockType, LOffset, LLength, key, 0, userp, &req, NULL);
6545 lock_ReleaseMutex(&scp->mx);
6548 fidp->flags = SMB_FID_DELETE;
6549 smb_ReleaseFID(fidp);
6551 cm_ReleaseSCache(scp);
6552 cm_ReleaseUser(userp);
6555 return CM_ERROR_SHARING_VIOLATION;
6559 /* save a pointer to the vnode */
6562 fidp->flags = fidflags;
6564 /* save parent dir and pathname for deletion or change notification */
6565 if (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE)) {
6566 fidp->flags |= SMB_FID_NTOPEN;
6567 fidp->NTopen_dscp = dscp;
6568 cm_HoldSCache(dscp);
6569 fidp->NTopen_pathp = strdup(lastNamep);
6571 fidp->NTopen_wholepathp = realPathp;
6573 /* we don't need this any longer */
6575 cm_ReleaseSCache(dscp);
6577 cm_Open(scp, 0, userp);
6579 /* set inp->fid so that later read calls in same msg can find fid */
6580 inp->fid = fidp->fid;
6582 /* check whether we are required to send an extended response */
6583 if (!extendedRespRequired) {
6585 parmOffset = 8*4 + 39;
6586 parmOffset += 1; /* pad to 4 */
6587 dataOffset = parmOffset + 70;
6591 /* Total Parameter Count */
6592 smb_SetSMBParmLong(outp, parmSlot, 70); parmSlot += 2;
6593 /* Total Data Count */
6594 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
6595 /* Parameter Count */
6596 smb_SetSMBParmLong(outp, parmSlot, 70); parmSlot += 2;
6597 /* Parameter Offset */
6598 smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
6599 /* Parameter Displacement */
6600 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
6602 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
6604 smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
6605 /* Data Displacement */
6606 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
6607 smb_SetSMBParmByte(outp, parmSlot, 0); /* Setup Count */
6608 smb_SetSMBDataLength(outp, 70);
6610 lock_ObtainMutex(&scp->mx);
6611 outData = smb_GetSMBData(outp, NULL);
6612 outData++; /* round to get to parmOffset */
6613 *outData = 0; outData++; /* oplock */
6614 *outData = 0; outData++; /* reserved */
6615 *((USHORT *)outData) = fidp->fid; outData += 2; /* fid */
6616 *((ULONG *)outData) = openAction; outData += 4;
6617 *((ULONG *)outData) = 0; outData += 4; /* EA error offset */
6618 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
6619 *((FILETIME *)outData) = ft; outData += 8; /* creation time */
6620 *((FILETIME *)outData) = ft; outData += 8; /* last access time */
6621 *((FILETIME *)outData) = ft; outData += 8; /* last write time */
6622 *((FILETIME *)outData) = ft; outData += 8; /* change time */
6623 *((ULONG *)outData) = smb_ExtAttributes(scp); outData += 4;
6624 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* alloc sz */
6625 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* EOF */
6626 *((USHORT *)outData) = 0; outData += 2; /* filetype */
6627 *((USHORT *)outData) = 0; outData += 2; /* dev state */
6628 *((USHORT *)outData) = (scp->fileType == CM_SCACHETYPE_DIRECTORY);
6629 outData += 2; /* is a dir? */
6630 lock_ReleaseMutex(&scp->mx);
6633 parmOffset = 8*4 + 39;
6634 parmOffset += 1; /* pad to 4 */
6635 dataOffset = parmOffset + 104;
6639 /* Total Parameter Count */
6640 smb_SetSMBParmLong(outp, parmSlot, 101); parmSlot += 2;
6641 /* Total Data Count */
6642 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
6643 /* Parameter Count */
6644 smb_SetSMBParmLong(outp, parmSlot, 101); parmSlot += 2;
6645 /* Parameter Offset */
6646 smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
6647 /* Parameter Displacement */
6648 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
6650 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
6652 smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
6653 /* Data Displacement */
6654 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
6655 smb_SetSMBParmByte(outp, parmSlot, 0); /* Setup Count */
6656 smb_SetSMBDataLength(outp, 105);
6658 lock_ObtainMutex(&scp->mx);
6659 outData = smb_GetSMBData(outp, NULL);
6660 outData++; /* round to get to parmOffset */
6661 *outData = 0; outData++; /* oplock */
6662 *outData = 1; outData++; /* response type */
6663 *((USHORT *)outData) = fidp->fid; outData += 2; /* fid */
6664 *((ULONG *)outData) = openAction; outData += 4;
6665 *((ULONG *)outData) = 0; outData += 4; /* EA error offset */
6666 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
6667 *((FILETIME *)outData) = ft; outData += 8; /* creation time */
6668 *((FILETIME *)outData) = ft; outData += 8; /* last access time */
6669 *((FILETIME *)outData) = ft; outData += 8; /* last write time */
6670 *((FILETIME *)outData) = ft; outData += 8; /* change time */
6671 *((ULONG *)outData) = smb_ExtAttributes(scp); outData += 4;
6672 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* alloc sz */
6673 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* EOF */
6674 *((USHORT *)outData) = 0; outData += 2; /* filetype */
6675 *((USHORT *)outData) = 0; outData += 2; /* dev state */
6676 *((USHORT *)outData) = (scp->fileType == CM_SCACHETYPE_DIRECTORY);
6677 outData += 1; /* is a dir? */
6678 memset(outData,0,24); outData += 24; /* Volume ID and file ID */
6679 *((ULONG *)outData) = 0x001f01ffL; outData += 4; /* Maxmimal access rights */
6680 *((ULONG *)outData) = 0; outData += 4; /* Guest Access rights */
6681 lock_ReleaseMutex(&scp->mx);
6684 osi_Log1(smb_logp, "SMB NTTranCreate opening fid %d", fidp->fid);
6686 smb_ReleaseFID(fidp);
6688 cm_ReleaseUser(userp);
6690 /* free(realPathp); Can't free realPathp here because fidp->NTopen_wholepathp points there */
6691 /* leave scp held since we put it in fidp->scp */
6695 long smb_ReceiveNTTranNotifyChange(smb_vc_t *vcp, smb_packet_t *inp,
6698 smb_packet_t *savedPacketp;
6699 ULONG filter; USHORT fid, watchtree;
6703 filter = smb_GetSMBParm(inp, 19) |
6704 (smb_GetSMBParm(inp, 20) << 16);
6705 fid = smb_GetSMBParm(inp, 21);
6706 watchtree = smb_GetSMBParm(inp, 22) && 0xffff; /* TODO: should this be 0xff ? */
6708 fidp = smb_FindFID(vcp, fid, 0);
6710 osi_Log1(smb_logp, "ERROR: NotifyChange given invalid fid [%d]", fid);
6711 return CM_ERROR_BADFD;
6714 savedPacketp = smb_CopyPacket(inp);
6716 if (savedPacketp->vcp)
6717 smb_ReleaseVC(savedPacketp->vcp);
6718 savedPacketp->vcp = vcp;
6719 lock_ObtainMutex(&smb_Dir_Watch_Lock);
6720 savedPacketp->nextp = smb_Directory_Watches;
6721 smb_Directory_Watches = savedPacketp;
6722 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
6724 osi_Log4(smb_logp, "Request for NotifyChange filter 0x%x fid %d wtree %d file %s",
6725 filter, fid, watchtree, osi_LogSaveString(smb_logp, fidp->NTopen_wholepathp));
6728 lock_ObtainMutex(&scp->mx);
6730 scp->flags |= CM_SCACHEFLAG_WATCHEDSUBTREE;
6732 scp->flags |= CM_SCACHEFLAG_WATCHED;
6733 lock_ReleaseMutex(&scp->mx);
6734 smb_ReleaseFID(fidp);
6736 outp->flags |= SMB_PACKETFLAG_NOSEND;
6740 unsigned char nullSecurityDesc[36] = {
6741 0x01, /* security descriptor revision */
6742 0x00, /* reserved, should be zero */
6743 0x00, 0x80, /* security descriptor control;
6744 * 0x8000 : self-relative format */
6745 0x14, 0x00, 0x00, 0x00, /* offset of owner SID */
6746 0x1c, 0x00, 0x00, 0x00, /* offset of group SID */
6747 0x00, 0x00, 0x00, 0x00, /* offset of DACL would go here */
6748 0x00, 0x00, 0x00, 0x00, /* offset of SACL would go here */
6749 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
6750 /* "null SID" owner SID */
6751 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
6752 /* "null SID" group SID */
6755 long smb_ReceiveNTTranQuerySecurityDesc(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6757 int parmOffset, parmCount, dataOffset, dataCount;
6765 ULONG securityInformation;
6767 parmOffset = smb_GetSMBOffsetParm(inp, 11, 1)
6768 | (smb_GetSMBOffsetParm(inp, 12, 1) << 16);
6769 parmp = inp->data + parmOffset;
6770 sparmp = (USHORT *) parmp;
6771 lparmp = (ULONG *) parmp;
6774 securityInformation = lparmp[1];
6776 maxData = smb_GetSMBOffsetParm(inp, 7, 1)
6777 | (smb_GetSMBOffsetParm(inp, 8, 1) << 16);
6785 parmOffset = 8*4 + 39;
6786 parmOffset += 1; /* pad to 4 */
6788 dataOffset = parmOffset + parmCount;
6792 /* Total Parameter Count */
6793 smb_SetSMBParmLong(outp, parmSlot, parmCount); parmSlot += 2;
6794 /* Total Data Count */
6795 smb_SetSMBParmLong(outp, parmSlot, dataCount); parmSlot += 2;
6796 /* Parameter Count */
6797 smb_SetSMBParmLong(outp, parmSlot, parmCount); parmSlot += 2;
6798 /* Parameter Offset */
6799 smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
6800 /* Parameter Displacement */
6801 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
6803 smb_SetSMBParmLong(outp, parmSlot, dataCount); parmSlot += 2;
6805 smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
6806 /* Data Displacement */
6807 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
6808 smb_SetSMBParmByte(outp, parmSlot, 0); /* Setup Count */
6809 smb_SetSMBDataLength(outp, 1 + parmCount + dataCount);
6811 outData = smb_GetSMBData(outp, NULL);
6812 outData++; /* round to get to parmOffset */
6813 *((ULONG *)outData) = 36; outData += 4; /* length */
6815 if (maxData >= 36) {
6816 memcpy(outData, nullSecurityDesc, 36);
6820 return CM_ERROR_BUFFERTOOSMALL;
6823 long smb_ReceiveNTTransact(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6825 unsigned short function;
6827 function = smb_GetSMBParm(inp, 18);
6829 osi_Log1(smb_logp, "SMB NT Transact function %d", function);
6831 /* We can handle long names */
6832 if (vcp->flags & SMB_VCFLAG_USENT)
6833 ((smb_t *)outp)->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
6837 return smb_ReceiveNTTranCreate(vcp, inp, outp);
6839 osi_Log0(smb_logp, "SMB NT Transact Ioctl - not implemented");
6842 osi_Log0(smb_logp, "SMB NT Transact SetSecurityDesc - not implemented");
6845 return smb_ReceiveNTTranNotifyChange(vcp, inp, outp);
6847 osi_Log0(smb_logp, "SMB NT Transact Rename - not implemented");
6850 return smb_ReceiveNTTranQuerySecurityDesc(vcp, inp, outp);
6852 return CM_ERROR_INVAL;
6856 * smb_NotifyChange -- find relevant change notification messages and
6859 * If we don't know the file name (i.e. a callback break), filename is
6860 * NULL, and we return a zero-length list.
6862 void smb_NotifyChange(DWORD action, DWORD notifyFilter,
6863 cm_scache_t *dscp, char *filename, char *otherFilename,
6864 BOOL isDirectParent)
6866 smb_packet_t *watch, *lastWatch, *nextWatch;
6867 ULONG parmSlot, parmCount, parmOffset, dataOffset, nameLen;
6868 char *outData, *oldOutData;
6872 BOOL twoEntries = FALSE;
6873 ULONG otherNameLen, oldParmCount = 0;
6877 /* Get ready for rename within directory */
6878 if (action == FILE_ACTION_RENAMED_OLD_NAME && otherFilename != NULL) {
6880 otherAction = FILE_ACTION_RENAMED_NEW_NAME;
6883 osi_Log2(smb_logp,"in smb_NotifyChange for file [%s] dscp [%x]",
6884 osi_LogSaveString(smb_logp,filename),dscp);
6886 lock_ObtainMutex(&smb_Dir_Watch_Lock);
6887 watch = smb_Directory_Watches;
6889 filter = smb_GetSMBParm(watch, 19)
6890 | (smb_GetSMBParm(watch, 20) << 16);
6891 fid = smb_GetSMBParm(watch, 21);
6892 wtree = smb_GetSMBParm(watch, 22) & 0xffff; /* TODO: should this be 0xff ? */
6893 maxLen = smb_GetSMBOffsetParm(watch, 5, 1)
6894 | (smb_GetSMBOffsetParm(watch, 6, 1) << 16);
6897 * Strange hack - bug in NT Client and NT Server that we
6900 if (filter == 3 && wtree)
6903 fidp = smb_FindFID(watch->vcp, fid, 0);
6905 osi_Log1(smb_logp," no fidp for fid[%d]",fid);
6907 watch = watch->nextp;
6910 if (fidp->scp != dscp
6911 || (filter & notifyFilter) == 0
6912 || (!isDirectParent && !wtree)) {
6913 osi_Log1(smb_logp," passing fidp->scp[%x]", fidp->scp);
6914 smb_ReleaseFID(fidp);
6916 watch = watch->nextp;
6919 smb_ReleaseFID(fidp);
6922 "Sending Change Notification for fid %d filter 0x%x wtree %d file %s",
6923 fid, filter, wtree, osi_LogSaveString(smb_logp, filename));
6925 nextWatch = watch->nextp;
6926 if (watch == smb_Directory_Watches)
6927 smb_Directory_Watches = nextWatch;
6929 lastWatch->nextp = nextWatch;
6931 /* Turn off WATCHED flag in dscp */
6932 lock_ObtainMutex(&dscp->mx);
6934 dscp->flags &= ~CM_SCACHEFLAG_WATCHEDSUBTREE;
6936 dscp->flags &= ~CM_SCACHEFLAG_WATCHED;
6937 lock_ReleaseMutex(&dscp->mx);
6939 /* Convert to response packet */
6940 ((smb_t *) watch)->reb = SMB_FLAGS_SERVER_TO_CLIENT | SMB_FLAGS_CANONICAL_PATHNAMES;
6941 ((smb_t *) watch)->wct = 0;
6944 if (filename == NULL)
6947 nameLen = (ULONG)strlen(filename);
6948 parmCount = 3*4 + nameLen*2;
6949 parmCount = (parmCount + 3) & ~3; /* pad to 4 */
6951 otherNameLen = (ULONG)strlen(otherFilename);
6952 oldParmCount = parmCount;
6953 parmCount += 3*4 + otherNameLen*2;
6954 parmCount = (parmCount + 3) & ~3; /* pad to 4 */
6956 if (maxLen < parmCount)
6957 parmCount = 0; /* not enough room */
6959 parmOffset = 8*4 + 39;
6960 parmOffset += 1; /* pad to 4 */
6961 dataOffset = parmOffset + parmCount;
6965 /* Total Parameter Count */
6966 smb_SetSMBParmLong(watch, parmSlot, parmCount); parmSlot += 2;
6967 /* Total Data Count */
6968 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
6969 /* Parameter Count */
6970 smb_SetSMBParmLong(watch, parmSlot, parmCount); parmSlot += 2;
6971 /* Parameter Offset */
6972 smb_SetSMBParmLong(watch, parmSlot, parmOffset); parmSlot += 2;
6973 /* Parameter Displacement */
6974 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
6976 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
6978 smb_SetSMBParmLong(watch, parmSlot, dataOffset); parmSlot += 2;
6979 /* Data Displacement */
6980 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
6981 smb_SetSMBParmByte(watch, parmSlot, 0); /* Setup Count */
6982 smb_SetSMBDataLength(watch, parmCount + 1);
6984 if (parmCount != 0) {
6986 outData = smb_GetSMBData(watch, NULL);
6987 outData++; /* round to get to parmOffset */
6988 oldOutData = outData;
6989 *((DWORD *)outData) = oldParmCount; outData += 4;
6990 /* Next Entry Offset */
6991 *((DWORD *)outData) = action; outData += 4;
6993 *((DWORD *)outData) = nameLen*2; outData += 4;
6994 /* File Name Length */
6995 p = strdup(filename);
6996 if (smb_StoreAnsiFilenames)
6998 mbstowcs((WCHAR *)outData, p, nameLen);
7002 outData = oldOutData + oldParmCount;
7003 *((DWORD *)outData) = 0; outData += 4;
7004 /* Next Entry Offset */
7005 *((DWORD *)outData) = otherAction; outData += 4;
7007 *((DWORD *)outData) = otherNameLen*2;
7008 outData += 4; /* File Name Length */
7009 p = strdup(otherFilename);
7010 if (smb_StoreAnsiFilenames)
7012 mbstowcs((WCHAR *)outData, p, otherNameLen); /* File Name */
7018 * If filename is null, we don't know the cause of the
7019 * change notification. We return zero data (see above),
7020 * and set error code to NT_STATUS_NOTIFY_ENUM_DIR
7021 * (= 0x010C). We set the error code here by hand, without
7022 * modifying wct and bcc.
7024 if (filename == NULL) {
7025 ((smb_t *) watch)->rcls = 0x0C;
7026 ((smb_t *) watch)->reh = 0x01;
7027 ((smb_t *) watch)->errLow = 0;
7028 ((smb_t *) watch)->errHigh = 0;
7029 /* Set NT Status codes flag */
7030 ((smb_t *) watch)->flg2 |= SMB_FLAGS2_32BIT_STATUS;
7033 smb_SendPacket(watch->vcp, watch);
7034 smb_FreePacket(watch);
7037 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
7040 long smb_ReceiveNTCancel(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7042 unsigned char *replyWctp;
7043 smb_packet_t *watch, *lastWatch;
7044 USHORT fid, watchtree;
7048 osi_Log0(smb_logp, "SMB3 receive NT cancel");
7050 lock_ObtainMutex(&smb_Dir_Watch_Lock);
7051 watch = smb_Directory_Watches;
7053 if (((smb_t *)watch)->uid == ((smb_t *)inp)->uid
7054 && ((smb_t *)watch)->pid == ((smb_t *)inp)->pid
7055 && ((smb_t *)watch)->mid == ((smb_t *)inp)->mid
7056 && ((smb_t *)watch)->tid == ((smb_t *)inp)->tid) {
7057 if (watch == smb_Directory_Watches)
7058 smb_Directory_Watches = watch->nextp;
7060 lastWatch->nextp = watch->nextp;
7061 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
7063 /* Turn off WATCHED flag in scp */
7064 fid = smb_GetSMBParm(watch, 21);
7065 watchtree = smb_GetSMBParm(watch, 22) & 0xffff;
7067 if (vcp != watch->vcp)
7068 osi_Log2(smb_logp, "smb_ReceiveNTCancel: vcp %x not equal to watch vcp %x",
7071 fidp = smb_FindFID(vcp, fid, 0);
7073 osi_Log3(smb_logp, "Cancelling change notification for fid %d wtree %d file %s",
7075 osi_LogSaveString(smb_logp, (fidp)?fidp->NTopen_wholepathp:""));
7078 lock_ObtainMutex(&scp->mx);
7080 scp->flags &= ~CM_SCACHEFLAG_WATCHEDSUBTREE;
7082 scp->flags &= ~CM_SCACHEFLAG_WATCHED;
7083 lock_ReleaseMutex(&scp->mx);
7084 smb_ReleaseFID(fidp);
7086 osi_Log2(smb_logp,"NTCancel unable to resolve fid [%d] in vcp[%x]", fid,vcp);
7089 /* assume STATUS32; return 0xC0000120 (CANCELED) */
7090 replyWctp = watch->wctp;
7094 ((smb_t *)watch)->rcls = 0x20;
7095 ((smb_t *)watch)->reh = 0x1;
7096 ((smb_t *)watch)->errLow = 0;
7097 ((smb_t *)watch)->errHigh = 0xC0;
7098 ((smb_t *)watch)->flg2 |= SMB_FLAGS2_32BIT_STATUS;
7099 smb_SendPacket(vcp, watch);
7100 smb_FreePacket(watch);
7104 watch = watch->nextp;
7106 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
7112 * NT rename also does hard links.
7115 #define RENAME_FLAG_MOVE_CLUSTER_INFORMATION 0x102
7116 #define RENAME_FLAG_HARD_LINK 0x103
7117 #define RENAME_FLAG_RENAME 0x104
7118 #define RENAME_FLAG_COPY 0x105
7120 long smb_ReceiveNTRename(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7122 char *oldPathp, *newPathp;
7128 attrs = smb_GetSMBParm(inp, 0);
7129 rename_type = smb_GetSMBParm(inp, 1);
7131 if (rename_type != RENAME_FLAG_RENAME && rename_type != RENAME_FLAG_HARD_LINK) {
7132 osi_Log1(smb_logp, "NTRename invalid infolevel [%x]", rename_type);
7133 return CM_ERROR_NOACCESS;
7136 tp = smb_GetSMBData(inp, NULL);
7137 oldPathp = smb_ParseASCIIBlock(tp, &tp);
7138 if (smb_StoreAnsiFilenames)
7139 OemToChar(oldPathp,oldPathp);
7140 newPathp = smb_ParseASCIIBlock(tp, &tp);
7141 if (smb_StoreAnsiFilenames)
7142 OemToChar(newPathp,newPathp);
7144 osi_Log3(smb_logp, "NTRename for [%s]->[%s] type [%s]",
7145 osi_LogSaveString(smb_logp, oldPathp),
7146 osi_LogSaveString(smb_logp, newPathp),
7147 ((rename_type==RENAME_FLAG_RENAME)?"rename":"hardlink"));
7149 if (rename_type == RENAME_FLAG_RENAME) {
7150 code = smb_Rename(vcp,inp,oldPathp,newPathp,attrs);
7151 } else { /* RENAME_FLAG_HARD_LINK */
7152 code = smb_Link(vcp,inp,oldPathp,newPathp);
7159 lock_InitializeMutex(&smb_Dir_Watch_Lock, "Directory Watch List Lock");
7162 cm_user_t *smb_FindCMUserByName(char *usern, char *machine, afs_uint32 flags)
7164 smb_username_t *unp;
7167 unp = smb_FindUserByName(usern, machine, flags);
7169 lock_ObtainMutex(&unp->mx);
7170 unp->userp = cm_NewUser();
7171 lock_ReleaseMutex(&unp->mx);
7172 osi_Log2(smb_logp,"smb_FindCMUserByName New user name[%s] machine[%s]",osi_LogSaveString(smb_logp,usern),osi_LogSaveString(smb_logp,machine));
7174 osi_Log2(smb_logp,"smb_FindCMUserByName Not found name[%s] machine[%s]",osi_LogSaveString(smb_logp,usern),osi_LogSaveString(smb_logp,machine));
7178 smb_ReleaseUsername(unp);