2 * Copyright 2000, International Business Machines Corporation and others.
5 * This software has been released under the terms of the IBM Public
6 * License. For details, see the LICENSE file in the top-level source
7 * directory or online at http://www.openafs.org/dl/license10.html
10 #include <afs/param.h>
15 #define SECURITY_WIN32
30 extern osi_hyper_t hzero;
32 smb_packet_t *smb_Directory_Watches = NULL;
33 osi_mutex_t smb_Dir_Watch_Lock;
35 smb_tran2Dispatch_t smb_tran2DispatchTable[SMB_TRAN2_NOPCODES];
37 smb_tran2Dispatch_t smb_rapDispatchTable[SMB_RAP_NOPCODES];
39 /* protected by the smb_globalLock */
40 smb_tran2Packet_t *smb_tran2AssemblyQueuep;
42 /* retrieve a held reference to a user structure corresponding to an incoming
44 cm_user_t *smb_GetTran2User(smb_vc_t *vcp, smb_tran2Packet_t *inp)
49 uidp = smb_FindUID(vcp, inp->uid, 0);
50 if (!uidp) return NULL;
52 lock_ObtainMutex(&uidp->mx);
54 up = uidp->unp->userp;
57 lock_ReleaseMutex(&uidp->mx);
65 * Return extended attributes.
66 * Right now, we aren't using any of the "new" bits, so this looks exactly
67 * like smb_Attributes() (see smb.c).
69 unsigned long smb_ExtAttributes(cm_scache_t *scp)
73 if (scp->fileType == CM_SCACHETYPE_DIRECTORY ||
74 scp->fileType == CM_SCACHETYPE_MOUNTPOINT)
76 attrs = SMB_ATTR_DIRECTORY;
77 #ifdef SPECIAL_FOLDERS
78 #ifdef AFS_FREELANCE_CLIENT
79 if ( cm_freelanceEnabled &&
80 scp->fid.cell==AFS_FAKE_ROOT_CELL_ID &&
81 scp->fid.volume==AFS_FAKE_ROOT_VOL_ID &&
82 scp->fid.vnode==0x1 && scp->fid.unique==0x1) {
83 attrs |= SMB_ATTR_SYSTEM; /* FILE_ATTRIBUTE_SYSTEM */
85 #endif /* AFS_FREELANCE_CLIENT */
86 #endif /* SPECIAL_FOLDERS */
90 * We used to mark a file RO if it was in an RO volume, but that
91 * turns out to be impolitic in NT. See defect 10007.
94 if ((scp->unixModeBits & 0222) == 0 || (scp->flags & CM_SCACHEFLAG_RO))
96 if ((scp->unixModeBits & 0222) == 0)
97 attrs |= SMB_ATTR_READONLY; /* Read-only */
100 attrs = SMB_ATTR_NORMAL; /* FILE_ATTRIBUTE_NORMAL */
105 int smb_V3IsStarMask(char *maskp)
109 while (tc = *maskp++)
110 if (tc == '?' || tc == '*')
115 unsigned char *smb_ParseString(unsigned char *inp, char **chainpp)
118 /* skip over null-terminated string */
119 *chainpp = inp + strlen(inp) + 1;
124 /*DEBUG do not checkin*/
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);
179 #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 = 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 = 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 = 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 = 0;
568 lmAuth.tsource.SourceIdentifier.LowPart = (DWORD) vcp;
569 strcpy(lmAuth.tsource.SourceName,"OpenAFS"); /* 8 char limit */
571 nts = LsaLogonUser( smb_lsaHandle,
586 OutputDebugF("Return from LsaLogonUser is 0x%lX", nts);
587 OutputDebugF("Extended status is 0x%lX", ntsEx);
589 if (nts == ERROR_SUCCESS) {
591 LsaFreeReturnBuffer(lmprofilep);
592 CloseHandle(lmToken);
596 if (nts == 0xC000015BL)
597 return CM_ERROR_BADLOGONTYPE;
598 else /* our catchall is a bad password though we could be more specific */
599 return CM_ERROR_BADPASSWORD;
603 /* The buffer pointed to by usern is assumed to be at least SMB_MAX_USERNAME_LENGTH bytes */
604 long smb_GetNormalizedUsername(char * usern, const char * accountName, const char * domainName)
609 /* check if we have sane input */
610 if ((strlen(accountName) + strlen(domainName) + 1) > SMB_MAX_USERNAME_LENGTH)
613 /* we could get : [accountName][domainName]
619 atsign = strchr(accountName, '@');
621 if (atsign) /* [user@domain][] -> [user@domain][domain] */
626 /* if for some reason the client doesn't know what domain to use,
627 it will either return an empty string or a '?' */
628 if (!domain[0] || domain[0] == '?')
629 /* Empty domains and empty usernames are usually sent from tokenless contexts.
630 This way such logins will get an empty username (easy to check). I don't know
631 when a non-empty username would be supplied with an anonymous domain, but *shrug* */
632 strcpy(usern,accountName);
634 /* TODO: what about WIN.MIT.EDU\user vs. WIN\user? */
635 strcpy(usern,domain);
638 strncat(usern,accountName,atsign - accountName);
640 strcat(usern,accountName);
648 /* When using SMB auth, all SMB sessions have to pass through here first to
649 * authenticate the user.
650 * Caveat: If not use the SMB auth the protocol does not require sending a
651 * session setup packet, which means that we can't rely on a UID in subsequent
652 * packets. Though in practice we get one anyway.
654 long smb_ReceiveV3SessionSetupX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
658 unsigned short newUid;
659 unsigned long caps = 0;
664 char usern[SMB_MAX_USERNAME_LENGTH];
665 char *secBlobOut = NULL;
666 int secBlobOutLength = 0;
668 /* Check for bad conns */
669 if (vcp->flags & SMB_VCFLAG_REMOTECONN)
670 return CM_ERROR_REMOTECONN;
672 if (vcp->flags & SMB_VCFLAG_USENT) {
673 if (smb_authType == SMB_AUTH_EXTENDED) {
674 /* extended authentication */
678 if (!(vcp->flags & SMB_VCFLAG_SESSX_RCVD)) {
679 caps = smb_GetSMBParm(inp,10) | (((unsigned long) smb_GetSMBParm(inp,11)) << 16);
682 secBlobInLength = smb_GetSMBParm(inp, 7);
683 secBlobIn = smb_GetSMBData(inp, NULL);
685 code = smb_AuthenticateUserExt(vcp, usern, secBlobIn, secBlobInLength, &secBlobOut, &secBlobOutLength);
687 if (code == CM_ERROR_GSSCONTINUE) {
688 smb_SetSMBParm(outp, 2, 0);
689 smb_SetSMBParm(outp, 3, secBlobOutLength);
690 smb_SetSMBDataLength(outp, secBlobOutLength + smb_ServerOSLength + smb_ServerLanManagerLength + smb_ServerDomainNameLength);
691 tp = smb_GetSMBData(outp, NULL);
692 if (secBlobOutLength) {
693 memcpy(tp, secBlobOut, secBlobOutLength);
695 tp += secBlobOutLength;
697 memcpy(tp,smb_ServerOS,smb_ServerOSLength);
698 tp += smb_ServerOSLength;
699 memcpy(tp,smb_ServerLanManager,smb_ServerLanManagerLength);
700 tp += smb_ServerLanManagerLength;
701 memcpy(tp,smb_ServerDomainName,smb_ServerDomainNameLength);
702 tp += smb_ServerDomainNameLength;
705 /* TODO: handle return code and continue auth. Also free secBlobOut if applicable. */
707 unsigned ciPwdLength, csPwdLength;
713 /* TODO: parse for extended auth as well */
714 ciPwdLength = smb_GetSMBParm(inp, 7); /* case insensitive password length */
715 csPwdLength = smb_GetSMBParm(inp, 8); /* case sensitive password length */
717 tp = smb_GetSMBData(inp, &datalen);
719 OutputDebugF("Session packet data size [%d]",datalen);
726 accountName = smb_ParseString(tp, &tp);
727 primaryDomain = smb_ParseString(tp, NULL);
729 if (smb_GetNormalizedUsername(usern, accountName, primaryDomain)) {
730 /* shouldn't happen */
731 code = CM_ERROR_BADSMB;
732 goto after_read_packet;
735 /* capabilities are only valid for first session packet */
736 if (!(vcp->flags & SMB_VCFLAG_SESSX_RCVD)) {
737 caps = smb_GetSMBParm(inp, 11) | (((unsigned long)smb_GetSMBParm(inp, 12)) << 16);
740 if (smb_authType == SMB_AUTH_NTLM) {
741 code = smb_AuthenticateUserLM(vcp, accountName, primaryDomain, ciPwd, ciPwdLength, csPwd, csPwdLength);
745 unsigned ciPwdLength;
750 ciPwdLength = smb_GetSMBParm(inp, 7);
751 tp = smb_GetSMBData(inp, NULL);
755 accountName = smb_ParseString(tp, &tp);
756 primaryDomain = smb_ParseString(tp, NULL);
758 if ( smb_GetNormalizedUsername(usern, accountName, primaryDomain)) {
759 /* shouldn't happen */
760 code = CM_ERROR_BADSMB;
761 goto after_read_packet;
764 /* even if we wanted extended auth, if we only negotiated V3, we have to fallback
767 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
768 code = smb_AuthenticateUserLM(vcp,accountName,primaryDomain,ciPwd,ciPwdLength,"",0);
773 /* note down that we received a session setup X and set the capabilities flag */
774 if (!(vcp->flags & SMB_VCFLAG_SESSX_RCVD)) {
775 lock_ObtainMutex(&vcp->mx);
776 vcp->flags |= SMB_VCFLAG_SESSX_RCVD;
777 /* for the moment we can only deal with NTSTATUS */
778 if (caps & NTNEGOTIATE_CAPABILITY_NTSTATUS) {
779 vcp->flags |= SMB_VCFLAG_STATUS32;
781 lock_ReleaseMutex(&vcp->mx);
784 /* code would be non-zero if there was an authentication failure.
785 Ideally we would like to invalidate the uid for this session or break
786 early to avoid accidently stealing someone else's tokens. */
792 OutputDebugF("Received username=[%s]", usern);
794 /* On Windows 2000, this function appears to be called more often than
795 it is expected to be called. This resulted in multiple smb_user_t
796 records existing all for the same user session which results in all
797 of the users tokens disappearing.
799 To avoid this problem, we look for an existing smb_user_t record
800 based on the users name, and use that one if we find it.
803 uidp = smb_FindUserByNameThisSession(vcp, usern);
804 if (uidp) { /* already there, so don't create a new one */
807 newUid = (unsigned short)uidp->userID; /* For some reason these are different types!*/
808 osi_LogEvent("AFS smb_ReceiveV3SessionSetupX",NULL,"FindUserByName:Lana[%d],lsn[%d],userid[%d],name[%s]",vcp->lana,vcp->lsn,newUid,osi_LogSaveString(smb_logp, usern));
809 osi_Log3(smb_logp,"smb_ReceiveV3SessionSetupX FindUserByName:Lana[%d],lsn[%d],userid[%d]",vcp->lana,vcp->lsn,newUid);
810 smb_ReleaseUID(uidp);
813 /* do a global search for the username/machine name pair */
814 unp = smb_FindUserByName(usern, vcp->rname, SMB_FLAG_CREATE);
816 /* Create a new UID and cm_user_t structure */
819 userp = cm_NewUser();
820 lock_ObtainMutex(&vcp->mx);
821 if (!vcp->uidCounter)
822 vcp->uidCounter++; /* handle unlikely wraparounds */
823 newUid = (strlen(usern)==0)?0:vcp->uidCounter++;
824 lock_ReleaseMutex(&vcp->mx);
826 /* Create a new smb_user_t structure and connect them up */
827 lock_ObtainMutex(&unp->mx);
829 lock_ReleaseMutex(&unp->mx);
831 uidp = smb_FindUID(vcp, newUid, SMB_FLAG_CREATE);
832 lock_ObtainMutex(&uidp->mx);
834 osi_LogEvent("AFS smb_ReceiveV3SessionSetupX",NULL,"MakeNewUser:VCP[%x],Lana[%d],lsn[%d],userid[%d],TicketKTCName[%s]",(int)vcp,vcp->lana,vcp->lsn,newUid,osi_LogSaveString(smb_logp, usern));
835 osi_Log4(smb_logp,"smb_ReceiveV3SessionSetupX MakeNewUser:VCP[%x],Lana[%d],lsn[%d],userid[%d]",vcp,vcp->lana,vcp->lsn,newUid);
836 lock_ReleaseMutex(&uidp->mx);
837 smb_ReleaseUID(uidp);
840 /* Return UID to the client */
841 ((smb_t *)outp)->uid = newUid;
842 /* Also to the next chained message */
843 ((smb_t *)inp)->uid = newUid;
845 osi_Log3(smb_logp, "SMB3 session setup name %s creating ID %d%s",
846 osi_LogSaveString(smb_logp, usern), newUid, osi_LogSaveString(smb_logp, s1));
848 smb_SetSMBParm(outp, 2, 0);
850 if (vcp->flags & SMB_VCFLAG_USENT) {
851 if (smb_authType == SMB_AUTH_EXTENDED) {
852 smb_SetSMBParm(outp, 3, secBlobOutLength);
853 smb_SetSMBDataLength(outp, secBlobOutLength + smb_ServerOSLength + smb_ServerLanManagerLength + smb_ServerDomainNameLength);
854 tp = smb_GetSMBData(outp, NULL);
855 if (secBlobOutLength) {
856 memcpy(tp, secBlobOut, secBlobOutLength);
858 tp += secBlobOutLength;
860 memcpy(tp,smb_ServerOS,smb_ServerOSLength);
861 tp += smb_ServerOSLength;
862 memcpy(tp,smb_ServerLanManager,smb_ServerLanManagerLength);
863 tp += smb_ServerLanManagerLength;
864 memcpy(tp,smb_ServerDomainName,smb_ServerDomainNameLength);
865 tp += smb_ServerDomainNameLength;
867 smb_SetSMBDataLength(outp, 0);
870 if (smb_authType == SMB_AUTH_EXTENDED) {
871 smb_SetSMBDataLength(outp, smb_ServerOSLength + smb_ServerLanManagerLength + smb_ServerDomainNameLength);
872 tp = smb_GetSMBData(outp, NULL);
873 memcpy(tp,smb_ServerOS,smb_ServerOSLength);
874 tp += smb_ServerOSLength;
875 memcpy(tp,smb_ServerLanManager,smb_ServerLanManagerLength);
876 tp += smb_ServerLanManagerLength;
877 memcpy(tp,smb_ServerDomainName,smb_ServerDomainNameLength);
878 tp += smb_ServerDomainNameLength;
880 smb_SetSMBDataLength(outp, 0);
887 long smb_ReceiveV3UserLogoffX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
891 /* don't get tokens from this VC */
892 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
894 inp->flags |= SMB_PACKETFLAG_PROFILE_UPDATE_OK;
896 /* find the tree and free it */
897 uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
898 /* TODO: smb_ReleaseUID() ? */
900 char *s1 = NULL, *s2 = NULL;
902 if (s2 == NULL) s2 = " ";
903 if (s1 == NULL) {s1 = s2; s2 = " ";}
905 osi_Log4(smb_logp, "SMB3 user logoffX uid %d name %s%s%s", uidp->userID,
906 osi_LogSaveString(smb_logp, (uidp->unp) ? uidp->unp->name: " "), s1, s2);
908 lock_ObtainMutex(&uidp->mx);
909 uidp->flags |= SMB_USERFLAG_DELETE;
911 * it doesn't get deleted right away
912 * because the vcp points to it
914 lock_ReleaseMutex(&uidp->mx);
917 osi_Log0(smb_logp, "SMB3 user logoffX");
919 smb_SetSMBDataLength(outp, 0);
923 #define SMB_SUPPORT_SEARCH_BITS 0x0001
925 long smb_ReceiveV3TreeConnectX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
929 unsigned short newTid;
940 osi_Log0(smb_logp, "SMB3 receive tree connect");
942 /* parse input parameters */
943 tp = smb_GetSMBData(inp, NULL);
944 passwordp = smb_ParseString(tp, &tp);
945 pathp = smb_ParseString(tp, &tp);
946 servicep = smb_ParseString(tp, &tp);
948 tp = strrchr(pathp, '\\');
950 return CM_ERROR_BADSMB;
952 strcpy(shareName, tp+1);
954 osi_Log2(smb_logp, "Tree connect pathp[%s] shareName[%s]",
955 osi_LogSaveString(smb_logp, pathp),
956 osi_LogSaveString(smb_logp, shareName));
958 if (strcmp(servicep, "IPC") == 0 || strcmp(shareName, "IPC$") == 0) {
960 osi_Log0(smb_logp, "TreeConnectX connecting to IPC$");
963 return CM_ERROR_NOIPC;
967 userp = smb_GetUser(vcp, inp);
969 lock_ObtainMutex(&vcp->mx);
970 newTid = vcp->tidCounter++;
971 lock_ReleaseMutex(&vcp->mx);
973 tidp = smb_FindTID(vcp, newTid, SMB_FLAG_CREATE);
976 uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
977 shareFound = smb_FindShare(vcp, uidp, shareName, &sharePath);
979 smb_ReleaseUID(uidp);
981 smb_ReleaseTID(tidp);
982 return CM_ERROR_BADSHARENAME;
985 if (vcp->flags & SMB_VCFLAG_USENT)
987 int policy = smb_FindShareCSCPolicy(shareName);
988 smb_SetSMBParm(outp, 2, SMB_SUPPORT_SEARCH_BITS | (policy << 2));
991 smb_SetSMBParm(outp, 2, 0);
995 lock_ObtainMutex(&tidp->mx);
997 tidp->pathname = sharePath;
998 if(ipc) tidp->flags |= SMB_TIDFLAG_IPC;
999 lock_ReleaseMutex(&tidp->mx);
1000 smb_ReleaseTID(tidp);
1002 ((smb_t *)outp)->tid = newTid;
1003 ((smb_t *)inp)->tid = newTid;
1004 tp = smb_GetSMBData(outp, NULL);
1009 smb_SetSMBDataLength(outp, 3);
1012 smb_SetSMBDataLength(outp, 4);
1015 osi_Log1(smb_logp, "SMB3 tree connect created ID %d", newTid);
1019 /* must be called with global tran lock held */
1020 smb_tran2Packet_t *smb_FindTran2Packet(smb_vc_t *vcp, smb_packet_t *inp)
1022 smb_tran2Packet_t *tp;
1025 smbp = (smb_t *) inp->data;
1026 for (tp = smb_tran2AssemblyQueuep; tp; tp = (smb_tran2Packet_t *) osi_QNext(&tp->q)) {
1027 if (tp->vcp == vcp && tp->mid == smbp->mid && tp->tid == smbp->tid)
1033 smb_tran2Packet_t *smb_NewTran2Packet(smb_vc_t *vcp, smb_packet_t *inp,
1034 int totalParms, int totalData)
1036 smb_tran2Packet_t *tp;
1039 smbp = (smb_t *) inp->data;
1040 tp = malloc(sizeof(*tp));
1041 memset(tp, 0, sizeof(*tp));
1044 tp->curData = tp->curParms = 0;
1045 tp->totalData = totalData;
1046 tp->totalParms = totalParms;
1047 tp->tid = smbp->tid;
1048 tp->mid = smbp->mid;
1049 tp->uid = smbp->uid;
1050 tp->pid = smbp->pid;
1051 tp->res[0] = smbp->res[0];
1052 osi_QAdd((osi_queue_t **)&smb_tran2AssemblyQueuep, &tp->q);
1053 if (totalParms != 0)
1054 tp->parmsp = malloc(totalParms);
1056 tp->datap = malloc(totalData);
1057 if (smbp->com == 0x25 || smbp->com == 0x26)
1060 tp->opcode = smb_GetSMBParm(inp, 14);
1063 tp->flags |= SMB_TRAN2PFLAG_ALLOC;
1067 smb_tran2Packet_t *smb_GetTran2ResponsePacket(smb_vc_t *vcp,
1068 smb_tran2Packet_t *inp, smb_packet_t *outp,
1069 int totalParms, int totalData)
1071 smb_tran2Packet_t *tp;
1072 unsigned short parmOffset;
1073 unsigned short dataOffset;
1074 unsigned short dataAlign;
1076 tp = malloc(sizeof(*tp));
1077 memset(tp, 0, sizeof(*tp));
1079 tp->curData = tp->curParms = 0;
1080 tp->totalData = totalData;
1081 tp->totalParms = totalParms;
1082 tp->oldTotalParms = totalParms;
1087 tp->res[0] = inp->res[0];
1088 tp->opcode = inp->opcode;
1092 * We calculate where the parameters and data will start.
1093 * This calculation must parallel the calculation in
1094 * smb_SendTran2Packet.
1097 parmOffset = 10*2 + 35;
1098 parmOffset++; /* round to even */
1099 tp->parmsp = (unsigned short *) (outp->data + parmOffset);
1101 dataOffset = parmOffset + totalParms;
1102 dataAlign = dataOffset & 2; /* quad-align */
1103 dataOffset += dataAlign;
1104 tp->datap = outp->data + dataOffset;
1109 /* free a tran2 packet; must be called with smb_globalLock held */
1110 void smb_FreeTran2Packet(smb_tran2Packet_t *t2p)
1112 if (t2p->vcp) smb_ReleaseVC(t2p->vcp);
1113 if (t2p->flags & SMB_TRAN2PFLAG_ALLOC) {
1122 /* called with a VC, an input packet to respond to, and an error code.
1123 * sends an error response.
1125 void smb_SendTran2Error(smb_vc_t *vcp, smb_tran2Packet_t *t2p,
1126 smb_packet_t *tp, long code)
1129 unsigned short errCode;
1130 unsigned char errClass;
1131 unsigned long NTStatus;
1133 if (vcp->flags & SMB_VCFLAG_STATUS32)
1134 smb_MapNTError(code, &NTStatus);
1136 smb_MapCoreError(code, vcp, &errCode, &errClass);
1138 smb_FormatResponsePacket(vcp, NULL, tp);
1139 smbp = (smb_t *) tp;
1141 /* We can handle long names */
1142 if (vcp->flags & SMB_VCFLAG_USENT)
1143 smbp->flg2 |= 0x40; /* IS_LONG_NAME */
1145 /* now copy important fields from the tran 2 packet */
1146 smbp->com = t2p->com;
1147 smbp->tid = t2p->tid;
1148 smbp->mid = t2p->mid;
1149 smbp->pid = t2p->pid;
1150 smbp->uid = t2p->uid;
1151 smbp->res[0] = t2p->res[0];
1152 if (vcp->flags & SMB_VCFLAG_STATUS32) {
1153 smbp->rcls = (unsigned char) (NTStatus & 0xff);
1154 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
1155 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
1156 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
1157 smbp->flg2 |= 0x4000;
1160 smbp->rcls = errClass;
1161 smbp->errLow = (unsigned char) (errCode & 0xff);
1162 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
1166 smb_SendPacket(vcp, tp);
1169 void smb_SendTran2Packet(smb_vc_t *vcp, smb_tran2Packet_t *t2p, smb_packet_t *tp)
1172 unsigned short parmOffset;
1173 unsigned short dataOffset;
1174 unsigned short totalLength;
1175 unsigned short dataAlign;
1178 smb_FormatResponsePacket(vcp, NULL, tp);
1179 smbp = (smb_t *) tp;
1181 /* We can handle long names */
1182 if (vcp->flags & SMB_VCFLAG_USENT)
1183 smbp->flg2 |= 0x40; /* IS_LONG_NAME */
1185 /* now copy important fields from the tran 2 packet */
1186 smbp->com = t2p->com;
1187 smbp->tid = t2p->tid;
1188 smbp->mid = t2p->mid;
1189 smbp->pid = t2p->pid;
1190 smbp->uid = t2p->uid;
1191 smbp->res[0] = t2p->res[0];
1193 totalLength = 1 + t2p->totalData + t2p->totalParms;
1195 /* now add the core parameters (tran2 info) to the packet */
1196 smb_SetSMBParm(tp, 0, t2p->totalParms); /* parm bytes */
1197 smb_SetSMBParm(tp, 1, t2p->totalData); /* data bytes */
1198 smb_SetSMBParm(tp, 2, 0); /* reserved */
1199 smb_SetSMBParm(tp, 3, t2p->totalParms); /* parm bytes in this packet */
1200 parmOffset = 10*2 + 35; /* parm offset in packet */
1201 parmOffset++; /* round to even */
1202 smb_SetSMBParm(tp, 4, parmOffset); /* 11 parm words plus *
1203 * hdr, bcc and wct */
1204 smb_SetSMBParm(tp, 5, 0); /* parm displacement */
1205 smb_SetSMBParm(tp, 6, t2p->totalData); /* data in this packet */
1206 dataOffset = parmOffset + t2p->oldTotalParms;
1207 dataAlign = dataOffset & 2; /* quad-align */
1208 dataOffset += dataAlign;
1209 smb_SetSMBParm(tp, 7, dataOffset); /* offset of data */
1210 smb_SetSMBParm(tp, 8, 0); /* data displacement */
1211 smb_SetSMBParm(tp, 9, 0); /* low: setup word count *
1214 datap = smb_GetSMBData(tp, NULL);
1215 *datap++ = 0; /* we rounded to even */
1217 totalLength += dataAlign;
1218 smb_SetSMBDataLength(tp, totalLength);
1220 /* next, send the datagram */
1221 smb_SendPacket(vcp, tp);
1224 long smb_ReceiveV3Trans(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
1226 smb_tran2Packet_t *asp;
1239 /* We sometimes see 0 word count. What to do? */
1240 if (*inp->wctp == 0) {
1245 osi_Log0(smb_logp, "TRANSACTION word count = 0");
1247 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
1248 ptbuf[0] = "Transaction2 word count = 0";
1249 ReportEvent(h, EVENTLOG_WARNING_TYPE, 0, 1003, NULL,
1250 1, inp->ncb_length, ptbuf, inp);
1251 DeregisterEventSource(h);
1253 osi_Log0(smb_logp, "TRANSACTION word count = 0");
1256 smb_SetSMBDataLength(outp, 0);
1257 smb_SendPacket(vcp, outp);
1261 totalParms = smb_GetSMBParm(inp, 0);
1262 totalData = smb_GetSMBParm(inp, 1);
1264 firstPacket = (inp->inCom == 0x25);
1266 /* find the packet we're reassembling */
1267 lock_ObtainWrite(&smb_globalLock);
1268 asp = smb_FindTran2Packet(vcp, inp);
1270 asp = smb_NewTran2Packet(vcp, inp, totalParms, totalData);
1272 lock_ReleaseWrite(&smb_globalLock);
1274 /* now merge in this latest packet; start by looking up offsets */
1276 parmDisp = dataDisp = 0;
1277 parmOffset = smb_GetSMBParm(inp, 10);
1278 dataOffset = smb_GetSMBParm(inp, 12);
1279 parmCount = smb_GetSMBParm(inp, 9);
1280 dataCount = smb_GetSMBParm(inp, 11);
1281 asp->maxReturnParms = smb_GetSMBParm(inp, 2);
1282 asp->maxReturnData = smb_GetSMBParm(inp, 3);
1284 osi_Log3(smb_logp, "SMB3 received Trans init packet total data %d, cur data %d, max return data %d",
1285 totalData, dataCount, asp->maxReturnData);
1288 parmDisp = smb_GetSMBParm(inp, 4);
1289 parmOffset = smb_GetSMBParm(inp, 3);
1290 dataDisp = smb_GetSMBParm(inp, 7);
1291 dataOffset = smb_GetSMBParm(inp, 6);
1292 parmCount = smb_GetSMBParm(inp, 2);
1293 dataCount = smb_GetSMBParm(inp, 5);
1295 osi_Log2(smb_logp, "SMB3 received Trans aux packet parms %d, data %d",
1296 parmCount, dataCount);
1299 /* now copy the parms and data */
1300 if ( asp->totalParms > 0 && parmCount != 0 )
1302 memcpy(((char *)asp->parmsp) + parmDisp, inp->data + parmOffset, parmCount);
1304 if ( asp->totalData > 0 && dataCount != 0 ) {
1305 memcpy(asp->datap + dataDisp, inp->data + dataOffset, dataCount);
1308 /* account for new bytes */
1309 asp->curData += dataCount;
1310 asp->curParms += parmCount;
1312 /* finally, if we're done, remove the packet from the queue and dispatch it */
1313 if (asp->totalParms > 0 &&
1314 asp->curParms > 0 &&
1315 asp->totalData <= asp->curData &&
1316 asp->totalParms <= asp->curParms) {
1317 /* we've received it all */
1318 lock_ObtainWrite(&smb_globalLock);
1319 osi_QRemove((osi_queue_t **) &smb_tran2AssemblyQueuep, &asp->q);
1320 lock_ReleaseWrite(&smb_globalLock);
1322 /* now dispatch it */
1323 rapOp = asp->parmsp[0];
1325 if ( rapOp >= 0 && rapOp < SMB_RAP_NOPCODES && smb_rapDispatchTable[rapOp].procp) {
1326 osi_LogEvent("AFS-Dispatch-RAP[%s]",myCrt_RapDispatch(rapOp),"vcp[%x] lana[%d] lsn[%d]",(int)vcp,vcp->lana,vcp->lsn);
1327 osi_Log4(smb_logp,"AFS Server - Dispatch-RAP %s vcp[%x] lana[%d] lsn[%d]",myCrt_RapDispatch(rapOp),vcp,vcp->lana,vcp->lsn);
1328 code = (*smb_rapDispatchTable[rapOp].procp)(vcp, asp, outp);
1331 osi_LogEvent("AFS-Dispatch-RAP [invalid]", NULL, "op[%x] vcp[%x] lana[%d] lsn[%d]", rapOp, vcp, vcp->lana, vcp->lsn);
1332 osi_Log4(smb_logp,"AFS Server - Dispatch-RAP [INVALID] op[%x] vcp[%x] lana[%d] lsn[%d]", rapOp, vcp, vcp->lana, vcp->lsn);
1333 code = CM_ERROR_BADOP;
1336 /* if an error is returned, we're supposed to send an error packet,
1337 * otherwise the dispatched function already did the data sending.
1338 * We give dispatched proc the responsibility since it knows how much
1339 * space to allocate.
1342 smb_SendTran2Error(vcp, asp, outp, code);
1345 /* free the input tran 2 packet */
1346 lock_ObtainWrite(&smb_globalLock);
1347 smb_FreeTran2Packet(asp);
1348 lock_ReleaseWrite(&smb_globalLock);
1350 else if (firstPacket) {
1351 /* the first packet in a multi-packet request, we need to send an
1352 * ack to get more data.
1354 smb_SetSMBDataLength(outp, 0);
1355 smb_SendPacket(vcp, outp);
1361 /* ANSI versions. The unicode versions support arbitrary length
1362 share names, but we don't support unicode yet. */
1364 typedef struct smb_rap_share_info_0 {
1365 char shi0_netname[13];
1366 } smb_rap_share_info_0_t;
1368 typedef struct smb_rap_share_info_1 {
1369 char shi1_netname[13];
1372 DWORD shi1_remark; /* char *shi1_remark; data offset */
1373 } smb_rap_share_info_1_t;
1375 typedef struct smb_rap_share_info_2 {
1376 char shi2_netname[13];
1378 unsigned short shi2_type;
1379 DWORD shi2_remark; /* char *shi2_remark; data offset */
1380 unsigned short shi2_permissions;
1381 unsigned short shi2_max_uses;
1382 unsigned short shi2_current_uses;
1383 DWORD shi2_path; /* char *shi2_path; data offset */
1384 unsigned short shi2_passwd[9];
1385 unsigned short shi2_pad2;
1386 } smb_rap_share_info_2_t;
1388 #define SMB_RAP_MAX_SHARES 512
1390 typedef struct smb_rap_share_list {
1393 smb_rap_share_info_0_t * shares;
1394 } smb_rap_share_list_t;
1396 int smb_rapCollectSharesProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp) {
1397 smb_rap_share_list_t * sp;
1402 if (name[0] == '.' && (!name[1] || (name[1] == '.' && !name[2])))
1403 return 0; /* skip over '.' and '..' */
1405 sp = (smb_rap_share_list_t *) vrockp;
1407 strncpy(sp->shares[sp->cShare].shi0_netname, name, 12);
1408 sp->shares[sp->cShare].shi0_netname[12] = 0;
1412 if (sp->cShare >= sp->maxShares)
1413 return CM_ERROR_STOPNOW;
1418 long smb_ReceiveRAPNetShareEnum(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1420 smb_tran2Packet_t *outp;
1421 unsigned short * tp;
1425 int outParmsTotal; /* total parameter bytes */
1426 int outDataTotal; /* total data bytes */
1434 HKEY hkSubmount = NULL;
1435 smb_rap_share_info_1_t * shares;
1438 char thisShare[256];
1441 smb_rap_share_list_t rootShares;
1446 tp = p->parmsp + 1; /* skip over function number (always 0) */
1447 (void) smb_ParseString((char *) tp, (char **) &tp); /* skip over parm descriptor */
1448 (void) smb_ParseString((char *) tp, (char **) &tp); /* skip over data descriptor */
1452 if (infoLevel != 1) {
1453 return CM_ERROR_INVAL;
1456 /* first figure out how many shares there are */
1457 rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSConfigKeyName, 0,
1458 KEY_QUERY_VALUE, &hkParam);
1459 if (rv == ERROR_SUCCESS) {
1460 len = sizeof(allSubmount);
1461 rv = RegQueryValueEx(hkParam, "AllSubmount", NULL, NULL,
1462 (BYTE *) &allSubmount, &len);
1463 if (rv != ERROR_SUCCESS || allSubmount != 0) {
1466 RegCloseKey (hkParam);
1469 rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SOFTWARE\\OpenAFS\\Client\\Submounts",
1470 0, KEY_QUERY_VALUE, &hkSubmount);
1471 if (rv == ERROR_SUCCESS) {
1472 rv = RegQueryInfoKey(hkSubmount, NULL, NULL, NULL, NULL,
1473 NULL, NULL, &nRegShares, NULL, NULL, NULL, NULL);
1474 if (rv != ERROR_SUCCESS)
1480 /* fetch the root shares */
1481 rootShares.maxShares = SMB_RAP_MAX_SHARES;
1482 rootShares.cShare = 0;
1483 rootShares.shares = malloc( sizeof(smb_rap_share_info_0_t) * SMB_RAP_MAX_SHARES );
1487 userp = smb_GetTran2User(vcp,p);
1489 thyper.HighPart = 0;
1492 cm_HoldSCache(cm_rootSCachep);
1493 cm_ApplyDir(cm_rootSCachep, smb_rapCollectSharesProc, &rootShares, &thyper, userp, &req, NULL);
1494 cm_ReleaseSCache(cm_rootSCachep);
1496 cm_ReleaseUser(userp);
1498 nShares = rootShares.cShare + nRegShares + allSubmount;
1500 #define REMARK_LEN 1
1501 outParmsTotal = 8; /* 4 dwords */
1502 outDataTotal = (sizeof(smb_rap_share_info_1_t) + REMARK_LEN) * nShares ;
1503 if(outDataTotal > bufsize) {
1504 nSharesRet = bufsize / (sizeof(smb_rap_share_info_1_t) + REMARK_LEN);
1505 outDataTotal = (sizeof(smb_rap_share_info_1_t) + REMARK_LEN) * nSharesRet;
1508 nSharesRet = nShares;
1511 outp = smb_GetTran2ResponsePacket(vcp, p, op, outParmsTotal, outDataTotal);
1513 /* now for the submounts */
1514 shares = (smb_rap_share_info_1_t *) outp->datap;
1515 cstrp = outp->datap + sizeof(smb_rap_share_info_1_t) * nSharesRet;
1517 memset(outp->datap, 0, (sizeof(smb_rap_share_info_1_t) + REMARK_LEN) * nSharesRet);
1520 strcpy( shares[cshare].shi1_netname, "all" );
1521 shares[cshare].shi1_remark = cstrp - outp->datap;
1522 /* type and pad are zero already */
1528 for (i=0; i < nRegShares && cshare < nSharesRet; i++) {
1529 len = sizeof(thisShare);
1530 rv = RegEnumValue(hkSubmount, i, thisShare, &len, NULL, NULL, NULL, NULL);
1531 if (rv == ERROR_SUCCESS && strlen(thisShare) && (!allSubmount || stricmp(thisShare,"all"))) {
1532 strncpy(shares[cshare].shi1_netname, thisShare, sizeof(shares->shi1_netname)-1);
1533 shares[cshare].shi1_netname[sizeof(shares->shi1_netname)-1] = 0; /* unfortunate truncation */
1534 shares[cshare].shi1_remark = cstrp - outp->datap;
1539 nShares--; /* uncount key */
1542 RegCloseKey(hkSubmount);
1545 nonrootShares = cshare;
1547 for (i=0; i < rootShares.cShare && cshare < nSharesRet; i++) {
1548 /* in case there are collisions with submounts, submounts have higher priority */
1549 for (j=0; j < nonrootShares; j++)
1550 if (!stricmp(shares[j].shi1_netname, rootShares.shares[i].shi0_netname))
1553 if (j < nonrootShares) {
1554 nShares--; /* uncount */
1558 strcpy(shares[cshare].shi1_netname, rootShares.shares[i].shi0_netname);
1559 shares[cshare].shi1_remark = cstrp - outp->datap;
1564 outp->parmsp[0] = ((cshare == nShares)? ERROR_SUCCESS : ERROR_MORE_DATA);
1565 outp->parmsp[1] = 0;
1566 outp->parmsp[2] = cshare;
1567 outp->parmsp[3] = nShares;
1569 outp->totalData = cstrp - outp->datap;
1570 outp->totalParms = outParmsTotal;
1572 smb_SendTran2Packet(vcp, outp, op);
1573 smb_FreeTran2Packet(outp);
1575 free(rootShares.shares);
1580 long smb_ReceiveRAPNetShareGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1582 smb_tran2Packet_t *outp;
1583 unsigned short * tp;
1585 BOOL shareFound = FALSE;
1586 unsigned short infoLevel;
1587 unsigned short bufsize;
1597 tp = p->parmsp + 1; /* skip over function number (always 1) */
1598 (void) smb_ParseString( (char *) tp, (char **) &tp); /* skip over param descriptor */
1599 (void) smb_ParseString( (char *) tp, (char **) &tp); /* skip over data descriptor */
1600 shareName = smb_ParseString( (char *) tp, (char **) &tp);
1607 totalData = sizeof(smb_rap_share_info_0_t);
1608 else if(infoLevel == 1)
1609 totalData = sizeof(smb_rap_share_info_1_t) + 1; /* + empty string */
1610 else if(infoLevel == 2)
1611 totalData = sizeof(smb_rap_share_info_2_t) + 2; /* + two empty strings */
1613 return CM_ERROR_INVAL;
1615 outp = smb_GetTran2ResponsePacket(vcp, p, op, totalParam, totalData);
1617 if(!stricmp(shareName,"all")) {
1618 rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSConfigKeyName, 0,
1619 KEY_QUERY_VALUE, &hkParam);
1620 if (rv == ERROR_SUCCESS) {
1621 len = sizeof(allSubmount);
1622 rv = RegQueryValueEx(hkParam, "AllSubmount", NULL, NULL,
1623 (BYTE *) &allSubmount, &len);
1624 if (rv != ERROR_SUCCESS || allSubmount != 0) {
1627 RegCloseKey (hkParam);
1634 rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SOFTWARE\\OpenAFS\\Client\\Submounts", 0,
1635 KEY_QUERY_VALUE, &hkSubmount);
1636 if (rv == ERROR_SUCCESS) {
1637 rv = RegQueryValueEx(hkSubmount, shareName, NULL, NULL, NULL, NULL);
1638 if (rv == ERROR_SUCCESS) {
1641 RegCloseKey(hkSubmount);
1646 smb_FreeTran2Packet(outp);
1647 return CM_ERROR_BADSHARENAME;
1650 memset(outp->datap, 0, totalData);
1652 outp->parmsp[0] = 0;
1653 outp->parmsp[1] = 0;
1654 outp->parmsp[2] = totalData;
1656 if (infoLevel == 0) {
1657 smb_rap_share_info_0_t * info = (smb_rap_share_info_0_t *) outp->datap;
1658 strncpy(info->shi0_netname, shareName, sizeof(info->shi0_netname)-1);
1659 info->shi0_netname[sizeof(info->shi0_netname)-1] = 0;
1660 } else if(infoLevel == 1) {
1661 smb_rap_share_info_1_t * info = (smb_rap_share_info_1_t *) outp->datap;
1662 strncpy(info->shi1_netname, shareName, sizeof(info->shi1_netname)-1);
1663 info->shi1_netname[sizeof(info->shi1_netname)-1] = 0;
1664 info->shi1_remark = ((unsigned char *) (info + 1)) - outp->datap;
1665 /* type and pad are already zero */
1666 } else { /* infoLevel==2 */
1667 smb_rap_share_info_2_t * info = (smb_rap_share_info_2_t *) outp->datap;
1668 strncpy(info->shi2_netname, shareName, sizeof(info->shi2_netname)-1);
1669 info->shi2_netname[sizeof(info->shi2_netname)-1] = 0;
1670 info->shi2_remark = ((unsigned char *) (info + 1)) - outp->datap;
1671 info->shi2_permissions = ACCESS_ALL;
1672 info->shi2_max_uses = (unsigned short) -1;
1673 info->shi2_path = 1 + (((unsigned char *) (info + 1)) - outp->datap);
1676 outp->totalData = totalData;
1677 outp->totalParms = totalParam;
1679 smb_SendTran2Packet(vcp, outp, op);
1680 smb_FreeTran2Packet(outp);
1685 typedef struct smb_rap_wksta_info_10 {
1686 DWORD wki10_computername; /*char *wki10_computername;*/
1687 DWORD wki10_username; /* char *wki10_username; */
1688 DWORD wki10_langroup; /* char *wki10_langroup;*/
1689 unsigned char wki10_ver_major;
1690 unsigned char wki10_ver_minor;
1691 DWORD wki10_logon_domain; /*char *wki10_logon_domain;*/
1692 DWORD wki10_oth_domains; /* char *wki10_oth_domains;*/
1693 } smb_rap_wksta_info_10_t;
1696 long smb_ReceiveRAPNetWkstaGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1698 smb_tran2Packet_t *outp;
1702 unsigned short * tp;
1705 smb_rap_wksta_info_10_t * info;
1709 tp = p->parmsp + 1; /* Skip over function number */
1710 (void) smb_ParseString((unsigned char*) tp, (char **) &tp); /* skip over param descriptor */
1711 (void) smb_ParseString((unsigned char*) tp, (char **) &tp); /* skip over data descriptor */
1715 if (infoLevel != 10) {
1716 return CM_ERROR_INVAL;
1722 totalData = sizeof(*info) + /* info */
1723 MAX_COMPUTERNAME_LENGTH + /* wki10_computername */
1724 SMB_MAX_USERNAME_LENGTH + /* wki10_username */
1725 MAX_COMPUTERNAME_LENGTH + /* wki10_langroup */
1726 MAX_COMPUTERNAME_LENGTH + /* wki10_logon_domain */
1727 1; /* wki10_oth_domains (null)*/
1729 outp = smb_GetTran2ResponsePacket(vcp, p, op, totalParams, totalData);
1731 memset(outp->parmsp,0,totalParams);
1732 memset(outp->datap,0,totalData);
1734 info = (smb_rap_wksta_info_10_t *) outp->datap;
1735 cstrp = (char *) (info + 1);
1737 info->wki10_computername = (DWORD) (cstrp - outp->datap);
1738 strcpy(cstrp, smb_localNamep);
1739 cstrp += strlen(cstrp) + 1;
1741 info->wki10_username = (DWORD) (cstrp - outp->datap);
1742 uidp = smb_FindUID(vcp, p->uid, 0);
1744 lock_ObtainMutex(&uidp->mx);
1745 if(uidp->unp && uidp->unp->name)
1746 strcpy(cstrp, uidp->unp->name);
1747 lock_ReleaseMutex(&uidp->mx);
1748 smb_ReleaseUID(uidp);
1750 cstrp += strlen(cstrp) + 1;
1752 info->wki10_langroup = (DWORD) (cstrp - outp->datap);
1753 strcpy(cstrp, "WORKGROUP");
1754 cstrp += strlen(cstrp) + 1;
1756 /* TODO: Not sure what values these should take, but these work */
1757 info->wki10_ver_major = 5;
1758 info->wki10_ver_minor = 1;
1760 info->wki10_logon_domain = (DWORD) (cstrp - outp->datap);
1761 strcpy(cstrp, smb_ServerDomainName);
1762 cstrp += strlen(cstrp) + 1;
1764 info->wki10_oth_domains = (DWORD) (cstrp - outp->datap);
1765 cstrp ++; /* no other domains */
1767 outp->totalData = (unsigned short) (cstrp - outp->datap); /* actual data size */
1768 outp->parmsp[2] = outp->totalData;
1769 outp->totalParms = totalParams;
1771 smb_SendTran2Packet(vcp,outp,op);
1772 smb_FreeTran2Packet(outp);
1777 typedef struct smb_rap_server_info_0 {
1779 } smb_rap_server_info_0_t;
1781 typedef struct smb_rap_server_info_1 {
1783 char sv1_version_major;
1784 char sv1_version_minor;
1785 unsigned long sv1_type;
1786 DWORD *sv1_comment_or_master_browser; /* char *sv1_comment_or_master_browser;*/
1787 } smb_rap_server_info_1_t;
1789 char smb_ServerComment[] = "OpenAFS Client";
1790 int smb_ServerCommentLen = sizeof(smb_ServerComment);
1792 #define SMB_SV_TYPE_SERVER 0x00000002L
1793 #define SMB_SV_TYPE_NT 0x00001000L
1794 #define SMB_SV_TYPE_SERVER_NT 0x00008000L
1796 long smb_ReceiveRAPNetServerGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1798 smb_tran2Packet_t *outp;
1802 unsigned short * tp;
1805 smb_rap_server_info_0_t * info0;
1806 smb_rap_server_info_1_t * info1;
1809 tp = p->parmsp + 1; /* Skip over function number */
1810 (void) smb_ParseString((unsigned char*) tp, (char **) &tp); /* skip over param descriptor */
1811 (void) smb_ParseString((unsigned char*) tp, (char **) &tp); /* skip over data descriptor */
1815 if (infoLevel != 0 && infoLevel != 1) {
1816 return CM_ERROR_INVAL;
1822 (infoLevel == 0) ? sizeof(smb_rap_server_info_0_t)
1823 : (sizeof(smb_rap_server_info_1_t) + smb_ServerCommentLen);
1825 outp = smb_GetTran2ResponsePacket(vcp, p, op, totalParams, totalData);
1827 memset(outp->parmsp,0,totalParams);
1828 memset(outp->datap,0,totalData);
1830 if (infoLevel == 0) {
1831 info0 = (smb_rap_server_info_0_t *) outp->datap;
1832 cstrp = (char *) (info0 + 1);
1833 strcpy(info0->sv0_name, "AFS");
1834 } else { /* infoLevel == 1 */
1835 info1 = (smb_rap_server_info_1_t *) outp->datap;
1836 cstrp = (char *) (info1 + 1);
1837 strcpy(info1->sv1_name, "AFS");
1840 SMB_SV_TYPE_SERVER |
1842 SMB_SV_TYPE_SERVER_NT;
1844 info1->sv1_version_major = 5;
1845 info1->sv1_version_minor = 1;
1846 info1->sv1_comment_or_master_browser = (DWORD *) (cstrp - outp->datap);
1848 strcpy(cstrp, smb_ServerComment);
1850 cstrp += smb_ServerCommentLen;
1853 totalData = cstrp - outp->datap;
1854 outp->totalData = min(bufsize,totalData); /* actual data size */
1855 outp->parmsp[0] = (outp->totalData == totalData)? 0 : ERROR_MORE_DATA;
1856 outp->parmsp[2] = totalData;
1857 outp->totalParms = totalParams;
1859 smb_SendTran2Packet(vcp,outp,op);
1860 smb_FreeTran2Packet(outp);
1865 long smb_ReceiveV3Tran2A(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
1867 smb_tran2Packet_t *asp;
1879 /* We sometimes see 0 word count. What to do? */
1880 if (*inp->wctp == 0) {
1885 osi_Log0(smb_logp, "TRANSACTION2 word count = 0");
1887 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
1888 ptbuf[0] = "Transaction2 word count = 0";
1889 ReportEvent(h, EVENTLOG_WARNING_TYPE, 0, 1003, NULL,
1890 1, inp->ncb_length, ptbuf, inp);
1891 DeregisterEventSource(h);
1893 osi_Log0(smb_logp, "TRANSACTION2 word count = 0");
1896 smb_SetSMBDataLength(outp, 0);
1897 smb_SendPacket(vcp, outp);
1901 totalParms = smb_GetSMBParm(inp, 0);
1902 totalData = smb_GetSMBParm(inp, 1);
1904 firstPacket = (inp->inCom == 0x32);
1906 /* find the packet we're reassembling */
1907 lock_ObtainWrite(&smb_globalLock);
1908 asp = smb_FindTran2Packet(vcp, inp);
1910 asp = smb_NewTran2Packet(vcp, inp, totalParms, totalData);
1912 lock_ReleaseWrite(&smb_globalLock);
1914 /* now merge in this latest packet; start by looking up offsets */
1916 parmDisp = dataDisp = 0;
1917 parmOffset = smb_GetSMBParm(inp, 10);
1918 dataOffset = smb_GetSMBParm(inp, 12);
1919 parmCount = smb_GetSMBParm(inp, 9);
1920 dataCount = smb_GetSMBParm(inp, 11);
1921 asp->maxReturnParms = smb_GetSMBParm(inp, 2);
1922 asp->maxReturnData = smb_GetSMBParm(inp, 3);
1924 osi_Log3(smb_logp, "SMB3 received T2 init packet total data %d, cur data %d, max return data %d",
1925 totalData, dataCount, asp->maxReturnData);
1928 parmDisp = smb_GetSMBParm(inp, 4);
1929 parmOffset = smb_GetSMBParm(inp, 3);
1930 dataDisp = smb_GetSMBParm(inp, 7);
1931 dataOffset = smb_GetSMBParm(inp, 6);
1932 parmCount = smb_GetSMBParm(inp, 2);
1933 dataCount = smb_GetSMBParm(inp, 5);
1935 osi_Log2(smb_logp, "SMB3 received T2 aux packet parms %d, data %d",
1936 parmCount, dataCount);
1939 /* now copy the parms and data */
1940 if ( asp->totalParms > 0 && parmCount != 0 )
1942 memcpy(((char *)asp->parmsp) + parmDisp, inp->data + parmOffset, parmCount);
1944 if ( asp->totalData > 0 && dataCount != 0 ) {
1945 memcpy(asp->datap + dataDisp, inp->data + dataOffset, dataCount);
1948 /* account for new bytes */
1949 asp->curData += dataCount;
1950 asp->curParms += parmCount;
1952 /* finally, if we're done, remove the packet from the queue and dispatch it */
1953 if (asp->totalParms > 0 &&
1954 asp->curParms > 0 &&
1955 asp->totalData <= asp->curData &&
1956 asp->totalParms <= asp->curParms) {
1957 /* we've received it all */
1958 lock_ObtainWrite(&smb_globalLock);
1959 osi_QRemove((osi_queue_t **) &smb_tran2AssemblyQueuep, &asp->q);
1960 lock_ReleaseWrite(&smb_globalLock);
1962 /* now dispatch it */
1963 if ( asp->opcode >= 0 && asp->opcode < 20 && smb_tran2DispatchTable[asp->opcode].procp) {
1964 osi_LogEvent("AFS-Dispatch-2[%s]",myCrt_2Dispatch(asp->opcode),"vcp[%x] lana[%d] lsn[%d]",(int)vcp,vcp->lana,vcp->lsn);
1965 osi_Log4(smb_logp,"AFS Server - Dispatch-2 %s vcp[%x] lana[%d] lsn[%d]",myCrt_2Dispatch(asp->opcode),vcp,vcp->lana,vcp->lsn);
1966 code = (*smb_tran2DispatchTable[asp->opcode].procp)(vcp, asp, outp);
1969 osi_LogEvent("AFS-Dispatch-2 [invalid]", NULL, "op[%x] vcp[%x] lana[%d] lsn[%d]", asp->opcode, vcp, vcp->lana, vcp->lsn);
1970 osi_Log4(smb_logp,"AFS Server - Dispatch-2 [INVALID] op[%x] vcp[%x] lana[%d] lsn[%d]", asp->opcode, vcp, vcp->lana, vcp->lsn);
1971 code = CM_ERROR_BADOP;
1974 /* if an error is returned, we're supposed to send an error packet,
1975 * otherwise the dispatched function already did the data sending.
1976 * We give dispatched proc the responsibility since it knows how much
1977 * space to allocate.
1980 smb_SendTran2Error(vcp, asp, outp, code);
1983 /* free the input tran 2 packet */
1984 lock_ObtainWrite(&smb_globalLock);
1985 smb_FreeTran2Packet(asp);
1986 lock_ReleaseWrite(&smb_globalLock);
1988 else if (firstPacket) {
1989 /* the first packet in a multi-packet request, we need to send an
1990 * ack to get more data.
1992 smb_SetSMBDataLength(outp, 0);
1993 smb_SendPacket(vcp, outp);
1999 long smb_ReceiveTran2Open(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
2002 smb_tran2Packet_t *outp;
2007 cm_scache_t *dscp; /* dir we're dealing with */
2008 cm_scache_t *scp; /* file we're creating */
2010 int initialModeBits;
2020 int parmSlot; /* which parm we're dealing with */
2021 long returnEALength;
2029 extraInfo = (p->parmsp[0] & 1); /* return extra info */
2030 returnEALength = (p->parmsp[0] & 8); /* return extended attr length */
2032 openFun = p->parmsp[6]; /* open function */
2033 excl = ((openFun & 3) == 0);
2034 trunc = ((openFun & 3) == 2); /* truncate it */
2035 openMode = (p->parmsp[1] & 0x7);
2036 openAction = 0; /* tracks what we did */
2038 attributes = p->parmsp[3];
2039 dosTime = p->parmsp[4] | (p->parmsp[5] << 16);
2041 /* compute initial mode bits based on read-only flag in attributes */
2042 initialModeBits = 0666;
2043 if (attributes & 1) initialModeBits &= ~0222;
2045 pathp = (char *) (&p->parmsp[14]);
2047 outp = smb_GetTran2ResponsePacket(vcp, p, op, 40, 0);
2049 spacep = cm_GetSpace();
2050 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
2052 if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
2053 /* special case magic file name for receiving IOCTL requests
2054 * (since IOCTL calls themselves aren't getting through).
2056 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
2057 smb_SetupIoctlFid(fidp, spacep);
2059 /* copy out remainder of the parms */
2061 outp->parmsp[parmSlot] = fidp->fid; parmSlot++;
2063 outp->parmsp[parmSlot] = /* attrs */ 0; parmSlot++;
2064 outp->parmsp[parmSlot] = 0; parmSlot++; /* mod time */
2065 outp->parmsp[parmSlot] = 0; parmSlot++;
2066 outp->parmsp[parmSlot] = 0; parmSlot++; /* len */
2067 outp->parmsp[parmSlot] = 0x7fff; parmSlot++;
2068 outp->parmsp[parmSlot] = openMode; parmSlot++;
2069 outp->parmsp[parmSlot] = 0; parmSlot++; /* file type 0 ==> normal file or dir */
2070 outp->parmsp[parmSlot] = 0; parmSlot++; /* IPC junk */
2072 /* and the final "always present" stuff */
2073 outp->parmsp[parmSlot] = /* openAction found existing file */ 1; parmSlot++;
2074 /* next write out the "unique" ID */
2075 outp->parmsp[parmSlot] = 0x1234; parmSlot++;
2076 outp->parmsp[parmSlot] = 0x5678; parmSlot++;
2077 outp->parmsp[parmSlot] = 0; parmSlot++;
2078 if (returnEALength) {
2079 outp->parmsp[parmSlot] = 0; parmSlot++;
2080 outp->parmsp[parmSlot] = 0; parmSlot++;
2083 outp->totalData = 0;
2084 outp->totalParms = parmSlot * 2;
2086 smb_SendTran2Packet(vcp, outp, op);
2088 smb_FreeTran2Packet(outp);
2090 /* and clean up fid reference */
2091 smb_ReleaseFID(fidp);
2095 #ifdef DEBUG_VERBOSE
2097 char *hexp, *asciip;
2098 asciip = (lastNamep ? lastNamep : pathp);
2099 hexp = osi_HexifyString( asciip );
2100 DEBUG_EVENT2("AFS","T2Open H[%s] A[%s]", hexp, asciip);
2105 userp = smb_GetTran2User(vcp, p);
2106 /* In the off chance that userp is NULL, we log and abandon */
2108 osi_Log1(smb_logp, "ReceiveTran2Open user [%d] not resolvable", p->uid);
2109 smb_FreeTran2Packet(outp);
2110 return CM_ERROR_BADSMB;
2113 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
2114 if (code == CM_ERROR_TIDIPC) {
2115 /* Attempt to use TID allocated for IPC. The client is
2116 probably trying to locate DCE RPC end points, which
2117 we don't support. */
2118 osi_Log0(smb_logp, "Tran2Open received IPC TID");
2119 cm_ReleaseUser(userp);
2120 smb_FreeTran2Packet(outp);
2121 return CM_ERROR_NOSUCHPATH;
2125 code = cm_NameI(cm_rootSCachep, pathp,
2126 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
2127 userp, tidPathp, &req, &scp);
2129 code = cm_NameI(cm_rootSCachep, spacep->data,
2130 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
2131 userp, tidPathp, &req, &dscp);
2132 cm_FreeSpace(spacep);
2135 cm_ReleaseUser(userp);
2136 smb_FreeTran2Packet(outp);
2140 /* otherwise, scp points to the parent directory. Do a lookup,
2141 * and truncate the file if we find it, otherwise we create the
2148 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD, userp,
2150 if (code && code != CM_ERROR_NOSUCHFILE) {
2151 cm_ReleaseSCache(dscp);
2152 cm_ReleaseUser(userp);
2153 smb_FreeTran2Packet(outp);
2158 cm_FreeSpace(spacep);
2161 /* if we get here, if code is 0, the file exists and is represented by
2162 * scp. Otherwise, we have to create it.
2165 code = cm_CheckOpen(scp, openMode, trunc, userp, &req);
2167 if (dscp) cm_ReleaseSCache(dscp);
2168 cm_ReleaseSCache(scp);
2169 cm_ReleaseUser(userp);
2170 smb_FreeTran2Packet(outp);
2175 /* oops, file shouldn't be there */
2176 if (dscp) cm_ReleaseSCache(dscp);
2177 cm_ReleaseSCache(scp);
2178 cm_ReleaseUser(userp);
2179 smb_FreeTran2Packet(outp);
2180 return CM_ERROR_EXISTS;
2184 setAttr.mask = CM_ATTRMASK_LENGTH;
2185 setAttr.length.LowPart = 0;
2186 setAttr.length.HighPart = 0;
2187 code = cm_SetAttr(scp, &setAttr, userp, &req);
2188 openAction = 3; /* truncated existing file */
2191 openAction = 1; /* found existing file */
2193 else if (!(openFun & SMB_ATTR_DIRECTORY)) {
2194 /* don't create if not found */
2195 if (dscp) cm_ReleaseSCache(dscp);
2196 osi_assert(scp == NULL);
2197 cm_ReleaseUser(userp);
2198 smb_FreeTran2Packet(outp);
2199 return CM_ERROR_NOSUCHFILE;
2202 osi_assert(dscp != NULL && scp == NULL);
2203 openAction = 2; /* created file */
2204 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
2205 smb_UnixTimeFromSearchTime(&setAttr.clientModTime, dosTime);
2206 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
2208 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
2209 smb_NotifyChange(FILE_ACTION_ADDED,
2210 FILE_NOTIFY_CHANGE_FILE_NAME,
2211 dscp, lastNamep, NULL, TRUE);
2212 if (!excl && code == CM_ERROR_EXISTS) {
2213 /* not an exclusive create, and someone else tried
2214 * creating it already, then we open it anyway. We
2215 * don't bother retrying after this, since if this next
2216 * fails, that means that the file was deleted after we
2217 * started this call.
2219 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
2223 setAttr.mask = CM_ATTRMASK_LENGTH;
2224 setAttr.length.LowPart = 0;
2225 setAttr.length.HighPart = 0;
2226 code = cm_SetAttr(scp, &setAttr, userp,
2229 } /* lookup succeeded */
2233 /* we don't need this any longer */
2234 if (dscp) cm_ReleaseSCache(dscp);
2237 /* something went wrong creating or truncating the file */
2238 if (scp) cm_ReleaseSCache(scp);
2239 cm_ReleaseUser(userp);
2240 smb_FreeTran2Packet(outp);
2244 /* make sure we're about to open a file */
2245 if (scp->fileType != CM_SCACHETYPE_FILE) {
2247 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
2248 cm_scache_t * targetScp = 0;
2249 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
2251 /* we have a more accurate file to use (the
2252 * target of the symbolic link). Otherwise,
2253 * we'll just use the symlink anyway.
2255 osi_Log2(smb_logp, "symlink vp %x to vp %x",
2257 cm_ReleaseSCache(scp);
2261 if (scp->fileType != CM_SCACHETYPE_FILE) {
2262 cm_ReleaseSCache(scp);
2263 cm_ReleaseUser(userp);
2264 smb_FreeTran2Packet(outp);
2265 return CM_ERROR_ISDIR;
2269 /* now all we have to do is open the file itself */
2270 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
2273 /* save a pointer to the vnode */
2276 /* compute open mode */
2277 if (openMode != 1) fidp->flags |= SMB_FID_OPENREAD;
2278 if (openMode == 1 || openMode == 2)
2279 fidp->flags |= SMB_FID_OPENWRITE;
2281 smb_ReleaseFID(fidp);
2283 cm_Open(scp, 0, userp);
2285 /* copy out remainder of the parms */
2287 outp->parmsp[parmSlot] = fidp->fid; parmSlot++;
2288 lock_ObtainMutex(&scp->mx);
2290 outp->parmsp[parmSlot] = smb_Attributes(scp); parmSlot++;
2291 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
2292 outp->parmsp[parmSlot] = (unsigned short)(dosTime & 0xffff); parmSlot++;
2293 outp->parmsp[parmSlot] = (unsigned short)((dosTime>>16) & 0xffff); parmSlot++;
2294 outp->parmsp[parmSlot] = (unsigned short) (scp->length.LowPart & 0xffff);
2296 outp->parmsp[parmSlot] = (unsigned short) ((scp->length.LowPart >> 16) & 0xffff);
2298 outp->parmsp[parmSlot] = openMode; parmSlot++;
2299 outp->parmsp[parmSlot] = 0; parmSlot++; /* file type 0 ==> normal file or dir */
2300 outp->parmsp[parmSlot] = 0; parmSlot++; /* IPC junk */
2302 /* and the final "always present" stuff */
2303 outp->parmsp[parmSlot] = openAction; parmSlot++;
2304 /* next write out the "unique" ID */
2305 outp->parmsp[parmSlot] = (unsigned short) (scp->fid.vnode & 0xffff); parmSlot++;
2306 outp->parmsp[parmSlot] = (unsigned short) (scp->fid.volume & 0xffff); parmSlot++;
2307 outp->parmsp[parmSlot] = 0; parmSlot++;
2308 if (returnEALength) {
2309 outp->parmsp[parmSlot] = 0; parmSlot++;
2310 outp->parmsp[parmSlot] = 0; parmSlot++;
2312 lock_ReleaseMutex(&scp->mx);
2313 outp->totalData = 0; /* total # of data bytes */
2314 outp->totalParms = parmSlot * 2; /* shorts are two bytes */
2316 smb_SendTran2Packet(vcp, outp, op);
2318 smb_FreeTran2Packet(outp);
2320 cm_ReleaseUser(userp);
2321 /* leave scp held since we put it in fidp->scp */
2325 long smb_ReceiveTran2FindFirst(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
2327 osi_Log0(smb_logp,"ReceiveTran2FindFirst - NOT_SUPPORTED");
2328 return CM_ERROR_BADOP;
2331 long smb_ReceiveTran2FindNext(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
2333 osi_Log0(smb_logp,"ReceiveTran2FindNext - NOT_SUPPORTED");
2334 return CM_ERROR_BADOP;
2337 long smb_ReceiveTran2QFSInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
2339 smb_tran2Packet_t *outp;
2340 smb_tran2QFSInfo_t qi;
2343 static char FSname[6] = {'A', 0, 'F', 0, 'S', 0};
2345 osi_Log1(smb_logp, "T2 QFSInfo type 0x%x", p->parmsp[0]);
2347 switch (p->parmsp[0]) {
2348 case 1: responseSize = sizeof(qi.u.allocInfo); break;
2349 case 2: responseSize = sizeof(qi.u.volumeInfo); break;
2350 case 0x102: responseSize = sizeof(qi.u.FSvolumeInfo); break;
2351 case 0x103: responseSize = sizeof(qi.u.FSsizeInfo); break;
2352 case 0x104: responseSize = sizeof(qi.u.FSdeviceInfo); break;
2353 case 0x105: responseSize = sizeof(qi.u.FSattributeInfo); break;
2354 default: return CM_ERROR_INVAL;
2357 outp = smb_GetTran2ResponsePacket(vcp, p, op, 0, responseSize);
2358 switch (p->parmsp[0]) {
2361 qi.u.allocInfo.FSID = 0;
2362 qi.u.allocInfo.sectorsPerAllocUnit = 1;
2363 qi.u.allocInfo.totalAllocUnits = 0x7fffffff;
2364 qi.u.allocInfo.availAllocUnits = 0x3fffffff;
2365 qi.u.allocInfo.bytesPerSector = 1024;
2370 qi.u.volumeInfo.vsn = 1234;
2371 qi.u.volumeInfo.vnCount = 4;
2372 /* we're supposed to pad it out with zeroes to the end */
2373 memset(&qi.u.volumeInfo.label, 0, sizeof(qi.u.volumeInfo.label));
2374 memcpy(qi.u.volumeInfo.label, "AFS", 4);
2378 /* FS volume info */
2379 memset((char *)&qi.u.FSvolumeInfo.vct, 0, sizeof(FILETIME));
2380 qi.u.FSvolumeInfo.vsn = 1234;
2381 qi.u.FSvolumeInfo.vnCount = 8;
2382 memcpy(qi.u.FSvolumeInfo.label, "A\0F\0S\0\0", 8);
2388 temp.LowPart = 0x7fffffff;
2389 qi.u.FSsizeInfo.totalAllocUnits = temp;
2390 temp.LowPart = 0x3fffffff;
2391 qi.u.FSsizeInfo.availAllocUnits = temp;
2392 qi.u.FSsizeInfo.sectorsPerAllocUnit = 1;
2393 qi.u.FSsizeInfo.bytesPerSector = 1024;
2397 /* FS device info */
2398 qi.u.FSdeviceInfo.devType = 0; /* don't have a number */
2399 qi.u.FSdeviceInfo.characteristics = 0x50; /* remote, virtual */
2403 /* FS attribute info */
2404 /* attributes, defined in WINNT.H:
2405 * FILE_CASE_SENSITIVE_SEARCH 0x1
2406 * FILE_CASE_PRESERVED_NAMES 0x2
2407 * <no name defined> 0x4000
2408 * If bit 0x4000 is not set, Windows 95 thinks
2409 * we can't handle long (non-8.3) names,
2410 * despite our protestations to the contrary.
2412 qi.u.FSattributeInfo.attributes = 0x4003;
2413 qi.u.FSattributeInfo.maxCompLength = 255;
2414 qi.u.FSattributeInfo.FSnameLength = 6;
2415 memcpy(qi.u.FSattributeInfo.FSname, FSname, 6);
2419 /* copy out return data, and set corresponding sizes */
2420 outp->totalParms = 0;
2421 outp->totalData = responseSize;
2422 memcpy(outp->datap, &qi, responseSize);
2424 /* send and free the packets */
2425 smb_SendTran2Packet(vcp, outp, op);
2426 smb_FreeTran2Packet(outp);
2431 long smb_ReceiveTran2SetFSInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
2433 osi_Log0(smb_logp,"ReceiveTran2SetFSInfo - NOT_SUPPORTED");
2434 return CM_ERROR_BADOP;
2437 struct smb_ShortNameRock {
2441 size_t shortNameLen;
2444 int cm_GetShortNameProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *vrockp,
2447 struct smb_ShortNameRock *rockp;
2451 /* compare both names and vnodes, though probably just comparing vnodes
2452 * would be safe enough.
2454 if (cm_stricmp(dep->name, rockp->maskp) != 0)
2456 if (ntohl(dep->fid.vnode) != rockp->vnode)
2458 /* This is the entry */
2459 cm_Gen8Dot3Name(dep, rockp->shortName, &shortNameEnd);
2460 rockp->shortNameLen = shortNameEnd - rockp->shortName;
2461 return CM_ERROR_STOPNOW;
2464 long cm_GetShortName(char *pathp, cm_user_t *userp, cm_req_t *reqp,
2465 char *tidPathp, int vnode, char *shortName, size_t *shortNameLenp)
2467 struct smb_ShortNameRock rock;
2471 int caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
2475 spacep = cm_GetSpace();
2476 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
2478 code = cm_NameI(cm_rootSCachep, spacep->data, caseFold, userp, tidPathp,
2480 cm_FreeSpace(spacep);
2481 if (code) return code;
2483 if (!lastNamep) lastNamep = pathp;
2486 thyper.HighPart = 0;
2487 rock.shortName = shortName;
2489 rock.maskp = lastNamep;
2490 code = cm_ApplyDir(dscp, cm_GetShortNameProc, &rock, &thyper, userp, reqp, NULL);
2492 cm_ReleaseSCache(dscp);
2495 return CM_ERROR_NOSUCHFILE;
2496 if (code == CM_ERROR_STOPNOW) {
2497 *shortNameLenp = rock.shortNameLen;
2503 long smb_ReceiveTran2QPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
2505 smb_tran2Packet_t *outp;
2508 unsigned short infoLevel;
2510 unsigned short attributes;
2511 unsigned long extAttributes;
2516 cm_scache_t *scp, *dscp;
2525 infoLevel = p->parmsp[0];
2526 if (infoLevel == 6) nbytesRequired = 0;
2527 else if (infoLevel == 1) nbytesRequired = 22;
2528 else if (infoLevel == 2) nbytesRequired = 26;
2529 else if (infoLevel == 0x101) nbytesRequired = 40;
2530 else if (infoLevel == 0x102) nbytesRequired = 24;
2531 else if (infoLevel == 0x103) nbytesRequired = 4;
2532 else if (infoLevel == 0x108) nbytesRequired = 30;
2534 osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
2535 p->opcode, infoLevel);
2536 smb_SendTran2Error(vcp, p, opx, CM_ERROR_INVAL);
2539 osi_Log2(smb_logp, "T2 QPathInfo type 0x%x path %s", infoLevel,
2540 osi_LogSaveString(smb_logp, (char *)(&p->parmsp[3])));
2542 outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, nbytesRequired);
2544 if (infoLevel > 0x100)
2545 outp->totalParms = 2;
2547 outp->totalParms = 0;
2548 outp->totalData = nbytesRequired;
2550 /* now, if we're at infoLevel 6, we're only being asked to check
2551 * the syntax, so we just OK things now. In particular, we're *not*
2552 * being asked to verify anything about the state of any parent dirs.
2554 if (infoLevel == 6) {
2555 smb_SendTran2Packet(vcp, outp, opx);
2556 smb_FreeTran2Packet(outp);
2560 userp = smb_GetTran2User(vcp, p);
2562 osi_Log1(smb_logp, "ReceiveTran2QPathInfo unable to resolve user [%d]", p->uid);
2563 smb_FreeTran2Packet(outp);
2564 return CM_ERROR_BADSMB;
2567 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
2569 cm_ReleaseUser(userp);
2570 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOSUCHPATH);
2571 smb_FreeTran2Packet(outp);
2576 * XXX Strange hack XXX
2578 * As of Patch 7 (13 January 98), we are having the following problem:
2579 * In NT Explorer 4.0, whenever we click on a directory, AFS gets
2580 * requests to look up "desktop.ini" in all the subdirectories.
2581 * This can cause zillions of timeouts looking up non-existent cells
2582 * and volumes, especially in the top-level directory.
2584 * We have not found any way to avoid this or work around it except
2585 * to explicitly ignore the requests for mount points that haven't
2586 * yet been evaluated and for directories that haven't yet been
2589 if (infoLevel == 0x101) {
2590 spacep = cm_GetSpace();
2591 smb_StripLastComponent(spacep->data, &lastComp,
2592 (char *)(&p->parmsp[3]));
2593 /* Make sure that lastComp is not NULL */
2595 if (strcmp(lastComp, "\\desktop.ini") == 0) {
2596 code = cm_NameI(cm_rootSCachep, spacep->data,
2600 userp, tidPathp, &req, &dscp);
2602 if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT
2603 && !dscp->mountRootFidp)
2604 code = CM_ERROR_NOSUCHFILE;
2605 else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
2606 cm_buf_t *bp = buf_Find(dscp, &hzero);
2610 code = CM_ERROR_NOSUCHFILE;
2612 cm_ReleaseSCache(dscp);
2614 cm_FreeSpace(spacep);
2615 cm_ReleaseUser(userp);
2616 smb_SendTran2Error(vcp, p, opx, code);
2617 smb_FreeTran2Packet(outp);
2623 cm_FreeSpace(spacep);
2626 /* now do namei and stat, and copy out the info */
2627 code = cm_NameI(cm_rootSCachep, (char *)(&p->parmsp[3]),
2628 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, tidPathp, &req, &scp);
2631 cm_ReleaseUser(userp);
2632 smb_SendTran2Error(vcp, p, opx, code);
2633 smb_FreeTran2Packet(outp);
2637 lock_ObtainMutex(&scp->mx);
2638 code = cm_SyncOp(scp, NULL, userp, &req, 0,
2639 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
2640 if (code) goto done;
2642 /* now we have the status in the cache entry, and everything is locked.
2643 * Marshall the output data.
2646 /* for info level 108, figure out short name */
2647 if (infoLevel == 0x108) {
2648 code = cm_GetShortName((char *)(&p->parmsp[3]), userp, &req,
2649 tidPathp, scp->fid.vnode, shortName,
2656 *((u_long *)op) = len * 2; op += 4;
2657 mbstowcs((unsigned short *)op, shortName, len);
2662 if (infoLevel == 1 || infoLevel == 2) {
2663 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
2664 *((u_long *)op) = dosTime; op += 4; /* creation time */
2665 *((u_long *)op) = dosTime; op += 4; /* access time */
2666 *((u_long *)op) = dosTime; op += 4; /* write time */
2667 *((u_long *)op) = scp->length.LowPart; op += 4; /* length */
2668 *((u_long *)op) = scp->length.LowPart; op += 4; /* alloc size */
2669 attributes = smb_Attributes(scp);
2670 *((u_short *)op) = attributes; op += 2; /* attributes */
2672 else if (infoLevel == 0x101) {
2673 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
2674 *((FILETIME *)op) = ft; op += 8; /* creation time */
2675 *((FILETIME *)op) = ft; op += 8; /* last access time */
2676 *((FILETIME *)op) = ft; op += 8; /* last write time */
2677 *((FILETIME *)op) = ft; op += 8; /* last change time */
2678 extAttributes = smb_ExtAttributes(scp);
2679 *((u_long *)op) = extAttributes; op += 4; /* extended attribs */
2680 *((u_long *)op) = 0; op += 4; /* don't know what this is */
2682 else if (infoLevel == 0x102) {
2683 *((LARGE_INTEGER *)op) = scp->length; op += 8; /* alloc size */
2684 *((LARGE_INTEGER *)op) = scp->length; op += 8; /* EOF */
2685 *((u_long *)op) = scp->linkCount; op += 4;
2688 *op++ = (scp->fileType == CM_SCACHETYPE_DIRECTORY ? 1 : 0);
2691 else if (infoLevel == 0x103) {
2692 memset(op, 0, 4); op += 4; /* EA size */
2695 /* now, if we are being asked about extended attrs, return a 0 size */
2696 if (infoLevel == 2) {
2697 *((u_long *)op) = 0; op += 4;
2701 /* send and free the packets */
2703 lock_ReleaseMutex(&scp->mx);
2704 cm_ReleaseSCache(scp);
2705 cm_ReleaseUser(userp);
2707 smb_SendTran2Packet(vcp, outp, opx);
2709 smb_SendTran2Error(vcp, p, opx, code);
2710 smb_FreeTran2Packet(outp);
2715 long smb_ReceiveTran2SetPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
2717 osi_Log0(smb_logp,"ReceiveTran2SetPathInfo - NOT_SUPPORTED");
2718 return CM_ERROR_BADOP;
2721 long smb_ReceiveTran2QFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
2723 smb_tran2Packet_t *outp;
2725 unsigned long attributes;
2726 unsigned short infoLevel;
2739 fidp = smb_FindFID(vcp, fid, 0);
2742 smb_SendTran2Error(vcp, p, opx, CM_ERROR_BADFD);
2746 infoLevel = p->parmsp[1];
2747 if (infoLevel == 0x101) nbytesRequired = 40;
2748 else if (infoLevel == 0x102) nbytesRequired = 24;
2749 else if (infoLevel == 0x103) nbytesRequired = 4;
2750 else if (infoLevel == 0x104) nbytesRequired = 6;
2752 osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
2753 p->opcode, infoLevel);
2754 smb_SendTran2Error(vcp, p, opx, CM_ERROR_INVAL);
2755 smb_ReleaseFID(fidp);
2758 osi_Log2(smb_logp, "T2 QFileInfo type 0x%x fid %d", infoLevel, fid);
2760 outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, nbytesRequired);
2762 if (infoLevel > 0x100)
2763 outp->totalParms = 2;
2765 outp->totalParms = 0;
2766 outp->totalData = nbytesRequired;
2768 userp = smb_GetTran2User(vcp, p);
2770 osi_Log1(smb_logp, "ReceiveTran2QFileInfo unable to resolve user [%d]", p->uid);
2771 code = CM_ERROR_BADSMB;
2776 lock_ObtainMutex(&scp->mx);
2777 code = cm_SyncOp(scp, NULL, userp, &req, 0,
2778 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
2782 /* now we have the status in the cache entry, and everything is locked.
2783 * Marshall the output data.
2786 if (infoLevel == 0x101) {
2787 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
2788 *((FILETIME *)op) = ft; op += 8; /* creation time */
2789 *((FILETIME *)op) = ft; op += 8; /* last access time */
2790 *((FILETIME *)op) = ft; op += 8; /* last write time */
2791 *((FILETIME *)op) = ft; op += 8; /* last change time */
2792 attributes = smb_ExtAttributes(scp);
2793 *((u_long *)op) = attributes; op += 4;
2794 *((u_long *)op) = 0; op += 4;
2796 else if (infoLevel == 0x102) {
2797 *((LARGE_INTEGER *)op) = scp->length; op += 8; /* alloc size */
2798 *((LARGE_INTEGER *)op) = scp->length; op += 8; /* EOF */
2799 *((u_long *)op) = scp->linkCount; op += 4;
2800 *op++ = ((fidp->flags & SMB_FID_DELONCLOSE) ? 1 : 0);
2801 *op++ = (scp->fileType == CM_SCACHETYPE_DIRECTORY ? 1 : 0);
2805 else if (infoLevel == 0x103) {
2806 *((u_long *)op) = 0; op += 4;
2808 else if (infoLevel == 0x104) {
2812 if (fidp->NTopen_wholepathp)
2813 name = fidp->NTopen_wholepathp;
2815 name = "\\"; /* probably can't happen */
2817 outp->totalData = (len*2) + 4; /* this is actually what we want to return */
2818 *((u_long *)op) = len * 2; op += 4;
2819 mbstowcs((unsigned short *)op, name, len); op += (len * 2);
2822 /* send and free the packets */
2824 lock_ReleaseMutex(&scp->mx);
2825 cm_ReleaseUser(userp);
2826 smb_ReleaseFID(fidp);
2828 smb_SendTran2Packet(vcp, outp, opx);
2830 smb_SendTran2Error(vcp, p, opx, code);
2831 smb_FreeTran2Packet(outp);
2836 long smb_ReceiveTran2SetFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
2841 unsigned short infoLevel;
2842 smb_tran2Packet_t *outp;
2850 fidp = smb_FindFID(vcp, fid, 0);
2853 smb_SendTran2Error(vcp, p, op, CM_ERROR_BADFD);
2857 infoLevel = p->parmsp[1];
2858 osi_Log2(smb_logp,"ReceiveTran2SetFileInfo type=[%x] fid=[%x]", infoLevel, fid);
2859 if (infoLevel > 0x104 || infoLevel < 0x101) {
2860 osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
2861 p->opcode, infoLevel);
2862 smb_SendTran2Error(vcp, p, op, CM_ERROR_INVAL);
2863 smb_ReleaseFID(fidp);
2867 if (infoLevel == 0x102 && !(fidp->flags & SMB_FID_OPENDELETE)) {
2868 smb_SendTran2Error(vcp, p, op, CM_ERROR_NOACCESS);
2869 smb_ReleaseFID(fidp);
2872 if ((infoLevel == 0x103 || infoLevel == 0x104)
2873 && !(fidp->flags & SMB_FID_OPENWRITE)) {
2874 smb_SendTran2Error(vcp, p, op, CM_ERROR_NOACCESS);
2875 smb_ReleaseFID(fidp);
2879 osi_Log1(smb_logp, "T2 SFileInfo type 0x%x", infoLevel);
2881 outp = smb_GetTran2ResponsePacket(vcp, p, op, 2, 0);
2883 outp->totalParms = 2;
2884 outp->totalData = 0;
2886 userp = smb_GetTran2User(vcp, p);
2888 osi_Log1(smb_logp,"ReceiveTran2SetFileInfo unable to resolve user [%d]", p->uid);
2889 code = CM_ERROR_BADSMB;
2895 if (infoLevel == 0x101) {
2897 unsigned int attribute;
2900 /* lock the vnode with a callback; we need the current status
2901 * to determine what the new status is, in some cases.
2903 lock_ObtainMutex(&scp->mx);
2904 code = cm_SyncOp(scp, NULL, userp, &req, 0,
2905 CM_SCACHESYNC_GETSTATUS
2906 | CM_SCACHESYNC_NEEDCALLBACK);
2908 lock_ReleaseMutex(&scp->mx);
2912 /* prepare for setattr call */
2915 lastMod = *((FILETIME *)(p->datap + 16));
2916 /* when called as result of move a b, lastMod is (-1, -1).
2917 * If the check for -1 is not present, timestamp
2918 * of the resulting file will be 1969 (-1)
2920 if (LargeIntegerNotEqualToZero(*((LARGE_INTEGER *)&lastMod)) &&
2921 lastMod.dwLowDateTime != -1 && lastMod.dwHighDateTime != -1) {
2922 attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
2923 smb_UnixTimeFromLargeSearchTime(&attr.clientModTime,
2925 fidp->flags |= SMB_FID_MTIMESETDONE;
2928 attribute = *((u_long *)(p->datap + 32));
2929 if (attribute != 0) {
2930 if ((scp->unixModeBits & 0222)
2931 && (attribute & 1) != 0) {
2932 /* make a writable file read-only */
2933 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
2934 attr.unixModeBits = scp->unixModeBits & ~0222;
2936 else if ((scp->unixModeBits & 0222) == 0
2937 && (attribute & 1) == 0) {
2938 /* make a read-only file writable */
2939 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
2940 attr.unixModeBits = scp->unixModeBits | 0222;
2943 lock_ReleaseMutex(&scp->mx);
2947 code = cm_SetAttr(scp, &attr, userp, &req);
2951 else if (infoLevel == 0x103 || infoLevel == 0x104) {
2952 LARGE_INTEGER size = *((LARGE_INTEGER *)(p->datap));
2955 attr.mask = CM_ATTRMASK_LENGTH;
2956 attr.length.LowPart = size.LowPart;
2957 attr.length.HighPart = size.HighPart;
2958 code = cm_SetAttr(scp, &attr, userp, &req);
2960 else if (infoLevel == 0x102) {
2961 if (*((char *)(p->datap))) {
2962 code = cm_CheckNTDelete(fidp->NTopen_dscp, scp, userp,
2965 fidp->flags |= SMB_FID_DELONCLOSE;
2969 fidp->flags &= ~SMB_FID_DELONCLOSE;
2974 cm_ReleaseUser(userp);
2975 smb_ReleaseFID(fidp);
2977 smb_SendTran2Packet(vcp, outp, op);
2979 smb_SendTran2Error(vcp, p, op, code);
2980 smb_FreeTran2Packet(outp);
2986 smb_ReceiveTran2FSCTL(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
2988 osi_Log0(smb_logp,"ReceiveTran2FSCTL - NOT_SUPPORTED");
2989 return CM_ERROR_BADOP;
2993 smb_ReceiveTran2IOCTL(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
2995 osi_Log0(smb_logp,"ReceiveTran2IOCTL - NOT_SUPPORTED");
2996 return CM_ERROR_BADOP;
3000 smb_ReceiveTran2FindNotifyFirst(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3002 osi_Log0(smb_logp,"ReceiveTran2FindNotifyFirst - NOT_SUPPORTED");
3003 return CM_ERROR_BADOP;
3007 smb_ReceiveTran2FindNotifyNext(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3009 osi_Log0(smb_logp,"ReceiveTran2FindNotifyNext - NOT_SUPPORTED");
3010 return CM_ERROR_BADOP;
3014 smb_ReceiveTran2CreateDirectory(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3016 osi_Log0(smb_logp,"ReceiveTran2CreateDirectory - NOT_SUPPORTED");
3017 return CM_ERROR_BADOP;
3021 smb_ReceiveTran2SessionSetup(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3023 osi_Log0(smb_logp,"ReceiveTran2SessionSetup - NOT_SUPPORTED");
3024 return CM_ERROR_BADOP;
3028 smb_ReceiveTran2GetDFSReferral(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3030 osi_Log0(smb_logp,"ReceiveTran2GetDFSReferral - NOT_SUPPORTED");
3031 return CM_ERROR_BADOP;
3035 smb_ReceiveTran2ReportDFSInconsistency(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3037 osi_Log0(smb_logp,"ReceiveTran2ReportDFSInconsistency - NOT_SUPPORTED");
3038 return CM_ERROR_BADOP;
3042 smb_ApplyV3DirListPatches(cm_scache_t *dscp,
3043 smb_dirListPatch_t **dirPatchespp, int infoLevel, cm_user_t *userp,
3048 cm_scache_t *targetScp; /* target if scp is a symlink */
3053 unsigned short attr;
3054 unsigned long lattr;
3055 smb_dirListPatch_t *patchp;
3056 smb_dirListPatch_t *npatchp;
3058 for(patchp = *dirPatchespp; patchp; patchp =
3059 (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
3060 code = cm_GetSCache(&patchp->fid, &scp, userp, reqp);
3062 lock_ObtainMutex(&scp->mx);
3063 code = cm_SyncOp(scp, NULL, userp, reqp, 0,
3064 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3066 lock_ReleaseMutex(&scp->mx);
3067 cm_ReleaseSCache(scp);
3069 dptr = patchp->dptr;
3071 /* Plug in fake timestamps. A time stamp of 0 causes 'invalid parameter'
3072 errors in the client. */
3073 if (infoLevel >= 0x101) {
3074 /* 1969-12-31 23:59:59 +00 */
3075 ft.dwHighDateTime = 0x19DB200;
3076 ft.dwLowDateTime = 0x5BB78980;
3078 /* copy to Creation Time */
3079 *((FILETIME *)dptr) = ft;
3082 /* copy to Last Access Time */
3083 *((FILETIME *)dptr) = ft;
3086 /* copy to Last Write Time */
3087 *((FILETIME *)dptr) = ft;
3090 /* copy to Change Time */
3091 *((FILETIME *)dptr) = ft;
3094 /* merge in hidden attribute */
3095 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
3096 *((u_long *)dptr) = SMB_ATTR_HIDDEN;
3100 /* 1969-12-31 23:59:58 +00*/
3101 dosTime = 0xEBBFBF7D;
3103 /* and copy out date */
3104 shortTemp = (dosTime>>16) & 0xffff;
3105 *((u_short *)dptr) = shortTemp;
3108 /* copy out creation time */
3109 shortTemp = dosTime & 0xffff;
3110 *((u_short *)dptr) = shortTemp;
3113 /* and copy out date */
3114 shortTemp = (dosTime>>16) & 0xffff;
3115 *((u_short *)dptr) = shortTemp;
3118 /* copy out access time */
3119 shortTemp = dosTime & 0xffff;
3120 *((u_short *)dptr) = shortTemp;
3123 /* and copy out date */
3124 shortTemp = (dosTime>>16) & 0xffff;
3125 *((u_short *)dptr) = shortTemp;
3128 /* copy out mod time */
3129 shortTemp = dosTime & 0xffff;
3130 *((u_short *)dptr) = shortTemp;
3133 /* merge in hidden (dot file) attribute */
3134 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
3135 attr = SMB_ATTR_HIDDEN;
3136 *dptr++ = attr & 0xff;
3137 *dptr++ = (attr >> 8) & 0xff;
3143 /* now watch for a symlink */
3145 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
3146 lock_ReleaseMutex(&scp->mx);
3147 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, reqp);
3149 /* we have a more accurate file to use (the
3150 * target of the symbolic link). Otherwise,
3151 * we'll just use the symlink anyway.
3153 osi_Log2(smb_logp, "symlink vp %x to vp %x",
3155 cm_ReleaseSCache(scp);
3158 lock_ObtainMutex(&scp->mx);
3161 dptr = patchp->dptr;
3163 if (infoLevel >= 0x101) {
3165 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
3167 /* copy to Creation Time */
3168 *((FILETIME *)dptr) = ft;
3171 /* copy to Last Access Time */
3172 *((FILETIME *)dptr) = ft;
3175 /* copy to Last Write Time */
3176 *((FILETIME *)dptr) = ft;
3179 /* copy to Change Time */
3180 *((FILETIME *)dptr) = ft;
3183 /* Use length for both file length and alloc length */
3184 *((LARGE_INTEGER *)dptr) = scp->length;
3186 *((LARGE_INTEGER *)dptr) = scp->length;
3189 /* Copy attributes */
3190 lattr = smb_ExtAttributes(scp);
3191 /* merge in hidden (dot file) attribute */
3192 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE )
3193 lattr |= SMB_ATTR_HIDDEN;
3194 *((u_long *)dptr) = lattr;
3199 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
3201 /* and copy out date */
3202 shortTemp = (dosTime>>16) & 0xffff;
3203 *((u_short *)dptr) = shortTemp;
3206 /* copy out creation time */
3207 shortTemp = dosTime & 0xffff;
3208 *((u_short *)dptr) = shortTemp;
3211 /* and copy out date */
3212 shortTemp = (dosTime>>16) & 0xffff;
3213 *((u_short *)dptr) = shortTemp;
3216 /* copy out access time */
3217 shortTemp = dosTime & 0xffff;
3218 *((u_short *)dptr) = shortTemp;
3221 /* and copy out date */
3222 shortTemp = (dosTime>>16) & 0xffff;
3223 *((u_short *)dptr) = shortTemp;
3226 /* copy out mod time */
3227 shortTemp = dosTime & 0xffff;
3228 *((u_short *)dptr) = shortTemp;
3231 /* copy out file length and alloc length,
3232 * using the same for both
3234 *((u_long *)dptr) = scp->length.LowPart;
3236 *((u_long *)dptr) = scp->length.LowPart;
3239 /* finally copy out attributes as short */
3240 attr = smb_Attributes(scp);
3241 /* merge in hidden (dot file) attribute */
3242 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE )
3243 attr |= SMB_ATTR_HIDDEN;
3244 *dptr++ = attr & 0xff;
3245 *dptr++ = (attr >> 8) & 0xff;
3248 lock_ReleaseMutex(&scp->mx);
3249 cm_ReleaseSCache(scp);
3252 /* now free the patches */
3253 for (patchp = *dirPatchespp; patchp; patchp = npatchp) {
3254 npatchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q);
3258 /* and mark the list as empty */
3259 *dirPatchespp = NULL;
3264 #ifndef USE_OLD_MATCHING
3265 // char table for case insensitive comparison
3266 char mapCaseTable[256];
3268 VOID initUpperCaseTable(VOID)
3271 for (i = 0; i < 256; ++i)
3272 mapCaseTable[i] = toupper(i);
3273 // make '"' match '.'
3274 mapCaseTable[(int)'"'] = toupper('.');
3275 // make '<' match '*'
3276 mapCaseTable[(int)'<'] = toupper('*');
3277 // make '>' match '?'
3278 mapCaseTable[(int)'>'] = toupper('?');
3281 // Compare 'pattern' (containing metacharacters '*' and '?') with the file
3283 // Note : this procedure works recursively calling itself.
3285 // PSZ pattern : string containing metacharacters.
3286 // PSZ name : file name to be compared with 'pattern'.
3288 // BOOL : TRUE/FALSE (match/mistmatch)
3291 szWildCardMatchFileName(PSZ pattern, PSZ name)
3293 PSZ pename; // points to the last 'name' character
3295 pename = name + strlen(name) - 1;
3305 if (*pattern == '\0')
3307 for (p = pename; p >= name; --p) {
3308 if ((mapCaseTable[*p] == mapCaseTable[*pattern]) &&
3309 szWildCardMatchFileName(pattern + 1, p + 1))
3314 if (mapCaseTable[*name] != mapCaseTable[*pattern])
3321 if (*pattern == '\0' || *pattern == '*' && *(pattern+1) == '\0')
3327 /* do a case-folding search of the star name mask with the name in namep.
3328 * Return 1 if we match, otherwise 0.
3330 int smb_V3MatchMask(char *namep, char *maskp, int flags)
3333 int i, j, star, qmark, retval;
3335 /* make sure we only match 8.3 names, if requested */
3336 if ((flags & CM_FLAG_8DOT3) && !cm_Is8Dot3(namep))
3339 /* optimize the pattern:
3340 * if there is a mixture of '?' and '*',
3341 * for example the sequence "*?*?*?*"
3342 * must be turned into the form "*"
3344 newmask = (char *)malloc(strlen(maskp)+1);
3345 for ( i=0, j=0, star=0, qmark=0; maskp[i]; i++) {
3346 switch ( maskp[i] ) {
3358 } else if ( qmark ) {
3362 newmask[j++] = maskp[i];
3369 } else if ( qmark ) {
3373 newmask[j++] = '\0';
3375 retval = szWildCardMatchFileName(newmask, namep) ? 1:0;
3381 #else /* USE_OLD_MATCHING */
3382 /* do a case-folding search of the star name mask with the name in namep.
3383 * Return 1 if we match, otherwise 0.
3385 int smb_V3MatchMask(char *namep, char *maskp, int flags)
3387 unsigned char tcp1, tcp2; /* Pattern characters */
3388 unsigned char tcn1; /* Name characters */
3389 int sawDot = 0, sawStar = 0, req8dot3 = 0;
3390 char *starNamep, *starMaskp;
3391 static char nullCharp[] = {0};
3392 int casefold = flags & CM_FLAG_CASEFOLD;
3394 /* make sure we only match 8.3 names, if requested */
3395 req8dot3 = (flags & CM_FLAG_8DOT3);
3396 if (req8dot3 && !cm_Is8Dot3(namep))
3401 /* Next pattern character */
3404 /* Next name character */
3408 /* 0 - end of pattern */
3414 else if (tcp1 == '.' || tcp1 == '"') {
3424 * first dot in pattern;
3425 * must match dot or end of name
3430 else if (tcn1 == '.') {
3439 else if (tcp1 == '?') {
3440 if (tcn1 == 0 || tcn1 == '.')
3445 else if (tcp1 == '>') {
3446 if (tcn1 != 0 && tcn1 != '.')
3450 else if (tcp1 == '*' || tcp1 == '<') {
3454 else if ((req8dot3 && tcp2 == '.') || tcp2 == '"') {
3455 while (req8dot3 && tcn1 != '.' && tcn1 != 0)
3470 * pattern character after '*' is not null or
3471 * period. If it is '?' or '>', we are not
3472 * going to understand it. If it is '*' or
3473 * '<', we are going to skip over it. None of
3474 * these are likely, I hope.
3476 /* skip over '*' and '<' */
3477 while (tcp2 == '*' || tcp2 == '<')
3480 /* skip over characters that don't match tcp2 */
3481 while (req8dot3 && tcn1 != '.' && tcn1 != 0 &&
3482 ((casefold && cm_foldUpper[tcn1] != cm_foldUpper[tcp2]) ||
3483 (!casefold && tcn1 != tcp2)))
3487 if ((req8dot3 && tcn1 == '.') || tcn1 == 0)
3490 /* Remember where we are */
3500 /* tcp1 is not a wildcard */
3501 if ((casefold && cm_foldUpper[tcn1] == cm_foldUpper[tcp1]) ||
3502 (!casefold && tcn1 == tcp1)) {
3507 /* if trying to match a star pattern, go back */
3509 maskp = starMaskp - 2;
3510 namep = starNamep + 1;
3519 #endif /* USE_OLD_MATCHING */
3521 long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
3530 smb_dirListPatch_t *dirListPatchesp;
3531 smb_dirListPatch_t *curPatchp;
3534 long orbytes; /* # of bytes in this output record */
3535 long ohbytes; /* # of bytes, except file name */
3536 long onbytes; /* # of bytes in name, incl. term. null */
3537 osi_hyper_t dirLength;
3538 osi_hyper_t bufferOffset;
3539 osi_hyper_t curOffset;
3541 smb_dirSearch_t *dsp;
3545 cm_pageHeader_t *pageHeaderp;
3546 cm_user_t *userp = NULL;
3549 long nextEntryCookie;
3550 int numDirChunks; /* # of 32 byte dir chunks in this entry */
3551 char *op; /* output data ptr */
3552 char *origOp; /* original value of op */
3553 cm_space_t *spacep; /* for pathname buffer */
3554 long maxReturnData; /* max # of return data */
3555 long maxReturnParms; /* max # of return parms */
3556 long bytesInBuffer; /* # data bytes in the output buffer */
3558 char *maskp; /* mask part of path */
3562 smb_tran2Packet_t *outp; /* response packet */
3565 char shortName[13]; /* 8.3 name if needed */
3576 if (p->opcode == 1) {
3577 /* find first; obtain basic parameters from request */
3578 attribute = p->parmsp[0];
3579 maxCount = p->parmsp[1];
3580 infoLevel = p->parmsp[3];
3581 searchFlags = p->parmsp[2];
3582 dsp = smb_NewDirSearch(1);
3583 dsp->attribute = attribute;
3584 pathp = ((char *) p->parmsp) + 12; /* points to path */
3586 maskp = strrchr(pathp, '\\');
3590 maskp++; /* skip over backslash */
3591 strcpy(dsp->mask, maskp); /* and save mask */
3592 /* track if this is likely to match a lot of entries */
3593 starPattern = smb_V3IsStarMask(maskp);
3596 osi_assert(p->opcode == 2);
3597 /* find next; obtain basic parameters from request or open dir file */
3598 dsp = smb_FindDirSearch(p->parmsp[0]);
3600 return CM_ERROR_BADFD;
3601 attribute = dsp->attribute;
3602 maxCount = p->parmsp[1];
3603 infoLevel = p->parmsp[2];
3604 searchFlags = p->parmsp[5];
3606 nextCookie = p->parmsp[3] | (p->parmsp[4] << 16);
3608 starPattern = 1; /* assume, since required a Find Next */
3612 "T2 search dir attr 0x%x, info level %d, max count %d, flags 0x%x",
3613 attribute, infoLevel, maxCount, searchFlags);
3615 osi_Log2(smb_logp, "...T2 search op %d, nextCookie 0x%x",
3616 p->opcode, nextCookie);
3618 if (infoLevel >= 0x101)
3619 searchFlags &= ~4; /* no resume keys */
3621 dirListPatchesp = NULL;
3623 maxReturnData = p->maxReturnData;
3624 if (p->opcode == 1) /* find first */
3625 maxReturnParms = 10; /* bytes */
3627 maxReturnParms = 8; /* bytes */
3629 #ifndef CM_CONFIG_MULTITRAN2RESPONSES
3630 if (maxReturnData > 6000)
3631 maxReturnData = 6000;
3632 #endif /* CM_CONFIG_MULTITRAN2RESPONSES */
3634 outp = smb_GetTran2ResponsePacket(vcp, p, opx, maxReturnParms,
3637 osi_Log1(smb_logp, "T2 receive search dir %s",
3638 osi_LogSaveString(smb_logp, pathp));
3640 /* bail out if request looks bad */
3641 if (p->opcode == 1 && !pathp) {
3642 smb_ReleaseDirSearch(dsp);
3643 smb_FreeTran2Packet(outp);
3644 return CM_ERROR_BADSMB;
3647 osi_Log2(smb_logp, "T2 dir search cookie 0x%x, connection %d",
3648 nextCookie, dsp->cookie);
3650 userp = smb_GetTran2User(vcp, p);
3652 osi_Log1(smb_logp, "T2 dir search unable to resolve user [%d]", p->uid);
3653 smb_ReleaseDirSearch(dsp);
3654 smb_FreeTran2Packet(outp);
3655 return CM_ERROR_BADSMB;
3658 /* try to get the vnode for the path name next */
3659 lock_ObtainMutex(&dsp->mx);
3666 spacep = cm_GetSpace();
3667 smb_StripLastComponent(spacep->data, NULL, pathp);
3668 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
3670 lock_ReleaseMutex(&dsp->mx);
3671 cm_ReleaseUser(userp);
3672 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOFILES);
3673 smb_FreeTran2Packet(outp);
3674 smb_DeleteDirSearch(dsp);
3675 smb_ReleaseDirSearch(dsp);
3678 code = cm_NameI(cm_rootSCachep, spacep->data,
3679 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
3680 userp, tidPathp, &req, &scp);
3681 cm_FreeSpace(spacep);
3685 cm_ReleaseSCache(dsp->scp);
3687 /* we need one hold for the entry we just stored into,
3688 * and one for our own processing. When we're done
3689 * with this function, we'll drop the one for our own
3690 * processing. We held it once from the namei call,
3691 * and so we do another hold now.
3694 lock_ObtainMutex(&scp->mx);
3695 if ((scp->flags & CM_SCACHEFLAG_BULKSTATTING) == 0 &&
3696 LargeIntegerGreaterOrEqualToZero(scp->bulkStatProgress)) {
3697 scp->flags |= CM_SCACHEFLAG_BULKSTATTING;
3698 dsp->flags |= SMB_DIRSEARCH_BULKST;
3700 lock_ReleaseMutex(&scp->mx);
3703 lock_ReleaseMutex(&dsp->mx);
3705 cm_ReleaseUser(userp);
3706 smb_FreeTran2Packet(outp);
3707 smb_DeleteDirSearch(dsp);
3708 smb_ReleaseDirSearch(dsp);
3712 /* get the directory size */
3713 lock_ObtainMutex(&scp->mx);
3714 code = cm_SyncOp(scp, NULL, userp, &req, 0,
3715 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3717 lock_ReleaseMutex(&scp->mx);
3718 cm_ReleaseSCache(scp);
3719 cm_ReleaseUser(userp);
3720 smb_FreeTran2Packet(outp);
3721 smb_DeleteDirSearch(dsp);
3722 smb_ReleaseDirSearch(dsp);
3727 dirLength = scp->length;
3729 bufferOffset.LowPart = bufferOffset.HighPart = 0;
3730 curOffset.HighPart = 0;
3731 curOffset.LowPart = nextCookie;
3732 origOp = outp->datap;
3740 if (searchFlags & 4)
3741 /* skip over resume key */
3744 /* make sure that curOffset.LowPart doesn't point to the first
3745 * 32 bytes in the 2nd through last dir page, and that it doesn't
3746 * point at the first 13 32-byte chunks in the first dir page,
3747 * since those are dir and page headers, and don't contain useful
3750 temp = curOffset.LowPart & (2048-1);
3751 if (curOffset.HighPart == 0 && curOffset.LowPart < 2048) {
3752 /* we're in the first page */
3753 if (temp < 13*32) temp = 13*32;
3756 /* we're in a later dir page */
3757 if (temp < 32) temp = 32;
3760 /* make sure the low order 5 bits are zero */
3763 /* now put temp bits back ito curOffset.LowPart */
3764 curOffset.LowPart &= ~(2048-1);
3765 curOffset.LowPart |= temp;
3767 /* check if we've passed the dir's EOF */
3768 if (LargeIntegerGreaterThanOrEqualTo(curOffset, dirLength)) {
3773 /* check if we've returned all the names that will fit in the
3774 * response packet; we check return count as well as the number
3775 * of bytes requested. We check the # of bytes after we find
3776 * the dir entry, since we'll need to check its size.
3778 if (returnedNames >= maxCount) {
3782 /* see if we can use the bufferp we have now; compute in which
3783 * page the current offset would be, and check whether that's
3784 * the offset of the buffer we have. If not, get the buffer.
3786 thyper.HighPart = curOffset.HighPart;
3787 thyper.LowPart = curOffset.LowPart & ~(buf_bufferSize-1);
3788 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
3791 buf_Release(bufferp);
3794 lock_ReleaseMutex(&scp->mx);
3795 lock_ObtainRead(&scp->bufCreateLock);
3796 code = buf_Get(scp, &thyper, &bufferp);
3797 lock_ReleaseRead(&scp->bufCreateLock);
3798 lock_ObtainMutex(&dsp->mx);
3800 /* now, if we're doing a star match, do bulk fetching
3801 * of all of the status info for files in the dir.
3804 smb_ApplyV3DirListPatches(scp, &dirListPatchesp,
3807 lock_ObtainMutex(&scp->mx);
3808 if ((dsp->flags & SMB_DIRSEARCH_BULKST) &&
3809 LargeIntegerGreaterThanOrEqualTo(thyper, scp->bulkStatProgress)) {
3810 /* Don't bulk stat if risking timeout */
3811 int now = GetCurrentTime();
3812 if (now - req.startTime > 5000) {
3813 scp->bulkStatProgress = thyper;
3814 scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
3815 dsp->flags &= ~SMB_DIRSEARCH_BULKST;
3817 cm_TryBulkStat(scp, &thyper, userp, &req);
3820 lock_ObtainMutex(&scp->mx);
3822 lock_ReleaseMutex(&dsp->mx);
3826 bufferOffset = thyper;
3828 /* now get the data in the cache */
3830 code = cm_SyncOp(scp, bufferp, userp, &req,
3832 CM_SCACHESYNC_NEEDCALLBACK
3833 | CM_SCACHESYNC_READ);
3836 if (cm_HaveBuffer(scp, bufferp, 0)) break;
3838 /* otherwise, load the buffer and try again */
3839 code = cm_GetBuffer(scp, bufferp, NULL, userp,
3844 buf_Release(bufferp);
3848 } /* if (wrong buffer) ... */
3850 /* now we have the buffer containing the entry we're interested
3851 * in; copy it out if it represents a non-deleted entry.
3853 entryInDir = curOffset.LowPart & (2048-1);
3854 entryInBuffer = curOffset.LowPart & (buf_bufferSize - 1);
3856 /* page header will help tell us which entries are free. Page
3857 * header can change more often than once per buffer, since
3858 * AFS 3 dir page size may be less than (but not more than)
3859 * a buffer package buffer.
3861 /* only look intra-buffer */
3862 temp = curOffset.LowPart & (buf_bufferSize - 1);
3863 temp &= ~(2048 - 1); /* turn off intra-page bits */
3864 pageHeaderp = (cm_pageHeader_t *) (bufferp->datap + temp);
3866 /* now determine which entry we're looking at in the page.
3867 * If it is free (there's a free bitmap at the start of the
3868 * dir), we should skip these 32 bytes.
3870 slotInPage = (entryInDir & 0x7e0) >> 5;
3871 if (!(pageHeaderp->freeBitmap[slotInPage>>3] &
3872 (1 << (slotInPage & 0x7)))) {
3873 /* this entry is free */
3874 numDirChunks = 1; /* only skip this guy */
3878 tp = bufferp->datap + entryInBuffer;
3879 dep = (cm_dirEntry_t *) tp; /* now points to AFS3 dir entry */
3881 /* while we're here, compute the next entry's location, too,
3882 * since we'll need it when writing out the cookie into the dir
3885 * XXXX Probably should do more sanity checking.
3887 numDirChunks = cm_NameEntries(dep->name, &onbytes);
3889 /* compute offset of cookie representing next entry */
3890 nextEntryCookie = curOffset.LowPart + (CM_DIR_CHUNKSIZE * numDirChunks);
3892 /* Need 8.3 name? */
3894 if (infoLevel == 0x104
3895 && dep->fid.vnode != 0
3896 && !cm_Is8Dot3(dep->name)) {
3897 cm_Gen8Dot3Name(dep, shortName, &shortNameEnd);
3901 /* When matching, we are using doing a case fold if we have a wildcard mask.
3902 * If we get a non-wildcard match, it's a lookup for a specific file.
3904 if (dep->fid.vnode != 0 &&
3905 (smb_V3MatchMask(dep->name, maskp, (starPattern? CM_FLAG_CASEFOLD : 0)) ||
3907 smb_V3MatchMask(shortName, maskp, CM_FLAG_CASEFOLD)))) {
3909 /* Eliminate entries that don't match requested attributes */
3910 if (smb_hideDotFiles && !(dsp->attribute & SMB_ATTR_HIDDEN) &&
3911 smb_IsDotFile(dep->name))
3912 goto nextEntry; /* no hidden files */
3914 if (!(dsp->attribute & SMB_ATTR_DIRECTORY)) /* no directories */
3916 /* We have already done the cm_TryBulkStat above */
3917 fid.cell = scp->fid.cell;
3918 fid.volume = scp->fid.volume;
3919 fid.vnode = ntohl(dep->fid.vnode);
3920 fid.unique = ntohl(dep->fid.unique);
3921 fileType = cm_FindFileType(&fid);
3922 /*osi_Log2(smb_logp, "smb_ReceiveTran2SearchDir: file %s "
3923 "has filetype %d", dep->name,
3925 if (fileType == CM_SCACHETYPE_DIRECTORY)
3929 /* finally check if this name will fit */
3931 /* standard dir entry stuff */
3932 if (infoLevel < 0x101)
3933 ohbytes = 23; /* pre-NT */
3934 else if (infoLevel == 0x103)
3935 ohbytes = 12; /* NT names only */
3937 ohbytes = 64; /* NT */
3939 if (infoLevel == 0x104)
3940 ohbytes += 26; /* Short name & length */
3942 if (searchFlags & 4) {
3943 ohbytes += 4; /* if resume key required */
3947 && infoLevel != 0x101
3948 && infoLevel != 0x103)
3949 ohbytes += 4; /* EASIZE */
3951 /* add header to name & term. null */
3952 orbytes = onbytes + ohbytes + 1;
3954 /* now, we round up the record to a 4 byte alignment,
3955 * and we make sure that we have enough room here for
3956 * even the aligned version (so we don't have to worry
3957 * about an * overflow when we pad things out below).
3958 * That's the reason for the alignment arithmetic below.
3960 if (infoLevel >= 0x101)
3961 align = (4 - (orbytes & 3)) & 3;
3964 if (orbytes + bytesInBuffer + align > maxReturnData)
3967 /* this is one of the entries to use: it is not deleted
3968 * and it matches the star pattern we're looking for.
3969 * Put out the name, preceded by its length.
3971 /* First zero everything else */
3972 memset(origOp, 0, ohbytes);
3974 if (infoLevel <= 0x101)
3975 *(origOp + ohbytes - 1) = (unsigned char) onbytes;
3976 else if (infoLevel == 0x103)
3977 *((u_long *)(op + 8)) = onbytes;
3979 *((u_long *)(op + 60)) = onbytes;
3980 strcpy(origOp+ohbytes, dep->name);
3982 /* Short name if requested and needed */
3983 if (infoLevel == 0x104) {
3984 if (NeedShortName) {
3985 strcpy(op + 70, shortName);
3986 *(op + 68) = shortNameEnd - shortName;
3990 /* now, adjust the # of entries copied */
3993 /* NextEntryOffset and FileIndex */
3994 if (infoLevel >= 101) {
3995 int entryOffset = orbytes + align;
3996 *((u_long *)op) = entryOffset;
3997 *((u_long *)(op+4)) = nextEntryCookie;
4000 /* now we emit the attribute. This is tricky, since
4001 * we need to really stat the file to find out what
4002 * type of entry we've got. Right now, we're copying
4003 * out data from * a buffer, while holding the scp
4004 * locked, so it isn't really convenient to stat
4005 * something now. We'll put in a place holder
4006 * now, and make a second pass before returning this
4007 * to get the real attributes. So, we just skip the
4008 * data for now, and adjust it later. We allocate a
4009 * patch record to make it easy to find this point
4010 * later. The replay will happen at a time when it is
4011 * safe to unlock the directory.
4013 if (infoLevel != 0x103) {
4014 curPatchp = malloc(sizeof(*curPatchp));
4015 osi_QAdd((osi_queue_t **) &dirListPatchesp,
4017 curPatchp->dptr = op;
4018 if (infoLevel >= 0x101)
4019 curPatchp->dptr += 8;
4021 if (smb_hideDotFiles && smb_IsDotFile(dep->name)) {
4022 curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
4025 curPatchp->flags = 0;
4027 curPatchp->fid.cell = scp->fid.cell;
4028 curPatchp->fid.volume = scp->fid.volume;
4029 curPatchp->fid.vnode = ntohl(dep->fid.vnode);
4030 curPatchp->fid.unique = ntohl(dep->fid.unique);
4033 curPatchp->dep = dep;
4036 if (searchFlags & 4)
4037 /* put out resume key */
4038 *((u_long *)origOp) = nextEntryCookie;
4040 /* Adjust byte ptr and count */
4041 origOp += orbytes; /* skip entire record */
4042 bytesInBuffer += orbytes;
4044 /* and pad the record out */
4045 while (--align >= 0) {
4049 } /* if we're including this name */
4050 else if (!NeedShortName &&
4053 dep->fid.vnode != 0 &&
4054 smb_V3MatchMask(dep->name, maskp, CM_FLAG_CASEFOLD)) {
4055 /* We were looking for exact matches, but here's an inexact one*/
4060 /* and adjust curOffset to be where the new cookie is */
4061 thyper.HighPart = 0;
4062 thyper.LowPart = CM_DIR_CHUNKSIZE * numDirChunks;
4063 curOffset = LargeIntegerAdd(thyper, curOffset);
4064 } /* while copying data for dir listing */
4066 /* If we didn't get a star pattern, we did an exact match during the first pass.
4067 * If there were no exact matches found, we fail over to inexact matches by
4068 * marking the query as a star pattern (matches all case permutations), and
4069 * re-running the query.
4071 if (returnedNames == 0 && !starPattern && foundInexact) {
4072 osi_Log0(afsd_logp,"T2 Search: No exact matches. Re-running for inexact matches");
4077 /* release the mutex */
4078 lock_ReleaseMutex(&scp->mx);
4079 if (bufferp) buf_Release(bufferp);
4081 /* apply and free last set of patches; if not doing a star match, this
4082 * will be empty, but better safe (and freeing everything) than sorry.
4084 smb_ApplyV3DirListPatches(scp, &dirListPatchesp, infoLevel, userp,
4087 /* now put out the final parameters */
4088 if (returnedNames == 0) eos = 1;
4089 if (p->opcode == 1) {
4091 outp->parmsp[0] = (unsigned short) dsp->cookie;
4092 outp->parmsp[1] = returnedNames;
4093 outp->parmsp[2] = eos;
4094 outp->parmsp[3] = 0; /* nothing wrong with EAS */
4095 outp->parmsp[4] = 0;
4096 /* don't need last name to continue
4097 * search, cookie is enough. Normally,
4098 * this is the offset of the file name
4099 * of the last entry returned.
4101 outp->totalParms = 10; /* in bytes */
4105 outp->parmsp[0] = returnedNames;
4106 outp->parmsp[1] = eos;
4107 outp->parmsp[2] = 0; /* EAS error */
4108 outp->parmsp[3] = 0; /* last name, as above */
4109 outp->totalParms = 8; /* in bytes */
4112 /* return # of bytes in the buffer */
4113 outp->totalData = bytesInBuffer;
4115 osi_Log2(smb_logp, "T2 search dir done, %d names, code %d",
4116 returnedNames, code);
4118 /* Return error code if unsuccessful on first request */
4119 if (code == 0 && p->opcode == 1 && returnedNames == 0)
4120 code = CM_ERROR_NOSUCHFILE;
4122 /* if we're supposed to close the search after this request, or if
4123 * we're supposed to close the search if we're done, and we're done,
4124 * or if something went wrong, close the search.
4126 /* ((searchFlags & 1) || ((searchFlags & 2) && eos) */
4127 if ((searchFlags & 1) || (returnedNames == 0) ||
4128 ((searchFlags & 2) && eos) || code != 0)
4129 smb_DeleteDirSearch(dsp);
4131 smb_SendTran2Error(vcp, p, opx, code);
4133 smb_SendTran2Packet(vcp, outp, opx);
4135 smb_FreeTran2Packet(outp);
4136 smb_ReleaseDirSearch(dsp);
4137 cm_ReleaseSCache(scp);
4138 cm_ReleaseUser(userp);
4142 long smb_ReceiveV3FindClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4145 smb_dirSearch_t *dsp;
4147 dirHandle = smb_GetSMBParm(inp, 0);
4149 osi_Log1(smb_logp, "SMB3 find close handle %d", dirHandle);
4151 dsp = smb_FindDirSearch(dirHandle);
4154 return CM_ERROR_BADFD;
4156 /* otherwise, we have an FD to destroy */
4157 smb_DeleteDirSearch(dsp);
4158 smb_ReleaseDirSearch(dsp);
4160 /* and return results */
4161 smb_SetSMBDataLength(outp, 0);
4166 long smb_ReceiveV3FindNotifyClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4168 smb_SetSMBDataLength(outp, 0);
4172 long smb_ReceiveV3OpenX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4179 cm_scache_t *dscp; /* dir we're dealing with */
4180 cm_scache_t *scp; /* file we're creating */
4182 int initialModeBits;
4192 int parmSlot; /* which parm we're dealing with */
4200 extraInfo = (smb_GetSMBParm(inp, 2) & 1); /* return extra info */
4201 openFun = smb_GetSMBParm(inp, 8); /* open function */
4202 excl = ((openFun & 3) == 0);
4203 trunc = ((openFun & 3) == 2); /* truncate it */
4204 openMode = (smb_GetSMBParm(inp, 3) & 0x7);
4205 openAction = 0; /* tracks what we did */
4207 attributes = smb_GetSMBParm(inp, 5);
4208 dosTime = smb_GetSMBParm(inp, 6) | (smb_GetSMBParm(inp, 7) << 16);
4210 /* compute initial mode bits based on read-only flag in attributes */
4211 initialModeBits = 0666;
4212 if (attributes & 1) initialModeBits &= ~0222;
4214 pathp = smb_GetSMBData(inp, NULL);
4216 spacep = inp->spacep;
4217 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
4219 if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
4220 /* special case magic file name for receiving IOCTL requests
4221 * (since IOCTL calls themselves aren't getting through).
4224 osi_Log0(smb_logp, "IOCTL Open");
4227 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
4228 smb_SetupIoctlFid(fidp, spacep);
4230 /* set inp->fid so that later read calls in same msg can find fid */
4231 inp->fid = fidp->fid;
4233 /* copy out remainder of the parms */
4235 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
4237 smb_SetSMBParm(outp, parmSlot, /* attrs */ 0); parmSlot++;
4238 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* mod time */
4239 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
4240 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* len */
4241 smb_SetSMBParm(outp, parmSlot, 0x7fff); parmSlot++;
4242 smb_SetSMBParm(outp, parmSlot, openMode); parmSlot++;
4243 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* file type 0 ==> normal file or dir */
4244 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* IPC junk */
4246 /* and the final "always present" stuff */
4247 smb_SetSMBParm(outp, parmSlot, /* openAction found existing file */ 1); parmSlot++;
4248 /* next write out the "unique" ID */
4249 smb_SetSMBParm(outp, parmSlot, 0x1234); parmSlot++;
4250 smb_SetSMBParm(outp, parmSlot, 0x5678); parmSlot++;
4251 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
4252 smb_SetSMBDataLength(outp, 0);
4254 /* and clean up fid reference */
4255 smb_ReleaseFID(fidp);
4259 #ifdef DEBUG_VERBOSE
4261 char *hexp, *asciip;
4262 asciip = (lastNamep ? lastNamep : pathp );
4263 hexp = osi_HexifyString(asciip);
4264 DEBUG_EVENT2("AFS", "V3Open H[%s] A[%s]", hexp, asciip );
4268 userp = smb_GetUser(vcp, inp);
4271 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4273 cm_ReleaseUser(userp);
4274 return CM_ERROR_NOSUCHPATH;
4276 code = cm_NameI(cm_rootSCachep, pathp,
4277 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
4278 userp, tidPathp, &req, &scp);
4280 code = cm_NameI(cm_rootSCachep, spacep->data,
4281 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
4282 userp, tidPathp, &req, &dscp);
4285 cm_ReleaseUser(userp);
4289 /* otherwise, scp points to the parent directory. Do a lookup,
4290 * and truncate the file if we find it, otherwise we create the
4293 if (!lastNamep) lastNamep = pathp;
4295 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD, userp,
4297 if (code && code != CM_ERROR_NOSUCHFILE) {
4298 cm_ReleaseSCache(dscp);
4299 cm_ReleaseUser(userp);
4304 /* if we get here, if code is 0, the file exists and is represented by
4305 * scp. Otherwise, we have to create it. The dir may be represented
4306 * by dscp, or we may have found the file directly. If code is non-zero,
4310 code = cm_CheckOpen(scp, openMode, trunc, userp, &req);
4312 if (dscp) cm_ReleaseSCache(dscp);
4313 cm_ReleaseSCache(scp);
4314 cm_ReleaseUser(userp);
4319 /* oops, file shouldn't be there */
4320 if (dscp) cm_ReleaseSCache(dscp);
4321 cm_ReleaseSCache(scp);
4322 cm_ReleaseUser(userp);
4323 return CM_ERROR_EXISTS;
4327 setAttr.mask = CM_ATTRMASK_LENGTH;
4328 setAttr.length.LowPart = 0;
4329 setAttr.length.HighPart = 0;
4330 code = cm_SetAttr(scp, &setAttr, userp, &req);
4331 openAction = 3; /* truncated existing file */
4333 else openAction = 1; /* found existing file */
4335 else if (!(openFun & 0x10)) {
4336 /* don't create if not found */
4337 if (dscp) cm_ReleaseSCache(dscp);
4338 cm_ReleaseUser(userp);
4339 return CM_ERROR_NOSUCHFILE;
4342 osi_assert(dscp != NULL);
4343 osi_Log1(smb_logp, "smb_ReceiveV3OpenX creating file %s",
4344 osi_LogSaveString(smb_logp, lastNamep));
4345 openAction = 2; /* created file */
4346 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
4347 smb_UnixTimeFromDosUTime(&setAttr.clientModTime, dosTime);
4348 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
4350 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
4351 smb_NotifyChange(FILE_ACTION_ADDED,
4352 FILE_NOTIFY_CHANGE_FILE_NAME,
4353 dscp, lastNamep, NULL, TRUE);
4354 if (!excl && code == CM_ERROR_EXISTS) {
4355 /* not an exclusive create, and someone else tried
4356 * creating it already, then we open it anyway. We
4357 * don't bother retrying after this, since if this next
4358 * fails, that means that the file was deleted after we
4359 * started this call.
4361 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
4365 setAttr.mask = CM_ATTRMASK_LENGTH;
4366 setAttr.length.LowPart = 0;
4367 setAttr.length.HighPart = 0;
4368 code = cm_SetAttr(scp, &setAttr, userp, &req);
4370 } /* lookup succeeded */
4374 /* we don't need this any longer */
4375 if (dscp) cm_ReleaseSCache(dscp);
4378 /* something went wrong creating or truncating the file */
4379 if (scp) cm_ReleaseSCache(scp);
4380 cm_ReleaseUser(userp);
4384 /* make sure we're about to open a file */
4385 if (scp->fileType != CM_SCACHETYPE_FILE) {
4386 cm_ReleaseSCache(scp);
4387 cm_ReleaseUser(userp);
4388 return CM_ERROR_ISDIR;
4391 /* now all we have to do is open the file itself */
4392 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
4395 /* save a pointer to the vnode */
4398 /* compute open mode */
4399 if (openMode != 1) fidp->flags |= SMB_FID_OPENREAD;
4400 if (openMode == 1 || openMode == 2)
4401 fidp->flags |= SMB_FID_OPENWRITE;
4403 smb_ReleaseFID(fidp);
4405 cm_Open(scp, 0, userp);
4407 /* set inp->fid so that later read calls in same msg can find fid */
4408 inp->fid = fidp->fid;
4410 /* copy out remainder of the parms */
4412 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
4413 lock_ObtainMutex(&scp->mx);
4415 smb_SetSMBParm(outp, parmSlot, smb_Attributes(scp)); parmSlot++;
4416 smb_DosUTimeFromUnixTime(&dosTime, scp->clientModTime);
4417 smb_SetSMBParm(outp, parmSlot, dosTime & 0xffff); parmSlot++;
4418 smb_SetSMBParm(outp, parmSlot, (dosTime>>16) & 0xffff); parmSlot++;
4419 smb_SetSMBParm(outp, parmSlot, scp->length.LowPart & 0xffff); parmSlot++;
4420 smb_SetSMBParm(outp, parmSlot, (scp->length.LowPart >> 16) & 0xffff); parmSlot++;
4421 smb_SetSMBParm(outp, parmSlot, openMode); parmSlot++;
4422 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* file type 0 ==> normal file or dir */
4423 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* IPC junk */
4425 /* and the final "always present" stuff */
4426 smb_SetSMBParm(outp, parmSlot, openAction); parmSlot++;
4427 /* next write out the "unique" ID */
4428 smb_SetSMBParm(outp, parmSlot, scp->fid.vnode & 0xffff); parmSlot++;
4429 smb_SetSMBParm(outp, parmSlot, scp->fid.volume & 0xffff); parmSlot++;
4430 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
4431 lock_ReleaseMutex(&scp->mx);
4432 smb_SetSMBDataLength(outp, 0);
4434 osi_Log1(smb_logp, "SMB OpenX opening fid %d", fidp->fid);
4436 cm_ReleaseUser(userp);
4437 /* leave scp held since we put it in fidp->scp */
4441 long smb_ReceiveV3LockingX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4448 unsigned char LockType;
4449 unsigned short NumberOfUnlocks, NumberOfLocks;
4450 unsigned long Timeout;
4452 LARGE_INTEGER LOffset, LLength;
4453 smb_waitingLock_t *waitingLock;
4460 fid = smb_GetSMBParm(inp, 2);
4461 fid = smb_ChainFID(fid, inp);
4463 fidp = smb_FindFID(vcp, fid, 0);
4464 if (!fidp || (fidp->flags & SMB_FID_IOCTL)) {
4465 return CM_ERROR_BADFD;
4467 /* set inp->fid so that later read calls in same msg can find fid */
4470 userp = smb_GetUser(vcp, inp);
4474 lock_ObtainMutex(&scp->mx);
4475 code = cm_SyncOp(scp, NULL, userp, &req, 0,
4476 CM_SCACHESYNC_NEEDCALLBACK
4477 | CM_SCACHESYNC_GETSTATUS
4478 | CM_SCACHESYNC_LOCK);
4479 if (code) goto doneSync;
4481 LockType = smb_GetSMBParm(inp, 3) & 0xff;
4482 Timeout = (smb_GetSMBParm(inp, 5) << 16) + smb_GetSMBParm(inp, 4);
4483 NumberOfUnlocks = smb_GetSMBParm(inp, 6);
4484 NumberOfLocks = smb_GetSMBParm(inp, 7);
4486 op = smb_GetSMBData(inp, NULL);
4488 for (i=0; i<NumberOfUnlocks; i++) {
4489 if (LockType & 0x10) {
4491 LOffset.HighPart = *((LONG *)(op + 4));
4492 LOffset.LowPart = *((DWORD *)(op + 8));
4493 LLength.HighPart = *((LONG *)(op + 12));
4494 LLength.LowPart = *((DWORD *)(op + 16));
4498 /* Not Large Files */
4499 LOffset.HighPart = 0;
4500 LOffset.LowPart = *((DWORD *)(op + 2));
4501 LLength.HighPart = 0;
4502 LLength.LowPart = *((DWORD *)(op + 6));
4505 if (LargeIntegerNotEqualToZero(LOffset))
4507 /* Do not check length -- length check done in cm_Unlock */
4509 code = cm_Unlock(scp, LockType, LOffset, LLength, userp, &req);
4510 if (code) goto done;
4513 for (i=0; i<NumberOfLocks; i++) {
4514 if (LockType & 0x10) {
4516 LOffset.HighPart = *((LONG *)(op + 4));
4517 LOffset.LowPart = *((DWORD *)(op + 8));
4518 LLength.HighPart = *((LONG *)(op + 12));
4519 LLength.LowPart = *((DWORD *)(op + 16));
4523 /* Not Large Files */
4524 LOffset.HighPart = 0;
4525 LOffset.LowPart = *((DWORD *)(op + 2));
4526 LLength.HighPart = 0;
4527 LLength.LowPart = *((DWORD *)(op + 6));
4530 if (LargeIntegerNotEqualToZero(LOffset))
4532 if (LargeIntegerLessThan(LOffset, scp->length))
4535 code = cm_Lock(scp, LockType, LOffset, LLength, Timeout,
4536 userp, &req, &lockp);
4537 if (code == CM_ERROR_WOULDBLOCK && Timeout != 0) {
4538 /* Put on waiting list */
4539 waitingLock = malloc(sizeof(smb_waitingLock_t));
4540 waitingLock->vcp = vcp;
4541 waitingLock->inp = smb_CopyPacket(inp);
4542 waitingLock->outp = smb_CopyPacket(outp);
4543 waitingLock->timeRemaining = Timeout;
4544 waitingLock->lockp = lockp;
4545 lock_ObtainWrite(&smb_globalLock);
4546 osi_QAdd((osi_queue_t **)&smb_allWaitingLocks,
4548 osi_Wakeup((long) &smb_allWaitingLocks);
4549 lock_ReleaseWrite(&smb_globalLock);
4550 /* don't send reply immediately */
4551 outp->flags |= SMB_PACKETFLAG_NOSEND;
4557 /* release any locks acquired before the failure */
4560 smb_SetSMBDataLength(outp, 0);
4562 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_LOCK);
4564 lock_ReleaseMutex(&scp->mx);
4565 cm_ReleaseUser(userp);
4566 smb_ReleaseFID(fidp);
4571 long smb_ReceiveV3GetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4583 fid = smb_GetSMBParm(inp, 0);
4584 fid = smb_ChainFID(fid, inp);
4586 fidp = smb_FindFID(vcp, fid, 0);
4587 if (!fidp || (fidp->flags & SMB_FID_IOCTL)) {
4588 return CM_ERROR_BADFD;
4591 userp = smb_GetUser(vcp, inp);
4595 /* otherwise, stat the file */
4596 lock_ObtainMutex(&scp->mx);
4597 code = cm_SyncOp(scp, NULL, userp, &req, 0,
4598 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4599 if (code) goto done;
4601 /* decode times. We need a search time, but the response to this
4602 * call provides the date first, not the time, as returned in the
4603 * searchTime variable. So we take the high-order bits first.
4605 smb_SearchTimeFromUnixTime(&searchTime, scp->clientModTime);
4606 smb_SetSMBParm(outp, 0, (searchTime >> 16) & 0xffff); /* ctime */
4607 smb_SetSMBParm(outp, 1, searchTime & 0xffff);
4608 smb_SetSMBParm(outp, 2, (searchTime >> 16) & 0xffff); /* atime */
4609 smb_SetSMBParm(outp, 3, searchTime & 0xffff);
4610 smb_SetSMBParm(outp, 4, (searchTime >> 16) & 0xffff); /* mtime */
4611 smb_SetSMBParm(outp, 5, searchTime & 0xffff);
4613 /* now handle file size and allocation size */
4614 smb_SetSMBParm(outp, 6, scp->length.LowPart & 0xffff); /* file size */
4615 smb_SetSMBParm(outp, 7, (scp->length.LowPart >> 16) & 0xffff);
4616 smb_SetSMBParm(outp, 8, scp->length.LowPart & 0xffff); /* alloc size */
4617 smb_SetSMBParm(outp, 9, (scp->length.LowPart >> 16) & 0xffff);
4619 /* file attribute */
4620 smb_SetSMBParm(outp, 10, smb_Attributes(scp));
4622 /* and finalize stuff */
4623 smb_SetSMBDataLength(outp, 0);
4627 lock_ReleaseMutex(&scp->mx);
4628 cm_ReleaseUser(userp);
4629 smb_ReleaseFID(fidp);
4633 long smb_ReceiveV3SetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4647 fid = smb_GetSMBParm(inp, 0);
4648 fid = smb_ChainFID(fid, inp);
4650 fidp = smb_FindFID(vcp, fid, 0);
4651 if (!fidp || (fidp->flags & SMB_FID_IOCTL)) {
4652 return CM_ERROR_BADFD;
4655 userp = smb_GetUser(vcp, inp);
4659 /* now prepare to call cm_setattr. This message only sets various times,
4660 * and AFS only implements mtime, and we'll set the mtime if that's
4661 * requested. The others we'll ignore.
4663 searchTime = smb_GetSMBParm(inp, 5) | (smb_GetSMBParm(inp, 6) << 16);
4665 if (searchTime != 0) {
4666 smb_UnixTimeFromSearchTime(&unixTime, searchTime);
4668 if ( unixTime != -1 ) {
4669 attrs.mask = CM_ATTRMASK_CLIENTMODTIME;
4670 attrs.clientModTime = unixTime;
4671 code = cm_SetAttr(scp, &attrs, userp, &req);
4673 osi_Log1(smb_logp, "SMB receive V3SetAttributes [fid=%ld]", fid);
4675 osi_Log1(smb_logp, "**smb_UnixTimeFromSearchTime failed searchTime=%ld", searchTime);
4680 cm_ReleaseUser(userp);
4681 smb_ReleaseFID(fidp);
4686 long smb_ReceiveV3ReadX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4689 long count, finalCount;
4696 fd = smb_GetSMBParm(inp, 2);
4697 count = smb_GetSMBParm(inp, 5);
4698 offset.HighPart = 0; /* too bad */
4699 offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
4701 osi_Log3(smb_logp, "smb_ReceiveV3Read fd %d, off 0x%x, size 0x%x",
4702 fd, offset.LowPart, count);
4704 fd = smb_ChainFID(fd, inp);
4705 fidp = smb_FindFID(vcp, fd, 0);
4707 return CM_ERROR_BADFD;
4709 /* set inp->fid so that later read calls in same msg can find fid */
4712 if (fidp->flags & SMB_FID_IOCTL) {
4713 return smb_IoctlV3Read(fidp, vcp, inp, outp);
4716 userp = smb_GetUser(vcp, inp);
4718 /* 0 and 1 are reserved for request chaining, were setup by our caller,
4719 * and will be further filled in after we return.
4721 smb_SetSMBParm(outp, 2, 0); /* remaining bytes, for pipes */
4722 smb_SetSMBParm(outp, 3, 0); /* resvd */
4723 smb_SetSMBParm(outp, 4, 0); /* resvd */
4724 smb_SetSMBParm(outp, 5, count); /* # of bytes we're going to read */
4725 /* fill in #6 when we have all the parameters' space reserved */
4726 smb_SetSMBParm(outp, 7, 0); /* resv'd */
4727 smb_SetSMBParm(outp, 8, 0); /* resv'd */
4728 smb_SetSMBParm(outp, 9, 0); /* resv'd */
4729 smb_SetSMBParm(outp, 10, 0); /* resv'd */
4730 smb_SetSMBParm(outp, 11, 0); /* reserved */
4732 /* get op ptr after putting in the parms, since otherwise we don't
4733 * know where the data really is.
4735 op = smb_GetSMBData(outp, NULL);
4737 /* now fill in offset from start of SMB header to first data byte (to op) */
4738 smb_SetSMBParm(outp, 6, ((int) (op - outp->data)));
4740 /* set the packet data length the count of the # of bytes */
4741 smb_SetSMBDataLength(outp, count);
4744 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount);
4746 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount, FALSE);
4749 /* fix some things up */
4750 smb_SetSMBParm(outp, 5, finalCount);
4751 smb_SetSMBDataLength(outp, finalCount);
4753 smb_ReleaseFID(fidp);
4755 cm_ReleaseUser(userp);
4760 * Values for createDisp, copied from NTDDK.H
4762 #define FILE_SUPERSEDE 0 // (???)
4763 #define FILE_OPEN 1 // (open)
4764 #define FILE_CREATE 2 // (exclusive)
4765 #define FILE_OPEN_IF 3 // (non-exclusive)
4766 #define FILE_OVERWRITE 4 // (open & truncate, but do not create)
4767 #define FILE_OVERWRITE_IF 5 // (open & truncate, or create)
4769 long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4771 char *pathp, *realPathp;
4775 cm_scache_t *dscp; /* parent dir */
4776 cm_scache_t *scp; /* file to create or open */
4777 cm_scache_t *targetScp; /* if scp is a symlink */
4781 unsigned short nameLength;
4783 unsigned int requestOpLock;
4784 unsigned int requestBatchOpLock;
4785 unsigned int mustBeDir;
4786 unsigned int treeCreate;
4788 unsigned int desiredAccess;
4789 unsigned int extAttributes;
4790 unsigned int createDisp;
4791 unsigned int createOptions;
4792 int initialModeBits;
4793 unsigned short baseFid;
4794 smb_fid_t *baseFidp;
4796 cm_scache_t *baseDirp;
4797 unsigned short openAction;
4812 nameLength = smb_GetSMBOffsetParm(inp, 2, 1);
4813 flags = smb_GetSMBOffsetParm(inp, 3, 1)
4814 | (smb_GetSMBOffsetParm(inp, 4, 1) << 16);
4815 requestOpLock = flags & 0x02;
4816 requestBatchOpLock = flags & 0x04;
4817 mustBeDir = flags & 0x08;
4820 * Why all of a sudden 32-bit FID?
4821 * We will reject all bits higher than 16.
4823 if (smb_GetSMBOffsetParm(inp, 6, 1) != 0)
4824 return CM_ERROR_INVAL;
4825 baseFid = smb_GetSMBOffsetParm(inp, 5, 1);
4826 desiredAccess = smb_GetSMBOffsetParm(inp, 7, 1)
4827 | (smb_GetSMBOffsetParm(inp, 8, 1) << 16);
4828 extAttributes = smb_GetSMBOffsetParm(inp, 13, 1)
4829 | (smb_GetSMBOffsetParm(inp, 14, 1) << 16);
4830 createDisp = smb_GetSMBOffsetParm(inp, 17, 1)
4831 | (smb_GetSMBOffsetParm(inp, 18, 1) << 16);
4832 createOptions = smb_GetSMBOffsetParm(inp, 19, 1)
4833 | (smb_GetSMBOffsetParm(inp, 20, 1) << 16);
4835 /* mustBeDir is never set; createOptions directory bit seems to be
4838 if (createOptions & 1)
4840 else if (createOptions & 0x40)
4846 * compute initial mode bits based on read-only flag in
4847 * extended attributes
4849 initialModeBits = 0666;
4850 if (extAttributes & 1)
4851 initialModeBits &= ~0222;
4853 pathp = smb_GetSMBData(inp, NULL);
4854 /* Sometimes path is not null-terminated, so we make a copy. */
4855 realPathp = malloc(nameLength+1);
4856 memcpy(realPathp, pathp, nameLength);
4857 realPathp[nameLength] = 0;
4859 spacep = inp->spacep;
4860 smb_StripLastComponent(spacep->data, &lastNamep, realPathp);
4862 osi_Log1(smb_logp,"NTCreateX for [%s]",osi_LogSaveString(smb_logp,realPathp));
4863 osi_Log4(smb_logp,"... da=[%x] ea=[%x] cd=[%x] co=[%x]", desiredAccess, extAttributes, createDisp, createOptions);
4864 osi_Log2(smb_logp,"... flags=[%x] lastNamep=[%s]", flags, osi_LogSaveString(smb_logp,(lastNamep?lastNamep:"null")));
4866 if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
4867 /* special case magic file name for receiving IOCTL requests
4868 * (since IOCTL calls themselves aren't getting through).
4870 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
4871 smb_SetupIoctlFid(fidp, spacep);
4872 osi_Log1(smb_logp,"NTCreateX Setting up IOCTL on fid[%d]",fidp->fid);
4874 /* set inp->fid so that later read calls in same msg can find fid */
4875 inp->fid = fidp->fid;
4879 smb_SetSMBParmByte(outp, parmSlot, 0); /* oplock */
4880 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
4881 smb_SetSMBParmLong(outp, parmSlot, 1); parmSlot += 2; /* Action */
4883 memset(&ft, 0, sizeof(ft));
4884 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
4885 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
4886 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
4887 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
4888 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2; /* attr */
4889 sz.HighPart = 0x7fff; sz.LowPart = 0;
4890 smb_SetSMBParmDouble(outp, parmSlot, (char *)&sz); parmSlot += 4; /* alen */
4891 smb_SetSMBParmDouble(outp, parmSlot, (char *)&sz); parmSlot += 4; /* len */
4892 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* filetype */
4893 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* dev state */
4894 smb_SetSMBParmByte(outp, parmSlot, 0); /* is a dir? */
4895 smb_SetSMBDataLength(outp, 0);
4897 /* clean up fid reference */
4898 smb_ReleaseFID(fidp);
4903 #ifdef DEBUG_VERBOSE
4905 char *hexp, *asciip;
4906 asciip = (lastNamep? lastNamep : realPathp);
4907 hexp = osi_HexifyString( asciip );
4908 DEBUG_EVENT2("AFS", "NTCreateX H[%s] A[%s]", hexp, asciip);
4912 userp = smb_GetUser(vcp, inp);
4914 osi_Log1(smb_logp, "NTCreateX Invalid user [%d]", ((smb_t *) inp)->uid);
4916 return CM_ERROR_INVAL;
4920 baseDirp = cm_rootSCachep;
4921 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4922 if (code == CM_ERROR_TIDIPC) {
4923 /* Attempt to use a TID allocated for IPC. The client
4924 * is probably looking for DCE RPC end points which we
4926 osi_Log0(smb_logp, "NTCreateX received IPC TID");
4928 cm_ReleaseUser(userp);
4929 return CM_ERROR_NOSUCHFILE;
4933 baseFidp = smb_FindFID(vcp, baseFid, 0);
4935 osi_Log1(smb_logp, "NTCreateX Invalid base fid [%d]", baseFid);
4937 cm_ReleaseUser(userp);
4938 return CM_ERROR_INVAL;
4940 baseDirp = baseFidp->scp;
4944 osi_Log1(smb_logp, "NTCreateX tidPathp=[%s]", (tidPathp==NULL)?"null": osi_LogSaveString(smb_logp,tidPathp));
4946 /* compute open mode */
4948 if (desiredAccess & DELETE)
4949 fidflags |= SMB_FID_OPENDELETE;
4950 if (desiredAccess & AFS_ACCESS_READ)
4951 fidflags |= SMB_FID_OPENREAD;
4952 if (desiredAccess & AFS_ACCESS_WRITE)
4953 fidflags |= SMB_FID_OPENWRITE;
4957 /* For an exclusive create, we want to do a case sensitive match for the last component. */
4958 if ( createDisp == FILE_CREATE ||
4959 createDisp == FILE_OVERWRITE ||
4960 createDisp == FILE_OVERWRITE_IF) {
4961 code = cm_NameI(baseDirp, spacep->data, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
4962 userp, tidPathp, &req, &dscp);
4964 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp, CM_FLAG_FOLLOW,
4966 if (code == CM_ERROR_NOSUCHFILE) {
4967 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp,
4968 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, &req, &scp);
4969 if (code == 0 && realDirFlag == 1) {
4970 cm_ReleaseSCache(scp);
4971 cm_ReleaseSCache(dscp);
4972 cm_ReleaseUser(userp);
4974 return CM_ERROR_EXISTS;
4980 code = cm_NameI(baseDirp, realPathp, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
4981 userp, tidPathp, &req, &scp);
4986 if (!foundscp || (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE))) {
4987 /* look up parent directory */
4988 /* If we are trying to create a path (i.e. multiple nested directories), then we don't *need*
4989 * the immediate parent. We have to work our way up realPathp until we hit something that we
4997 code = cm_NameI(baseDirp, spacep->data,
4998 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
4999 userp, tidPathp, &req, &dscp);
5002 (tp = strrchr(spacep->data,'\\')) &&
5003 (createDisp == FILE_CREATE) &&
5004 (realDirFlag == 1)) {
5007 treeStartp = realPathp + (tp - spacep->data);
5009 if (*tp && !smb_IsLegalFilename(tp)) {
5011 smb_ReleaseFID(baseFidp);
5012 cm_ReleaseUser(userp);
5014 return CM_ERROR_BADNTFILENAME;
5024 smb_ReleaseFID(baseFidp);
5027 osi_Log0(smb_logp,"NTCreateX parent not found");
5028 cm_ReleaseUser(userp);
5033 if (treeCreate && dscp->fileType == CM_SCACHETYPE_FILE) {
5034 /* A file exists where we want a directory. */
5035 cm_ReleaseSCache(dscp);
5036 cm_ReleaseUser(userp);
5038 return CM_ERROR_EXISTS;
5042 lastNamep = realPathp;
5046 if (!smb_IsLegalFilename(lastNamep)) {
5047 cm_ReleaseSCache(dscp);
5048 cm_ReleaseUser(userp);
5050 return CM_ERROR_BADNTFILENAME;
5053 if (!foundscp && !treeCreate) {
5054 if ( createDisp == FILE_CREATE ||
5055 createDisp == FILE_OVERWRITE ||
5056 createDisp == FILE_OVERWRITE_IF)
5058 code = cm_Lookup(dscp, lastNamep,
5059 CM_FLAG_FOLLOW, userp, &req, &scp);
5061 code = cm_Lookup(dscp, lastNamep,
5062 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
5065 if (code && code != CM_ERROR_NOSUCHFILE) {
5066 cm_ReleaseSCache(dscp);
5067 cm_ReleaseUser(userp);
5075 smb_ReleaseFID(baseFidp);
5078 /* if we get here, if code is 0, the file exists and is represented by
5079 * scp. Otherwise, we have to create it. The dir may be represented
5080 * by dscp, or we may have found the file directly. If code is non-zero,
5083 if (code == 0 && !treeCreate) {
5084 if (createDisp == FILE_CREATE) {
5085 /* oops, file shouldn't be there */
5086 if (dscp) cm_ReleaseSCache(dscp);
5087 cm_ReleaseSCache(scp);
5088 cm_ReleaseUser(userp);
5090 return CM_ERROR_EXISTS;
5093 if ( createDisp == FILE_OVERWRITE ||
5094 createDisp == FILE_OVERWRITE_IF) {
5095 setAttr.mask = CM_ATTRMASK_LENGTH;
5096 setAttr.length.LowPart = 0;
5097 setAttr.length.HighPart = 0;
5098 /* now watch for a symlink */
5100 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
5102 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
5104 /* we have a more accurate file to use (the
5105 * target of the symbolic link). Otherwise,
5106 * we'll just use the symlink anyway.
5108 osi_Log2(smb_logp, "symlink vp %x to vp %x",
5110 cm_ReleaseSCache(scp);
5114 code = cm_SetAttr(scp, &setAttr, userp, &req);
5115 openAction = 3; /* truncated existing file */
5118 openAction = 1; /* found existing file */
5120 code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp,
5123 if (dscp) cm_ReleaseSCache(dscp);
5124 cm_ReleaseSCache(scp);
5125 cm_ReleaseUser(userp);
5130 else if (createDisp == FILE_OPEN || createDisp == FILE_OVERWRITE) {
5131 /* don't create if not found */
5132 if (dscp) cm_ReleaseSCache(dscp);
5133 cm_ReleaseUser(userp);
5135 return CM_ERROR_NOSUCHFILE;
5137 else if (realDirFlag == 0 || realDirFlag == -1) {
5138 osi_assert(dscp != NULL);
5139 osi_Log1(smb_logp, "smb_ReceiveNTCreateX creating file %s",
5140 osi_LogSaveString(smb_logp, lastNamep));
5141 openAction = 2; /* created file */
5142 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
5143 setAttr.clientModTime = time(NULL);
5144 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
5146 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
5147 smb_NotifyChange(FILE_ACTION_ADDED,
5148 FILE_NOTIFY_CHANGE_FILE_NAME,
5149 dscp, lastNamep, NULL, TRUE);
5150 if (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE) {
5151 /* Not an exclusive create, and someone else tried
5152 * creating it already, then we open it anyway. We
5153 * don't bother retrying after this, since if this next
5154 * fails, that means that the file was deleted after we
5155 * started this call.
5157 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
5160 if (createDisp == FILE_OVERWRITE_IF) {
5161 setAttr.mask = CM_ATTRMASK_LENGTH;
5162 setAttr.length.LowPart = 0;
5163 setAttr.length.HighPart = 0;
5165 /* now watch for a symlink */
5167 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
5169 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
5171 /* we have a more accurate file to use (the
5172 * target of the symbolic link). Otherwise,
5173 * we'll just use the symlink anyway.
5175 osi_Log2(smb_logp, "symlink vp %x to vp %x",
5177 cm_ReleaseSCache(scp);
5181 code = cm_SetAttr(scp, &setAttr, userp, &req);
5183 } /* lookup succeeded */
5188 char *cp; /* This component */
5189 int clen = 0; /* length of component */
5193 /* create directory */
5195 treeStartp = lastNamep;
5196 osi_assert(dscp != NULL);
5197 osi_Log1(smb_logp, "smb_ReceiveNTCreateX creating directory [%s]",
5198 osi_LogSaveString(smb_logp, treeStartp));
5199 openAction = 2; /* created directory */
5201 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
5202 setAttr.clientModTime = time(NULL);
5209 tp = strchr(pp, '\\');
5213 isLast = 1; /* indicate last component. the supplied path never ends in a slash */
5217 strncpy(cp,pp,clen);
5224 continue; /* the supplied path can't have consecutive slashes either , but */
5226 /* cp is the next component to be created. */
5227 code = cm_MakeDir(tscp, cp, 0, &setAttr, userp, &req);
5228 if (code == 0 && (tscp->flags & CM_SCACHEFLAG_ANYWATCH))
5229 smb_NotifyChange(FILE_ACTION_ADDED,
5230 FILE_NOTIFY_CHANGE_DIR_NAME,
5231 tscp, cp, NULL, TRUE);
5233 (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE)) {
5234 /* Not an exclusive create, and someone else tried
5235 * creating it already, then we open it anyway. We
5236 * don't bother retrying after this, since if this next
5237 * fails, that means that the file was deleted after we
5238 * started this call.
5240 code = cm_Lookup(tscp, cp, CM_FLAG_CASEFOLD,
5245 if (!isLast) { /* for anything other than dscp, release it unless it's the last one */
5246 cm_ReleaseSCache(tscp);
5247 tscp = scp; /* Newly created directory will be next parent */
5252 * if we get here and code == 0, then scp is the last directory created, and tscp is the
5253 * parent of scp. dscp got released if dscp != tscp. both tscp and scp are held.
5259 /* something went wrong creating or truncating the file */
5260 if (scp) cm_ReleaseSCache(scp);
5261 if (dscp) cm_ReleaseSCache(dscp);
5262 cm_ReleaseUser(userp);
5267 /* make sure we have file vs. dir right (only applies for single component case) */
5268 if (realDirFlag == 0 && scp->fileType != CM_SCACHETYPE_FILE) {
5269 /* now watch for a symlink */
5271 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
5272 cm_scache_t * targetScp = 0;
5273 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
5275 /* we have a more accurate file to use (the
5276 * target of the symbolic link). Otherwise,
5277 * we'll just use the symlink anyway.
5279 osi_Log2(smb_logp, "symlink vp %x to vp %x",
5281 cm_ReleaseSCache(scp);
5286 if (scp->fileType != CM_SCACHETYPE_FILE) {
5287 cm_ReleaseSCache(scp);
5288 cm_ReleaseUser(userp);
5290 return CM_ERROR_ISDIR;
5294 /* (only applies to single component case) */
5295 if (realDirFlag == 1 && scp->fileType == CM_SCACHETYPE_FILE) {
5296 cm_ReleaseSCache(scp);
5297 if (dscp) cm_ReleaseSCache(dscp);
5298 cm_ReleaseUser(userp);
5300 return CM_ERROR_NOTDIR;
5303 /* open the file itself */
5304 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
5306 /* save a pointer to the vnode */
5309 fidp->flags = fidflags;
5311 /* save parent dir and pathname for delete or change notification */
5312 if (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE)) {
5313 fidp->flags |= SMB_FID_NTOPEN;
5314 fidp->NTopen_dscp = dscp;
5315 cm_HoldSCache(dscp);
5316 fidp->NTopen_pathp = strdup(lastNamep);
5318 fidp->NTopen_wholepathp = realPathp;
5320 /* we don't need this any longer */
5321 if (dscp) cm_ReleaseSCache(dscp);
5322 cm_Open(scp, 0, userp);
5324 /* set inp->fid so that later read calls in same msg can find fid */
5325 inp->fid = fidp->fid;
5329 lock_ObtainMutex(&scp->mx);
5330 smb_SetSMBParmByte(outp, parmSlot, 0); /* oplock */
5331 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
5332 smb_SetSMBParmLong(outp, parmSlot, openAction); parmSlot += 2;
5333 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
5334 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
5335 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
5336 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
5337 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
5338 smb_SetSMBParmLong(outp, parmSlot, smb_ExtAttributes(scp));
5340 smb_SetSMBParmDouble(outp, parmSlot, (char *)&scp->length); parmSlot += 4;
5341 smb_SetSMBParmDouble(outp, parmSlot, (char *)&scp->length); parmSlot += 4;
5342 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* filetype */
5343 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* dev state */
5344 smb_SetSMBParmByte(outp, parmSlot,
5345 scp->fileType == CM_SCACHETYPE_DIRECTORY); /* is a dir? */
5346 lock_ReleaseMutex(&scp->mx);
5347 smb_SetSMBDataLength(outp, 0);
5349 osi_Log2(smb_logp, "SMB NT CreateX opening fid %d path %s", fidp->fid,
5350 osi_LogSaveString(smb_logp, realPathp));
5352 smb_ReleaseFID(fidp);
5354 cm_ReleaseUser(userp);
5356 /* Can't free realPathp if we get here since fidp->NTopen_wholepathp is pointing there */
5358 /* leave scp held since we put it in fidp->scp */
5363 * A lot of stuff copied verbatim from NT Create&X to NT Tran Create.
5364 * Instead, ultimately, would like to use a subroutine for common code.
5366 long smb_ReceiveNTTranCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5368 char *pathp, *realPathp;
5372 cm_scache_t *dscp; /* parent dir */
5373 cm_scache_t *scp; /* file to create or open */
5374 cm_scache_t *targetScp; /* if scp is a symlink */
5377 unsigned long nameLength;
5379 unsigned int requestOpLock;
5380 unsigned int requestBatchOpLock;
5381 unsigned int mustBeDir;
5382 unsigned int extendedRespRequired;
5384 unsigned int desiredAccess;
5385 #ifdef DEBUG_VERBOSE
5386 unsigned int allocSize;
5387 unsigned int shareAccess;
5389 unsigned int extAttributes;
5390 unsigned int createDisp;
5391 #ifdef DEBUG_VERBOSE
5394 unsigned int createOptions;
5395 int initialModeBits;
5396 unsigned short baseFid;
5397 smb_fid_t *baseFidp;
5399 cm_scache_t *baseDirp;
5400 unsigned short openAction;
5406 int parmOffset, dataOffset;
5417 parmOffset = smb_GetSMBOffsetParm(inp, 11, 1)
5418 | (smb_GetSMBOffsetParm(inp, 12, 1) << 16);
5419 parmp = inp->data + parmOffset;
5420 lparmp = (ULONG *) parmp;
5423 requestOpLock = flags & 0x02;
5424 requestBatchOpLock = flags & 0x04;
5425 mustBeDir = flags & 0x08;
5426 extendedRespRequired = flags & 0x10;
5429 * Why all of a sudden 32-bit FID?
5430 * We will reject all bits higher than 16.
5432 if (lparmp[1] & 0xFFFF0000)
5433 return CM_ERROR_INVAL;
5434 baseFid = (unsigned short)lparmp[1];
5435 desiredAccess = lparmp[2];
5436 #ifdef DEBUG_VERBOSE
5437 allocSize = lparmp[3];
5438 #endif /* DEBUG_VERSOSE */
5439 extAttributes = lparmp[5];
5441 shareAccess = lparmp[6];
5443 createDisp = lparmp[7];
5444 createOptions = lparmp[8];
5445 #ifdef DEBUG_VERBOSE
5448 nameLength = lparmp[11];
5450 #ifdef DEBUG_VERBOSE
5451 osi_Log4(smb_logp,"NTTranCreate with da[%x],ea[%x],sa[%x],cd[%x]",desiredAccess,extAttributes,shareAccess,createDisp);
5452 osi_Log3(smb_logp,"... co[%x],sdl[%x],as[%x]",createOptions,sdLen,allocSize);
5453 osi_Log1(smb_logp,"... flags[%x]",flags);
5456 /* mustBeDir is never set; createOptions directory bit seems to be
5459 if (createOptions & 1)
5461 else if (createOptions & 0x40)
5467 * compute initial mode bits based on read-only flag in
5468 * extended attributes
5470 initialModeBits = 0666;
5471 if (extAttributes & 1)
5472 initialModeBits &= ~0222;
5474 pathp = parmp + (13 * sizeof(ULONG)) + sizeof(UCHAR);
5475 /* Sometimes path is not null-terminated, so we make a copy. */
5476 realPathp = malloc(nameLength+1);
5477 memcpy(realPathp, pathp, nameLength);
5478 realPathp[nameLength] = 0;
5480 spacep = cm_GetSpace();
5481 smb_StripLastComponent(spacep->data, &lastNamep, realPathp);
5484 * Nothing here to handle SMB_IOCTL_FILENAME.
5485 * Will add it if necessary.
5488 #ifdef DEBUG_VERBOSE
5490 char *hexp, *asciip;
5491 asciip = (lastNamep? lastNamep : realPathp);
5492 hexp = osi_HexifyString( asciip );
5493 DEBUG_EVENT2("AFS", "NTTranCreate H[%s] A[%s]", hexp, asciip);
5498 userp = smb_GetUser(vcp, inp);
5500 osi_Log1(smb_logp, "NTTranCreate invalid user [%d]", ((smb_t *) inp)->uid);
5502 return CM_ERROR_INVAL;
5506 baseDirp = cm_rootSCachep;
5507 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5508 if(code == CM_ERROR_TIDIPC) {
5509 /* Attempt to use TID allocated for IPC. The client is
5510 * probably trying to locate DCE RPC endpoints, which we
5512 osi_Log0(smb_logp, "NTTranCreate received IPC TID");
5514 cm_ReleaseUser(userp);
5515 return CM_ERROR_NOSUCHPATH;
5519 baseFidp = smb_FindFID(vcp, baseFid, 0);
5521 osi_Log1(smb_logp, "NTTranCreate Invalid fid [%d]", baseFid);
5523 cm_ReleaseUser(userp);
5524 return CM_ERROR_INVAL;
5526 baseDirp = baseFidp->scp;
5530 /* compute open mode */
5532 if (desiredAccess & DELETE)
5533 fidflags |= SMB_FID_OPENDELETE;
5534 if (desiredAccess & AFS_ACCESS_READ)
5535 fidflags |= SMB_FID_OPENREAD;
5536 if (desiredAccess & AFS_ACCESS_WRITE)
5537 fidflags |= SMB_FID_OPENWRITE;
5541 if ( createDisp == FILE_OPEN ||
5542 createDisp == FILE_OVERWRITE ||
5543 createDisp == FILE_OVERWRITE_IF) {
5544 code = cm_NameI(baseDirp, spacep->data, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
5545 userp, tidPathp, &req, &dscp);
5547 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp, CM_FLAG_FOLLOW,
5549 if (code == CM_ERROR_NOSUCHFILE) {
5550 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp,
5551 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, &req, &scp);
5552 if (code == 0 && realDirFlag == 1) {
5553 cm_ReleaseSCache(scp);
5554 cm_ReleaseSCache(dscp);
5555 cm_ReleaseUser(userp);
5557 return CM_ERROR_EXISTS;
5563 code = cm_NameI(baseDirp, realPathp, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
5564 userp, tidPathp, &req, &scp);
5570 || (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE))) {
5571 /* look up parent directory */
5573 code = cm_NameI(baseDirp, spacep->data,
5574 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
5575 userp, tidPathp, &req, &dscp);
5579 cm_FreeSpace(spacep);
5582 smb_ReleaseFID(baseFidp);
5587 cm_ReleaseUser(userp);
5592 if (!lastNamep) lastNamep = realPathp;
5595 if (!smb_IsLegalFilename(lastNamep))
5596 return CM_ERROR_BADNTFILENAME;
5599 if (createDisp == FILE_CREATE || createDisp == FILE_OVERWRITE_IF) {
5600 code = cm_Lookup(dscp, lastNamep,
5601 CM_FLAG_FOLLOW, userp, &req, &scp);
5603 code = cm_Lookup(dscp, lastNamep,
5604 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
5607 if (code && code != CM_ERROR_NOSUCHFILE) {
5608 cm_ReleaseSCache(dscp);
5609 cm_ReleaseUser(userp);
5617 smb_ReleaseFID(baseFidp);
5620 cm_FreeSpace(spacep);
5623 /* if we get here, if code is 0, the file exists and is represented by
5624 * scp. Otherwise, we have to create it. The dir may be represented
5625 * by dscp, or we may have found the file directly. If code is non-zero,
5629 code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp,
5632 if (dscp) cm_ReleaseSCache(dscp);
5633 cm_ReleaseSCache(scp);
5634 cm_ReleaseUser(userp);
5639 if (createDisp == FILE_CREATE) {
5640 /* oops, file shouldn't be there */
5641 if (dscp) cm_ReleaseSCache(dscp);
5642 cm_ReleaseSCache(scp);
5643 cm_ReleaseUser(userp);
5645 return CM_ERROR_EXISTS;
5648 if (createDisp == FILE_OVERWRITE ||
5649 createDisp == FILE_OVERWRITE_IF) {
5650 setAttr.mask = CM_ATTRMASK_LENGTH;
5651 setAttr.length.LowPart = 0;
5652 setAttr.length.HighPart = 0;
5654 /* now watch for a symlink */
5656 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
5658 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
5660 /* we have a more accurate file to use (the
5661 * target of the symbolic link). Otherwise,
5662 * we'll just use the symlink anyway.
5664 osi_Log2(smb_logp, "symlink vp %x to vp %x",
5666 cm_ReleaseSCache(scp);
5670 code = cm_SetAttr(scp, &setAttr, userp, &req);
5671 openAction = 3; /* truncated existing file */
5673 else openAction = 1; /* found existing file */
5675 else if (createDisp == FILE_OPEN || createDisp == FILE_OVERWRITE) {
5676 /* don't create if not found */
5677 if (dscp) cm_ReleaseSCache(dscp);
5678 cm_ReleaseUser(userp);
5680 return CM_ERROR_NOSUCHFILE;
5682 else if (realDirFlag == 0 || realDirFlag == -1) {
5683 osi_assert(dscp != NULL);
5684 osi_Log1(smb_logp, "smb_ReceiveNTTranCreate creating file %s",
5685 osi_LogSaveString(smb_logp, lastNamep));
5686 openAction = 2; /* created file */
5687 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
5688 setAttr.clientModTime = time(NULL);
5689 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
5691 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
5692 smb_NotifyChange(FILE_ACTION_ADDED,
5693 FILE_NOTIFY_CHANGE_FILE_NAME,
5694 dscp, lastNamep, NULL, TRUE);
5695 if (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE) {
5696 /* Not an exclusive create, and someone else tried
5697 * creating it already, then we open it anyway. We
5698 * don't bother retrying after this, since if this next
5699 * fails, that means that the file was deleted after we
5700 * started this call.
5702 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
5705 if (createDisp == FILE_OVERWRITE_IF) {
5706 setAttr.mask = CM_ATTRMASK_LENGTH;
5707 setAttr.length.LowPart = 0;
5708 setAttr.length.HighPart = 0;
5710 /* now watch for a symlink */
5712 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
5714 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
5716 /* we have a more accurate file to use (the
5717 * target of the symbolic link). Otherwise,
5718 * we'll just use the symlink anyway.
5720 osi_Log2(smb_logp, "symlink vp %x to vp %x",
5722 cm_ReleaseSCache(scp);
5726 code = cm_SetAttr(scp, &setAttr, userp, &req);
5728 } /* lookup succeeded */
5732 /* create directory */
5733 osi_assert(dscp != NULL);
5735 "smb_ReceiveNTTranCreate creating directory %s",
5736 osi_LogSaveString(smb_logp, lastNamep));
5737 openAction = 2; /* created directory */
5738 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
5739 setAttr.clientModTime = time(NULL);
5740 code = cm_MakeDir(dscp, lastNamep, 0, &setAttr, userp, &req);
5741 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
5742 smb_NotifyChange(FILE_ACTION_ADDED,
5743 FILE_NOTIFY_CHANGE_DIR_NAME,
5744 dscp, lastNamep, NULL, TRUE);
5746 (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE)) {
5747 /* Not an exclusive create, and someone else tried
5748 * creating it already, then we open it anyway. We
5749 * don't bother retrying after this, since if this next
5750 * fails, that means that the file was deleted after we
5751 * started this call.
5753 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
5759 /* something went wrong creating or truncating the file */
5760 if (scp) cm_ReleaseSCache(scp);
5761 cm_ReleaseUser(userp);
5766 /* make sure we have file vs. dir right */
5767 if (realDirFlag == 0 && scp->fileType != CM_SCACHETYPE_FILE) {
5768 /* now watch for a symlink */
5770 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
5772 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
5774 /* we have a more accurate file to use (the
5775 * target of the symbolic link). Otherwise,
5776 * we'll just use the symlink anyway.
5778 osi_Log2(smb_logp, "symlink vp %x to vp %x",
5780 cm_ReleaseSCache(scp);
5785 if (scp->fileType != CM_SCACHETYPE_FILE) {
5786 cm_ReleaseSCache(scp);
5787 cm_ReleaseUser(userp);
5789 return CM_ERROR_ISDIR;
5793 if (realDirFlag == 1 && scp->fileType == CM_SCACHETYPE_FILE) {
5794 cm_ReleaseSCache(scp);
5795 cm_ReleaseUser(userp);
5797 return CM_ERROR_NOTDIR;
5800 /* open the file itself */
5801 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
5804 /* save a pointer to the vnode */
5807 fidp->flags = fidflags;
5809 /* save parent dir and pathname for deletion or change notification */
5810 if (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE)) {
5811 fidp->flags |= SMB_FID_NTOPEN;
5812 fidp->NTopen_dscp = dscp;
5813 cm_HoldSCache(dscp);
5814 fidp->NTopen_pathp = strdup(lastNamep);
5816 fidp->NTopen_wholepathp = realPathp;
5818 /* we don't need this any longer */
5819 if (dscp) cm_ReleaseSCache(dscp);
5821 cm_Open(scp, 0, userp);
5823 /* set inp->fid so that later read calls in same msg can find fid */
5824 inp->fid = fidp->fid;
5826 /* check whether we are required to send an extended response */
5827 if (!extendedRespRequired) {
5829 parmOffset = 8*4 + 39;
5830 parmOffset += 1; /* pad to 4 */
5831 dataOffset = parmOffset + 70;
5835 /* Total Parameter Count */
5836 smb_SetSMBParmLong(outp, parmSlot, 70); parmSlot += 2;
5837 /* Total Data Count */
5838 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
5839 /* Parameter Count */
5840 smb_SetSMBParmLong(outp, parmSlot, 70); parmSlot += 2;
5841 /* Parameter Offset */
5842 smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
5843 /* Parameter Displacement */
5844 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
5846 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
5848 smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
5849 /* Data Displacement */
5850 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
5851 smb_SetSMBParmByte(outp, parmSlot, 0); /* Setup Count */
5852 smb_SetSMBDataLength(outp, 70);
5854 lock_ObtainMutex(&scp->mx);
5855 outData = smb_GetSMBData(outp, NULL);
5856 outData++; /* round to get to parmOffset */
5857 *outData = 0; outData++; /* oplock */
5858 *outData = 0; outData++; /* reserved */
5859 *((USHORT *)outData) = fidp->fid; outData += 2; /* fid */
5860 *((ULONG *)outData) = openAction; outData += 4;
5861 *((ULONG *)outData) = 0; outData += 4; /* EA error offset */
5862 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
5863 *((FILETIME *)outData) = ft; outData += 8; /* creation time */
5864 *((FILETIME *)outData) = ft; outData += 8; /* last access time */
5865 *((FILETIME *)outData) = ft; outData += 8; /* last write time */
5866 *((FILETIME *)outData) = ft; outData += 8; /* change time */
5867 *((ULONG *)outData) = smb_ExtAttributes(scp); outData += 4;
5868 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* alloc sz */
5869 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* EOF */
5870 *((USHORT *)outData) = 0; outData += 2; /* filetype */
5871 *((USHORT *)outData) = 0; outData += 2; /* dev state */
5872 *((USHORT *)outData) = (scp->fileType == CM_SCACHETYPE_DIRECTORY);
5873 outData += 2; /* is a dir? */
5874 lock_ReleaseMutex(&scp->mx);
5877 parmOffset = 8*4 + 39;
5878 parmOffset += 1; /* pad to 4 */
5879 dataOffset = parmOffset + 104;
5883 /* Total Parameter Count */
5884 smb_SetSMBParmLong(outp, parmSlot, 101); parmSlot += 2;
5885 /* Total Data Count */
5886 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
5887 /* Parameter Count */
5888 smb_SetSMBParmLong(outp, parmSlot, 101); parmSlot += 2;
5889 /* Parameter Offset */
5890 smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
5891 /* Parameter Displacement */
5892 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
5894 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
5896 smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
5897 /* Data Displacement */
5898 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
5899 smb_SetSMBParmByte(outp, parmSlot, 0); /* Setup Count */
5900 smb_SetSMBDataLength(outp, 105);
5902 lock_ObtainMutex(&scp->mx);
5903 outData = smb_GetSMBData(outp, NULL);
5904 outData++; /* round to get to parmOffset */
5905 *outData = 0; outData++; /* oplock */
5906 *outData = 1; outData++; /* response type */
5907 *((USHORT *)outData) = fidp->fid; outData += 2; /* fid */
5908 *((ULONG *)outData) = openAction; outData += 4;
5909 *((ULONG *)outData) = 0; outData += 4; /* EA error offset */
5910 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
5911 *((FILETIME *)outData) = ft; outData += 8; /* creation time */
5912 *((FILETIME *)outData) = ft; outData += 8; /* last access time */
5913 *((FILETIME *)outData) = ft; outData += 8; /* last write time */
5914 *((FILETIME *)outData) = ft; outData += 8; /* change time */
5915 *((ULONG *)outData) = smb_ExtAttributes(scp); outData += 4;
5916 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* alloc sz */
5917 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* EOF */
5918 *((USHORT *)outData) = 0; outData += 2; /* filetype */
5919 *((USHORT *)outData) = 0; outData += 2; /* dev state */
5920 *((USHORT *)outData) = (scp->fileType == CM_SCACHETYPE_DIRECTORY);
5921 outData += 1; /* is a dir? */
5922 memset(outData,0,24); outData += 24; /* Volume ID and file ID */
5923 *((ULONG *)outData) = 0x001f01ffL; outData += 4; /* Maxmimal access rights */
5924 *((ULONG *)outData) = 0; outData += 4; /* Guest Access rights */
5925 lock_ReleaseMutex(&scp->mx);
5928 osi_Log1(smb_logp, "SMB NTTranCreate opening fid %d", fidp->fid);
5930 smb_ReleaseFID(fidp);
5932 cm_ReleaseUser(userp);
5934 /* free(realPathp); Can't free realPathp here because fidp->NTopen_wholepathp points there */
5935 /* leave scp held since we put it in fidp->scp */
5939 long smb_ReceiveNTTranNotifyChange(smb_vc_t *vcp, smb_packet_t *inp,
5942 smb_packet_t *savedPacketp;
5943 ULONG filter; USHORT fid, watchtree;
5947 filter = smb_GetSMBParm(inp, 19) |
5948 (smb_GetSMBParm(inp, 20) << 16);
5949 fid = smb_GetSMBParm(inp, 21);
5950 watchtree = smb_GetSMBParm(inp, 22) && 0xffff; /* TODO: should this be 0xff ? */
5952 fidp = smb_FindFID(vcp, fid, 0);
5954 osi_Log1(smb_logp, "ERROR: NotifyChange given invalid fid [%d]", fid);
5955 return CM_ERROR_BADFD;
5958 savedPacketp = smb_CopyPacket(inp);
5960 savedPacketp->vcp = vcp;
5961 lock_ObtainMutex(&smb_Dir_Watch_Lock);
5962 savedPacketp->nextp = smb_Directory_Watches;
5963 smb_Directory_Watches = savedPacketp;
5964 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
5966 osi_Log4(smb_logp, "Request for NotifyChange filter 0x%x fid %d wtree %d file %s",
5967 filter, fid, watchtree, osi_LogSaveString(smb_logp, fidp->NTopen_wholepathp));
5970 lock_ObtainMutex(&scp->mx);
5972 scp->flags |= CM_SCACHEFLAG_WATCHEDSUBTREE;
5974 scp->flags |= CM_SCACHEFLAG_WATCHED;
5975 lock_ReleaseMutex(&scp->mx);
5976 smb_ReleaseFID(fidp);
5978 outp->flags |= SMB_PACKETFLAG_NOSEND;
5982 unsigned char nullSecurityDesc[36] = {
5983 0x01, /* security descriptor revision */
5984 0x00, /* reserved, should be zero */
5985 0x00, 0x80, /* security descriptor control;
5986 * 0x8000 : self-relative format */
5987 0x14, 0x00, 0x00, 0x00, /* offset of owner SID */
5988 0x1c, 0x00, 0x00, 0x00, /* offset of group SID */
5989 0x00, 0x00, 0x00, 0x00, /* offset of DACL would go here */
5990 0x00, 0x00, 0x00, 0x00, /* offset of SACL would go here */
5991 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
5992 /* "null SID" owner SID */
5993 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
5994 /* "null SID" group SID */
5997 long smb_ReceiveNTTranQuerySecurityDesc(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5999 int parmOffset, parmCount, dataOffset, dataCount;
6007 ULONG securityInformation;
6009 parmOffset = smb_GetSMBOffsetParm(inp, 11, 1)
6010 | (smb_GetSMBOffsetParm(inp, 12, 1) << 16);
6011 parmp = inp->data + parmOffset;
6012 sparmp = (USHORT *) parmp;
6013 lparmp = (ULONG *) parmp;
6016 securityInformation = lparmp[1];
6018 maxData = smb_GetSMBOffsetParm(inp, 7, 1)
6019 | (smb_GetSMBOffsetParm(inp, 8, 1) << 16);
6027 parmOffset = 8*4 + 39;
6028 parmOffset += 1; /* pad to 4 */
6030 dataOffset = parmOffset + parmCount;
6034 /* Total Parameter Count */
6035 smb_SetSMBParmLong(outp, parmSlot, parmCount); parmSlot += 2;
6036 /* Total Data Count */
6037 smb_SetSMBParmLong(outp, parmSlot, dataCount); parmSlot += 2;
6038 /* Parameter Count */
6039 smb_SetSMBParmLong(outp, parmSlot, parmCount); parmSlot += 2;
6040 /* Parameter Offset */
6041 smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
6042 /* Parameter Displacement */
6043 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
6045 smb_SetSMBParmLong(outp, parmSlot, dataCount); parmSlot += 2;
6047 smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
6048 /* Data Displacement */
6049 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
6050 smb_SetSMBParmByte(outp, parmSlot, 0); /* Setup Count */
6051 smb_SetSMBDataLength(outp, 1 + parmCount + dataCount);
6053 outData = smb_GetSMBData(outp, NULL);
6054 outData++; /* round to get to parmOffset */
6055 *((ULONG *)outData) = 36; outData += 4; /* length */
6057 if (maxData >= 36) {
6058 memcpy(outData, nullSecurityDesc, 36);
6062 return CM_ERROR_BUFFERTOOSMALL;
6065 long smb_ReceiveNTTransact(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6067 unsigned short function;
6069 function = smb_GetSMBParm(inp, 18);
6071 osi_Log1(smb_logp, "SMB NT Transact function %d", function);
6073 /* We can handle long names */
6074 if (vcp->flags & SMB_VCFLAG_USENT)
6075 ((smb_t *)outp)->flg2 |= 0x40; /* IS_LONG_NAME */
6079 return smb_ReceiveNTTranQuerySecurityDesc(vcp, inp, outp);
6081 return smb_ReceiveNTTranNotifyChange(vcp, inp, outp);
6083 return smb_ReceiveNTTranCreate(vcp, inp, outp);
6085 return CM_ERROR_INVAL;
6090 * smb_NotifyChange -- find relevant change notification messages and
6093 * If we don't know the file name (i.e. a callback break), filename is
6094 * NULL, and we return a zero-length list.
6096 void smb_NotifyChange(DWORD action, DWORD notifyFilter,
6097 cm_scache_t *dscp, char *filename, char *otherFilename,
6098 BOOL isDirectParent)
6100 smb_packet_t *watch, *lastWatch, *nextWatch;
6101 ULONG parmSlot, parmCount, parmOffset, dataOffset, nameLen;
6102 char *outData, *oldOutData;
6106 BOOL twoEntries = FALSE;
6107 ULONG otherNameLen, oldParmCount = 0;
6112 /* Get ready for rename within directory */
6113 if (action == FILE_ACTION_RENAMED_OLD_NAME && otherFilename != NULL) {
6115 otherAction = FILE_ACTION_RENAMED_NEW_NAME;
6118 osi_Log2(smb_logp,"in smb_NotifyChange for file [%s] dscp [%x]",
6119 osi_LogSaveString(smb_logp,filename),dscp);
6121 lock_ObtainMutex(&smb_Dir_Watch_Lock);
6122 watch = smb_Directory_Watches;
6124 filter = smb_GetSMBParm(watch, 19)
6125 | (smb_GetSMBParm(watch, 20) << 16);
6126 fid = smb_GetSMBParm(watch, 21);
6127 wtree = smb_GetSMBParm(watch, 22) & 0xffff; /* TODO: should this be 0xff ? */
6128 maxLen = smb_GetSMBOffsetParm(watch, 5, 1)
6129 | (smb_GetSMBOffsetParm(watch, 6, 1) << 16);
6133 * Strange hack - bug in NT Client and NT Server that we
6136 if (filter == 3 && wtree)
6139 fidp = smb_FindFID(vcp, fid, 0);
6141 osi_Log1(smb_logp," no fidp for fid[%d]",fid);
6143 watch = watch->nextp;
6146 if (fidp->scp != dscp
6147 || (filter & notifyFilter) == 0
6148 || (!isDirectParent && !wtree)) {
6149 osi_Log1(smb_logp," passing fidp->scp[%x]", fidp->scp);
6150 smb_ReleaseFID(fidp);
6152 watch = watch->nextp;
6155 smb_ReleaseFID(fidp);
6158 "Sending Change Notification for fid %d filter 0x%x wtree %d file %s",
6159 fid, filter, wtree, osi_LogSaveString(smb_logp, filename));
6161 nextWatch = watch->nextp;
6162 if (watch == smb_Directory_Watches)
6163 smb_Directory_Watches = nextWatch;
6165 lastWatch->nextp = nextWatch;
6167 /* Turn off WATCHED flag in dscp */
6168 lock_ObtainMutex(&dscp->mx);
6170 dscp->flags &= ~CM_SCACHEFLAG_WATCHEDSUBTREE;
6172 dscp->flags &= ~CM_SCACHEFLAG_WATCHED;
6173 lock_ReleaseMutex(&dscp->mx);
6175 /* Convert to response packet */
6176 ((smb_t *) watch)->reb = 0x80;
6177 ((smb_t *) watch)->wct = 0;
6180 if (filename == NULL)
6183 nameLen = strlen(filename);
6184 parmCount = 3*4 + nameLen*2;
6185 parmCount = (parmCount + 3) & ~3; /* pad to 4 */
6187 otherNameLen = strlen(otherFilename);
6188 oldParmCount = parmCount;
6189 parmCount += 3*4 + otherNameLen*2;
6190 parmCount = (parmCount + 3) & ~3; /* pad to 4 */
6192 if (maxLen < parmCount)
6193 parmCount = 0; /* not enough room */
6195 parmOffset = 8*4 + 39;
6196 parmOffset += 1; /* pad to 4 */
6197 dataOffset = parmOffset + parmCount;
6201 /* Total Parameter Count */
6202 smb_SetSMBParmLong(watch, parmSlot, parmCount); parmSlot += 2;
6203 /* Total Data Count */
6204 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
6205 /* Parameter Count */
6206 smb_SetSMBParmLong(watch, parmSlot, parmCount); parmSlot += 2;
6207 /* Parameter Offset */
6208 smb_SetSMBParmLong(watch, parmSlot, parmOffset); parmSlot += 2;
6209 /* Parameter Displacement */
6210 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
6212 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
6214 smb_SetSMBParmLong(watch, parmSlot, dataOffset); parmSlot += 2;
6215 /* Data Displacement */
6216 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
6217 smb_SetSMBParmByte(watch, parmSlot, 0); /* Setup Count */
6218 smb_SetSMBDataLength(watch, parmCount + 1);
6220 if (parmCount != 0) {
6221 outData = smb_GetSMBData(watch, NULL);
6222 outData++; /* round to get to parmOffset */
6223 oldOutData = outData;
6224 *((DWORD *)outData) = oldParmCount; outData += 4;
6225 /* Next Entry Offset */
6226 *((DWORD *)outData) = action; outData += 4;
6228 *((DWORD *)outData) = nameLen*2; outData += 4;
6229 /* File Name Length */
6230 mbstowcs((WCHAR *)outData, filename, nameLen);
6233 outData = oldOutData + oldParmCount;
6234 *((DWORD *)outData) = 0; outData += 4;
6235 /* Next Entry Offset */
6236 *((DWORD *)outData) = otherAction; outData += 4;
6238 *((DWORD *)outData) = otherNameLen*2;
6239 outData += 4; /* File Name Length */
6240 mbstowcs((WCHAR *)outData, otherFilename,
6241 otherNameLen); /* File Name */
6246 * If filename is null, we don't know the cause of the
6247 * change notification. We return zero data (see above),
6248 * and set error code to NT_STATUS_NOTIFY_ENUM_DIR
6249 * (= 0x010C). We set the error code here by hand, without
6250 * modifying wct and bcc.
6252 if (filename == NULL) {
6253 ((smb_t *) watch)->rcls = 0x0C;
6254 ((smb_t *) watch)->reh = 0x01;
6255 ((smb_t *) watch)->errLow = 0;
6256 ((smb_t *) watch)->errHigh = 0;
6257 /* Set NT Status codes flag */
6258 ((smb_t *) watch)->flg2 |= 0x4000;
6261 smb_SendPacket(vcp, watch);
6263 smb_FreePacket(watch);
6266 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
6269 long smb_ReceiveNTCancel(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6271 unsigned char *replyWctp;
6272 smb_packet_t *watch, *lastWatch;
6273 USHORT fid, watchtree;
6277 osi_Log0(smb_logp, "SMB3 receive NT cancel");
6279 lock_ObtainMutex(&smb_Dir_Watch_Lock);
6280 watch = smb_Directory_Watches;
6282 if (((smb_t *)watch)->uid == ((smb_t *)inp)->uid
6283 && ((smb_t *)watch)->pid == ((smb_t *)inp)->pid
6284 && ((smb_t *)watch)->mid == ((smb_t *)inp)->mid
6285 && ((smb_t *)watch)->tid == ((smb_t *)inp)->tid) {
6286 if (watch == smb_Directory_Watches)
6287 smb_Directory_Watches = watch->nextp;
6289 lastWatch->nextp = watch->nextp;
6290 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
6292 /* Turn off WATCHED flag in scp */
6293 fid = smb_GetSMBParm(watch, 21);
6294 watchtree = smb_GetSMBParm(watch, 22) & 0xffff;
6296 if (vcp != watch->vcp)
6297 osi_Log2(smb_logp, "smb_ReceiveNTCancel: vcp %x not equal to watch vcp %x",
6300 fidp = smb_FindFID(vcp, fid, 0);
6302 osi_Log3(smb_logp, "Cancelling change notification for fid %d wtree %d file %s",
6304 osi_LogSaveString(smb_logp, (fidp)?fidp->NTopen_wholepathp:""));
6307 lock_ObtainMutex(&scp->mx);
6309 scp->flags &= ~CM_SCACHEFLAG_WATCHEDSUBTREE;
6311 scp->flags &= ~CM_SCACHEFLAG_WATCHED;
6312 lock_ReleaseMutex(&scp->mx);
6313 smb_ReleaseFID(fidp);
6315 osi_Log2(smb_logp,"NTCancel unable to resolve fid [%d] in vcp[%x]", fid,vcp);
6318 /* assume STATUS32; return 0xC0000120 (CANCELED) */
6319 replyWctp = watch->wctp;
6323 ((smb_t *)watch)->rcls = 0x20;
6324 ((smb_t *)watch)->reh = 0x1;
6325 ((smb_t *)watch)->errLow = 0;
6326 ((smb_t *)watch)->errHigh = 0xC0;
6327 ((smb_t *)watch)->flg2 |= 0x4000;
6328 smb_SendPacket(vcp, watch);
6330 smb_ReleaseVC(watch->vcp);
6331 smb_FreePacket(watch);
6335 watch = watch->nextp;
6337 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
6343 * NT rename also does hard links.
6346 #define RENAME_FLAG_MOVE_CLUSTER_INFORMATION 0x102
6347 #define RENAME_FLAG_HARD_LINK 0x103
6348 #define RENAME_FLAG_RENAME 0x104
6349 #define RENAME_FLAG_COPY 0x105
6351 long smb_ReceiveNTRename(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6353 char *oldname, *newname;
6360 attrs = smb_GetSMBParm(inp, 0);
6361 rename_type = smb_GetSMBParm(inp, 1);
6363 if (rename_type != RENAME_FLAG_RENAME && rename_type != RENAME_FLAG_HARD_LINK) {
6364 osi_Log1(smb_logp, "NTRename invalid infolevel [%x]", rename_type);
6365 return CM_ERROR_NOACCESS;
6368 tp = smb_GetSMBData(inp, NULL);
6369 oldname = smb_ParseASCIIBlock(tp, &tp);
6370 newname = smb_ParseASCIIBlock(tp, &tp);
6372 osi_Log3(smb_logp, "NTRename for [%s]->[%s] type [%s]",
6373 osi_LogSaveString(smb_logp, oldname),
6374 osi_LogSaveString(smb_logp, newname),
6375 ((rename_type==RENAME_FLAG_RENAME)?"rename":"hardlink"));
6377 if (rename_type == RENAME_FLAG_RENAME) {
6378 code = smb_Rename(vcp,inp,oldname,newname,attrs);
6379 } else { /* RENAME_FLAG_HARD_LINK */
6380 code = smb_Link(vcp,inp,oldname,newname);
6387 lock_InitializeMutex(&smb_Dir_Watch_Lock, "Directory Watch List Lock");
6390 cm_user_t *smb_FindCMUserByName(/*smb_vc_t *vcp,*/ char *usern, char *machine)
6393 smb_username_t *unp;
6395 unp = smb_FindUserByName(usern, machine, SMB_FLAG_CREATE);
6397 lock_ObtainMutex(&unp->mx);
6398 unp->userp = cm_NewUser();
6399 lock_ReleaseMutex(&unp->mx);
6400 osi_Log2(smb_logp,"smb_FindCMUserByName New user name[%s] machine[%s]",osi_LogSaveString(smb_logp,usern),osi_LogSaveString(smb_logp,machine));
6401 osi_LogEvent("AFS smb_FindCMUserByName : New User",NULL,"name[%s] machine[%s]",usern,machine);
6403 osi_Log2(smb_logp,"smb_FindCMUserByName Not found name[%s] machine[%s]",osi_LogSaveString(smb_logp,usern),osi_LogSaveString(smb_logp,machine));
6404 osi_LogEvent("AFS smb_FindCMUserByName : Found",NULL,"name[%s] machine[%s]",usern,machine);