2 * Copyright 2000, International Business Machines Corporation and others.
5 * This software has been released under the terms of the IBM Public
6 * License. For details, see the LICENSE file in the top-level source
7 * directory or online at http://www.openafs.org/dl/license10.html
10 #include <afs/param.h>
15 #define SECURITY_WIN32
30 extern osi_hyper_t hzero;
32 smb_packet_t *smb_Directory_Watches = NULL;
33 osi_mutex_t smb_Dir_Watch_Lock;
35 smb_tran2Dispatch_t smb_tran2DispatchTable[SMB_TRAN2_NOPCODES];
37 smb_tran2Dispatch_t smb_rapDispatchTable[SMB_RAP_NOPCODES];
39 /* protected by the smb_globalLock */
40 smb_tran2Packet_t *smb_tran2AssemblyQueuep;
42 /* retrieve a held reference to a user structure corresponding to an incoming
44 cm_user_t *smb_GetTran2User(smb_vc_t *vcp, smb_tran2Packet_t *inp)
49 uidp = smb_FindUID(vcp, inp->uid, 0);
50 if (!uidp) return NULL;
52 lock_ObtainMutex(&uidp->mx);
54 up = uidp->unp->userp;
57 lock_ReleaseMutex(&uidp->mx);
65 * Return extended attributes.
66 * Right now, we aren't using any of the "new" bits, so this looks exactly
67 * like smb_Attributes() (see smb.c).
69 unsigned long smb_ExtAttributes(cm_scache_t *scp)
73 if (scp->fileType == CM_SCACHETYPE_DIRECTORY ||
74 scp->fileType == CM_SCACHETYPE_MOUNTPOINT)
76 attrs = SMB_ATTR_DIRECTORY;
77 #ifdef SPECIAL_FOLDERS
78 attrs |= SMB_ATTR_SYSTEM; /* FILE_ATTRIBUTE_SYSTEM */
79 #endif /* SPECIAL_FOLDERS */
83 * We used to mark a file RO if it was in an RO volume, but that
84 * turns out to be impolitic in NT. See defect 10007.
87 if ((scp->unixModeBits & 0222) == 0 || (scp->flags & CM_SCACHEFLAG_RO))
89 if ((scp->unixModeBits & 0222) == 0)
90 attrs |= SMB_ATTR_READONLY; /* Read-only */
93 attrs = SMB_ATTR_NORMAL; /* FILE_ATTRIBUTE_NORMAL */
98 int smb_V3IsStarMask(char *maskp)
102 while (tc = *maskp++)
103 if (tc == '?' || tc == '*')
108 unsigned char *smb_ParseString(unsigned char *inp, char **chainpp)
111 /* skip over null-terminated string */
112 *chainpp = inp + strlen(inp) + 1;
117 /*DEBUG do not checkin*/
118 void OutputDebugF(char * format, ...) {
123 va_start( args, format );
124 len = _vscprintf( format, args ) // _vscprintf doesn't count
125 + 3; // terminating '\0' + '\n'
126 buffer = malloc( len * sizeof(char) );
127 vsprintf( buffer, format, args );
128 osi_Log0(smb_logp, osi_LogSaveString(smb_logp, buffer));
129 strcat(buffer, "\n");
130 OutputDebugString(buffer);
134 void OutputDebugHexDump(unsigned char * buffer, int len) {
137 static char tr[16] = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
139 OutputDebugF("Hexdump length [%d]",len);
141 for (i=0;i<len;i++) {
144 osi_Log0(smb_logp, osi_LogSaveString(smb_logp, buf));
146 OutputDebugString(buf);
148 sprintf(buf,"%5x",i);
149 memset(buf+5,' ',80);
154 j = j*3 + 7 + ((j>7)?1:0);
157 buf[j] = tr[k / 16]; buf[j+1] = tr[k % 16];
160 j = j + 56 + ((j>7)?1:0);
162 buf[j] = (k>32 && k<127)?k:'.';
165 osi_Log0(smb_logp, osi_LogSaveString(smb_logp, buf));
167 OutputDebugString(buf);
172 #define SMB_EXT_SEC_PACKAGE_NAME "Negotiate"
173 void smb_NegotiateExtendedSecurity(void ** secBlob, int * secBlobLength) {
174 SECURITY_STATUS status, istatus;
175 CredHandle creds = {0,0};
177 SecBufferDesc secOut;
185 OutputDebugF("Negotiating Extended Security");
187 status = AcquireCredentialsHandle( NULL,
188 SMB_EXT_SEC_PACKAGE_NAME,
197 if (status != SEC_E_OK) {
198 /* Really bad. We return an empty security blob */
199 OutputDebugF("AcquireCredentialsHandle failed with %lX", status);
204 secOut.pBuffers = &secTok;
205 secOut.ulVersion = SECBUFFER_VERSION;
207 secTok.BufferType = SECBUFFER_TOKEN;
209 secTok.pvBuffer = NULL;
211 ctx.dwLower = ctx.dwUpper = 0;
213 status = AcceptSecurityContext( &creds,
216 ASC_REQ_CONNECTION | ASC_REQ_EXTENDED_ERROR | ASC_REQ_ALLOCATE_MEMORY,
217 SECURITY_NETWORK_DREP,
224 if (status == SEC_I_COMPLETE_NEEDED || status == SEC_I_COMPLETE_AND_CONTINUE) {
225 OutputDebugF("Completing token...");
226 istatus = CompleteAuthToken(&ctx, &secOut);
227 if ( istatus != SEC_E_OK )
228 OutputDebugF("Token completion failed: %x", istatus);
231 if (status == SEC_I_COMPLETE_AND_CONTINUE || status == SEC_I_CONTINUE_NEEDED) {
232 if (secTok.pvBuffer) {
233 *secBlobLength = secTok.cbBuffer;
234 *secBlob = malloc( secTok.cbBuffer );
235 memcpy(*secBlob, secTok.pvBuffer, secTok.cbBuffer );
238 if ( status != SEC_E_OK )
239 OutputDebugF("AcceptSecurityContext status != CONTINUE %lX", status);
242 /* Discard partial security context */
243 DeleteSecurityContext(&ctx);
245 if (secTok.pvBuffer) FreeContextBuffer( secTok.pvBuffer );
247 /* Discard credentials handle. We'll reacquire one when we get the session setup X */
248 FreeCredentialsHandle(&creds);
254 struct smb_ext_context {
261 long smb_AuthenticateUserExt(smb_vc_t * vcp, char * usern, char * secBlobIn, int secBlobInLength, char ** secBlobOut, int * secBlobOutLength) {
262 SECURITY_STATUS status, istatus;
266 SecBufferDesc secBufIn;
268 SecBufferDesc secBufOut;
271 struct smb_ext_context * secCtx = NULL;
272 struct smb_ext_context * newSecCtx = NULL;
273 void * assembledBlob = NULL;
274 int assembledBlobLength = 0;
277 OutputDebugF("In smb_AuthenticateUserExt");
280 *secBlobOutLength = 0;
282 if (vcp->flags & SMB_VCFLAG_AUTH_IN_PROGRESS) {
283 secCtx = vcp->secCtx;
284 lock_ObtainMutex(&vcp->mx);
285 vcp->flags &= ~SMB_VCFLAG_AUTH_IN_PROGRESS;
287 lock_ReleaseMutex(&vcp->mx);
291 OutputDebugF("Received incoming token:");
292 OutputDebugHexDump(secBlobIn,secBlobInLength);
296 OutputDebugF("Continuing with existing context.");
297 creds = secCtx->creds;
300 if (secCtx->partialToken) {
301 assembledBlobLength = secCtx->partialTokenLen + secBlobInLength;
302 assembledBlob = malloc(assembledBlobLength);
303 memcpy(assembledBlob,secCtx->partialToken, secCtx->partialTokenLen);
304 memcpy(((BYTE *)assembledBlob) + secCtx->partialTokenLen, secBlobIn, secBlobInLength);
307 status = AcquireCredentialsHandle( NULL,
308 SMB_EXT_SEC_PACKAGE_NAME,
317 if (status != SEC_E_OK) {
318 OutputDebugF("Can't acquire Credentials handle [%lX]", status);
319 code = CM_ERROR_BADPASSWORD; /* means "try again when I'm sober" */
327 secBufIn.cBuffers = 1;
328 secBufIn.pBuffers = &secTokIn;
329 secBufIn.ulVersion = SECBUFFER_VERSION;
331 secTokIn.BufferType = SECBUFFER_TOKEN;
333 secTokIn.cbBuffer = assembledBlobLength;
334 secTokIn.pvBuffer = assembledBlob;
336 secTokIn.cbBuffer = secBlobInLength;
337 secTokIn.pvBuffer = secBlobIn;
340 secBufOut.cBuffers = 1;
341 secBufOut.pBuffers = &secTokOut;
342 secBufOut.ulVersion = SECBUFFER_VERSION;
344 secTokOut.BufferType = SECBUFFER_TOKEN;
345 secTokOut.cbBuffer = 0;
346 secTokOut.pvBuffer = NULL;
348 status = AcceptSecurityContext( &creds,
349 ((secCtx)?&ctx:NULL),
351 ASC_REQ_CONNECTION | ASC_REQ_EXTENDED_ERROR | ASC_REQ_ALLOCATE_MEMORY,
352 SECURITY_NETWORK_DREP,
359 if (status == SEC_I_COMPLETE_NEEDED || status == SEC_I_COMPLETE_AND_CONTINUE) {
360 OutputDebugF("Completing token...");
361 istatus = CompleteAuthToken(&ctx, &secBufOut);
362 if ( istatus != SEC_E_OK )
363 OutputDebugF("Token completion failed: %lX", istatus);
366 if (status == SEC_I_COMPLETE_AND_CONTINUE || status == SEC_I_CONTINUE_NEEDED) {
367 OutputDebugF("Continue needed");
369 newSecCtx = malloc(sizeof(*newSecCtx));
371 newSecCtx->creds = creds;
372 newSecCtx->ctx = ctx;
373 newSecCtx->partialToken = NULL;
374 newSecCtx->partialTokenLen = 0;
376 lock_ObtainMutex( &vcp->mx );
377 vcp->flags |= SMB_VCFLAG_AUTH_IN_PROGRESS;
378 vcp->secCtx = newSecCtx;
379 lock_ReleaseMutex( &vcp->mx );
381 code = CM_ERROR_GSSCONTINUE;
384 if ((status == SEC_I_COMPLETE_NEEDED || status == SEC_E_OK ||
385 status == SEC_I_COMPLETE_AND_CONTINUE || status == SEC_I_CONTINUE_NEEDED) &&
386 secTokOut.pvBuffer) {
387 OutputDebugF("Need to send token back to client");
389 *secBlobOutLength = secTokOut.cbBuffer;
390 *secBlobOut = malloc(secTokOut.cbBuffer);
391 memcpy(*secBlobOut, secTokOut.pvBuffer, secTokOut.cbBuffer);
393 OutputDebugF("Outgoing token:");
394 OutputDebugHexDump(*secBlobOut,*secBlobOutLength);
395 } else if (status == SEC_E_INCOMPLETE_MESSAGE) {
396 OutputDebugF("Incomplete message");
398 newSecCtx = malloc(sizeof(*newSecCtx));
400 newSecCtx->creds = creds;
401 newSecCtx->ctx = ctx;
402 newSecCtx->partialToken = malloc(secTokOut.cbBuffer);
403 memcpy(newSecCtx->partialToken, secTokOut.pvBuffer, secTokOut.cbBuffer);
404 newSecCtx->partialTokenLen = secTokOut.cbBuffer;
406 lock_ObtainMutex( &vcp->mx );
407 vcp->flags |= SMB_VCFLAG_AUTH_IN_PROGRESS;
408 vcp->secCtx = newSecCtx;
409 lock_ReleaseMutex( &vcp->mx );
411 code = CM_ERROR_GSSCONTINUE;
414 if (status == SEC_E_OK || status == SEC_I_COMPLETE_NEEDED) {
416 SecPkgContext_Names names;
418 OutputDebugF("Authentication completed");
419 OutputDebugF("Returned flags : [%lX]", flags);
421 if (!QueryContextAttributes(&ctx, SECPKG_ATTR_NAMES, &names)) {
422 OutputDebugF("Received name [%s]", names.sUserName);
423 strcpy(usern, names.sUserName);
424 strlwr(usern); /* in tandem with smb_GetNormalizedUsername */
425 FreeContextBuffer(names.sUserName);
427 /* Force the user to retry if the context is invalid */
428 OutputDebugF("QueryContextAttributes Names failed [%x]", GetLastError());
429 code = CM_ERROR_BADPASSWORD;
433 case SEC_E_INVALID_TOKEN:
434 OutputDebugF("Returning bad password :: INVALID_TOKEN");
436 case SEC_E_INVALID_HANDLE:
437 OutputDebugF("Returning bad password :: INVALID_HANDLE");
439 case SEC_E_LOGON_DENIED:
440 OutputDebugF("Returning bad password :: LOGON_DENIED");
442 case SEC_E_UNKNOWN_CREDENTIALS:
443 OutputDebugF("Returning bad password :: UNKNOWN_CREDENTIALS");
445 case SEC_E_NO_CREDENTIALS:
446 OutputDebugF("Returning bad password :: NO_CREDENTIALS");
448 case SEC_E_CONTEXT_EXPIRED:
449 OutputDebugF("Returning bad password :: CONTEXT_EXPIRED");
451 case SEC_E_INCOMPLETE_CREDENTIALS:
452 OutputDebugF("Returning bad password :: INCOMPLETE_CREDENTIALS");
454 case SEC_E_WRONG_PRINCIPAL:
455 OutputDebugF("Returning bad password :: WRONG_PRINCIPAL");
457 case SEC_E_TIME_SKEW:
458 OutputDebugF("Returning bad password :: TIME_SKEW");
461 OutputDebugF("Returning bad password :: Status == %lX", status);
463 code = CM_ERROR_BADPASSWORD;
467 if (secCtx->partialToken) free(secCtx->partialToken);
475 if (secTokOut.pvBuffer)
476 FreeContextBuffer(secTokOut.pvBuffer);
478 if (code != CM_ERROR_GSSCONTINUE) {
479 DeleteSecurityContext(&ctx);
480 FreeCredentialsHandle(&creds);
488 #define P_RESP_LEN 128
490 /* LsaLogonUser expects input parameters to be in a contiguous block of memory.
491 So put stuff in a struct. */
492 struct Lm20AuthBlob {
493 MSV1_0_LM20_LOGON lmlogon;
494 BYTE ciResponse[P_RESP_LEN]; /* Unicode representation */
495 BYTE csResponse[P_RESP_LEN]; /* ANSI representation */
496 WCHAR accountNameW[P_LEN];
497 WCHAR primaryDomainW[P_LEN];
498 WCHAR workstationW[MAX_COMPUTERNAME_LENGTH + 1];
499 TOKEN_GROUPS tgroups;
500 TOKEN_SOURCE tsource;
503 long smb_AuthenticateUserLM(smb_vc_t *vcp, char * accountName, char * primaryDomain, char * ciPwd, unsigned ciPwdLength, char * csPwd, unsigned csPwdLength)
506 struct Lm20AuthBlob lmAuth;
507 PMSV1_0_LM20_LOGON_PROFILE lmprofilep;
508 QUOTA_LIMITS quotaLimits;
510 ULONG lmprofilepSize;
514 OutputDebugF("In smb_AuthenticateUser for user [%s] domain [%s]", accountName, primaryDomain);
515 OutputDebugF("ciPwdLength is %d and csPwdLength is %d", ciPwdLength, csPwdLength);
517 if (ciPwdLength > P_RESP_LEN || csPwdLength > P_RESP_LEN) {
518 OutputDebugF("ciPwdLength or csPwdLength is too long");
519 return CM_ERROR_BADPASSWORD;
522 memset(&lmAuth,0,sizeof(lmAuth));
524 lmAuth.lmlogon.MessageType = MsV1_0NetworkLogon;
526 lmAuth.lmlogon.LogonDomainName.Buffer = lmAuth.primaryDomainW;
527 mbstowcs(lmAuth.primaryDomainW, primaryDomain, P_LEN);
528 lmAuth.lmlogon.LogonDomainName.Length = wcslen(lmAuth.primaryDomainW) * sizeof(WCHAR);
529 lmAuth.lmlogon.LogonDomainName.MaximumLength = P_LEN * sizeof(WCHAR);
531 lmAuth.lmlogon.UserName.Buffer = lmAuth.accountNameW;
532 mbstowcs(lmAuth.accountNameW, accountName, P_LEN);
533 lmAuth.lmlogon.UserName.Length = wcslen(lmAuth.accountNameW) * sizeof(WCHAR);
534 lmAuth.lmlogon.UserName.MaximumLength = P_LEN * sizeof(WCHAR);
536 lmAuth.lmlogon.Workstation.Buffer = lmAuth.workstationW;
537 lmAuth.lmlogon.Workstation.MaximumLength = (MAX_COMPUTERNAME_LENGTH + 1) * sizeof(WCHAR);
538 size = MAX_COMPUTERNAME_LENGTH + 1;
539 GetComputerNameW(lmAuth.workstationW, &size);
540 lmAuth.lmlogon.Workstation.Length = wcslen(lmAuth.workstationW) * sizeof(WCHAR);
542 memcpy(lmAuth.lmlogon.ChallengeToClient, vcp->encKey, MSV1_0_CHALLENGE_LENGTH);
544 lmAuth.lmlogon.CaseInsensitiveChallengeResponse.Buffer = lmAuth.ciResponse;
545 lmAuth.lmlogon.CaseInsensitiveChallengeResponse.Length = ciPwdLength;
546 lmAuth.lmlogon.CaseInsensitiveChallengeResponse.MaximumLength = P_RESP_LEN;
547 memcpy(lmAuth.ciResponse, ciPwd, ciPwdLength);
549 lmAuth.lmlogon.CaseSensitiveChallengeResponse.Buffer = lmAuth.csResponse;
550 lmAuth.lmlogon.CaseSensitiveChallengeResponse.Length = csPwdLength;
551 lmAuth.lmlogon.CaseSensitiveChallengeResponse.MaximumLength = P_RESP_LEN;
552 memcpy(lmAuth.csResponse, csPwd, csPwdLength);
554 lmAuth.lmlogon.ParameterControl = 0;
556 lmAuth.tgroups.GroupCount = 0;
557 lmAuth.tgroups.Groups[0].Sid = NULL;
558 lmAuth.tgroups.Groups[0].Attributes = 0;
560 lmAuth.tsource.SourceIdentifier.HighPart = 0;
561 lmAuth.tsource.SourceIdentifier.LowPart = (DWORD) vcp;
562 strcpy(lmAuth.tsource.SourceName,"OpenAFS"); /* 8 char limit */
564 nts = LsaLogonUser( smb_lsaHandle,
579 OutputDebugF("Return from LsaLogonUser is 0x%lX", nts);
580 OutputDebugF("Extended status is 0x%lX", ntsEx);
582 if (nts == ERROR_SUCCESS) {
584 LsaFreeReturnBuffer(lmprofilep);
585 CloseHandle(lmToken);
589 if (nts == 0xC000015BL)
590 return CM_ERROR_BADLOGONTYPE;
591 else /* our catchall is a bad password though we could be more specific */
592 return CM_ERROR_BADPASSWORD;
596 /* The buffer pointed to by usern is assumed to be at least SMB_MAX_USERNAME_LENGTH bytes */
597 long smb_GetNormalizedUsername(char * usern, const char * accountName, const char * domainName)
602 /* check if we have sane input */
603 if ((strlen(accountName) + strlen(domainName) + 1) > SMB_MAX_USERNAME_LENGTH)
606 /* we could get : [accountName][domainName]
612 atsign = strchr(accountName, '@');
614 if (atsign) /* [user@domain][] -> [user@domain][domain] */
619 /* if for some reason the client doesn't know what domain to use,
620 it will either return an empty string or a '?' */
621 if (!domain[0] || domain[0] == '?')
622 /* Empty domains and empty usernames are usually sent from tokenless contexts.
623 This way such logins will get an empty username (easy to check). I don't know
624 when a non-empty username would be supplied with an anonymous domain, but *shrug* */
625 strcpy(usern,accountName);
627 /* TODO: what about WIN.MIT.EDU\user vs. WIN\user? */
628 strcpy(usern,domain);
631 strncat(usern,accountName,atsign - accountName);
633 strcat(usern,accountName);
641 /* When using SMB auth, all SMB sessions have to pass through here first to
642 * authenticate the user.
643 * Caveat: If not use the SMB auth the protocol does not require sending a
644 * session setup packet, which means that we can't rely on a UID in subsequent
645 * packets. Though in practice we get one anyway.
647 long smb_ReceiveV3SessionSetupX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
651 unsigned short newUid;
652 unsigned long caps = 0;
657 char usern[SMB_MAX_USERNAME_LENGTH];
658 char *secBlobOut = NULL;
659 int secBlobOutLength = 0;
661 /* Check for bad conns */
662 if (vcp->flags & SMB_VCFLAG_REMOTECONN)
663 return CM_ERROR_REMOTECONN;
665 if (vcp->flags & SMB_VCFLAG_USENT) {
666 if (smb_authType == SMB_AUTH_EXTENDED) {
667 /* extended authentication */
671 if (!(vcp->flags & SMB_VCFLAG_SESSX_RCVD)) {
672 caps = smb_GetSMBParm(inp,10) | (((unsigned long) smb_GetSMBParm(inp,11)) << 16);
675 secBlobInLength = smb_GetSMBParm(inp, 7);
676 secBlobIn = smb_GetSMBData(inp, NULL);
678 code = smb_AuthenticateUserExt(vcp, usern, secBlobIn, secBlobInLength, &secBlobOut, &secBlobOutLength);
680 if (code == CM_ERROR_GSSCONTINUE) {
681 smb_SetSMBParm(outp, 2, 0);
682 smb_SetSMBParm(outp, 3, secBlobOutLength);
683 smb_SetSMBDataLength(outp, secBlobOutLength + smb_ServerOSLength + smb_ServerLanManagerLength + smb_ServerDomainNameLength);
684 tp = smb_GetSMBData(outp, NULL);
685 if (secBlobOutLength) {
686 memcpy(tp, secBlobOut, secBlobOutLength);
688 tp += secBlobOutLength;
690 memcpy(tp,smb_ServerOS,smb_ServerOSLength);
691 tp += smb_ServerOSLength;
692 memcpy(tp,smb_ServerLanManager,smb_ServerLanManagerLength);
693 tp += smb_ServerLanManagerLength;
694 memcpy(tp,smb_ServerDomainName,smb_ServerDomainNameLength);
695 tp += smb_ServerDomainNameLength;
698 /* TODO: handle return code and continue auth. Also free secBlobOut if applicable. */
700 unsigned ciPwdLength, csPwdLength;
706 /* TODO: parse for extended auth as well */
707 ciPwdLength = smb_GetSMBParm(inp, 7); /* case insensitive password length */
708 csPwdLength = smb_GetSMBParm(inp, 8); /* case sensitive password length */
710 tp = smb_GetSMBData(inp, &datalen);
712 OutputDebugF("Session packet data size [%d]",datalen);
719 accountName = smb_ParseString(tp, &tp);
720 primaryDomain = smb_ParseString(tp, NULL);
722 if (smb_GetNormalizedUsername(usern, accountName, primaryDomain)) {
723 /* shouldn't happen */
724 code = CM_ERROR_BADSMB;
725 goto after_read_packet;
728 /* capabilities are only valid for first session packet */
729 if (!(vcp->flags & SMB_VCFLAG_SESSX_RCVD)) {
730 caps = smb_GetSMBParm(inp, 11) | (((unsigned long)smb_GetSMBParm(inp, 12)) << 16);
733 if (smb_authType == SMB_AUTH_NTLM) {
734 code = smb_AuthenticateUserLM(vcp, accountName, primaryDomain, ciPwd, ciPwdLength, csPwd, csPwdLength);
738 unsigned ciPwdLength;
743 ciPwdLength = smb_GetSMBParm(inp, 7);
744 tp = smb_GetSMBData(inp, NULL);
748 accountName = smb_ParseString(tp, &tp);
749 primaryDomain = smb_ParseString(tp, NULL);
751 if ( smb_GetNormalizedUsername(usern, accountName, primaryDomain)) {
752 /* shouldn't happen */
753 code = CM_ERROR_BADSMB;
754 goto after_read_packet;
757 /* even if we wanted extended auth, if we only negotiated V3, we have to fallback
760 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
761 code = smb_AuthenticateUserLM(vcp,accountName,primaryDomain,ciPwd,ciPwdLength,"",0);
766 /* note down that we received a session setup X and set the capabilities flag */
767 if (!(vcp->flags & SMB_VCFLAG_SESSX_RCVD)) {
768 lock_ObtainMutex(&vcp->mx);
769 vcp->flags |= SMB_VCFLAG_SESSX_RCVD;
770 /* for the moment we can only deal with NTSTATUS */
771 if (caps & NTNEGOTIATE_CAPABILITY_NTSTATUS) {
772 vcp->flags |= SMB_VCFLAG_STATUS32;
774 lock_ReleaseMutex(&vcp->mx);
777 /* code would be non-zero if there was an authentication failure.
778 Ideally we would like to invalidate the uid for this session or break
779 early to avoid accidently stealing someone else's tokens. */
785 OutputDebugF("Received username=[%s]", usern);
787 /* On Windows 2000, this function appears to be called more often than
788 it is expected to be called. This resulted in multiple smb_user_t
789 records existing all for the same user session which results in all
790 of the users tokens disappearing.
792 To avoid this problem, we look for an existing smb_user_t record
793 based on the users name, and use that one if we find it.
796 uidp = smb_FindUserByNameThisSession(vcp, usern);
797 if (uidp) { /* already there, so don't create a new one */
800 newUid = (unsigned short)uidp->userID; /* For some reason these are different types!*/
801 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));
802 osi_Log3(smb_logp,"smb_ReceiveV3SessionSetupX FindUserByName:Lana[%d],lsn[%d],userid[%d]",vcp->lana,vcp->lsn,newUid);
803 smb_ReleaseUID(uidp);
806 /* do a global search for the username/machine name pair */
807 unp = smb_FindUserByName(usern, vcp->rname, SMB_FLAG_CREATE);
809 /* Create a new UID and cm_user_t structure */
812 userp = cm_NewUser();
813 lock_ObtainMutex(&vcp->mx);
814 if (!vcp->uidCounter)
815 vcp->uidCounter++; /* handle unlikely wraparounds */
816 newUid = (strlen(usern)==0)?0:vcp->uidCounter++;
817 lock_ReleaseMutex(&vcp->mx);
819 /* Create a new smb_user_t structure and connect them up */
820 lock_ObtainMutex(&unp->mx);
822 lock_ReleaseMutex(&unp->mx);
824 uidp = smb_FindUID(vcp, newUid, SMB_FLAG_CREATE);
825 lock_ObtainMutex(&uidp->mx);
827 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));
828 osi_Log4(smb_logp,"smb_ReceiveV3SessionSetupX MakeNewUser:VCP[%x],Lana[%d],lsn[%d],userid[%d]",vcp,vcp->lana,vcp->lsn,newUid);
829 lock_ReleaseMutex(&uidp->mx);
830 smb_ReleaseUID(uidp);
833 /* Return UID to the client */
834 ((smb_t *)outp)->uid = newUid;
835 /* Also to the next chained message */
836 ((smb_t *)inp)->uid = newUid;
838 osi_Log3(smb_logp, "SMB3 session setup name %s creating ID %d%s",
839 osi_LogSaveString(smb_logp, usern), newUid, osi_LogSaveString(smb_logp, s1));
841 smb_SetSMBParm(outp, 2, 0);
843 if (vcp->flags & SMB_VCFLAG_USENT) {
844 if (smb_authType == SMB_AUTH_EXTENDED) {
845 smb_SetSMBParm(outp, 3, secBlobOutLength);
846 smb_SetSMBDataLength(outp, secBlobOutLength + smb_ServerOSLength + smb_ServerLanManagerLength + smb_ServerDomainNameLength);
847 tp = smb_GetSMBData(outp, NULL);
848 if (secBlobOutLength) {
849 memcpy(tp, secBlobOut, secBlobOutLength);
851 tp += secBlobOutLength;
853 memcpy(tp,smb_ServerOS,smb_ServerOSLength);
854 tp += smb_ServerOSLength;
855 memcpy(tp,smb_ServerLanManager,smb_ServerLanManagerLength);
856 tp += smb_ServerLanManagerLength;
857 memcpy(tp,smb_ServerDomainName,smb_ServerDomainNameLength);
858 tp += smb_ServerDomainNameLength;
860 smb_SetSMBDataLength(outp, 0);
863 if (smb_authType == SMB_AUTH_EXTENDED) {
864 smb_SetSMBDataLength(outp, smb_ServerOSLength + smb_ServerLanManagerLength + smb_ServerDomainNameLength);
865 tp = smb_GetSMBData(outp, NULL);
866 memcpy(tp,smb_ServerOS,smb_ServerOSLength);
867 tp += smb_ServerOSLength;
868 memcpy(tp,smb_ServerLanManager,smb_ServerLanManagerLength);
869 tp += smb_ServerLanManagerLength;
870 memcpy(tp,smb_ServerDomainName,smb_ServerDomainNameLength);
871 tp += smb_ServerDomainNameLength;
873 smb_SetSMBDataLength(outp, 0);
880 long smb_ReceiveV3UserLogoffX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
884 /* don't get tokens from this VC */
885 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
887 inp->flags |= SMB_PACKETFLAG_PROFILE_UPDATE_OK;
889 /* find the tree and free it */
890 uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
891 /* TODO: smb_ReleaseUID() ? */
893 char *s1 = NULL, *s2 = NULL;
895 if (s2 == NULL) s2 = " ";
896 if (s1 == NULL) {s1 = s2; s2 = " ";}
898 osi_Log4(smb_logp, "SMB3 user logoffX uid %d name %s%s%s", uidp->userID,
899 osi_LogSaveString(smb_logp, (uidp->unp) ? uidp->unp->name: " "), s1, s2);
901 lock_ObtainMutex(&uidp->mx);
902 uidp->flags |= SMB_USERFLAG_DELETE;
904 * it doesn't get deleted right away
905 * because the vcp points to it
907 lock_ReleaseMutex(&uidp->mx);
910 osi_Log0(smb_logp, "SMB3 user logoffX");
912 smb_SetSMBDataLength(outp, 0);
916 #define SMB_SUPPORT_SEARCH_BITS 0x0001
918 long smb_ReceiveV3TreeConnectX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
922 unsigned short newTid;
933 osi_Log0(smb_logp, "SMB3 receive tree connect");
935 /* parse input parameters */
936 tp = smb_GetSMBData(inp, NULL);
937 passwordp = smb_ParseString(tp, &tp);
938 pathp = smb_ParseString(tp, &tp);
939 servicep = smb_ParseString(tp, &tp);
941 tp = strrchr(pathp, '\\');
943 return CM_ERROR_BADSMB;
945 strcpy(shareName, tp+1);
947 osi_Log2(smb_logp, "Tree connect pathp[%s] shareName[%s]",
948 osi_LogSaveString(smb_logp, pathp),
949 osi_LogSaveString(smb_logp, shareName));
951 if (strcmp(servicep, "IPC") == 0 || strcmp(shareName, "IPC$") == 0) {
953 osi_Log0(smb_logp, "TreeConnectX connecting to IPC$");
956 return CM_ERROR_NOIPC;
960 userp = smb_GetUser(vcp, inp);
962 lock_ObtainMutex(&vcp->mx);
963 newTid = vcp->tidCounter++;
964 lock_ReleaseMutex(&vcp->mx);
966 tidp = smb_FindTID(vcp, newTid, SMB_FLAG_CREATE);
969 uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
970 shareFound = smb_FindShare(vcp, uidp, shareName, &sharePath);
972 smb_ReleaseUID(uidp);
974 smb_ReleaseTID(tidp);
975 return CM_ERROR_BADSHARENAME;
978 if (vcp->flags & SMB_VCFLAG_USENT)
980 int policy = smb_FindShareCSCPolicy(shareName);
981 smb_SetSMBParm(outp, 2, SMB_SUPPORT_SEARCH_BITS | (policy << 2));
984 smb_SetSMBParm(outp, 2, 0);
988 lock_ObtainMutex(&tidp->mx);
990 tidp->pathname = sharePath;
991 if(ipc) tidp->flags |= SMB_TIDFLAG_IPC;
992 lock_ReleaseMutex(&tidp->mx);
993 smb_ReleaseTID(tidp);
995 ((smb_t *)outp)->tid = newTid;
996 ((smb_t *)inp)->tid = newTid;
997 tp = smb_GetSMBData(outp, NULL);
1002 smb_SetSMBDataLength(outp, 3);
1005 smb_SetSMBDataLength(outp, 4);
1008 osi_Log1(smb_logp, "SMB3 tree connect created ID %d", newTid);
1012 /* must be called with global tran lock held */
1013 smb_tran2Packet_t *smb_FindTran2Packet(smb_vc_t *vcp, smb_packet_t *inp)
1015 smb_tran2Packet_t *tp;
1018 smbp = (smb_t *) inp->data;
1019 for (tp = smb_tran2AssemblyQueuep; tp; tp = (smb_tran2Packet_t *) osi_QNext(&tp->q)) {
1020 if (tp->vcp == vcp && tp->mid == smbp->mid && tp->tid == smbp->tid)
1026 smb_tran2Packet_t *smb_NewTran2Packet(smb_vc_t *vcp, smb_packet_t *inp,
1027 int totalParms, int totalData)
1029 smb_tran2Packet_t *tp;
1032 smbp = (smb_t *) inp->data;
1033 tp = malloc(sizeof(*tp));
1034 memset(tp, 0, sizeof(*tp));
1037 tp->curData = tp->curParms = 0;
1038 tp->totalData = totalData;
1039 tp->totalParms = totalParms;
1040 tp->tid = smbp->tid;
1041 tp->mid = smbp->mid;
1042 tp->uid = smbp->uid;
1043 tp->pid = smbp->pid;
1044 tp->res[0] = smbp->res[0];
1045 osi_QAdd((osi_queue_t **)&smb_tran2AssemblyQueuep, &tp->q);
1046 if (totalParms != 0)
1047 tp->parmsp = malloc(totalParms);
1049 tp->datap = malloc(totalData);
1050 if (smbp->com == 0x25 || smbp->com == 0x26)
1053 tp->opcode = smb_GetSMBParm(inp, 14);
1056 tp->flags |= SMB_TRAN2PFLAG_ALLOC;
1060 smb_tran2Packet_t *smb_GetTran2ResponsePacket(smb_vc_t *vcp,
1061 smb_tran2Packet_t *inp, smb_packet_t *outp,
1062 int totalParms, int totalData)
1064 smb_tran2Packet_t *tp;
1065 unsigned short parmOffset;
1066 unsigned short dataOffset;
1067 unsigned short dataAlign;
1069 tp = malloc(sizeof(*tp));
1070 memset(tp, 0, sizeof(*tp));
1072 tp->curData = tp->curParms = 0;
1073 tp->totalData = totalData;
1074 tp->totalParms = totalParms;
1075 tp->oldTotalParms = totalParms;
1080 tp->res[0] = inp->res[0];
1081 tp->opcode = inp->opcode;
1085 * We calculate where the parameters and data will start.
1086 * This calculation must parallel the calculation in
1087 * smb_SendTran2Packet.
1090 parmOffset = 10*2 + 35;
1091 parmOffset++; /* round to even */
1092 tp->parmsp = (unsigned short *) (outp->data + parmOffset);
1094 dataOffset = parmOffset + totalParms;
1095 dataAlign = dataOffset & 2; /* quad-align */
1096 dataOffset += dataAlign;
1097 tp->datap = outp->data + dataOffset;
1102 /* free a tran2 packet; must be called with smb_globalLock held */
1103 void smb_FreeTran2Packet(smb_tran2Packet_t *t2p)
1105 if (t2p->vcp) smb_ReleaseVC(t2p->vcp);
1106 if (t2p->flags & SMB_TRAN2PFLAG_ALLOC) {
1115 /* called with a VC, an input packet to respond to, and an error code.
1116 * sends an error response.
1118 void smb_SendTran2Error(smb_vc_t *vcp, smb_tran2Packet_t *t2p,
1119 smb_packet_t *tp, long code)
1122 unsigned short errCode;
1123 unsigned char errClass;
1124 unsigned long NTStatus;
1126 if (vcp->flags & SMB_VCFLAG_STATUS32)
1127 smb_MapNTError(code, &NTStatus);
1129 smb_MapCoreError(code, vcp, &errCode, &errClass);
1131 smb_FormatResponsePacket(vcp, NULL, tp);
1132 smbp = (smb_t *) tp;
1134 /* We can handle long names */
1135 if (vcp->flags & SMB_VCFLAG_USENT)
1136 smbp->flg2 |= 0x40; /* IS_LONG_NAME */
1138 /* now copy important fields from the tran 2 packet */
1139 smbp->com = t2p->com;
1140 smbp->tid = t2p->tid;
1141 smbp->mid = t2p->mid;
1142 smbp->pid = t2p->pid;
1143 smbp->uid = t2p->uid;
1144 smbp->res[0] = t2p->res[0];
1145 if (vcp->flags & SMB_VCFLAG_STATUS32) {
1146 smbp->rcls = (unsigned char) (NTStatus & 0xff);
1147 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
1148 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
1149 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
1150 smbp->flg2 |= 0x4000;
1153 smbp->rcls = errClass;
1154 smbp->errLow = (unsigned char) (errCode & 0xff);
1155 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
1159 smb_SendPacket(vcp, tp);
1162 void smb_SendTran2Packet(smb_vc_t *vcp, smb_tran2Packet_t *t2p, smb_packet_t *tp)
1165 unsigned short parmOffset;
1166 unsigned short dataOffset;
1167 unsigned short totalLength;
1168 unsigned short dataAlign;
1171 smb_FormatResponsePacket(vcp, NULL, tp);
1172 smbp = (smb_t *) tp;
1174 /* We can handle long names */
1175 if (vcp->flags & SMB_VCFLAG_USENT)
1176 smbp->flg2 |= 0x40; /* IS_LONG_NAME */
1178 /* now copy important fields from the tran 2 packet */
1179 smbp->com = t2p->com;
1180 smbp->tid = t2p->tid;
1181 smbp->mid = t2p->mid;
1182 smbp->pid = t2p->pid;
1183 smbp->uid = t2p->uid;
1184 smbp->res[0] = t2p->res[0];
1186 totalLength = 1 + t2p->totalData + t2p->totalParms;
1188 /* now add the core parameters (tran2 info) to the packet */
1189 smb_SetSMBParm(tp, 0, t2p->totalParms); /* parm bytes */
1190 smb_SetSMBParm(tp, 1, t2p->totalData); /* data bytes */
1191 smb_SetSMBParm(tp, 2, 0); /* reserved */
1192 smb_SetSMBParm(tp, 3, t2p->totalParms); /* parm bytes in this packet */
1193 parmOffset = 10*2 + 35; /* parm offset in packet */
1194 parmOffset++; /* round to even */
1195 smb_SetSMBParm(tp, 4, parmOffset); /* 11 parm words plus *
1196 * hdr, bcc and wct */
1197 smb_SetSMBParm(tp, 5, 0); /* parm displacement */
1198 smb_SetSMBParm(tp, 6, t2p->totalData); /* data in this packet */
1199 dataOffset = parmOffset + t2p->oldTotalParms;
1200 dataAlign = dataOffset & 2; /* quad-align */
1201 dataOffset += dataAlign;
1202 smb_SetSMBParm(tp, 7, dataOffset); /* offset of data */
1203 smb_SetSMBParm(tp, 8, 0); /* data displacement */
1204 smb_SetSMBParm(tp, 9, 0); /* low: setup word count *
1207 datap = smb_GetSMBData(tp, NULL);
1208 *datap++ = 0; /* we rounded to even */
1210 totalLength += dataAlign;
1211 smb_SetSMBDataLength(tp, totalLength);
1213 /* next, send the datagram */
1214 smb_SendPacket(vcp, tp);
1217 long smb_ReceiveV3Trans(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
1219 smb_tran2Packet_t *asp;
1232 /* We sometimes see 0 word count. What to do? */
1233 if (*inp->wctp == 0) {
1238 osi_Log0(smb_logp, "TRANSACTION word count = 0");
1240 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
1241 ptbuf[0] = "Transaction2 word count = 0";
1242 ReportEvent(h, EVENTLOG_WARNING_TYPE, 0, 1003, NULL,
1243 1, inp->ncb_length, ptbuf, inp);
1244 DeregisterEventSource(h);
1246 osi_Log0(smb_logp, "TRANSACTION word count = 0");
1249 smb_SetSMBDataLength(outp, 0);
1250 smb_SendPacket(vcp, outp);
1254 totalParms = smb_GetSMBParm(inp, 0);
1255 totalData = smb_GetSMBParm(inp, 1);
1257 firstPacket = (inp->inCom == 0x25);
1259 /* find the packet we're reassembling */
1260 lock_ObtainWrite(&smb_globalLock);
1261 asp = smb_FindTran2Packet(vcp, inp);
1263 asp = smb_NewTran2Packet(vcp, inp, totalParms, totalData);
1265 lock_ReleaseWrite(&smb_globalLock);
1267 /* now merge in this latest packet; start by looking up offsets */
1269 parmDisp = dataDisp = 0;
1270 parmOffset = smb_GetSMBParm(inp, 10);
1271 dataOffset = smb_GetSMBParm(inp, 12);
1272 parmCount = smb_GetSMBParm(inp, 9);
1273 dataCount = smb_GetSMBParm(inp, 11);
1274 asp->maxReturnParms = smb_GetSMBParm(inp, 2);
1275 asp->maxReturnData = smb_GetSMBParm(inp, 3);
1277 osi_Log3(smb_logp, "SMB3 received Trans init packet total data %d, cur data %d, max return data %d",
1278 totalData, dataCount, asp->maxReturnData);
1281 parmDisp = smb_GetSMBParm(inp, 4);
1282 parmOffset = smb_GetSMBParm(inp, 3);
1283 dataDisp = smb_GetSMBParm(inp, 7);
1284 dataOffset = smb_GetSMBParm(inp, 6);
1285 parmCount = smb_GetSMBParm(inp, 2);
1286 dataCount = smb_GetSMBParm(inp, 5);
1288 osi_Log2(smb_logp, "SMB3 received Trans aux packet parms %d, data %d",
1289 parmCount, dataCount);
1292 /* now copy the parms and data */
1293 if ( asp->totalParms > 0 && parmCount != 0 )
1295 memcpy(((char *)asp->parmsp) + parmDisp, inp->data + parmOffset, parmCount);
1297 if ( asp->totalData > 0 && dataCount != 0 ) {
1298 memcpy(asp->datap + dataDisp, inp->data + dataOffset, dataCount);
1301 /* account for new bytes */
1302 asp->curData += dataCount;
1303 asp->curParms += parmCount;
1305 /* finally, if we're done, remove the packet from the queue and dispatch it */
1306 if (asp->totalParms > 0 &&
1307 asp->curParms > 0 &&
1308 asp->totalData <= asp->curData &&
1309 asp->totalParms <= asp->curParms) {
1310 /* we've received it all */
1311 lock_ObtainWrite(&smb_globalLock);
1312 osi_QRemove((osi_queue_t **) &smb_tran2AssemblyQueuep, &asp->q);
1313 lock_ReleaseWrite(&smb_globalLock);
1315 /* now dispatch it */
1316 rapOp = asp->parmsp[0];
1318 if ( rapOp >= 0 && rapOp < SMB_RAP_NOPCODES && smb_rapDispatchTable[rapOp].procp) {
1319 osi_LogEvent("AFS-Dispatch-RAP[%s]",myCrt_RapDispatch(rapOp),"vcp[%x] lana[%d] lsn[%d]",(int)vcp,vcp->lana,vcp->lsn);
1320 osi_Log4(smb_logp,"AFS Server - Dispatch-RAP %s vcp[%x] lana[%d] lsn[%d]",myCrt_RapDispatch(rapOp),vcp,vcp->lana,vcp->lsn);
1321 code = (*smb_rapDispatchTable[rapOp].procp)(vcp, asp, outp);
1324 osi_LogEvent("AFS-Dispatch-RAP [invalid]", NULL, "op[%x] vcp[%x] lana[%d] lsn[%d]", rapOp, vcp, vcp->lana, vcp->lsn);
1325 osi_Log4(smb_logp,"AFS Server - Dispatch-RAP [INVALID] op[%x] vcp[%x] lana[%d] lsn[%d]", rapOp, vcp, vcp->lana, vcp->lsn);
1326 code = CM_ERROR_BADOP;
1329 /* if an error is returned, we're supposed to send an error packet,
1330 * otherwise the dispatched function already did the data sending.
1331 * We give dispatched proc the responsibility since it knows how much
1332 * space to allocate.
1335 smb_SendTran2Error(vcp, asp, outp, code);
1338 /* free the input tran 2 packet */
1339 lock_ObtainWrite(&smb_globalLock);
1340 smb_FreeTran2Packet(asp);
1341 lock_ReleaseWrite(&smb_globalLock);
1343 else if (firstPacket) {
1344 /* the first packet in a multi-packet request, we need to send an
1345 * ack to get more data.
1347 smb_SetSMBDataLength(outp, 0);
1348 smb_SendPacket(vcp, outp);
1354 /* ANSI versions. The unicode versions support arbitrary length
1355 share names, but we don't support unicode yet. */
1357 typedef struct smb_rap_share_info_0 {
1358 char shi0_netname[13];
1359 } smb_rap_share_info_0_t;
1361 typedef struct smb_rap_share_info_1 {
1362 char shi1_netname[13];
1365 DWORD shi1_remark; /* char *shi1_remark; data offset */
1366 } smb_rap_share_info_1_t;
1368 typedef struct smb_rap_share_info_2 {
1369 char shi2_netname[13];
1371 unsigned short shi2_type;
1372 DWORD shi2_remark; /* char *shi2_remark; data offset */
1373 unsigned short shi2_permissions;
1374 unsigned short shi2_max_uses;
1375 unsigned short shi2_current_uses;
1376 DWORD shi2_path; /* char *shi2_path; data offset */
1377 unsigned short shi2_passwd[9];
1378 unsigned short shi2_pad2;
1379 } smb_rap_share_info_2_t;
1381 #define SMB_RAP_MAX_SHARES 512
1383 typedef struct smb_rap_share_list {
1386 smb_rap_share_info_0_t * shares;
1387 } smb_rap_share_list_t;
1389 int smb_rapCollectSharesProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp) {
1390 smb_rap_share_list_t * sp;
1395 if (name[0] == '.' && (!name[1] || (name[1] == '.' && !name[2])))
1396 return 0; /* skip over '.' and '..' */
1398 sp = (smb_rap_share_list_t *) vrockp;
1400 strncpy(sp->shares[sp->cShare].shi0_netname, name, 12);
1401 sp->shares[sp->cShare].shi0_netname[12] = 0;
1405 if (sp->cShare >= sp->maxShares)
1406 return CM_ERROR_STOPNOW;
1411 long smb_ReceiveRAPNetShareEnum(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1413 smb_tran2Packet_t *outp;
1414 unsigned short * tp;
1418 int outParmsTotal; /* total parameter bytes */
1419 int outDataTotal; /* total data bytes */
1427 HKEY hkSubmount = NULL;
1428 smb_rap_share_info_1_t * shares;
1431 char thisShare[256];
1434 smb_rap_share_list_t rootShares;
1439 tp = p->parmsp + 1; /* skip over function number (always 0) */
1440 (void) smb_ParseString((char *) tp, (char **) &tp); /* skip over parm descriptor */
1441 (void) smb_ParseString((char *) tp, (char **) &tp); /* skip over data descriptor */
1445 if (infoLevel != 1) {
1446 return CM_ERROR_INVAL;
1449 /* first figure out how many shares there are */
1450 rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSConfigKeyName, 0,
1451 KEY_QUERY_VALUE, &hkParam);
1452 if (rv == ERROR_SUCCESS) {
1453 len = sizeof(allSubmount);
1454 rv = RegQueryValueEx(hkParam, "AllSubmount", NULL, NULL,
1455 (BYTE *) &allSubmount, &len);
1456 if (rv != ERROR_SUCCESS || allSubmount != 0) {
1459 RegCloseKey (hkParam);
1462 rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SOFTWARE\\OpenAFS\\Client\\Submounts",
1463 0, KEY_QUERY_VALUE, &hkSubmount);
1464 if (rv == ERROR_SUCCESS) {
1465 rv = RegQueryInfoKey(hkSubmount, NULL, NULL, NULL, NULL,
1466 NULL, NULL, &nRegShares, NULL, NULL, NULL, NULL);
1467 if (rv != ERROR_SUCCESS)
1473 /* fetch the root shares */
1474 rootShares.maxShares = SMB_RAP_MAX_SHARES;
1475 rootShares.cShare = 0;
1476 rootShares.shares = malloc( sizeof(smb_rap_share_info_0_t) * SMB_RAP_MAX_SHARES );
1480 userp = smb_GetTran2User(vcp,p);
1482 thyper.HighPart = 0;
1485 cm_HoldSCache(cm_rootSCachep);
1486 cm_ApplyDir(cm_rootSCachep, smb_rapCollectSharesProc, &rootShares, &thyper, userp, &req, NULL);
1487 cm_ReleaseSCache(cm_rootSCachep);
1489 cm_ReleaseUser(userp);
1491 nShares = rootShares.cShare + nRegShares + allSubmount;
1493 #define REMARK_LEN 1
1494 outParmsTotal = 8; /* 4 dwords */
1495 outDataTotal = (sizeof(smb_rap_share_info_1_t) + REMARK_LEN) * nShares ;
1496 if(outDataTotal > bufsize) {
1497 nSharesRet = bufsize / (sizeof(smb_rap_share_info_1_t) + REMARK_LEN);
1498 outDataTotal = (sizeof(smb_rap_share_info_1_t) + REMARK_LEN) * nSharesRet;
1501 nSharesRet = nShares;
1504 outp = smb_GetTran2ResponsePacket(vcp, p, op, outParmsTotal, outDataTotal);
1506 /* now for the submounts */
1507 shares = (smb_rap_share_info_1_t *) outp->datap;
1508 cstrp = outp->datap + sizeof(smb_rap_share_info_1_t) * nSharesRet;
1510 memset(outp->datap, 0, (sizeof(smb_rap_share_info_1_t) + REMARK_LEN) * nSharesRet);
1513 strcpy( shares[cshare].shi1_netname, "all" );
1514 shares[cshare].shi1_remark = cstrp - outp->datap;
1515 /* type and pad are zero already */
1521 for (i=0; i < nRegShares && cshare < nSharesRet; i++) {
1522 len = sizeof(thisShare);
1523 rv = RegEnumValue(hkSubmount, i, thisShare, &len, NULL, NULL, NULL, NULL);
1524 if (rv == ERROR_SUCCESS && strlen(thisShare) && (!allSubmount || stricmp(thisShare,"all"))) {
1525 strncpy(shares[cshare].shi1_netname, thisShare, sizeof(shares->shi1_netname)-1);
1526 shares[cshare].shi1_netname[sizeof(shares->shi1_netname)-1] = 0; /* unfortunate truncation */
1527 shares[cshare].shi1_remark = cstrp - outp->datap;
1532 nShares--; /* uncount key */
1535 RegCloseKey(hkSubmount);
1538 nonrootShares = cshare;
1540 for (i=0; i < rootShares.cShare && cshare < nSharesRet; i++) {
1541 /* in case there are collisions with submounts, submounts have higher priority */
1542 for (j=0; j < nonrootShares; j++)
1543 if (!stricmp(shares[j].shi1_netname, rootShares.shares[i].shi0_netname))
1546 if (j < nonrootShares) {
1547 nShares--; /* uncount */
1551 strcpy(shares[cshare].shi1_netname, rootShares.shares[i].shi0_netname);
1552 shares[cshare].shi1_remark = cstrp - outp->datap;
1557 outp->parmsp[0] = ((cshare == nShares)? ERROR_SUCCESS : ERROR_MORE_DATA);
1558 outp->parmsp[1] = 0;
1559 outp->parmsp[2] = cshare;
1560 outp->parmsp[3] = nShares;
1562 outp->totalData = cstrp - outp->datap;
1563 outp->totalParms = outParmsTotal;
1565 smb_SendTran2Packet(vcp, outp, op);
1566 smb_FreeTran2Packet(outp);
1568 free(rootShares.shares);
1573 long smb_ReceiveRAPNetShareGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1575 smb_tran2Packet_t *outp;
1576 unsigned short * tp;
1578 BOOL shareFound = FALSE;
1579 unsigned short infoLevel;
1580 unsigned short bufsize;
1590 tp = p->parmsp + 1; /* skip over function number (always 1) */
1591 (void) smb_ParseString( (char *) tp, (char **) &tp); /* skip over param descriptor */
1592 (void) smb_ParseString( (char *) tp, (char **) &tp); /* skip over data descriptor */
1593 shareName = smb_ParseString( (char *) tp, (char **) &tp);
1600 totalData = sizeof(smb_rap_share_info_0_t);
1601 else if(infoLevel == 1)
1602 totalData = sizeof(smb_rap_share_info_1_t) + 1; /* + empty string */
1603 else if(infoLevel == 2)
1604 totalData = sizeof(smb_rap_share_info_2_t) + 2; /* + two empty strings */
1606 return CM_ERROR_INVAL;
1608 outp = smb_GetTran2ResponsePacket(vcp, p, op, totalParam, totalData);
1610 if(!stricmp(shareName,"all")) {
1611 rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSConfigKeyName, 0,
1612 KEY_QUERY_VALUE, &hkParam);
1613 if (rv == ERROR_SUCCESS) {
1614 len = sizeof(allSubmount);
1615 rv = RegQueryValueEx(hkParam, "AllSubmount", NULL, NULL,
1616 (BYTE *) &allSubmount, &len);
1617 if (rv != ERROR_SUCCESS || allSubmount != 0) {
1620 RegCloseKey (hkParam);
1627 rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SOFTWARE\\OpenAFS\\Client\\Submounts", 0,
1628 KEY_QUERY_VALUE, &hkSubmount);
1629 if (rv == ERROR_SUCCESS) {
1630 rv = RegQueryValueEx(hkSubmount, shareName, NULL, NULL, NULL, NULL);
1631 if (rv == ERROR_SUCCESS) {
1634 RegCloseKey(hkSubmount);
1639 smb_FreeTran2Packet(outp);
1640 return CM_ERROR_BADSHARENAME;
1643 memset(outp->datap, 0, totalData);
1645 outp->parmsp[0] = 0;
1646 outp->parmsp[1] = 0;
1647 outp->parmsp[2] = totalData;
1649 if (infoLevel == 0) {
1650 smb_rap_share_info_0_t * info = (smb_rap_share_info_0_t *) outp->datap;
1651 strncpy(info->shi0_netname, shareName, sizeof(info->shi0_netname)-1);
1652 info->shi0_netname[sizeof(info->shi0_netname)-1] = 0;
1653 } else if(infoLevel == 1) {
1654 smb_rap_share_info_1_t * info = (smb_rap_share_info_1_t *) outp->datap;
1655 strncpy(info->shi1_netname, shareName, sizeof(info->shi1_netname)-1);
1656 info->shi1_netname[sizeof(info->shi1_netname)-1] = 0;
1657 info->shi1_remark = ((unsigned char *) (info + 1)) - outp->datap;
1658 /* type and pad are already zero */
1659 } else { /* infoLevel==2 */
1660 smb_rap_share_info_2_t * info = (smb_rap_share_info_2_t *) outp->datap;
1661 strncpy(info->shi2_netname, shareName, sizeof(info->shi2_netname)-1);
1662 info->shi2_netname[sizeof(info->shi2_netname)-1] = 0;
1663 info->shi2_remark = ((unsigned char *) (info + 1)) - outp->datap;
1664 info->shi2_permissions = ACCESS_ALL;
1665 info->shi2_max_uses = (unsigned short) -1;
1666 info->shi2_path = 1 + (((unsigned char *) (info + 1)) - outp->datap);
1669 outp->totalData = totalData;
1670 outp->totalParms = totalParam;
1672 smb_SendTran2Packet(vcp, outp, op);
1673 smb_FreeTran2Packet(outp);
1678 typedef struct smb_rap_wksta_info_10 {
1679 DWORD wki10_computername; /*char *wki10_computername;*/
1680 DWORD wki10_username; /* char *wki10_username; */
1681 DWORD wki10_langroup; /* char *wki10_langroup;*/
1682 unsigned char wki10_ver_major;
1683 unsigned char wki10_ver_minor;
1684 DWORD wki10_logon_domain; /*char *wki10_logon_domain;*/
1685 DWORD wki10_oth_domains; /* char *wki10_oth_domains;*/
1686 } smb_rap_wksta_info_10_t;
1689 long smb_ReceiveRAPNetWkstaGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1691 smb_tran2Packet_t *outp;
1695 unsigned short * tp;
1698 smb_rap_wksta_info_10_t * info;
1702 tp = p->parmsp + 1; /* Skip over function number */
1703 (void) smb_ParseString((unsigned char*) tp, (char **) &tp); /* skip over param descriptor */
1704 (void) smb_ParseString((unsigned char*) tp, (char **) &tp); /* skip over data descriptor */
1708 if (infoLevel != 10) {
1709 return CM_ERROR_INVAL;
1715 totalData = sizeof(*info) + /* info */
1716 MAX_COMPUTERNAME_LENGTH + /* wki10_computername */
1717 SMB_MAX_USERNAME_LENGTH + /* wki10_username */
1718 MAX_COMPUTERNAME_LENGTH + /* wki10_langroup */
1719 MAX_COMPUTERNAME_LENGTH + /* wki10_logon_domain */
1720 1; /* wki10_oth_domains (null)*/
1722 outp = smb_GetTran2ResponsePacket(vcp, p, op, totalParams, totalData);
1724 memset(outp->parmsp,0,totalParams);
1725 memset(outp->datap,0,totalData);
1727 info = (smb_rap_wksta_info_10_t *) outp->datap;
1728 cstrp = (char *) (info + 1);
1730 info->wki10_computername = (DWORD) (cstrp - outp->datap);
1731 strcpy(cstrp, smb_localNamep);
1732 cstrp += strlen(cstrp) + 1;
1734 info->wki10_username = (DWORD) (cstrp - outp->datap);
1735 uidp = smb_FindUID(vcp, p->uid, 0);
1737 lock_ObtainMutex(&uidp->mx);
1738 if(uidp->unp && uidp->unp->name)
1739 strcpy(cstrp, uidp->unp->name);
1740 lock_ReleaseMutex(&uidp->mx);
1741 smb_ReleaseUID(uidp);
1743 cstrp += strlen(cstrp) + 1;
1745 info->wki10_langroup = (DWORD) (cstrp - outp->datap);
1746 strcpy(cstrp, "WORKGROUP");
1747 cstrp += strlen(cstrp) + 1;
1749 /* TODO: Not sure what values these should take, but these work */
1750 info->wki10_ver_major = 5;
1751 info->wki10_ver_minor = 1;
1753 info->wki10_logon_domain = (DWORD) (cstrp - outp->datap);
1754 strcpy(cstrp, smb_ServerDomainName);
1755 cstrp += strlen(cstrp) + 1;
1757 info->wki10_oth_domains = (DWORD) (cstrp - outp->datap);
1758 cstrp ++; /* no other domains */
1760 outp->totalData = (unsigned short) (cstrp - outp->datap); /* actual data size */
1761 outp->parmsp[2] = outp->totalData;
1762 outp->totalParms = totalParams;
1764 smb_SendTran2Packet(vcp,outp,op);
1765 smb_FreeTran2Packet(outp);
1770 typedef struct smb_rap_server_info_0 {
1772 } smb_rap_server_info_0_t;
1774 typedef struct smb_rap_server_info_1 {
1776 char sv1_version_major;
1777 char sv1_version_minor;
1778 unsigned long sv1_type;
1779 DWORD *sv1_comment_or_master_browser; /* char *sv1_comment_or_master_browser;*/
1780 } smb_rap_server_info_1_t;
1782 char smb_ServerComment[] = "OpenAFS Client";
1783 int smb_ServerCommentLen = sizeof(smb_ServerComment);
1785 #define SMB_SV_TYPE_SERVER 0x00000002L
1786 #define SMB_SV_TYPE_NT 0x00001000L
1787 #define SMB_SV_TYPE_SERVER_NT 0x00008000L
1789 long smb_ReceiveRAPNetServerGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1791 smb_tran2Packet_t *outp;
1795 unsigned short * tp;
1798 smb_rap_server_info_0_t * info0;
1799 smb_rap_server_info_1_t * info1;
1802 tp = p->parmsp + 1; /* Skip over function number */
1803 (void) smb_ParseString((unsigned char*) tp, (char **) &tp); /* skip over param descriptor */
1804 (void) smb_ParseString((unsigned char*) tp, (char **) &tp); /* skip over data descriptor */
1808 if (infoLevel != 0 && infoLevel != 1) {
1809 return CM_ERROR_INVAL;
1815 (infoLevel == 0) ? sizeof(smb_rap_server_info_0_t)
1816 : (sizeof(smb_rap_server_info_1_t) + smb_ServerCommentLen);
1818 outp = smb_GetTran2ResponsePacket(vcp, p, op, totalParams, totalData);
1820 memset(outp->parmsp,0,totalParams);
1821 memset(outp->datap,0,totalData);
1823 if (infoLevel == 0) {
1824 info0 = (smb_rap_server_info_0_t *) outp->datap;
1825 cstrp = (char *) (info0 + 1);
1826 strcpy(info0->sv0_name, "AFS");
1827 } else { /* infoLevel == 1 */
1828 info1 = (smb_rap_server_info_1_t *) outp->datap;
1829 cstrp = (char *) (info1 + 1);
1830 strcpy(info1->sv1_name, "AFS");
1833 SMB_SV_TYPE_SERVER |
1835 SMB_SV_TYPE_SERVER_NT;
1837 info1->sv1_version_major = 5;
1838 info1->sv1_version_minor = 1;
1839 info1->sv1_comment_or_master_browser = (DWORD *) (cstrp - outp->datap);
1841 strcpy(cstrp, smb_ServerComment);
1843 cstrp += smb_ServerCommentLen;
1846 totalData = cstrp - outp->datap;
1847 outp->totalData = min(bufsize,totalData); /* actual data size */
1848 outp->parmsp[0] = (outp->totalData == totalData)? 0 : ERROR_MORE_DATA;
1849 outp->parmsp[2] = totalData;
1850 outp->totalParms = totalParams;
1852 smb_SendTran2Packet(vcp,outp,op);
1853 smb_FreeTran2Packet(outp);
1858 long smb_ReceiveV3Tran2A(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
1860 smb_tran2Packet_t *asp;
1872 /* We sometimes see 0 word count. What to do? */
1873 if (*inp->wctp == 0) {
1878 osi_Log0(smb_logp, "TRANSACTION2 word count = 0");
1880 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
1881 ptbuf[0] = "Transaction2 word count = 0";
1882 ReportEvent(h, EVENTLOG_WARNING_TYPE, 0, 1003, NULL,
1883 1, inp->ncb_length, ptbuf, inp);
1884 DeregisterEventSource(h);
1886 osi_Log0(smb_logp, "TRANSACTION2 word count = 0");
1889 smb_SetSMBDataLength(outp, 0);
1890 smb_SendPacket(vcp, outp);
1894 totalParms = smb_GetSMBParm(inp, 0);
1895 totalData = smb_GetSMBParm(inp, 1);
1897 firstPacket = (inp->inCom == 0x32);
1899 /* find the packet we're reassembling */
1900 lock_ObtainWrite(&smb_globalLock);
1901 asp = smb_FindTran2Packet(vcp, inp);
1903 asp = smb_NewTran2Packet(vcp, inp, totalParms, totalData);
1905 lock_ReleaseWrite(&smb_globalLock);
1907 /* now merge in this latest packet; start by looking up offsets */
1909 parmDisp = dataDisp = 0;
1910 parmOffset = smb_GetSMBParm(inp, 10);
1911 dataOffset = smb_GetSMBParm(inp, 12);
1912 parmCount = smb_GetSMBParm(inp, 9);
1913 dataCount = smb_GetSMBParm(inp, 11);
1914 asp->maxReturnParms = smb_GetSMBParm(inp, 2);
1915 asp->maxReturnData = smb_GetSMBParm(inp, 3);
1917 osi_Log3(smb_logp, "SMB3 received T2 init packet total data %d, cur data %d, max return data %d",
1918 totalData, dataCount, asp->maxReturnData);
1921 parmDisp = smb_GetSMBParm(inp, 4);
1922 parmOffset = smb_GetSMBParm(inp, 3);
1923 dataDisp = smb_GetSMBParm(inp, 7);
1924 dataOffset = smb_GetSMBParm(inp, 6);
1925 parmCount = smb_GetSMBParm(inp, 2);
1926 dataCount = smb_GetSMBParm(inp, 5);
1928 osi_Log2(smb_logp, "SMB3 received T2 aux packet parms %d, data %d",
1929 parmCount, dataCount);
1932 /* now copy the parms and data */
1933 if ( asp->totalParms > 0 && parmCount != 0 )
1935 memcpy(((char *)asp->parmsp) + parmDisp, inp->data + parmOffset, parmCount);
1937 if ( asp->totalData > 0 && dataCount != 0 ) {
1938 memcpy(asp->datap + dataDisp, inp->data + dataOffset, dataCount);
1941 /* account for new bytes */
1942 asp->curData += dataCount;
1943 asp->curParms += parmCount;
1945 /* finally, if we're done, remove the packet from the queue and dispatch it */
1946 if (asp->totalParms > 0 &&
1947 asp->curParms > 0 &&
1948 asp->totalData <= asp->curData &&
1949 asp->totalParms <= asp->curParms) {
1950 /* we've received it all */
1951 lock_ObtainWrite(&smb_globalLock);
1952 osi_QRemove((osi_queue_t **) &smb_tran2AssemblyQueuep, &asp->q);
1953 lock_ReleaseWrite(&smb_globalLock);
1955 /* now dispatch it */
1956 if ( asp->opcode >= 0 && asp->opcode < 20 && smb_tran2DispatchTable[asp->opcode].procp) {
1957 osi_LogEvent("AFS-Dispatch-2[%s]",myCrt_2Dispatch(asp->opcode),"vcp[%x] lana[%d] lsn[%d]",(int)vcp,vcp->lana,vcp->lsn);
1958 osi_Log4(smb_logp,"AFS Server - Dispatch-2 %s vcp[%x] lana[%d] lsn[%d]",myCrt_2Dispatch(asp->opcode),vcp,vcp->lana,vcp->lsn);
1959 code = (*smb_tran2DispatchTable[asp->opcode].procp)(vcp, asp, outp);
1962 osi_LogEvent("AFS-Dispatch-2 [invalid]", NULL, "op[%x] vcp[%x] lana[%d] lsn[%d]", asp->opcode, vcp, vcp->lana, vcp->lsn);
1963 osi_Log4(smb_logp,"AFS Server - Dispatch-2 [INVALID] op[%x] vcp[%x] lana[%d] lsn[%d]", asp->opcode, vcp, vcp->lana, vcp->lsn);
1964 code = CM_ERROR_BADOP;
1967 /* if an error is returned, we're supposed to send an error packet,
1968 * otherwise the dispatched function already did the data sending.
1969 * We give dispatched proc the responsibility since it knows how much
1970 * space to allocate.
1973 smb_SendTran2Error(vcp, asp, outp, code);
1976 /* free the input tran 2 packet */
1977 lock_ObtainWrite(&smb_globalLock);
1978 smb_FreeTran2Packet(asp);
1979 lock_ReleaseWrite(&smb_globalLock);
1981 else if (firstPacket) {
1982 /* the first packet in a multi-packet request, we need to send an
1983 * ack to get more data.
1985 smb_SetSMBDataLength(outp, 0);
1986 smb_SendPacket(vcp, outp);
1992 long smb_ReceiveTran2Open(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1995 smb_tran2Packet_t *outp;
2000 cm_scache_t *dscp; /* dir we're dealing with */
2001 cm_scache_t *scp; /* file we're creating */
2003 int initialModeBits;
2013 int parmSlot; /* which parm we're dealing with */
2014 long returnEALength;
2022 extraInfo = (p->parmsp[0] & 1); /* return extra info */
2023 returnEALength = (p->parmsp[0] & 8); /* return extended attr length */
2025 openFun = p->parmsp[6]; /* open function */
2026 excl = ((openFun & 3) == 0);
2027 trunc = ((openFun & 3) == 2); /* truncate it */
2028 openMode = (p->parmsp[1] & 0x7);
2029 openAction = 0; /* tracks what we did */
2031 attributes = p->parmsp[3];
2032 dosTime = p->parmsp[4] | (p->parmsp[5] << 16);
2034 /* compute initial mode bits based on read-only flag in attributes */
2035 initialModeBits = 0666;
2036 if (attributes & 1) initialModeBits &= ~0222;
2038 pathp = (char *) (&p->parmsp[14]);
2040 outp = smb_GetTran2ResponsePacket(vcp, p, op, 40, 0);
2042 spacep = cm_GetSpace();
2043 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
2045 if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
2046 /* special case magic file name for receiving IOCTL requests
2047 * (since IOCTL calls themselves aren't getting through).
2049 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
2050 smb_SetupIoctlFid(fidp, spacep);
2052 /* copy out remainder of the parms */
2054 outp->parmsp[parmSlot] = fidp->fid; parmSlot++;
2056 outp->parmsp[parmSlot] = /* attrs */ 0; parmSlot++;
2057 outp->parmsp[parmSlot] = 0; parmSlot++; /* mod time */
2058 outp->parmsp[parmSlot] = 0; parmSlot++;
2059 outp->parmsp[parmSlot] = 0; parmSlot++; /* len */
2060 outp->parmsp[parmSlot] = 0x7fff; parmSlot++;
2061 outp->parmsp[parmSlot] = openMode; parmSlot++;
2062 outp->parmsp[parmSlot] = 0; parmSlot++; /* file type 0 ==> normal file or dir */
2063 outp->parmsp[parmSlot] = 0; parmSlot++; /* IPC junk */
2065 /* and the final "always present" stuff */
2066 outp->parmsp[parmSlot] = /* openAction found existing file */ 1; parmSlot++;
2067 /* next write out the "unique" ID */
2068 outp->parmsp[parmSlot] = 0x1234; parmSlot++;
2069 outp->parmsp[parmSlot] = 0x5678; parmSlot++;
2070 outp->parmsp[parmSlot] = 0; parmSlot++;
2071 if (returnEALength) {
2072 outp->parmsp[parmSlot] = 0; parmSlot++;
2073 outp->parmsp[parmSlot] = 0; parmSlot++;
2076 outp->totalData = 0;
2077 outp->totalParms = parmSlot * 2;
2079 smb_SendTran2Packet(vcp, outp, op);
2081 smb_FreeTran2Packet(outp);
2083 /* and clean up fid reference */
2084 smb_ReleaseFID(fidp);
2088 #ifdef DEBUG_VERBOSE
2090 char *hexp, *asciip;
2091 asciip = (lastNamep ? lastNamep : pathp);
2092 hexp = osi_HexifyString( asciip );
2093 DEBUG_EVENT2("AFS","T2Open H[%s] A[%s]", hexp, asciip);
2098 userp = smb_GetTran2User(vcp, p);
2099 /* In the off chance that userp is NULL, we log and abandon */
2101 osi_Log1(smb_logp, "ReceiveTran2Open user [%d] not resolvable", p->uid);
2102 smb_FreeTran2Packet(outp);
2103 return CM_ERROR_BADSMB;
2106 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
2107 if (code == CM_ERROR_TIDIPC) {
2108 /* Attempt to use TID allocated for IPC. The client is
2109 probably trying to locate DCE RPC end points, which
2110 we don't support. */
2111 osi_Log0(smb_logp, "Tran2Open received IPC TID");
2112 cm_ReleaseUser(userp);
2113 smb_FreeTran2Packet(outp);
2114 return CM_ERROR_NOSUCHPATH;
2118 code = cm_NameI(cm_rootSCachep, pathp,
2119 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
2120 userp, tidPathp, &req, &scp);
2122 code = cm_NameI(cm_rootSCachep, spacep->data,
2123 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
2124 userp, tidPathp, &req, &dscp);
2125 cm_FreeSpace(spacep);
2128 cm_ReleaseUser(userp);
2129 smb_FreeTran2Packet(outp);
2133 /* otherwise, scp points to the parent directory. Do a lookup,
2134 * and truncate the file if we find it, otherwise we create the
2141 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD, userp,
2143 if (code && code != CM_ERROR_NOSUCHFILE) {
2144 cm_ReleaseSCache(dscp);
2145 cm_ReleaseUser(userp);
2146 smb_FreeTran2Packet(outp);
2151 cm_FreeSpace(spacep);
2154 /* if we get here, if code is 0, the file exists and is represented by
2155 * scp. Otherwise, we have to create it.
2158 code = cm_CheckOpen(scp, openMode, trunc, userp, &req);
2160 if (dscp) cm_ReleaseSCache(dscp);
2161 cm_ReleaseSCache(scp);
2162 cm_ReleaseUser(userp);
2163 smb_FreeTran2Packet(outp);
2168 /* oops, file shouldn't be there */
2169 if (dscp) cm_ReleaseSCache(dscp);
2170 cm_ReleaseSCache(scp);
2171 cm_ReleaseUser(userp);
2172 smb_FreeTran2Packet(outp);
2173 return CM_ERROR_EXISTS;
2177 setAttr.mask = CM_ATTRMASK_LENGTH;
2178 setAttr.length.LowPart = 0;
2179 setAttr.length.HighPart = 0;
2180 code = cm_SetAttr(scp, &setAttr, userp, &req);
2181 openAction = 3; /* truncated existing file */
2184 openAction = 1; /* found existing file */
2186 else if (!(openFun & SMB_ATTR_DIRECTORY)) {
2187 /* don't create if not found */
2188 if (dscp) cm_ReleaseSCache(dscp);
2189 osi_assert(scp == NULL);
2190 cm_ReleaseUser(userp);
2191 smb_FreeTran2Packet(outp);
2192 return CM_ERROR_NOSUCHFILE;
2195 osi_assert(dscp != NULL && scp == NULL);
2196 openAction = 2; /* created file */
2197 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
2198 smb_UnixTimeFromSearchTime(&setAttr.clientModTime, dosTime);
2199 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
2201 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
2202 smb_NotifyChange(FILE_ACTION_ADDED,
2203 FILE_NOTIFY_CHANGE_FILE_NAME,
2204 dscp, lastNamep, NULL, TRUE);
2205 if (!excl && code == CM_ERROR_EXISTS) {
2206 /* not an exclusive create, and someone else tried
2207 * creating it already, then we open it anyway. We
2208 * don't bother retrying after this, since if this next
2209 * fails, that means that the file was deleted after we
2210 * started this call.
2212 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
2216 setAttr.mask = CM_ATTRMASK_LENGTH;
2217 setAttr.length.LowPart = 0;
2218 setAttr.length.HighPart = 0;
2219 code = cm_SetAttr(scp, &setAttr, userp,
2222 } /* lookup succeeded */
2226 /* we don't need this any longer */
2227 if (dscp) cm_ReleaseSCache(dscp);
2230 /* something went wrong creating or truncating the file */
2231 if (scp) cm_ReleaseSCache(scp);
2232 cm_ReleaseUser(userp);
2233 smb_FreeTran2Packet(outp);
2237 /* make sure we're about to open a file */
2238 if (scp->fileType != CM_SCACHETYPE_FILE) {
2240 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
2241 cm_scache_t * targetScp = 0;
2242 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
2244 /* we have a more accurate file to use (the
2245 * target of the symbolic link). Otherwise,
2246 * we'll just use the symlink anyway.
2248 osi_Log2(smb_logp, "symlink vp %x to vp %x",
2250 cm_ReleaseSCache(scp);
2254 if (scp->fileType != CM_SCACHETYPE_FILE) {
2255 cm_ReleaseSCache(scp);
2256 cm_ReleaseUser(userp);
2257 smb_FreeTran2Packet(outp);
2258 return CM_ERROR_ISDIR;
2262 /* now all we have to do is open the file itself */
2263 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
2266 /* save a pointer to the vnode */
2269 /* compute open mode */
2270 if (openMode != 1) fidp->flags |= SMB_FID_OPENREAD;
2271 if (openMode == 1 || openMode == 2)
2272 fidp->flags |= SMB_FID_OPENWRITE;
2274 smb_ReleaseFID(fidp);
2276 cm_Open(scp, 0, userp);
2278 /* copy out remainder of the parms */
2280 outp->parmsp[parmSlot] = fidp->fid; parmSlot++;
2281 lock_ObtainMutex(&scp->mx);
2283 outp->parmsp[parmSlot] = smb_Attributes(scp); parmSlot++;
2284 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
2285 outp->parmsp[parmSlot] = (unsigned short)(dosTime & 0xffff); parmSlot++;
2286 outp->parmsp[parmSlot] = (unsigned short)((dosTime>>16) & 0xffff); parmSlot++;
2287 outp->parmsp[parmSlot] = (unsigned short) (scp->length.LowPart & 0xffff);
2289 outp->parmsp[parmSlot] = (unsigned short) ((scp->length.LowPart >> 16) & 0xffff);
2291 outp->parmsp[parmSlot] = openMode; parmSlot++;
2292 outp->parmsp[parmSlot] = 0; parmSlot++; /* file type 0 ==> normal file or dir */
2293 outp->parmsp[parmSlot] = 0; parmSlot++; /* IPC junk */
2295 /* and the final "always present" stuff */
2296 outp->parmsp[parmSlot] = openAction; parmSlot++;
2297 /* next write out the "unique" ID */
2298 outp->parmsp[parmSlot] = (unsigned short) (scp->fid.vnode & 0xffff); parmSlot++;
2299 outp->parmsp[parmSlot] = (unsigned short) (scp->fid.volume & 0xffff); parmSlot++;
2300 outp->parmsp[parmSlot] = 0; parmSlot++;
2301 if (returnEALength) {
2302 outp->parmsp[parmSlot] = 0; parmSlot++;
2303 outp->parmsp[parmSlot] = 0; parmSlot++;
2305 lock_ReleaseMutex(&scp->mx);
2306 outp->totalData = 0; /* total # of data bytes */
2307 outp->totalParms = parmSlot * 2; /* shorts are two bytes */
2309 smb_SendTran2Packet(vcp, outp, op);
2311 smb_FreeTran2Packet(outp);
2313 cm_ReleaseUser(userp);
2314 /* leave scp held since we put it in fidp->scp */
2318 long smb_ReceiveTran2FindFirst(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
2320 osi_Log0(smb_logp,"ReceiveTran2FindFirst - NOT_SUPPORTED");
2321 return CM_ERROR_BADOP;
2324 long smb_ReceiveTran2FindNext(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
2326 osi_Log0(smb_logp,"ReceiveTran2FindNext - NOT_SUPPORTED");
2327 return CM_ERROR_BADOP;
2330 long smb_ReceiveTran2QFSInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
2332 smb_tran2Packet_t *outp;
2333 smb_tran2QFSInfo_t qi;
2336 static char FSname[6] = {'A', 0, 'F', 0, 'S', 0};
2338 osi_Log1(smb_logp, "T2 QFSInfo type 0x%x", p->parmsp[0]);
2340 switch (p->parmsp[0]) {
2341 case 1: responseSize = sizeof(qi.u.allocInfo); break;
2342 case 2: responseSize = sizeof(qi.u.volumeInfo); break;
2343 case 0x102: responseSize = sizeof(qi.u.FSvolumeInfo); break;
2344 case 0x103: responseSize = sizeof(qi.u.FSsizeInfo); break;
2345 case 0x104: responseSize = sizeof(qi.u.FSdeviceInfo); break;
2346 case 0x105: responseSize = sizeof(qi.u.FSattributeInfo); break;
2347 default: return CM_ERROR_INVAL;
2350 outp = smb_GetTran2ResponsePacket(vcp, p, op, 0, responseSize);
2351 switch (p->parmsp[0]) {
2354 qi.u.allocInfo.FSID = 0;
2355 qi.u.allocInfo.sectorsPerAllocUnit = 1;
2356 qi.u.allocInfo.totalAllocUnits = 0x7fffffff;
2357 qi.u.allocInfo.availAllocUnits = 0x3fffffff;
2358 qi.u.allocInfo.bytesPerSector = 1024;
2363 qi.u.volumeInfo.vsn = 1234;
2364 qi.u.volumeInfo.vnCount = 4;
2365 /* we're supposed to pad it out with zeroes to the end */
2366 memset(&qi.u.volumeInfo.label, 0, sizeof(qi.u.volumeInfo.label));
2367 memcpy(qi.u.volumeInfo.label, "AFS", 4);
2371 /* FS volume info */
2372 memset((char *)&qi.u.FSvolumeInfo.vct, 0, sizeof(FILETIME));
2373 qi.u.FSvolumeInfo.vsn = 1234;
2374 qi.u.FSvolumeInfo.vnCount = 8;
2375 memcpy(qi.u.FSvolumeInfo.label, "A\0F\0S\0\0", 8);
2381 temp.LowPart = 0x7fffffff;
2382 qi.u.FSsizeInfo.totalAllocUnits = temp;
2383 temp.LowPart = 0x3fffffff;
2384 qi.u.FSsizeInfo.availAllocUnits = temp;
2385 qi.u.FSsizeInfo.sectorsPerAllocUnit = 1;
2386 qi.u.FSsizeInfo.bytesPerSector = 1024;
2390 /* FS device info */
2391 qi.u.FSdeviceInfo.devType = 0; /* don't have a number */
2392 qi.u.FSdeviceInfo.characteristics = 0x50; /* remote, virtual */
2396 /* FS attribute info */
2397 /* attributes, defined in WINNT.H:
2398 * FILE_CASE_SENSITIVE_SEARCH 0x1
2399 * FILE_CASE_PRESERVED_NAMES 0x2
2400 * <no name defined> 0x4000
2401 * If bit 0x4000 is not set, Windows 95 thinks
2402 * we can't handle long (non-8.3) names,
2403 * despite our protestations to the contrary.
2405 qi.u.FSattributeInfo.attributes = 0x4003;
2406 qi.u.FSattributeInfo.maxCompLength = 255;
2407 qi.u.FSattributeInfo.FSnameLength = 6;
2408 memcpy(qi.u.FSattributeInfo.FSname, FSname, 6);
2412 /* copy out return data, and set corresponding sizes */
2413 outp->totalParms = 0;
2414 outp->totalData = responseSize;
2415 memcpy(outp->datap, &qi, responseSize);
2417 /* send and free the packets */
2418 smb_SendTran2Packet(vcp, outp, op);
2419 smb_FreeTran2Packet(outp);
2424 long smb_ReceiveTran2SetFSInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
2426 osi_Log0(smb_logp,"ReceiveTran2SetFSInfo - NOT_SUPPORTED");
2427 return CM_ERROR_BADOP;
2430 struct smb_ShortNameRock {
2434 size_t shortNameLen;
2437 int cm_GetShortNameProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *vrockp,
2440 struct smb_ShortNameRock *rockp;
2444 /* compare both names and vnodes, though probably just comparing vnodes
2445 * would be safe enough.
2447 if (cm_stricmp(dep->name, rockp->maskp) != 0)
2449 if (ntohl(dep->fid.vnode) != rockp->vnode)
2451 /* This is the entry */
2452 cm_Gen8Dot3Name(dep, rockp->shortName, &shortNameEnd);
2453 rockp->shortNameLen = shortNameEnd - rockp->shortName;
2454 return CM_ERROR_STOPNOW;
2457 long cm_GetShortName(char *pathp, cm_user_t *userp, cm_req_t *reqp,
2458 char *tidPathp, int vnode, char *shortName, size_t *shortNameLenp)
2460 struct smb_ShortNameRock rock;
2464 int caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
2468 spacep = cm_GetSpace();
2469 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
2471 code = cm_NameI(cm_rootSCachep, spacep->data, caseFold, userp, tidPathp,
2473 cm_FreeSpace(spacep);
2474 if (code) return code;
2476 if (!lastNamep) lastNamep = pathp;
2479 thyper.HighPart = 0;
2480 rock.shortName = shortName;
2482 rock.maskp = lastNamep;
2483 code = cm_ApplyDir(dscp, cm_GetShortNameProc, &rock, &thyper, userp, reqp, NULL);
2485 cm_ReleaseSCache(dscp);
2488 return CM_ERROR_NOSUCHFILE;
2489 if (code == CM_ERROR_STOPNOW) {
2490 *shortNameLenp = rock.shortNameLen;
2496 long smb_ReceiveTran2QPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
2498 smb_tran2Packet_t *outp;
2501 unsigned short infoLevel;
2503 unsigned short attributes;
2504 unsigned long extAttributes;
2509 cm_scache_t *scp, *dscp;
2518 infoLevel = p->parmsp[0];
2519 if (infoLevel == 6) nbytesRequired = 0;
2520 else if (infoLevel == 1) nbytesRequired = 22;
2521 else if (infoLevel == 2) nbytesRequired = 26;
2522 else if (infoLevel == 0x101) nbytesRequired = 40;
2523 else if (infoLevel == 0x102) nbytesRequired = 24;
2524 else if (infoLevel == 0x103) nbytesRequired = 4;
2525 else if (infoLevel == 0x108) nbytesRequired = 30;
2527 osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
2528 p->opcode, infoLevel);
2529 smb_SendTran2Error(vcp, p, opx, CM_ERROR_INVAL);
2532 osi_Log2(smb_logp, "T2 QPathInfo type 0x%x path %s", infoLevel,
2533 osi_LogSaveString(smb_logp, (char *)(&p->parmsp[3])));
2535 outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, nbytesRequired);
2537 if (infoLevel > 0x100)
2538 outp->totalParms = 2;
2540 outp->totalParms = 0;
2541 outp->totalData = nbytesRequired;
2543 /* now, if we're at infoLevel 6, we're only being asked to check
2544 * the syntax, so we just OK things now. In particular, we're *not*
2545 * being asked to verify anything about the state of any parent dirs.
2547 if (infoLevel == 6) {
2548 smb_SendTran2Packet(vcp, outp, opx);
2549 smb_FreeTran2Packet(outp);
2553 userp = smb_GetTran2User(vcp, p);
2555 osi_Log1(smb_logp, "ReceiveTran2QPathInfo unable to resolve user [%d]", p->uid);
2556 smb_FreeTran2Packet(outp);
2557 return CM_ERROR_BADSMB;
2560 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
2562 cm_ReleaseUser(userp);
2563 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOSUCHPATH);
2564 smb_FreeTran2Packet(outp);
2569 * XXX Strange hack XXX
2571 * As of Patch 7 (13 January 98), we are having the following problem:
2572 * In NT Explorer 4.0, whenever we click on a directory, AFS gets
2573 * requests to look up "desktop.ini" in all the subdirectories.
2574 * This can cause zillions of timeouts looking up non-existent cells
2575 * and volumes, especially in the top-level directory.
2577 * We have not found any way to avoid this or work around it except
2578 * to explicitly ignore the requests for mount points that haven't
2579 * yet been evaluated and for directories that haven't yet been
2582 if (infoLevel == 0x101) {
2583 spacep = cm_GetSpace();
2584 smb_StripLastComponent(spacep->data, &lastComp,
2585 (char *)(&p->parmsp[3]));
2586 #ifndef SPECIAL_FOLDERS
2587 /* Make sure that lastComp is not NULL */
2589 if (stricmp(lastComp, "\\desktop.ini") == 0) {
2590 code = cm_NameI(cm_rootSCachep, spacep->data,
2594 userp, tidPathp, &req, &dscp);
2596 if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT
2597 && !dscp->mountRootFidp)
2598 code = CM_ERROR_NOSUCHFILE;
2599 else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
2600 cm_buf_t *bp = buf_Find(dscp, &hzero);
2604 code = CM_ERROR_NOSUCHFILE;
2606 cm_ReleaseSCache(dscp);
2608 cm_FreeSpace(spacep);
2609 cm_ReleaseUser(userp);
2610 smb_SendTran2Error(vcp, p, opx, code);
2611 smb_FreeTran2Packet(outp);
2617 #endif /* SPECIAL_FOLDERS */
2619 cm_FreeSpace(spacep);
2622 /* now do namei and stat, and copy out the info */
2623 code = cm_NameI(cm_rootSCachep, (char *)(&p->parmsp[3]),
2624 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, tidPathp, &req, &scp);
2627 cm_ReleaseUser(userp);
2628 smb_SendTran2Error(vcp, p, opx, code);
2629 smb_FreeTran2Packet(outp);
2633 lock_ObtainMutex(&scp->mx);
2634 code = cm_SyncOp(scp, NULL, userp, &req, 0,
2635 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
2636 if (code) goto done;
2638 /* now we have the status in the cache entry, and everything is locked.
2639 * Marshall the output data.
2642 /* for info level 108, figure out short name */
2643 if (infoLevel == 0x108) {
2644 code = cm_GetShortName((char *)(&p->parmsp[3]), userp, &req,
2645 tidPathp, scp->fid.vnode, shortName,
2652 *((u_long *)op) = len * 2; op += 4;
2653 mbstowcs((unsigned short *)op, shortName, len);
2658 if (infoLevel == 1 || infoLevel == 2) {
2659 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
2660 *((u_long *)op) = dosTime; op += 4; /* creation time */
2661 *((u_long *)op) = dosTime; op += 4; /* access time */
2662 *((u_long *)op) = dosTime; op += 4; /* write time */
2663 *((u_long *)op) = scp->length.LowPart; op += 4; /* length */
2664 *((u_long *)op) = scp->length.LowPart; op += 4; /* alloc size */
2665 attributes = smb_Attributes(scp);
2666 *((u_short *)op) = attributes; op += 2; /* attributes */
2668 else if (infoLevel == 0x101) {
2669 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
2670 *((FILETIME *)op) = ft; op += 8; /* creation time */
2671 *((FILETIME *)op) = ft; op += 8; /* last access time */
2672 *((FILETIME *)op) = ft; op += 8; /* last write time */
2673 *((FILETIME *)op) = ft; op += 8; /* last change time */
2674 extAttributes = smb_ExtAttributes(scp);
2675 *((u_long *)op) = extAttributes; op += 4; /* extended attribs */
2676 *((u_long *)op) = 0; op += 4; /* don't know what this is */
2678 else if (infoLevel == 0x102) {
2679 *((LARGE_INTEGER *)op) = scp->length; op += 8; /* alloc size */
2680 *((LARGE_INTEGER *)op) = scp->length; op += 8; /* EOF */
2681 *((u_long *)op) = scp->linkCount; op += 4;
2684 *op++ = (scp->fileType == CM_SCACHETYPE_DIRECTORY ? 1 : 0);
2687 else if (infoLevel == 0x103) {
2688 memset(op, 0, 4); op += 4; /* EA size */
2691 /* now, if we are being asked about extended attrs, return a 0 size */
2692 if (infoLevel == 2) {
2693 *((u_long *)op) = 0; op += 4;
2697 /* send and free the packets */
2699 lock_ReleaseMutex(&scp->mx);
2700 cm_ReleaseSCache(scp);
2701 cm_ReleaseUser(userp);
2703 smb_SendTran2Packet(vcp, outp, opx);
2705 smb_SendTran2Error(vcp, p, opx, code);
2706 smb_FreeTran2Packet(outp);
2711 long smb_ReceiveTran2SetPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
2713 osi_Log0(smb_logp,"ReceiveTran2SetPathInfo - NOT_SUPPORTED");
2714 return CM_ERROR_BADOP;
2717 long smb_ReceiveTran2QFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
2719 smb_tran2Packet_t *outp;
2721 unsigned long attributes;
2722 unsigned short infoLevel;
2735 fidp = smb_FindFID(vcp, fid, 0);
2738 smb_SendTran2Error(vcp, p, opx, CM_ERROR_BADFD);
2742 infoLevel = p->parmsp[1];
2743 if (infoLevel == 0x101) nbytesRequired = 40;
2744 else if (infoLevel == 0x102) nbytesRequired = 24;
2745 else if (infoLevel == 0x103) nbytesRequired = 4;
2746 else if (infoLevel == 0x104) nbytesRequired = 6;
2748 osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
2749 p->opcode, infoLevel);
2750 smb_SendTran2Error(vcp, p, opx, CM_ERROR_INVAL);
2751 smb_ReleaseFID(fidp);
2754 osi_Log2(smb_logp, "T2 QFileInfo type 0x%x fid %d", infoLevel, fid);
2756 outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, nbytesRequired);
2758 if (infoLevel > 0x100)
2759 outp->totalParms = 2;
2761 outp->totalParms = 0;
2762 outp->totalData = nbytesRequired;
2764 userp = smb_GetTran2User(vcp, p);
2766 osi_Log1(smb_logp, "ReceiveTran2QFileInfo unable to resolve user [%d]", p->uid);
2767 code = CM_ERROR_BADSMB;
2772 lock_ObtainMutex(&scp->mx);
2773 code = cm_SyncOp(scp, NULL, userp, &req, 0,
2774 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
2778 /* now we have the status in the cache entry, and everything is locked.
2779 * Marshall the output data.
2782 if (infoLevel == 0x101) {
2783 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
2784 *((FILETIME *)op) = ft; op += 8; /* creation time */
2785 *((FILETIME *)op) = ft; op += 8; /* last access time */
2786 *((FILETIME *)op) = ft; op += 8; /* last write time */
2787 *((FILETIME *)op) = ft; op += 8; /* last change time */
2788 attributes = smb_ExtAttributes(scp);
2789 *((u_long *)op) = attributes; op += 4;
2790 *((u_long *)op) = 0; op += 4;
2792 else if (infoLevel == 0x102) {
2793 *((LARGE_INTEGER *)op) = scp->length; op += 8; /* alloc size */
2794 *((LARGE_INTEGER *)op) = scp->length; op += 8; /* EOF */
2795 *((u_long *)op) = scp->linkCount; op += 4;
2796 *op++ = ((fidp->flags & SMB_FID_DELONCLOSE) ? 1 : 0);
2797 *op++ = (scp->fileType == CM_SCACHETYPE_DIRECTORY ? 1 : 0);
2801 else if (infoLevel == 0x103) {
2802 *((u_long *)op) = 0; op += 4;
2804 else if (infoLevel == 0x104) {
2808 if (fidp->NTopen_wholepathp)
2809 name = fidp->NTopen_wholepathp;
2811 name = "\\"; /* probably can't happen */
2813 outp->totalData = (len*2) + 4; /* this is actually what we want to return */
2814 *((u_long *)op) = len * 2; op += 4;
2815 mbstowcs((unsigned short *)op, name, len); op += (len * 2);
2818 /* send and free the packets */
2820 lock_ReleaseMutex(&scp->mx);
2821 cm_ReleaseUser(userp);
2822 smb_ReleaseFID(fidp);
2824 smb_SendTran2Packet(vcp, outp, opx);
2826 smb_SendTran2Error(vcp, p, opx, code);
2827 smb_FreeTran2Packet(outp);
2832 long smb_ReceiveTran2SetFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
2837 unsigned short infoLevel;
2838 smb_tran2Packet_t *outp;
2846 fidp = smb_FindFID(vcp, fid, 0);
2849 smb_SendTran2Error(vcp, p, op, CM_ERROR_BADFD);
2853 infoLevel = p->parmsp[1];
2854 osi_Log2(smb_logp,"ReceiveTran2SetFileInfo type=[%x] fid=[%x]", infoLevel, fid);
2855 if (infoLevel > 0x104 || infoLevel < 0x101) {
2856 osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
2857 p->opcode, infoLevel);
2858 smb_SendTran2Error(vcp, p, op, CM_ERROR_INVAL);
2859 smb_ReleaseFID(fidp);
2863 if (infoLevel == 0x102 && !(fidp->flags & SMB_FID_OPENDELETE)) {
2864 smb_SendTran2Error(vcp, p, op, CM_ERROR_NOACCESS);
2865 smb_ReleaseFID(fidp);
2868 if ((infoLevel == 0x103 || infoLevel == 0x104)
2869 && !(fidp->flags & SMB_FID_OPENWRITE)) {
2870 smb_SendTran2Error(vcp, p, op, CM_ERROR_NOACCESS);
2871 smb_ReleaseFID(fidp);
2875 osi_Log1(smb_logp, "T2 SFileInfo type 0x%x", infoLevel);
2877 outp = smb_GetTran2ResponsePacket(vcp, p, op, 2, 0);
2879 outp->totalParms = 2;
2880 outp->totalData = 0;
2882 userp = smb_GetTran2User(vcp, p);
2884 osi_Log1(smb_logp,"ReceiveTran2SetFileInfo unable to resolve user [%d]", p->uid);
2885 code = CM_ERROR_BADSMB;
2891 if (infoLevel == 0x101) {
2893 unsigned int attribute;
2896 /* lock the vnode with a callback; we need the current status
2897 * to determine what the new status is, in some cases.
2899 lock_ObtainMutex(&scp->mx);
2900 code = cm_SyncOp(scp, NULL, userp, &req, 0,
2901 CM_SCACHESYNC_GETSTATUS
2902 | CM_SCACHESYNC_NEEDCALLBACK);
2904 lock_ReleaseMutex(&scp->mx);
2908 /* prepare for setattr call */
2911 lastMod = *((FILETIME *)(p->datap + 16));
2912 /* when called as result of move a b, lastMod is (-1, -1).
2913 * If the check for -1 is not present, timestamp
2914 * of the resulting file will be 1969 (-1)
2916 if (LargeIntegerNotEqualToZero(*((LARGE_INTEGER *)&lastMod)) &&
2917 lastMod.dwLowDateTime != -1 && lastMod.dwHighDateTime != -1) {
2918 attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
2919 smb_UnixTimeFromLargeSearchTime(&attr.clientModTime,
2921 fidp->flags |= SMB_FID_MTIMESETDONE;
2924 attribute = *((u_long *)(p->datap + 32));
2925 if (attribute != 0) {
2926 if ((scp->unixModeBits & 0222)
2927 && (attribute & 1) != 0) {
2928 /* make a writable file read-only */
2929 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
2930 attr.unixModeBits = scp->unixModeBits & ~0222;
2932 else if ((scp->unixModeBits & 0222) == 0
2933 && (attribute & 1) == 0) {
2934 /* make a read-only file writable */
2935 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
2936 attr.unixModeBits = scp->unixModeBits | 0222;
2939 lock_ReleaseMutex(&scp->mx);
2943 code = cm_SetAttr(scp, &attr, userp, &req);
2947 else if (infoLevel == 0x103 || infoLevel == 0x104) {
2948 LARGE_INTEGER size = *((LARGE_INTEGER *)(p->datap));
2951 attr.mask = CM_ATTRMASK_LENGTH;
2952 attr.length.LowPart = size.LowPart;
2953 attr.length.HighPart = size.HighPart;
2954 code = cm_SetAttr(scp, &attr, userp, &req);
2956 else if (infoLevel == 0x102) {
2957 if (*((char *)(p->datap))) {
2958 code = cm_CheckNTDelete(fidp->NTopen_dscp, scp, userp,
2961 fidp->flags |= SMB_FID_DELONCLOSE;
2965 fidp->flags &= ~SMB_FID_DELONCLOSE;
2970 cm_ReleaseUser(userp);
2971 smb_ReleaseFID(fidp);
2973 smb_SendTran2Packet(vcp, outp, op);
2975 smb_SendTran2Error(vcp, p, op, code);
2976 smb_FreeTran2Packet(outp);
2982 smb_ReceiveTran2FSCTL(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
2984 osi_Log0(smb_logp,"ReceiveTran2FSCTL - NOT_SUPPORTED");
2985 return CM_ERROR_BADOP;
2989 smb_ReceiveTran2IOCTL(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
2991 osi_Log0(smb_logp,"ReceiveTran2IOCTL - NOT_SUPPORTED");
2992 return CM_ERROR_BADOP;
2996 smb_ReceiveTran2FindNotifyFirst(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
2998 osi_Log0(smb_logp,"ReceiveTran2FindNotifyFirst - NOT_SUPPORTED");
2999 return CM_ERROR_BADOP;
3003 smb_ReceiveTran2FindNotifyNext(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3005 osi_Log0(smb_logp,"ReceiveTran2FindNotifyNext - NOT_SUPPORTED");
3006 return CM_ERROR_BADOP;
3010 smb_ReceiveTran2CreateDirectory(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3012 osi_Log0(smb_logp,"ReceiveTran2CreateDirectory - NOT_SUPPORTED");
3013 return CM_ERROR_BADOP;
3017 smb_ReceiveTran2SessionSetup(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3019 osi_Log0(smb_logp,"ReceiveTran2SessionSetup - NOT_SUPPORTED");
3020 return CM_ERROR_BADOP;
3024 smb_ReceiveTran2GetDFSReferral(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3026 osi_Log0(smb_logp,"ReceiveTran2GetDFSReferral - NOT_SUPPORTED");
3027 return CM_ERROR_BADOP;
3031 smb_ReceiveTran2ReportDFSInconsistency(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3033 osi_Log0(smb_logp,"ReceiveTran2ReportDFSInconsistency - NOT_SUPPORTED");
3034 return CM_ERROR_BADOP;
3038 smb_ApplyV3DirListPatches(cm_scache_t *dscp,
3039 smb_dirListPatch_t **dirPatchespp, int infoLevel, cm_user_t *userp,
3044 cm_scache_t *targetScp; /* target if scp is a symlink */
3049 unsigned short attr;
3050 unsigned long lattr;
3051 smb_dirListPatch_t *patchp;
3052 smb_dirListPatch_t *npatchp;
3054 for(patchp = *dirPatchespp; patchp; patchp =
3055 (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
3056 code = cm_GetSCache(&patchp->fid, &scp, userp, reqp);
3058 lock_ObtainMutex(&scp->mx);
3059 code = cm_SyncOp(scp, NULL, userp, reqp, 0,
3060 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3062 lock_ReleaseMutex(&scp->mx);
3063 cm_ReleaseSCache(scp);
3065 dptr = patchp->dptr;
3067 /* Plug in fake timestamps. A time stamp of 0 causes 'invalid parameter'
3068 errors in the client. */
3069 if (infoLevel >= 0x101) {
3070 /* 1969-12-31 23:59:59 +00 */
3071 ft.dwHighDateTime = 0x19DB200;
3072 ft.dwLowDateTime = 0x5BB78980;
3074 /* copy to Creation Time */
3075 *((FILETIME *)dptr) = ft;
3078 /* copy to Last Access Time */
3079 *((FILETIME *)dptr) = ft;
3082 /* copy to Last Write Time */
3083 *((FILETIME *)dptr) = ft;
3086 /* copy to Change Time */
3087 *((FILETIME *)dptr) = ft;
3090 /* merge in hidden attribute */
3091 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
3092 *((u_long *)dptr) = SMB_ATTR_HIDDEN;
3096 /* 1969-12-31 23:59:58 +00*/
3097 dosTime = 0xEBBFBF7D;
3099 /* and copy out date */
3100 shortTemp = (dosTime>>16) & 0xffff;
3101 *((u_short *)dptr) = shortTemp;
3104 /* copy out creation time */
3105 shortTemp = dosTime & 0xffff;
3106 *((u_short *)dptr) = shortTemp;
3109 /* and copy out date */
3110 shortTemp = (dosTime>>16) & 0xffff;
3111 *((u_short *)dptr) = shortTemp;
3114 /* copy out access time */
3115 shortTemp = dosTime & 0xffff;
3116 *((u_short *)dptr) = shortTemp;
3119 /* and copy out date */
3120 shortTemp = (dosTime>>16) & 0xffff;
3121 *((u_short *)dptr) = shortTemp;
3124 /* copy out mod time */
3125 shortTemp = dosTime & 0xffff;
3126 *((u_short *)dptr) = shortTemp;
3129 /* merge in hidden (dot file) attribute */
3130 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
3131 attr = SMB_ATTR_HIDDEN;
3132 *dptr++ = attr & 0xff;
3133 *dptr++ = (attr >> 8) & 0xff;
3139 /* now watch for a symlink */
3141 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
3142 lock_ReleaseMutex(&scp->mx);
3143 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, reqp);
3145 /* we have a more accurate file to use (the
3146 * target of the symbolic link). Otherwise,
3147 * we'll just use the symlink anyway.
3149 osi_Log2(smb_logp, "symlink vp %x to vp %x",
3151 cm_ReleaseSCache(scp);
3154 lock_ObtainMutex(&scp->mx);
3157 dptr = patchp->dptr;
3159 if (infoLevel >= 0x101) {
3161 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
3163 /* copy to Creation Time */
3164 *((FILETIME *)dptr) = ft;
3167 /* copy to Last Access Time */
3168 *((FILETIME *)dptr) = ft;
3171 /* copy to Last Write Time */
3172 *((FILETIME *)dptr) = ft;
3175 /* copy to Change Time */
3176 *((FILETIME *)dptr) = ft;
3179 /* Use length for both file length and alloc length */
3180 *((LARGE_INTEGER *)dptr) = scp->length;
3182 *((LARGE_INTEGER *)dptr) = scp->length;
3185 /* Copy attributes */
3186 lattr = smb_ExtAttributes(scp);
3187 /* merge in hidden (dot file) attribute */
3188 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE )
3189 lattr |= SMB_ATTR_HIDDEN;
3190 *((u_long *)dptr) = lattr;
3195 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
3197 /* and copy out date */
3198 shortTemp = (dosTime>>16) & 0xffff;
3199 *((u_short *)dptr) = shortTemp;
3202 /* copy out creation time */
3203 shortTemp = dosTime & 0xffff;
3204 *((u_short *)dptr) = shortTemp;
3207 /* and copy out date */
3208 shortTemp = (dosTime>>16) & 0xffff;
3209 *((u_short *)dptr) = shortTemp;
3212 /* copy out access time */
3213 shortTemp = dosTime & 0xffff;
3214 *((u_short *)dptr) = shortTemp;
3217 /* and copy out date */
3218 shortTemp = (dosTime>>16) & 0xffff;
3219 *((u_short *)dptr) = shortTemp;
3222 /* copy out mod time */
3223 shortTemp = dosTime & 0xffff;
3224 *((u_short *)dptr) = shortTemp;
3227 /* copy out file length and alloc length,
3228 * using the same for both
3230 *((u_long *)dptr) = scp->length.LowPart;
3232 *((u_long *)dptr) = scp->length.LowPart;
3235 /* finally copy out attributes as short */
3236 attr = smb_Attributes(scp);
3237 /* merge in hidden (dot file) attribute */
3238 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE )
3239 attr |= SMB_ATTR_HIDDEN;
3240 *dptr++ = attr & 0xff;
3241 *dptr++ = (attr >> 8) & 0xff;
3244 lock_ReleaseMutex(&scp->mx);
3245 cm_ReleaseSCache(scp);
3248 /* now free the patches */
3249 for (patchp = *dirPatchespp; patchp; patchp = npatchp) {
3250 npatchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q);
3254 /* and mark the list as empty */
3255 *dirPatchespp = NULL;
3260 #ifndef USE_OLD_MATCHING
3261 // char table for case insensitive comparison
3262 char mapCaseTable[256];
3264 VOID initUpperCaseTable(VOID)
3267 for (i = 0; i < 256; ++i)
3268 mapCaseTable[i] = toupper(i);
3269 // make '"' match '.'
3270 mapCaseTable[(int)'"'] = toupper('.');
3271 // make '<' match '*'
3272 mapCaseTable[(int)'<'] = toupper('*');
3273 // make '>' match '?'
3274 mapCaseTable[(int)'>'] = toupper('?');
3277 // Compare 'pattern' (containing metacharacters '*' and '?') with the file
3279 // Note : this procedure works recursively calling itself.
3281 // PSZ pattern : string containing metacharacters.
3282 // PSZ name : file name to be compared with 'pattern'.
3284 // BOOL : TRUE/FALSE (match/mistmatch)
3287 szWildCardMatchFileName(PSZ pattern, PSZ name)
3289 PSZ pename; // points to the last 'name' character
3291 pename = name + strlen(name) - 1;
3301 if (*pattern == '\0')
3303 for (p = pename; p >= name; --p) {
3304 if ((mapCaseTable[*p] == mapCaseTable[*pattern]) &&
3305 szWildCardMatchFileName(pattern + 1, p + 1))
3310 if (mapCaseTable[*name] != mapCaseTable[*pattern])
3317 if (*pattern == '\0' || *pattern == '*' && *(pattern+1) == '\0')
3323 /* do a case-folding search of the star name mask with the name in namep.
3324 * Return 1 if we match, otherwise 0.
3326 int smb_V3MatchMask(char *namep, char *maskp, int flags)
3329 int i, j, star, qmark, retval;
3331 /* make sure we only match 8.3 names, if requested */
3332 if ((flags & CM_FLAG_8DOT3) && !cm_Is8Dot3(namep))
3335 /* optimize the pattern:
3336 * if there is a mixture of '?' and '*',
3337 * for example the sequence "*?*?*?*"
3338 * must be turned into the form "*"
3340 newmask = (char *)malloc(strlen(maskp)+1);
3341 for ( i=0, j=0, star=0, qmark=0; maskp[i]; i++) {
3342 switch ( maskp[i] ) {
3354 } else if ( qmark ) {
3358 newmask[j++] = maskp[i];
3365 } else if ( qmark ) {
3369 newmask[j++] = '\0';
3371 retval = szWildCardMatchFileName(newmask, namep) ? 1:0;
3377 #else /* USE_OLD_MATCHING */
3378 /* do a case-folding search of the star name mask with the name in namep.
3379 * Return 1 if we match, otherwise 0.
3381 int smb_V3MatchMask(char *namep, char *maskp, int flags)
3383 unsigned char tcp1, tcp2; /* Pattern characters */
3384 unsigned char tcn1; /* Name characters */
3385 int sawDot = 0, sawStar = 0, req8dot3 = 0;
3386 char *starNamep, *starMaskp;
3387 static char nullCharp[] = {0};
3388 int casefold = flags & CM_FLAG_CASEFOLD;
3390 /* make sure we only match 8.3 names, if requested */
3391 req8dot3 = (flags & CM_FLAG_8DOT3);
3392 if (req8dot3 && !cm_Is8Dot3(namep))
3397 /* Next pattern character */
3400 /* Next name character */
3404 /* 0 - end of pattern */
3410 else if (tcp1 == '.' || tcp1 == '"') {
3420 * first dot in pattern;
3421 * must match dot or end of name
3426 else if (tcn1 == '.') {
3435 else if (tcp1 == '?') {
3436 if (tcn1 == 0 || tcn1 == '.')
3441 else if (tcp1 == '>') {
3442 if (tcn1 != 0 && tcn1 != '.')
3446 else if (tcp1 == '*' || tcp1 == '<') {
3450 else if ((req8dot3 && tcp2 == '.') || tcp2 == '"') {
3451 while (req8dot3 && tcn1 != '.' && tcn1 != 0)
3466 * pattern character after '*' is not null or
3467 * period. If it is '?' or '>', we are not
3468 * going to understand it. If it is '*' or
3469 * '<', we are going to skip over it. None of
3470 * these are likely, I hope.
3472 /* skip over '*' and '<' */
3473 while (tcp2 == '*' || tcp2 == '<')
3476 /* skip over characters that don't match tcp2 */
3477 while (req8dot3 && tcn1 != '.' && tcn1 != 0 &&
3478 ((casefold && cm_foldUpper[tcn1] != cm_foldUpper[tcp2]) ||
3479 (!casefold && tcn1 != tcp2)))
3483 if ((req8dot3 && tcn1 == '.') || tcn1 == 0)
3486 /* Remember where we are */
3496 /* tcp1 is not a wildcard */
3497 if ((casefold && cm_foldUpper[tcn1] == cm_foldUpper[tcp1]) ||
3498 (!casefold && tcn1 == tcp1)) {
3503 /* if trying to match a star pattern, go back */
3505 maskp = starMaskp - 2;
3506 namep = starNamep + 1;
3515 #endif /* USE_OLD_MATCHING */
3517 long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
3526 smb_dirListPatch_t *dirListPatchesp;
3527 smb_dirListPatch_t *curPatchp;
3530 long orbytes; /* # of bytes in this output record */
3531 long ohbytes; /* # of bytes, except file name */
3532 long onbytes; /* # of bytes in name, incl. term. null */
3533 osi_hyper_t dirLength;
3534 osi_hyper_t bufferOffset;
3535 osi_hyper_t curOffset;
3537 smb_dirSearch_t *dsp;
3541 cm_pageHeader_t *pageHeaderp;
3542 cm_user_t *userp = NULL;
3545 long nextEntryCookie;
3546 int numDirChunks; /* # of 32 byte dir chunks in this entry */
3547 char *op; /* output data ptr */
3548 char *origOp; /* original value of op */
3549 cm_space_t *spacep; /* for pathname buffer */
3550 long maxReturnData; /* max # of return data */
3551 long maxReturnParms; /* max # of return parms */
3552 long bytesInBuffer; /* # data bytes in the output buffer */
3554 char *maskp; /* mask part of path */
3558 smb_tran2Packet_t *outp; /* response packet */
3561 char shortName[13]; /* 8.3 name if needed */
3572 if (p->opcode == 1) {
3573 /* find first; obtain basic parameters from request */
3574 attribute = p->parmsp[0];
3575 maxCount = p->parmsp[1];
3576 infoLevel = p->parmsp[3];
3577 searchFlags = p->parmsp[2];
3578 dsp = smb_NewDirSearch(1);
3579 dsp->attribute = attribute;
3580 pathp = ((char *) p->parmsp) + 12; /* points to path */
3582 maskp = strrchr(pathp, '\\');
3586 maskp++; /* skip over backslash */
3587 strcpy(dsp->mask, maskp); /* and save mask */
3588 /* track if this is likely to match a lot of entries */
3589 starPattern = smb_V3IsStarMask(maskp);
3592 osi_assert(p->opcode == 2);
3593 /* find next; obtain basic parameters from request or open dir file */
3594 dsp = smb_FindDirSearch(p->parmsp[0]);
3596 return CM_ERROR_BADFD;
3597 attribute = dsp->attribute;
3598 maxCount = p->parmsp[1];
3599 infoLevel = p->parmsp[2];
3600 searchFlags = p->parmsp[5];
3602 nextCookie = p->parmsp[3] | (p->parmsp[4] << 16);
3604 starPattern = 1; /* assume, since required a Find Next */
3608 "T2 search dir attr 0x%x, info level %d, max count %d, flags 0x%x",
3609 attribute, infoLevel, maxCount, searchFlags);
3611 osi_Log2(smb_logp, "...T2 search op %d, nextCookie 0x%x",
3612 p->opcode, nextCookie);
3614 if (infoLevel >= 0x101)
3615 searchFlags &= ~4; /* no resume keys */
3617 dirListPatchesp = NULL;
3619 maxReturnData = p->maxReturnData;
3620 if (p->opcode == 1) /* find first */
3621 maxReturnParms = 10; /* bytes */
3623 maxReturnParms = 8; /* bytes */
3625 #ifndef CM_CONFIG_MULTITRAN2RESPONSES
3626 if (maxReturnData > 6000)
3627 maxReturnData = 6000;
3628 #endif /* CM_CONFIG_MULTITRAN2RESPONSES */
3630 outp = smb_GetTran2ResponsePacket(vcp, p, opx, maxReturnParms,
3633 osi_Log1(smb_logp, "T2 receive search dir %s",
3634 osi_LogSaveString(smb_logp, pathp));
3636 /* bail out if request looks bad */
3637 if (p->opcode == 1 && !pathp) {
3638 smb_ReleaseDirSearch(dsp);
3639 smb_FreeTran2Packet(outp);
3640 return CM_ERROR_BADSMB;
3643 osi_Log2(smb_logp, "T2 dir search cookie 0x%x, connection %d",
3644 nextCookie, dsp->cookie);
3646 userp = smb_GetTran2User(vcp, p);
3648 osi_Log1(smb_logp, "T2 dir search unable to resolve user [%d]", p->uid);
3649 smb_ReleaseDirSearch(dsp);
3650 smb_FreeTran2Packet(outp);
3651 return CM_ERROR_BADSMB;
3654 /* try to get the vnode for the path name next */
3655 lock_ObtainMutex(&dsp->mx);
3662 spacep = cm_GetSpace();
3663 smb_StripLastComponent(spacep->data, NULL, pathp);
3664 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
3666 lock_ReleaseMutex(&dsp->mx);
3667 cm_ReleaseUser(userp);
3668 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOFILES);
3669 smb_FreeTran2Packet(outp);
3670 smb_DeleteDirSearch(dsp);
3671 smb_ReleaseDirSearch(dsp);
3674 code = cm_NameI(cm_rootSCachep, spacep->data,
3675 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
3676 userp, tidPathp, &req, &scp);
3677 cm_FreeSpace(spacep);
3681 cm_ReleaseSCache(dsp->scp);
3683 /* we need one hold for the entry we just stored into,
3684 * and one for our own processing. When we're done
3685 * with this function, we'll drop the one for our own
3686 * processing. We held it once from the namei call,
3687 * and so we do another hold now.
3690 lock_ObtainMutex(&scp->mx);
3691 if ((scp->flags & CM_SCACHEFLAG_BULKSTATTING) == 0 &&
3692 LargeIntegerGreaterOrEqualToZero(scp->bulkStatProgress)) {
3693 scp->flags |= CM_SCACHEFLAG_BULKSTATTING;
3694 dsp->flags |= SMB_DIRSEARCH_BULKST;
3696 lock_ReleaseMutex(&scp->mx);
3699 lock_ReleaseMutex(&dsp->mx);
3701 cm_ReleaseUser(userp);
3702 smb_FreeTran2Packet(outp);
3703 smb_DeleteDirSearch(dsp);
3704 smb_ReleaseDirSearch(dsp);
3708 /* get the directory size */
3709 lock_ObtainMutex(&scp->mx);
3710 code = cm_SyncOp(scp, NULL, userp, &req, 0,
3711 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3713 lock_ReleaseMutex(&scp->mx);
3714 cm_ReleaseSCache(scp);
3715 cm_ReleaseUser(userp);
3716 smb_FreeTran2Packet(outp);
3717 smb_DeleteDirSearch(dsp);
3718 smb_ReleaseDirSearch(dsp);
3723 dirLength = scp->length;
3725 bufferOffset.LowPart = bufferOffset.HighPart = 0;
3726 curOffset.HighPart = 0;
3727 curOffset.LowPart = nextCookie;
3728 origOp = outp->datap;
3736 if (searchFlags & 4)
3737 /* skip over resume key */
3740 /* make sure that curOffset.LowPart doesn't point to the first
3741 * 32 bytes in the 2nd through last dir page, and that it doesn't
3742 * point at the first 13 32-byte chunks in the first dir page,
3743 * since those are dir and page headers, and don't contain useful
3746 temp = curOffset.LowPart & (2048-1);
3747 if (curOffset.HighPart == 0 && curOffset.LowPart < 2048) {
3748 /* we're in the first page */
3749 if (temp < 13*32) temp = 13*32;
3752 /* we're in a later dir page */
3753 if (temp < 32) temp = 32;
3756 /* make sure the low order 5 bits are zero */
3759 /* now put temp bits back ito curOffset.LowPart */
3760 curOffset.LowPart &= ~(2048-1);
3761 curOffset.LowPart |= temp;
3763 /* check if we've passed the dir's EOF */
3764 if (LargeIntegerGreaterThanOrEqualTo(curOffset, dirLength)) {
3769 /* check if we've returned all the names that will fit in the
3770 * response packet; we check return count as well as the number
3771 * of bytes requested. We check the # of bytes after we find
3772 * the dir entry, since we'll need to check its size.
3774 if (returnedNames >= maxCount) {
3778 /* see if we can use the bufferp we have now; compute in which
3779 * page the current offset would be, and check whether that's
3780 * the offset of the buffer we have. If not, get the buffer.
3782 thyper.HighPart = curOffset.HighPart;
3783 thyper.LowPart = curOffset.LowPart & ~(buf_bufferSize-1);
3784 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
3787 buf_Release(bufferp);
3790 lock_ReleaseMutex(&scp->mx);
3791 lock_ObtainRead(&scp->bufCreateLock);
3792 code = buf_Get(scp, &thyper, &bufferp);
3793 lock_ReleaseRead(&scp->bufCreateLock);
3794 lock_ObtainMutex(&dsp->mx);
3796 /* now, if we're doing a star match, do bulk fetching
3797 * of all of the status info for files in the dir.
3800 smb_ApplyV3DirListPatches(scp, &dirListPatchesp,
3803 lock_ObtainMutex(&scp->mx);
3804 if ((dsp->flags & SMB_DIRSEARCH_BULKST) &&
3805 LargeIntegerGreaterThanOrEqualTo(thyper, scp->bulkStatProgress)) {
3806 /* Don't bulk stat if risking timeout */
3807 int now = GetCurrentTime();
3808 if (now - req.startTime > 5000) {
3809 scp->bulkStatProgress = thyper;
3810 scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
3811 dsp->flags &= ~SMB_DIRSEARCH_BULKST;
3813 cm_TryBulkStat(scp, &thyper, userp, &req);
3816 lock_ObtainMutex(&scp->mx);
3818 lock_ReleaseMutex(&dsp->mx);
3822 bufferOffset = thyper;
3824 /* now get the data in the cache */
3826 code = cm_SyncOp(scp, bufferp, userp, &req,
3828 CM_SCACHESYNC_NEEDCALLBACK
3829 | CM_SCACHESYNC_READ);
3832 if (cm_HaveBuffer(scp, bufferp, 0)) break;
3834 /* otherwise, load the buffer and try again */
3835 code = cm_GetBuffer(scp, bufferp, NULL, userp,
3840 buf_Release(bufferp);
3844 } /* if (wrong buffer) ... */
3846 /* now we have the buffer containing the entry we're interested
3847 * in; copy it out if it represents a non-deleted entry.
3849 entryInDir = curOffset.LowPart & (2048-1);
3850 entryInBuffer = curOffset.LowPart & (buf_bufferSize - 1);
3852 /* page header will help tell us which entries are free. Page
3853 * header can change more often than once per buffer, since
3854 * AFS 3 dir page size may be less than (but not more than)
3855 * a buffer package buffer.
3857 /* only look intra-buffer */
3858 temp = curOffset.LowPart & (buf_bufferSize - 1);
3859 temp &= ~(2048 - 1); /* turn off intra-page bits */
3860 pageHeaderp = (cm_pageHeader_t *) (bufferp->datap + temp);
3862 /* now determine which entry we're looking at in the page.
3863 * If it is free (there's a free bitmap at the start of the
3864 * dir), we should skip these 32 bytes.
3866 slotInPage = (entryInDir & 0x7e0) >> 5;
3867 if (!(pageHeaderp->freeBitmap[slotInPage>>3] &
3868 (1 << (slotInPage & 0x7)))) {
3869 /* this entry is free */
3870 numDirChunks = 1; /* only skip this guy */
3874 tp = bufferp->datap + entryInBuffer;
3875 dep = (cm_dirEntry_t *) tp; /* now points to AFS3 dir entry */
3877 /* while we're here, compute the next entry's location, too,
3878 * since we'll need it when writing out the cookie into the dir
3881 * XXXX Probably should do more sanity checking.
3883 numDirChunks = cm_NameEntries(dep->name, &onbytes);
3885 /* compute offset of cookie representing next entry */
3886 nextEntryCookie = curOffset.LowPart + (CM_DIR_CHUNKSIZE * numDirChunks);
3888 /* Need 8.3 name? */
3890 if (infoLevel == 0x104
3891 && dep->fid.vnode != 0
3892 && !cm_Is8Dot3(dep->name)) {
3893 cm_Gen8Dot3Name(dep, shortName, &shortNameEnd);
3897 /* When matching, we are using doing a case fold if we have a wildcard mask.
3898 * If we get a non-wildcard match, it's a lookup for a specific file.
3900 if (dep->fid.vnode != 0 &&
3901 (smb_V3MatchMask(dep->name, maskp, (starPattern? CM_FLAG_CASEFOLD : 0)) ||
3903 smb_V3MatchMask(shortName, maskp, CM_FLAG_CASEFOLD)))) {
3905 /* Eliminate entries that don't match requested attributes */
3906 if (smb_hideDotFiles && !(dsp->attribute & SMB_ATTR_HIDDEN) &&
3907 smb_IsDotFile(dep->name))
3908 goto nextEntry; /* no hidden files */
3910 if (!(dsp->attribute & SMB_ATTR_DIRECTORY)) /* no directories */
3912 /* We have already done the cm_TryBulkStat above */
3913 fid.cell = scp->fid.cell;
3914 fid.volume = scp->fid.volume;
3915 fid.vnode = ntohl(dep->fid.vnode);
3916 fid.unique = ntohl(dep->fid.unique);
3917 fileType = cm_FindFileType(&fid);
3918 /*osi_Log2(smb_logp, "smb_ReceiveTran2SearchDir: file %s "
3919 "has filetype %d", dep->name,
3921 if (fileType == CM_SCACHETYPE_DIRECTORY)
3925 /* finally check if this name will fit */
3927 /* standard dir entry stuff */
3928 if (infoLevel < 0x101)
3929 ohbytes = 23; /* pre-NT */
3930 else if (infoLevel == 0x103)
3931 ohbytes = 12; /* NT names only */
3933 ohbytes = 64; /* NT */
3935 if (infoLevel == 0x104)
3936 ohbytes += 26; /* Short name & length */
3938 if (searchFlags & 4) {
3939 ohbytes += 4; /* if resume key required */
3943 && infoLevel != 0x101
3944 && infoLevel != 0x103)
3945 ohbytes += 4; /* EASIZE */
3947 /* add header to name & term. null */
3948 orbytes = onbytes + ohbytes + 1;
3950 /* now, we round up the record to a 4 byte alignment,
3951 * and we make sure that we have enough room here for
3952 * even the aligned version (so we don't have to worry
3953 * about an * overflow when we pad things out below).
3954 * That's the reason for the alignment arithmetic below.
3956 if (infoLevel >= 0x101)
3957 align = (4 - (orbytes & 3)) & 3;
3960 if (orbytes + bytesInBuffer + align > maxReturnData)
3963 /* this is one of the entries to use: it is not deleted
3964 * and it matches the star pattern we're looking for.
3965 * Put out the name, preceded by its length.
3967 /* First zero everything else */
3968 memset(origOp, 0, ohbytes);
3970 if (infoLevel <= 0x101)
3971 *(origOp + ohbytes - 1) = (unsigned char) onbytes;
3972 else if (infoLevel == 0x103)
3973 *((u_long *)(op + 8)) = onbytes;
3975 *((u_long *)(op + 60)) = onbytes;
3976 strcpy(origOp+ohbytes, dep->name);
3978 /* Short name if requested and needed */
3979 if (infoLevel == 0x104) {
3980 if (NeedShortName) {
3981 strcpy(op + 70, shortName);
3982 *(op + 68) = shortNameEnd - shortName;
3986 /* now, adjust the # of entries copied */
3989 /* NextEntryOffset and FileIndex */
3990 if (infoLevel >= 101) {
3991 int entryOffset = orbytes + align;
3992 *((u_long *)op) = entryOffset;
3993 *((u_long *)(op+4)) = nextEntryCookie;
3996 /* now we emit the attribute. This is tricky, since
3997 * we need to really stat the file to find out what
3998 * type of entry we've got. Right now, we're copying
3999 * out data from * a buffer, while holding the scp
4000 * locked, so it isn't really convenient to stat
4001 * something now. We'll put in a place holder
4002 * now, and make a second pass before returning this
4003 * to get the real attributes. So, we just skip the
4004 * data for now, and adjust it later. We allocate a
4005 * patch record to make it easy to find this point
4006 * later. The replay will happen at a time when it is
4007 * safe to unlock the directory.
4009 if (infoLevel != 0x103) {
4010 curPatchp = malloc(sizeof(*curPatchp));
4011 osi_QAdd((osi_queue_t **) &dirListPatchesp,
4013 curPatchp->dptr = op;
4014 if (infoLevel >= 0x101)
4015 curPatchp->dptr += 8;
4017 if (smb_hideDotFiles && smb_IsDotFile(dep->name)) {
4018 curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
4021 curPatchp->flags = 0;
4023 curPatchp->fid.cell = scp->fid.cell;
4024 curPatchp->fid.volume = scp->fid.volume;
4025 curPatchp->fid.vnode = ntohl(dep->fid.vnode);
4026 curPatchp->fid.unique = ntohl(dep->fid.unique);
4029 curPatchp->dep = dep;
4032 if (searchFlags & 4)
4033 /* put out resume key */
4034 *((u_long *)origOp) = nextEntryCookie;
4036 /* Adjust byte ptr and count */
4037 origOp += orbytes; /* skip entire record */
4038 bytesInBuffer += orbytes;
4040 /* and pad the record out */
4041 while (--align >= 0) {
4045 } /* if we're including this name */
4046 else if (!NeedShortName &&
4049 dep->fid.vnode != 0 &&
4050 smb_V3MatchMask(dep->name, maskp, CM_FLAG_CASEFOLD)) {
4051 /* We were looking for exact matches, but here's an inexact one*/
4056 /* and adjust curOffset to be where the new cookie is */
4057 thyper.HighPart = 0;
4058 thyper.LowPart = CM_DIR_CHUNKSIZE * numDirChunks;
4059 curOffset = LargeIntegerAdd(thyper, curOffset);
4060 } /* while copying data for dir listing */
4062 /* If we didn't get a star pattern, we did an exact match during the first pass.
4063 * If there were no exact matches found, we fail over to inexact matches by
4064 * marking the query as a star pattern (matches all case permutations), and
4065 * re-running the query.
4067 if (returnedNames == 0 && !starPattern && foundInexact) {
4068 osi_Log0(afsd_logp,"T2 Search: No exact matches. Re-running for inexact matches");
4073 /* release the mutex */
4074 lock_ReleaseMutex(&scp->mx);
4075 if (bufferp) buf_Release(bufferp);
4077 /* apply and free last set of patches; if not doing a star match, this
4078 * will be empty, but better safe (and freeing everything) than sorry.
4080 smb_ApplyV3DirListPatches(scp, &dirListPatchesp, infoLevel, userp,
4083 /* now put out the final parameters */
4084 if (returnedNames == 0) eos = 1;
4085 if (p->opcode == 1) {
4087 outp->parmsp[0] = (unsigned short) dsp->cookie;
4088 outp->parmsp[1] = returnedNames;
4089 outp->parmsp[2] = eos;
4090 outp->parmsp[3] = 0; /* nothing wrong with EAS */
4091 outp->parmsp[4] = 0;
4092 /* don't need last name to continue
4093 * search, cookie is enough. Normally,
4094 * this is the offset of the file name
4095 * of the last entry returned.
4097 outp->totalParms = 10; /* in bytes */
4101 outp->parmsp[0] = returnedNames;
4102 outp->parmsp[1] = eos;
4103 outp->parmsp[2] = 0; /* EAS error */
4104 outp->parmsp[3] = 0; /* last name, as above */
4105 outp->totalParms = 8; /* in bytes */
4108 /* return # of bytes in the buffer */
4109 outp->totalData = bytesInBuffer;
4111 osi_Log2(smb_logp, "T2 search dir done, %d names, code %d",
4112 returnedNames, code);
4114 /* Return error code if unsuccessful on first request */
4115 if (code == 0 && p->opcode == 1 && returnedNames == 0)
4116 code = CM_ERROR_NOSUCHFILE;
4118 /* if we're supposed to close the search after this request, or if
4119 * we're supposed to close the search if we're done, and we're done,
4120 * or if something went wrong, close the search.
4122 /* ((searchFlags & 1) || ((searchFlags & 2) && eos) */
4123 if ((searchFlags & 1) || (returnedNames == 0) ||
4124 ((searchFlags & 2) && eos) || code != 0)
4125 smb_DeleteDirSearch(dsp);
4127 smb_SendTran2Error(vcp, p, opx, code);
4129 smb_SendTran2Packet(vcp, outp, opx);
4131 smb_FreeTran2Packet(outp);
4132 smb_ReleaseDirSearch(dsp);
4133 cm_ReleaseSCache(scp);
4134 cm_ReleaseUser(userp);
4138 long smb_ReceiveV3FindClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4141 smb_dirSearch_t *dsp;
4143 dirHandle = smb_GetSMBParm(inp, 0);
4145 osi_Log1(smb_logp, "SMB3 find close handle %d", dirHandle);
4147 dsp = smb_FindDirSearch(dirHandle);
4150 return CM_ERROR_BADFD;
4152 /* otherwise, we have an FD to destroy */
4153 smb_DeleteDirSearch(dsp);
4154 smb_ReleaseDirSearch(dsp);
4156 /* and return results */
4157 smb_SetSMBDataLength(outp, 0);
4162 long smb_ReceiveV3FindNotifyClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4164 smb_SetSMBDataLength(outp, 0);
4168 long smb_ReceiveV3OpenX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4175 cm_scache_t *dscp; /* dir we're dealing with */
4176 cm_scache_t *scp; /* file we're creating */
4178 int initialModeBits;
4188 int parmSlot; /* which parm we're dealing with */
4196 extraInfo = (smb_GetSMBParm(inp, 2) & 1); /* return extra info */
4197 openFun = smb_GetSMBParm(inp, 8); /* open function */
4198 excl = ((openFun & 3) == 0);
4199 trunc = ((openFun & 3) == 2); /* truncate it */
4200 openMode = (smb_GetSMBParm(inp, 3) & 0x7);
4201 openAction = 0; /* tracks what we did */
4203 attributes = smb_GetSMBParm(inp, 5);
4204 dosTime = smb_GetSMBParm(inp, 6) | (smb_GetSMBParm(inp, 7) << 16);
4206 /* compute initial mode bits based on read-only flag in attributes */
4207 initialModeBits = 0666;
4208 if (attributes & 1) initialModeBits &= ~0222;
4210 pathp = smb_GetSMBData(inp, NULL);
4212 spacep = inp->spacep;
4213 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
4215 if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
4216 /* special case magic file name for receiving IOCTL requests
4217 * (since IOCTL calls themselves aren't getting through).
4220 osi_Log0(smb_logp, "IOCTL Open");
4223 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
4224 smb_SetupIoctlFid(fidp, spacep);
4226 /* set inp->fid so that later read calls in same msg can find fid */
4227 inp->fid = fidp->fid;
4229 /* copy out remainder of the parms */
4231 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
4233 smb_SetSMBParm(outp, parmSlot, /* attrs */ 0); parmSlot++;
4234 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* mod time */
4235 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
4236 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* len */
4237 smb_SetSMBParm(outp, parmSlot, 0x7fff); parmSlot++;
4238 smb_SetSMBParm(outp, parmSlot, openMode); parmSlot++;
4239 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* file type 0 ==> normal file or dir */
4240 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* IPC junk */
4242 /* and the final "always present" stuff */
4243 smb_SetSMBParm(outp, parmSlot, /* openAction found existing file */ 1); parmSlot++;
4244 /* next write out the "unique" ID */
4245 smb_SetSMBParm(outp, parmSlot, 0x1234); parmSlot++;
4246 smb_SetSMBParm(outp, parmSlot, 0x5678); parmSlot++;
4247 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
4248 smb_SetSMBDataLength(outp, 0);
4250 /* and clean up fid reference */
4251 smb_ReleaseFID(fidp);
4255 #ifdef DEBUG_VERBOSE
4257 char *hexp, *asciip;
4258 asciip = (lastNamep ? lastNamep : pathp );
4259 hexp = osi_HexifyString(asciip);
4260 DEBUG_EVENT2("AFS", "V3Open H[%s] A[%s]", hexp, asciip );
4264 userp = smb_GetUser(vcp, inp);
4267 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4269 cm_ReleaseUser(userp);
4270 return CM_ERROR_NOSUCHPATH;
4272 code = cm_NameI(cm_rootSCachep, pathp,
4273 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
4274 userp, tidPathp, &req, &scp);
4276 code = cm_NameI(cm_rootSCachep, spacep->data,
4277 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
4278 userp, tidPathp, &req, &dscp);
4281 cm_ReleaseUser(userp);
4285 /* otherwise, scp points to the parent directory. Do a lookup,
4286 * and truncate the file if we find it, otherwise we create the
4289 if (!lastNamep) lastNamep = pathp;
4291 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD, userp,
4293 if (code && code != CM_ERROR_NOSUCHFILE) {
4294 cm_ReleaseSCache(dscp);
4295 cm_ReleaseUser(userp);
4300 /* if we get here, if code is 0, the file exists and is represented by
4301 * scp. Otherwise, we have to create it. The dir may be represented
4302 * by dscp, or we may have found the file directly. If code is non-zero,
4306 code = cm_CheckOpen(scp, openMode, trunc, userp, &req);
4308 if (dscp) cm_ReleaseSCache(dscp);
4309 cm_ReleaseSCache(scp);
4310 cm_ReleaseUser(userp);
4315 /* oops, file shouldn't be there */
4316 if (dscp) cm_ReleaseSCache(dscp);
4317 cm_ReleaseSCache(scp);
4318 cm_ReleaseUser(userp);
4319 return CM_ERROR_EXISTS;
4323 setAttr.mask = CM_ATTRMASK_LENGTH;
4324 setAttr.length.LowPart = 0;
4325 setAttr.length.HighPart = 0;
4326 code = cm_SetAttr(scp, &setAttr, userp, &req);
4327 openAction = 3; /* truncated existing file */
4329 else openAction = 1; /* found existing file */
4331 else if (!(openFun & 0x10)) {
4332 /* don't create if not found */
4333 if (dscp) cm_ReleaseSCache(dscp);
4334 cm_ReleaseUser(userp);
4335 return CM_ERROR_NOSUCHFILE;
4338 osi_assert(dscp != NULL);
4339 osi_Log1(smb_logp, "smb_ReceiveV3OpenX creating file %s",
4340 osi_LogSaveString(smb_logp, lastNamep));
4341 openAction = 2; /* created file */
4342 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
4343 smb_UnixTimeFromDosUTime(&setAttr.clientModTime, dosTime);
4344 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
4346 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
4347 smb_NotifyChange(FILE_ACTION_ADDED,
4348 FILE_NOTIFY_CHANGE_FILE_NAME,
4349 dscp, lastNamep, NULL, TRUE);
4350 if (!excl && code == CM_ERROR_EXISTS) {
4351 /* not an exclusive create, and someone else tried
4352 * creating it already, then we open it anyway. We
4353 * don't bother retrying after this, since if this next
4354 * fails, that means that the file was deleted after we
4355 * started this call.
4357 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
4361 setAttr.mask = CM_ATTRMASK_LENGTH;
4362 setAttr.length.LowPart = 0;
4363 setAttr.length.HighPart = 0;
4364 code = cm_SetAttr(scp, &setAttr, userp, &req);
4366 } /* lookup succeeded */
4370 /* we don't need this any longer */
4371 if (dscp) cm_ReleaseSCache(dscp);
4374 /* something went wrong creating or truncating the file */
4375 if (scp) cm_ReleaseSCache(scp);
4376 cm_ReleaseUser(userp);
4380 /* make sure we're about to open a file */
4381 if (scp->fileType != CM_SCACHETYPE_FILE) {
4382 cm_ReleaseSCache(scp);
4383 cm_ReleaseUser(userp);
4384 return CM_ERROR_ISDIR;
4387 /* now all we have to do is open the file itself */
4388 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
4391 /* save a pointer to the vnode */
4394 /* compute open mode */
4395 if (openMode != 1) fidp->flags |= SMB_FID_OPENREAD;
4396 if (openMode == 1 || openMode == 2)
4397 fidp->flags |= SMB_FID_OPENWRITE;
4399 smb_ReleaseFID(fidp);
4401 cm_Open(scp, 0, userp);
4403 /* set inp->fid so that later read calls in same msg can find fid */
4404 inp->fid = fidp->fid;
4406 /* copy out remainder of the parms */
4408 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
4409 lock_ObtainMutex(&scp->mx);
4411 smb_SetSMBParm(outp, parmSlot, smb_Attributes(scp)); parmSlot++;
4412 smb_DosUTimeFromUnixTime(&dosTime, scp->clientModTime);
4413 smb_SetSMBParm(outp, parmSlot, dosTime & 0xffff); parmSlot++;
4414 smb_SetSMBParm(outp, parmSlot, (dosTime>>16) & 0xffff); parmSlot++;
4415 smb_SetSMBParm(outp, parmSlot, scp->length.LowPart & 0xffff); parmSlot++;
4416 smb_SetSMBParm(outp, parmSlot, (scp->length.LowPart >> 16) & 0xffff); parmSlot++;
4417 smb_SetSMBParm(outp, parmSlot, openMode); parmSlot++;
4418 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* file type 0 ==> normal file or dir */
4419 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* IPC junk */
4421 /* and the final "always present" stuff */
4422 smb_SetSMBParm(outp, parmSlot, openAction); parmSlot++;
4423 /* next write out the "unique" ID */
4424 smb_SetSMBParm(outp, parmSlot, scp->fid.vnode & 0xffff); parmSlot++;
4425 smb_SetSMBParm(outp, parmSlot, scp->fid.volume & 0xffff); parmSlot++;
4426 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
4427 lock_ReleaseMutex(&scp->mx);
4428 smb_SetSMBDataLength(outp, 0);
4430 osi_Log1(smb_logp, "SMB OpenX opening fid %d", fidp->fid);
4432 cm_ReleaseUser(userp);
4433 /* leave scp held since we put it in fidp->scp */
4437 long smb_ReceiveV3LockingX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4444 unsigned char LockType;
4445 unsigned short NumberOfUnlocks, NumberOfLocks;
4446 unsigned long Timeout;
4448 LARGE_INTEGER LOffset, LLength;
4449 smb_waitingLock_t *waitingLock;
4456 fid = smb_GetSMBParm(inp, 2);
4457 fid = smb_ChainFID(fid, inp);
4459 fidp = smb_FindFID(vcp, fid, 0);
4460 if (!fidp || (fidp->flags & SMB_FID_IOCTL)) {
4461 return CM_ERROR_BADFD;
4463 /* set inp->fid so that later read calls in same msg can find fid */
4466 userp = smb_GetUser(vcp, inp);
4470 lock_ObtainMutex(&scp->mx);
4471 code = cm_SyncOp(scp, NULL, userp, &req, 0,
4472 CM_SCACHESYNC_NEEDCALLBACK
4473 | CM_SCACHESYNC_GETSTATUS
4474 | CM_SCACHESYNC_LOCK);
4475 if (code) goto doneSync;
4477 LockType = smb_GetSMBParm(inp, 3) & 0xff;
4478 Timeout = (smb_GetSMBParm(inp, 5) << 16) + smb_GetSMBParm(inp, 4);
4479 NumberOfUnlocks = smb_GetSMBParm(inp, 6);
4480 NumberOfLocks = smb_GetSMBParm(inp, 7);
4482 op = smb_GetSMBData(inp, NULL);
4484 for (i=0; i<NumberOfUnlocks; i++) {
4485 if (LockType & 0x10) {
4487 LOffset.HighPart = *((LONG *)(op + 4));
4488 LOffset.LowPart = *((DWORD *)(op + 8));
4489 LLength.HighPart = *((LONG *)(op + 12));
4490 LLength.LowPart = *((DWORD *)(op + 16));
4494 /* Not Large Files */
4495 LOffset.HighPart = 0;
4496 LOffset.LowPart = *((DWORD *)(op + 2));
4497 LLength.HighPart = 0;
4498 LLength.LowPart = *((DWORD *)(op + 6));
4501 if (LargeIntegerNotEqualToZero(LOffset))
4503 /* Do not check length -- length check done in cm_Unlock */
4505 code = cm_Unlock(scp, LockType, LOffset, LLength, userp, &req);
4506 if (code) goto done;
4509 for (i=0; i<NumberOfLocks; i++) {
4510 if (LockType & 0x10) {
4512 LOffset.HighPart = *((LONG *)(op + 4));
4513 LOffset.LowPart = *((DWORD *)(op + 8));
4514 LLength.HighPart = *((LONG *)(op + 12));
4515 LLength.LowPart = *((DWORD *)(op + 16));
4519 /* Not Large Files */
4520 LOffset.HighPart = 0;
4521 LOffset.LowPart = *((DWORD *)(op + 2));
4522 LLength.HighPart = 0;
4523 LLength.LowPart = *((DWORD *)(op + 6));
4526 if (LargeIntegerNotEqualToZero(LOffset))
4528 if (LargeIntegerLessThan(LOffset, scp->length))
4531 code = cm_Lock(scp, LockType, LOffset, LLength, Timeout,
4532 userp, &req, &lockp);
4533 if (code == CM_ERROR_WOULDBLOCK && Timeout != 0) {
4534 /* Put on waiting list */
4535 waitingLock = malloc(sizeof(smb_waitingLock_t));
4536 waitingLock->vcp = vcp;
4537 waitingLock->inp = smb_CopyPacket(inp);
4538 waitingLock->outp = smb_CopyPacket(outp);
4539 waitingLock->timeRemaining = Timeout;
4540 waitingLock->lockp = lockp;
4541 lock_ObtainWrite(&smb_globalLock);
4542 osi_QAdd((osi_queue_t **)&smb_allWaitingLocks,
4544 osi_Wakeup((long) &smb_allWaitingLocks);
4545 lock_ReleaseWrite(&smb_globalLock);
4546 /* don't send reply immediately */
4547 outp->flags |= SMB_PACKETFLAG_NOSEND;
4553 /* release any locks acquired before the failure */
4556 smb_SetSMBDataLength(outp, 0);
4558 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_LOCK);
4560 lock_ReleaseMutex(&scp->mx);
4561 cm_ReleaseUser(userp);
4562 smb_ReleaseFID(fidp);
4567 long smb_ReceiveV3GetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4579 fid = smb_GetSMBParm(inp, 0);
4580 fid = smb_ChainFID(fid, inp);
4582 fidp = smb_FindFID(vcp, fid, 0);
4583 if (!fidp || (fidp->flags & SMB_FID_IOCTL)) {
4584 return CM_ERROR_BADFD;
4587 userp = smb_GetUser(vcp, inp);
4591 /* otherwise, stat the file */
4592 lock_ObtainMutex(&scp->mx);
4593 code = cm_SyncOp(scp, NULL, userp, &req, 0,
4594 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4595 if (code) goto done;
4597 /* decode times. We need a search time, but the response to this
4598 * call provides the date first, not the time, as returned in the
4599 * searchTime variable. So we take the high-order bits first.
4601 smb_SearchTimeFromUnixTime(&searchTime, scp->clientModTime);
4602 smb_SetSMBParm(outp, 0, (searchTime >> 16) & 0xffff); /* ctime */
4603 smb_SetSMBParm(outp, 1, searchTime & 0xffff);
4604 smb_SetSMBParm(outp, 2, (searchTime >> 16) & 0xffff); /* atime */
4605 smb_SetSMBParm(outp, 3, searchTime & 0xffff);
4606 smb_SetSMBParm(outp, 4, (searchTime >> 16) & 0xffff); /* mtime */
4607 smb_SetSMBParm(outp, 5, searchTime & 0xffff);
4609 /* now handle file size and allocation size */
4610 smb_SetSMBParm(outp, 6, scp->length.LowPart & 0xffff); /* file size */
4611 smb_SetSMBParm(outp, 7, (scp->length.LowPart >> 16) & 0xffff);
4612 smb_SetSMBParm(outp, 8, scp->length.LowPart & 0xffff); /* alloc size */
4613 smb_SetSMBParm(outp, 9, (scp->length.LowPart >> 16) & 0xffff);
4615 /* file attribute */
4616 smb_SetSMBParm(outp, 10, smb_Attributes(scp));
4618 /* and finalize stuff */
4619 smb_SetSMBDataLength(outp, 0);
4623 lock_ReleaseMutex(&scp->mx);
4624 cm_ReleaseUser(userp);
4625 smb_ReleaseFID(fidp);
4629 long smb_ReceiveV3SetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4643 fid = smb_GetSMBParm(inp, 0);
4644 fid = smb_ChainFID(fid, inp);
4646 fidp = smb_FindFID(vcp, fid, 0);
4647 if (!fidp || (fidp->flags & SMB_FID_IOCTL)) {
4648 return CM_ERROR_BADFD;
4651 userp = smb_GetUser(vcp, inp);
4655 /* now prepare to call cm_setattr. This message only sets various times,
4656 * and AFS only implements mtime, and we'll set the mtime if that's
4657 * requested. The others we'll ignore.
4659 searchTime = smb_GetSMBParm(inp, 5) | (smb_GetSMBParm(inp, 6) << 16);
4661 if (searchTime != 0) {
4662 smb_UnixTimeFromSearchTime(&unixTime, searchTime);
4664 if ( unixTime != -1 ) {
4665 attrs.mask = CM_ATTRMASK_CLIENTMODTIME;
4666 attrs.clientModTime = unixTime;
4667 code = cm_SetAttr(scp, &attrs, userp, &req);
4669 osi_Log1(smb_logp, "SMB receive V3SetAttributes [fid=%ld]", fid);
4671 osi_Log1(smb_logp, "**smb_UnixTimeFromSearchTime failed searchTime=%ld", searchTime);
4676 cm_ReleaseUser(userp);
4677 smb_ReleaseFID(fidp);
4682 long smb_ReceiveV3ReadX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4685 long count, finalCount;
4692 fd = smb_GetSMBParm(inp, 2);
4693 count = smb_GetSMBParm(inp, 5);
4694 offset.HighPart = 0; /* too bad */
4695 offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
4697 osi_Log3(smb_logp, "smb_ReceiveV3Read fd %d, off 0x%x, size 0x%x",
4698 fd, offset.LowPart, count);
4700 fd = smb_ChainFID(fd, inp);
4701 fidp = smb_FindFID(vcp, fd, 0);
4703 return CM_ERROR_BADFD;
4705 /* set inp->fid so that later read calls in same msg can find fid */
4708 if (fidp->flags & SMB_FID_IOCTL) {
4709 return smb_IoctlV3Read(fidp, vcp, inp, outp);
4712 userp = smb_GetUser(vcp, inp);
4714 /* 0 and 1 are reserved for request chaining, were setup by our caller,
4715 * and will be further filled in after we return.
4717 smb_SetSMBParm(outp, 2, 0); /* remaining bytes, for pipes */
4718 smb_SetSMBParm(outp, 3, 0); /* resvd */
4719 smb_SetSMBParm(outp, 4, 0); /* resvd */
4720 smb_SetSMBParm(outp, 5, count); /* # of bytes we're going to read */
4721 /* fill in #6 when we have all the parameters' space reserved */
4722 smb_SetSMBParm(outp, 7, 0); /* resv'd */
4723 smb_SetSMBParm(outp, 8, 0); /* resv'd */
4724 smb_SetSMBParm(outp, 9, 0); /* resv'd */
4725 smb_SetSMBParm(outp, 10, 0); /* resv'd */
4726 smb_SetSMBParm(outp, 11, 0); /* reserved */
4728 /* get op ptr after putting in the parms, since otherwise we don't
4729 * know where the data really is.
4731 op = smb_GetSMBData(outp, NULL);
4733 /* now fill in offset from start of SMB header to first data byte (to op) */
4734 smb_SetSMBParm(outp, 6, ((int) (op - outp->data)));
4736 /* set the packet data length the count of the # of bytes */
4737 smb_SetSMBDataLength(outp, count);
4740 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount);
4742 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount, FALSE);
4745 /* fix some things up */
4746 smb_SetSMBParm(outp, 5, finalCount);
4747 smb_SetSMBDataLength(outp, finalCount);
4749 smb_ReleaseFID(fidp);
4751 cm_ReleaseUser(userp);
4756 * Values for createDisp, copied from NTDDK.H
4758 #define FILE_SUPERSEDE 0 // (???)
4759 #define FILE_OPEN 1 // (open)
4760 #define FILE_CREATE 2 // (exclusive)
4761 #define FILE_OPEN_IF 3 // (non-exclusive)
4762 #define FILE_OVERWRITE 4 // (open & truncate, but do not create)
4763 #define FILE_OVERWRITE_IF 5 // (open & truncate, or create)
4765 long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4767 char *pathp, *realPathp;
4771 cm_scache_t *dscp; /* parent dir */
4772 cm_scache_t *scp; /* file to create or open */
4773 cm_scache_t *targetScp; /* if scp is a symlink */
4777 unsigned short nameLength;
4779 unsigned int requestOpLock;
4780 unsigned int requestBatchOpLock;
4781 unsigned int mustBeDir;
4782 unsigned int treeCreate;
4784 unsigned int desiredAccess;
4785 unsigned int extAttributes;
4786 unsigned int createDisp;
4787 unsigned int createOptions;
4788 int initialModeBits;
4789 unsigned short baseFid;
4790 smb_fid_t *baseFidp;
4792 cm_scache_t *baseDirp;
4793 unsigned short openAction;
4808 nameLength = smb_GetSMBOffsetParm(inp, 2, 1);
4809 flags = smb_GetSMBOffsetParm(inp, 3, 1)
4810 | (smb_GetSMBOffsetParm(inp, 4, 1) << 16);
4811 requestOpLock = flags & 0x02;
4812 requestBatchOpLock = flags & 0x04;
4813 mustBeDir = flags & 0x08;
4816 * Why all of a sudden 32-bit FID?
4817 * We will reject all bits higher than 16.
4819 if (smb_GetSMBOffsetParm(inp, 6, 1) != 0)
4820 return CM_ERROR_INVAL;
4821 baseFid = smb_GetSMBOffsetParm(inp, 5, 1);
4822 desiredAccess = smb_GetSMBOffsetParm(inp, 7, 1)
4823 | (smb_GetSMBOffsetParm(inp, 8, 1) << 16);
4824 extAttributes = smb_GetSMBOffsetParm(inp, 13, 1)
4825 | (smb_GetSMBOffsetParm(inp, 14, 1) << 16);
4826 createDisp = smb_GetSMBOffsetParm(inp, 17, 1)
4827 | (smb_GetSMBOffsetParm(inp, 18, 1) << 16);
4828 createOptions = smb_GetSMBOffsetParm(inp, 19, 1)
4829 | (smb_GetSMBOffsetParm(inp, 20, 1) << 16);
4831 /* mustBeDir is never set; createOptions directory bit seems to be
4834 if (createOptions & 1)
4836 else if (createOptions & 0x40)
4842 * compute initial mode bits based on read-only flag in
4843 * extended attributes
4845 initialModeBits = 0666;
4846 if (extAttributes & 1)
4847 initialModeBits &= ~0222;
4849 pathp = smb_GetSMBData(inp, NULL);
4850 /* Sometimes path is not null-terminated, so we make a copy. */
4851 realPathp = malloc(nameLength+1);
4852 memcpy(realPathp, pathp, nameLength);
4853 realPathp[nameLength] = 0;
4855 spacep = inp->spacep;
4856 smb_StripLastComponent(spacep->data, &lastNamep, realPathp);
4858 osi_Log1(smb_logp,"NTCreateX for [%s]",osi_LogSaveString(smb_logp,realPathp));
4859 osi_Log4(smb_logp,"... da=[%x] ea=[%x] cd=[%x] co=[%x]", desiredAccess, extAttributes, createDisp, createOptions);
4860 osi_Log2(smb_logp,"... flags=[%x] lastNamep=[%s]", flags, osi_LogSaveString(smb_logp,(lastNamep?lastNamep:"null")));
4862 if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
4863 /* special case magic file name for receiving IOCTL requests
4864 * (since IOCTL calls themselves aren't getting through).
4866 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
4867 smb_SetupIoctlFid(fidp, spacep);
4868 osi_Log1(smb_logp,"NTCreateX Setting up IOCTL on fid[%d]",fidp->fid);
4870 /* set inp->fid so that later read calls in same msg can find fid */
4871 inp->fid = fidp->fid;
4875 smb_SetSMBParmByte(outp, parmSlot, 0); /* oplock */
4876 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
4877 smb_SetSMBParmLong(outp, parmSlot, 1); parmSlot += 2; /* Action */
4879 memset(&ft, 0, sizeof(ft));
4880 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
4881 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
4882 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
4883 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
4884 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2; /* attr */
4885 sz.HighPart = 0x7fff; sz.LowPart = 0;
4886 smb_SetSMBParmDouble(outp, parmSlot, (char *)&sz); parmSlot += 4; /* alen */
4887 smb_SetSMBParmDouble(outp, parmSlot, (char *)&sz); parmSlot += 4; /* len */
4888 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* filetype */
4889 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* dev state */
4890 smb_SetSMBParmByte(outp, parmSlot, 0); /* is a dir? */
4891 smb_SetSMBDataLength(outp, 0);
4893 /* clean up fid reference */
4894 smb_ReleaseFID(fidp);
4899 #ifdef DEBUG_VERBOSE
4901 char *hexp, *asciip;
4902 asciip = (lastNamep? lastNamep : realPathp);
4903 hexp = osi_HexifyString( asciip );
4904 DEBUG_EVENT2("AFS", "NTCreateX H[%s] A[%s]", hexp, asciip);
4908 userp = smb_GetUser(vcp, inp);
4910 osi_Log1(smb_logp, "NTCreateX Invalid user [%d]", ((smb_t *) inp)->uid);
4912 return CM_ERROR_INVAL;
4916 baseDirp = cm_rootSCachep;
4917 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4918 if (code == CM_ERROR_TIDIPC) {
4919 /* Attempt to use a TID allocated for IPC. The client
4920 * is probably looking for DCE RPC end points which we
4922 osi_Log0(smb_logp, "NTCreateX received IPC TID");
4924 cm_ReleaseUser(userp);
4925 return CM_ERROR_NOSUCHFILE;
4929 baseFidp = smb_FindFID(vcp, baseFid, 0);
4931 osi_Log1(smb_logp, "NTCreateX Invalid base fid [%d]", baseFid);
4933 cm_ReleaseUser(userp);
4934 return CM_ERROR_INVAL;
4936 baseDirp = baseFidp->scp;
4940 osi_Log1(smb_logp, "NTCreateX tidPathp=[%s]", (tidPathp==NULL)?"null": osi_LogSaveString(smb_logp,tidPathp));
4942 /* compute open mode */
4944 if (desiredAccess & DELETE)
4945 fidflags |= SMB_FID_OPENDELETE;
4946 if (desiredAccess & AFS_ACCESS_READ)
4947 fidflags |= SMB_FID_OPENREAD;
4948 if (desiredAccess & AFS_ACCESS_WRITE)
4949 fidflags |= SMB_FID_OPENWRITE;
4953 /* For an exclusive create, we want to do a case sensitive match for the last component. */
4954 if ( createDisp == FILE_CREATE ||
4955 createDisp == FILE_OVERWRITE ||
4956 createDisp == FILE_OVERWRITE_IF) {
4957 code = cm_NameI(baseDirp, spacep->data, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
4958 userp, tidPathp, &req, &dscp);
4960 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp, CM_FLAG_FOLLOW,
4962 if (code == CM_ERROR_NOSUCHFILE) {
4963 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp,
4964 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, &req, &scp);
4965 if (code == 0 && realDirFlag == 1) {
4966 cm_ReleaseSCache(scp);
4967 cm_ReleaseSCache(dscp);
4968 cm_ReleaseUser(userp);
4970 return CM_ERROR_EXISTS;
4976 code = cm_NameI(baseDirp, realPathp, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
4977 userp, tidPathp, &req, &scp);
4982 if (!foundscp || (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE))) {
4983 /* look up parent directory */
4984 /* If we are trying to create a path (i.e. multiple nested directories), then we don't *need*
4985 * the immediate parent. We have to work our way up realPathp until we hit something that we
4993 code = cm_NameI(baseDirp, spacep->data,
4994 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
4995 userp, tidPathp, &req, &dscp);
4998 (tp = strrchr(spacep->data,'\\')) &&
4999 (createDisp == FILE_CREATE) &&
5000 (realDirFlag == 1)) {
5003 treeStartp = realPathp + (tp - spacep->data);
5005 if (*tp && !smb_IsLegalFilename(tp)) {
5007 smb_ReleaseFID(baseFidp);
5008 cm_ReleaseUser(userp);
5010 return CM_ERROR_BADNTFILENAME;
5020 smb_ReleaseFID(baseFidp);
5023 osi_Log0(smb_logp,"NTCreateX parent not found");
5024 cm_ReleaseUser(userp);
5029 if (treeCreate && dscp->fileType == CM_SCACHETYPE_FILE) {
5030 /* A file exists where we want a directory. */
5031 cm_ReleaseSCache(dscp);
5032 cm_ReleaseUser(userp);
5034 return CM_ERROR_EXISTS;
5038 lastNamep = realPathp;
5042 if (!smb_IsLegalFilename(lastNamep)) {
5043 cm_ReleaseSCache(dscp);
5044 cm_ReleaseUser(userp);
5046 return CM_ERROR_BADNTFILENAME;
5049 if (!foundscp && !treeCreate) {
5050 if ( createDisp == FILE_CREATE ||
5051 createDisp == FILE_OVERWRITE ||
5052 createDisp == FILE_OVERWRITE_IF)
5054 code = cm_Lookup(dscp, lastNamep,
5055 CM_FLAG_FOLLOW, userp, &req, &scp);
5057 code = cm_Lookup(dscp, lastNamep,
5058 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
5061 if (code && code != CM_ERROR_NOSUCHFILE) {
5062 cm_ReleaseSCache(dscp);
5063 cm_ReleaseUser(userp);
5071 smb_ReleaseFID(baseFidp);
5074 /* if we get here, if code is 0, the file exists and is represented by
5075 * scp. Otherwise, we have to create it. The dir may be represented
5076 * by dscp, or we may have found the file directly. If code is non-zero,
5079 if (code == 0 && !treeCreate) {
5080 if (createDisp == FILE_CREATE) {
5081 /* oops, file shouldn't be there */
5082 if (dscp) cm_ReleaseSCache(dscp);
5083 cm_ReleaseSCache(scp);
5084 cm_ReleaseUser(userp);
5086 return CM_ERROR_EXISTS;
5089 if ( createDisp == FILE_OVERWRITE ||
5090 createDisp == FILE_OVERWRITE_IF) {
5091 setAttr.mask = CM_ATTRMASK_LENGTH;
5092 setAttr.length.LowPart = 0;
5093 setAttr.length.HighPart = 0;
5094 /* now watch for a symlink */
5096 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
5098 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
5100 /* we have a more accurate file to use (the
5101 * target of the symbolic link). Otherwise,
5102 * we'll just use the symlink anyway.
5104 osi_Log2(smb_logp, "symlink vp %x to vp %x",
5106 cm_ReleaseSCache(scp);
5110 code = cm_SetAttr(scp, &setAttr, userp, &req);
5111 openAction = 3; /* truncated existing file */
5114 openAction = 1; /* found existing file */
5116 code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp,
5119 if (dscp) cm_ReleaseSCache(dscp);
5120 cm_ReleaseSCache(scp);
5121 cm_ReleaseUser(userp);
5126 else if (createDisp == FILE_OPEN || createDisp == FILE_OVERWRITE) {
5127 /* don't create if not found */
5128 if (dscp) cm_ReleaseSCache(dscp);
5129 cm_ReleaseUser(userp);
5131 return CM_ERROR_NOSUCHFILE;
5133 else if (realDirFlag == 0 || realDirFlag == -1) {
5134 osi_assert(dscp != NULL);
5135 osi_Log1(smb_logp, "smb_ReceiveNTCreateX creating file %s",
5136 osi_LogSaveString(smb_logp, lastNamep));
5137 openAction = 2; /* created file */
5138 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
5139 setAttr.clientModTime = time(NULL);
5140 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
5142 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
5143 smb_NotifyChange(FILE_ACTION_ADDED,
5144 FILE_NOTIFY_CHANGE_FILE_NAME,
5145 dscp, lastNamep, NULL, TRUE);
5146 if (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE) {
5147 /* Not an exclusive create, and someone else tried
5148 * creating it already, then we open it anyway. We
5149 * don't bother retrying after this, since if this next
5150 * fails, that means that the file was deleted after we
5151 * started this call.
5153 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
5156 if (createDisp == FILE_OVERWRITE_IF) {
5157 setAttr.mask = CM_ATTRMASK_LENGTH;
5158 setAttr.length.LowPart = 0;
5159 setAttr.length.HighPart = 0;
5161 /* now watch for a symlink */
5163 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
5165 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
5167 /* we have a more accurate file to use (the
5168 * target of the symbolic link). Otherwise,
5169 * we'll just use the symlink anyway.
5171 osi_Log2(smb_logp, "symlink vp %x to vp %x",
5173 cm_ReleaseSCache(scp);
5177 code = cm_SetAttr(scp, &setAttr, userp, &req);
5179 } /* lookup succeeded */
5184 char *cp; /* This component */
5185 int clen = 0; /* length of component */
5189 /* create directory */
5191 treeStartp = lastNamep;
5192 osi_assert(dscp != NULL);
5193 osi_Log1(smb_logp, "smb_ReceiveNTCreateX creating directory [%s]",
5194 osi_LogSaveString(smb_logp, treeStartp));
5195 openAction = 2; /* created directory */
5197 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
5198 setAttr.clientModTime = time(NULL);
5205 tp = strchr(pp, '\\');
5209 isLast = 1; /* indicate last component. the supplied path never ends in a slash */
5213 strncpy(cp,pp,clen);
5220 continue; /* the supplied path can't have consecutive slashes either , but */
5222 /* cp is the next component to be created. */
5223 code = cm_MakeDir(tscp, cp, 0, &setAttr, userp, &req);
5224 if (code == 0 && (tscp->flags & CM_SCACHEFLAG_ANYWATCH))
5225 smb_NotifyChange(FILE_ACTION_ADDED,
5226 FILE_NOTIFY_CHANGE_DIR_NAME,
5227 tscp, cp, NULL, TRUE);
5229 (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE)) {
5230 /* Not an exclusive create, and someone else tried
5231 * creating it already, then we open it anyway. We
5232 * don't bother retrying after this, since if this next
5233 * fails, that means that the file was deleted after we
5234 * started this call.
5236 code = cm_Lookup(tscp, cp, CM_FLAG_CASEFOLD,
5241 if (!isLast) { /* for anything other than dscp, release it unless it's the last one */
5242 cm_ReleaseSCache(tscp);
5243 tscp = scp; /* Newly created directory will be next parent */
5248 * if we get here and code == 0, then scp is the last directory created, and tscp is the
5249 * parent of scp. dscp got released if dscp != tscp. both tscp and scp are held.
5255 /* something went wrong creating or truncating the file */
5256 if (scp) cm_ReleaseSCache(scp);
5257 if (dscp) cm_ReleaseSCache(dscp);
5258 cm_ReleaseUser(userp);
5263 /* make sure we have file vs. dir right (only applies for single component case) */
5264 if (realDirFlag == 0 && scp->fileType != CM_SCACHETYPE_FILE) {
5265 /* now watch for a symlink */
5267 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
5268 cm_scache_t * targetScp = 0;
5269 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
5271 /* we have a more accurate file to use (the
5272 * target of the symbolic link). Otherwise,
5273 * we'll just use the symlink anyway.
5275 osi_Log2(smb_logp, "symlink vp %x to vp %x",
5277 cm_ReleaseSCache(scp);
5282 if (scp->fileType != CM_SCACHETYPE_FILE) {
5283 cm_ReleaseSCache(scp);
5284 cm_ReleaseUser(userp);
5286 return CM_ERROR_ISDIR;
5290 /* (only applies to single component case) */
5291 if (realDirFlag == 1 && scp->fileType == CM_SCACHETYPE_FILE) {
5292 cm_ReleaseSCache(scp);
5293 if (dscp) cm_ReleaseSCache(dscp);
5294 cm_ReleaseUser(userp);
5296 return CM_ERROR_NOTDIR;
5299 /* open the file itself */
5300 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
5302 /* save a pointer to the vnode */
5305 fidp->flags = fidflags;
5307 /* save parent dir and pathname for delete or change notification */
5308 if (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE)) {
5309 fidp->flags |= SMB_FID_NTOPEN;
5310 fidp->NTopen_dscp = dscp;
5311 cm_HoldSCache(dscp);
5312 fidp->NTopen_pathp = strdup(lastNamep);
5314 fidp->NTopen_wholepathp = realPathp;
5316 /* we don't need this any longer */
5317 if (dscp) cm_ReleaseSCache(dscp);
5318 cm_Open(scp, 0, userp);
5320 /* set inp->fid so that later read calls in same msg can find fid */
5321 inp->fid = fidp->fid;
5325 lock_ObtainMutex(&scp->mx);
5326 smb_SetSMBParmByte(outp, parmSlot, 0); /* oplock */
5327 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
5328 smb_SetSMBParmLong(outp, parmSlot, openAction); parmSlot += 2;
5329 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
5330 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
5331 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
5332 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
5333 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
5334 smb_SetSMBParmLong(outp, parmSlot, smb_ExtAttributes(scp));
5336 smb_SetSMBParmDouble(outp, parmSlot, (char *)&scp->length); parmSlot += 4;
5337 smb_SetSMBParmDouble(outp, parmSlot, (char *)&scp->length); parmSlot += 4;
5338 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* filetype */
5339 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* dev state */
5340 smb_SetSMBParmByte(outp, parmSlot,
5341 scp->fileType == CM_SCACHETYPE_DIRECTORY); /* is a dir? */
5342 lock_ReleaseMutex(&scp->mx);
5343 smb_SetSMBDataLength(outp, 0);
5345 osi_Log2(smb_logp, "SMB NT CreateX opening fid %d path %s", fidp->fid,
5346 osi_LogSaveString(smb_logp, realPathp));
5348 smb_ReleaseFID(fidp);
5350 cm_ReleaseUser(userp);
5352 /* Can't free realPathp if we get here since fidp->NTopen_wholepathp is pointing there */
5354 /* leave scp held since we put it in fidp->scp */
5359 * A lot of stuff copied verbatim from NT Create&X to NT Tran Create.
5360 * Instead, ultimately, would like to use a subroutine for common code.
5362 long smb_ReceiveNTTranCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5364 char *pathp, *realPathp;
5368 cm_scache_t *dscp; /* parent dir */
5369 cm_scache_t *scp; /* file to create or open */
5370 cm_scache_t *targetScp; /* if scp is a symlink */
5373 unsigned long nameLength;
5375 unsigned int requestOpLock;
5376 unsigned int requestBatchOpLock;
5377 unsigned int mustBeDir;
5378 unsigned int extendedRespRequired;
5380 unsigned int desiredAccess;
5381 #ifdef DEBUG_VERBOSE
5382 unsigned int allocSize;
5383 unsigned int shareAccess;
5385 unsigned int extAttributes;
5386 unsigned int createDisp;
5387 #ifdef DEBUG_VERBOSE
5390 unsigned int createOptions;
5391 int initialModeBits;
5392 unsigned short baseFid;
5393 smb_fid_t *baseFidp;
5395 cm_scache_t *baseDirp;
5396 unsigned short openAction;
5402 int parmOffset, dataOffset;
5413 parmOffset = smb_GetSMBOffsetParm(inp, 11, 1)
5414 | (smb_GetSMBOffsetParm(inp, 12, 1) << 16);
5415 parmp = inp->data + parmOffset;
5416 lparmp = (ULONG *) parmp;
5419 requestOpLock = flags & 0x02;
5420 requestBatchOpLock = flags & 0x04;
5421 mustBeDir = flags & 0x08;
5422 extendedRespRequired = flags & 0x10;
5425 * Why all of a sudden 32-bit FID?
5426 * We will reject all bits higher than 16.
5428 if (lparmp[1] & 0xFFFF0000)
5429 return CM_ERROR_INVAL;
5430 baseFid = (unsigned short)lparmp[1];
5431 desiredAccess = lparmp[2];
5432 #ifdef DEBUG_VERBOSE
5433 allocSize = lparmp[3];
5434 #endif /* DEBUG_VERSOSE */
5435 extAttributes = lparmp[5];
5437 shareAccess = lparmp[6];
5439 createDisp = lparmp[7];
5440 createOptions = lparmp[8];
5441 #ifdef DEBUG_VERBOSE
5444 nameLength = lparmp[11];
5446 #ifdef DEBUG_VERBOSE
5447 osi_Log4(smb_logp,"NTTranCreate with da[%x],ea[%x],sa[%x],cd[%x]",desiredAccess,extAttributes,shareAccess,createDisp);
5448 osi_Log3(smb_logp,"... co[%x],sdl[%x],as[%x]",createOptions,sdLen,allocSize);
5449 osi_Log1(smb_logp,"... flags[%x]",flags);
5452 /* mustBeDir is never set; createOptions directory bit seems to be
5455 if (createOptions & 1)
5457 else if (createOptions & 0x40)
5463 * compute initial mode bits based on read-only flag in
5464 * extended attributes
5466 initialModeBits = 0666;
5467 if (extAttributes & 1)
5468 initialModeBits &= ~0222;
5470 pathp = parmp + (13 * sizeof(ULONG)) + sizeof(UCHAR);
5471 /* Sometimes path is not null-terminated, so we make a copy. */
5472 realPathp = malloc(nameLength+1);
5473 memcpy(realPathp, pathp, nameLength);
5474 realPathp[nameLength] = 0;
5476 spacep = cm_GetSpace();
5477 smb_StripLastComponent(spacep->data, &lastNamep, realPathp);
5480 * Nothing here to handle SMB_IOCTL_FILENAME.
5481 * Will add it if necessary.
5484 #ifdef DEBUG_VERBOSE
5486 char *hexp, *asciip;
5487 asciip = (lastNamep? lastNamep : realPathp);
5488 hexp = osi_HexifyString( asciip );
5489 DEBUG_EVENT2("AFS", "NTTranCreate H[%s] A[%s]", hexp, asciip);
5494 userp = smb_GetUser(vcp, inp);
5496 osi_Log1(smb_logp, "NTTranCreate invalid user [%d]", ((smb_t *) inp)->uid);
5498 return CM_ERROR_INVAL;
5502 baseDirp = cm_rootSCachep;
5503 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5504 if(code == CM_ERROR_TIDIPC) {
5505 /* Attempt to use TID allocated for IPC. The client is
5506 * probably trying to locate DCE RPC endpoints, which we
5508 osi_Log0(smb_logp, "NTTranCreate received IPC TID");
5510 cm_ReleaseUser(userp);
5511 return CM_ERROR_NOSUCHPATH;
5515 baseFidp = smb_FindFID(vcp, baseFid, 0);
5517 osi_Log1(smb_logp, "NTTranCreate Invalid fid [%d]", baseFid);
5519 cm_ReleaseUser(userp);
5520 return CM_ERROR_INVAL;
5522 baseDirp = baseFidp->scp;
5526 /* compute open mode */
5528 if (desiredAccess & DELETE)
5529 fidflags |= SMB_FID_OPENDELETE;
5530 if (desiredAccess & AFS_ACCESS_READ)
5531 fidflags |= SMB_FID_OPENREAD;
5532 if (desiredAccess & AFS_ACCESS_WRITE)
5533 fidflags |= SMB_FID_OPENWRITE;
5537 if ( createDisp == FILE_OPEN ||
5538 createDisp == FILE_OVERWRITE ||
5539 createDisp == FILE_OVERWRITE_IF) {
5540 code = cm_NameI(baseDirp, spacep->data, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
5541 userp, tidPathp, &req, &dscp);
5543 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp, CM_FLAG_FOLLOW,
5545 if (code == CM_ERROR_NOSUCHFILE) {
5546 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp,
5547 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, &req, &scp);
5548 if (code == 0 && realDirFlag == 1) {
5549 cm_ReleaseSCache(scp);
5550 cm_ReleaseSCache(dscp);
5551 cm_ReleaseUser(userp);
5553 return CM_ERROR_EXISTS;
5559 code = cm_NameI(baseDirp, realPathp, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
5560 userp, tidPathp, &req, &scp);
5566 || (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE))) {
5567 /* look up parent directory */
5569 code = cm_NameI(baseDirp, spacep->data,
5570 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
5571 userp, tidPathp, &req, &dscp);
5575 cm_FreeSpace(spacep);
5578 smb_ReleaseFID(baseFidp);
5583 cm_ReleaseUser(userp);
5588 if (!lastNamep) lastNamep = realPathp;
5591 if (!smb_IsLegalFilename(lastNamep))
5592 return CM_ERROR_BADNTFILENAME;
5595 if (createDisp == FILE_CREATE || createDisp == FILE_OVERWRITE_IF) {
5596 code = cm_Lookup(dscp, lastNamep,
5597 CM_FLAG_FOLLOW, userp, &req, &scp);
5599 code = cm_Lookup(dscp, lastNamep,
5600 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
5603 if (code && code != CM_ERROR_NOSUCHFILE) {
5604 cm_ReleaseSCache(dscp);
5605 cm_ReleaseUser(userp);
5613 smb_ReleaseFID(baseFidp);
5616 cm_FreeSpace(spacep);
5619 /* if we get here, if code is 0, the file exists and is represented by
5620 * scp. Otherwise, we have to create it. The dir may be represented
5621 * by dscp, or we may have found the file directly. If code is non-zero,
5625 code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp,
5628 if (dscp) cm_ReleaseSCache(dscp);
5629 cm_ReleaseSCache(scp);
5630 cm_ReleaseUser(userp);
5635 if (createDisp == FILE_CREATE) {
5636 /* oops, file shouldn't be there */
5637 if (dscp) cm_ReleaseSCache(dscp);
5638 cm_ReleaseSCache(scp);
5639 cm_ReleaseUser(userp);
5641 return CM_ERROR_EXISTS;
5644 if (createDisp == FILE_OVERWRITE ||
5645 createDisp == FILE_OVERWRITE_IF) {
5646 setAttr.mask = CM_ATTRMASK_LENGTH;
5647 setAttr.length.LowPart = 0;
5648 setAttr.length.HighPart = 0;
5650 /* now watch for a symlink */
5652 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
5654 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
5656 /* we have a more accurate file to use (the
5657 * target of the symbolic link). Otherwise,
5658 * we'll just use the symlink anyway.
5660 osi_Log2(smb_logp, "symlink vp %x to vp %x",
5662 cm_ReleaseSCache(scp);
5666 code = cm_SetAttr(scp, &setAttr, userp, &req);
5667 openAction = 3; /* truncated existing file */
5669 else openAction = 1; /* found existing file */
5671 else if (createDisp == FILE_OPEN || createDisp == FILE_OVERWRITE) {
5672 /* don't create if not found */
5673 if (dscp) cm_ReleaseSCache(dscp);
5674 cm_ReleaseUser(userp);
5676 return CM_ERROR_NOSUCHFILE;
5678 else if (realDirFlag == 0 || realDirFlag == -1) {
5679 osi_assert(dscp != NULL);
5680 osi_Log1(smb_logp, "smb_ReceiveNTTranCreate creating file %s",
5681 osi_LogSaveString(smb_logp, lastNamep));
5682 openAction = 2; /* created file */
5683 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
5684 setAttr.clientModTime = time(NULL);
5685 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
5687 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
5688 smb_NotifyChange(FILE_ACTION_ADDED,
5689 FILE_NOTIFY_CHANGE_FILE_NAME,
5690 dscp, lastNamep, NULL, TRUE);
5691 if (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE) {
5692 /* Not an exclusive create, and someone else tried
5693 * creating it already, then we open it anyway. We
5694 * don't bother retrying after this, since if this next
5695 * fails, that means that the file was deleted after we
5696 * started this call.
5698 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
5701 if (createDisp == FILE_OVERWRITE_IF) {
5702 setAttr.mask = CM_ATTRMASK_LENGTH;
5703 setAttr.length.LowPart = 0;
5704 setAttr.length.HighPart = 0;
5706 /* now watch for a symlink */
5708 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
5710 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
5712 /* we have a more accurate file to use (the
5713 * target of the symbolic link). Otherwise,
5714 * we'll just use the symlink anyway.
5716 osi_Log2(smb_logp, "symlink vp %x to vp %x",
5718 cm_ReleaseSCache(scp);
5722 code = cm_SetAttr(scp, &setAttr, userp, &req);
5724 } /* lookup succeeded */
5728 /* create directory */
5729 osi_assert(dscp != NULL);
5731 "smb_ReceiveNTTranCreate creating directory %s",
5732 osi_LogSaveString(smb_logp, lastNamep));
5733 openAction = 2; /* created directory */
5734 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
5735 setAttr.clientModTime = time(NULL);
5736 code = cm_MakeDir(dscp, lastNamep, 0, &setAttr, userp, &req);
5737 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
5738 smb_NotifyChange(FILE_ACTION_ADDED,
5739 FILE_NOTIFY_CHANGE_DIR_NAME,
5740 dscp, lastNamep, NULL, TRUE);
5742 (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE)) {
5743 /* Not an exclusive create, and someone else tried
5744 * creating it already, then we open it anyway. We
5745 * don't bother retrying after this, since if this next
5746 * fails, that means that the file was deleted after we
5747 * started this call.
5749 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
5755 /* something went wrong creating or truncating the file */
5756 if (scp) cm_ReleaseSCache(scp);
5757 cm_ReleaseUser(userp);
5762 /* make sure we have file vs. dir right */
5763 if (realDirFlag == 0 && scp->fileType != CM_SCACHETYPE_FILE) {
5764 /* now watch for a symlink */
5766 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
5768 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
5770 /* we have a more accurate file to use (the
5771 * target of the symbolic link). Otherwise,
5772 * we'll just use the symlink anyway.
5774 osi_Log2(smb_logp, "symlink vp %x to vp %x",
5776 cm_ReleaseSCache(scp);
5781 if (scp->fileType != CM_SCACHETYPE_FILE) {
5782 cm_ReleaseSCache(scp);
5783 cm_ReleaseUser(userp);
5785 return CM_ERROR_ISDIR;
5789 if (realDirFlag == 1 && scp->fileType == CM_SCACHETYPE_FILE) {
5790 cm_ReleaseSCache(scp);
5791 cm_ReleaseUser(userp);
5793 return CM_ERROR_NOTDIR;
5796 /* open the file itself */
5797 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
5800 /* save a pointer to the vnode */
5803 fidp->flags = fidflags;
5805 /* save parent dir and pathname for deletion or change notification */
5806 if (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE)) {
5807 fidp->flags |= SMB_FID_NTOPEN;
5808 fidp->NTopen_dscp = dscp;
5809 cm_HoldSCache(dscp);
5810 fidp->NTopen_pathp = strdup(lastNamep);
5812 fidp->NTopen_wholepathp = realPathp;
5814 /* we don't need this any longer */
5815 if (dscp) cm_ReleaseSCache(dscp);
5817 cm_Open(scp, 0, userp);
5819 /* set inp->fid so that later read calls in same msg can find fid */
5820 inp->fid = fidp->fid;
5822 /* check whether we are required to send an extended response */
5823 if (!extendedRespRequired) {
5825 parmOffset = 8*4 + 39;
5826 parmOffset += 1; /* pad to 4 */
5827 dataOffset = parmOffset + 70;
5831 /* Total Parameter Count */
5832 smb_SetSMBParmLong(outp, parmSlot, 70); parmSlot += 2;
5833 /* Total Data Count */
5834 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
5835 /* Parameter Count */
5836 smb_SetSMBParmLong(outp, parmSlot, 70); parmSlot += 2;
5837 /* Parameter Offset */
5838 smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
5839 /* Parameter Displacement */
5840 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
5842 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
5844 smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
5845 /* Data Displacement */
5846 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
5847 smb_SetSMBParmByte(outp, parmSlot, 0); /* Setup Count */
5848 smb_SetSMBDataLength(outp, 70);
5850 lock_ObtainMutex(&scp->mx);
5851 outData = smb_GetSMBData(outp, NULL);
5852 outData++; /* round to get to parmOffset */
5853 *outData = 0; outData++; /* oplock */
5854 *outData = 0; outData++; /* reserved */
5855 *((USHORT *)outData) = fidp->fid; outData += 2; /* fid */
5856 *((ULONG *)outData) = openAction; outData += 4;
5857 *((ULONG *)outData) = 0; outData += 4; /* EA error offset */
5858 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
5859 *((FILETIME *)outData) = ft; outData += 8; /* creation time */
5860 *((FILETIME *)outData) = ft; outData += 8; /* last access time */
5861 *((FILETIME *)outData) = ft; outData += 8; /* last write time */
5862 *((FILETIME *)outData) = ft; outData += 8; /* change time */
5863 *((ULONG *)outData) = smb_ExtAttributes(scp); outData += 4;
5864 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* alloc sz */
5865 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* EOF */
5866 *((USHORT *)outData) = 0; outData += 2; /* filetype */
5867 *((USHORT *)outData) = 0; outData += 2; /* dev state */
5868 *((USHORT *)outData) = (scp->fileType == CM_SCACHETYPE_DIRECTORY);
5869 outData += 2; /* is a dir? */
5870 lock_ReleaseMutex(&scp->mx);
5873 parmOffset = 8*4 + 39;
5874 parmOffset += 1; /* pad to 4 */
5875 dataOffset = parmOffset + 104;
5879 /* Total Parameter Count */
5880 smb_SetSMBParmLong(outp, parmSlot, 101); parmSlot += 2;
5881 /* Total Data Count */
5882 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
5883 /* Parameter Count */
5884 smb_SetSMBParmLong(outp, parmSlot, 101); parmSlot += 2;
5885 /* Parameter Offset */
5886 smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
5887 /* Parameter Displacement */
5888 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
5890 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
5892 smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
5893 /* Data Displacement */
5894 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
5895 smb_SetSMBParmByte(outp, parmSlot, 0); /* Setup Count */
5896 smb_SetSMBDataLength(outp, 105);
5898 lock_ObtainMutex(&scp->mx);
5899 outData = smb_GetSMBData(outp, NULL);
5900 outData++; /* round to get to parmOffset */
5901 *outData = 0; outData++; /* oplock */
5902 *outData = 1; outData++; /* response type */
5903 *((USHORT *)outData) = fidp->fid; outData += 2; /* fid */
5904 *((ULONG *)outData) = openAction; outData += 4;
5905 *((ULONG *)outData) = 0; outData += 4; /* EA error offset */
5906 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
5907 *((FILETIME *)outData) = ft; outData += 8; /* creation time */
5908 *((FILETIME *)outData) = ft; outData += 8; /* last access time */
5909 *((FILETIME *)outData) = ft; outData += 8; /* last write time */
5910 *((FILETIME *)outData) = ft; outData += 8; /* change time */
5911 *((ULONG *)outData) = smb_ExtAttributes(scp); outData += 4;
5912 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* alloc sz */
5913 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* EOF */
5914 *((USHORT *)outData) = 0; outData += 2; /* filetype */
5915 *((USHORT *)outData) = 0; outData += 2; /* dev state */
5916 *((USHORT *)outData) = (scp->fileType == CM_SCACHETYPE_DIRECTORY);
5917 outData += 1; /* is a dir? */
5918 memset(outData,0,24); outData += 24; /* Volume ID and file ID */
5919 *((ULONG *)outData) = 0x001f01ffL; outData += 4; /* Maxmimal access rights */
5920 *((ULONG *)outData) = 0; outData += 4; /* Guest Access rights */
5921 lock_ReleaseMutex(&scp->mx);
5924 osi_Log1(smb_logp, "SMB NTTranCreate opening fid %d", fidp->fid);
5926 smb_ReleaseFID(fidp);
5928 cm_ReleaseUser(userp);
5930 /* free(realPathp); Can't free realPathp here because fidp->NTopen_wholepathp points there */
5931 /* leave scp held since we put it in fidp->scp */
5935 long smb_ReceiveNTTranNotifyChange(smb_vc_t *vcp, smb_packet_t *inp,
5938 smb_packet_t *savedPacketp;
5939 ULONG filter; USHORT fid, watchtree;
5943 filter = smb_GetSMBParm(inp, 19) |
5944 (smb_GetSMBParm(inp, 20) << 16);
5945 fid = smb_GetSMBParm(inp, 21);
5946 watchtree = smb_GetSMBParm(inp, 22) && 0xffff; /* TODO: should this be 0xff ? */
5948 fidp = smb_FindFID(vcp, fid, 0);
5950 osi_Log1(smb_logp, "ERROR: NotifyChange given invalid fid [%d]", fid);
5951 return CM_ERROR_BADFD;
5954 savedPacketp = smb_CopyPacket(inp);
5956 savedPacketp->vcp = vcp;
5957 lock_ObtainMutex(&smb_Dir_Watch_Lock);
5958 savedPacketp->nextp = smb_Directory_Watches;
5959 smb_Directory_Watches = savedPacketp;
5960 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
5962 osi_Log4(smb_logp, "Request for NotifyChange filter 0x%x fid %d wtree %d file %s",
5963 filter, fid, watchtree, osi_LogSaveString(smb_logp, fidp->NTopen_wholepathp));
5966 lock_ObtainMutex(&scp->mx);
5968 scp->flags |= CM_SCACHEFLAG_WATCHEDSUBTREE;
5970 scp->flags |= CM_SCACHEFLAG_WATCHED;
5971 lock_ReleaseMutex(&scp->mx);
5972 smb_ReleaseFID(fidp);
5974 outp->flags |= SMB_PACKETFLAG_NOSEND;
5978 unsigned char nullSecurityDesc[36] = {
5979 0x01, /* security descriptor revision */
5980 0x00, /* reserved, should be zero */
5981 0x00, 0x80, /* security descriptor control;
5982 * 0x8000 : self-relative format */
5983 0x14, 0x00, 0x00, 0x00, /* offset of owner SID */
5984 0x1c, 0x00, 0x00, 0x00, /* offset of group SID */
5985 0x00, 0x00, 0x00, 0x00, /* offset of DACL would go here */
5986 0x00, 0x00, 0x00, 0x00, /* offset of SACL would go here */
5987 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
5988 /* "null SID" owner SID */
5989 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
5990 /* "null SID" group SID */
5993 long smb_ReceiveNTTranQuerySecurityDesc(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5995 int parmOffset, parmCount, dataOffset, dataCount;
6003 ULONG securityInformation;
6005 parmOffset = smb_GetSMBOffsetParm(inp, 11, 1)
6006 | (smb_GetSMBOffsetParm(inp, 12, 1) << 16);
6007 parmp = inp->data + parmOffset;
6008 sparmp = (USHORT *) parmp;
6009 lparmp = (ULONG *) parmp;
6012 securityInformation = lparmp[1];
6014 maxData = smb_GetSMBOffsetParm(inp, 7, 1)
6015 | (smb_GetSMBOffsetParm(inp, 8, 1) << 16);
6023 parmOffset = 8*4 + 39;
6024 parmOffset += 1; /* pad to 4 */
6026 dataOffset = parmOffset + parmCount;
6030 /* Total Parameter Count */
6031 smb_SetSMBParmLong(outp, parmSlot, parmCount); parmSlot += 2;
6032 /* Total Data Count */
6033 smb_SetSMBParmLong(outp, parmSlot, dataCount); parmSlot += 2;
6034 /* Parameter Count */
6035 smb_SetSMBParmLong(outp, parmSlot, parmCount); parmSlot += 2;
6036 /* Parameter Offset */
6037 smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
6038 /* Parameter Displacement */
6039 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
6041 smb_SetSMBParmLong(outp, parmSlot, dataCount); parmSlot += 2;
6043 smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
6044 /* Data Displacement */
6045 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
6046 smb_SetSMBParmByte(outp, parmSlot, 0); /* Setup Count */
6047 smb_SetSMBDataLength(outp, 1 + parmCount + dataCount);
6049 outData = smb_GetSMBData(outp, NULL);
6050 outData++; /* round to get to parmOffset */
6051 *((ULONG *)outData) = 36; outData += 4; /* length */
6053 if (maxData >= 36) {
6054 memcpy(outData, nullSecurityDesc, 36);
6058 return CM_ERROR_BUFFERTOOSMALL;
6061 long smb_ReceiveNTTransact(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6063 unsigned short function;
6065 function = smb_GetSMBParm(inp, 18);
6067 osi_Log1(smb_logp, "SMB NT Transact function %d", function);
6069 /* We can handle long names */
6070 if (vcp->flags & SMB_VCFLAG_USENT)
6071 ((smb_t *)outp)->flg2 |= 0x40; /* IS_LONG_NAME */
6075 return smb_ReceiveNTTranQuerySecurityDesc(vcp, inp, outp);
6077 return smb_ReceiveNTTranNotifyChange(vcp, inp, outp);
6079 return smb_ReceiveNTTranCreate(vcp, inp, outp);
6081 return CM_ERROR_INVAL;
6086 * smb_NotifyChange -- find relevant change notification messages and
6089 * If we don't know the file name (i.e. a callback break), filename is
6090 * NULL, and we return a zero-length list.
6092 void smb_NotifyChange(DWORD action, DWORD notifyFilter,
6093 cm_scache_t *dscp, char *filename, char *otherFilename,
6094 BOOL isDirectParent)
6096 smb_packet_t *watch, *lastWatch, *nextWatch;
6097 ULONG parmSlot, parmCount, parmOffset, dataOffset, nameLen;
6098 char *outData, *oldOutData;
6102 BOOL twoEntries = FALSE;
6103 ULONG otherNameLen, oldParmCount = 0;
6108 /* Get ready for rename within directory */
6109 if (action == FILE_ACTION_RENAMED_OLD_NAME && otherFilename != NULL) {
6111 otherAction = FILE_ACTION_RENAMED_NEW_NAME;
6114 osi_Log2(smb_logp,"in smb_NotifyChange for file [%s] dscp [%x]",
6115 osi_LogSaveString(smb_logp,filename),dscp);
6117 lock_ObtainMutex(&smb_Dir_Watch_Lock);
6118 watch = smb_Directory_Watches;
6120 filter = smb_GetSMBParm(watch, 19)
6121 | (smb_GetSMBParm(watch, 20) << 16);
6122 fid = smb_GetSMBParm(watch, 21);
6123 wtree = smb_GetSMBParm(watch, 22) & 0xffff; /* TODO: should this be 0xff ? */
6124 maxLen = smb_GetSMBOffsetParm(watch, 5, 1)
6125 | (smb_GetSMBOffsetParm(watch, 6, 1) << 16);
6129 * Strange hack - bug in NT Client and NT Server that we
6132 if (filter == 3 && wtree)
6135 fidp = smb_FindFID(vcp, fid, 0);
6137 osi_Log1(smb_logp," no fidp for fid[%d]",fid);
6139 watch = watch->nextp;
6142 if (fidp->scp != dscp
6143 || (filter & notifyFilter) == 0
6144 || (!isDirectParent && !wtree)) {
6145 osi_Log1(smb_logp," passing fidp->scp[%x]", fidp->scp);
6146 smb_ReleaseFID(fidp);
6148 watch = watch->nextp;
6151 smb_ReleaseFID(fidp);
6154 "Sending Change Notification for fid %d filter 0x%x wtree %d file %s",
6155 fid, filter, wtree, osi_LogSaveString(smb_logp, filename));
6157 nextWatch = watch->nextp;
6158 if (watch == smb_Directory_Watches)
6159 smb_Directory_Watches = nextWatch;
6161 lastWatch->nextp = nextWatch;
6163 /* Turn off WATCHED flag in dscp */
6164 lock_ObtainMutex(&dscp->mx);
6166 dscp->flags &= ~CM_SCACHEFLAG_WATCHEDSUBTREE;
6168 dscp->flags &= ~CM_SCACHEFLAG_WATCHED;
6169 lock_ReleaseMutex(&dscp->mx);
6171 /* Convert to response packet */
6172 ((smb_t *) watch)->reb = 0x80;
6173 ((smb_t *) watch)->wct = 0;
6176 if (filename == NULL)
6179 nameLen = strlen(filename);
6180 parmCount = 3*4 + nameLen*2;
6181 parmCount = (parmCount + 3) & ~3; /* pad to 4 */
6183 otherNameLen = strlen(otherFilename);
6184 oldParmCount = parmCount;
6185 parmCount += 3*4 + otherNameLen*2;
6186 parmCount = (parmCount + 3) & ~3; /* pad to 4 */
6188 if (maxLen < parmCount)
6189 parmCount = 0; /* not enough room */
6191 parmOffset = 8*4 + 39;
6192 parmOffset += 1; /* pad to 4 */
6193 dataOffset = parmOffset + parmCount;
6197 /* Total Parameter Count */
6198 smb_SetSMBParmLong(watch, parmSlot, parmCount); parmSlot += 2;
6199 /* Total Data Count */
6200 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
6201 /* Parameter Count */
6202 smb_SetSMBParmLong(watch, parmSlot, parmCount); parmSlot += 2;
6203 /* Parameter Offset */
6204 smb_SetSMBParmLong(watch, parmSlot, parmOffset); parmSlot += 2;
6205 /* Parameter Displacement */
6206 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
6208 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
6210 smb_SetSMBParmLong(watch, parmSlot, dataOffset); parmSlot += 2;
6211 /* Data Displacement */
6212 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
6213 smb_SetSMBParmByte(watch, parmSlot, 0); /* Setup Count */
6214 smb_SetSMBDataLength(watch, parmCount + 1);
6216 if (parmCount != 0) {
6217 outData = smb_GetSMBData(watch, NULL);
6218 outData++; /* round to get to parmOffset */
6219 oldOutData = outData;
6220 *((DWORD *)outData) = oldParmCount; outData += 4;
6221 /* Next Entry Offset */
6222 *((DWORD *)outData) = action; outData += 4;
6224 *((DWORD *)outData) = nameLen*2; outData += 4;
6225 /* File Name Length */
6226 mbstowcs((WCHAR *)outData, filename, nameLen);
6229 outData = oldOutData + oldParmCount;
6230 *((DWORD *)outData) = 0; outData += 4;
6231 /* Next Entry Offset */
6232 *((DWORD *)outData) = otherAction; outData += 4;
6234 *((DWORD *)outData) = otherNameLen*2;
6235 outData += 4; /* File Name Length */
6236 mbstowcs((WCHAR *)outData, otherFilename,
6237 otherNameLen); /* File Name */
6242 * If filename is null, we don't know the cause of the
6243 * change notification. We return zero data (see above),
6244 * and set error code to NT_STATUS_NOTIFY_ENUM_DIR
6245 * (= 0x010C). We set the error code here by hand, without
6246 * modifying wct and bcc.
6248 if (filename == NULL) {
6249 ((smb_t *) watch)->rcls = 0x0C;
6250 ((smb_t *) watch)->reh = 0x01;
6251 ((smb_t *) watch)->errLow = 0;
6252 ((smb_t *) watch)->errHigh = 0;
6253 /* Set NT Status codes flag */
6254 ((smb_t *) watch)->flg2 |= 0x4000;
6257 smb_SendPacket(vcp, watch);
6259 smb_FreePacket(watch);
6262 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
6265 long smb_ReceiveNTCancel(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6267 unsigned char *replyWctp;
6268 smb_packet_t *watch, *lastWatch;
6269 USHORT fid, watchtree;
6273 osi_Log0(smb_logp, "SMB3 receive NT cancel");
6275 lock_ObtainMutex(&smb_Dir_Watch_Lock);
6276 watch = smb_Directory_Watches;
6278 if (((smb_t *)watch)->uid == ((smb_t *)inp)->uid
6279 && ((smb_t *)watch)->pid == ((smb_t *)inp)->pid
6280 && ((smb_t *)watch)->mid == ((smb_t *)inp)->mid
6281 && ((smb_t *)watch)->tid == ((smb_t *)inp)->tid) {
6282 if (watch == smb_Directory_Watches)
6283 smb_Directory_Watches = watch->nextp;
6285 lastWatch->nextp = watch->nextp;
6286 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
6288 /* Turn off WATCHED flag in scp */
6289 fid = smb_GetSMBParm(watch, 21);
6290 watchtree = smb_GetSMBParm(watch, 22) & 0xffff;
6292 if (vcp != watch->vcp)
6293 osi_Log2(smb_logp, "smb_ReceiveNTCancel: vcp %x not equal to watch vcp %x",
6296 fidp = smb_FindFID(vcp, fid, 0);
6298 osi_Log3(smb_logp, "Cancelling change notification for fid %d wtree %d file %s",
6300 osi_LogSaveString(smb_logp, (fidp)?fidp->NTopen_wholepathp:""));
6303 lock_ObtainMutex(&scp->mx);
6305 scp->flags &= ~CM_SCACHEFLAG_WATCHEDSUBTREE;
6307 scp->flags &= ~CM_SCACHEFLAG_WATCHED;
6308 lock_ReleaseMutex(&scp->mx);
6309 smb_ReleaseFID(fidp);
6311 osi_Log2(smb_logp,"NTCancel unable to resolve fid [%d] in vcp[%x]", fid,vcp);
6314 /* assume STATUS32; return 0xC0000120 (CANCELED) */
6315 replyWctp = watch->wctp;
6319 ((smb_t *)watch)->rcls = 0x20;
6320 ((smb_t *)watch)->reh = 0x1;
6321 ((smb_t *)watch)->errLow = 0;
6322 ((smb_t *)watch)->errHigh = 0xC0;
6323 ((smb_t *)watch)->flg2 |= 0x4000;
6324 smb_SendPacket(vcp, watch);
6326 smb_ReleaseVC(watch->vcp);
6327 smb_FreePacket(watch);
6331 watch = watch->nextp;
6333 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
6339 * NT rename also does hard links.
6342 #define RENAME_FLAG_MOVE_CLUSTER_INFORMATION 0x102
6343 #define RENAME_FLAG_HARD_LINK 0x103
6344 #define RENAME_FLAG_RENAME 0x104
6345 #define RENAME_FLAG_COPY 0x105
6347 long smb_ReceiveNTRename(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6349 char *oldname, *newname;
6356 attrs = smb_GetSMBParm(inp, 0);
6357 rename_type = smb_GetSMBParm(inp, 1);
6359 if (rename_type != RENAME_FLAG_RENAME && rename_type != RENAME_FLAG_HARD_LINK) {
6360 osi_Log1(smb_logp, "NTRename invalid infolevel [%x]", rename_type);
6361 return CM_ERROR_NOACCESS;
6364 tp = smb_GetSMBData(inp, NULL);
6365 oldname = smb_ParseASCIIBlock(tp, &tp);
6366 newname = smb_ParseASCIIBlock(tp, &tp);
6368 osi_Log3(smb_logp, "NTRename for [%s]->[%s] type [%s]",
6369 osi_LogSaveString(smb_logp, oldname),
6370 osi_LogSaveString(smb_logp, newname),
6371 ((rename_type==RENAME_FLAG_RENAME)?"rename":"hardlink"));
6373 if (rename_type == RENAME_FLAG_RENAME) {
6374 code = smb_Rename(vcp,inp,oldname,newname,attrs);
6375 } else { /* RENAME_FLAG_HARD_LINK */
6376 code = smb_Link(vcp,inp,oldname,newname);
6383 lock_InitializeMutex(&smb_Dir_Watch_Lock, "Directory Watch List Lock");
6386 cm_user_t *smb_FindCMUserByName(/*smb_vc_t *vcp,*/ char *usern, char *machine)
6389 smb_username_t *unp;
6391 unp = smb_FindUserByName(usern, machine, SMB_FLAG_CREATE);
6393 lock_ObtainMutex(&unp->mx);
6394 unp->userp = cm_NewUser();
6395 lock_ReleaseMutex(&unp->mx);
6396 osi_Log2(smb_logp,"smb_FindCMUserByName New user name[%s] machine[%s]",osi_LogSaveString(smb_logp,usern),osi_LogSaveString(smb_logp,machine));
6397 osi_LogEvent("AFS smb_FindCMUserByName : New User",NULL,"name[%s] machine[%s]",usern,machine);
6399 osi_Log2(smb_logp,"smb_FindCMUserByName Not found name[%s] machine[%s]",osi_LogSaveString(smb_logp,usern),osi_LogSaveString(smb_logp,machine));
6400 osi_LogEvent("AFS smb_FindCMUserByName : Found",NULL,"name[%s] machine[%s]",usern,machine);