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
31 extern osi_hyper_t hzero;
33 smb_packet_t *smb_Directory_Watches = NULL;
34 osi_mutex_t smb_Dir_Watch_Lock;
36 smb_tran2Dispatch_t smb_tran2DispatchTable[SMB_TRAN2_NOPCODES];
38 smb_tran2Dispatch_t smb_rapDispatchTable[SMB_RAP_NOPCODES];
40 /* protected by the smb_globalLock */
41 smb_tran2Packet_t *smb_tran2AssemblyQueuep;
43 /* retrieve a held reference to a user structure corresponding to an incoming
45 cm_user_t *smb_GetTran2User(smb_vc_t *vcp, smb_tran2Packet_t *inp)
50 uidp = smb_FindUID(vcp, inp->uid, 0);
51 if (!uidp) return NULL;
53 lock_ObtainMutex(&uidp->mx);
55 up = uidp->unp->userp;
58 lock_ReleaseMutex(&uidp->mx);
66 * Return extended attributes.
67 * Right now, we aren't using any of the "new" bits, so this looks exactly
68 * like smb_Attributes() (see smb.c).
70 unsigned long smb_ExtAttributes(cm_scache_t *scp)
74 if (scp->fileType == CM_SCACHETYPE_DIRECTORY ||
75 scp->fileType == CM_SCACHETYPE_MOUNTPOINT)
77 attrs = SMB_ATTR_DIRECTORY;
78 #ifdef SPECIAL_FOLDERS
79 #ifdef AFS_FREELANCE_CLIENT
80 if ( cm_freelanceEnabled &&
81 scp->fid.cell==AFS_FAKE_ROOT_CELL_ID &&
82 scp->fid.volume==AFS_FAKE_ROOT_VOL_ID &&
83 scp->fid.vnode==0x1 && scp->fid.unique==0x1) {
84 attrs |= SMB_ATTR_SYSTEM; /* FILE_ATTRIBUTE_SYSTEM */
86 #endif /* AFS_FREELANCE_CLIENT */
87 #endif /* SPECIAL_FOLDERS */
91 * We used to mark a file RO if it was in an RO volume, but that
92 * turns out to be impolitic in NT. See defect 10007.
95 if ((scp->unixModeBits & 0222) == 0 || (scp->flags & CM_SCACHEFLAG_RO))
97 if ((scp->unixModeBits & 0222) == 0)
98 attrs |= SMB_ATTR_READONLY; /* Read-only */
101 attrs = SMB_ATTR_NORMAL; /* FILE_ATTRIBUTE_NORMAL */
106 int smb_V3IsStarMask(char *maskp)
110 while (tc = *maskp++)
111 if (tc == '?' || tc == '*')
116 unsigned char *smb_ParseString(unsigned char *inp, char **chainpp)
119 /* skip over null-terminated string */
120 *chainpp = inp + strlen(inp) + 1;
125 /*DEBUG do not checkin*/
126 void OutputDebugF(char * format, ...) {
131 va_start( args, format );
132 len = _vscprintf( format, args ) // _vscprintf doesn't count
133 + 3; // terminating '\0' + '\n'
134 buffer = malloc( len * sizeof(char) );
135 vsprintf( buffer, format, args );
136 osi_Log0(smb_logp, osi_LogSaveString(smb_logp, buffer));
137 strcat(buffer, "\n");
138 OutputDebugString(buffer);
142 void OutputDebugHexDump(unsigned char * buffer, int len) {
145 static char tr[16] = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
147 OutputDebugF("Hexdump length [%d]",len);
149 for (i=0;i<len;i++) {
152 osi_Log0(smb_logp, osi_LogSaveString(smb_logp, buf));
154 OutputDebugString(buf);
156 sprintf(buf,"%5x",i);
157 memset(buf+5,' ',80);
162 j = j*3 + 7 + ((j>7)?1:0);
165 buf[j] = tr[k / 16]; buf[j+1] = tr[k % 16];
168 j = j + 56 + ((j>7)?1:0);
170 buf[j] = (k>32 && k<127)?k:'.';
173 osi_Log0(smb_logp, osi_LogSaveString(smb_logp, buf));
175 OutputDebugString(buf);
180 #define SMB_EXT_SEC_PACKAGE_NAME "Negotiate"
181 void smb_NegotiateExtendedSecurity(void ** secBlob, int * secBlobLength) {
182 SECURITY_STATUS status, istatus;
183 CredHandle creds = {0,0};
185 SecBufferDesc secOut;
193 OutputDebugF("Negotiating Extended Security");
195 status = AcquireCredentialsHandle( NULL,
196 SMB_EXT_SEC_PACKAGE_NAME,
205 if (status != SEC_E_OK) {
206 /* Really bad. We return an empty security blob */
207 OutputDebugF("AcquireCredentialsHandle failed with %lX", status);
212 secOut.pBuffers = &secTok;
213 secOut.ulVersion = SECBUFFER_VERSION;
215 secTok.BufferType = SECBUFFER_TOKEN;
217 secTok.pvBuffer = NULL;
219 ctx.dwLower = ctx.dwUpper = 0;
221 status = AcceptSecurityContext( &creds,
224 ASC_REQ_CONNECTION | ASC_REQ_EXTENDED_ERROR | ASC_REQ_ALLOCATE_MEMORY,
225 SECURITY_NETWORK_DREP,
232 if (status == SEC_I_COMPLETE_NEEDED || status == SEC_I_COMPLETE_AND_CONTINUE) {
233 OutputDebugF("Completing token...");
234 istatus = CompleteAuthToken(&ctx, &secOut);
235 if ( istatus != SEC_E_OK )
236 OutputDebugF("Token completion failed: %x", istatus);
239 if (status == SEC_I_COMPLETE_AND_CONTINUE || status == SEC_I_CONTINUE_NEEDED) {
240 if (secTok.pvBuffer) {
241 *secBlobLength = secTok.cbBuffer;
242 *secBlob = malloc( secTok.cbBuffer );
243 memcpy(*secBlob, secTok.pvBuffer, secTok.cbBuffer );
246 if ( status != SEC_E_OK )
247 OutputDebugF("AcceptSecurityContext status != CONTINUE %lX", status);
250 /* Discard partial security context */
251 DeleteSecurityContext(&ctx);
253 if (secTok.pvBuffer) FreeContextBuffer( secTok.pvBuffer );
255 /* Discard credentials handle. We'll reacquire one when we get the session setup X */
256 FreeCredentialsHandle(&creds);
262 struct smb_ext_context {
269 long smb_AuthenticateUserExt(smb_vc_t * vcp, char * usern, char * secBlobIn, int secBlobInLength, char ** secBlobOut, int * secBlobOutLength) {
270 SECURITY_STATUS status, istatus;
274 SecBufferDesc secBufIn;
276 SecBufferDesc secBufOut;
279 struct smb_ext_context * secCtx = NULL;
280 struct smb_ext_context * newSecCtx = NULL;
281 void * assembledBlob = NULL;
282 int assembledBlobLength = 0;
285 OutputDebugF("In smb_AuthenticateUserExt");
288 *secBlobOutLength = 0;
290 if (vcp->flags & SMB_VCFLAG_AUTH_IN_PROGRESS) {
291 secCtx = vcp->secCtx;
292 lock_ObtainMutex(&vcp->mx);
293 vcp->flags &= ~SMB_VCFLAG_AUTH_IN_PROGRESS;
295 lock_ReleaseMutex(&vcp->mx);
299 OutputDebugF("Received incoming token:");
300 OutputDebugHexDump(secBlobIn,secBlobInLength);
304 OutputDebugF("Continuing with existing context.");
305 creds = secCtx->creds;
308 if (secCtx->partialToken) {
309 assembledBlobLength = secCtx->partialTokenLen + secBlobInLength;
310 assembledBlob = malloc(assembledBlobLength);
311 memcpy(assembledBlob,secCtx->partialToken, secCtx->partialTokenLen);
312 memcpy(((BYTE *)assembledBlob) + secCtx->partialTokenLen, secBlobIn, secBlobInLength);
315 status = AcquireCredentialsHandle( NULL,
316 SMB_EXT_SEC_PACKAGE_NAME,
325 if (status != SEC_E_OK) {
326 OutputDebugF("Can't acquire Credentials handle [%lX]", status);
327 code = CM_ERROR_BADPASSWORD; /* means "try again when I'm sober" */
335 secBufIn.cBuffers = 1;
336 secBufIn.pBuffers = &secTokIn;
337 secBufIn.ulVersion = SECBUFFER_VERSION;
339 secTokIn.BufferType = SECBUFFER_TOKEN;
341 secTokIn.cbBuffer = assembledBlobLength;
342 secTokIn.pvBuffer = assembledBlob;
344 secTokIn.cbBuffer = secBlobInLength;
345 secTokIn.pvBuffer = secBlobIn;
348 secBufOut.cBuffers = 1;
349 secBufOut.pBuffers = &secTokOut;
350 secBufOut.ulVersion = SECBUFFER_VERSION;
352 secTokOut.BufferType = SECBUFFER_TOKEN;
353 secTokOut.cbBuffer = 0;
354 secTokOut.pvBuffer = NULL;
356 status = AcceptSecurityContext( &creds,
357 ((secCtx)?&ctx:NULL),
359 ASC_REQ_CONNECTION | ASC_REQ_EXTENDED_ERROR | ASC_REQ_ALLOCATE_MEMORY,
360 SECURITY_NETWORK_DREP,
367 if (status == SEC_I_COMPLETE_NEEDED || status == SEC_I_COMPLETE_AND_CONTINUE) {
368 OutputDebugF("Completing token...");
369 istatus = CompleteAuthToken(&ctx, &secBufOut);
370 if ( istatus != SEC_E_OK )
371 OutputDebugF("Token completion failed: %lX", istatus);
374 if (status == SEC_I_COMPLETE_AND_CONTINUE || status == SEC_I_CONTINUE_NEEDED) {
375 OutputDebugF("Continue needed");
377 newSecCtx = malloc(sizeof(*newSecCtx));
379 newSecCtx->creds = creds;
380 newSecCtx->ctx = ctx;
381 newSecCtx->partialToken = NULL;
382 newSecCtx->partialTokenLen = 0;
384 lock_ObtainMutex( &vcp->mx );
385 vcp->flags |= SMB_VCFLAG_AUTH_IN_PROGRESS;
386 vcp->secCtx = newSecCtx;
387 lock_ReleaseMutex( &vcp->mx );
389 code = CM_ERROR_GSSCONTINUE;
392 if ((status == SEC_I_COMPLETE_NEEDED || status == SEC_E_OK ||
393 status == SEC_I_COMPLETE_AND_CONTINUE || status == SEC_I_CONTINUE_NEEDED) &&
394 secTokOut.pvBuffer) {
395 OutputDebugF("Need to send token back to client");
397 *secBlobOutLength = secTokOut.cbBuffer;
398 *secBlobOut = malloc(secTokOut.cbBuffer);
399 memcpy(*secBlobOut, secTokOut.pvBuffer, secTokOut.cbBuffer);
401 OutputDebugF("Outgoing token:");
402 OutputDebugHexDump(*secBlobOut,*secBlobOutLength);
403 } else if (status == SEC_E_INCOMPLETE_MESSAGE) {
404 OutputDebugF("Incomplete message");
406 newSecCtx = malloc(sizeof(*newSecCtx));
408 newSecCtx->creds = creds;
409 newSecCtx->ctx = ctx;
410 newSecCtx->partialToken = malloc(secTokOut.cbBuffer);
411 memcpy(newSecCtx->partialToken, secTokOut.pvBuffer, secTokOut.cbBuffer);
412 newSecCtx->partialTokenLen = secTokOut.cbBuffer;
414 lock_ObtainMutex( &vcp->mx );
415 vcp->flags |= SMB_VCFLAG_AUTH_IN_PROGRESS;
416 vcp->secCtx = newSecCtx;
417 lock_ReleaseMutex( &vcp->mx );
419 code = CM_ERROR_GSSCONTINUE;
422 if (status == SEC_E_OK || status == SEC_I_COMPLETE_NEEDED) {
424 SecPkgContext_Names names;
426 OutputDebugF("Authentication completed");
427 OutputDebugF("Returned flags : [%lX]", flags);
429 if (!QueryContextAttributes(&ctx, SECPKG_ATTR_NAMES, &names)) {
430 OutputDebugF("Received name [%s]", names.sUserName);
431 strcpy(usern, names.sUserName);
432 strlwr(usern); /* in tandem with smb_GetNormalizedUsername */
433 FreeContextBuffer(names.sUserName);
435 /* Force the user to retry if the context is invalid */
436 OutputDebugF("QueryContextAttributes Names failed [%x]", GetLastError());
437 code = CM_ERROR_BADPASSWORD;
441 case SEC_E_INVALID_TOKEN:
442 OutputDebugF("Returning bad password :: INVALID_TOKEN");
444 case SEC_E_INVALID_HANDLE:
445 OutputDebugF("Returning bad password :: INVALID_HANDLE");
447 case SEC_E_LOGON_DENIED:
448 OutputDebugF("Returning bad password :: LOGON_DENIED");
450 case SEC_E_UNKNOWN_CREDENTIALS:
451 OutputDebugF("Returning bad password :: UNKNOWN_CREDENTIALS");
453 case SEC_E_NO_CREDENTIALS:
454 OutputDebugF("Returning bad password :: NO_CREDENTIALS");
456 case SEC_E_CONTEXT_EXPIRED:
457 OutputDebugF("Returning bad password :: CONTEXT_EXPIRED");
459 case SEC_E_INCOMPLETE_CREDENTIALS:
460 OutputDebugF("Returning bad password :: INCOMPLETE_CREDENTIALS");
462 case SEC_E_WRONG_PRINCIPAL:
463 OutputDebugF("Returning bad password :: WRONG_PRINCIPAL");
465 case SEC_E_TIME_SKEW:
466 OutputDebugF("Returning bad password :: TIME_SKEW");
469 OutputDebugF("Returning bad password :: Status == %lX", status);
471 code = CM_ERROR_BADPASSWORD;
475 if (secCtx->partialToken) free(secCtx->partialToken);
483 if (secTokOut.pvBuffer)
484 FreeContextBuffer(secTokOut.pvBuffer);
486 if (code != CM_ERROR_GSSCONTINUE) {
487 DeleteSecurityContext(&ctx);
488 FreeCredentialsHandle(&creds);
496 #define P_RESP_LEN 128
498 /* LsaLogonUser expects input parameters to be in a contiguous block of memory.
499 So put stuff in a struct. */
500 struct Lm20AuthBlob {
501 MSV1_0_LM20_LOGON lmlogon;
502 BYTE ciResponse[P_RESP_LEN]; /* Unicode representation */
503 BYTE csResponse[P_RESP_LEN]; /* ANSI representation */
504 WCHAR accountNameW[P_LEN];
505 WCHAR primaryDomainW[P_LEN];
506 WCHAR workstationW[MAX_COMPUTERNAME_LENGTH + 1];
507 TOKEN_GROUPS tgroups;
508 TOKEN_SOURCE tsource;
511 long smb_AuthenticateUserLM(smb_vc_t *vcp, char * accountName, char * primaryDomain, char * ciPwd, unsigned ciPwdLength, char * csPwd, unsigned csPwdLength)
514 struct Lm20AuthBlob lmAuth;
515 PMSV1_0_LM20_LOGON_PROFILE lmprofilep;
516 QUOTA_LIMITS quotaLimits;
518 ULONG lmprofilepSize;
522 OutputDebugF("In smb_AuthenticateUser for user [%s] domain [%s]", accountName, primaryDomain);
523 OutputDebugF("ciPwdLength is %d and csPwdLength is %d", ciPwdLength, csPwdLength);
525 if (ciPwdLength > P_RESP_LEN || csPwdLength > P_RESP_LEN) {
526 OutputDebugF("ciPwdLength or csPwdLength is too long");
527 return CM_ERROR_BADPASSWORD;
530 memset(&lmAuth,0,sizeof(lmAuth));
532 lmAuth.lmlogon.MessageType = MsV1_0NetworkLogon;
534 lmAuth.lmlogon.LogonDomainName.Buffer = lmAuth.primaryDomainW;
535 mbstowcs(lmAuth.primaryDomainW, primaryDomain, P_LEN);
536 lmAuth.lmlogon.LogonDomainName.Length = wcslen(lmAuth.primaryDomainW) * sizeof(WCHAR);
537 lmAuth.lmlogon.LogonDomainName.MaximumLength = P_LEN * sizeof(WCHAR);
539 lmAuth.lmlogon.UserName.Buffer = lmAuth.accountNameW;
540 mbstowcs(lmAuth.accountNameW, accountName, P_LEN);
541 lmAuth.lmlogon.UserName.Length = wcslen(lmAuth.accountNameW) * sizeof(WCHAR);
542 lmAuth.lmlogon.UserName.MaximumLength = P_LEN * sizeof(WCHAR);
544 lmAuth.lmlogon.Workstation.Buffer = lmAuth.workstationW;
545 lmAuth.lmlogon.Workstation.MaximumLength = (MAX_COMPUTERNAME_LENGTH + 1) * sizeof(WCHAR);
546 size = MAX_COMPUTERNAME_LENGTH + 1;
547 GetComputerNameW(lmAuth.workstationW, &size);
548 lmAuth.lmlogon.Workstation.Length = wcslen(lmAuth.workstationW) * sizeof(WCHAR);
550 memcpy(lmAuth.lmlogon.ChallengeToClient, vcp->encKey, MSV1_0_CHALLENGE_LENGTH);
552 lmAuth.lmlogon.CaseInsensitiveChallengeResponse.Buffer = lmAuth.ciResponse;
553 lmAuth.lmlogon.CaseInsensitiveChallengeResponse.Length = ciPwdLength;
554 lmAuth.lmlogon.CaseInsensitiveChallengeResponse.MaximumLength = P_RESP_LEN;
555 memcpy(lmAuth.ciResponse, ciPwd, ciPwdLength);
557 lmAuth.lmlogon.CaseSensitiveChallengeResponse.Buffer = lmAuth.csResponse;
558 lmAuth.lmlogon.CaseSensitiveChallengeResponse.Length = csPwdLength;
559 lmAuth.lmlogon.CaseSensitiveChallengeResponse.MaximumLength = P_RESP_LEN;
560 memcpy(lmAuth.csResponse, csPwd, csPwdLength);
562 lmAuth.lmlogon.ParameterControl = 0;
564 lmAuth.tgroups.GroupCount = 0;
565 lmAuth.tgroups.Groups[0].Sid = NULL;
566 lmAuth.tgroups.Groups[0].Attributes = 0;
568 lmAuth.tsource.SourceIdentifier.HighPart = 0;
569 lmAuth.tsource.SourceIdentifier.LowPart = (DWORD) vcp;
570 strcpy(lmAuth.tsource.SourceName,"OpenAFS"); /* 8 char limit */
572 nts = LsaLogonUser( smb_lsaHandle,
587 OutputDebugF("Return from LsaLogonUser is 0x%lX", nts);
588 OutputDebugF("Extended status is 0x%lX", ntsEx);
590 if (nts == ERROR_SUCCESS) {
592 LsaFreeReturnBuffer(lmprofilep);
593 CloseHandle(lmToken);
597 if (nts == 0xC000015BL)
598 return CM_ERROR_BADLOGONTYPE;
599 else /* our catchall is a bad password though we could be more specific */
600 return CM_ERROR_BADPASSWORD;
604 /* The buffer pointed to by usern is assumed to be at least SMB_MAX_USERNAME_LENGTH bytes */
605 long smb_GetNormalizedUsername(char * usern, const char * accountName, const char * domainName)
610 /* check if we have sane input */
611 if ((strlen(accountName) + strlen(domainName) + 1) > SMB_MAX_USERNAME_LENGTH)
614 /* we could get : [accountName][domainName]
620 atsign = strchr(accountName, '@');
622 if (atsign) /* [user@domain][] -> [user@domain][domain] */
627 /* if for some reason the client doesn't know what domain to use,
628 it will either return an empty string or a '?' */
629 if (!domain[0] || domain[0] == '?')
630 /* Empty domains and empty usernames are usually sent from tokenless contexts.
631 This way such logins will get an empty username (easy to check). I don't know
632 when a non-empty username would be supplied with an anonymous domain, but *shrug* */
633 strcpy(usern,accountName);
635 /* TODO: what about WIN.MIT.EDU\user vs. WIN\user? */
636 strcpy(usern,domain);
639 strncat(usern,accountName,atsign - accountName);
641 strcat(usern,accountName);
649 /* When using SMB auth, all SMB sessions have to pass through here first to
650 * authenticate the user.
651 * Caveat: If not use the SMB auth the protocol does not require sending a
652 * session setup packet, which means that we can't rely on a UID in subsequent
653 * packets. Though in practice we get one anyway.
655 long smb_ReceiveV3SessionSetupX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
659 unsigned short newUid;
660 unsigned long caps = 0;
665 char usern[SMB_MAX_USERNAME_LENGTH];
666 char *secBlobOut = NULL;
667 int secBlobOutLength = 0;
669 /* Check for bad conns */
670 if (vcp->flags & SMB_VCFLAG_REMOTECONN)
671 return CM_ERROR_REMOTECONN;
673 if (vcp->flags & SMB_VCFLAG_USENT) {
674 if (smb_authType == SMB_AUTH_EXTENDED) {
675 /* extended authentication */
679 if (!(vcp->flags & SMB_VCFLAG_SESSX_RCVD)) {
680 caps = smb_GetSMBParm(inp,10) | (((unsigned long) smb_GetSMBParm(inp,11)) << 16);
683 secBlobInLength = smb_GetSMBParm(inp, 7);
684 secBlobIn = smb_GetSMBData(inp, NULL);
686 code = smb_AuthenticateUserExt(vcp, usern, secBlobIn, secBlobInLength, &secBlobOut, &secBlobOutLength);
688 if (code == CM_ERROR_GSSCONTINUE) {
689 smb_SetSMBParm(outp, 2, 0);
690 smb_SetSMBParm(outp, 3, secBlobOutLength);
691 smb_SetSMBDataLength(outp, secBlobOutLength + smb_ServerOSLength + smb_ServerLanManagerLength + smb_ServerDomainNameLength);
692 tp = smb_GetSMBData(outp, NULL);
693 if (secBlobOutLength) {
694 memcpy(tp, secBlobOut, secBlobOutLength);
696 tp += secBlobOutLength;
698 memcpy(tp,smb_ServerOS,smb_ServerOSLength);
699 tp += smb_ServerOSLength;
700 memcpy(tp,smb_ServerLanManager,smb_ServerLanManagerLength);
701 tp += smb_ServerLanManagerLength;
702 memcpy(tp,smb_ServerDomainName,smb_ServerDomainNameLength);
703 tp += smb_ServerDomainNameLength;
706 /* TODO: handle return code and continue auth. Also free secBlobOut if applicable. */
708 unsigned ciPwdLength, csPwdLength;
714 /* TODO: parse for extended auth as well */
715 ciPwdLength = smb_GetSMBParm(inp, 7); /* case insensitive password length */
716 csPwdLength = smb_GetSMBParm(inp, 8); /* case sensitive password length */
718 tp = smb_GetSMBData(inp, &datalen);
720 OutputDebugF("Session packet data size [%d]",datalen);
727 accountName = smb_ParseString(tp, &tp);
728 primaryDomain = smb_ParseString(tp, NULL);
730 if (smb_GetNormalizedUsername(usern, accountName, primaryDomain)) {
731 /* shouldn't happen */
732 code = CM_ERROR_BADSMB;
733 goto after_read_packet;
736 /* capabilities are only valid for first session packet */
737 if (!(vcp->flags & SMB_VCFLAG_SESSX_RCVD)) {
738 caps = smb_GetSMBParm(inp, 11) | (((unsigned long)smb_GetSMBParm(inp, 12)) << 16);
741 if (smb_authType == SMB_AUTH_NTLM) {
742 code = smb_AuthenticateUserLM(vcp, accountName, primaryDomain, ciPwd, ciPwdLength, csPwd, csPwdLength);
746 unsigned ciPwdLength;
751 ciPwdLength = smb_GetSMBParm(inp, 7);
752 tp = smb_GetSMBData(inp, NULL);
756 accountName = smb_ParseString(tp, &tp);
757 primaryDomain = smb_ParseString(tp, NULL);
759 if ( smb_GetNormalizedUsername(usern, accountName, primaryDomain)) {
760 /* shouldn't happen */
761 code = CM_ERROR_BADSMB;
762 goto after_read_packet;
765 /* even if we wanted extended auth, if we only negotiated V3, we have to fallback
768 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
769 code = smb_AuthenticateUserLM(vcp,accountName,primaryDomain,ciPwd,ciPwdLength,"",0);
774 /* note down that we received a session setup X and set the capabilities flag */
775 if (!(vcp->flags & SMB_VCFLAG_SESSX_RCVD)) {
776 lock_ObtainMutex(&vcp->mx);
777 vcp->flags |= SMB_VCFLAG_SESSX_RCVD;
778 /* for the moment we can only deal with NTSTATUS */
779 if (caps & NTNEGOTIATE_CAPABILITY_NTSTATUS) {
780 vcp->flags |= SMB_VCFLAG_STATUS32;
782 lock_ReleaseMutex(&vcp->mx);
785 /* code would be non-zero if there was an authentication failure.
786 Ideally we would like to invalidate the uid for this session or break
787 early to avoid accidently stealing someone else's tokens. */
793 OutputDebugF("Received username=[%s]", usern);
795 /* On Windows 2000, this function appears to be called more often than
796 it is expected to be called. This resulted in multiple smb_user_t
797 records existing all for the same user session which results in all
798 of the users tokens disappearing.
800 To avoid this problem, we look for an existing smb_user_t record
801 based on the users name, and use that one if we find it.
804 uidp = smb_FindUserByNameThisSession(vcp, usern);
805 if (uidp) { /* already there, so don't create a new one */
808 newUid = (unsigned short)uidp->userID; /* For some reason these are different types!*/
809 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));
810 osi_Log3(smb_logp,"smb_ReceiveV3SessionSetupX FindUserByName:Lana[%d],lsn[%d],userid[%d]",vcp->lana,vcp->lsn,newUid);
811 smb_ReleaseUID(uidp);
814 /* do a global search for the username/machine name pair */
815 unp = smb_FindUserByName(usern, vcp->rname, SMB_FLAG_CREATE);
817 /* Create a new UID and cm_user_t structure */
820 userp = cm_NewUser();
821 lock_ObtainMutex(&vcp->mx);
822 if (!vcp->uidCounter)
823 vcp->uidCounter++; /* handle unlikely wraparounds */
824 newUid = (strlen(usern)==0)?0:vcp->uidCounter++;
825 lock_ReleaseMutex(&vcp->mx);
827 /* Create a new smb_user_t structure and connect them up */
828 lock_ObtainMutex(&unp->mx);
830 lock_ReleaseMutex(&unp->mx);
832 uidp = smb_FindUID(vcp, newUid, SMB_FLAG_CREATE);
833 lock_ObtainMutex(&uidp->mx);
835 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));
836 osi_Log4(smb_logp,"smb_ReceiveV3SessionSetupX MakeNewUser:VCP[%x],Lana[%d],lsn[%d],userid[%d]",vcp,vcp->lana,vcp->lsn,newUid);
837 lock_ReleaseMutex(&uidp->mx);
838 smb_ReleaseUID(uidp);
841 /* Return UID to the client */
842 ((smb_t *)outp)->uid = newUid;
843 /* Also to the next chained message */
844 ((smb_t *)inp)->uid = newUid;
846 osi_Log3(smb_logp, "SMB3 session setup name %s creating ID %d%s",
847 osi_LogSaveString(smb_logp, usern), newUid, osi_LogSaveString(smb_logp, s1));
849 smb_SetSMBParm(outp, 2, 0);
851 if (vcp->flags & SMB_VCFLAG_USENT) {
852 if (smb_authType == SMB_AUTH_EXTENDED) {
853 smb_SetSMBParm(outp, 3, secBlobOutLength);
854 smb_SetSMBDataLength(outp, secBlobOutLength + smb_ServerOSLength + smb_ServerLanManagerLength + smb_ServerDomainNameLength);
855 tp = smb_GetSMBData(outp, NULL);
856 if (secBlobOutLength) {
857 memcpy(tp, secBlobOut, secBlobOutLength);
859 tp += secBlobOutLength;
861 memcpy(tp,smb_ServerOS,smb_ServerOSLength);
862 tp += smb_ServerOSLength;
863 memcpy(tp,smb_ServerLanManager,smb_ServerLanManagerLength);
864 tp += smb_ServerLanManagerLength;
865 memcpy(tp,smb_ServerDomainName,smb_ServerDomainNameLength);
866 tp += smb_ServerDomainNameLength;
868 smb_SetSMBDataLength(outp, 0);
871 if (smb_authType == SMB_AUTH_EXTENDED) {
872 smb_SetSMBDataLength(outp, smb_ServerOSLength + smb_ServerLanManagerLength + smb_ServerDomainNameLength);
873 tp = smb_GetSMBData(outp, NULL);
874 memcpy(tp,smb_ServerOS,smb_ServerOSLength);
875 tp += smb_ServerOSLength;
876 memcpy(tp,smb_ServerLanManager,smb_ServerLanManagerLength);
877 tp += smb_ServerLanManagerLength;
878 memcpy(tp,smb_ServerDomainName,smb_ServerDomainNameLength);
879 tp += smb_ServerDomainNameLength;
881 smb_SetSMBDataLength(outp, 0);
888 long smb_ReceiveV3UserLogoffX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
892 /* don't get tokens from this VC */
893 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
895 inp->flags |= SMB_PACKETFLAG_PROFILE_UPDATE_OK;
897 /* find the tree and free it */
898 uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
899 /* TODO: smb_ReleaseUID() ? */
901 char *s1 = NULL, *s2 = NULL;
903 if (s2 == NULL) s2 = " ";
904 if (s1 == NULL) {s1 = s2; s2 = " ";}
906 osi_Log4(smb_logp, "SMB3 user logoffX uid %d name %s%s%s", uidp->userID,
907 osi_LogSaveString(smb_logp, (uidp->unp) ? uidp->unp->name: " "), s1, s2);
909 lock_ObtainMutex(&uidp->mx);
910 uidp->flags |= SMB_USERFLAG_DELETE;
912 * it doesn't get deleted right away
913 * because the vcp points to it
915 lock_ReleaseMutex(&uidp->mx);
918 osi_Log0(smb_logp, "SMB3 user logoffX");
920 smb_SetSMBDataLength(outp, 0);
924 #define SMB_SUPPORT_SEARCH_BITS 0x0001
926 long smb_ReceiveV3TreeConnectX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
930 unsigned short newTid;
941 osi_Log0(smb_logp, "SMB3 receive tree connect");
943 /* parse input parameters */
944 tp = smb_GetSMBData(inp, NULL);
945 passwordp = smb_ParseString(tp, &tp);
946 pathp = smb_ParseString(tp, &tp);
947 servicep = smb_ParseString(tp, &tp);
949 tp = strrchr(pathp, '\\');
951 return CM_ERROR_BADSMB;
953 strcpy(shareName, tp+1);
955 osi_Log2(smb_logp, "Tree connect pathp[%s] shareName[%s]",
956 osi_LogSaveString(smb_logp, pathp),
957 osi_LogSaveString(smb_logp, shareName));
959 if (strcmp(servicep, "IPC") == 0 || strcmp(shareName, "IPC$") == 0) {
961 osi_Log0(smb_logp, "TreeConnectX connecting to IPC$");
964 return CM_ERROR_NOIPC;
968 userp = smb_GetUser(vcp, inp);
970 lock_ObtainMutex(&vcp->mx);
971 newTid = vcp->tidCounter++;
972 lock_ReleaseMutex(&vcp->mx);
974 tidp = smb_FindTID(vcp, newTid, SMB_FLAG_CREATE);
977 uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
978 shareFound = smb_FindShare(vcp, uidp, shareName, &sharePath);
980 smb_ReleaseUID(uidp);
982 smb_ReleaseTID(tidp);
983 return CM_ERROR_BADSHARENAME;
986 if (vcp->flags & SMB_VCFLAG_USENT)
988 int policy = smb_FindShareCSCPolicy(shareName);
989 smb_SetSMBParm(outp, 2, SMB_SUPPORT_SEARCH_BITS | (policy << 2));
992 smb_SetSMBParm(outp, 2, 0);
996 lock_ObtainMutex(&tidp->mx);
998 tidp->pathname = sharePath;
999 if(ipc) tidp->flags |= SMB_TIDFLAG_IPC;
1000 lock_ReleaseMutex(&tidp->mx);
1001 smb_ReleaseTID(tidp);
1003 ((smb_t *)outp)->tid = newTid;
1004 ((smb_t *)inp)->tid = newTid;
1005 tp = smb_GetSMBData(outp, NULL);
1010 smb_SetSMBDataLength(outp, 3);
1013 smb_SetSMBDataLength(outp, 4);
1016 osi_Log1(smb_logp, "SMB3 tree connect created ID %d", newTid);
1020 /* must be called with global tran lock held */
1021 smb_tran2Packet_t *smb_FindTran2Packet(smb_vc_t *vcp, smb_packet_t *inp)
1023 smb_tran2Packet_t *tp;
1026 smbp = (smb_t *) inp->data;
1027 for (tp = smb_tran2AssemblyQueuep; tp; tp = (smb_tran2Packet_t *) osi_QNext(&tp->q)) {
1028 if (tp->vcp == vcp && tp->mid == smbp->mid && tp->tid == smbp->tid)
1034 smb_tran2Packet_t *smb_NewTran2Packet(smb_vc_t *vcp, smb_packet_t *inp,
1035 int totalParms, int totalData)
1037 smb_tran2Packet_t *tp;
1040 smbp = (smb_t *) inp->data;
1041 tp = malloc(sizeof(*tp));
1042 memset(tp, 0, sizeof(*tp));
1045 tp->curData = tp->curParms = 0;
1046 tp->totalData = totalData;
1047 tp->totalParms = totalParms;
1048 tp->tid = smbp->tid;
1049 tp->mid = smbp->mid;
1050 tp->uid = smbp->uid;
1051 tp->pid = smbp->pid;
1052 tp->res[0] = smbp->res[0];
1053 osi_QAdd((osi_queue_t **)&smb_tran2AssemblyQueuep, &tp->q);
1054 if (totalParms != 0)
1055 tp->parmsp = malloc(totalParms);
1057 tp->datap = malloc(totalData);
1058 if (smbp->com == 0x25 || smbp->com == 0x26)
1061 tp->opcode = smb_GetSMBParm(inp, 14);
1064 tp->flags |= SMB_TRAN2PFLAG_ALLOC;
1068 smb_tran2Packet_t *smb_GetTran2ResponsePacket(smb_vc_t *vcp,
1069 smb_tran2Packet_t *inp, smb_packet_t *outp,
1070 int totalParms, int totalData)
1072 smb_tran2Packet_t *tp;
1073 unsigned short parmOffset;
1074 unsigned short dataOffset;
1075 unsigned short dataAlign;
1077 tp = malloc(sizeof(*tp));
1078 memset(tp, 0, sizeof(*tp));
1080 tp->curData = tp->curParms = 0;
1081 tp->totalData = totalData;
1082 tp->totalParms = totalParms;
1083 tp->oldTotalParms = totalParms;
1088 tp->res[0] = inp->res[0];
1089 tp->opcode = inp->opcode;
1093 * We calculate where the parameters and data will start.
1094 * This calculation must parallel the calculation in
1095 * smb_SendTran2Packet.
1098 parmOffset = 10*2 + 35;
1099 parmOffset++; /* round to even */
1100 tp->parmsp = (unsigned short *) (outp->data + parmOffset);
1102 dataOffset = parmOffset + totalParms;
1103 dataAlign = dataOffset & 2; /* quad-align */
1104 dataOffset += dataAlign;
1105 tp->datap = outp->data + dataOffset;
1110 /* free a tran2 packet; must be called with smb_globalLock held */
1111 void smb_FreeTran2Packet(smb_tran2Packet_t *t2p)
1113 if (t2p->vcp) smb_ReleaseVC(t2p->vcp);
1114 if (t2p->flags & SMB_TRAN2PFLAG_ALLOC) {
1123 /* called with a VC, an input packet to respond to, and an error code.
1124 * sends an error response.
1126 void smb_SendTran2Error(smb_vc_t *vcp, smb_tran2Packet_t *t2p,
1127 smb_packet_t *tp, long code)
1130 unsigned short errCode;
1131 unsigned char errClass;
1132 unsigned long NTStatus;
1134 if (vcp->flags & SMB_VCFLAG_STATUS32)
1135 smb_MapNTError(code, &NTStatus);
1137 smb_MapCoreError(code, vcp, &errCode, &errClass);
1139 smb_FormatResponsePacket(vcp, NULL, tp);
1140 smbp = (smb_t *) tp;
1142 /* We can handle long names */
1143 if (vcp->flags & SMB_VCFLAG_USENT)
1144 smbp->flg2 |= 0x40; /* IS_LONG_NAME */
1146 /* now copy important fields from the tran 2 packet */
1147 smbp->com = t2p->com;
1148 smbp->tid = t2p->tid;
1149 smbp->mid = t2p->mid;
1150 smbp->pid = t2p->pid;
1151 smbp->uid = t2p->uid;
1152 smbp->res[0] = t2p->res[0];
1153 if (vcp->flags & SMB_VCFLAG_STATUS32) {
1154 smbp->rcls = (unsigned char) (NTStatus & 0xff);
1155 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
1156 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
1157 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
1158 smbp->flg2 |= 0x4000;
1161 smbp->rcls = errClass;
1162 smbp->errLow = (unsigned char) (errCode & 0xff);
1163 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
1167 smb_SendPacket(vcp, tp);
1170 void smb_SendTran2Packet(smb_vc_t *vcp, smb_tran2Packet_t *t2p, smb_packet_t *tp)
1173 unsigned short parmOffset;
1174 unsigned short dataOffset;
1175 unsigned short totalLength;
1176 unsigned short dataAlign;
1179 smb_FormatResponsePacket(vcp, NULL, tp);
1180 smbp = (smb_t *) tp;
1182 /* We can handle long names */
1183 if (vcp->flags & SMB_VCFLAG_USENT)
1184 smbp->flg2 |= 0x40; /* IS_LONG_NAME */
1186 /* now copy important fields from the tran 2 packet */
1187 smbp->com = t2p->com;
1188 smbp->tid = t2p->tid;
1189 smbp->mid = t2p->mid;
1190 smbp->pid = t2p->pid;
1191 smbp->uid = t2p->uid;
1192 smbp->res[0] = t2p->res[0];
1194 totalLength = 1 + t2p->totalData + t2p->totalParms;
1196 /* now add the core parameters (tran2 info) to the packet */
1197 smb_SetSMBParm(tp, 0, t2p->totalParms); /* parm bytes */
1198 smb_SetSMBParm(tp, 1, t2p->totalData); /* data bytes */
1199 smb_SetSMBParm(tp, 2, 0); /* reserved */
1200 smb_SetSMBParm(tp, 3, t2p->totalParms); /* parm bytes in this packet */
1201 parmOffset = 10*2 + 35; /* parm offset in packet */
1202 parmOffset++; /* round to even */
1203 smb_SetSMBParm(tp, 4, parmOffset); /* 11 parm words plus *
1204 * hdr, bcc and wct */
1205 smb_SetSMBParm(tp, 5, 0); /* parm displacement */
1206 smb_SetSMBParm(tp, 6, t2p->totalData); /* data in this packet */
1207 dataOffset = parmOffset + t2p->oldTotalParms;
1208 dataAlign = dataOffset & 2; /* quad-align */
1209 dataOffset += dataAlign;
1210 smb_SetSMBParm(tp, 7, dataOffset); /* offset of data */
1211 smb_SetSMBParm(tp, 8, 0); /* data displacement */
1212 smb_SetSMBParm(tp, 9, 0); /* low: setup word count *
1215 datap = smb_GetSMBData(tp, NULL);
1216 *datap++ = 0; /* we rounded to even */
1218 totalLength += dataAlign;
1219 smb_SetSMBDataLength(tp, totalLength);
1221 /* next, send the datagram */
1222 smb_SendPacket(vcp, tp);
1225 long smb_ReceiveV3Trans(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
1227 smb_tran2Packet_t *asp;
1240 /* We sometimes see 0 word count. What to do? */
1241 if (*inp->wctp == 0) {
1246 osi_Log0(smb_logp, "TRANSACTION word count = 0");
1248 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
1249 ptbuf[0] = "Transaction2 word count = 0";
1250 ReportEvent(h, EVENTLOG_WARNING_TYPE, 0, 1003, NULL,
1251 1, inp->ncb_length, ptbuf, inp);
1252 DeregisterEventSource(h);
1254 osi_Log0(smb_logp, "TRANSACTION word count = 0");
1257 smb_SetSMBDataLength(outp, 0);
1258 smb_SendPacket(vcp, outp);
1262 totalParms = smb_GetSMBParm(inp, 0);
1263 totalData = smb_GetSMBParm(inp, 1);
1265 firstPacket = (inp->inCom == 0x25);
1267 /* find the packet we're reassembling */
1268 lock_ObtainWrite(&smb_globalLock);
1269 asp = smb_FindTran2Packet(vcp, inp);
1271 asp = smb_NewTran2Packet(vcp, inp, totalParms, totalData);
1273 lock_ReleaseWrite(&smb_globalLock);
1275 /* now merge in this latest packet; start by looking up offsets */
1277 parmDisp = dataDisp = 0;
1278 parmOffset = smb_GetSMBParm(inp, 10);
1279 dataOffset = smb_GetSMBParm(inp, 12);
1280 parmCount = smb_GetSMBParm(inp, 9);
1281 dataCount = smb_GetSMBParm(inp, 11);
1282 asp->maxReturnParms = smb_GetSMBParm(inp, 2);
1283 asp->maxReturnData = smb_GetSMBParm(inp, 3);
1285 osi_Log3(smb_logp, "SMB3 received Trans init packet total data %d, cur data %d, max return data %d",
1286 totalData, dataCount, asp->maxReturnData);
1289 parmDisp = smb_GetSMBParm(inp, 4);
1290 parmOffset = smb_GetSMBParm(inp, 3);
1291 dataDisp = smb_GetSMBParm(inp, 7);
1292 dataOffset = smb_GetSMBParm(inp, 6);
1293 parmCount = smb_GetSMBParm(inp, 2);
1294 dataCount = smb_GetSMBParm(inp, 5);
1296 osi_Log2(smb_logp, "SMB3 received Trans aux packet parms %d, data %d",
1297 parmCount, dataCount);
1300 /* now copy the parms and data */
1301 if ( asp->totalParms > 0 && parmCount != 0 )
1303 memcpy(((char *)asp->parmsp) + parmDisp, inp->data + parmOffset, parmCount);
1305 if ( asp->totalData > 0 && dataCount != 0 ) {
1306 memcpy(asp->datap + dataDisp, inp->data + dataOffset, dataCount);
1309 /* account for new bytes */
1310 asp->curData += dataCount;
1311 asp->curParms += parmCount;
1313 /* finally, if we're done, remove the packet from the queue and dispatch it */
1314 if (asp->totalParms > 0 &&
1315 asp->curParms > 0 &&
1316 asp->totalData <= asp->curData &&
1317 asp->totalParms <= asp->curParms) {
1318 /* we've received it all */
1319 lock_ObtainWrite(&smb_globalLock);
1320 osi_QRemove((osi_queue_t **) &smb_tran2AssemblyQueuep, &asp->q);
1321 lock_ReleaseWrite(&smb_globalLock);
1323 /* now dispatch it */
1324 rapOp = asp->parmsp[0];
1326 if ( rapOp >= 0 && rapOp < SMB_RAP_NOPCODES && smb_rapDispatchTable[rapOp].procp) {
1327 osi_LogEvent("AFS-Dispatch-RAP[%s]",myCrt_RapDispatch(rapOp),"vcp[%x] lana[%d] lsn[%d]",(int)vcp,vcp->lana,vcp->lsn);
1328 osi_Log4(smb_logp,"AFS Server - Dispatch-RAP %s vcp[%x] lana[%d] lsn[%d]",myCrt_RapDispatch(rapOp),vcp,vcp->lana,vcp->lsn);
1329 code = (*smb_rapDispatchTable[rapOp].procp)(vcp, asp, outp);
1332 osi_LogEvent("AFS-Dispatch-RAP [invalid]", NULL, "op[%x] vcp[%x] lana[%d] lsn[%d]", rapOp, vcp, vcp->lana, vcp->lsn);
1333 osi_Log4(smb_logp,"AFS Server - Dispatch-RAP [INVALID] op[%x] vcp[%x] lana[%d] lsn[%d]", rapOp, vcp, vcp->lana, vcp->lsn);
1334 code = CM_ERROR_BADOP;
1337 /* if an error is returned, we're supposed to send an error packet,
1338 * otherwise the dispatched function already did the data sending.
1339 * We give dispatched proc the responsibility since it knows how much
1340 * space to allocate.
1343 smb_SendTran2Error(vcp, asp, outp, code);
1346 /* free the input tran 2 packet */
1347 lock_ObtainWrite(&smb_globalLock);
1348 smb_FreeTran2Packet(asp);
1349 lock_ReleaseWrite(&smb_globalLock);
1351 else if (firstPacket) {
1352 /* the first packet in a multi-packet request, we need to send an
1353 * ack to get more data.
1355 smb_SetSMBDataLength(outp, 0);
1356 smb_SendPacket(vcp, outp);
1362 /* ANSI versions. The unicode versions support arbitrary length
1363 share names, but we don't support unicode yet. */
1365 typedef struct smb_rap_share_info_0 {
1366 char shi0_netname[13];
1367 } smb_rap_share_info_0_t;
1369 typedef struct smb_rap_share_info_1 {
1370 char shi1_netname[13];
1373 DWORD shi1_remark; /* char *shi1_remark; data offset */
1374 } smb_rap_share_info_1_t;
1376 typedef struct smb_rap_share_info_2 {
1377 char shi2_netname[13];
1379 unsigned short shi2_type;
1380 DWORD shi2_remark; /* char *shi2_remark; data offset */
1381 unsigned short shi2_permissions;
1382 unsigned short shi2_max_uses;
1383 unsigned short shi2_current_uses;
1384 DWORD shi2_path; /* char *shi2_path; data offset */
1385 unsigned short shi2_passwd[9];
1386 unsigned short shi2_pad2;
1387 } smb_rap_share_info_2_t;
1389 #define SMB_RAP_MAX_SHARES 512
1391 typedef struct smb_rap_share_list {
1394 smb_rap_share_info_0_t * shares;
1395 } smb_rap_share_list_t;
1397 int smb_rapCollectSharesProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp) {
1398 smb_rap_share_list_t * sp;
1403 if (name[0] == '.' && (!name[1] || (name[1] == '.' && !name[2])))
1404 return 0; /* skip over '.' and '..' */
1406 sp = (smb_rap_share_list_t *) vrockp;
1408 strncpy(sp->shares[sp->cShare].shi0_netname, name, 12);
1409 sp->shares[sp->cShare].shi0_netname[12] = 0;
1413 if (sp->cShare >= sp->maxShares)
1414 return CM_ERROR_STOPNOW;
1419 long smb_ReceiveRAPNetShareEnum(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1421 smb_tran2Packet_t *outp;
1422 unsigned short * tp;
1426 int outParmsTotal; /* total parameter bytes */
1427 int outDataTotal; /* total data bytes */
1435 HKEY hkSubmount = NULL;
1436 smb_rap_share_info_1_t * shares;
1439 char thisShare[256];
1442 smb_rap_share_list_t rootShares;
1447 tp = p->parmsp + 1; /* skip over function number (always 0) */
1448 (void) smb_ParseString((char *) tp, (char **) &tp); /* skip over parm descriptor */
1449 (void) smb_ParseString((char *) tp, (char **) &tp); /* skip over data descriptor */
1453 if (infoLevel != 1) {
1454 return CM_ERROR_INVAL;
1457 /* first figure out how many shares there are */
1458 rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSConfigKeyName, 0,
1459 KEY_QUERY_VALUE, &hkParam);
1460 if (rv == ERROR_SUCCESS) {
1461 len = sizeof(allSubmount);
1462 rv = RegQueryValueEx(hkParam, "AllSubmount", NULL, NULL,
1463 (BYTE *) &allSubmount, &len);
1464 if (rv != ERROR_SUCCESS || allSubmount != 0) {
1467 RegCloseKey (hkParam);
1470 rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SOFTWARE\\OpenAFS\\Client\\Submounts",
1471 0, KEY_QUERY_VALUE, &hkSubmount);
1472 if (rv == ERROR_SUCCESS) {
1473 rv = RegQueryInfoKey(hkSubmount, NULL, NULL, NULL, NULL,
1474 NULL, NULL, &nRegShares, NULL, NULL, NULL, NULL);
1475 if (rv != ERROR_SUCCESS)
1481 /* fetch the root shares */
1482 rootShares.maxShares = SMB_RAP_MAX_SHARES;
1483 rootShares.cShare = 0;
1484 rootShares.shares = malloc( sizeof(smb_rap_share_info_0_t) * SMB_RAP_MAX_SHARES );
1488 userp = smb_GetTran2User(vcp,p);
1490 thyper.HighPart = 0;
1493 cm_HoldSCache(cm_rootSCachep);
1494 cm_ApplyDir(cm_rootSCachep, smb_rapCollectSharesProc, &rootShares, &thyper, userp, &req, NULL);
1495 cm_ReleaseSCache(cm_rootSCachep);
1497 cm_ReleaseUser(userp);
1499 nShares = rootShares.cShare + nRegShares + allSubmount;
1501 #define REMARK_LEN 1
1502 outParmsTotal = 8; /* 4 dwords */
1503 outDataTotal = (sizeof(smb_rap_share_info_1_t) + REMARK_LEN) * nShares ;
1504 if(outDataTotal > bufsize) {
1505 nSharesRet = bufsize / (sizeof(smb_rap_share_info_1_t) + REMARK_LEN);
1506 outDataTotal = (sizeof(smb_rap_share_info_1_t) + REMARK_LEN) * nSharesRet;
1509 nSharesRet = nShares;
1512 outp = smb_GetTran2ResponsePacket(vcp, p, op, outParmsTotal, outDataTotal);
1514 /* now for the submounts */
1515 shares = (smb_rap_share_info_1_t *) outp->datap;
1516 cstrp = outp->datap + sizeof(smb_rap_share_info_1_t) * nSharesRet;
1518 memset(outp->datap, 0, (sizeof(smb_rap_share_info_1_t) + REMARK_LEN) * nSharesRet);
1521 strcpy( shares[cshare].shi1_netname, "all" );
1522 shares[cshare].shi1_remark = cstrp - outp->datap;
1523 /* type and pad are zero already */
1529 for (i=0; i < nRegShares && cshare < nSharesRet; i++) {
1530 len = sizeof(thisShare);
1531 rv = RegEnumValue(hkSubmount, i, thisShare, &len, NULL, NULL, NULL, NULL);
1532 if (rv == ERROR_SUCCESS && strlen(thisShare) && (!allSubmount || stricmp(thisShare,"all"))) {
1533 strncpy(shares[cshare].shi1_netname, thisShare, sizeof(shares->shi1_netname)-1);
1534 shares[cshare].shi1_netname[sizeof(shares->shi1_netname)-1] = 0; /* unfortunate truncation */
1535 shares[cshare].shi1_remark = cstrp - outp->datap;
1540 nShares--; /* uncount key */
1543 RegCloseKey(hkSubmount);
1546 nonrootShares = cshare;
1548 for (i=0; i < rootShares.cShare && cshare < nSharesRet; i++) {
1549 /* in case there are collisions with submounts, submounts have higher priority */
1550 for (j=0; j < nonrootShares; j++)
1551 if (!stricmp(shares[j].shi1_netname, rootShares.shares[i].shi0_netname))
1554 if (j < nonrootShares) {
1555 nShares--; /* uncount */
1559 strcpy(shares[cshare].shi1_netname, rootShares.shares[i].shi0_netname);
1560 shares[cshare].shi1_remark = cstrp - outp->datap;
1565 outp->parmsp[0] = ((cshare == nShares)? ERROR_SUCCESS : ERROR_MORE_DATA);
1566 outp->parmsp[1] = 0;
1567 outp->parmsp[2] = cshare;
1568 outp->parmsp[3] = nShares;
1570 outp->totalData = cstrp - outp->datap;
1571 outp->totalParms = outParmsTotal;
1573 smb_SendTran2Packet(vcp, outp, op);
1574 smb_FreeTran2Packet(outp);
1576 free(rootShares.shares);
1581 long smb_ReceiveRAPNetShareGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1583 smb_tran2Packet_t *outp;
1584 unsigned short * tp;
1586 BOOL shareFound = FALSE;
1587 unsigned short infoLevel;
1588 unsigned short bufsize;
1598 tp = p->parmsp + 1; /* skip over function number (always 1) */
1599 (void) smb_ParseString( (char *) tp, (char **) &tp); /* skip over param descriptor */
1600 (void) smb_ParseString( (char *) tp, (char **) &tp); /* skip over data descriptor */
1601 shareName = smb_ParseString( (char *) tp, (char **) &tp);
1608 totalData = sizeof(smb_rap_share_info_0_t);
1609 else if(infoLevel == 1)
1610 totalData = sizeof(smb_rap_share_info_1_t) + 1; /* + empty string */
1611 else if(infoLevel == 2)
1612 totalData = sizeof(smb_rap_share_info_2_t) + 2; /* + two empty strings */
1614 return CM_ERROR_INVAL;
1616 outp = smb_GetTran2ResponsePacket(vcp, p, op, totalParam, totalData);
1618 if(!stricmp(shareName,"all")) {
1619 rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSConfigKeyName, 0,
1620 KEY_QUERY_VALUE, &hkParam);
1621 if (rv == ERROR_SUCCESS) {
1622 len = sizeof(allSubmount);
1623 rv = RegQueryValueEx(hkParam, "AllSubmount", NULL, NULL,
1624 (BYTE *) &allSubmount, &len);
1625 if (rv != ERROR_SUCCESS || allSubmount != 0) {
1628 RegCloseKey (hkParam);
1635 rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SOFTWARE\\OpenAFS\\Client\\Submounts", 0,
1636 KEY_QUERY_VALUE, &hkSubmount);
1637 if (rv == ERROR_SUCCESS) {
1638 rv = RegQueryValueEx(hkSubmount, shareName, NULL, NULL, NULL, NULL);
1639 if (rv == ERROR_SUCCESS) {
1642 RegCloseKey(hkSubmount);
1647 smb_FreeTran2Packet(outp);
1648 return CM_ERROR_BADSHARENAME;
1651 memset(outp->datap, 0, totalData);
1653 outp->parmsp[0] = 0;
1654 outp->parmsp[1] = 0;
1655 outp->parmsp[2] = totalData;
1657 if (infoLevel == 0) {
1658 smb_rap_share_info_0_t * info = (smb_rap_share_info_0_t *) outp->datap;
1659 strncpy(info->shi0_netname, shareName, sizeof(info->shi0_netname)-1);
1660 info->shi0_netname[sizeof(info->shi0_netname)-1] = 0;
1661 } else if(infoLevel == 1) {
1662 smb_rap_share_info_1_t * info = (smb_rap_share_info_1_t *) outp->datap;
1663 strncpy(info->shi1_netname, shareName, sizeof(info->shi1_netname)-1);
1664 info->shi1_netname[sizeof(info->shi1_netname)-1] = 0;
1665 info->shi1_remark = ((unsigned char *) (info + 1)) - outp->datap;
1666 /* type and pad are already zero */
1667 } else { /* infoLevel==2 */
1668 smb_rap_share_info_2_t * info = (smb_rap_share_info_2_t *) outp->datap;
1669 strncpy(info->shi2_netname, shareName, sizeof(info->shi2_netname)-1);
1670 info->shi2_netname[sizeof(info->shi2_netname)-1] = 0;
1671 info->shi2_remark = ((unsigned char *) (info + 1)) - outp->datap;
1672 info->shi2_permissions = ACCESS_ALL;
1673 info->shi2_max_uses = (unsigned short) -1;
1674 info->shi2_path = 1 + (((unsigned char *) (info + 1)) - outp->datap);
1677 outp->totalData = totalData;
1678 outp->totalParms = totalParam;
1680 smb_SendTran2Packet(vcp, outp, op);
1681 smb_FreeTran2Packet(outp);
1686 typedef struct smb_rap_wksta_info_10 {
1687 DWORD wki10_computername; /*char *wki10_computername;*/
1688 DWORD wki10_username; /* char *wki10_username; */
1689 DWORD wki10_langroup; /* char *wki10_langroup;*/
1690 unsigned char wki10_ver_major;
1691 unsigned char wki10_ver_minor;
1692 DWORD wki10_logon_domain; /*char *wki10_logon_domain;*/
1693 DWORD wki10_oth_domains; /* char *wki10_oth_domains;*/
1694 } smb_rap_wksta_info_10_t;
1697 long smb_ReceiveRAPNetWkstaGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1699 smb_tran2Packet_t *outp;
1703 unsigned short * tp;
1706 smb_rap_wksta_info_10_t * info;
1710 tp = p->parmsp + 1; /* Skip over function number */
1711 (void) smb_ParseString((unsigned char*) tp, (char **) &tp); /* skip over param descriptor */
1712 (void) smb_ParseString((unsigned char*) tp, (char **) &tp); /* skip over data descriptor */
1716 if (infoLevel != 10) {
1717 return CM_ERROR_INVAL;
1723 totalData = sizeof(*info) + /* info */
1724 MAX_COMPUTERNAME_LENGTH + /* wki10_computername */
1725 SMB_MAX_USERNAME_LENGTH + /* wki10_username */
1726 MAX_COMPUTERNAME_LENGTH + /* wki10_langroup */
1727 MAX_COMPUTERNAME_LENGTH + /* wki10_logon_domain */
1728 1; /* wki10_oth_domains (null)*/
1730 outp = smb_GetTran2ResponsePacket(vcp, p, op, totalParams, totalData);
1732 memset(outp->parmsp,0,totalParams);
1733 memset(outp->datap,0,totalData);
1735 info = (smb_rap_wksta_info_10_t *) outp->datap;
1736 cstrp = (char *) (info + 1);
1738 info->wki10_computername = (DWORD) (cstrp - outp->datap);
1739 strcpy(cstrp, smb_localNamep);
1740 cstrp += strlen(cstrp) + 1;
1742 info->wki10_username = (DWORD) (cstrp - outp->datap);
1743 uidp = smb_FindUID(vcp, p->uid, 0);
1745 lock_ObtainMutex(&uidp->mx);
1746 if(uidp->unp && uidp->unp->name)
1747 strcpy(cstrp, uidp->unp->name);
1748 lock_ReleaseMutex(&uidp->mx);
1749 smb_ReleaseUID(uidp);
1751 cstrp += strlen(cstrp) + 1;
1753 info->wki10_langroup = (DWORD) (cstrp - outp->datap);
1754 strcpy(cstrp, "WORKGROUP");
1755 cstrp += strlen(cstrp) + 1;
1757 /* TODO: Not sure what values these should take, but these work */
1758 info->wki10_ver_major = 5;
1759 info->wki10_ver_minor = 1;
1761 info->wki10_logon_domain = (DWORD) (cstrp - outp->datap);
1762 strcpy(cstrp, smb_ServerDomainName);
1763 cstrp += strlen(cstrp) + 1;
1765 info->wki10_oth_domains = (DWORD) (cstrp - outp->datap);
1766 cstrp ++; /* no other domains */
1768 outp->totalData = (unsigned short) (cstrp - outp->datap); /* actual data size */
1769 outp->parmsp[2] = outp->totalData;
1770 outp->totalParms = totalParams;
1772 smb_SendTran2Packet(vcp,outp,op);
1773 smb_FreeTran2Packet(outp);
1778 typedef struct smb_rap_server_info_0 {
1780 } smb_rap_server_info_0_t;
1782 typedef struct smb_rap_server_info_1 {
1784 char sv1_version_major;
1785 char sv1_version_minor;
1786 unsigned long sv1_type;
1787 DWORD *sv1_comment_or_master_browser; /* char *sv1_comment_or_master_browser;*/
1788 } smb_rap_server_info_1_t;
1790 char smb_ServerComment[] = "OpenAFS Client";
1791 int smb_ServerCommentLen = sizeof(smb_ServerComment);
1793 #define SMB_SV_TYPE_SERVER 0x00000002L
1794 #define SMB_SV_TYPE_NT 0x00001000L
1795 #define SMB_SV_TYPE_SERVER_NT 0x00008000L
1797 long smb_ReceiveRAPNetServerGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1799 smb_tran2Packet_t *outp;
1803 unsigned short * tp;
1806 smb_rap_server_info_0_t * info0;
1807 smb_rap_server_info_1_t * info1;
1810 tp = p->parmsp + 1; /* Skip over function number */
1811 (void) smb_ParseString((unsigned char*) tp, (char **) &tp); /* skip over param descriptor */
1812 (void) smb_ParseString((unsigned char*) tp, (char **) &tp); /* skip over data descriptor */
1816 if (infoLevel != 0 && infoLevel != 1) {
1817 return CM_ERROR_INVAL;
1823 (infoLevel == 0) ? sizeof(smb_rap_server_info_0_t)
1824 : (sizeof(smb_rap_server_info_1_t) + smb_ServerCommentLen);
1826 outp = smb_GetTran2ResponsePacket(vcp, p, op, totalParams, totalData);
1828 memset(outp->parmsp,0,totalParams);
1829 memset(outp->datap,0,totalData);
1831 if (infoLevel == 0) {
1832 info0 = (smb_rap_server_info_0_t *) outp->datap;
1833 cstrp = (char *) (info0 + 1);
1834 strcpy(info0->sv0_name, "AFS");
1835 } else { /* infoLevel == 1 */
1836 info1 = (smb_rap_server_info_1_t *) outp->datap;
1837 cstrp = (char *) (info1 + 1);
1838 strcpy(info1->sv1_name, "AFS");
1841 SMB_SV_TYPE_SERVER |
1843 SMB_SV_TYPE_SERVER_NT;
1845 info1->sv1_version_major = 5;
1846 info1->sv1_version_minor = 1;
1847 info1->sv1_comment_or_master_browser = (DWORD *) (cstrp - outp->datap);
1849 strcpy(cstrp, smb_ServerComment);
1851 cstrp += smb_ServerCommentLen;
1854 totalData = cstrp - outp->datap;
1855 outp->totalData = min(bufsize,totalData); /* actual data size */
1856 outp->parmsp[0] = (outp->totalData == totalData)? 0 : ERROR_MORE_DATA;
1857 outp->parmsp[2] = totalData;
1858 outp->totalParms = totalParams;
1860 smb_SendTran2Packet(vcp,outp,op);
1861 smb_FreeTran2Packet(outp);
1866 long smb_ReceiveV3Tran2A(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
1868 smb_tran2Packet_t *asp;
1880 /* We sometimes see 0 word count. What to do? */
1881 if (*inp->wctp == 0) {
1886 osi_Log0(smb_logp, "TRANSACTION2 word count = 0");
1888 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
1889 ptbuf[0] = "Transaction2 word count = 0";
1890 ReportEvent(h, EVENTLOG_WARNING_TYPE, 0, 1003, NULL,
1891 1, inp->ncb_length, ptbuf, inp);
1892 DeregisterEventSource(h);
1894 osi_Log0(smb_logp, "TRANSACTION2 word count = 0");
1897 smb_SetSMBDataLength(outp, 0);
1898 smb_SendPacket(vcp, outp);
1902 totalParms = smb_GetSMBParm(inp, 0);
1903 totalData = smb_GetSMBParm(inp, 1);
1905 firstPacket = (inp->inCom == 0x32);
1907 /* find the packet we're reassembling */
1908 lock_ObtainWrite(&smb_globalLock);
1909 asp = smb_FindTran2Packet(vcp, inp);
1911 asp = smb_NewTran2Packet(vcp, inp, totalParms, totalData);
1913 lock_ReleaseWrite(&smb_globalLock);
1915 /* now merge in this latest packet; start by looking up offsets */
1917 parmDisp = dataDisp = 0;
1918 parmOffset = smb_GetSMBParm(inp, 10);
1919 dataOffset = smb_GetSMBParm(inp, 12);
1920 parmCount = smb_GetSMBParm(inp, 9);
1921 dataCount = smb_GetSMBParm(inp, 11);
1922 asp->maxReturnParms = smb_GetSMBParm(inp, 2);
1923 asp->maxReturnData = smb_GetSMBParm(inp, 3);
1925 osi_Log3(smb_logp, "SMB3 received T2 init packet total data %d, cur data %d, max return data %d",
1926 totalData, dataCount, asp->maxReturnData);
1929 parmDisp = smb_GetSMBParm(inp, 4);
1930 parmOffset = smb_GetSMBParm(inp, 3);
1931 dataDisp = smb_GetSMBParm(inp, 7);
1932 dataOffset = smb_GetSMBParm(inp, 6);
1933 parmCount = smb_GetSMBParm(inp, 2);
1934 dataCount = smb_GetSMBParm(inp, 5);
1936 osi_Log2(smb_logp, "SMB3 received T2 aux packet parms %d, data %d",
1937 parmCount, dataCount);
1940 /* now copy the parms and data */
1941 if ( asp->totalParms > 0 && parmCount != 0 )
1943 memcpy(((char *)asp->parmsp) + parmDisp, inp->data + parmOffset, parmCount);
1945 if ( asp->totalData > 0 && dataCount != 0 ) {
1946 memcpy(asp->datap + dataDisp, inp->data + dataOffset, dataCount);
1949 /* account for new bytes */
1950 asp->curData += dataCount;
1951 asp->curParms += parmCount;
1953 /* finally, if we're done, remove the packet from the queue and dispatch it */
1954 if (asp->totalParms > 0 &&
1955 asp->curParms > 0 &&
1956 asp->totalData <= asp->curData &&
1957 asp->totalParms <= asp->curParms) {
1958 /* we've received it all */
1959 lock_ObtainWrite(&smb_globalLock);
1960 osi_QRemove((osi_queue_t **) &smb_tran2AssemblyQueuep, &asp->q);
1961 lock_ReleaseWrite(&smb_globalLock);
1963 /* now dispatch it */
1964 if ( asp->opcode >= 0 && asp->opcode < 20 && smb_tran2DispatchTable[asp->opcode].procp) {
1965 osi_LogEvent("AFS-Dispatch-2[%s]",myCrt_2Dispatch(asp->opcode),"vcp[%x] lana[%d] lsn[%d]",(int)vcp,vcp->lana,vcp->lsn);
1966 osi_Log4(smb_logp,"AFS Server - Dispatch-2 %s vcp[%x] lana[%d] lsn[%d]",myCrt_2Dispatch(asp->opcode),vcp,vcp->lana,vcp->lsn);
1967 code = (*smb_tran2DispatchTable[asp->opcode].procp)(vcp, asp, outp);
1970 osi_LogEvent("AFS-Dispatch-2 [invalid]", NULL, "op[%x] vcp[%x] lana[%d] lsn[%d]", asp->opcode, vcp, vcp->lana, vcp->lsn);
1971 osi_Log4(smb_logp,"AFS Server - Dispatch-2 [INVALID] op[%x] vcp[%x] lana[%d] lsn[%d]", asp->opcode, vcp, vcp->lana, vcp->lsn);
1972 code = CM_ERROR_BADOP;
1975 /* if an error is returned, we're supposed to send an error packet,
1976 * otherwise the dispatched function already did the data sending.
1977 * We give dispatched proc the responsibility since it knows how much
1978 * space to allocate.
1981 smb_SendTran2Error(vcp, asp, outp, code);
1984 /* free the input tran 2 packet */
1985 lock_ObtainWrite(&smb_globalLock);
1986 smb_FreeTran2Packet(asp);
1987 lock_ReleaseWrite(&smb_globalLock);
1989 else if (firstPacket) {
1990 /* the first packet in a multi-packet request, we need to send an
1991 * ack to get more data.
1993 smb_SetSMBDataLength(outp, 0);
1994 smb_SendPacket(vcp, outp);
2000 long smb_ReceiveTran2Open(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
2003 smb_tran2Packet_t *outp;
2008 cm_scache_t *dscp; /* dir we're dealing with */
2009 cm_scache_t *scp; /* file we're creating */
2011 int initialModeBits;
2021 int parmSlot; /* which parm we're dealing with */
2022 long returnEALength;
2030 extraInfo = (p->parmsp[0] & 1); /* return extra info */
2031 returnEALength = (p->parmsp[0] & 8); /* return extended attr length */
2033 openFun = p->parmsp[6]; /* open function */
2034 excl = ((openFun & 3) == 0);
2035 trunc = ((openFun & 3) == 2); /* truncate it */
2036 openMode = (p->parmsp[1] & 0x7);
2037 openAction = 0; /* tracks what we did */
2039 attributes = p->parmsp[3];
2040 dosTime = p->parmsp[4] | (p->parmsp[5] << 16);
2042 /* compute initial mode bits based on read-only flag in attributes */
2043 initialModeBits = 0666;
2044 if (attributes & 1) initialModeBits &= ~0222;
2046 pathp = (char *) (&p->parmsp[14]);
2048 outp = smb_GetTran2ResponsePacket(vcp, p, op, 40, 0);
2050 spacep = cm_GetSpace();
2051 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
2053 if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
2054 /* special case magic file name for receiving IOCTL requests
2055 * (since IOCTL calls themselves aren't getting through).
2057 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
2058 smb_SetupIoctlFid(fidp, spacep);
2060 /* copy out remainder of the parms */
2062 outp->parmsp[parmSlot] = fidp->fid; parmSlot++;
2064 outp->parmsp[parmSlot] = /* attrs */ 0; parmSlot++;
2065 outp->parmsp[parmSlot] = 0; parmSlot++; /* mod time */
2066 outp->parmsp[parmSlot] = 0; parmSlot++;
2067 outp->parmsp[parmSlot] = 0; parmSlot++; /* len */
2068 outp->parmsp[parmSlot] = 0x7fff; parmSlot++;
2069 outp->parmsp[parmSlot] = openMode; parmSlot++;
2070 outp->parmsp[parmSlot] = 0; parmSlot++; /* file type 0 ==> normal file or dir */
2071 outp->parmsp[parmSlot] = 0; parmSlot++; /* IPC junk */
2073 /* and the final "always present" stuff */
2074 outp->parmsp[parmSlot] = /* openAction found existing file */ 1; parmSlot++;
2075 /* next write out the "unique" ID */
2076 outp->parmsp[parmSlot] = 0x1234; parmSlot++;
2077 outp->parmsp[parmSlot] = 0x5678; parmSlot++;
2078 outp->parmsp[parmSlot] = 0; parmSlot++;
2079 if (returnEALength) {
2080 outp->parmsp[parmSlot] = 0; parmSlot++;
2081 outp->parmsp[parmSlot] = 0; parmSlot++;
2084 outp->totalData = 0;
2085 outp->totalParms = parmSlot * 2;
2087 smb_SendTran2Packet(vcp, outp, op);
2089 smb_FreeTran2Packet(outp);
2091 /* and clean up fid reference */
2092 smb_ReleaseFID(fidp);
2096 #ifdef DEBUG_VERBOSE
2098 char *hexp, *asciip;
2099 asciip = (lastNamep ? lastNamep : pathp);
2100 hexp = osi_HexifyString( asciip );
2101 DEBUG_EVENT2("AFS","T2Open H[%s] A[%s]", hexp, asciip);
2106 userp = smb_GetTran2User(vcp, p);
2107 /* In the off chance that userp is NULL, we log and abandon */
2109 osi_Log1(smb_logp, "ReceiveTran2Open user [%d] not resolvable", p->uid);
2110 smb_FreeTran2Packet(outp);
2111 return CM_ERROR_BADSMB;
2114 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
2115 if (code == CM_ERROR_TIDIPC) {
2116 /* Attempt to use TID allocated for IPC. The client is
2117 probably trying to locate DCE RPC end points, which
2118 we don't support. */
2119 osi_Log0(smb_logp, "Tran2Open received IPC TID");
2120 cm_ReleaseUser(userp);
2121 smb_FreeTran2Packet(outp);
2122 return CM_ERROR_NOSUCHPATH;
2126 code = cm_NameI(cm_rootSCachep, pathp,
2127 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
2128 userp, tidPathp, &req, &scp);
2130 code = cm_NameI(cm_rootSCachep, spacep->data,
2131 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
2132 userp, tidPathp, &req, &dscp);
2133 cm_FreeSpace(spacep);
2136 cm_ReleaseUser(userp);
2137 smb_FreeTran2Packet(outp);
2141 /* otherwise, scp points to the parent directory. Do a lookup,
2142 * and truncate the file if we find it, otherwise we create the
2149 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD, userp,
2151 if (code && code != CM_ERROR_NOSUCHFILE) {
2152 cm_ReleaseSCache(dscp);
2153 cm_ReleaseUser(userp);
2154 smb_FreeTran2Packet(outp);
2159 cm_FreeSpace(spacep);
2162 /* if we get here, if code is 0, the file exists and is represented by
2163 * scp. Otherwise, we have to create it.
2166 code = cm_CheckOpen(scp, openMode, trunc, userp, &req);
2168 if (dscp) cm_ReleaseSCache(dscp);
2169 cm_ReleaseSCache(scp);
2170 cm_ReleaseUser(userp);
2171 smb_FreeTran2Packet(outp);
2176 /* oops, file shouldn't be there */
2177 if (dscp) cm_ReleaseSCache(dscp);
2178 cm_ReleaseSCache(scp);
2179 cm_ReleaseUser(userp);
2180 smb_FreeTran2Packet(outp);
2181 return CM_ERROR_EXISTS;
2185 setAttr.mask = CM_ATTRMASK_LENGTH;
2186 setAttr.length.LowPart = 0;
2187 setAttr.length.HighPart = 0;
2188 code = cm_SetAttr(scp, &setAttr, userp, &req);
2189 openAction = 3; /* truncated existing file */
2192 openAction = 1; /* found existing file */
2194 else if (!(openFun & SMB_ATTR_DIRECTORY)) {
2195 /* don't create if not found */
2196 if (dscp) cm_ReleaseSCache(dscp);
2197 osi_assert(scp == NULL);
2198 cm_ReleaseUser(userp);
2199 smb_FreeTran2Packet(outp);
2200 return CM_ERROR_NOSUCHFILE;
2203 osi_assert(dscp != NULL && scp == NULL);
2204 openAction = 2; /* created file */
2205 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
2206 smb_UnixTimeFromSearchTime(&setAttr.clientModTime, dosTime);
2207 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
2209 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
2210 smb_NotifyChange(FILE_ACTION_ADDED,
2211 FILE_NOTIFY_CHANGE_FILE_NAME,
2212 dscp, lastNamep, NULL, TRUE);
2213 if (!excl && code == CM_ERROR_EXISTS) {
2214 /* not an exclusive create, and someone else tried
2215 * creating it already, then we open it anyway. We
2216 * don't bother retrying after this, since if this next
2217 * fails, that means that the file was deleted after we
2218 * started this call.
2220 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
2224 setAttr.mask = CM_ATTRMASK_LENGTH;
2225 setAttr.length.LowPart = 0;
2226 setAttr.length.HighPart = 0;
2227 code = cm_SetAttr(scp, &setAttr, userp,
2230 } /* lookup succeeded */
2234 /* we don't need this any longer */
2235 if (dscp) cm_ReleaseSCache(dscp);
2238 /* something went wrong creating or truncating the file */
2239 if (scp) cm_ReleaseSCache(scp);
2240 cm_ReleaseUser(userp);
2241 smb_FreeTran2Packet(outp);
2245 /* make sure we're about to open a file */
2246 if (scp->fileType != CM_SCACHETYPE_FILE) {
2248 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
2249 cm_scache_t * targetScp = 0;
2250 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
2252 /* we have a more accurate file to use (the
2253 * target of the symbolic link). Otherwise,
2254 * we'll just use the symlink anyway.
2256 osi_Log2(smb_logp, "symlink vp %x to vp %x",
2258 cm_ReleaseSCache(scp);
2262 if (scp->fileType != CM_SCACHETYPE_FILE) {
2263 cm_ReleaseSCache(scp);
2264 cm_ReleaseUser(userp);
2265 smb_FreeTran2Packet(outp);
2266 return CM_ERROR_ISDIR;
2270 /* now all we have to do is open the file itself */
2271 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
2274 /* save a pointer to the vnode */
2277 /* compute open mode */
2278 if (openMode != 1) fidp->flags |= SMB_FID_OPENREAD;
2279 if (openMode == 1 || openMode == 2)
2280 fidp->flags |= SMB_FID_OPENWRITE;
2282 smb_ReleaseFID(fidp);
2284 cm_Open(scp, 0, userp);
2286 /* copy out remainder of the parms */
2288 outp->parmsp[parmSlot] = fidp->fid; parmSlot++;
2289 lock_ObtainMutex(&scp->mx);
2291 outp->parmsp[parmSlot] = smb_Attributes(scp); parmSlot++;
2292 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
2293 outp->parmsp[parmSlot] = (unsigned short)(dosTime & 0xffff); parmSlot++;
2294 outp->parmsp[parmSlot] = (unsigned short)((dosTime>>16) & 0xffff); parmSlot++;
2295 outp->parmsp[parmSlot] = (unsigned short) (scp->length.LowPart & 0xffff);
2297 outp->parmsp[parmSlot] = (unsigned short) ((scp->length.LowPart >> 16) & 0xffff);
2299 outp->parmsp[parmSlot] = openMode; parmSlot++;
2300 outp->parmsp[parmSlot] = 0; parmSlot++; /* file type 0 ==> normal file or dir */
2301 outp->parmsp[parmSlot] = 0; parmSlot++; /* IPC junk */
2303 /* and the final "always present" stuff */
2304 outp->parmsp[parmSlot] = openAction; parmSlot++;
2305 /* next write out the "unique" ID */
2306 outp->parmsp[parmSlot] = (unsigned short) (scp->fid.vnode & 0xffff); parmSlot++;
2307 outp->parmsp[parmSlot] = (unsigned short) (scp->fid.volume & 0xffff); parmSlot++;
2308 outp->parmsp[parmSlot] = 0; parmSlot++;
2309 if (returnEALength) {
2310 outp->parmsp[parmSlot] = 0; parmSlot++;
2311 outp->parmsp[parmSlot] = 0; parmSlot++;
2313 lock_ReleaseMutex(&scp->mx);
2314 outp->totalData = 0; /* total # of data bytes */
2315 outp->totalParms = parmSlot * 2; /* shorts are two bytes */
2317 smb_SendTran2Packet(vcp, outp, op);
2319 smb_FreeTran2Packet(outp);
2321 cm_ReleaseUser(userp);
2322 /* leave scp held since we put it in fidp->scp */
2326 long smb_ReceiveTran2FindFirst(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
2328 osi_Log0(smb_logp,"ReceiveTran2FindFirst - NOT_SUPPORTED");
2329 return CM_ERROR_BADOP;
2332 long smb_ReceiveTran2FindNext(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
2334 osi_Log0(smb_logp,"ReceiveTran2FindNext - NOT_SUPPORTED");
2335 return CM_ERROR_BADOP;
2338 long smb_ReceiveTran2QFSInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
2340 smb_tran2Packet_t *outp;
2341 smb_tran2QFSInfo_t qi;
2344 static char FSname[6] = {'A', 0, 'F', 0, 'S', 0};
2346 osi_Log1(smb_logp, "T2 QFSInfo type 0x%x", p->parmsp[0]);
2348 switch (p->parmsp[0]) {
2349 case 1: responseSize = sizeof(qi.u.allocInfo); break;
2350 case 2: responseSize = sizeof(qi.u.volumeInfo); break;
2351 case 0x102: responseSize = sizeof(qi.u.FSvolumeInfo); break;
2352 case 0x103: responseSize = sizeof(qi.u.FSsizeInfo); break;
2353 case 0x104: responseSize = sizeof(qi.u.FSdeviceInfo); break;
2354 case 0x105: responseSize = sizeof(qi.u.FSattributeInfo); break;
2355 default: return CM_ERROR_INVAL;
2358 outp = smb_GetTran2ResponsePacket(vcp, p, op, 0, responseSize);
2359 switch (p->parmsp[0]) {
2362 qi.u.allocInfo.FSID = 0;
2363 qi.u.allocInfo.sectorsPerAllocUnit = 1;
2364 qi.u.allocInfo.totalAllocUnits = 0x7fffffff;
2365 qi.u.allocInfo.availAllocUnits = 0x3fffffff;
2366 qi.u.allocInfo.bytesPerSector = 1024;
2371 qi.u.volumeInfo.vsn = 1234;
2372 qi.u.volumeInfo.vnCount = 4;
2373 /* we're supposed to pad it out with zeroes to the end */
2374 memset(&qi.u.volumeInfo.label, 0, sizeof(qi.u.volumeInfo.label));
2375 memcpy(qi.u.volumeInfo.label, "AFS", 4);
2379 /* FS volume info */
2380 memset((char *)&qi.u.FSvolumeInfo.vct, 0, sizeof(FILETIME));
2381 qi.u.FSvolumeInfo.vsn = 1234;
2382 qi.u.FSvolumeInfo.vnCount = 8;
2383 memcpy(qi.u.FSvolumeInfo.label, "A\0F\0S\0\0", 8);
2389 temp.LowPart = 0x7fffffff;
2390 qi.u.FSsizeInfo.totalAllocUnits = temp;
2391 temp.LowPart = 0x3fffffff;
2392 qi.u.FSsizeInfo.availAllocUnits = temp;
2393 qi.u.FSsizeInfo.sectorsPerAllocUnit = 1;
2394 qi.u.FSsizeInfo.bytesPerSector = 1024;
2398 /* FS device info */
2399 qi.u.FSdeviceInfo.devType = 0; /* don't have a number */
2400 qi.u.FSdeviceInfo.characteristics = 0x50; /* remote, virtual */
2404 /* FS attribute info */
2405 /* attributes, defined in WINNT.H:
2406 * FILE_CASE_SENSITIVE_SEARCH 0x1
2407 * FILE_CASE_PRESERVED_NAMES 0x2
2408 * <no name defined> 0x4000
2409 * If bit 0x4000 is not set, Windows 95 thinks
2410 * we can't handle long (non-8.3) names,
2411 * despite our protestations to the contrary.
2413 qi.u.FSattributeInfo.attributes = 0x4003;
2414 qi.u.FSattributeInfo.maxCompLength = 255;
2415 qi.u.FSattributeInfo.FSnameLength = 6;
2416 memcpy(qi.u.FSattributeInfo.FSname, FSname, 6);
2420 /* copy out return data, and set corresponding sizes */
2421 outp->totalParms = 0;
2422 outp->totalData = responseSize;
2423 memcpy(outp->datap, &qi, responseSize);
2425 /* send and free the packets */
2426 smb_SendTran2Packet(vcp, outp, op);
2427 smb_FreeTran2Packet(outp);
2432 long smb_ReceiveTran2SetFSInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
2434 osi_Log0(smb_logp,"ReceiveTran2SetFSInfo - NOT_SUPPORTED");
2435 return CM_ERROR_BADOP;
2438 struct smb_ShortNameRock {
2442 size_t shortNameLen;
2445 int cm_GetShortNameProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *vrockp,
2448 struct smb_ShortNameRock *rockp;
2452 /* compare both names and vnodes, though probably just comparing vnodes
2453 * would be safe enough.
2455 if (cm_stricmp(dep->name, rockp->maskp) != 0)
2457 if (ntohl(dep->fid.vnode) != rockp->vnode)
2459 /* This is the entry */
2460 cm_Gen8Dot3Name(dep, rockp->shortName, &shortNameEnd);
2461 rockp->shortNameLen = shortNameEnd - rockp->shortName;
2462 return CM_ERROR_STOPNOW;
2465 long cm_GetShortName(char *pathp, cm_user_t *userp, cm_req_t *reqp,
2466 char *tidPathp, int vnode, char *shortName, size_t *shortNameLenp)
2468 struct smb_ShortNameRock rock;
2472 int caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
2476 spacep = cm_GetSpace();
2477 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
2479 code = cm_NameI(cm_rootSCachep, spacep->data, caseFold, userp, tidPathp,
2481 cm_FreeSpace(spacep);
2482 if (code) return code;
2484 if (!lastNamep) lastNamep = pathp;
2487 thyper.HighPart = 0;
2488 rock.shortName = shortName;
2490 rock.maskp = lastNamep;
2491 code = cm_ApplyDir(dscp, cm_GetShortNameProc, &rock, &thyper, userp,
2494 cm_ReleaseSCache(dscp);
2497 return CM_ERROR_NOSUCHFILE;
2498 if (code == CM_ERROR_STOPNOW) {
2499 *shortNameLenp = rock.shortNameLen;
2505 long smb_ReceiveTran2QPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
2507 smb_tran2Packet_t *outp;
2510 unsigned short infoLevel;
2512 unsigned short attributes;
2513 unsigned long extAttributes;
2518 cm_scache_t *scp, *dscp;
2527 infoLevel = p->parmsp[0];
2528 if (infoLevel == 6) nbytesRequired = 0;
2529 else if (infoLevel == 1) nbytesRequired = 22;
2530 else if (infoLevel == 2) nbytesRequired = 26;
2531 else if (infoLevel == 0x101) nbytesRequired = 40;
2532 else if (infoLevel == 0x102) nbytesRequired = 24;
2533 else if (infoLevel == 0x103) nbytesRequired = 4;
2534 else if (infoLevel == 0x108) nbytesRequired = 30;
2536 osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
2537 p->opcode, infoLevel);
2538 smb_SendTran2Error(vcp, p, opx, CM_ERROR_INVAL);
2541 osi_Log2(smb_logp, "T2 QPathInfo type 0x%x path %s", infoLevel,
2542 osi_LogSaveString(smb_logp, (char *)(&p->parmsp[3])));
2544 outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, nbytesRequired);
2546 if (infoLevel > 0x100)
2547 outp->totalParms = 2;
2549 outp->totalParms = 0;
2550 outp->totalData = nbytesRequired;
2552 /* now, if we're at infoLevel 6, we're only being asked to check
2553 * the syntax, so we just OK things now. In particular, we're *not*
2554 * being asked to verify anything about the state of any parent dirs.
2556 if (infoLevel == 6) {
2557 smb_SendTran2Packet(vcp, outp, opx);
2558 smb_FreeTran2Packet(outp);
2562 userp = smb_GetTran2User(vcp, p);
2564 osi_Log1(smb_logp, "ReceiveTran2QPathInfo unable to resolve user [%d]", p->uid);
2565 smb_FreeTran2Packet(outp);
2566 return CM_ERROR_BADSMB;
2569 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
2571 cm_ReleaseUser(userp);
2572 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOSUCHPATH);
2573 smb_FreeTran2Packet(outp);
2578 * XXX Strange hack XXX
2580 * As of Patch 7 (13 January 98), we are having the following problem:
2581 * In NT Explorer 4.0, whenever we click on a directory, AFS gets
2582 * requests to look up "desktop.ini" in all the subdirectories.
2583 * This can cause zillions of timeouts looking up non-existent cells
2584 * and volumes, especially in the top-level directory.
2586 * We have not found any way to avoid this or work around it except
2587 * to explicitly ignore the requests for mount points that haven't
2588 * yet been evaluated and for directories that haven't yet been
2591 if (infoLevel == 0x101) {
2592 spacep = cm_GetSpace();
2593 smb_StripLastComponent(spacep->data, &lastComp,
2594 (char *)(&p->parmsp[3]));
2595 /* Make sure that lastComp is not NULL */
2597 if (strcmp(lastComp, "\\desktop.ini") == 0) {
2598 code = cm_NameI(cm_rootSCachep, spacep->data,
2602 userp, tidPathp, &req, &dscp);
2604 if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT
2605 && !dscp->mountRootFidp)
2606 code = CM_ERROR_NOSUCHFILE;
2607 else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
2608 cm_buf_t *bp = buf_Find(dscp, &hzero);
2612 code = CM_ERROR_NOSUCHFILE;
2614 cm_ReleaseSCache(dscp);
2616 cm_FreeSpace(spacep);
2617 cm_ReleaseUser(userp);
2618 smb_SendTran2Error(vcp, p, opx, code);
2619 smb_FreeTran2Packet(outp);
2625 cm_FreeSpace(spacep);
2628 /* now do namei and stat, and copy out the info */
2629 code = cm_NameI(cm_rootSCachep, (char *)(&p->parmsp[3]),
2630 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, tidPathp, &req, &scp);
2633 cm_ReleaseUser(userp);
2634 smb_SendTran2Error(vcp, p, opx, code);
2635 smb_FreeTran2Packet(outp);
2639 lock_ObtainMutex(&scp->mx);
2640 code = cm_SyncOp(scp, NULL, userp, &req, 0,
2641 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
2642 if (code) goto done;
2644 /* now we have the status in the cache entry, and everything is locked.
2645 * Marshall the output data.
2648 /* for info level 108, figure out short name */
2649 if (infoLevel == 0x108) {
2650 code = cm_GetShortName((char *)(&p->parmsp[3]), userp, &req,
2651 tidPathp, scp->fid.vnode, shortName,
2658 *((u_long *)op) = len * 2; op += 4;
2659 mbstowcs((unsigned short *)op, shortName, len);
2664 if (infoLevel == 1 || infoLevel == 2) {
2665 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
2666 *((u_long *)op) = dosTime; op += 4; /* creation time */
2667 *((u_long *)op) = dosTime; op += 4; /* access time */
2668 *((u_long *)op) = dosTime; op += 4; /* write time */
2669 *((u_long *)op) = scp->length.LowPart; op += 4; /* length */
2670 *((u_long *)op) = scp->length.LowPart; op += 4; /* alloc size */
2671 attributes = smb_Attributes(scp);
2672 *((u_short *)op) = attributes; op += 2; /* attributes */
2674 else if (infoLevel == 0x101) {
2675 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
2676 *((FILETIME *)op) = ft; op += 8; /* creation time */
2677 *((FILETIME *)op) = ft; op += 8; /* last access time */
2678 *((FILETIME *)op) = ft; op += 8; /* last write time */
2679 *((FILETIME *)op) = ft; op += 8; /* last change time */
2680 extAttributes = smb_ExtAttributes(scp);
2681 *((u_long *)op) = extAttributes; op += 4; /* extended attribs */
2682 *((u_long *)op) = 0; op += 4; /* don't know what this is */
2684 else if (infoLevel == 0x102) {
2685 *((LARGE_INTEGER *)op) = scp->length; op += 8; /* alloc size */
2686 *((LARGE_INTEGER *)op) = scp->length; op += 8; /* EOF */
2687 *((u_long *)op) = scp->linkCount; op += 4;
2690 *op++ = (scp->fileType == CM_SCACHETYPE_DIRECTORY ? 1 : 0);
2693 else if (infoLevel == 0x103) {
2694 memset(op, 0, 4); op += 4; /* EA size */
2697 /* now, if we are being asked about extended attrs, return a 0 size */
2698 if (infoLevel == 2) {
2699 *((u_long *)op) = 0; op += 4;
2703 /* send and free the packets */
2705 lock_ReleaseMutex(&scp->mx);
2706 cm_ReleaseSCache(scp);
2707 cm_ReleaseUser(userp);
2709 smb_SendTran2Packet(vcp, outp, opx);
2711 smb_SendTran2Error(vcp, p, opx, code);
2712 smb_FreeTran2Packet(outp);
2717 long smb_ReceiveTran2SetPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
2719 osi_Log0(smb_logp,"ReceiveTran2SetPathInfo - NOT_SUPPORTED");
2720 return CM_ERROR_BADOP;
2723 long smb_ReceiveTran2QFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
2725 smb_tran2Packet_t *outp;
2727 unsigned long attributes;
2728 unsigned short infoLevel;
2741 fidp = smb_FindFID(vcp, fid, 0);
2744 smb_SendTran2Error(vcp, p, opx, CM_ERROR_BADFD);
2748 infoLevel = p->parmsp[1];
2749 if (infoLevel == 0x101) nbytesRequired = 40;
2750 else if (infoLevel == 0x102) nbytesRequired = 24;
2751 else if (infoLevel == 0x103) nbytesRequired = 4;
2752 else if (infoLevel == 0x104) nbytesRequired = 6;
2754 osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
2755 p->opcode, infoLevel);
2756 smb_SendTran2Error(vcp, p, opx, CM_ERROR_INVAL);
2757 smb_ReleaseFID(fidp);
2760 osi_Log2(smb_logp, "T2 QFileInfo type 0x%x fid %d", infoLevel, fid);
2762 outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, nbytesRequired);
2764 if (infoLevel > 0x100)
2765 outp->totalParms = 2;
2767 outp->totalParms = 0;
2768 outp->totalData = nbytesRequired;
2770 userp = smb_GetTran2User(vcp, p);
2772 osi_Log1(smb_logp, "ReceiveTran2QFileInfo unable to resolve user [%d]", p->uid);
2773 code = CM_ERROR_BADSMB;
2778 lock_ObtainMutex(&scp->mx);
2779 code = cm_SyncOp(scp, NULL, userp, &req, 0,
2780 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
2784 /* now we have the status in the cache entry, and everything is locked.
2785 * Marshall the output data.
2788 if (infoLevel == 0x101) {
2789 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
2790 *((FILETIME *)op) = ft; op += 8; /* creation time */
2791 *((FILETIME *)op) = ft; op += 8; /* last access time */
2792 *((FILETIME *)op) = ft; op += 8; /* last write time */
2793 *((FILETIME *)op) = ft; op += 8; /* last change time */
2794 attributes = smb_ExtAttributes(scp);
2795 *((u_long *)op) = attributes; op += 4;
2796 *((u_long *)op) = 0; op += 4;
2798 else if (infoLevel == 0x102) {
2799 *((LARGE_INTEGER *)op) = scp->length; op += 8; /* alloc size */
2800 *((LARGE_INTEGER *)op) = scp->length; op += 8; /* EOF */
2801 *((u_long *)op) = scp->linkCount; op += 4;
2802 *op++ = ((fidp->flags & SMB_FID_DELONCLOSE) ? 1 : 0);
2803 *op++ = (scp->fileType == CM_SCACHETYPE_DIRECTORY ? 1 : 0);
2807 else if (infoLevel == 0x103) {
2808 *((u_long *)op) = 0; op += 4;
2810 else if (infoLevel == 0x104) {
2814 if (fidp->NTopen_wholepathp)
2815 name = fidp->NTopen_wholepathp;
2817 name = "\\"; /* probably can't happen */
2819 outp->totalData = (len*2) + 4; /* this is actually what we want to return */
2820 *((u_long *)op) = len * 2; op += 4;
2821 mbstowcs((unsigned short *)op, name, len); op += (len * 2);
2824 /* send and free the packets */
2826 lock_ReleaseMutex(&scp->mx);
2827 cm_ReleaseUser(userp);
2828 smb_ReleaseFID(fidp);
2830 smb_SendTran2Packet(vcp, outp, opx);
2832 smb_SendTran2Error(vcp, p, opx, code);
2833 smb_FreeTran2Packet(outp);
2838 long smb_ReceiveTran2SetFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
2843 unsigned short infoLevel;
2844 smb_tran2Packet_t *outp;
2852 fidp = smb_FindFID(vcp, fid, 0);
2855 smb_SendTran2Error(vcp, p, op, CM_ERROR_BADFD);
2859 infoLevel = p->parmsp[1];
2860 osi_Log2(smb_logp,"ReceiveTran2SetFileInfo type=[%x] fid=[%x]", infoLevel, fid);
2861 if (infoLevel > 0x104 || infoLevel < 0x101) {
2862 osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
2863 p->opcode, infoLevel);
2864 smb_SendTran2Error(vcp, p, op, CM_ERROR_INVAL);
2865 smb_ReleaseFID(fidp);
2869 if (infoLevel == 0x102 && !(fidp->flags & SMB_FID_OPENDELETE)) {
2870 smb_SendTran2Error(vcp, p, op, CM_ERROR_NOACCESS);
2871 smb_ReleaseFID(fidp);
2874 if ((infoLevel == 0x103 || infoLevel == 0x104)
2875 && !(fidp->flags & SMB_FID_OPENWRITE)) {
2876 smb_SendTran2Error(vcp, p, op, CM_ERROR_NOACCESS);
2877 smb_ReleaseFID(fidp);
2881 osi_Log1(smb_logp, "T2 SFileInfo type 0x%x", infoLevel);
2883 outp = smb_GetTran2ResponsePacket(vcp, p, op, 2, 0);
2885 outp->totalParms = 2;
2886 outp->totalData = 0;
2888 userp = smb_GetTran2User(vcp, p);
2890 osi_Log1(smb_logp,"ReceiveTran2SetFileInfo unable to resolve user [%d]", p->uid);
2891 code = CM_ERROR_BADSMB;
2897 if (infoLevel == 0x101) {
2899 unsigned int attribute;
2902 /* lock the vnode with a callback; we need the current status
2903 * to determine what the new status is, in some cases.
2905 lock_ObtainMutex(&scp->mx);
2906 code = cm_SyncOp(scp, NULL, userp, &req, 0,
2907 CM_SCACHESYNC_GETSTATUS
2908 | CM_SCACHESYNC_NEEDCALLBACK);
2910 lock_ReleaseMutex(&scp->mx);
2914 /* prepare for setattr call */
2917 lastMod = *((FILETIME *)(p->datap + 16));
2918 /* when called as result of move a b, lastMod is (-1, -1).
2919 * If the check for -1 is not present, timestamp
2920 * of the resulting file will be 1969 (-1)
2922 if (LargeIntegerNotEqualToZero(*((LARGE_INTEGER *)&lastMod)) &&
2923 lastMod.dwLowDateTime != -1 && lastMod.dwHighDateTime != -1) {
2924 attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
2925 smb_UnixTimeFromLargeSearchTime(&attr.clientModTime,
2927 fidp->flags |= SMB_FID_MTIMESETDONE;
2930 attribute = *((u_long *)(p->datap + 32));
2931 if (attribute != 0) {
2932 if ((scp->unixModeBits & 0222)
2933 && (attribute & 1) != 0) {
2934 /* make a writable file read-only */
2935 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
2936 attr.unixModeBits = scp->unixModeBits & ~0222;
2938 else if ((scp->unixModeBits & 0222) == 0
2939 && (attribute & 1) == 0) {
2940 /* make a read-only file writable */
2941 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
2942 attr.unixModeBits = scp->unixModeBits | 0222;
2945 lock_ReleaseMutex(&scp->mx);
2949 code = cm_SetAttr(scp, &attr, userp, &req);
2953 else if (infoLevel == 0x103 || infoLevel == 0x104) {
2954 LARGE_INTEGER size = *((LARGE_INTEGER *)(p->datap));
2957 attr.mask = CM_ATTRMASK_LENGTH;
2958 attr.length.LowPart = size.LowPart;
2959 attr.length.HighPart = size.HighPart;
2960 code = cm_SetAttr(scp, &attr, userp, &req);
2962 else if (infoLevel == 0x102) {
2963 if (*((char *)(p->datap))) {
2964 code = cm_CheckNTDelete(fidp->NTopen_dscp, scp, userp,
2967 fidp->flags |= SMB_FID_DELONCLOSE;
2971 fidp->flags &= ~SMB_FID_DELONCLOSE;
2976 cm_ReleaseUser(userp);
2977 smb_ReleaseFID(fidp);
2979 smb_SendTran2Packet(vcp, outp, op);
2981 smb_SendTran2Error(vcp, p, op, code);
2982 smb_FreeTran2Packet(outp);
2988 smb_ReceiveTran2FSCTL(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
2990 osi_Log0(smb_logp,"ReceiveTran2FSCTL - NOT_SUPPORTED");
2991 return CM_ERROR_BADOP;
2995 smb_ReceiveTran2IOCTL(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
2997 osi_Log0(smb_logp,"ReceiveTran2IOCTL - NOT_SUPPORTED");
2998 return CM_ERROR_BADOP;
3002 smb_ReceiveTran2FindNotifyFirst(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3004 osi_Log0(smb_logp,"ReceiveTran2FindNotifyFirst - NOT_SUPPORTED");
3005 return CM_ERROR_BADOP;
3009 smb_ReceiveTran2FindNotifyNext(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3011 osi_Log0(smb_logp,"ReceiveTran2FindNotifyNext - NOT_SUPPORTED");
3012 return CM_ERROR_BADOP;
3016 smb_ReceiveTran2CreateDirectory(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3018 osi_Log0(smb_logp,"ReceiveTran2CreateDirectory - NOT_SUPPORTED");
3019 return CM_ERROR_BADOP;
3023 smb_ReceiveTran2SessionSetup(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3025 osi_Log0(smb_logp,"ReceiveTran2SessionSetup - NOT_SUPPORTED");
3026 return CM_ERROR_BADOP;
3030 smb_ReceiveTran2GetDFSReferral(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3032 osi_Log0(smb_logp,"ReceiveTran2GetDFSReferral - NOT_SUPPORTED");
3033 return CM_ERROR_BADOP;
3037 smb_ReceiveTran2ReportDFSInconsistency(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3039 osi_Log0(smb_logp,"ReceiveTran2ReportDFSInconsistency - NOT_SUPPORTED");
3040 return CM_ERROR_BADOP;
3044 smb_ApplyV3DirListPatches(cm_scache_t *dscp,
3045 smb_dirListPatch_t **dirPatchespp, int infoLevel, cm_user_t *userp,
3050 cm_scache_t *targetScp; /* target if scp is a symlink */
3055 unsigned short attr;
3056 unsigned long lattr;
3057 smb_dirListPatch_t *patchp;
3058 smb_dirListPatch_t *npatchp;
3060 for(patchp = *dirPatchespp; patchp; patchp =
3061 (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
3062 code = cm_GetSCache(&patchp->fid, &scp, userp, reqp);
3064 lock_ObtainMutex(&scp->mx);
3065 code = cm_SyncOp(scp, NULL, userp, reqp, 0,
3066 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3068 lock_ReleaseMutex(&scp->mx);
3069 cm_ReleaseSCache(scp);
3071 dptr = patchp->dptr;
3073 /* Plug in fake timestamps. A time stamp of 0 causes 'invalid parameter'
3074 errors in the client. */
3075 if (infoLevel >= 0x101) {
3076 /* 1969-12-31 23:59:59 +00 */
3077 ft.dwHighDateTime = 0x19DB200;
3078 ft.dwLowDateTime = 0x5BB78980;
3080 /* copy to Creation Time */
3081 *((FILETIME *)dptr) = ft;
3084 /* copy to Last Access Time */
3085 *((FILETIME *)dptr) = ft;
3088 /* copy to Last Write Time */
3089 *((FILETIME *)dptr) = ft;
3092 /* copy to Change Time */
3093 *((FILETIME *)dptr) = ft;
3096 /* merge in hidden attribute */
3097 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
3098 *((u_long *)dptr) = SMB_ATTR_HIDDEN;
3102 /* 1969-12-31 23:59:58 +00*/
3103 dosTime = 0xEBBFBF7D;
3105 /* and copy out date */
3106 shortTemp = (dosTime>>16) & 0xffff;
3107 *((u_short *)dptr) = shortTemp;
3110 /* copy out creation time */
3111 shortTemp = dosTime & 0xffff;
3112 *((u_short *)dptr) = shortTemp;
3115 /* and copy out date */
3116 shortTemp = (dosTime>>16) & 0xffff;
3117 *((u_short *)dptr) = shortTemp;
3120 /* copy out access time */
3121 shortTemp = dosTime & 0xffff;
3122 *((u_short *)dptr) = shortTemp;
3125 /* and copy out date */
3126 shortTemp = (dosTime>>16) & 0xffff;
3127 *((u_short *)dptr) = shortTemp;
3130 /* copy out mod time */
3131 shortTemp = dosTime & 0xffff;
3132 *((u_short *)dptr) = shortTemp;
3135 /* merge in hidden (dot file) attribute */
3136 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
3137 attr = SMB_ATTR_HIDDEN;
3138 *dptr++ = attr & 0xff;
3139 *dptr++ = (attr >> 8) & 0xff;
3145 /* now watch for a symlink */
3147 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
3148 lock_ReleaseMutex(&scp->mx);
3149 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, reqp);
3151 /* we have a more accurate file to use (the
3152 * target of the symbolic link). Otherwise,
3153 * we'll just use the symlink anyway.
3155 osi_Log2(smb_logp, "symlink vp %x to vp %x",
3157 cm_ReleaseSCache(scp);
3160 lock_ObtainMutex(&scp->mx);
3163 dptr = patchp->dptr;
3165 if (infoLevel >= 0x101) {
3167 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
3169 /* copy to Creation Time */
3170 *((FILETIME *)dptr) = ft;
3173 /* copy to Last Access Time */
3174 *((FILETIME *)dptr) = ft;
3177 /* copy to Last Write Time */
3178 *((FILETIME *)dptr) = ft;
3181 /* copy to Change Time */
3182 *((FILETIME *)dptr) = ft;
3185 /* Use length for both file length and alloc length */
3186 *((LARGE_INTEGER *)dptr) = scp->length;
3188 *((LARGE_INTEGER *)dptr) = scp->length;
3191 /* Copy attributes */
3192 lattr = smb_ExtAttributes(scp);
3193 /* merge in hidden (dot file) attribute */
3194 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE )
3195 lattr |= SMB_ATTR_HIDDEN;
3196 *((u_long *)dptr) = lattr;
3201 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
3203 /* and copy out date */
3204 shortTemp = (dosTime>>16) & 0xffff;
3205 *((u_short *)dptr) = shortTemp;
3208 /* copy out creation time */
3209 shortTemp = dosTime & 0xffff;
3210 *((u_short *)dptr) = shortTemp;
3213 /* and copy out date */
3214 shortTemp = (dosTime>>16) & 0xffff;
3215 *((u_short *)dptr) = shortTemp;
3218 /* copy out access time */
3219 shortTemp = dosTime & 0xffff;
3220 *((u_short *)dptr) = shortTemp;
3223 /* and copy out date */
3224 shortTemp = (dosTime>>16) & 0xffff;
3225 *((u_short *)dptr) = shortTemp;
3228 /* copy out mod time */
3229 shortTemp = dosTime & 0xffff;
3230 *((u_short *)dptr) = shortTemp;
3233 /* copy out file length and alloc length,
3234 * using the same for both
3236 *((u_long *)dptr) = scp->length.LowPart;
3238 *((u_long *)dptr) = scp->length.LowPart;
3241 /* finally copy out attributes as short */
3242 attr = smb_Attributes(scp);
3243 /* merge in hidden (dot file) attribute */
3244 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE )
3245 attr |= SMB_ATTR_HIDDEN;
3246 *dptr++ = attr & 0xff;
3247 *dptr++ = (attr >> 8) & 0xff;
3250 lock_ReleaseMutex(&scp->mx);
3251 cm_ReleaseSCache(scp);
3254 /* now free the patches */
3255 for (patchp = *dirPatchespp; patchp; patchp = npatchp) {
3256 npatchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q);
3260 /* and mark the list as empty */
3261 *dirPatchespp = NULL;
3266 #ifndef USE_OLD_MATCHING
3267 // char table for case insensitive comparison
3268 char mapCaseTable[256];
3270 VOID initUpperCaseTable(VOID)
3273 for (i = 0; i < 256; ++i)
3274 mapCaseTable[i] = toupper(i);
3275 // make '"' match '.'
3276 mapCaseTable[(int)'"'] = toupper('.');
3277 // make '<' match '*'
3278 mapCaseTable[(int)'<'] = toupper('*');
3279 // make '>' match '?'
3280 mapCaseTable[(int)'>'] = toupper('?');
3283 // Compare 'pattern' (containing metacharacters '*' and '?') with the file
3285 // Note : this procedure works recursively calling itself.
3287 // PSZ pattern : string containing metacharacters.
3288 // PSZ name : file name to be compared with 'pattern'.
3290 // BOOL : TRUE/FALSE (match/mistmatch)
3293 szWildCardMatchFileName(PSZ pattern, PSZ name)
3295 PSZ pename; // points to the last 'name' character
3297 pename = name + strlen(name) - 1;
3307 if (*pattern == '\0')
3309 for (p = pename; p >= name; --p) {
3310 if ((mapCaseTable[*p] == mapCaseTable[*pattern]) &&
3311 szWildCardMatchFileName(pattern + 1, p + 1))
3316 if (mapCaseTable[*name] != mapCaseTable[*pattern])
3323 if (*pattern == '\0' || *pattern == '*' && *(pattern+1) == '\0')
3329 /* do a case-folding search of the star name mask with the name in namep.
3330 * Return 1 if we match, otherwise 0.
3332 int smb_V3MatchMask(char *namep, char *maskp, int flags)
3335 int i, j, star, qmark, retval;
3337 /* make sure we only match 8.3 names, if requested */
3338 if ((flags & CM_FLAG_8DOT3) && !cm_Is8Dot3(namep))
3341 /* optimize the pattern:
3342 * if there is a mixture of '?' and '*',
3343 * for example the sequence "*?*?*?*"
3344 * must be turned into the form "*"
3346 newmask = (char *)malloc(strlen(maskp)+1);
3347 for ( i=0, j=0, star=0, qmark=0; maskp[i]; i++) {
3348 switch ( maskp[i] ) {
3360 } else if ( qmark ) {
3364 newmask[j++] = maskp[i];
3371 } else if ( qmark ) {
3375 newmask[j++] = '\0';
3377 retval = szWildCardMatchFileName(newmask, namep) ? 1:0;
3383 #else /* USE_OLD_MATCHING */
3384 /* do a case-folding search of the star name mask with the name in namep.
3385 * Return 1 if we match, otherwise 0.
3387 int smb_V3MatchMask(char *namep, char *maskp, int flags)
3389 unsigned char tcp1, tcp2; /* Pattern characters */
3390 unsigned char tcn1; /* Name characters */
3391 int sawDot = 0, sawStar = 0, req8dot3 = 0;
3392 char *starNamep, *starMaskp;
3393 static char nullCharp[] = {0};
3394 int casefold = flags & CM_FLAG_CASEFOLD;
3396 /* make sure we only match 8.3 names, if requested */
3397 req8dot3 = (flags & CM_FLAG_8DOT3);
3398 if (req8dot3 && !cm_Is8Dot3(namep))
3403 /* Next pattern character */
3406 /* Next name character */
3410 /* 0 - end of pattern */
3416 else if (tcp1 == '.' || tcp1 == '"') {
3426 * first dot in pattern;
3427 * must match dot or end of name
3432 else if (tcn1 == '.') {
3441 else if (tcp1 == '?') {
3442 if (tcn1 == 0 || tcn1 == '.')
3447 else if (tcp1 == '>') {
3448 if (tcn1 != 0 && tcn1 != '.')
3452 else if (tcp1 == '*' || tcp1 == '<') {
3456 else if ((req8dot3 && tcp2 == '.') || tcp2 == '"') {
3457 while (req8dot3 && tcn1 != '.' && tcn1 != 0)
3472 * pattern character after '*' is not null or
3473 * period. If it is '?' or '>', we are not
3474 * going to understand it. If it is '*' or
3475 * '<', we are going to skip over it. None of
3476 * these are likely, I hope.
3478 /* skip over '*' and '<' */
3479 while (tcp2 == '*' || tcp2 == '<')
3482 /* skip over characters that don't match tcp2 */
3483 while (req8dot3 && tcn1 != '.' && tcn1 != 0 &&
3484 ((casefold && cm_foldUpper[tcn1] != cm_foldUpper[tcp2]) ||
3485 (!casefold && tcn1 != tcp2)))
3489 if ((req8dot3 && tcn1 == '.') || tcn1 == 0)
3492 /* Remember where we are */
3502 /* tcp1 is not a wildcard */
3503 if ((casefold && cm_foldUpper[tcn1] == cm_foldUpper[tcp1]) ||
3504 (!casefold && tcn1 == tcp1)) {
3509 /* if trying to match a star pattern, go back */
3511 maskp = starMaskp - 2;
3512 namep = starNamep + 1;
3521 #endif /* USE_OLD_MATCHING */
3523 long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
3532 smb_dirListPatch_t *dirListPatchesp;
3533 smb_dirListPatch_t *curPatchp;
3536 long orbytes; /* # of bytes in this output record */
3537 long ohbytes; /* # of bytes, except file name */
3538 long onbytes; /* # of bytes in name, incl. term. null */
3539 osi_hyper_t dirLength;
3540 osi_hyper_t bufferOffset;
3541 osi_hyper_t curOffset;
3543 smb_dirSearch_t *dsp;
3547 cm_pageHeader_t *pageHeaderp;
3548 cm_user_t *userp = NULL;
3551 long nextEntryCookie;
3552 int numDirChunks; /* # of 32 byte dir chunks in this entry */
3553 char *op; /* output data ptr */
3554 char *origOp; /* original value of op */
3555 cm_space_t *spacep; /* for pathname buffer */
3556 long maxReturnData; /* max # of return data */
3557 long maxReturnParms; /* max # of return parms */
3558 long bytesInBuffer; /* # data bytes in the output buffer */
3560 char *maskp; /* mask part of path */
3564 smb_tran2Packet_t *outp; /* response packet */
3567 char shortName[13]; /* 8.3 name if needed */
3578 if (p->opcode == 1) {
3579 /* find first; obtain basic parameters from request */
3580 attribute = p->parmsp[0];
3581 maxCount = p->parmsp[1];
3582 infoLevel = p->parmsp[3];
3583 searchFlags = p->parmsp[2];
3584 dsp = smb_NewDirSearch(1);
3585 dsp->attribute = attribute;
3586 pathp = ((char *) p->parmsp) + 12; /* points to path */
3588 maskp = strrchr(pathp, '\\');
3592 maskp++; /* skip over backslash */
3593 strcpy(dsp->mask, maskp); /* and save mask */
3594 /* track if this is likely to match a lot of entries */
3595 starPattern = smb_V3IsStarMask(maskp);
3598 osi_assert(p->opcode == 2);
3599 /* find next; obtain basic parameters from request or open dir file */
3600 dsp = smb_FindDirSearch(p->parmsp[0]);
3602 return CM_ERROR_BADFD;
3603 attribute = dsp->attribute;
3604 maxCount = p->parmsp[1];
3605 infoLevel = p->parmsp[2];
3606 searchFlags = p->parmsp[5];
3608 nextCookie = p->parmsp[3] | (p->parmsp[4] << 16);
3610 starPattern = 1; /* assume, since required a Find Next */
3614 "T2 search dir attr 0x%x, info level %d, max count %d, flags 0x%x",
3615 attribute, infoLevel, maxCount, searchFlags);
3617 osi_Log2(smb_logp, "...T2 search op %d, nextCookie 0x%x",
3618 p->opcode, nextCookie);
3620 if (infoLevel >= 0x101)
3621 searchFlags &= ~4; /* no resume keys */
3623 dirListPatchesp = NULL;
3625 maxReturnData = p->maxReturnData;
3626 if (p->opcode == 1) /* find first */
3627 maxReturnParms = 10; /* bytes */
3629 maxReturnParms = 8; /* bytes */
3631 #ifndef CM_CONFIG_MULTITRAN2RESPONSES
3632 if (maxReturnData > 6000)
3633 maxReturnData = 6000;
3634 #endif /* CM_CONFIG_MULTITRAN2RESPONSES */
3636 outp = smb_GetTran2ResponsePacket(vcp, p, opx, maxReturnParms,
3639 osi_Log1(smb_logp, "T2 receive search dir %s",
3640 osi_LogSaveString(smb_logp, pathp));
3642 /* bail out if request looks bad */
3643 if (p->opcode == 1 && !pathp) {
3644 smb_ReleaseDirSearch(dsp);
3645 smb_FreeTran2Packet(outp);
3646 return CM_ERROR_BADSMB;
3649 osi_Log2(smb_logp, "T2 dir search cookie 0x%x, connection %d",
3650 nextCookie, dsp->cookie);
3652 userp = smb_GetTran2User(vcp, p);
3654 osi_Log1(smb_logp, "T2 dir search unable to resolve user [%d]", p->uid);
3655 smb_ReleaseDirSearch(dsp);
3656 smb_FreeTran2Packet(outp);
3657 return CM_ERROR_BADSMB;
3660 /* try to get the vnode for the path name next */
3661 lock_ObtainMutex(&dsp->mx);
3668 spacep = cm_GetSpace();
3669 smb_StripLastComponent(spacep->data, NULL, pathp);
3670 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
3672 lock_ReleaseMutex(&dsp->mx);
3673 cm_ReleaseUser(userp);
3674 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOFILES);
3675 smb_FreeTran2Packet(outp);
3676 smb_DeleteDirSearch(dsp);
3677 smb_ReleaseDirSearch(dsp);
3680 code = cm_NameI(cm_rootSCachep, spacep->data,
3681 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
3682 userp, tidPathp, &req, &scp);
3683 cm_FreeSpace(spacep);
3687 cm_ReleaseSCache(dsp->scp);
3689 /* we need one hold for the entry we just stored into,
3690 * and one for our own processing. When we're done
3691 * with this function, we'll drop the one for our own
3692 * processing. We held it once from the namei call,
3693 * and so we do another hold now.
3696 lock_ObtainMutex(&scp->mx);
3697 if ((scp->flags & CM_SCACHEFLAG_BULKSTATTING) == 0 &&
3698 LargeIntegerGreaterOrEqualToZero(scp->bulkStatProgress)) {
3699 scp->flags |= CM_SCACHEFLAG_BULKSTATTING;
3700 dsp->flags |= SMB_DIRSEARCH_BULKST;
3702 lock_ReleaseMutex(&scp->mx);
3705 lock_ReleaseMutex(&dsp->mx);
3707 cm_ReleaseUser(userp);
3708 smb_FreeTran2Packet(outp);
3709 smb_DeleteDirSearch(dsp);
3710 smb_ReleaseDirSearch(dsp);
3714 /* get the directory size */
3715 lock_ObtainMutex(&scp->mx);
3716 code = cm_SyncOp(scp, NULL, userp, &req, 0,
3717 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3719 lock_ReleaseMutex(&scp->mx);
3720 cm_ReleaseSCache(scp);
3721 cm_ReleaseUser(userp);
3722 smb_FreeTran2Packet(outp);
3723 smb_DeleteDirSearch(dsp);
3724 smb_ReleaseDirSearch(dsp);
3729 dirLength = scp->length;
3731 bufferOffset.LowPart = bufferOffset.HighPart = 0;
3732 curOffset.HighPart = 0;
3733 curOffset.LowPart = nextCookie;
3734 origOp = outp->datap;
3742 if (searchFlags & 4)
3743 /* skip over resume key */
3746 /* make sure that curOffset.LowPart doesn't point to the first
3747 * 32 bytes in the 2nd through last dir page, and that it doesn't
3748 * point at the first 13 32-byte chunks in the first dir page,
3749 * since those are dir and page headers, and don't contain useful
3752 temp = curOffset.LowPart & (2048-1);
3753 if (curOffset.HighPart == 0 && curOffset.LowPart < 2048) {
3754 /* we're in the first page */
3755 if (temp < 13*32) temp = 13*32;
3758 /* we're in a later dir page */
3759 if (temp < 32) temp = 32;
3762 /* make sure the low order 5 bits are zero */
3765 /* now put temp bits back ito curOffset.LowPart */
3766 curOffset.LowPart &= ~(2048-1);
3767 curOffset.LowPart |= temp;
3769 /* check if we've passed the dir's EOF */
3770 if (LargeIntegerGreaterThanOrEqualTo(curOffset, dirLength)) {
3775 /* check if we've returned all the names that will fit in the
3776 * response packet; we check return count as well as the number
3777 * of bytes requested. We check the # of bytes after we find
3778 * the dir entry, since we'll need to check its size.
3780 if (returnedNames >= maxCount) {
3784 /* see if we can use the bufferp we have now; compute in which
3785 * page the current offset would be, and check whether that's
3786 * the offset of the buffer we have. If not, get the buffer.
3788 thyper.HighPart = curOffset.HighPart;
3789 thyper.LowPart = curOffset.LowPart & ~(buf_bufferSize-1);
3790 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
3793 buf_Release(bufferp);
3796 lock_ReleaseMutex(&scp->mx);
3797 lock_ObtainRead(&scp->bufCreateLock);
3798 code = buf_Get(scp, &thyper, &bufferp);
3799 lock_ReleaseRead(&scp->bufCreateLock);
3800 lock_ObtainMutex(&dsp->mx);
3802 /* now, if we're doing a star match, do bulk fetching
3803 * of all of the status info for files in the dir.
3806 smb_ApplyV3DirListPatches(scp, &dirListPatchesp,
3809 lock_ObtainMutex(&scp->mx);
3810 if ((dsp->flags & SMB_DIRSEARCH_BULKST) &&
3811 LargeIntegerGreaterThanOrEqualTo(thyper, scp->bulkStatProgress)) {
3812 /* Don't bulk stat if risking timeout */
3813 int now = GetCurrentTime();
3814 if (now - req.startTime > 5000) {
3815 scp->bulkStatProgress = thyper;
3816 scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
3817 dsp->flags &= ~SMB_DIRSEARCH_BULKST;
3819 cm_TryBulkStat(scp, &thyper, userp, &req);
3822 lock_ObtainMutex(&scp->mx);
3824 lock_ReleaseMutex(&dsp->mx);
3828 bufferOffset = thyper;
3830 /* now get the data in the cache */
3832 code = cm_SyncOp(scp, bufferp, userp, &req,
3834 CM_SCACHESYNC_NEEDCALLBACK
3835 | CM_SCACHESYNC_READ);
3838 if (cm_HaveBuffer(scp, bufferp, 0)) break;
3840 /* otherwise, load the buffer and try again */
3841 code = cm_GetBuffer(scp, bufferp, NULL, userp,
3846 buf_Release(bufferp);
3850 } /* if (wrong buffer) ... */
3852 /* now we have the buffer containing the entry we're interested
3853 * in; copy it out if it represents a non-deleted entry.
3855 entryInDir = curOffset.LowPart & (2048-1);
3856 entryInBuffer = curOffset.LowPart & (buf_bufferSize - 1);
3858 /* page header will help tell us which entries are free. Page
3859 * header can change more often than once per buffer, since
3860 * AFS 3 dir page size may be less than (but not more than)
3861 * a buffer package buffer.
3863 /* only look intra-buffer */
3864 temp = curOffset.LowPart & (buf_bufferSize - 1);
3865 temp &= ~(2048 - 1); /* turn off intra-page bits */
3866 pageHeaderp = (cm_pageHeader_t *) (bufferp->datap + temp);
3868 /* now determine which entry we're looking at in the page.
3869 * If it is free (there's a free bitmap at the start of the
3870 * dir), we should skip these 32 bytes.
3872 slotInPage = (entryInDir & 0x7e0) >> 5;
3873 if (!(pageHeaderp->freeBitmap[slotInPage>>3] &
3874 (1 << (slotInPage & 0x7)))) {
3875 /* this entry is free */
3876 numDirChunks = 1; /* only skip this guy */
3880 tp = bufferp->datap + entryInBuffer;
3881 dep = (cm_dirEntry_t *) tp; /* now points to AFS3 dir entry */
3883 /* while we're here, compute the next entry's location, too,
3884 * since we'll need it when writing out the cookie into the dir
3887 * XXXX Probably should do more sanity checking.
3889 numDirChunks = cm_NameEntries(dep->name, &onbytes);
3891 /* compute offset of cookie representing next entry */
3892 nextEntryCookie = curOffset.LowPart + (CM_DIR_CHUNKSIZE * numDirChunks);
3894 /* Need 8.3 name? */
3896 if (infoLevel == 0x104
3897 && dep->fid.vnode != 0
3898 && !cm_Is8Dot3(dep->name)) {
3899 cm_Gen8Dot3Name(dep, shortName, &shortNameEnd);
3903 /* When matching, we are using doing a case fold if we have a wildcard mask.
3904 * If we get a non-wildcard match, it's a lookup for a specific file.
3906 if (dep->fid.vnode != 0 &&
3907 (smb_V3MatchMask(dep->name, maskp, (starPattern? CM_FLAG_CASEFOLD : 0)) ||
3909 smb_V3MatchMask(shortName, maskp, CM_FLAG_CASEFOLD)))) {
3911 /* Eliminate entries that don't match requested attributes */
3912 if (smb_hideDotFiles && !(dsp->attribute & SMB_ATTR_HIDDEN) &&
3913 smb_IsDotFile(dep->name))
3914 goto nextEntry; /* no hidden files */
3916 if (!(dsp->attribute & SMB_ATTR_DIRECTORY)) /* no directories */
3918 /* We have already done the cm_TryBulkStat above */
3919 fid.cell = scp->fid.cell;
3920 fid.volume = scp->fid.volume;
3921 fid.vnode = ntohl(dep->fid.vnode);
3922 fid.unique = ntohl(dep->fid.unique);
3923 fileType = cm_FindFileType(&fid);
3924 /*osi_Log2(smb_logp, "smb_ReceiveTran2SearchDir: file %s "
3925 "has filetype %d", dep->name,
3927 if (fileType == CM_SCACHETYPE_DIRECTORY)
3931 /* finally check if this name will fit */
3933 /* standard dir entry stuff */
3934 if (infoLevel < 0x101)
3935 ohbytes = 23; /* pre-NT */
3936 else if (infoLevel == 0x103)
3937 ohbytes = 12; /* NT names only */
3939 ohbytes = 64; /* NT */
3941 if (infoLevel == 0x104)
3942 ohbytes += 26; /* Short name & length */
3944 if (searchFlags & 4) {
3945 ohbytes += 4; /* if resume key required */
3949 && infoLevel != 0x101
3950 && infoLevel != 0x103)
3951 ohbytes += 4; /* EASIZE */
3953 /* add header to name & term. null */
3954 orbytes = onbytes + ohbytes + 1;
3956 /* now, we round up the record to a 4 byte alignment,
3957 * and we make sure that we have enough room here for
3958 * even the aligned version (so we don't have to worry
3959 * about an * overflow when we pad things out below).
3960 * That's the reason for the alignment arithmetic below.
3962 if (infoLevel >= 0x101)
3963 align = (4 - (orbytes & 3)) & 3;
3966 if (orbytes + bytesInBuffer + align > maxReturnData)
3969 /* this is one of the entries to use: it is not deleted
3970 * and it matches the star pattern we're looking for.
3971 * Put out the name, preceded by its length.
3973 /* First zero everything else */
3974 memset(origOp, 0, ohbytes);
3976 if (infoLevel <= 0x101)
3977 *(origOp + ohbytes - 1) = (unsigned char) onbytes;
3978 else if (infoLevel == 0x103)
3979 *((u_long *)(op + 8)) = onbytes;
3981 *((u_long *)(op + 60)) = onbytes;
3982 strcpy(origOp+ohbytes, dep->name);
3984 /* Short name if requested and needed */
3985 if (infoLevel == 0x104) {
3986 if (NeedShortName) {
3987 strcpy(op + 70, shortName);
3988 *(op + 68) = shortNameEnd - shortName;
3992 /* now, adjust the # of entries copied */
3995 /* NextEntryOffset and FileIndex */
3996 if (infoLevel >= 101) {
3997 int entryOffset = orbytes + align;
3998 *((u_long *)op) = entryOffset;
3999 *((u_long *)(op+4)) = nextEntryCookie;
4002 /* now we emit the attribute. This is tricky, since
4003 * we need to really stat the file to find out what
4004 * type of entry we've got. Right now, we're copying
4005 * out data from * a buffer, while holding the scp
4006 * locked, so it isn't really convenient to stat
4007 * something now. We'll put in a place holder
4008 * now, and make a second pass before returning this
4009 * to get the real attributes. So, we just skip the
4010 * data for now, and adjust it later. We allocate a
4011 * patch record to make it easy to find this point
4012 * later. The replay will happen at a time when it is
4013 * safe to unlock the directory.
4015 if (infoLevel != 0x103) {
4016 curPatchp = malloc(sizeof(*curPatchp));
4017 osi_QAdd((osi_queue_t **) &dirListPatchesp,
4019 curPatchp->dptr = op;
4020 if (infoLevel >= 0x101)
4021 curPatchp->dptr += 8;
4023 if (smb_hideDotFiles && smb_IsDotFile(dep->name)) {
4024 curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
4027 curPatchp->flags = 0;
4029 curPatchp->fid.cell = scp->fid.cell;
4030 curPatchp->fid.volume = scp->fid.volume;
4031 curPatchp->fid.vnode = ntohl(dep->fid.vnode);
4032 curPatchp->fid.unique = ntohl(dep->fid.unique);
4035 curPatchp->dep = dep;
4038 if (searchFlags & 4)
4039 /* put out resume key */
4040 *((u_long *)origOp) = nextEntryCookie;
4042 /* Adjust byte ptr and count */
4043 origOp += orbytes; /* skip entire record */
4044 bytesInBuffer += orbytes;
4046 /* and pad the record out */
4047 while (--align >= 0) {
4051 } /* if we're including this name */
4052 else if (!NeedShortName &&
4055 dep->fid.vnode != 0 &&
4056 smb_V3MatchMask(dep->name, maskp, CM_FLAG_CASEFOLD)) {
4057 /* We were looking for exact matches, but here's an inexact one*/
4062 /* and adjust curOffset to be where the new cookie is */
4063 thyper.HighPart = 0;
4064 thyper.LowPart = CM_DIR_CHUNKSIZE * numDirChunks;
4065 curOffset = LargeIntegerAdd(thyper, curOffset);
4066 } /* while copying data for dir listing */
4068 /* If we didn't get a star pattern, we did an exact match during the first pass.
4069 * If there were no exact matches found, we fail over to inexact matches by
4070 * marking the query as a star pattern (matches all case permutations), and
4071 * re-running the query.
4073 if (returnedNames == 0 && !starPattern && foundInexact) {
4074 osi_Log0(afsd_logp,"T2 Search: No exact matches. Re-running for inexact matches");
4079 /* release the mutex */
4080 lock_ReleaseMutex(&scp->mx);
4081 if (bufferp) buf_Release(bufferp);
4083 /* apply and free last set of patches; if not doing a star match, this
4084 * will be empty, but better safe (and freeing everything) than sorry.
4086 smb_ApplyV3DirListPatches(scp, &dirListPatchesp, infoLevel, userp,
4089 /* now put out the final parameters */
4090 if (returnedNames == 0) eos = 1;
4091 if (p->opcode == 1) {
4093 outp->parmsp[0] = (unsigned short) dsp->cookie;
4094 outp->parmsp[1] = returnedNames;
4095 outp->parmsp[2] = eos;
4096 outp->parmsp[3] = 0; /* nothing wrong with EAS */
4097 outp->parmsp[4] = 0;
4098 /* don't need last name to continue
4099 * search, cookie is enough. Normally,
4100 * this is the offset of the file name
4101 * of the last entry returned.
4103 outp->totalParms = 10; /* in bytes */
4107 outp->parmsp[0] = returnedNames;
4108 outp->parmsp[1] = eos;
4109 outp->parmsp[2] = 0; /* EAS error */
4110 outp->parmsp[3] = 0; /* last name, as above */
4111 outp->totalParms = 8; /* in bytes */
4114 /* return # of bytes in the buffer */
4115 outp->totalData = bytesInBuffer;
4117 osi_Log2(smb_logp, "T2 search dir done, %d names, code %d",
4118 returnedNames, code);
4120 /* Return error code if unsuccessful on first request */
4121 if (code == 0 && p->opcode == 1 && returnedNames == 0)
4122 code = CM_ERROR_NOSUCHFILE;
4124 /* if we're supposed to close the search after this request, or if
4125 * we're supposed to close the search if we're done, and we're done,
4126 * or if something went wrong, close the search.
4128 /* ((searchFlags & 1) || ((searchFlags & 2) && eos) */
4129 if ((searchFlags & 1) || (returnedNames == 0) ||
4130 ((searchFlags & 2) && eos) || code != 0)
4131 smb_DeleteDirSearch(dsp);
4133 smb_SendTran2Error(vcp, p, opx, code);
4135 smb_SendTran2Packet(vcp, outp, opx);
4137 smb_FreeTran2Packet(outp);
4138 smb_ReleaseDirSearch(dsp);
4139 cm_ReleaseSCache(scp);
4140 cm_ReleaseUser(userp);
4144 long smb_ReceiveV3FindClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4147 smb_dirSearch_t *dsp;
4149 dirHandle = smb_GetSMBParm(inp, 0);
4151 osi_Log1(smb_logp, "SMB3 find close handle %d", dirHandle);
4153 dsp = smb_FindDirSearch(dirHandle);
4156 return CM_ERROR_BADFD;
4158 /* otherwise, we have an FD to destroy */
4159 smb_DeleteDirSearch(dsp);
4160 smb_ReleaseDirSearch(dsp);
4162 /* and return results */
4163 smb_SetSMBDataLength(outp, 0);
4168 long smb_ReceiveV3FindNotifyClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4170 smb_SetSMBDataLength(outp, 0);
4174 long smb_ReceiveV3OpenX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4181 cm_scache_t *dscp; /* dir we're dealing with */
4182 cm_scache_t *scp; /* file we're creating */
4184 int initialModeBits;
4194 int parmSlot; /* which parm we're dealing with */
4202 extraInfo = (smb_GetSMBParm(inp, 2) & 1); /* return extra info */
4203 openFun = smb_GetSMBParm(inp, 8); /* open function */
4204 excl = ((openFun & 3) == 0);
4205 trunc = ((openFun & 3) == 2); /* truncate it */
4206 openMode = (smb_GetSMBParm(inp, 3) & 0x7);
4207 openAction = 0; /* tracks what we did */
4209 attributes = smb_GetSMBParm(inp, 5);
4210 dosTime = smb_GetSMBParm(inp, 6) | (smb_GetSMBParm(inp, 7) << 16);
4212 /* compute initial mode bits based on read-only flag in attributes */
4213 initialModeBits = 0666;
4214 if (attributes & 1) initialModeBits &= ~0222;
4216 pathp = smb_GetSMBData(inp, NULL);
4218 spacep = inp->spacep;
4219 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
4221 if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
4222 /* special case magic file name for receiving IOCTL requests
4223 * (since IOCTL calls themselves aren't getting through).
4226 osi_Log0(smb_logp, "IOCTL Open");
4229 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
4230 smb_SetupIoctlFid(fidp, spacep);
4232 /* set inp->fid so that later read calls in same msg can find fid */
4233 inp->fid = fidp->fid;
4235 /* copy out remainder of the parms */
4237 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
4239 smb_SetSMBParm(outp, parmSlot, /* attrs */ 0); parmSlot++;
4240 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* mod time */
4241 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
4242 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* len */
4243 smb_SetSMBParm(outp, parmSlot, 0x7fff); parmSlot++;
4244 smb_SetSMBParm(outp, parmSlot, openMode); parmSlot++;
4245 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* file type 0 ==> normal file or dir */
4246 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* IPC junk */
4248 /* and the final "always present" stuff */
4249 smb_SetSMBParm(outp, parmSlot, /* openAction found existing file */ 1); parmSlot++;
4250 /* next write out the "unique" ID */
4251 smb_SetSMBParm(outp, parmSlot, 0x1234); parmSlot++;
4252 smb_SetSMBParm(outp, parmSlot, 0x5678); parmSlot++;
4253 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
4254 smb_SetSMBDataLength(outp, 0);
4256 /* and clean up fid reference */
4257 smb_ReleaseFID(fidp);
4261 #ifdef DEBUG_VERBOSE
4263 char *hexp, *asciip;
4264 asciip = (lastNamep ? lastNamep : pathp );
4265 hexp = osi_HexifyString(asciip);
4266 DEBUG_EVENT2("AFS", "V3Open H[%s] A[%s]", hexp, asciip );
4270 userp = smb_GetUser(vcp, inp);
4273 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4275 cm_ReleaseUser(userp);
4276 return CM_ERROR_NOSUCHPATH;
4278 code = cm_NameI(cm_rootSCachep, pathp,
4279 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
4280 userp, tidPathp, &req, &scp);
4282 code = cm_NameI(cm_rootSCachep, spacep->data,
4283 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
4284 userp, tidPathp, &req, &dscp);
4287 cm_ReleaseUser(userp);
4291 /* otherwise, scp points to the parent directory. Do a lookup,
4292 * and truncate the file if we find it, otherwise we create the
4295 if (!lastNamep) lastNamep = pathp;
4297 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD, userp,
4299 if (code && code != CM_ERROR_NOSUCHFILE) {
4300 cm_ReleaseSCache(dscp);
4301 cm_ReleaseUser(userp);
4306 /* if we get here, if code is 0, the file exists and is represented by
4307 * scp. Otherwise, we have to create it. The dir may be represented
4308 * by dscp, or we may have found the file directly. If code is non-zero,
4312 code = cm_CheckOpen(scp, openMode, trunc, userp, &req);
4314 if (dscp) cm_ReleaseSCache(dscp);
4315 cm_ReleaseSCache(scp);
4316 cm_ReleaseUser(userp);
4321 /* oops, file shouldn't be there */
4322 if (dscp) cm_ReleaseSCache(dscp);
4323 cm_ReleaseSCache(scp);
4324 cm_ReleaseUser(userp);
4325 return CM_ERROR_EXISTS;
4329 setAttr.mask = CM_ATTRMASK_LENGTH;
4330 setAttr.length.LowPart = 0;
4331 setAttr.length.HighPart = 0;
4332 code = cm_SetAttr(scp, &setAttr, userp, &req);
4333 openAction = 3; /* truncated existing file */
4335 else openAction = 1; /* found existing file */
4337 else if (!(openFun & 0x10)) {
4338 /* don't create if not found */
4339 if (dscp) cm_ReleaseSCache(dscp);
4340 cm_ReleaseUser(userp);
4341 return CM_ERROR_NOSUCHFILE;
4344 osi_assert(dscp != NULL);
4345 osi_Log1(smb_logp, "smb_ReceiveV3OpenX creating file %s",
4346 osi_LogSaveString(smb_logp, lastNamep));
4347 openAction = 2; /* created file */
4348 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
4349 smb_UnixTimeFromDosUTime(&setAttr.clientModTime, dosTime);
4350 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
4352 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
4353 smb_NotifyChange(FILE_ACTION_ADDED,
4354 FILE_NOTIFY_CHANGE_FILE_NAME,
4355 dscp, lastNamep, NULL, TRUE);
4356 if (!excl && code == CM_ERROR_EXISTS) {
4357 /* not an exclusive create, and someone else tried
4358 * creating it already, then we open it anyway. We
4359 * don't bother retrying after this, since if this next
4360 * fails, that means that the file was deleted after we
4361 * started this call.
4363 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
4367 setAttr.mask = CM_ATTRMASK_LENGTH;
4368 setAttr.length.LowPart = 0;
4369 setAttr.length.HighPart = 0;
4370 code = cm_SetAttr(scp, &setAttr, userp, &req);
4372 } /* lookup succeeded */
4376 /* we don't need this any longer */
4377 if (dscp) cm_ReleaseSCache(dscp);
4380 /* something went wrong creating or truncating the file */
4381 if (scp) cm_ReleaseSCache(scp);
4382 cm_ReleaseUser(userp);
4386 /* make sure we're about to open a file */
4387 if (scp->fileType != CM_SCACHETYPE_FILE) {
4388 cm_ReleaseSCache(scp);
4389 cm_ReleaseUser(userp);
4390 return CM_ERROR_ISDIR;
4393 /* now all we have to do is open the file itself */
4394 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
4397 /* save a pointer to the vnode */
4400 /* compute open mode */
4401 if (openMode != 1) fidp->flags |= SMB_FID_OPENREAD;
4402 if (openMode == 1 || openMode == 2)
4403 fidp->flags |= SMB_FID_OPENWRITE;
4405 smb_ReleaseFID(fidp);
4407 cm_Open(scp, 0, userp);
4409 /* set inp->fid so that later read calls in same msg can find fid */
4410 inp->fid = fidp->fid;
4412 /* copy out remainder of the parms */
4414 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
4415 lock_ObtainMutex(&scp->mx);
4417 smb_SetSMBParm(outp, parmSlot, smb_Attributes(scp)); parmSlot++;
4418 smb_DosUTimeFromUnixTime(&dosTime, scp->clientModTime);
4419 smb_SetSMBParm(outp, parmSlot, dosTime & 0xffff); parmSlot++;
4420 smb_SetSMBParm(outp, parmSlot, (dosTime>>16) & 0xffff); parmSlot++;
4421 smb_SetSMBParm(outp, parmSlot, scp->length.LowPart & 0xffff); parmSlot++;
4422 smb_SetSMBParm(outp, parmSlot, (scp->length.LowPart >> 16) & 0xffff); parmSlot++;
4423 smb_SetSMBParm(outp, parmSlot, openMode); parmSlot++;
4424 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* file type 0 ==> normal file or dir */
4425 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* IPC junk */
4427 /* and the final "always present" stuff */
4428 smb_SetSMBParm(outp, parmSlot, openAction); parmSlot++;
4429 /* next write out the "unique" ID */
4430 smb_SetSMBParm(outp, parmSlot, scp->fid.vnode & 0xffff); parmSlot++;
4431 smb_SetSMBParm(outp, parmSlot, scp->fid.volume & 0xffff); parmSlot++;
4432 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
4433 lock_ReleaseMutex(&scp->mx);
4434 smb_SetSMBDataLength(outp, 0);
4436 osi_Log1(smb_logp, "SMB OpenX opening fid %d", fidp->fid);
4438 cm_ReleaseUser(userp);
4439 /* leave scp held since we put it in fidp->scp */
4443 long smb_ReceiveV3LockingX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4450 unsigned char LockType;
4451 unsigned short NumberOfUnlocks, NumberOfLocks;
4452 unsigned long Timeout;
4454 LARGE_INTEGER LOffset, LLength;
4455 smb_waitingLock_t *waitingLock;
4462 fid = smb_GetSMBParm(inp, 2);
4463 fid = smb_ChainFID(fid, inp);
4465 fidp = smb_FindFID(vcp, fid, 0);
4466 if (!fidp || (fidp->flags & SMB_FID_IOCTL)) {
4467 return CM_ERROR_BADFD;
4469 /* set inp->fid so that later read calls in same msg can find fid */
4472 userp = smb_GetUser(vcp, inp);
4476 lock_ObtainMutex(&scp->mx);
4477 code = cm_SyncOp(scp, NULL, userp, &req, 0,
4478 CM_SCACHESYNC_NEEDCALLBACK
4479 | CM_SCACHESYNC_GETSTATUS
4480 | CM_SCACHESYNC_LOCK);
4481 if (code) goto doneSync;
4483 LockType = smb_GetSMBParm(inp, 3) & 0xff;
4484 Timeout = (smb_GetSMBParm(inp, 5) << 16) + smb_GetSMBParm(inp, 4);
4485 NumberOfUnlocks = smb_GetSMBParm(inp, 6);
4486 NumberOfLocks = smb_GetSMBParm(inp, 7);
4488 op = smb_GetSMBData(inp, NULL);
4490 for (i=0; i<NumberOfUnlocks; i++) {
4491 if (LockType & 0x10) {
4493 LOffset.HighPart = *((LONG *)(op + 4));
4494 LOffset.LowPart = *((DWORD *)(op + 8));
4495 LLength.HighPart = *((LONG *)(op + 12));
4496 LLength.LowPart = *((DWORD *)(op + 16));
4500 /* Not Large Files */
4501 LOffset.HighPart = 0;
4502 LOffset.LowPart = *((DWORD *)(op + 2));
4503 LLength.HighPart = 0;
4504 LLength.LowPart = *((DWORD *)(op + 6));
4507 if (LargeIntegerNotEqualToZero(LOffset))
4509 /* Do not check length -- length check done in cm_Unlock */
4511 code = cm_Unlock(scp, LockType, LOffset, LLength, userp, &req);
4512 if (code) goto done;
4515 for (i=0; i<NumberOfLocks; i++) {
4516 if (LockType & 0x10) {
4518 LOffset.HighPart = *((LONG *)(op + 4));
4519 LOffset.LowPart = *((DWORD *)(op + 8));
4520 LLength.HighPart = *((LONG *)(op + 12));
4521 LLength.LowPart = *((DWORD *)(op + 16));
4525 /* Not Large Files */
4526 LOffset.HighPart = 0;
4527 LOffset.LowPart = *((DWORD *)(op + 2));
4528 LLength.HighPart = 0;
4529 LLength.LowPart = *((DWORD *)(op + 6));
4532 if (LargeIntegerNotEqualToZero(LOffset))
4534 if (LargeIntegerLessThan(LOffset, scp->length))
4537 code = cm_Lock(scp, LockType, LOffset, LLength, Timeout,
4538 userp, &req, &lockp);
4539 if (code == CM_ERROR_WOULDBLOCK && Timeout != 0) {
4540 /* Put on waiting list */
4541 waitingLock = malloc(sizeof(smb_waitingLock_t));
4542 waitingLock->vcp = vcp;
4543 waitingLock->inp = smb_CopyPacket(inp);
4544 waitingLock->outp = smb_CopyPacket(outp);
4545 waitingLock->timeRemaining = Timeout;
4546 waitingLock->lockp = lockp;
4547 lock_ObtainWrite(&smb_globalLock);
4548 osi_QAdd((osi_queue_t **)&smb_allWaitingLocks,
4550 osi_Wakeup((long) &smb_allWaitingLocks);
4551 lock_ReleaseWrite(&smb_globalLock);
4552 /* don't send reply immediately */
4553 outp->flags |= SMB_PACKETFLAG_NOSEND;
4559 /* release any locks acquired before the failure */
4562 smb_SetSMBDataLength(outp, 0);
4564 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_LOCK);
4566 lock_ReleaseMutex(&scp->mx);
4567 cm_ReleaseUser(userp);
4568 smb_ReleaseFID(fidp);
4573 long smb_ReceiveV3GetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4585 fid = smb_GetSMBParm(inp, 0);
4586 fid = smb_ChainFID(fid, inp);
4588 fidp = smb_FindFID(vcp, fid, 0);
4589 if (!fidp || (fidp->flags & SMB_FID_IOCTL)) {
4590 return CM_ERROR_BADFD;
4593 userp = smb_GetUser(vcp, inp);
4597 /* otherwise, stat the file */
4598 lock_ObtainMutex(&scp->mx);
4599 code = cm_SyncOp(scp, NULL, userp, &req, 0,
4600 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4601 if (code) goto done;
4603 /* decode times. We need a search time, but the response to this
4604 * call provides the date first, not the time, as returned in the
4605 * searchTime variable. So we take the high-order bits first.
4607 smb_SearchTimeFromUnixTime(&searchTime, scp->clientModTime);
4608 smb_SetSMBParm(outp, 0, (searchTime >> 16) & 0xffff); /* ctime */
4609 smb_SetSMBParm(outp, 1, searchTime & 0xffff);
4610 smb_SetSMBParm(outp, 2, (searchTime >> 16) & 0xffff); /* atime */
4611 smb_SetSMBParm(outp, 3, searchTime & 0xffff);
4612 smb_SetSMBParm(outp, 4, (searchTime >> 16) & 0xffff); /* mtime */
4613 smb_SetSMBParm(outp, 5, searchTime & 0xffff);
4615 /* now handle file size and allocation size */
4616 smb_SetSMBParm(outp, 6, scp->length.LowPart & 0xffff); /* file size */
4617 smb_SetSMBParm(outp, 7, (scp->length.LowPart >> 16) & 0xffff);
4618 smb_SetSMBParm(outp, 8, scp->length.LowPart & 0xffff); /* alloc size */
4619 smb_SetSMBParm(outp, 9, (scp->length.LowPart >> 16) & 0xffff);
4621 /* file attribute */
4622 smb_SetSMBParm(outp, 10, smb_Attributes(scp));
4624 /* and finalize stuff */
4625 smb_SetSMBDataLength(outp, 0);
4629 lock_ReleaseMutex(&scp->mx);
4630 cm_ReleaseUser(userp);
4631 smb_ReleaseFID(fidp);
4635 long smb_ReceiveV3SetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4649 fid = smb_GetSMBParm(inp, 0);
4650 fid = smb_ChainFID(fid, inp);
4652 fidp = smb_FindFID(vcp, fid, 0);
4653 if (!fidp || (fidp->flags & SMB_FID_IOCTL)) {
4654 return CM_ERROR_BADFD;
4657 userp = smb_GetUser(vcp, inp);
4661 /* now prepare to call cm_setattr. This message only sets various times,
4662 * and AFS only implements mtime, and we'll set the mtime if that's
4663 * requested. The others we'll ignore.
4665 searchTime = smb_GetSMBParm(inp, 5) | (smb_GetSMBParm(inp, 6) << 16);
4667 if (searchTime != 0) {
4668 smb_UnixTimeFromSearchTime(&unixTime, searchTime);
4670 if ( unixTime != -1 ) {
4671 attrs.mask = CM_ATTRMASK_CLIENTMODTIME;
4672 attrs.clientModTime = unixTime;
4673 code = cm_SetAttr(scp, &attrs, userp, &req);
4675 osi_Log1(smb_logp, "SMB receive V3SetAttributes [fid=%ld]", fid);
4677 osi_Log1(smb_logp, "**smb_UnixTimeFromSearchTime failed searchTime=%ld", searchTime);
4682 cm_ReleaseUser(userp);
4683 smb_ReleaseFID(fidp);
4688 long smb_ReceiveV3ReadX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4691 long count, finalCount;
4698 fd = smb_GetSMBParm(inp, 2);
4699 count = smb_GetSMBParm(inp, 5);
4700 offset.HighPart = 0; /* too bad */
4701 offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
4703 osi_Log3(smb_logp, "smb_ReceiveV3Read fd %d, off 0x%x, size 0x%x",
4704 fd, offset.LowPart, count);
4706 fd = smb_ChainFID(fd, inp);
4707 fidp = smb_FindFID(vcp, fd, 0);
4709 return CM_ERROR_BADFD;
4711 /* set inp->fid so that later read calls in same msg can find fid */
4714 if (fidp->flags & SMB_FID_IOCTL) {
4715 return smb_IoctlV3Read(fidp, vcp, inp, outp);
4718 userp = smb_GetUser(vcp, inp);
4720 /* 0 and 1 are reserved for request chaining, were setup by our caller,
4721 * and will be further filled in after we return.
4723 smb_SetSMBParm(outp, 2, 0); /* remaining bytes, for pipes */
4724 smb_SetSMBParm(outp, 3, 0); /* resvd */
4725 smb_SetSMBParm(outp, 4, 0); /* resvd */
4726 smb_SetSMBParm(outp, 5, count); /* # of bytes we're going to read */
4727 /* fill in #6 when we have all the parameters' space reserved */
4728 smb_SetSMBParm(outp, 7, 0); /* resv'd */
4729 smb_SetSMBParm(outp, 8, 0); /* resv'd */
4730 smb_SetSMBParm(outp, 9, 0); /* resv'd */
4731 smb_SetSMBParm(outp, 10, 0); /* resv'd */
4732 smb_SetSMBParm(outp, 11, 0); /* reserved */
4734 /* get op ptr after putting in the parms, since otherwise we don't
4735 * know where the data really is.
4737 op = smb_GetSMBData(outp, NULL);
4739 /* now fill in offset from start of SMB header to first data byte (to op) */
4740 smb_SetSMBParm(outp, 6, ((int) (op - outp->data)));
4742 /* set the packet data length the count of the # of bytes */
4743 smb_SetSMBDataLength(outp, count);
4746 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount);
4748 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount, FALSE);
4751 /* fix some things up */
4752 smb_SetSMBParm(outp, 5, finalCount);
4753 smb_SetSMBDataLength(outp, finalCount);
4755 smb_ReleaseFID(fidp);
4757 cm_ReleaseUser(userp);
4762 * Values for createDisp, copied from NTDDK.H
4764 #define FILE_SUPERSEDE 0 // (???)
4765 #define FILE_OPEN 1 // (open)
4766 #define FILE_CREATE 2 // (exclusive)
4767 #define FILE_OPEN_IF 3 // (non-exclusive)
4768 #define FILE_OVERWRITE 4 // (open & truncate, but do not create)
4769 #define FILE_OVERWRITE_IF 5 // (open & truncate, or create)
4771 long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4773 char *pathp, *realPathp;
4777 cm_scache_t *dscp; /* parent dir */
4778 cm_scache_t *scp; /* file to create or open */
4779 cm_scache_t *targetScp; /* if scp is a symlink */
4783 unsigned short nameLength;
4785 unsigned int requestOpLock;
4786 unsigned int requestBatchOpLock;
4787 unsigned int mustBeDir;
4788 unsigned int treeCreate;
4790 unsigned int desiredAccess;
4791 unsigned int extAttributes;
4792 unsigned int createDisp;
4793 unsigned int createOptions;
4794 int initialModeBits;
4795 unsigned short baseFid;
4796 smb_fid_t *baseFidp;
4798 cm_scache_t *baseDirp;
4799 unsigned short openAction;
4814 nameLength = smb_GetSMBOffsetParm(inp, 2, 1);
4815 flags = smb_GetSMBOffsetParm(inp, 3, 1)
4816 | (smb_GetSMBOffsetParm(inp, 4, 1) << 16);
4817 requestOpLock = flags & 0x02;
4818 requestBatchOpLock = flags & 0x04;
4819 mustBeDir = flags & 0x08;
4822 * Why all of a sudden 32-bit FID?
4823 * We will reject all bits higher than 16.
4825 if (smb_GetSMBOffsetParm(inp, 6, 1) != 0)
4826 return CM_ERROR_INVAL;
4827 baseFid = smb_GetSMBOffsetParm(inp, 5, 1);
4828 desiredAccess = smb_GetSMBOffsetParm(inp, 7, 1)
4829 | (smb_GetSMBOffsetParm(inp, 8, 1) << 16);
4830 extAttributes = smb_GetSMBOffsetParm(inp, 13, 1)
4831 | (smb_GetSMBOffsetParm(inp, 14, 1) << 16);
4832 createDisp = smb_GetSMBOffsetParm(inp, 17, 1)
4833 | (smb_GetSMBOffsetParm(inp, 18, 1) << 16);
4834 createOptions = smb_GetSMBOffsetParm(inp, 19, 1)
4835 | (smb_GetSMBOffsetParm(inp, 20, 1) << 16);
4837 /* mustBeDir is never set; createOptions directory bit seems to be
4840 if (createOptions & 1)
4842 else if (createOptions & 0x40)
4848 * compute initial mode bits based on read-only flag in
4849 * extended attributes
4851 initialModeBits = 0666;
4852 if (extAttributes & 1)
4853 initialModeBits &= ~0222;
4855 pathp = smb_GetSMBData(inp, NULL);
4856 /* Sometimes path is not null-terminated, so we make a copy. */
4857 realPathp = malloc(nameLength+1);
4858 memcpy(realPathp, pathp, nameLength);
4859 realPathp[nameLength] = 0;
4861 spacep = inp->spacep;
4862 smb_StripLastComponent(spacep->data, &lastNamep, realPathp);
4864 osi_Log1(smb_logp,"NTCreateX for [%s]",osi_LogSaveString(smb_logp,realPathp));
4865 osi_Log4(smb_logp,"... da=[%x] ea=[%x] cd=[%x] co=[%x]", desiredAccess, extAttributes, createDisp, createOptions);
4866 osi_Log2(smb_logp,"... flags=[%x] lastNamep=[%s]", flags, osi_LogSaveString(smb_logp,(lastNamep?lastNamep:"null")));
4868 if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
4869 /* special case magic file name for receiving IOCTL requests
4870 * (since IOCTL calls themselves aren't getting through).
4872 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
4873 smb_SetupIoctlFid(fidp, spacep);
4874 osi_Log1(smb_logp,"NTCreateX Setting up IOCTL on fid[%d]",fidp->fid);
4876 /* set inp->fid so that later read calls in same msg can find fid */
4877 inp->fid = fidp->fid;
4881 smb_SetSMBParmByte(outp, parmSlot, 0); /* oplock */
4882 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
4883 smb_SetSMBParmLong(outp, parmSlot, 1); parmSlot += 2; /* Action */
4885 memset(&ft, 0, sizeof(ft));
4886 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
4887 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
4888 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
4889 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
4890 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2; /* attr */
4891 sz.HighPart = 0x7fff; sz.LowPart = 0;
4892 smb_SetSMBParmDouble(outp, parmSlot, (char *)&sz); parmSlot += 4; /* alen */
4893 smb_SetSMBParmDouble(outp, parmSlot, (char *)&sz); parmSlot += 4; /* len */
4894 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* filetype */
4895 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* dev state */
4896 smb_SetSMBParmByte(outp, parmSlot, 0); /* is a dir? */
4897 smb_SetSMBDataLength(outp, 0);
4899 /* clean up fid reference */
4900 smb_ReleaseFID(fidp);
4905 #ifdef DEBUG_VERBOSE
4907 char *hexp, *asciip;
4908 asciip = (lastNamep? lastNamep : realPathp);
4909 hexp = osi_HexifyString( asciip );
4910 DEBUG_EVENT2("AFS", "NTCreateX H[%s] A[%s]", hexp, asciip);
4914 userp = smb_GetUser(vcp, inp);
4916 osi_Log1(smb_logp, "NTCreateX Invalid user [%d]", ((smb_t *) inp)->uid);
4918 return CM_ERROR_INVAL;
4922 baseDirp = cm_rootSCachep;
4923 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4924 if (code == CM_ERROR_TIDIPC) {
4925 /* Attempt to use a TID allocated for IPC. The client
4926 * is probably looking for DCE RPC end points which we
4928 osi_Log0(smb_logp, "NTCreateX received IPC TID");
4930 cm_ReleaseUser(userp);
4931 return CM_ERROR_NOSUCHFILE;
4935 baseFidp = smb_FindFID(vcp, baseFid, 0);
4937 osi_Log1(smb_logp, "NTCreateX Invalid base fid [%d]", baseFid);
4939 cm_ReleaseUser(userp);
4940 return CM_ERROR_INVAL;
4942 baseDirp = baseFidp->scp;
4946 osi_Log1(smb_logp, "NTCreateX tidPathp=[%s]", (tidPathp==NULL)?"null": osi_LogSaveString(smb_logp,tidPathp));
4948 /* compute open mode */
4950 if (desiredAccess & DELETE)
4951 fidflags |= SMB_FID_OPENDELETE;
4952 if (desiredAccess & AFS_ACCESS_READ)
4953 fidflags |= SMB_FID_OPENREAD;
4954 if (desiredAccess & AFS_ACCESS_WRITE)
4955 fidflags |= SMB_FID_OPENWRITE;
4959 /* For an exclusive create, we want to do a case sensitive match for the last component. */
4960 if ( createDisp == FILE_CREATE ||
4961 createDisp == FILE_OVERWRITE ||
4962 createDisp == FILE_OVERWRITE_IF) {
4963 code = cm_NameI(baseDirp, spacep->data, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
4964 userp, tidPathp, &req, &dscp);
4966 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp, CM_FLAG_FOLLOW,
4968 if (code == CM_ERROR_NOSUCHFILE) {
4969 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp,
4970 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, &req, &scp);
4971 if (code == 0 && realDirFlag == 1) {
4972 cm_ReleaseSCache(scp);
4973 cm_ReleaseSCache(dscp);
4974 cm_ReleaseUser(userp);
4976 return CM_ERROR_EXISTS;
4982 code = cm_NameI(baseDirp, realPathp, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
4983 userp, tidPathp, &req, &scp);
4988 if (!foundscp || (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE))) {
4989 /* look up parent directory */
4990 /* If we are trying to create a path (i.e. multiple nested directories), then we don't *need*
4991 * the immediate parent. We have to work our way up realPathp until we hit something that we
4999 code = cm_NameI(baseDirp, spacep->data,
5000 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
5001 userp, tidPathp, &req, &dscp);
5004 (tp = strrchr(spacep->data,'\\')) &&
5005 (createDisp == FILE_CREATE) &&
5006 (realDirFlag == 1)) {
5009 treeStartp = realPathp + (tp - spacep->data);
5011 if (*tp && !smb_IsLegalFilename(tp)) {
5013 smb_ReleaseFID(baseFidp);
5014 cm_ReleaseUser(userp);
5016 return CM_ERROR_BADNTFILENAME;
5026 smb_ReleaseFID(baseFidp);
5029 osi_Log0(smb_logp,"NTCreateX parent not found");
5030 cm_ReleaseUser(userp);
5035 if (treeCreate && dscp->fileType == CM_SCACHETYPE_FILE) {
5036 /* A file exists where we want a directory. */
5037 cm_ReleaseSCache(dscp);
5038 cm_ReleaseUser(userp);
5040 return CM_ERROR_EXISTS;
5044 lastNamep = realPathp;
5048 if (!smb_IsLegalFilename(lastNamep)) {
5049 cm_ReleaseSCache(dscp);
5050 cm_ReleaseUser(userp);
5052 return CM_ERROR_BADNTFILENAME;
5055 if (!foundscp && !treeCreate) {
5056 if ( createDisp == FILE_CREATE ||
5057 createDisp == FILE_OVERWRITE ||
5058 createDisp == FILE_OVERWRITE_IF)
5060 code = cm_Lookup(dscp, lastNamep,
5061 CM_FLAG_FOLLOW, userp, &req, &scp);
5063 code = cm_Lookup(dscp, lastNamep,
5064 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
5067 if (code && code != CM_ERROR_NOSUCHFILE) {
5068 cm_ReleaseSCache(dscp);
5069 cm_ReleaseUser(userp);
5077 smb_ReleaseFID(baseFidp);
5080 /* if we get here, if code is 0, the file exists and is represented by
5081 * scp. Otherwise, we have to create it. The dir may be represented
5082 * by dscp, or we may have found the file directly. If code is non-zero,
5085 if (code == 0 && !treeCreate) {
5086 if (createDisp == FILE_CREATE) {
5087 /* oops, file shouldn't be there */
5088 if (dscp) cm_ReleaseSCache(dscp);
5089 cm_ReleaseSCache(scp);
5090 cm_ReleaseUser(userp);
5092 return CM_ERROR_EXISTS;
5095 if ( createDisp == FILE_OVERWRITE ||
5096 createDisp == FILE_OVERWRITE_IF) {
5097 setAttr.mask = CM_ATTRMASK_LENGTH;
5098 setAttr.length.LowPart = 0;
5099 setAttr.length.HighPart = 0;
5100 /* now watch for a symlink */
5102 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
5104 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
5106 /* we have a more accurate file to use (the
5107 * target of the symbolic link). Otherwise,
5108 * we'll just use the symlink anyway.
5110 osi_Log2(smb_logp, "symlink vp %x to vp %x",
5112 cm_ReleaseSCache(scp);
5116 code = cm_SetAttr(scp, &setAttr, userp, &req);
5117 openAction = 3; /* truncated existing file */
5120 openAction = 1; /* found existing file */
5122 code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp,
5125 if (dscp) cm_ReleaseSCache(dscp);
5126 cm_ReleaseSCache(scp);
5127 cm_ReleaseUser(userp);
5132 else if (createDisp == FILE_OPEN || createDisp == FILE_OVERWRITE) {
5133 /* don't create if not found */
5134 if (dscp) cm_ReleaseSCache(dscp);
5135 cm_ReleaseUser(userp);
5137 return CM_ERROR_NOSUCHFILE;
5139 else if (realDirFlag == 0 || realDirFlag == -1) {
5140 osi_assert(dscp != NULL);
5141 osi_Log1(smb_logp, "smb_ReceiveNTCreateX creating file %s",
5142 osi_LogSaveString(smb_logp, lastNamep));
5143 openAction = 2; /* created file */
5144 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
5145 setAttr.clientModTime = time(NULL);
5146 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
5148 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
5149 smb_NotifyChange(FILE_ACTION_ADDED,
5150 FILE_NOTIFY_CHANGE_FILE_NAME,
5151 dscp, lastNamep, NULL, TRUE);
5152 if (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE) {
5153 /* Not an exclusive create, and someone else tried
5154 * creating it already, then we open it anyway. We
5155 * don't bother retrying after this, since if this next
5156 * fails, that means that the file was deleted after we
5157 * started this call.
5159 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
5162 if (createDisp == FILE_OVERWRITE_IF) {
5163 setAttr.mask = CM_ATTRMASK_LENGTH;
5164 setAttr.length.LowPart = 0;
5165 setAttr.length.HighPart = 0;
5167 /* now watch for a symlink */
5169 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
5171 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
5173 /* we have a more accurate file to use (the
5174 * target of the symbolic link). Otherwise,
5175 * we'll just use the symlink anyway.
5177 osi_Log2(smb_logp, "symlink vp %x to vp %x",
5179 cm_ReleaseSCache(scp);
5183 code = cm_SetAttr(scp, &setAttr, userp, &req);
5185 } /* lookup succeeded */
5190 char *cp; /* This component */
5191 int clen = 0; /* length of component */
5195 /* create directory */
5197 treeStartp = lastNamep;
5198 osi_assert(dscp != NULL);
5199 osi_Log1(smb_logp, "smb_ReceiveNTCreateX creating directory [%s]",
5200 osi_LogSaveString(smb_logp, treeStartp));
5201 openAction = 2; /* created directory */
5203 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
5204 setAttr.clientModTime = time(NULL);
5211 tp = strchr(pp, '\\');
5215 isLast = 1; /* indicate last component. the supplied path never ends in a slash */
5219 strncpy(cp,pp,clen);
5226 continue; /* the supplied path can't have consecutive slashes either , but */
5228 /* cp is the next component to be created. */
5229 code = cm_MakeDir(tscp, cp, 0, &setAttr, userp, &req);
5230 if (code == 0 && (tscp->flags & CM_SCACHEFLAG_ANYWATCH))
5231 smb_NotifyChange(FILE_ACTION_ADDED,
5232 FILE_NOTIFY_CHANGE_DIR_NAME,
5233 tscp, cp, NULL, TRUE);
5235 (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE)) {
5236 /* Not an exclusive create, and someone else tried
5237 * creating it already, then we open it anyway. We
5238 * don't bother retrying after this, since if this next
5239 * fails, that means that the file was deleted after we
5240 * started this call.
5242 code = cm_Lookup(tscp, cp, CM_FLAG_CASEFOLD,
5247 if (!isLast) { /* for anything other than dscp, release it unless it's the last one */
5248 cm_ReleaseSCache(tscp);
5249 tscp = scp; /* Newly created directory will be next parent */
5254 * if we get here and code == 0, then scp is the last directory created, and tscp is the
5255 * parent of scp. dscp got released if dscp != tscp. both tscp and scp are held.
5261 /* something went wrong creating or truncating the file */
5262 if (scp) cm_ReleaseSCache(scp);
5263 if (dscp) cm_ReleaseSCache(dscp);
5264 cm_ReleaseUser(userp);
5269 /* make sure we have file vs. dir right (only applies for single component case) */
5270 if (realDirFlag == 0 && scp->fileType != CM_SCACHETYPE_FILE) {
5271 /* now watch for a symlink */
5273 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
5274 cm_scache_t * targetScp = 0;
5275 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
5277 /* we have a more accurate file to use (the
5278 * target of the symbolic link). Otherwise,
5279 * we'll just use the symlink anyway.
5281 osi_Log2(smb_logp, "symlink vp %x to vp %x",
5283 cm_ReleaseSCache(scp);
5288 if (scp->fileType != CM_SCACHETYPE_FILE) {
5289 cm_ReleaseSCache(scp);
5290 cm_ReleaseUser(userp);
5292 return CM_ERROR_ISDIR;
5296 /* (only applies to single component case) */
5297 if (realDirFlag == 1 && scp->fileType == CM_SCACHETYPE_FILE) {
5298 cm_ReleaseSCache(scp);
5299 if (dscp) cm_ReleaseSCache(dscp);
5300 cm_ReleaseUser(userp);
5302 return CM_ERROR_NOTDIR;
5305 /* open the file itself */
5306 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
5308 /* save a pointer to the vnode */
5311 fidp->flags = fidflags;
5313 /* save parent dir and pathname for delete or change notification */
5314 if (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE)) {
5315 fidp->flags |= SMB_FID_NTOPEN;
5316 fidp->NTopen_dscp = dscp;
5317 cm_HoldSCache(dscp);
5318 fidp->NTopen_pathp = strdup(lastNamep);
5320 fidp->NTopen_wholepathp = realPathp;
5322 /* we don't need this any longer */
5323 if (dscp) cm_ReleaseSCache(dscp);
5324 cm_Open(scp, 0, userp);
5326 /* set inp->fid so that later read calls in same msg can find fid */
5327 inp->fid = fidp->fid;
5331 lock_ObtainMutex(&scp->mx);
5332 smb_SetSMBParmByte(outp, parmSlot, 0); /* oplock */
5333 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
5334 smb_SetSMBParmLong(outp, parmSlot, openAction); parmSlot += 2;
5335 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
5336 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
5337 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
5338 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
5339 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
5340 smb_SetSMBParmLong(outp, parmSlot, smb_ExtAttributes(scp));
5342 smb_SetSMBParmDouble(outp, parmSlot, (char *)&scp->length); parmSlot += 4;
5343 smb_SetSMBParmDouble(outp, parmSlot, (char *)&scp->length); parmSlot += 4;
5344 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* filetype */
5345 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* dev state */
5346 smb_SetSMBParmByte(outp, parmSlot,
5347 scp->fileType == CM_SCACHETYPE_DIRECTORY); /* is a dir? */
5348 lock_ReleaseMutex(&scp->mx);
5349 smb_SetSMBDataLength(outp, 0);
5351 osi_Log2(smb_logp, "SMB NT CreateX opening fid %d path %s", fidp->fid,
5352 osi_LogSaveString(smb_logp, realPathp));
5354 smb_ReleaseFID(fidp);
5356 cm_ReleaseUser(userp);
5358 /* Can't free realPathp if we get here since fidp->NTopen_wholepathp is pointing there */
5360 /* leave scp held since we put it in fidp->scp */
5365 * A lot of stuff copied verbatim from NT Create&X to NT Tran Create.
5366 * Instead, ultimately, would like to use a subroutine for common code.
5368 long smb_ReceiveNTTranCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5370 char *pathp, *realPathp;
5374 cm_scache_t *dscp; /* parent dir */
5375 cm_scache_t *scp; /* file to create or open */
5376 cm_scache_t *targetScp; /* if scp is a symlink */
5379 unsigned long nameLength;
5381 unsigned int requestOpLock;
5382 unsigned int requestBatchOpLock;
5383 unsigned int mustBeDir;
5384 unsigned int extendedRespRequired;
5386 unsigned int desiredAccess;
5387 #ifdef DEBUG_VERBOSE
5388 unsigned int allocSize;
5389 unsigned int shareAccess;
5391 unsigned int extAttributes;
5392 unsigned int createDisp;
5393 #ifdef DEBUG_VERBOSE
5396 unsigned int createOptions;
5397 int initialModeBits;
5398 unsigned short baseFid;
5399 smb_fid_t *baseFidp;
5401 cm_scache_t *baseDirp;
5402 unsigned short openAction;
5408 int parmOffset, dataOffset;
5419 parmOffset = smb_GetSMBOffsetParm(inp, 11, 1)
5420 | (smb_GetSMBOffsetParm(inp, 12, 1) << 16);
5421 parmp = inp->data + parmOffset;
5422 lparmp = (ULONG *) parmp;
5425 requestOpLock = flags & 0x02;
5426 requestBatchOpLock = flags & 0x04;
5427 mustBeDir = flags & 0x08;
5428 extendedRespRequired = flags & 0x10;
5431 * Why all of a sudden 32-bit FID?
5432 * We will reject all bits higher than 16.
5434 if (lparmp[1] & 0xFFFF0000)
5435 return CM_ERROR_INVAL;
5436 baseFid = (unsigned short)lparmp[1];
5437 desiredAccess = lparmp[2];
5438 #ifdef DEBUG_VERBOSE
5439 allocSize = lparmp[3];
5440 #endif /* DEBUG_VERSOSE */
5441 extAttributes = lparmp[5];
5443 shareAccess = lparmp[6];
5445 createDisp = lparmp[7];
5446 createOptions = lparmp[8];
5447 #ifdef DEBUG_VERBOSE
5450 nameLength = lparmp[11];
5452 #ifdef DEBUG_VERBOSE
5453 osi_Log4(smb_logp,"NTTranCreate with da[%x],ea[%x],sa[%x],cd[%x]",desiredAccess,extAttributes,shareAccess,createDisp);
5454 osi_Log3(smb_logp,"... co[%x],sdl[%x],as[%x]",createOptions,sdLen,allocSize);
5455 osi_Log1(smb_logp,"... flags[%x]",flags);
5458 /* mustBeDir is never set; createOptions directory bit seems to be
5461 if (createOptions & 1)
5463 else if (createOptions & 0x40)
5469 * compute initial mode bits based on read-only flag in
5470 * extended attributes
5472 initialModeBits = 0666;
5473 if (extAttributes & 1)
5474 initialModeBits &= ~0222;
5476 pathp = parmp + (13 * sizeof(ULONG)) + sizeof(UCHAR);
5477 /* Sometimes path is not null-terminated, so we make a copy. */
5478 realPathp = malloc(nameLength+1);
5479 memcpy(realPathp, pathp, nameLength);
5480 realPathp[nameLength] = 0;
5482 spacep = cm_GetSpace();
5483 smb_StripLastComponent(spacep->data, &lastNamep, realPathp);
5486 * Nothing here to handle SMB_IOCTL_FILENAME.
5487 * Will add it if necessary.
5490 #ifdef DEBUG_VERBOSE
5492 char *hexp, *asciip;
5493 asciip = (lastNamep? lastNamep : realPathp);
5494 hexp = osi_HexifyString( asciip );
5495 DEBUG_EVENT2("AFS", "NTTranCreate H[%s] A[%s]", hexp, asciip);
5500 userp = smb_GetUser(vcp, inp);
5502 osi_Log1(smb_logp, "NTTranCreate invalid user [%d]", ((smb_t *) inp)->uid);
5504 return CM_ERROR_INVAL;
5508 baseDirp = cm_rootSCachep;
5509 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5510 if(code == CM_ERROR_TIDIPC) {
5511 /* Attempt to use TID allocated for IPC. The client is
5512 * probably trying to locate DCE RPC endpoints, which we
5514 osi_Log0(smb_logp, "NTTranCreate received IPC TID");
5516 cm_ReleaseUser(userp);
5517 return CM_ERROR_NOSUCHPATH;
5521 baseFidp = smb_FindFID(vcp, baseFid, 0);
5523 osi_Log1(smb_logp, "NTTranCreate Invalid fid [%d]", baseFid);
5525 cm_ReleaseUser(userp);
5526 return CM_ERROR_INVAL;
5528 baseDirp = baseFidp->scp;
5532 /* compute open mode */
5534 if (desiredAccess & DELETE)
5535 fidflags |= SMB_FID_OPENDELETE;
5536 if (desiredAccess & AFS_ACCESS_READ)
5537 fidflags |= SMB_FID_OPENREAD;
5538 if (desiredAccess & AFS_ACCESS_WRITE)
5539 fidflags |= SMB_FID_OPENWRITE;
5543 if ( createDisp == FILE_OPEN ||
5544 createDisp == FILE_OVERWRITE ||
5545 createDisp == FILE_OVERWRITE_IF) {
5546 code = cm_NameI(baseDirp, spacep->data, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
5547 userp, tidPathp, &req, &dscp);
5549 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp, CM_FLAG_FOLLOW,
5551 if (code == CM_ERROR_NOSUCHFILE) {
5552 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp,
5553 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, &req, &scp);
5554 if (code == 0 && realDirFlag == 1) {
5555 cm_ReleaseSCache(scp);
5556 cm_ReleaseSCache(dscp);
5557 cm_ReleaseUser(userp);
5559 return CM_ERROR_EXISTS;
5565 code = cm_NameI(baseDirp, realPathp, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
5566 userp, tidPathp, &req, &scp);
5572 || (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE))) {
5573 /* look up parent directory */
5575 code = cm_NameI(baseDirp, spacep->data,
5576 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
5577 userp, tidPathp, &req, &dscp);
5581 cm_FreeSpace(spacep);
5584 smb_ReleaseFID(baseFidp);
5589 cm_ReleaseUser(userp);
5594 if (!lastNamep) lastNamep = realPathp;
5597 if (!smb_IsLegalFilename(lastNamep))
5598 return CM_ERROR_BADNTFILENAME;
5601 if (createDisp == FILE_CREATE || createDisp == FILE_OVERWRITE_IF) {
5602 code = cm_Lookup(dscp, lastNamep,
5603 CM_FLAG_FOLLOW, userp, &req, &scp);
5605 code = cm_Lookup(dscp, lastNamep,
5606 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
5609 if (code && code != CM_ERROR_NOSUCHFILE) {
5610 cm_ReleaseSCache(dscp);
5611 cm_ReleaseUser(userp);
5619 smb_ReleaseFID(baseFidp);
5622 cm_FreeSpace(spacep);
5625 /* if we get here, if code is 0, the file exists and is represented by
5626 * scp. Otherwise, we have to create it. The dir may be represented
5627 * by dscp, or we may have found the file directly. If code is non-zero,
5631 code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp,
5634 if (dscp) cm_ReleaseSCache(dscp);
5635 cm_ReleaseSCache(scp);
5636 cm_ReleaseUser(userp);
5641 if (createDisp == FILE_CREATE) {
5642 /* oops, file shouldn't be there */
5643 if (dscp) cm_ReleaseSCache(dscp);
5644 cm_ReleaseSCache(scp);
5645 cm_ReleaseUser(userp);
5647 return CM_ERROR_EXISTS;
5650 if (createDisp == FILE_OVERWRITE ||
5651 createDisp == FILE_OVERWRITE_IF) {
5652 setAttr.mask = CM_ATTRMASK_LENGTH;
5653 setAttr.length.LowPart = 0;
5654 setAttr.length.HighPart = 0;
5656 /* now watch for a symlink */
5658 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
5660 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
5662 /* we have a more accurate file to use (the
5663 * target of the symbolic link). Otherwise,
5664 * we'll just use the symlink anyway.
5666 osi_Log2(smb_logp, "symlink vp %x to vp %x",
5668 cm_ReleaseSCache(scp);
5672 code = cm_SetAttr(scp, &setAttr, userp, &req);
5673 openAction = 3; /* truncated existing file */
5675 else openAction = 1; /* found existing file */
5677 else if (createDisp == FILE_OPEN || createDisp == FILE_OVERWRITE) {
5678 /* don't create if not found */
5679 if (dscp) cm_ReleaseSCache(dscp);
5680 cm_ReleaseUser(userp);
5682 return CM_ERROR_NOSUCHFILE;
5684 else if (realDirFlag == 0 || realDirFlag == -1) {
5685 osi_assert(dscp != NULL);
5686 osi_Log1(smb_logp, "smb_ReceiveNTTranCreate creating file %s",
5687 osi_LogSaveString(smb_logp, lastNamep));
5688 openAction = 2; /* created file */
5689 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
5690 setAttr.clientModTime = time(NULL);
5691 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
5693 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
5694 smb_NotifyChange(FILE_ACTION_ADDED,
5695 FILE_NOTIFY_CHANGE_FILE_NAME,
5696 dscp, lastNamep, NULL, TRUE);
5697 if (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE) {
5698 /* Not an exclusive create, and someone else tried
5699 * creating it already, then we open it anyway. We
5700 * don't bother retrying after this, since if this next
5701 * fails, that means that the file was deleted after we
5702 * started this call.
5704 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
5707 if (createDisp == FILE_OVERWRITE_IF) {
5708 setAttr.mask = CM_ATTRMASK_LENGTH;
5709 setAttr.length.LowPart = 0;
5710 setAttr.length.HighPart = 0;
5712 /* now watch for a symlink */
5714 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
5716 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
5718 /* we have a more accurate file to use (the
5719 * target of the symbolic link). Otherwise,
5720 * we'll just use the symlink anyway.
5722 osi_Log2(smb_logp, "symlink vp %x to vp %x",
5724 cm_ReleaseSCache(scp);
5728 code = cm_SetAttr(scp, &setAttr, userp, &req);
5730 } /* lookup succeeded */
5734 /* create directory */
5735 osi_assert(dscp != NULL);
5737 "smb_ReceiveNTTranCreate creating directory %s",
5738 osi_LogSaveString(smb_logp, lastNamep));
5739 openAction = 2; /* created directory */
5740 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
5741 setAttr.clientModTime = time(NULL);
5742 code = cm_MakeDir(dscp, lastNamep, 0, &setAttr, userp, &req);
5743 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
5744 smb_NotifyChange(FILE_ACTION_ADDED,
5745 FILE_NOTIFY_CHANGE_DIR_NAME,
5746 dscp, lastNamep, NULL, TRUE);
5748 (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE)) {
5749 /* Not an exclusive create, and someone else tried
5750 * creating it already, then we open it anyway. We
5751 * don't bother retrying after this, since if this next
5752 * fails, that means that the file was deleted after we
5753 * started this call.
5755 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
5761 /* something went wrong creating or truncating the file */
5762 if (scp) cm_ReleaseSCache(scp);
5763 cm_ReleaseUser(userp);
5768 /* make sure we have file vs. dir right */
5769 if (realDirFlag == 0 && scp->fileType != CM_SCACHETYPE_FILE) {
5770 /* now watch for a symlink */
5772 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
5774 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
5776 /* we have a more accurate file to use (the
5777 * target of the symbolic link). Otherwise,
5778 * we'll just use the symlink anyway.
5780 osi_Log2(smb_logp, "symlink vp %x to vp %x",
5782 cm_ReleaseSCache(scp);
5787 if (scp->fileType != CM_SCACHETYPE_FILE) {
5788 cm_ReleaseSCache(scp);
5789 cm_ReleaseUser(userp);
5791 return CM_ERROR_ISDIR;
5795 if (realDirFlag == 1 && scp->fileType == CM_SCACHETYPE_FILE) {
5796 cm_ReleaseSCache(scp);
5797 cm_ReleaseUser(userp);
5799 return CM_ERROR_NOTDIR;
5802 /* open the file itself */
5803 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
5806 /* save a pointer to the vnode */
5809 fidp->flags = fidflags;
5811 /* save parent dir and pathname for deletion or change notification */
5812 if (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE)) {
5813 fidp->flags |= SMB_FID_NTOPEN;
5814 fidp->NTopen_dscp = dscp;
5815 cm_HoldSCache(dscp);
5816 fidp->NTopen_pathp = strdup(lastNamep);
5818 fidp->NTopen_wholepathp = realPathp;
5820 /* we don't need this any longer */
5821 if (dscp) cm_ReleaseSCache(dscp);
5823 cm_Open(scp, 0, userp);
5825 /* set inp->fid so that later read calls in same msg can find fid */
5826 inp->fid = fidp->fid;
5828 /* check whether we are required to send an extended response */
5829 if (!extendedRespRequired) {
5831 parmOffset = 8*4 + 39;
5832 parmOffset += 1; /* pad to 4 */
5833 dataOffset = parmOffset + 70;
5837 /* Total Parameter Count */
5838 smb_SetSMBParmLong(outp, parmSlot, 70); parmSlot += 2;
5839 /* Total Data Count */
5840 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
5841 /* Parameter Count */
5842 smb_SetSMBParmLong(outp, parmSlot, 70); parmSlot += 2;
5843 /* Parameter Offset */
5844 smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
5845 /* Parameter Displacement */
5846 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
5848 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
5850 smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
5851 /* Data Displacement */
5852 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
5853 smb_SetSMBParmByte(outp, parmSlot, 0); /* Setup Count */
5854 smb_SetSMBDataLength(outp, 70);
5856 lock_ObtainMutex(&scp->mx);
5857 outData = smb_GetSMBData(outp, NULL);
5858 outData++; /* round to get to parmOffset */
5859 *outData = 0; outData++; /* oplock */
5860 *outData = 0; outData++; /* reserved */
5861 *((USHORT *)outData) = fidp->fid; outData += 2; /* fid */
5862 *((ULONG *)outData) = openAction; outData += 4;
5863 *((ULONG *)outData) = 0; outData += 4; /* EA error offset */
5864 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
5865 *((FILETIME *)outData) = ft; outData += 8; /* creation time */
5866 *((FILETIME *)outData) = ft; outData += 8; /* last access time */
5867 *((FILETIME *)outData) = ft; outData += 8; /* last write time */
5868 *((FILETIME *)outData) = ft; outData += 8; /* change time */
5869 *((ULONG *)outData) = smb_ExtAttributes(scp); outData += 4;
5870 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* alloc sz */
5871 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* EOF */
5872 *((USHORT *)outData) = 0; outData += 2; /* filetype */
5873 *((USHORT *)outData) = 0; outData += 2; /* dev state */
5874 *((USHORT *)outData) = (scp->fileType == CM_SCACHETYPE_DIRECTORY);
5875 outData += 2; /* is a dir? */
5876 lock_ReleaseMutex(&scp->mx);
5879 parmOffset = 8*4 + 39;
5880 parmOffset += 1; /* pad to 4 */
5881 dataOffset = parmOffset + 104;
5885 /* Total Parameter Count */
5886 smb_SetSMBParmLong(outp, parmSlot, 101); parmSlot += 2;
5887 /* Total Data Count */
5888 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
5889 /* Parameter Count */
5890 smb_SetSMBParmLong(outp, parmSlot, 101); parmSlot += 2;
5891 /* Parameter Offset */
5892 smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
5893 /* Parameter Displacement */
5894 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
5896 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
5898 smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
5899 /* Data Displacement */
5900 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
5901 smb_SetSMBParmByte(outp, parmSlot, 0); /* Setup Count */
5902 smb_SetSMBDataLength(outp, 105);
5904 lock_ObtainMutex(&scp->mx);
5905 outData = smb_GetSMBData(outp, NULL);
5906 outData++; /* round to get to parmOffset */
5907 *outData = 0; outData++; /* oplock */
5908 *outData = 1; outData++; /* response type */
5909 *((USHORT *)outData) = fidp->fid; outData += 2; /* fid */
5910 *((ULONG *)outData) = openAction; outData += 4;
5911 *((ULONG *)outData) = 0; outData += 4; /* EA error offset */
5912 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
5913 *((FILETIME *)outData) = ft; outData += 8; /* creation time */
5914 *((FILETIME *)outData) = ft; outData += 8; /* last access time */
5915 *((FILETIME *)outData) = ft; outData += 8; /* last write time */
5916 *((FILETIME *)outData) = ft; outData += 8; /* change time */
5917 *((ULONG *)outData) = smb_ExtAttributes(scp); outData += 4;
5918 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* alloc sz */
5919 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* EOF */
5920 *((USHORT *)outData) = 0; outData += 2; /* filetype */
5921 *((USHORT *)outData) = 0; outData += 2; /* dev state */
5922 *((USHORT *)outData) = (scp->fileType == CM_SCACHETYPE_DIRECTORY);
5923 outData += 1; /* is a dir? */
5924 memset(outData,0,24); outData += 24; /* Volume ID and file ID */
5925 *((ULONG *)outData) = 0x001f01ffL; outData += 4; /* Maxmimal access rights */
5926 *((ULONG *)outData) = 0; outData += 4; /* Guest Access rights */
5927 lock_ReleaseMutex(&scp->mx);
5930 osi_Log1(smb_logp, "SMB NTTranCreate opening fid %d", fidp->fid);
5932 smb_ReleaseFID(fidp);
5934 cm_ReleaseUser(userp);
5936 /* free(realPathp); Can't free realPathp here because fidp->NTopen_wholepathp points there */
5937 /* leave scp held since we put it in fidp->scp */
5941 long smb_ReceiveNTTranNotifyChange(smb_vc_t *vcp, smb_packet_t *inp,
5944 smb_packet_t *savedPacketp;
5945 ULONG filter; USHORT fid, watchtree;
5949 filter = smb_GetSMBParm(inp, 19) |
5950 (smb_GetSMBParm(inp, 20) << 16);
5951 fid = smb_GetSMBParm(inp, 21);
5952 watchtree = smb_GetSMBParm(inp, 22) && 0xffff; /* TODO: should this be 0xff ? */
5954 fidp = smb_FindFID(vcp, fid, 0);
5956 osi_Log1(smb_logp, "ERROR: NotifyChange given invalid fid [%d]", fid);
5957 return CM_ERROR_BADFD;
5960 savedPacketp = smb_CopyPacket(inp);
5962 savedPacketp->vcp = vcp;
5963 lock_ObtainMutex(&smb_Dir_Watch_Lock);
5964 savedPacketp->nextp = smb_Directory_Watches;
5965 smb_Directory_Watches = savedPacketp;
5966 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
5968 osi_Log4(smb_logp, "Request for NotifyChange filter 0x%x fid %d wtree %d file %s",
5969 filter, fid, watchtree, osi_LogSaveString(smb_logp, fidp->NTopen_wholepathp));
5972 lock_ObtainMutex(&scp->mx);
5974 scp->flags |= CM_SCACHEFLAG_WATCHEDSUBTREE;
5976 scp->flags |= CM_SCACHEFLAG_WATCHED;
5977 lock_ReleaseMutex(&scp->mx);
5978 smb_ReleaseFID(fidp);
5980 outp->flags |= SMB_PACKETFLAG_NOSEND;
5984 unsigned char nullSecurityDesc[36] = {
5985 0x01, /* security descriptor revision */
5986 0x00, /* reserved, should be zero */
5987 0x00, 0x80, /* security descriptor control;
5988 * 0x8000 : self-relative format */
5989 0x14, 0x00, 0x00, 0x00, /* offset of owner SID */
5990 0x1c, 0x00, 0x00, 0x00, /* offset of group SID */
5991 0x00, 0x00, 0x00, 0x00, /* offset of DACL would go here */
5992 0x00, 0x00, 0x00, 0x00, /* offset of SACL would go here */
5993 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
5994 /* "null SID" owner SID */
5995 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
5996 /* "null SID" group SID */
5999 long smb_ReceiveNTTranQuerySecurityDesc(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6001 int parmOffset, parmCount, dataOffset, dataCount;
6009 ULONG securityInformation;
6011 parmOffset = smb_GetSMBOffsetParm(inp, 11, 1)
6012 | (smb_GetSMBOffsetParm(inp, 12, 1) << 16);
6013 parmp = inp->data + parmOffset;
6014 sparmp = (USHORT *) parmp;
6015 lparmp = (ULONG *) parmp;
6018 securityInformation = lparmp[1];
6020 maxData = smb_GetSMBOffsetParm(inp, 7, 1)
6021 | (smb_GetSMBOffsetParm(inp, 8, 1) << 16);
6029 parmOffset = 8*4 + 39;
6030 parmOffset += 1; /* pad to 4 */
6032 dataOffset = parmOffset + parmCount;
6036 /* Total Parameter Count */
6037 smb_SetSMBParmLong(outp, parmSlot, parmCount); parmSlot += 2;
6038 /* Total Data Count */
6039 smb_SetSMBParmLong(outp, parmSlot, dataCount); parmSlot += 2;
6040 /* Parameter Count */
6041 smb_SetSMBParmLong(outp, parmSlot, parmCount); parmSlot += 2;
6042 /* Parameter Offset */
6043 smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
6044 /* Parameter Displacement */
6045 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
6047 smb_SetSMBParmLong(outp, parmSlot, dataCount); parmSlot += 2;
6049 smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
6050 /* Data Displacement */
6051 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
6052 smb_SetSMBParmByte(outp, parmSlot, 0); /* Setup Count */
6053 smb_SetSMBDataLength(outp, 1 + parmCount + dataCount);
6055 outData = smb_GetSMBData(outp, NULL);
6056 outData++; /* round to get to parmOffset */
6057 *((ULONG *)outData) = 36; outData += 4; /* length */
6059 if (maxData >= 36) {
6060 memcpy(outData, nullSecurityDesc, 36);
6064 return CM_ERROR_BUFFERTOOSMALL;
6067 long smb_ReceiveNTTransact(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6069 unsigned short function;
6071 function = smb_GetSMBParm(inp, 18);
6073 osi_Log1(smb_logp, "SMB NT Transact function %d", function);
6075 /* We can handle long names */
6076 if (vcp->flags & SMB_VCFLAG_USENT)
6077 ((smb_t *)outp)->flg2 |= 0x40; /* IS_LONG_NAME */
6081 return smb_ReceiveNTTranQuerySecurityDesc(vcp, inp, outp);
6083 return smb_ReceiveNTTranNotifyChange(vcp, inp, outp);
6085 return smb_ReceiveNTTranCreate(vcp, inp, outp);
6087 return CM_ERROR_INVAL;
6092 * smb_NotifyChange -- find relevant change notification messages and
6095 * If we don't know the file name (i.e. a callback break), filename is
6096 * NULL, and we return a zero-length list.
6098 void smb_NotifyChange(DWORD action, DWORD notifyFilter,
6099 cm_scache_t *dscp, char *filename, char *otherFilename,
6100 BOOL isDirectParent)
6102 smb_packet_t *watch, *lastWatch, *nextWatch;
6103 ULONG parmSlot, parmCount, parmOffset, dataOffset, nameLen;
6104 char *outData, *oldOutData;
6108 BOOL twoEntries = FALSE;
6109 ULONG otherNameLen, oldParmCount = 0;
6114 /* Get ready for rename within directory */
6115 if (action == FILE_ACTION_RENAMED_OLD_NAME && otherFilename != NULL) {
6117 otherAction = FILE_ACTION_RENAMED_NEW_NAME;
6120 osi_Log2(smb_logp,"in smb_NotifyChange for file [%s] dscp [%x]",
6121 osi_LogSaveString(smb_logp,filename),dscp);
6123 lock_ObtainMutex(&smb_Dir_Watch_Lock);
6124 watch = smb_Directory_Watches;
6126 filter = smb_GetSMBParm(watch, 19)
6127 | (smb_GetSMBParm(watch, 20) << 16);
6128 fid = smb_GetSMBParm(watch, 21);
6129 wtree = smb_GetSMBParm(watch, 22) & 0xffff; /* TODO: should this be 0xff ? */
6130 maxLen = smb_GetSMBOffsetParm(watch, 5, 1)
6131 | (smb_GetSMBOffsetParm(watch, 6, 1) << 16);
6135 * Strange hack - bug in NT Client and NT Server that we
6138 if (filter == 3 && wtree)
6141 fidp = smb_FindFID(vcp, fid, 0);
6143 osi_Log1(smb_logp," no fidp for fid[%d]",fid);
6145 watch = watch->nextp;
6148 if (fidp->scp != dscp
6149 || (filter & notifyFilter) == 0
6150 || (!isDirectParent && !wtree)) {
6151 osi_Log1(smb_logp," passing fidp->scp[%x]", fidp->scp);
6152 smb_ReleaseFID(fidp);
6154 watch = watch->nextp;
6157 smb_ReleaseFID(fidp);
6160 "Sending Change Notification for fid %d filter 0x%x wtree %d file %s",
6161 fid, filter, wtree, osi_LogSaveString(smb_logp, filename));
6163 nextWatch = watch->nextp;
6164 if (watch == smb_Directory_Watches)
6165 smb_Directory_Watches = nextWatch;
6167 lastWatch->nextp = nextWatch;
6169 /* Turn off WATCHED flag in dscp */
6170 lock_ObtainMutex(&dscp->mx);
6172 dscp->flags &= ~CM_SCACHEFLAG_WATCHEDSUBTREE;
6174 dscp->flags &= ~CM_SCACHEFLAG_WATCHED;
6175 lock_ReleaseMutex(&dscp->mx);
6177 /* Convert to response packet */
6178 ((smb_t *) watch)->reb = 0x80;
6179 ((smb_t *) watch)->wct = 0;
6182 if (filename == NULL)
6185 nameLen = strlen(filename);
6186 parmCount = 3*4 + nameLen*2;
6187 parmCount = (parmCount + 3) & ~3; /* pad to 4 */
6189 otherNameLen = strlen(otherFilename);
6190 oldParmCount = parmCount;
6191 parmCount += 3*4 + otherNameLen*2;
6192 parmCount = (parmCount + 3) & ~3; /* pad to 4 */
6194 if (maxLen < parmCount)
6195 parmCount = 0; /* not enough room */
6197 parmOffset = 8*4 + 39;
6198 parmOffset += 1; /* pad to 4 */
6199 dataOffset = parmOffset + parmCount;
6203 /* Total Parameter Count */
6204 smb_SetSMBParmLong(watch, parmSlot, parmCount); parmSlot += 2;
6205 /* Total Data Count */
6206 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
6207 /* Parameter Count */
6208 smb_SetSMBParmLong(watch, parmSlot, parmCount); parmSlot += 2;
6209 /* Parameter Offset */
6210 smb_SetSMBParmLong(watch, parmSlot, parmOffset); parmSlot += 2;
6211 /* Parameter Displacement */
6212 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
6214 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
6216 smb_SetSMBParmLong(watch, parmSlot, dataOffset); parmSlot += 2;
6217 /* Data Displacement */
6218 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
6219 smb_SetSMBParmByte(watch, parmSlot, 0); /* Setup Count */
6220 smb_SetSMBDataLength(watch, parmCount + 1);
6222 if (parmCount != 0) {
6223 outData = smb_GetSMBData(watch, NULL);
6224 outData++; /* round to get to parmOffset */
6225 oldOutData = outData;
6226 *((DWORD *)outData) = oldParmCount; outData += 4;
6227 /* Next Entry Offset */
6228 *((DWORD *)outData) = action; outData += 4;
6230 *((DWORD *)outData) = nameLen*2; outData += 4;
6231 /* File Name Length */
6232 mbstowcs((WCHAR *)outData, filename, nameLen);
6235 outData = oldOutData + oldParmCount;
6236 *((DWORD *)outData) = 0; outData += 4;
6237 /* Next Entry Offset */
6238 *((DWORD *)outData) = otherAction; outData += 4;
6240 *((DWORD *)outData) = otherNameLen*2;
6241 outData += 4; /* File Name Length */
6242 mbstowcs((WCHAR *)outData, otherFilename,
6243 otherNameLen); /* File Name */
6248 * If filename is null, we don't know the cause of the
6249 * change notification. We return zero data (see above),
6250 * and set error code to NT_STATUS_NOTIFY_ENUM_DIR
6251 * (= 0x010C). We set the error code here by hand, without
6252 * modifying wct and bcc.
6254 if (filename == NULL) {
6255 ((smb_t *) watch)->rcls = 0x0C;
6256 ((smb_t *) watch)->reh = 0x01;
6257 ((smb_t *) watch)->errLow = 0;
6258 ((smb_t *) watch)->errHigh = 0;
6259 /* Set NT Status codes flag */
6260 ((smb_t *) watch)->flg2 |= 0x4000;
6263 smb_SendPacket(vcp, watch);
6265 smb_FreePacket(watch);
6268 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
6271 long smb_ReceiveNTCancel(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6273 unsigned char *replyWctp;
6274 smb_packet_t *watch, *lastWatch;
6275 USHORT fid, watchtree;
6279 osi_Log0(smb_logp, "SMB3 receive NT cancel");
6281 lock_ObtainMutex(&smb_Dir_Watch_Lock);
6282 watch = smb_Directory_Watches;
6284 if (((smb_t *)watch)->uid == ((smb_t *)inp)->uid
6285 && ((smb_t *)watch)->pid == ((smb_t *)inp)->pid
6286 && ((smb_t *)watch)->mid == ((smb_t *)inp)->mid
6287 && ((smb_t *)watch)->tid == ((smb_t *)inp)->tid) {
6288 if (watch == smb_Directory_Watches)
6289 smb_Directory_Watches = watch->nextp;
6291 lastWatch->nextp = watch->nextp;
6292 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
6294 /* Turn off WATCHED flag in scp */
6295 fid = smb_GetSMBParm(watch, 21);
6296 watchtree = smb_GetSMBParm(watch, 22) & 0xffff;
6298 if (vcp != watch->vcp)
6299 osi_Log2(smb_logp, "smb_ReceiveNTCancel: vcp %x not equal to watch vcp %x",
6302 fidp = smb_FindFID(vcp, fid, 0);
6304 osi_Log3(smb_logp, "Cancelling change notification for fid %d wtree %d file %s",
6306 osi_LogSaveString(smb_logp, (fidp)?fidp->NTopen_wholepathp:""));
6309 lock_ObtainMutex(&scp->mx);
6311 scp->flags &= ~CM_SCACHEFLAG_WATCHEDSUBTREE;
6313 scp->flags &= ~CM_SCACHEFLAG_WATCHED;
6314 lock_ReleaseMutex(&scp->mx);
6315 smb_ReleaseFID(fidp);
6317 osi_Log2(smb_logp,"NTCancel unable to resolve fid [%d] in vcp[%x]", fid,vcp);
6320 /* assume STATUS32; return 0xC0000120 (CANCELED) */
6321 replyWctp = watch->wctp;
6325 ((smb_t *)watch)->rcls = 0x20;
6326 ((smb_t *)watch)->reh = 0x1;
6327 ((smb_t *)watch)->errLow = 0;
6328 ((smb_t *)watch)->errHigh = 0xC0;
6329 ((smb_t *)watch)->flg2 |= 0x4000;
6330 smb_SendPacket(vcp, watch);
6332 smb_ReleaseVC(watch->vcp);
6333 smb_FreePacket(watch);
6337 watch = watch->nextp;
6339 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
6345 * NT rename also does hard links.
6348 #define RENAME_FLAG_MOVE_CLUSTER_INFORMATION 0x102
6349 #define RENAME_FLAG_HARD_LINK 0x103
6350 #define RENAME_FLAG_RENAME 0x104
6351 #define RENAME_FLAG_COPY 0x105
6353 long smb_ReceiveNTRename(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6355 char *oldname, *newname;
6362 attrs = smb_GetSMBParm(inp, 0);
6363 rename_type = smb_GetSMBParm(inp, 1);
6365 if (rename_type != RENAME_FLAG_RENAME && rename_type != RENAME_FLAG_HARD_LINK) {
6366 osi_Log1(smb_logp, "NTRename invalid infolevel [%x]", rename_type);
6367 return CM_ERROR_NOACCESS;
6370 tp = smb_GetSMBData(inp, NULL);
6371 oldname = smb_ParseASCIIBlock(tp, &tp);
6372 newname = smb_ParseASCIIBlock(tp, &tp);
6374 osi_Log3(smb_logp, "NTRename for [%s]->[%s] type [%s]",
6375 osi_LogSaveString(smb_logp, oldname),
6376 osi_LogSaveString(smb_logp, newname),
6377 ((rename_type==RENAME_FLAG_RENAME)?"rename":"hardlink"));
6379 if (rename_type == RENAME_FLAG_RENAME) {
6380 code = smb_Rename(vcp,inp,oldname,newname,attrs);
6381 } else { /* RENAME_FLAG_HARD_LINK */
6382 code = smb_Link(vcp,inp,oldname,newname);
6389 lock_InitializeMutex(&smb_Dir_Watch_Lock, "Directory Watch List Lock");
6392 cm_user_t *smb_FindCMUserByName(/*smb_vc_t *vcp,*/ char *usern, char *machine)
6395 smb_username_t *unp;
6397 unp = smb_FindUserByName(usern, machine, SMB_FLAG_CREATE);
6399 lock_ObtainMutex(&unp->mx);
6400 unp->userp = cm_NewUser();
6401 lock_ReleaseMutex(&unp->mx);
6402 osi_Log2(smb_logp,"smb_FindCMUserByName New user name[%s] machine[%s]",osi_LogSaveString(smb_logp,usern),osi_LogSaveString(smb_logp,machine));
6403 osi_LogEvent("AFS smb_FindCMUserByName : New User",NULL,"name[%s] machine[%s]",usern,machine);
6405 osi_Log2(smb_logp,"smb_FindCMUserByName Not found name[%s] machine[%s]",osi_LogSaveString(smb_logp,usern),osi_LogSaveString(smb_logp,machine));
6406 osi_LogEvent("AFS smb_FindCMUserByName : Found",NULL,"name[%s] machine[%s]",usern,machine);