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 if (smb_StoreAnsiFilenames)
940 OemToChar(pathp,pathp);
941 servicep = smb_ParseString(tp, &tp);
943 tp = strrchr(pathp, '\\');
945 return CM_ERROR_BADSMB;
947 strcpy(shareName, tp+1);
949 osi_Log2(smb_logp, "Tree connect pathp[%s] shareName[%s]",
950 osi_LogSaveString(smb_logp, pathp),
951 osi_LogSaveString(smb_logp, shareName));
953 if (strcmp(servicep, "IPC") == 0 || strcmp(shareName, "IPC$") == 0) {
955 osi_Log0(smb_logp, "TreeConnectX connecting to IPC$");
958 return CM_ERROR_NOIPC;
962 userp = smb_GetUser(vcp, inp);
964 lock_ObtainMutex(&vcp->mx);
965 newTid = vcp->tidCounter++;
966 lock_ReleaseMutex(&vcp->mx);
968 tidp = smb_FindTID(vcp, newTid, SMB_FLAG_CREATE);
971 uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
972 shareFound = smb_FindShare(vcp, uidp, shareName, &sharePath);
974 smb_ReleaseUID(uidp);
976 smb_ReleaseTID(tidp);
977 return CM_ERROR_BADSHARENAME;
980 if (vcp->flags & SMB_VCFLAG_USENT)
982 int policy = smb_FindShareCSCPolicy(shareName);
983 smb_SetSMBParm(outp, 2, SMB_SUPPORT_SEARCH_BITS | (policy << 2));
986 smb_SetSMBParm(outp, 2, 0);
990 lock_ObtainMutex(&tidp->mx);
992 tidp->pathname = sharePath;
993 if(ipc) tidp->flags |= SMB_TIDFLAG_IPC;
994 lock_ReleaseMutex(&tidp->mx);
995 smb_ReleaseTID(tidp);
997 ((smb_t *)outp)->tid = newTid;
998 ((smb_t *)inp)->tid = newTid;
999 tp = smb_GetSMBData(outp, NULL);
1004 smb_SetSMBDataLength(outp, 3);
1007 smb_SetSMBDataLength(outp, 4);
1010 osi_Log1(smb_logp, "SMB3 tree connect created ID %d", newTid);
1014 /* must be called with global tran lock held */
1015 smb_tran2Packet_t *smb_FindTran2Packet(smb_vc_t *vcp, smb_packet_t *inp)
1017 smb_tran2Packet_t *tp;
1020 smbp = (smb_t *) inp->data;
1021 for (tp = smb_tran2AssemblyQueuep; tp; tp = (smb_tran2Packet_t *) osi_QNext(&tp->q)) {
1022 if (tp->vcp == vcp && tp->mid == smbp->mid && tp->tid == smbp->tid)
1028 smb_tran2Packet_t *smb_NewTran2Packet(smb_vc_t *vcp, smb_packet_t *inp,
1029 int totalParms, int totalData)
1031 smb_tran2Packet_t *tp;
1034 smbp = (smb_t *) inp->data;
1035 tp = malloc(sizeof(*tp));
1036 memset(tp, 0, sizeof(*tp));
1039 tp->curData = tp->curParms = 0;
1040 tp->totalData = totalData;
1041 tp->totalParms = totalParms;
1042 tp->tid = smbp->tid;
1043 tp->mid = smbp->mid;
1044 tp->uid = smbp->uid;
1045 tp->pid = smbp->pid;
1046 tp->res[0] = smbp->res[0];
1047 osi_QAdd((osi_queue_t **)&smb_tran2AssemblyQueuep, &tp->q);
1048 if (totalParms != 0)
1049 tp->parmsp = malloc(totalParms);
1051 tp->datap = malloc(totalData);
1052 if (smbp->com == 0x25 || smbp->com == 0x26)
1055 tp->opcode = smb_GetSMBParm(inp, 14);
1058 tp->flags |= SMB_TRAN2PFLAG_ALLOC;
1062 smb_tran2Packet_t *smb_GetTran2ResponsePacket(smb_vc_t *vcp,
1063 smb_tran2Packet_t *inp, smb_packet_t *outp,
1064 int totalParms, int totalData)
1066 smb_tran2Packet_t *tp;
1067 unsigned short parmOffset;
1068 unsigned short dataOffset;
1069 unsigned short dataAlign;
1071 tp = malloc(sizeof(*tp));
1072 memset(tp, 0, sizeof(*tp));
1074 tp->curData = tp->curParms = 0;
1075 tp->totalData = totalData;
1076 tp->totalParms = totalParms;
1077 tp->oldTotalParms = totalParms;
1082 tp->res[0] = inp->res[0];
1083 tp->opcode = inp->opcode;
1087 * We calculate where the parameters and data will start.
1088 * This calculation must parallel the calculation in
1089 * smb_SendTran2Packet.
1092 parmOffset = 10*2 + 35;
1093 parmOffset++; /* round to even */
1094 tp->parmsp = (unsigned short *) (outp->data + parmOffset);
1096 dataOffset = parmOffset + totalParms;
1097 dataAlign = dataOffset & 2; /* quad-align */
1098 dataOffset += dataAlign;
1099 tp->datap = outp->data + dataOffset;
1104 /* free a tran2 packet; must be called with smb_globalLock held */
1105 void smb_FreeTran2Packet(smb_tran2Packet_t *t2p)
1107 if (t2p->vcp) smb_ReleaseVC(t2p->vcp);
1108 if (t2p->flags & SMB_TRAN2PFLAG_ALLOC) {
1117 /* called with a VC, an input packet to respond to, and an error code.
1118 * sends an error response.
1120 void smb_SendTran2Error(smb_vc_t *vcp, smb_tran2Packet_t *t2p,
1121 smb_packet_t *tp, long code)
1124 unsigned short errCode;
1125 unsigned char errClass;
1126 unsigned long NTStatus;
1128 if (vcp->flags & SMB_VCFLAG_STATUS32)
1129 smb_MapNTError(code, &NTStatus);
1131 smb_MapCoreError(code, vcp, &errCode, &errClass);
1133 smb_FormatResponsePacket(vcp, NULL, tp);
1134 smbp = (smb_t *) tp;
1136 /* We can handle long names */
1137 if (vcp->flags & SMB_VCFLAG_USENT)
1138 smbp->flg2 |= 0x40; /* IS_LONG_NAME */
1140 /* now copy important fields from the tran 2 packet */
1141 smbp->com = t2p->com;
1142 smbp->tid = t2p->tid;
1143 smbp->mid = t2p->mid;
1144 smbp->pid = t2p->pid;
1145 smbp->uid = t2p->uid;
1146 smbp->res[0] = t2p->res[0];
1147 if (vcp->flags & SMB_VCFLAG_STATUS32) {
1148 smbp->rcls = (unsigned char) (NTStatus & 0xff);
1149 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
1150 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
1151 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
1152 smbp->flg2 |= 0x4000;
1155 smbp->rcls = errClass;
1156 smbp->errLow = (unsigned char) (errCode & 0xff);
1157 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
1161 smb_SendPacket(vcp, tp);
1164 void smb_SendTran2Packet(smb_vc_t *vcp, smb_tran2Packet_t *t2p, smb_packet_t *tp)
1167 unsigned short parmOffset;
1168 unsigned short dataOffset;
1169 unsigned short totalLength;
1170 unsigned short dataAlign;
1173 smb_FormatResponsePacket(vcp, NULL, tp);
1174 smbp = (smb_t *) tp;
1176 /* We can handle long names */
1177 if (vcp->flags & SMB_VCFLAG_USENT)
1178 smbp->flg2 |= 0x40; /* IS_LONG_NAME */
1180 /* now copy important fields from the tran 2 packet */
1181 smbp->com = t2p->com;
1182 smbp->tid = t2p->tid;
1183 smbp->mid = t2p->mid;
1184 smbp->pid = t2p->pid;
1185 smbp->uid = t2p->uid;
1186 smbp->res[0] = t2p->res[0];
1188 totalLength = 1 + t2p->totalData + t2p->totalParms;
1190 /* now add the core parameters (tran2 info) to the packet */
1191 smb_SetSMBParm(tp, 0, t2p->totalParms); /* parm bytes */
1192 smb_SetSMBParm(tp, 1, t2p->totalData); /* data bytes */
1193 smb_SetSMBParm(tp, 2, 0); /* reserved */
1194 smb_SetSMBParm(tp, 3, t2p->totalParms); /* parm bytes in this packet */
1195 parmOffset = 10*2 + 35; /* parm offset in packet */
1196 parmOffset++; /* round to even */
1197 smb_SetSMBParm(tp, 4, parmOffset); /* 11 parm words plus *
1198 * hdr, bcc and wct */
1199 smb_SetSMBParm(tp, 5, 0); /* parm displacement */
1200 smb_SetSMBParm(tp, 6, t2p->totalData); /* data in this packet */
1201 dataOffset = parmOffset + t2p->oldTotalParms;
1202 dataAlign = dataOffset & 2; /* quad-align */
1203 dataOffset += dataAlign;
1204 smb_SetSMBParm(tp, 7, dataOffset); /* offset of data */
1205 smb_SetSMBParm(tp, 8, 0); /* data displacement */
1206 smb_SetSMBParm(tp, 9, 0); /* low: setup word count *
1209 datap = smb_GetSMBData(tp, NULL);
1210 *datap++ = 0; /* we rounded to even */
1212 totalLength += dataAlign;
1213 smb_SetSMBDataLength(tp, totalLength);
1215 /* next, send the datagram */
1216 smb_SendPacket(vcp, tp);
1219 long smb_ReceiveV3Trans(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
1221 smb_tran2Packet_t *asp;
1234 /* We sometimes see 0 word count. What to do? */
1235 if (*inp->wctp == 0) {
1240 osi_Log0(smb_logp, "TRANSACTION word count = 0");
1242 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
1243 ptbuf[0] = "Transaction2 word count = 0";
1244 ReportEvent(h, EVENTLOG_WARNING_TYPE, 0, 1003, NULL,
1245 1, inp->ncb_length, ptbuf, inp);
1246 DeregisterEventSource(h);
1248 osi_Log0(smb_logp, "TRANSACTION word count = 0");
1251 smb_SetSMBDataLength(outp, 0);
1252 smb_SendPacket(vcp, outp);
1256 totalParms = smb_GetSMBParm(inp, 0);
1257 totalData = smb_GetSMBParm(inp, 1);
1259 firstPacket = (inp->inCom == 0x25);
1261 /* find the packet we're reassembling */
1262 lock_ObtainWrite(&smb_globalLock);
1263 asp = smb_FindTran2Packet(vcp, inp);
1265 asp = smb_NewTran2Packet(vcp, inp, totalParms, totalData);
1267 lock_ReleaseWrite(&smb_globalLock);
1269 /* now merge in this latest packet; start by looking up offsets */
1271 parmDisp = dataDisp = 0;
1272 parmOffset = smb_GetSMBParm(inp, 10);
1273 dataOffset = smb_GetSMBParm(inp, 12);
1274 parmCount = smb_GetSMBParm(inp, 9);
1275 dataCount = smb_GetSMBParm(inp, 11);
1276 asp->maxReturnParms = smb_GetSMBParm(inp, 2);
1277 asp->maxReturnData = smb_GetSMBParm(inp, 3);
1279 osi_Log3(smb_logp, "SMB3 received Trans init packet total data %d, cur data %d, max return data %d",
1280 totalData, dataCount, asp->maxReturnData);
1283 parmDisp = smb_GetSMBParm(inp, 4);
1284 parmOffset = smb_GetSMBParm(inp, 3);
1285 dataDisp = smb_GetSMBParm(inp, 7);
1286 dataOffset = smb_GetSMBParm(inp, 6);
1287 parmCount = smb_GetSMBParm(inp, 2);
1288 dataCount = smb_GetSMBParm(inp, 5);
1290 osi_Log2(smb_logp, "SMB3 received Trans aux packet parms %d, data %d",
1291 parmCount, dataCount);
1294 /* now copy the parms and data */
1295 if ( asp->totalParms > 0 && parmCount != 0 )
1297 memcpy(((char *)asp->parmsp) + parmDisp, inp->data + parmOffset, parmCount);
1299 if ( asp->totalData > 0 && dataCount != 0 ) {
1300 memcpy(asp->datap + dataDisp, inp->data + dataOffset, dataCount);
1303 /* account for new bytes */
1304 asp->curData += dataCount;
1305 asp->curParms += parmCount;
1307 /* finally, if we're done, remove the packet from the queue and dispatch it */
1308 if (asp->totalParms > 0 &&
1309 asp->curParms > 0 &&
1310 asp->totalData <= asp->curData &&
1311 asp->totalParms <= asp->curParms) {
1312 /* we've received it all */
1313 lock_ObtainWrite(&smb_globalLock);
1314 osi_QRemove((osi_queue_t **) &smb_tran2AssemblyQueuep, &asp->q);
1315 lock_ReleaseWrite(&smb_globalLock);
1317 /* now dispatch it */
1318 rapOp = asp->parmsp[0];
1320 if ( rapOp >= 0 && rapOp < SMB_RAP_NOPCODES && smb_rapDispatchTable[rapOp].procp) {
1321 osi_LogEvent("AFS-Dispatch-RAP[%s]",myCrt_RapDispatch(rapOp),"vcp[%x] lana[%d] lsn[%d]",(int)vcp,vcp->lana,vcp->lsn);
1322 osi_Log4(smb_logp,"AFS Server - Dispatch-RAP %s vcp[%x] lana[%d] lsn[%d]",myCrt_RapDispatch(rapOp),vcp,vcp->lana,vcp->lsn);
1323 code = (*smb_rapDispatchTable[rapOp].procp)(vcp, asp, outp);
1326 osi_LogEvent("AFS-Dispatch-RAP [invalid]", NULL, "op[%x] vcp[%x] lana[%d] lsn[%d]", rapOp, vcp, vcp->lana, vcp->lsn);
1327 osi_Log4(smb_logp,"AFS Server - Dispatch-RAP [INVALID] op[%x] vcp[%x] lana[%d] lsn[%d]", rapOp, vcp, vcp->lana, vcp->lsn);
1328 code = CM_ERROR_BADOP;
1331 /* if an error is returned, we're supposed to send an error packet,
1332 * otherwise the dispatched function already did the data sending.
1333 * We give dispatched proc the responsibility since it knows how much
1334 * space to allocate.
1337 smb_SendTran2Error(vcp, asp, outp, code);
1340 /* free the input tran 2 packet */
1341 lock_ObtainWrite(&smb_globalLock);
1342 smb_FreeTran2Packet(asp);
1343 lock_ReleaseWrite(&smb_globalLock);
1345 else if (firstPacket) {
1346 /* the first packet in a multi-packet request, we need to send an
1347 * ack to get more data.
1349 smb_SetSMBDataLength(outp, 0);
1350 smb_SendPacket(vcp, outp);
1356 /* ANSI versions. The unicode versions support arbitrary length
1357 share names, but we don't support unicode yet. */
1359 typedef struct smb_rap_share_info_0 {
1360 char shi0_netname[13];
1361 } smb_rap_share_info_0_t;
1363 typedef struct smb_rap_share_info_1 {
1364 char shi1_netname[13];
1367 DWORD shi1_remark; /* char *shi1_remark; data offset */
1368 } smb_rap_share_info_1_t;
1370 typedef struct smb_rap_share_info_2 {
1371 char shi2_netname[13];
1373 unsigned short shi2_type;
1374 DWORD shi2_remark; /* char *shi2_remark; data offset */
1375 unsigned short shi2_permissions;
1376 unsigned short shi2_max_uses;
1377 unsigned short shi2_current_uses;
1378 DWORD shi2_path; /* char *shi2_path; data offset */
1379 unsigned short shi2_passwd[9];
1380 unsigned short shi2_pad2;
1381 } smb_rap_share_info_2_t;
1383 #define SMB_RAP_MAX_SHARES 512
1385 typedef struct smb_rap_share_list {
1388 smb_rap_share_info_0_t * shares;
1389 } smb_rap_share_list_t;
1391 int smb_rapCollectSharesProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp) {
1392 smb_rap_share_list_t * sp;
1397 if (name[0] == '.' && (!name[1] || (name[1] == '.' && !name[2])))
1398 return 0; /* skip over '.' and '..' */
1400 sp = (smb_rap_share_list_t *) vrockp;
1402 strncpy(sp->shares[sp->cShare].shi0_netname, name, 12);
1403 sp->shares[sp->cShare].shi0_netname[12] = 0;
1407 if (sp->cShare >= sp->maxShares)
1408 return CM_ERROR_STOPNOW;
1413 long smb_ReceiveRAPNetShareEnum(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1415 smb_tran2Packet_t *outp;
1416 unsigned short * tp;
1420 int outParmsTotal; /* total parameter bytes */
1421 int outDataTotal; /* total data bytes */
1429 HKEY hkSubmount = NULL;
1430 smb_rap_share_info_1_t * shares;
1433 char thisShare[256];
1436 smb_rap_share_list_t rootShares;
1441 tp = p->parmsp + 1; /* skip over function number (always 0) */
1442 (void) smb_ParseString((char *) tp, (char **) &tp); /* skip over parm descriptor */
1443 (void) smb_ParseString((char *) tp, (char **) &tp); /* skip over data descriptor */
1447 if (infoLevel != 1) {
1448 return CM_ERROR_INVAL;
1451 /* first figure out how many shares there are */
1452 rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSConfigKeyName, 0,
1453 KEY_QUERY_VALUE, &hkParam);
1454 if (rv == ERROR_SUCCESS) {
1455 len = sizeof(allSubmount);
1456 rv = RegQueryValueEx(hkParam, "AllSubmount", NULL, NULL,
1457 (BYTE *) &allSubmount, &len);
1458 if (rv != ERROR_SUCCESS || allSubmount != 0) {
1461 RegCloseKey (hkParam);
1464 rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SOFTWARE\\OpenAFS\\Client\\Submounts",
1465 0, KEY_QUERY_VALUE, &hkSubmount);
1466 if (rv == ERROR_SUCCESS) {
1467 rv = RegQueryInfoKey(hkSubmount, NULL, NULL, NULL, NULL,
1468 NULL, NULL, &nRegShares, NULL, NULL, NULL, NULL);
1469 if (rv != ERROR_SUCCESS)
1475 /* fetch the root shares */
1476 rootShares.maxShares = SMB_RAP_MAX_SHARES;
1477 rootShares.cShare = 0;
1478 rootShares.shares = malloc( sizeof(smb_rap_share_info_0_t) * SMB_RAP_MAX_SHARES );
1482 userp = smb_GetTran2User(vcp,p);
1484 thyper.HighPart = 0;
1487 cm_HoldSCache(cm_rootSCachep);
1488 cm_ApplyDir(cm_rootSCachep, smb_rapCollectSharesProc, &rootShares, &thyper, userp, &req, NULL);
1489 cm_ReleaseSCache(cm_rootSCachep);
1491 cm_ReleaseUser(userp);
1493 nShares = rootShares.cShare + nRegShares + allSubmount;
1495 #define REMARK_LEN 1
1496 outParmsTotal = 8; /* 4 dwords */
1497 outDataTotal = (sizeof(smb_rap_share_info_1_t) + REMARK_LEN) * nShares ;
1498 if(outDataTotal > bufsize) {
1499 nSharesRet = bufsize / (sizeof(smb_rap_share_info_1_t) + REMARK_LEN);
1500 outDataTotal = (sizeof(smb_rap_share_info_1_t) + REMARK_LEN) * nSharesRet;
1503 nSharesRet = nShares;
1506 outp = smb_GetTran2ResponsePacket(vcp, p, op, outParmsTotal, outDataTotal);
1508 /* now for the submounts */
1509 shares = (smb_rap_share_info_1_t *) outp->datap;
1510 cstrp = outp->datap + sizeof(smb_rap_share_info_1_t) * nSharesRet;
1512 memset(outp->datap, 0, (sizeof(smb_rap_share_info_1_t) + REMARK_LEN) * nSharesRet);
1515 strcpy( shares[cshare].shi1_netname, "all" );
1516 shares[cshare].shi1_remark = cstrp - outp->datap;
1517 /* type and pad are zero already */
1523 for (i=0; i < nRegShares && cshare < nSharesRet; i++) {
1524 len = sizeof(thisShare);
1525 rv = RegEnumValue(hkSubmount, i, thisShare, &len, NULL, NULL, NULL, NULL);
1526 if (rv == ERROR_SUCCESS && strlen(thisShare) && (!allSubmount || stricmp(thisShare,"all"))) {
1527 strncpy(shares[cshare].shi1_netname, thisShare, sizeof(shares->shi1_netname)-1);
1528 shares[cshare].shi1_netname[sizeof(shares->shi1_netname)-1] = 0; /* unfortunate truncation */
1529 shares[cshare].shi1_remark = cstrp - outp->datap;
1534 nShares--; /* uncount key */
1537 RegCloseKey(hkSubmount);
1540 nonrootShares = cshare;
1542 for (i=0; i < rootShares.cShare && cshare < nSharesRet; i++) {
1543 /* in case there are collisions with submounts, submounts have higher priority */
1544 for (j=0; j < nonrootShares; j++)
1545 if (!stricmp(shares[j].shi1_netname, rootShares.shares[i].shi0_netname))
1548 if (j < nonrootShares) {
1549 nShares--; /* uncount */
1553 strcpy(shares[cshare].shi1_netname, rootShares.shares[i].shi0_netname);
1554 shares[cshare].shi1_remark = cstrp - outp->datap;
1559 outp->parmsp[0] = ((cshare == nShares)? ERROR_SUCCESS : ERROR_MORE_DATA);
1560 outp->parmsp[1] = 0;
1561 outp->parmsp[2] = cshare;
1562 outp->parmsp[3] = nShares;
1564 outp->totalData = cstrp - outp->datap;
1565 outp->totalParms = outParmsTotal;
1567 smb_SendTran2Packet(vcp, outp, op);
1568 smb_FreeTran2Packet(outp);
1570 free(rootShares.shares);
1575 long smb_ReceiveRAPNetShareGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1577 smb_tran2Packet_t *outp;
1578 unsigned short * tp;
1580 BOOL shareFound = FALSE;
1581 unsigned short infoLevel;
1582 unsigned short bufsize;
1592 tp = p->parmsp + 1; /* skip over function number (always 1) */
1593 (void) smb_ParseString( (char *) tp, (char **) &tp); /* skip over param descriptor */
1594 (void) smb_ParseString( (char *) tp, (char **) &tp); /* skip over data descriptor */
1595 shareName = smb_ParseString( (char *) tp, (char **) &tp);
1602 totalData = sizeof(smb_rap_share_info_0_t);
1603 else if(infoLevel == 1)
1604 totalData = sizeof(smb_rap_share_info_1_t) + 1; /* + empty string */
1605 else if(infoLevel == 2)
1606 totalData = sizeof(smb_rap_share_info_2_t) + 2; /* + two empty strings */
1608 return CM_ERROR_INVAL;
1610 outp = smb_GetTran2ResponsePacket(vcp, p, op, totalParam, totalData);
1612 if(!stricmp(shareName,"all")) {
1613 rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSConfigKeyName, 0,
1614 KEY_QUERY_VALUE, &hkParam);
1615 if (rv == ERROR_SUCCESS) {
1616 len = sizeof(allSubmount);
1617 rv = RegQueryValueEx(hkParam, "AllSubmount", NULL, NULL,
1618 (BYTE *) &allSubmount, &len);
1619 if (rv != ERROR_SUCCESS || allSubmount != 0) {
1622 RegCloseKey (hkParam);
1629 rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SOFTWARE\\OpenAFS\\Client\\Submounts", 0,
1630 KEY_QUERY_VALUE, &hkSubmount);
1631 if (rv == ERROR_SUCCESS) {
1632 rv = RegQueryValueEx(hkSubmount, shareName, NULL, NULL, NULL, NULL);
1633 if (rv == ERROR_SUCCESS) {
1636 RegCloseKey(hkSubmount);
1641 smb_FreeTran2Packet(outp);
1642 return CM_ERROR_BADSHARENAME;
1645 memset(outp->datap, 0, totalData);
1647 outp->parmsp[0] = 0;
1648 outp->parmsp[1] = 0;
1649 outp->parmsp[2] = totalData;
1651 if (infoLevel == 0) {
1652 smb_rap_share_info_0_t * info = (smb_rap_share_info_0_t *) outp->datap;
1653 strncpy(info->shi0_netname, shareName, sizeof(info->shi0_netname)-1);
1654 info->shi0_netname[sizeof(info->shi0_netname)-1] = 0;
1655 } else if(infoLevel == 1) {
1656 smb_rap_share_info_1_t * info = (smb_rap_share_info_1_t *) outp->datap;
1657 strncpy(info->shi1_netname, shareName, sizeof(info->shi1_netname)-1);
1658 info->shi1_netname[sizeof(info->shi1_netname)-1] = 0;
1659 info->shi1_remark = ((unsigned char *) (info + 1)) - outp->datap;
1660 /* type and pad are already zero */
1661 } else { /* infoLevel==2 */
1662 smb_rap_share_info_2_t * info = (smb_rap_share_info_2_t *) outp->datap;
1663 strncpy(info->shi2_netname, shareName, sizeof(info->shi2_netname)-1);
1664 info->shi2_netname[sizeof(info->shi2_netname)-1] = 0;
1665 info->shi2_remark = ((unsigned char *) (info + 1)) - outp->datap;
1666 info->shi2_permissions = ACCESS_ALL;
1667 info->shi2_max_uses = (unsigned short) -1;
1668 info->shi2_path = 1 + (((unsigned char *) (info + 1)) - outp->datap);
1671 outp->totalData = totalData;
1672 outp->totalParms = totalParam;
1674 smb_SendTran2Packet(vcp, outp, op);
1675 smb_FreeTran2Packet(outp);
1680 typedef struct smb_rap_wksta_info_10 {
1681 DWORD wki10_computername; /*char *wki10_computername;*/
1682 DWORD wki10_username; /* char *wki10_username; */
1683 DWORD wki10_langroup; /* char *wki10_langroup;*/
1684 unsigned char wki10_ver_major;
1685 unsigned char wki10_ver_minor;
1686 DWORD wki10_logon_domain; /*char *wki10_logon_domain;*/
1687 DWORD wki10_oth_domains; /* char *wki10_oth_domains;*/
1688 } smb_rap_wksta_info_10_t;
1691 long smb_ReceiveRAPNetWkstaGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1693 smb_tran2Packet_t *outp;
1697 unsigned short * tp;
1700 smb_rap_wksta_info_10_t * info;
1704 tp = p->parmsp + 1; /* Skip over function number */
1705 (void) smb_ParseString((unsigned char*) tp, (char **) &tp); /* skip over param descriptor */
1706 (void) smb_ParseString((unsigned char*) tp, (char **) &tp); /* skip over data descriptor */
1710 if (infoLevel != 10) {
1711 return CM_ERROR_INVAL;
1717 totalData = sizeof(*info) + /* info */
1718 MAX_COMPUTERNAME_LENGTH + /* wki10_computername */
1719 SMB_MAX_USERNAME_LENGTH + /* wki10_username */
1720 MAX_COMPUTERNAME_LENGTH + /* wki10_langroup */
1721 MAX_COMPUTERNAME_LENGTH + /* wki10_logon_domain */
1722 1; /* wki10_oth_domains (null)*/
1724 outp = smb_GetTran2ResponsePacket(vcp, p, op, totalParams, totalData);
1726 memset(outp->parmsp,0,totalParams);
1727 memset(outp->datap,0,totalData);
1729 info = (smb_rap_wksta_info_10_t *) outp->datap;
1730 cstrp = (char *) (info + 1);
1732 info->wki10_computername = (DWORD) (cstrp - outp->datap);
1733 strcpy(cstrp, smb_localNamep);
1734 cstrp += strlen(cstrp) + 1;
1736 info->wki10_username = (DWORD) (cstrp - outp->datap);
1737 uidp = smb_FindUID(vcp, p->uid, 0);
1739 lock_ObtainMutex(&uidp->mx);
1740 if(uidp->unp && uidp->unp->name)
1741 strcpy(cstrp, uidp->unp->name);
1742 lock_ReleaseMutex(&uidp->mx);
1743 smb_ReleaseUID(uidp);
1745 cstrp += strlen(cstrp) + 1;
1747 info->wki10_langroup = (DWORD) (cstrp - outp->datap);
1748 strcpy(cstrp, "WORKGROUP");
1749 cstrp += strlen(cstrp) + 1;
1751 /* TODO: Not sure what values these should take, but these work */
1752 info->wki10_ver_major = 5;
1753 info->wki10_ver_minor = 1;
1755 info->wki10_logon_domain = (DWORD) (cstrp - outp->datap);
1756 strcpy(cstrp, smb_ServerDomainName);
1757 cstrp += strlen(cstrp) + 1;
1759 info->wki10_oth_domains = (DWORD) (cstrp - outp->datap);
1760 cstrp ++; /* no other domains */
1762 outp->totalData = (unsigned short) (cstrp - outp->datap); /* actual data size */
1763 outp->parmsp[2] = outp->totalData;
1764 outp->totalParms = totalParams;
1766 smb_SendTran2Packet(vcp,outp,op);
1767 smb_FreeTran2Packet(outp);
1772 typedef struct smb_rap_server_info_0 {
1774 } smb_rap_server_info_0_t;
1776 typedef struct smb_rap_server_info_1 {
1778 char sv1_version_major;
1779 char sv1_version_minor;
1780 unsigned long sv1_type;
1781 DWORD *sv1_comment_or_master_browser; /* char *sv1_comment_or_master_browser;*/
1782 } smb_rap_server_info_1_t;
1784 char smb_ServerComment[] = "OpenAFS Client";
1785 int smb_ServerCommentLen = sizeof(smb_ServerComment);
1787 #define SMB_SV_TYPE_SERVER 0x00000002L
1788 #define SMB_SV_TYPE_NT 0x00001000L
1789 #define SMB_SV_TYPE_SERVER_NT 0x00008000L
1791 long smb_ReceiveRAPNetServerGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1793 smb_tran2Packet_t *outp;
1797 unsigned short * tp;
1800 smb_rap_server_info_0_t * info0;
1801 smb_rap_server_info_1_t * info1;
1804 tp = p->parmsp + 1; /* Skip over function number */
1805 (void) smb_ParseString((unsigned char*) tp, (char **) &tp); /* skip over param descriptor */
1806 (void) smb_ParseString((unsigned char*) tp, (char **) &tp); /* skip over data descriptor */
1810 if (infoLevel != 0 && infoLevel != 1) {
1811 return CM_ERROR_INVAL;
1817 (infoLevel == 0) ? sizeof(smb_rap_server_info_0_t)
1818 : (sizeof(smb_rap_server_info_1_t) + smb_ServerCommentLen);
1820 outp = smb_GetTran2ResponsePacket(vcp, p, op, totalParams, totalData);
1822 memset(outp->parmsp,0,totalParams);
1823 memset(outp->datap,0,totalData);
1825 if (infoLevel == 0) {
1826 info0 = (smb_rap_server_info_0_t *) outp->datap;
1827 cstrp = (char *) (info0 + 1);
1828 strcpy(info0->sv0_name, "AFS");
1829 } else { /* infoLevel == 1 */
1830 info1 = (smb_rap_server_info_1_t *) outp->datap;
1831 cstrp = (char *) (info1 + 1);
1832 strcpy(info1->sv1_name, "AFS");
1835 SMB_SV_TYPE_SERVER |
1837 SMB_SV_TYPE_SERVER_NT;
1839 info1->sv1_version_major = 5;
1840 info1->sv1_version_minor = 1;
1841 info1->sv1_comment_or_master_browser = (DWORD *) (cstrp - outp->datap);
1843 strcpy(cstrp, smb_ServerComment);
1845 cstrp += smb_ServerCommentLen;
1848 totalData = cstrp - outp->datap;
1849 outp->totalData = min(bufsize,totalData); /* actual data size */
1850 outp->parmsp[0] = (outp->totalData == totalData)? 0 : ERROR_MORE_DATA;
1851 outp->parmsp[2] = totalData;
1852 outp->totalParms = totalParams;
1854 smb_SendTran2Packet(vcp,outp,op);
1855 smb_FreeTran2Packet(outp);
1860 long smb_ReceiveV3Tran2A(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
1862 smb_tran2Packet_t *asp;
1874 /* We sometimes see 0 word count. What to do? */
1875 if (*inp->wctp == 0) {
1880 osi_Log0(smb_logp, "TRANSACTION2 word count = 0");
1882 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
1883 ptbuf[0] = "Transaction2 word count = 0";
1884 ReportEvent(h, EVENTLOG_WARNING_TYPE, 0, 1003, NULL,
1885 1, inp->ncb_length, ptbuf, inp);
1886 DeregisterEventSource(h);
1888 osi_Log0(smb_logp, "TRANSACTION2 word count = 0");
1891 smb_SetSMBDataLength(outp, 0);
1892 smb_SendPacket(vcp, outp);
1896 totalParms = smb_GetSMBParm(inp, 0);
1897 totalData = smb_GetSMBParm(inp, 1);
1899 firstPacket = (inp->inCom == 0x32);
1901 /* find the packet we're reassembling */
1902 lock_ObtainWrite(&smb_globalLock);
1903 asp = smb_FindTran2Packet(vcp, inp);
1905 asp = smb_NewTran2Packet(vcp, inp, totalParms, totalData);
1907 lock_ReleaseWrite(&smb_globalLock);
1909 /* now merge in this latest packet; start by looking up offsets */
1911 parmDisp = dataDisp = 0;
1912 parmOffset = smb_GetSMBParm(inp, 10);
1913 dataOffset = smb_GetSMBParm(inp, 12);
1914 parmCount = smb_GetSMBParm(inp, 9);
1915 dataCount = smb_GetSMBParm(inp, 11);
1916 asp->maxReturnParms = smb_GetSMBParm(inp, 2);
1917 asp->maxReturnData = smb_GetSMBParm(inp, 3);
1919 osi_Log3(smb_logp, "SMB3 received T2 init packet total data %d, cur data %d, max return data %d",
1920 totalData, dataCount, asp->maxReturnData);
1923 parmDisp = smb_GetSMBParm(inp, 4);
1924 parmOffset = smb_GetSMBParm(inp, 3);
1925 dataDisp = smb_GetSMBParm(inp, 7);
1926 dataOffset = smb_GetSMBParm(inp, 6);
1927 parmCount = smb_GetSMBParm(inp, 2);
1928 dataCount = smb_GetSMBParm(inp, 5);
1930 osi_Log2(smb_logp, "SMB3 received T2 aux packet parms %d, data %d",
1931 parmCount, dataCount);
1934 /* now copy the parms and data */
1935 if ( asp->totalParms > 0 && parmCount != 0 )
1937 memcpy(((char *)asp->parmsp) + parmDisp, inp->data + parmOffset, parmCount);
1939 if ( asp->totalData > 0 && dataCount != 0 ) {
1940 memcpy(asp->datap + dataDisp, inp->data + dataOffset, dataCount);
1943 /* account for new bytes */
1944 asp->curData += dataCount;
1945 asp->curParms += parmCount;
1947 /* finally, if we're done, remove the packet from the queue and dispatch it */
1948 if (asp->totalParms > 0 &&
1949 asp->curParms > 0 &&
1950 asp->totalData <= asp->curData &&
1951 asp->totalParms <= asp->curParms) {
1952 /* we've received it all */
1953 lock_ObtainWrite(&smb_globalLock);
1954 osi_QRemove((osi_queue_t **) &smb_tran2AssemblyQueuep, &asp->q);
1955 lock_ReleaseWrite(&smb_globalLock);
1957 /* now dispatch it */
1958 if ( asp->opcode >= 0 && asp->opcode < 20 && smb_tran2DispatchTable[asp->opcode].procp) {
1959 osi_LogEvent("AFS-Dispatch-2[%s]",myCrt_2Dispatch(asp->opcode),"vcp[%x] lana[%d] lsn[%d]",(int)vcp,vcp->lana,vcp->lsn);
1960 osi_Log4(smb_logp,"AFS Server - Dispatch-2 %s vcp[%x] lana[%d] lsn[%d]",myCrt_2Dispatch(asp->opcode),vcp,vcp->lana,vcp->lsn);
1961 code = (*smb_tran2DispatchTable[asp->opcode].procp)(vcp, asp, outp);
1964 osi_LogEvent("AFS-Dispatch-2 [invalid]", NULL, "op[%x] vcp[%x] lana[%d] lsn[%d]", asp->opcode, vcp, vcp->lana, vcp->lsn);
1965 osi_Log4(smb_logp,"AFS Server - Dispatch-2 [INVALID] op[%x] vcp[%x] lana[%d] lsn[%d]", asp->opcode, vcp, vcp->lana, vcp->lsn);
1966 code = CM_ERROR_BADOP;
1969 /* if an error is returned, we're supposed to send an error packet,
1970 * otherwise the dispatched function already did the data sending.
1971 * We give dispatched proc the responsibility since it knows how much
1972 * space to allocate.
1975 smb_SendTran2Error(vcp, asp, outp, code);
1978 /* free the input tran 2 packet */
1979 lock_ObtainWrite(&smb_globalLock);
1980 smb_FreeTran2Packet(asp);
1981 lock_ReleaseWrite(&smb_globalLock);
1983 else if (firstPacket) {
1984 /* the first packet in a multi-packet request, we need to send an
1985 * ack to get more data.
1987 smb_SetSMBDataLength(outp, 0);
1988 smb_SendPacket(vcp, outp);
1994 long smb_ReceiveTran2Open(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1997 smb_tran2Packet_t *outp;
2002 cm_scache_t *dscp; /* dir we're dealing with */
2003 cm_scache_t *scp; /* file we're creating */
2005 int initialModeBits;
2015 int parmSlot; /* which parm we're dealing with */
2016 long returnEALength;
2024 extraInfo = (p->parmsp[0] & 1); /* return extra info */
2025 returnEALength = (p->parmsp[0] & 8); /* return extended attr length */
2027 openFun = p->parmsp[6]; /* open function */
2028 excl = ((openFun & 3) == 0);
2029 trunc = ((openFun & 3) == 2); /* truncate it */
2030 openMode = (p->parmsp[1] & 0x7);
2031 openAction = 0; /* tracks what we did */
2033 attributes = p->parmsp[3];
2034 dosTime = p->parmsp[4] | (p->parmsp[5] << 16);
2036 /* compute initial mode bits based on read-only flag in attributes */
2037 initialModeBits = 0666;
2038 if (attributes & 1) initialModeBits &= ~0222;
2040 pathp = (char *) (&p->parmsp[14]);
2041 if (smb_StoreAnsiFilenames)
2042 OemToChar(pathp,pathp);
2044 outp = smb_GetTran2ResponsePacket(vcp, p, op, 40, 0);
2046 spacep = cm_GetSpace();
2047 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
2049 if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
2050 /* special case magic file name for receiving IOCTL requests
2051 * (since IOCTL calls themselves aren't getting through).
2053 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
2054 smb_SetupIoctlFid(fidp, spacep);
2056 /* copy out remainder of the parms */
2058 outp->parmsp[parmSlot] = fidp->fid; parmSlot++;
2060 outp->parmsp[parmSlot] = /* attrs */ 0; parmSlot++;
2061 outp->parmsp[parmSlot] = 0; parmSlot++; /* mod time */
2062 outp->parmsp[parmSlot] = 0; parmSlot++;
2063 outp->parmsp[parmSlot] = 0; parmSlot++; /* len */
2064 outp->parmsp[parmSlot] = 0x7fff; parmSlot++;
2065 outp->parmsp[parmSlot] = openMode; parmSlot++;
2066 outp->parmsp[parmSlot] = 0; parmSlot++; /* file type 0 ==> normal file or dir */
2067 outp->parmsp[parmSlot] = 0; parmSlot++; /* IPC junk */
2069 /* and the final "always present" stuff */
2070 outp->parmsp[parmSlot] = /* openAction found existing file */ 1; parmSlot++;
2071 /* next write out the "unique" ID */
2072 outp->parmsp[parmSlot] = 0x1234; parmSlot++;
2073 outp->parmsp[parmSlot] = 0x5678; parmSlot++;
2074 outp->parmsp[parmSlot] = 0; parmSlot++;
2075 if (returnEALength) {
2076 outp->parmsp[parmSlot] = 0; parmSlot++;
2077 outp->parmsp[parmSlot] = 0; parmSlot++;
2080 outp->totalData = 0;
2081 outp->totalParms = parmSlot * 2;
2083 smb_SendTran2Packet(vcp, outp, op);
2085 smb_FreeTran2Packet(outp);
2087 /* and clean up fid reference */
2088 smb_ReleaseFID(fidp);
2092 #ifdef DEBUG_VERBOSE
2094 char *hexp, *asciip;
2095 asciip = (lastNamep ? lastNamep : pathp);
2096 hexp = osi_HexifyString( asciip );
2097 DEBUG_EVENT2("AFS","T2Open H[%s] A[%s]", hexp, asciip);
2102 userp = smb_GetTran2User(vcp, p);
2103 /* In the off chance that userp is NULL, we log and abandon */
2105 osi_Log1(smb_logp, "ReceiveTran2Open user [%d] not resolvable", p->uid);
2106 smb_FreeTran2Packet(outp);
2107 return CM_ERROR_BADSMB;
2110 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
2111 if (code == CM_ERROR_TIDIPC) {
2112 /* Attempt to use TID allocated for IPC. The client is
2113 probably trying to locate DCE RPC end points, which
2114 we don't support. */
2115 osi_Log0(smb_logp, "Tran2Open received IPC TID");
2116 cm_ReleaseUser(userp);
2117 smb_FreeTran2Packet(outp);
2118 return CM_ERROR_NOSUCHPATH;
2122 code = cm_NameI(cm_rootSCachep, pathp,
2123 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
2124 userp, tidPathp, &req, &scp);
2126 code = cm_NameI(cm_rootSCachep, spacep->data,
2127 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
2128 userp, tidPathp, &req, &dscp);
2129 cm_FreeSpace(spacep);
2132 cm_ReleaseUser(userp);
2133 smb_FreeTran2Packet(outp);
2137 /* otherwise, scp points to the parent directory. Do a lookup,
2138 * and truncate the file if we find it, otherwise we create the
2145 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD, userp,
2147 if (code && code != CM_ERROR_NOSUCHFILE) {
2148 cm_ReleaseSCache(dscp);
2149 cm_ReleaseUser(userp);
2150 smb_FreeTran2Packet(outp);
2155 cm_FreeSpace(spacep);
2158 /* if we get here, if code is 0, the file exists and is represented by
2159 * scp. Otherwise, we have to create it.
2162 code = cm_CheckOpen(scp, openMode, trunc, userp, &req);
2164 if (dscp) cm_ReleaseSCache(dscp);
2165 cm_ReleaseSCache(scp);
2166 cm_ReleaseUser(userp);
2167 smb_FreeTran2Packet(outp);
2172 /* oops, file shouldn't be there */
2173 if (dscp) cm_ReleaseSCache(dscp);
2174 cm_ReleaseSCache(scp);
2175 cm_ReleaseUser(userp);
2176 smb_FreeTran2Packet(outp);
2177 return CM_ERROR_EXISTS;
2181 setAttr.mask = CM_ATTRMASK_LENGTH;
2182 setAttr.length.LowPart = 0;
2183 setAttr.length.HighPart = 0;
2184 code = cm_SetAttr(scp, &setAttr, userp, &req);
2185 openAction = 3; /* truncated existing file */
2188 openAction = 1; /* found existing file */
2190 else if (!(openFun & SMB_ATTR_DIRECTORY)) {
2191 /* don't create if not found */
2192 if (dscp) cm_ReleaseSCache(dscp);
2193 osi_assert(scp == NULL);
2194 cm_ReleaseUser(userp);
2195 smb_FreeTran2Packet(outp);
2196 return CM_ERROR_NOSUCHFILE;
2199 osi_assert(dscp != NULL && scp == NULL);
2200 openAction = 2; /* created file */
2201 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
2202 smb_UnixTimeFromSearchTime(&setAttr.clientModTime, dosTime);
2203 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
2205 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
2206 smb_NotifyChange(FILE_ACTION_ADDED,
2207 FILE_NOTIFY_CHANGE_FILE_NAME,
2208 dscp, lastNamep, NULL, TRUE);
2209 if (!excl && code == CM_ERROR_EXISTS) {
2210 /* not an exclusive create, and someone else tried
2211 * creating it already, then we open it anyway. We
2212 * don't bother retrying after this, since if this next
2213 * fails, that means that the file was deleted after we
2214 * started this call.
2216 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
2220 setAttr.mask = CM_ATTRMASK_LENGTH;
2221 setAttr.length.LowPart = 0;
2222 setAttr.length.HighPart = 0;
2223 code = cm_SetAttr(scp, &setAttr, userp,
2226 } /* lookup succeeded */
2230 /* we don't need this any longer */
2231 if (dscp) cm_ReleaseSCache(dscp);
2234 /* something went wrong creating or truncating the file */
2235 if (scp) cm_ReleaseSCache(scp);
2236 cm_ReleaseUser(userp);
2237 smb_FreeTran2Packet(outp);
2241 /* make sure we're about to open a file */
2242 if (scp->fileType != CM_SCACHETYPE_FILE) {
2244 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
2245 cm_scache_t * targetScp = 0;
2246 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
2248 /* we have a more accurate file to use (the
2249 * target of the symbolic link). Otherwise,
2250 * we'll just use the symlink anyway.
2252 osi_Log2(smb_logp, "symlink vp %x to vp %x",
2254 cm_ReleaseSCache(scp);
2258 if (scp->fileType != CM_SCACHETYPE_FILE) {
2259 cm_ReleaseSCache(scp);
2260 cm_ReleaseUser(userp);
2261 smb_FreeTran2Packet(outp);
2262 return CM_ERROR_ISDIR;
2266 /* now all we have to do is open the file itself */
2267 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
2270 /* save a pointer to the vnode */
2273 /* compute open mode */
2274 if (openMode != 1) fidp->flags |= SMB_FID_OPENREAD;
2275 if (openMode == 1 || openMode == 2)
2276 fidp->flags |= SMB_FID_OPENWRITE;
2278 smb_ReleaseFID(fidp);
2280 cm_Open(scp, 0, userp);
2282 /* copy out remainder of the parms */
2284 outp->parmsp[parmSlot] = fidp->fid; parmSlot++;
2285 lock_ObtainMutex(&scp->mx);
2287 outp->parmsp[parmSlot] = smb_Attributes(scp); parmSlot++;
2288 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
2289 outp->parmsp[parmSlot] = (unsigned short)(dosTime & 0xffff); parmSlot++;
2290 outp->parmsp[parmSlot] = (unsigned short)((dosTime>>16) & 0xffff); parmSlot++;
2291 outp->parmsp[parmSlot] = (unsigned short) (scp->length.LowPart & 0xffff);
2293 outp->parmsp[parmSlot] = (unsigned short) ((scp->length.LowPart >> 16) & 0xffff);
2295 outp->parmsp[parmSlot] = openMode; parmSlot++;
2296 outp->parmsp[parmSlot] = 0; parmSlot++; /* file type 0 ==> normal file or dir */
2297 outp->parmsp[parmSlot] = 0; parmSlot++; /* IPC junk */
2299 /* and the final "always present" stuff */
2300 outp->parmsp[parmSlot] = openAction; parmSlot++;
2301 /* next write out the "unique" ID */
2302 outp->parmsp[parmSlot] = (unsigned short) (scp->fid.vnode & 0xffff); parmSlot++;
2303 outp->parmsp[parmSlot] = (unsigned short) (scp->fid.volume & 0xffff); parmSlot++;
2304 outp->parmsp[parmSlot] = 0; parmSlot++;
2305 if (returnEALength) {
2306 outp->parmsp[parmSlot] = 0; parmSlot++;
2307 outp->parmsp[parmSlot] = 0; parmSlot++;
2309 lock_ReleaseMutex(&scp->mx);
2310 outp->totalData = 0; /* total # of data bytes */
2311 outp->totalParms = parmSlot * 2; /* shorts are two bytes */
2313 smb_SendTran2Packet(vcp, outp, op);
2315 smb_FreeTran2Packet(outp);
2317 cm_ReleaseUser(userp);
2318 /* leave scp held since we put it in fidp->scp */
2322 long smb_ReceiveTran2FindFirst(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
2324 osi_Log0(smb_logp,"ReceiveTran2FindFirst - NOT_SUPPORTED");
2325 return CM_ERROR_BADOP;
2328 long smb_ReceiveTran2FindNext(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
2330 osi_Log0(smb_logp,"ReceiveTran2FindNext - NOT_SUPPORTED");
2331 return CM_ERROR_BADOP;
2334 long smb_ReceiveTran2QFSInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
2336 smb_tran2Packet_t *outp;
2337 smb_tran2QFSInfo_t qi;
2340 static char FSname[6] = {'A', 0, 'F', 0, 'S', 0};
2342 osi_Log1(smb_logp, "T2 QFSInfo type 0x%x", p->parmsp[0]);
2344 switch (p->parmsp[0]) {
2345 case 1: responseSize = sizeof(qi.u.allocInfo); break;
2346 case 2: responseSize = sizeof(qi.u.volumeInfo); break;
2347 case 0x102: responseSize = sizeof(qi.u.FSvolumeInfo); break;
2348 case 0x103: responseSize = sizeof(qi.u.FSsizeInfo); break;
2349 case 0x104: responseSize = sizeof(qi.u.FSdeviceInfo); break;
2350 case 0x105: responseSize = sizeof(qi.u.FSattributeInfo); break;
2351 default: return CM_ERROR_INVAL;
2354 outp = smb_GetTran2ResponsePacket(vcp, p, op, 0, responseSize);
2355 switch (p->parmsp[0]) {
2358 qi.u.allocInfo.FSID = 0;
2359 qi.u.allocInfo.sectorsPerAllocUnit = 1;
2360 qi.u.allocInfo.totalAllocUnits = 0x7fffffff;
2361 qi.u.allocInfo.availAllocUnits = 0x3fffffff;
2362 qi.u.allocInfo.bytesPerSector = 1024;
2367 qi.u.volumeInfo.vsn = 1234;
2368 qi.u.volumeInfo.vnCount = 4;
2369 /* we're supposed to pad it out with zeroes to the end */
2370 memset(&qi.u.volumeInfo.label, 0, sizeof(qi.u.volumeInfo.label));
2371 memcpy(qi.u.volumeInfo.label, "AFS", 4);
2375 /* FS volume info */
2376 memset((char *)&qi.u.FSvolumeInfo.vct, 0, sizeof(FILETIME));
2377 qi.u.FSvolumeInfo.vsn = 1234;
2378 qi.u.FSvolumeInfo.vnCount = 8;
2379 memcpy(qi.u.FSvolumeInfo.label, "A\0F\0S\0\0", 8);
2385 temp.LowPart = 0x7fffffff;
2386 qi.u.FSsizeInfo.totalAllocUnits = temp;
2387 temp.LowPart = 0x3fffffff;
2388 qi.u.FSsizeInfo.availAllocUnits = temp;
2389 qi.u.FSsizeInfo.sectorsPerAllocUnit = 1;
2390 qi.u.FSsizeInfo.bytesPerSector = 1024;
2394 /* FS device info */
2395 qi.u.FSdeviceInfo.devType = 0; /* don't have a number */
2396 qi.u.FSdeviceInfo.characteristics = 0x50; /* remote, virtual */
2400 /* FS attribute info */
2401 /* attributes, defined in WINNT.H:
2402 * FILE_CASE_SENSITIVE_SEARCH 0x1
2403 * FILE_CASE_PRESERVED_NAMES 0x2
2404 * <no name defined> 0x4000
2405 * If bit 0x4000 is not set, Windows 95 thinks
2406 * we can't handle long (non-8.3) names,
2407 * despite our protestations to the contrary.
2409 qi.u.FSattributeInfo.attributes = 0x4003;
2410 qi.u.FSattributeInfo.maxCompLength = 255;
2411 qi.u.FSattributeInfo.FSnameLength = 6;
2412 memcpy(qi.u.FSattributeInfo.FSname, FSname, 6);
2416 /* copy out return data, and set corresponding sizes */
2417 outp->totalParms = 0;
2418 outp->totalData = responseSize;
2419 memcpy(outp->datap, &qi, responseSize);
2421 /* send and free the packets */
2422 smb_SendTran2Packet(vcp, outp, op);
2423 smb_FreeTran2Packet(outp);
2428 long smb_ReceiveTran2SetFSInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
2430 osi_Log0(smb_logp,"ReceiveTran2SetFSInfo - NOT_SUPPORTED");
2431 return CM_ERROR_BADOP;
2434 struct smb_ShortNameRock {
2438 size_t shortNameLen;
2441 int cm_GetShortNameProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *vrockp,
2444 struct smb_ShortNameRock *rockp;
2448 /* compare both names and vnodes, though probably just comparing vnodes
2449 * would be safe enough.
2451 if (cm_stricmp(dep->name, rockp->maskp) != 0)
2453 if (ntohl(dep->fid.vnode) != rockp->vnode)
2455 /* This is the entry */
2456 cm_Gen8Dot3Name(dep, rockp->shortName, &shortNameEnd);
2457 rockp->shortNameLen = shortNameEnd - rockp->shortName;
2458 return CM_ERROR_STOPNOW;
2461 long cm_GetShortName(char *pathp, cm_user_t *userp, cm_req_t *reqp,
2462 char *tidPathp, int vnode, char *shortName, size_t *shortNameLenp)
2464 struct smb_ShortNameRock rock;
2468 int caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
2472 spacep = cm_GetSpace();
2473 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
2475 code = cm_NameI(cm_rootSCachep, spacep->data, caseFold, userp, tidPathp,
2477 cm_FreeSpace(spacep);
2478 if (code) return code;
2480 if (!lastNamep) lastNamep = pathp;
2483 thyper.HighPart = 0;
2484 rock.shortName = shortName;
2486 rock.maskp = lastNamep;
2487 code = cm_ApplyDir(dscp, cm_GetShortNameProc, &rock, &thyper, userp, reqp, NULL);
2489 cm_ReleaseSCache(dscp);
2492 return CM_ERROR_NOSUCHFILE;
2493 if (code == CM_ERROR_STOPNOW) {
2494 *shortNameLenp = rock.shortNameLen;
2500 long smb_ReceiveTran2QPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
2502 smb_tran2Packet_t *outp;
2505 unsigned short infoLevel;
2507 unsigned short attributes;
2508 unsigned long extAttributes;
2513 cm_scache_t *scp, *dscp;
2522 infoLevel = p->parmsp[0];
2523 if (infoLevel == 6) nbytesRequired = 0;
2524 else if (infoLevel == 1) nbytesRequired = 22;
2525 else if (infoLevel == 2) nbytesRequired = 26;
2526 else if (infoLevel == 0x101) nbytesRequired = 40;
2527 else if (infoLevel == 0x102) nbytesRequired = 24;
2528 else if (infoLevel == 0x103) nbytesRequired = 4;
2529 else if (infoLevel == 0x108) nbytesRequired = 30;
2531 osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
2532 p->opcode, infoLevel);
2533 smb_SendTran2Error(vcp, p, opx, CM_ERROR_INVAL);
2536 osi_Log2(smb_logp, "T2 QPathInfo type 0x%x path %s", infoLevel,
2537 osi_LogSaveString(smb_logp, (char *)(&p->parmsp[3])));
2539 outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, nbytesRequired);
2541 if (infoLevel > 0x100)
2542 outp->totalParms = 2;
2544 outp->totalParms = 0;
2545 outp->totalData = nbytesRequired;
2547 /* now, if we're at infoLevel 6, we're only being asked to check
2548 * the syntax, so we just OK things now. In particular, we're *not*
2549 * being asked to verify anything about the state of any parent dirs.
2551 if (infoLevel == 6) {
2552 smb_SendTran2Packet(vcp, outp, opx);
2553 smb_FreeTran2Packet(outp);
2557 userp = smb_GetTran2User(vcp, p);
2559 osi_Log1(smb_logp, "ReceiveTran2QPathInfo unable to resolve user [%d]", p->uid);
2560 smb_FreeTran2Packet(outp);
2561 return CM_ERROR_BADSMB;
2564 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
2566 cm_ReleaseUser(userp);
2567 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOSUCHPATH);
2568 smb_FreeTran2Packet(outp);
2573 * XXX Strange hack XXX
2575 * As of Patch 7 (13 January 98), we are having the following problem:
2576 * In NT Explorer 4.0, whenever we click on a directory, AFS gets
2577 * requests to look up "desktop.ini" in all the subdirectories.
2578 * This can cause zillions of timeouts looking up non-existent cells
2579 * and volumes, especially in the top-level directory.
2581 * We have not found any way to avoid this or work around it except
2582 * to explicitly ignore the requests for mount points that haven't
2583 * yet been evaluated and for directories that haven't yet been
2586 if (infoLevel == 0x101) {
2587 spacep = cm_GetSpace();
2588 smb_StripLastComponent(spacep->data, &lastComp,
2589 (char *)(&p->parmsp[3]));
2590 #ifndef SPECIAL_FOLDERS
2591 /* Make sure that lastComp is not NULL */
2593 if (stricmp(lastComp, "\\desktop.ini") == 0) {
2594 code = cm_NameI(cm_rootSCachep, spacep->data,
2598 userp, tidPathp, &req, &dscp);
2600 if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT
2601 && !dscp->mountRootFidp)
2602 code = CM_ERROR_NOSUCHFILE;
2603 else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
2604 cm_buf_t *bp = buf_Find(dscp, &hzero);
2608 code = CM_ERROR_NOSUCHFILE;
2610 cm_ReleaseSCache(dscp);
2612 cm_FreeSpace(spacep);
2613 cm_ReleaseUser(userp);
2614 smb_SendTran2Error(vcp, p, opx, code);
2615 smb_FreeTran2Packet(outp);
2621 #endif /* SPECIAL_FOLDERS */
2623 cm_FreeSpace(spacep);
2626 /* now do namei and stat, and copy out the info */
2627 code = cm_NameI(cm_rootSCachep, (char *)(&p->parmsp[3]),
2628 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, tidPathp, &req, &scp);
2631 cm_ReleaseUser(userp);
2632 smb_SendTran2Error(vcp, p, opx, code);
2633 smb_FreeTran2Packet(outp);
2637 lock_ObtainMutex(&scp->mx);
2638 code = cm_SyncOp(scp, NULL, userp, &req, 0,
2639 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
2640 if (code) goto done;
2642 /* now we have the status in the cache entry, and everything is locked.
2643 * Marshall the output data.
2646 /* for info level 108, figure out short name */
2647 if (infoLevel == 0x108) {
2648 code = cm_GetShortName((char *)(&p->parmsp[3]), userp, &req,
2649 tidPathp, scp->fid.vnode, shortName,
2656 *((u_long *)op) = len * 2; op += 4;
2657 mbstowcs((unsigned short *)op, shortName, len);
2662 if (infoLevel == 1 || infoLevel == 2) {
2663 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
2664 *((u_long *)op) = dosTime; op += 4; /* creation time */
2665 *((u_long *)op) = dosTime; op += 4; /* access time */
2666 *((u_long *)op) = dosTime; op += 4; /* write time */
2667 *((u_long *)op) = scp->length.LowPart; op += 4; /* length */
2668 *((u_long *)op) = scp->length.LowPart; op += 4; /* alloc size */
2669 attributes = smb_Attributes(scp);
2670 *((u_short *)op) = attributes; op += 2; /* attributes */
2672 else if (infoLevel == 0x101) {
2673 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
2674 *((FILETIME *)op) = ft; op += 8; /* creation time */
2675 *((FILETIME *)op) = ft; op += 8; /* last access time */
2676 *((FILETIME *)op) = ft; op += 8; /* last write time */
2677 *((FILETIME *)op) = ft; op += 8; /* last change time */
2678 extAttributes = smb_ExtAttributes(scp);
2679 *((u_long *)op) = extAttributes; op += 4; /* extended attribs */
2680 *((u_long *)op) = 0; op += 4; /* don't know what this is */
2682 else if (infoLevel == 0x102) {
2683 *((LARGE_INTEGER *)op) = scp->length; op += 8; /* alloc size */
2684 *((LARGE_INTEGER *)op) = scp->length; op += 8; /* EOF */
2685 *((u_long *)op) = scp->linkCount; op += 4;
2688 *op++ = (scp->fileType == CM_SCACHETYPE_DIRECTORY ? 1 : 0);
2691 else if (infoLevel == 0x103) {
2692 memset(op, 0, 4); op += 4; /* EA size */
2695 /* now, if we are being asked about extended attrs, return a 0 size */
2696 if (infoLevel == 2) {
2697 *((u_long *)op) = 0; op += 4;
2701 /* send and free the packets */
2703 lock_ReleaseMutex(&scp->mx);
2704 cm_ReleaseSCache(scp);
2705 cm_ReleaseUser(userp);
2707 smb_SendTran2Packet(vcp, outp, opx);
2709 smb_SendTran2Error(vcp, p, opx, code);
2710 smb_FreeTran2Packet(outp);
2715 long smb_ReceiveTran2SetPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
2717 osi_Log0(smb_logp,"ReceiveTran2SetPathInfo - NOT_SUPPORTED");
2718 return CM_ERROR_BADOP;
2721 long smb_ReceiveTran2QFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
2723 smb_tran2Packet_t *outp;
2725 unsigned long attributes;
2726 unsigned short infoLevel;
2739 fidp = smb_FindFID(vcp, fid, 0);
2742 smb_SendTran2Error(vcp, p, opx, CM_ERROR_BADFD);
2746 infoLevel = p->parmsp[1];
2747 if (infoLevel == 0x101) nbytesRequired = 40;
2748 else if (infoLevel == 0x102) nbytesRequired = 24;
2749 else if (infoLevel == 0x103) nbytesRequired = 4;
2750 else if (infoLevel == 0x104) nbytesRequired = 6;
2752 osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
2753 p->opcode, infoLevel);
2754 smb_SendTran2Error(vcp, p, opx, CM_ERROR_INVAL);
2755 smb_ReleaseFID(fidp);
2758 osi_Log2(smb_logp, "T2 QFileInfo type 0x%x fid %d", infoLevel, fid);
2760 outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, nbytesRequired);
2762 if (infoLevel > 0x100)
2763 outp->totalParms = 2;
2765 outp->totalParms = 0;
2766 outp->totalData = nbytesRequired;
2768 userp = smb_GetTran2User(vcp, p);
2770 osi_Log1(smb_logp, "ReceiveTran2QFileInfo unable to resolve user [%d]", p->uid);
2771 code = CM_ERROR_BADSMB;
2776 lock_ObtainMutex(&scp->mx);
2777 code = cm_SyncOp(scp, NULL, userp, &req, 0,
2778 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
2782 /* now we have the status in the cache entry, and everything is locked.
2783 * Marshall the output data.
2786 if (infoLevel == 0x101) {
2787 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
2788 *((FILETIME *)op) = ft; op += 8; /* creation time */
2789 *((FILETIME *)op) = ft; op += 8; /* last access time */
2790 *((FILETIME *)op) = ft; op += 8; /* last write time */
2791 *((FILETIME *)op) = ft; op += 8; /* last change time */
2792 attributes = smb_ExtAttributes(scp);
2793 *((u_long *)op) = attributes; op += 4;
2794 *((u_long *)op) = 0; op += 4;
2796 else if (infoLevel == 0x102) {
2797 *((LARGE_INTEGER *)op) = scp->length; op += 8; /* alloc size */
2798 *((LARGE_INTEGER *)op) = scp->length; op += 8; /* EOF */
2799 *((u_long *)op) = scp->linkCount; op += 4;
2800 *op++ = ((fidp->flags & SMB_FID_DELONCLOSE) ? 1 : 0);
2801 *op++ = (scp->fileType == CM_SCACHETYPE_DIRECTORY ? 1 : 0);
2805 else if (infoLevel == 0x103) {
2806 *((u_long *)op) = 0; op += 4;
2808 else if (infoLevel == 0x104) {
2812 if (fidp->NTopen_wholepathp)
2813 name = fidp->NTopen_wholepathp;
2815 name = "\\"; /* probably can't happen */
2817 outp->totalData = (len*2) + 4; /* this is actually what we want to return */
2818 *((u_long *)op) = len * 2; op += 4;
2819 mbstowcs((unsigned short *)op, name, len); op += (len * 2);
2822 /* send and free the packets */
2824 lock_ReleaseMutex(&scp->mx);
2825 cm_ReleaseUser(userp);
2826 smb_ReleaseFID(fidp);
2828 smb_SendTran2Packet(vcp, outp, opx);
2830 smb_SendTran2Error(vcp, p, opx, code);
2831 smb_FreeTran2Packet(outp);
2836 long smb_ReceiveTran2SetFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
2841 unsigned short infoLevel;
2842 smb_tran2Packet_t *outp;
2850 fidp = smb_FindFID(vcp, fid, 0);
2853 smb_SendTran2Error(vcp, p, op, CM_ERROR_BADFD);
2857 infoLevel = p->parmsp[1];
2858 osi_Log2(smb_logp,"ReceiveTran2SetFileInfo type=[%x] fid=[%x]", infoLevel, fid);
2859 if (infoLevel > 0x104 || infoLevel < 0x101) {
2860 osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
2861 p->opcode, infoLevel);
2862 smb_SendTran2Error(vcp, p, op, CM_ERROR_INVAL);
2863 smb_ReleaseFID(fidp);
2867 if (infoLevel == 0x102 && !(fidp->flags & SMB_FID_OPENDELETE)) {
2868 smb_SendTran2Error(vcp, p, op, CM_ERROR_NOACCESS);
2869 smb_ReleaseFID(fidp);
2872 if ((infoLevel == 0x103 || infoLevel == 0x104)
2873 && !(fidp->flags & SMB_FID_OPENWRITE)) {
2874 smb_SendTran2Error(vcp, p, op, CM_ERROR_NOACCESS);
2875 smb_ReleaseFID(fidp);
2879 osi_Log1(smb_logp, "T2 SFileInfo type 0x%x", infoLevel);
2881 outp = smb_GetTran2ResponsePacket(vcp, p, op, 2, 0);
2883 outp->totalParms = 2;
2884 outp->totalData = 0;
2886 userp = smb_GetTran2User(vcp, p);
2888 osi_Log1(smb_logp,"ReceiveTran2SetFileInfo unable to resolve user [%d]", p->uid);
2889 code = CM_ERROR_BADSMB;
2895 if (infoLevel == 0x101) {
2897 unsigned int attribute;
2900 /* lock the vnode with a callback; we need the current status
2901 * to determine what the new status is, in some cases.
2903 lock_ObtainMutex(&scp->mx);
2904 code = cm_SyncOp(scp, NULL, userp, &req, 0,
2905 CM_SCACHESYNC_GETSTATUS
2906 | CM_SCACHESYNC_NEEDCALLBACK);
2908 lock_ReleaseMutex(&scp->mx);
2912 /* prepare for setattr call */
2915 lastMod = *((FILETIME *)(p->datap + 16));
2916 /* when called as result of move a b, lastMod is (-1, -1).
2917 * If the check for -1 is not present, timestamp
2918 * of the resulting file will be 1969 (-1)
2920 if (LargeIntegerNotEqualToZero(*((LARGE_INTEGER *)&lastMod)) &&
2921 lastMod.dwLowDateTime != -1 && lastMod.dwHighDateTime != -1) {
2922 attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
2923 smb_UnixTimeFromLargeSearchTime(&attr.clientModTime,
2925 fidp->flags |= SMB_FID_MTIMESETDONE;
2928 attribute = *((u_long *)(p->datap + 32));
2929 if (attribute != 0) {
2930 if ((scp->unixModeBits & 0222)
2931 && (attribute & 1) != 0) {
2932 /* make a writable file read-only */
2933 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
2934 attr.unixModeBits = scp->unixModeBits & ~0222;
2936 else if ((scp->unixModeBits & 0222) == 0
2937 && (attribute & 1) == 0) {
2938 /* make a read-only file writable */
2939 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
2940 attr.unixModeBits = scp->unixModeBits | 0222;
2943 lock_ReleaseMutex(&scp->mx);
2947 code = cm_SetAttr(scp, &attr, userp, &req);
2951 else if (infoLevel == 0x103 || infoLevel == 0x104) {
2952 LARGE_INTEGER size = *((LARGE_INTEGER *)(p->datap));
2955 attr.mask = CM_ATTRMASK_LENGTH;
2956 attr.length.LowPart = size.LowPart;
2957 attr.length.HighPart = size.HighPart;
2958 code = cm_SetAttr(scp, &attr, userp, &req);
2960 else if (infoLevel == 0x102) {
2961 if (*((char *)(p->datap))) {
2962 code = cm_CheckNTDelete(fidp->NTopen_dscp, scp, userp,
2965 fidp->flags |= SMB_FID_DELONCLOSE;
2969 fidp->flags &= ~SMB_FID_DELONCLOSE;
2974 cm_ReleaseUser(userp);
2975 smb_ReleaseFID(fidp);
2977 smb_SendTran2Packet(vcp, outp, op);
2979 smb_SendTran2Error(vcp, p, op, code);
2980 smb_FreeTran2Packet(outp);
2986 smb_ReceiveTran2FSCTL(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
2988 osi_Log0(smb_logp,"ReceiveTran2FSCTL - NOT_SUPPORTED");
2989 return CM_ERROR_BADOP;
2993 smb_ReceiveTran2IOCTL(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
2995 osi_Log0(smb_logp,"ReceiveTran2IOCTL - NOT_SUPPORTED");
2996 return CM_ERROR_BADOP;
3000 smb_ReceiveTran2FindNotifyFirst(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3002 osi_Log0(smb_logp,"ReceiveTran2FindNotifyFirst - NOT_SUPPORTED");
3003 return CM_ERROR_BADOP;
3007 smb_ReceiveTran2FindNotifyNext(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3009 osi_Log0(smb_logp,"ReceiveTran2FindNotifyNext - NOT_SUPPORTED");
3010 return CM_ERROR_BADOP;
3014 smb_ReceiveTran2CreateDirectory(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3016 osi_Log0(smb_logp,"ReceiveTran2CreateDirectory - NOT_SUPPORTED");
3017 return CM_ERROR_BADOP;
3021 smb_ReceiveTran2SessionSetup(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3023 osi_Log0(smb_logp,"ReceiveTran2SessionSetup - NOT_SUPPORTED");
3024 return CM_ERROR_BADOP;
3028 smb_ReceiveTran2GetDFSReferral(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3030 osi_Log0(smb_logp,"ReceiveTran2GetDFSReferral - NOT_SUPPORTED");
3031 return CM_ERROR_BADOP;
3035 smb_ReceiveTran2ReportDFSInconsistency(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3037 osi_Log0(smb_logp,"ReceiveTran2ReportDFSInconsistency - NOT_SUPPORTED");
3038 return CM_ERROR_BADOP;
3042 smb_ApplyV3DirListPatches(cm_scache_t *dscp,
3043 smb_dirListPatch_t **dirPatchespp, int infoLevel, cm_user_t *userp,
3048 cm_scache_t *targetScp; /* target if scp is a symlink */
3053 unsigned short attr;
3054 unsigned long lattr;
3055 smb_dirListPatch_t *patchp;
3056 smb_dirListPatch_t *npatchp;
3058 for(patchp = *dirPatchespp; patchp; patchp =
3059 (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
3060 code = cm_GetSCache(&patchp->fid, &scp, userp, reqp);
3062 lock_ObtainMutex(&scp->mx);
3063 code = cm_SyncOp(scp, NULL, userp, reqp, 0,
3064 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3066 lock_ReleaseMutex(&scp->mx);
3067 cm_ReleaseSCache(scp);
3069 dptr = patchp->dptr;
3071 /* Plug in fake timestamps. A time stamp of 0 causes 'invalid parameter'
3072 errors in the client. */
3073 if (infoLevel >= 0x101) {
3074 /* 1969-12-31 23:59:59 +00 */
3075 ft.dwHighDateTime = 0x19DB200;
3076 ft.dwLowDateTime = 0x5BB78980;
3078 /* copy to Creation Time */
3079 *((FILETIME *)dptr) = ft;
3082 /* copy to Last Access Time */
3083 *((FILETIME *)dptr) = ft;
3086 /* copy to Last Write Time */
3087 *((FILETIME *)dptr) = ft;
3090 /* copy to Change Time */
3091 *((FILETIME *)dptr) = ft;
3094 /* merge in hidden attribute */
3095 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
3096 *((u_long *)dptr) = SMB_ATTR_HIDDEN;
3100 /* 1969-12-31 23:59:58 +00*/
3101 dosTime = 0xEBBFBF7D;
3103 /* and copy out date */
3104 shortTemp = (dosTime>>16) & 0xffff;
3105 *((u_short *)dptr) = shortTemp;
3108 /* copy out creation time */
3109 shortTemp = dosTime & 0xffff;
3110 *((u_short *)dptr) = shortTemp;
3113 /* and copy out date */
3114 shortTemp = (dosTime>>16) & 0xffff;
3115 *((u_short *)dptr) = shortTemp;
3118 /* copy out access time */
3119 shortTemp = dosTime & 0xffff;
3120 *((u_short *)dptr) = shortTemp;
3123 /* and copy out date */
3124 shortTemp = (dosTime>>16) & 0xffff;
3125 *((u_short *)dptr) = shortTemp;
3128 /* copy out mod time */
3129 shortTemp = dosTime & 0xffff;
3130 *((u_short *)dptr) = shortTemp;
3133 /* merge in hidden (dot file) attribute */
3134 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
3135 attr = SMB_ATTR_HIDDEN;
3136 *dptr++ = attr & 0xff;
3137 *dptr++ = (attr >> 8) & 0xff;
3143 /* now watch for a symlink */
3145 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
3146 lock_ReleaseMutex(&scp->mx);
3147 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, reqp);
3149 /* we have a more accurate file to use (the
3150 * target of the symbolic link). Otherwise,
3151 * we'll just use the symlink anyway.
3153 osi_Log2(smb_logp, "symlink vp %x to vp %x",
3155 cm_ReleaseSCache(scp);
3158 lock_ObtainMutex(&scp->mx);
3161 dptr = patchp->dptr;
3163 if (infoLevel >= 0x101) {
3165 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
3167 /* copy to Creation Time */
3168 *((FILETIME *)dptr) = ft;
3171 /* copy to Last Access Time */
3172 *((FILETIME *)dptr) = ft;
3175 /* copy to Last Write Time */
3176 *((FILETIME *)dptr) = ft;
3179 /* copy to Change Time */
3180 *((FILETIME *)dptr) = ft;
3183 /* Use length for both file length and alloc length */
3184 *((LARGE_INTEGER *)dptr) = scp->length;
3186 *((LARGE_INTEGER *)dptr) = scp->length;
3189 /* Copy attributes */
3190 lattr = smb_ExtAttributes(scp);
3191 /* merge in hidden (dot file) attribute */
3192 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE )
3193 lattr |= SMB_ATTR_HIDDEN;
3194 *((u_long *)dptr) = lattr;
3199 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
3201 /* and copy out date */
3202 shortTemp = (dosTime>>16) & 0xffff;
3203 *((u_short *)dptr) = shortTemp;
3206 /* copy out creation time */
3207 shortTemp = dosTime & 0xffff;
3208 *((u_short *)dptr) = shortTemp;
3211 /* and copy out date */
3212 shortTemp = (dosTime>>16) & 0xffff;
3213 *((u_short *)dptr) = shortTemp;
3216 /* copy out access time */
3217 shortTemp = dosTime & 0xffff;
3218 *((u_short *)dptr) = shortTemp;
3221 /* and copy out date */
3222 shortTemp = (dosTime>>16) & 0xffff;
3223 *((u_short *)dptr) = shortTemp;
3226 /* copy out mod time */
3227 shortTemp = dosTime & 0xffff;
3228 *((u_short *)dptr) = shortTemp;
3231 /* copy out file length and alloc length,
3232 * using the same for both
3234 *((u_long *)dptr) = scp->length.LowPart;
3236 *((u_long *)dptr) = scp->length.LowPart;
3239 /* finally copy out attributes as short */
3240 attr = smb_Attributes(scp);
3241 /* merge in hidden (dot file) attribute */
3242 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE )
3243 attr |= SMB_ATTR_HIDDEN;
3244 *dptr++ = attr & 0xff;
3245 *dptr++ = (attr >> 8) & 0xff;
3248 lock_ReleaseMutex(&scp->mx);
3249 cm_ReleaseSCache(scp);
3252 /* now free the patches */
3253 for (patchp = *dirPatchespp; patchp; patchp = npatchp) {
3254 npatchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q);
3258 /* and mark the list as empty */
3259 *dirPatchespp = NULL;
3264 #ifndef USE_OLD_MATCHING
3265 // char table for case insensitive comparison
3266 char mapCaseTable[256];
3268 VOID initUpperCaseTable(VOID)
3271 for (i = 0; i < 256; ++i)
3272 mapCaseTable[i] = toupper(i);
3273 // make '"' match '.'
3274 mapCaseTable[(int)'"'] = toupper('.');
3275 // make '<' match '*'
3276 mapCaseTable[(int)'<'] = toupper('*');
3277 // make '>' match '?'
3278 mapCaseTable[(int)'>'] = toupper('?');
3281 // Compare 'pattern' (containing metacharacters '*' and '?') with the file
3283 // Note : this procedure works recursively calling itself.
3285 // PSZ pattern : string containing metacharacters.
3286 // PSZ name : file name to be compared with 'pattern'.
3288 // BOOL : TRUE/FALSE (match/mistmatch)
3291 szWildCardMatchFileName(PSZ pattern, PSZ name)
3293 PSZ pename; // points to the last 'name' character
3295 pename = name + strlen(name) - 1;
3305 if (*pattern == '\0')
3307 for (p = pename; p >= name; --p) {
3308 if ((mapCaseTable[*p] == mapCaseTable[*pattern]) &&
3309 szWildCardMatchFileName(pattern + 1, p + 1))
3314 if (mapCaseTable[*name] != mapCaseTable[*pattern])
3321 if (*pattern == '\0' || *pattern == '*' && *(pattern+1) == '\0')
3327 /* do a case-folding search of the star name mask with the name in namep.
3328 * Return 1 if we match, otherwise 0.
3330 int smb_V3MatchMask(char *namep, char *maskp, int flags)
3333 int i, j, star, qmark, retval;
3335 /* make sure we only match 8.3 names, if requested */
3336 if ((flags & CM_FLAG_8DOT3) && !cm_Is8Dot3(namep))
3339 /* optimize the pattern:
3340 * if there is a mixture of '?' and '*',
3341 * for example the sequence "*?*?*?*"
3342 * must be turned into the form "*"
3344 newmask = (char *)malloc(strlen(maskp)+1);
3345 for ( i=0, j=0, star=0, qmark=0; maskp[i]; i++) {
3346 switch ( maskp[i] ) {
3358 } else if ( qmark ) {
3362 newmask[j++] = maskp[i];
3369 } else if ( qmark ) {
3373 newmask[j++] = '\0';
3375 retval = szWildCardMatchFileName(newmask, namep) ? 1:0;
3381 #else /* USE_OLD_MATCHING */
3382 /* do a case-folding search of the star name mask with the name in namep.
3383 * Return 1 if we match, otherwise 0.
3385 int smb_V3MatchMask(char *namep, char *maskp, int flags)
3387 unsigned char tcp1, tcp2; /* Pattern characters */
3388 unsigned char tcn1; /* Name characters */
3389 int sawDot = 0, sawStar = 0, req8dot3 = 0;
3390 char *starNamep, *starMaskp;
3391 static char nullCharp[] = {0};
3392 int casefold = flags & CM_FLAG_CASEFOLD;
3394 /* make sure we only match 8.3 names, if requested */
3395 req8dot3 = (flags & CM_FLAG_8DOT3);
3396 if (req8dot3 && !cm_Is8Dot3(namep))
3401 /* Next pattern character */
3404 /* Next name character */
3408 /* 0 - end of pattern */
3414 else if (tcp1 == '.' || tcp1 == '"') {
3424 * first dot in pattern;
3425 * must match dot or end of name
3430 else if (tcn1 == '.') {
3439 else if (tcp1 == '?') {
3440 if (tcn1 == 0 || tcn1 == '.')
3445 else if (tcp1 == '>') {
3446 if (tcn1 != 0 && tcn1 != '.')
3450 else if (tcp1 == '*' || tcp1 == '<') {
3454 else if ((req8dot3 && tcp2 == '.') || tcp2 == '"') {
3455 while (req8dot3 && tcn1 != '.' && tcn1 != 0)
3470 * pattern character after '*' is not null or
3471 * period. If it is '?' or '>', we are not
3472 * going to understand it. If it is '*' or
3473 * '<', we are going to skip over it. None of
3474 * these are likely, I hope.
3476 /* skip over '*' and '<' */
3477 while (tcp2 == '*' || tcp2 == '<')
3480 /* skip over characters that don't match tcp2 */
3481 while (req8dot3 && tcn1 != '.' && tcn1 != 0 &&
3482 ((casefold && cm_foldUpper[tcn1] != cm_foldUpper[tcp2]) ||
3483 (!casefold && tcn1 != tcp2)))
3487 if ((req8dot3 && tcn1 == '.') || tcn1 == 0)
3490 /* Remember where we are */
3500 /* tcp1 is not a wildcard */
3501 if ((casefold && cm_foldUpper[tcn1] == cm_foldUpper[tcp1]) ||
3502 (!casefold && tcn1 == tcp1)) {
3507 /* if trying to match a star pattern, go back */
3509 maskp = starMaskp - 2;
3510 namep = starNamep + 1;
3519 #endif /* USE_OLD_MATCHING */
3521 long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
3530 smb_dirListPatch_t *dirListPatchesp;
3531 smb_dirListPatch_t *curPatchp;
3534 long orbytes; /* # of bytes in this output record */
3535 long ohbytes; /* # of bytes, except file name */
3536 long onbytes; /* # of bytes in name, incl. term. null */
3537 osi_hyper_t dirLength;
3538 osi_hyper_t bufferOffset;
3539 osi_hyper_t curOffset;
3541 smb_dirSearch_t *dsp;
3545 cm_pageHeader_t *pageHeaderp;
3546 cm_user_t *userp = NULL;
3549 long nextEntryCookie;
3550 int numDirChunks; /* # of 32 byte dir chunks in this entry */
3551 char *op; /* output data ptr */
3552 char *origOp; /* original value of op */
3553 cm_space_t *spacep; /* for pathname buffer */
3554 long maxReturnData; /* max # of return data */
3555 long maxReturnParms; /* max # of return parms */
3556 long bytesInBuffer; /* # data bytes in the output buffer */
3558 char *maskp; /* mask part of path */
3562 smb_tran2Packet_t *outp; /* response packet */
3565 char shortName[13]; /* 8.3 name if needed */
3576 if (p->opcode == 1) {
3577 /* find first; obtain basic parameters from request */
3578 attribute = p->parmsp[0];
3579 maxCount = p->parmsp[1];
3580 infoLevel = p->parmsp[3];
3581 searchFlags = p->parmsp[2];
3582 dsp = smb_NewDirSearch(1);
3583 dsp->attribute = attribute;
3584 pathp = ((char *) p->parmsp) + 12; /* points to path */
3585 if (smb_StoreAnsiFilenames)
3586 OemToChar(pathp,pathp);
3588 maskp = strrchr(pathp, '\\');
3592 maskp++; /* skip over backslash */
3593 strcpy(dsp->mask, maskp); /* and save mask */
3594 /* track if this is likely to match a lot of entries */
3595 starPattern = smb_V3IsStarMask(maskp);
3598 osi_assert(p->opcode == 2);
3599 /* find next; obtain basic parameters from request or open dir file */
3600 dsp = smb_FindDirSearch(p->parmsp[0]);
3602 return CM_ERROR_BADFD;
3603 attribute = dsp->attribute;
3604 maxCount = p->parmsp[1];
3605 infoLevel = p->parmsp[2];
3606 searchFlags = p->parmsp[5];
3608 nextCookie = p->parmsp[3] | (p->parmsp[4] << 16);
3610 starPattern = 1; /* assume, since required a Find Next */
3614 "T2 search dir attr 0x%x, info level %d, max count %d, flags 0x%x",
3615 attribute, infoLevel, maxCount, searchFlags);
3617 osi_Log2(smb_logp, "...T2 search op %d, nextCookie 0x%x",
3618 p->opcode, nextCookie);
3620 if (infoLevel >= 0x101)
3621 searchFlags &= ~4; /* no resume keys */
3623 dirListPatchesp = NULL;
3625 maxReturnData = p->maxReturnData;
3626 if (p->opcode == 1) /* find first */
3627 maxReturnParms = 10; /* bytes */
3629 maxReturnParms = 8; /* bytes */
3631 #ifndef CM_CONFIG_MULTITRAN2RESPONSES
3632 if (maxReturnData > 6000)
3633 maxReturnData = 6000;
3634 #endif /* CM_CONFIG_MULTITRAN2RESPONSES */
3636 outp = smb_GetTran2ResponsePacket(vcp, p, opx, maxReturnParms,
3639 osi_Log1(smb_logp, "T2 receive search dir %s",
3640 osi_LogSaveString(smb_logp, pathp));
3642 /* bail out if request looks bad */
3643 if (p->opcode == 1 && !pathp) {
3644 smb_ReleaseDirSearch(dsp);
3645 smb_FreeTran2Packet(outp);
3646 return CM_ERROR_BADSMB;
3649 osi_Log2(smb_logp, "T2 dir search cookie 0x%x, connection %d",
3650 nextCookie, dsp->cookie);
3652 userp = smb_GetTran2User(vcp, p);
3654 osi_Log1(smb_logp, "T2 dir search unable to resolve user [%d]", p->uid);
3655 smb_ReleaseDirSearch(dsp);
3656 smb_FreeTran2Packet(outp);
3657 return CM_ERROR_BADSMB;
3660 /* try to get the vnode for the path name next */
3661 lock_ObtainMutex(&dsp->mx);
3668 spacep = cm_GetSpace();
3669 smb_StripLastComponent(spacep->data, NULL, pathp);
3670 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
3672 lock_ReleaseMutex(&dsp->mx);
3673 cm_ReleaseUser(userp);
3674 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOFILES);
3675 smb_FreeTran2Packet(outp);
3676 smb_DeleteDirSearch(dsp);
3677 smb_ReleaseDirSearch(dsp);
3680 code = cm_NameI(cm_rootSCachep, spacep->data,
3681 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
3682 userp, tidPathp, &req, &scp);
3683 cm_FreeSpace(spacep);
3687 cm_ReleaseSCache(dsp->scp);
3689 /* we need one hold for the entry we just stored into,
3690 * and one for our own processing. When we're done
3691 * with this function, we'll drop the one for our own
3692 * processing. We held it once from the namei call,
3693 * and so we do another hold now.
3696 lock_ObtainMutex(&scp->mx);
3697 if ((scp->flags & CM_SCACHEFLAG_BULKSTATTING) == 0 &&
3698 LargeIntegerGreaterOrEqualToZero(scp->bulkStatProgress)) {
3699 scp->flags |= CM_SCACHEFLAG_BULKSTATTING;
3700 dsp->flags |= SMB_DIRSEARCH_BULKST;
3702 lock_ReleaseMutex(&scp->mx);
3705 lock_ReleaseMutex(&dsp->mx);
3707 cm_ReleaseUser(userp);
3708 smb_FreeTran2Packet(outp);
3709 smb_DeleteDirSearch(dsp);
3710 smb_ReleaseDirSearch(dsp);
3714 /* get the directory size */
3715 lock_ObtainMutex(&scp->mx);
3716 code = cm_SyncOp(scp, NULL, userp, &req, 0,
3717 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3719 lock_ReleaseMutex(&scp->mx);
3720 cm_ReleaseSCache(scp);
3721 cm_ReleaseUser(userp);
3722 smb_FreeTran2Packet(outp);
3723 smb_DeleteDirSearch(dsp);
3724 smb_ReleaseDirSearch(dsp);
3729 dirLength = scp->length;
3731 bufferOffset.LowPart = bufferOffset.HighPart = 0;
3732 curOffset.HighPart = 0;
3733 curOffset.LowPart = nextCookie;
3734 origOp = outp->datap;
3742 if (searchFlags & 4)
3743 /* skip over resume key */
3746 /* make sure that curOffset.LowPart doesn't point to the first
3747 * 32 bytes in the 2nd through last dir page, and that it doesn't
3748 * point at the first 13 32-byte chunks in the first dir page,
3749 * since those are dir and page headers, and don't contain useful
3752 temp = curOffset.LowPart & (2048-1);
3753 if (curOffset.HighPart == 0 && curOffset.LowPart < 2048) {
3754 /* we're in the first page */
3755 if (temp < 13*32) temp = 13*32;
3758 /* we're in a later dir page */
3759 if (temp < 32) temp = 32;
3762 /* make sure the low order 5 bits are zero */
3765 /* now put temp bits back ito curOffset.LowPart */
3766 curOffset.LowPart &= ~(2048-1);
3767 curOffset.LowPart |= temp;
3769 /* check if we've passed the dir's EOF */
3770 if (LargeIntegerGreaterThanOrEqualTo(curOffset, dirLength)) {
3775 /* check if we've returned all the names that will fit in the
3776 * response packet; we check return count as well as the number
3777 * of bytes requested. We check the # of bytes after we find
3778 * the dir entry, since we'll need to check its size.
3780 if (returnedNames >= maxCount) {
3784 /* see if we can use the bufferp we have now; compute in which
3785 * page the current offset would be, and check whether that's
3786 * the offset of the buffer we have. If not, get the buffer.
3788 thyper.HighPart = curOffset.HighPart;
3789 thyper.LowPart = curOffset.LowPart & ~(buf_bufferSize-1);
3790 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
3793 buf_Release(bufferp);
3796 lock_ReleaseMutex(&scp->mx);
3797 lock_ObtainRead(&scp->bufCreateLock);
3798 code = buf_Get(scp, &thyper, &bufferp);
3799 lock_ReleaseRead(&scp->bufCreateLock);
3800 lock_ObtainMutex(&dsp->mx);
3802 /* now, if we're doing a star match, do bulk fetching
3803 * of all of the status info for files in the dir.
3806 smb_ApplyV3DirListPatches(scp, &dirListPatchesp,
3809 lock_ObtainMutex(&scp->mx);
3810 if ((dsp->flags & SMB_DIRSEARCH_BULKST) &&
3811 LargeIntegerGreaterThanOrEqualTo(thyper, scp->bulkStatProgress)) {
3812 /* Don't bulk stat if risking timeout */
3813 int now = GetCurrentTime();
3814 if (now - req.startTime > 5000) {
3815 scp->bulkStatProgress = thyper;
3816 scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
3817 dsp->flags &= ~SMB_DIRSEARCH_BULKST;
3819 cm_TryBulkStat(scp, &thyper, userp, &req);
3822 lock_ObtainMutex(&scp->mx);
3824 lock_ReleaseMutex(&dsp->mx);
3828 bufferOffset = thyper;
3830 /* now get the data in the cache */
3832 code = cm_SyncOp(scp, bufferp, userp, &req,
3834 CM_SCACHESYNC_NEEDCALLBACK
3835 | CM_SCACHESYNC_READ);
3838 if (cm_HaveBuffer(scp, bufferp, 0)) break;
3840 /* otherwise, load the buffer and try again */
3841 code = cm_GetBuffer(scp, bufferp, NULL, userp,
3846 buf_Release(bufferp);
3850 } /* if (wrong buffer) ... */
3852 /* now we have the buffer containing the entry we're interested
3853 * in; copy it out if it represents a non-deleted entry.
3855 entryInDir = curOffset.LowPart & (2048-1);
3856 entryInBuffer = curOffset.LowPart & (buf_bufferSize - 1);
3858 /* page header will help tell us which entries are free. Page
3859 * header can change more often than once per buffer, since
3860 * AFS 3 dir page size may be less than (but not more than)
3861 * a buffer package buffer.
3863 /* only look intra-buffer */
3864 temp = curOffset.LowPart & (buf_bufferSize - 1);
3865 temp &= ~(2048 - 1); /* turn off intra-page bits */
3866 pageHeaderp = (cm_pageHeader_t *) (bufferp->datap + temp);
3868 /* now determine which entry we're looking at in the page.
3869 * If it is free (there's a free bitmap at the start of the
3870 * dir), we should skip these 32 bytes.
3872 slotInPage = (entryInDir & 0x7e0) >> 5;
3873 if (!(pageHeaderp->freeBitmap[slotInPage>>3] &
3874 (1 << (slotInPage & 0x7)))) {
3875 /* this entry is free */
3876 numDirChunks = 1; /* only skip this guy */
3880 tp = bufferp->datap + entryInBuffer;
3881 dep = (cm_dirEntry_t *) tp; /* now points to AFS3 dir entry */
3883 /* while we're here, compute the next entry's location, too,
3884 * since we'll need it when writing out the cookie into the dir
3887 * XXXX Probably should do more sanity checking.
3889 numDirChunks = cm_NameEntries(dep->name, &onbytes);
3891 /* compute offset of cookie representing next entry */
3892 nextEntryCookie = curOffset.LowPart + (CM_DIR_CHUNKSIZE * numDirChunks);
3894 /* Need 8.3 name? */
3896 if (infoLevel == 0x104
3897 && dep->fid.vnode != 0
3898 && !cm_Is8Dot3(dep->name)) {
3899 cm_Gen8Dot3Name(dep, shortName, &shortNameEnd);
3903 /* When matching, we are using doing a case fold if we have a wildcard mask.
3904 * If we get a non-wildcard match, it's a lookup for a specific file.
3906 if (dep->fid.vnode != 0 &&
3907 (smb_V3MatchMask(dep->name, maskp, (starPattern? CM_FLAG_CASEFOLD : 0)) ||
3909 smb_V3MatchMask(shortName, maskp, CM_FLAG_CASEFOLD)))) {
3911 /* Eliminate entries that don't match requested attributes */
3912 if (smb_hideDotFiles && !(dsp->attribute & SMB_ATTR_HIDDEN) &&
3913 smb_IsDotFile(dep->name))
3914 goto nextEntry; /* no hidden files */
3916 if (!(dsp->attribute & SMB_ATTR_DIRECTORY)) /* no directories */
3918 /* We have already done the cm_TryBulkStat above */
3919 fid.cell = scp->fid.cell;
3920 fid.volume = scp->fid.volume;
3921 fid.vnode = ntohl(dep->fid.vnode);
3922 fid.unique = ntohl(dep->fid.unique);
3923 fileType = cm_FindFileType(&fid);
3924 /*osi_Log2(smb_logp, "smb_ReceiveTran2SearchDir: file %s "
3925 "has filetype %d", dep->name,
3927 if (fileType == CM_SCACHETYPE_DIRECTORY)
3931 /* finally check if this name will fit */
3933 /* standard dir entry stuff */
3934 if (infoLevel < 0x101)
3935 ohbytes = 23; /* pre-NT */
3936 else if (infoLevel == 0x103)
3937 ohbytes = 12; /* NT names only */
3939 ohbytes = 64; /* NT */
3941 if (infoLevel == 0x104)
3942 ohbytes += 26; /* Short name & length */
3944 if (searchFlags & 4) {
3945 ohbytes += 4; /* if resume key required */
3949 && infoLevel != 0x101
3950 && infoLevel != 0x103)
3951 ohbytes += 4; /* EASIZE */
3953 /* add header to name & term. null */
3954 orbytes = onbytes + ohbytes + 1;
3956 /* now, we round up the record to a 4 byte alignment,
3957 * and we make sure that we have enough room here for
3958 * even the aligned version (so we don't have to worry
3959 * about an * overflow when we pad things out below).
3960 * That's the reason for the alignment arithmetic below.
3962 if (infoLevel >= 0x101)
3963 align = (4 - (orbytes & 3)) & 3;
3966 if (orbytes + bytesInBuffer + align > maxReturnData)
3969 /* this is one of the entries to use: it is not deleted
3970 * and it matches the star pattern we're looking for.
3971 * Put out the name, preceded by its length.
3973 /* First zero everything else */
3974 memset(origOp, 0, ohbytes);
3976 if (infoLevel <= 0x101)
3977 *(origOp + ohbytes - 1) = (unsigned char) onbytes;
3978 else if (infoLevel == 0x103)
3979 *((u_long *)(op + 8)) = onbytes;
3981 *((u_long *)(op + 60)) = onbytes;
3982 strcpy(origOp+ohbytes, dep->name);
3983 if (smb_StoreAnsiFilenames)
3984 CharToOem(origOp+ohbytes, origOp+ohbytes);
3986 /* Short name if requested and needed */
3987 if (infoLevel == 0x104) {
3988 if (NeedShortName) {
3989 strcpy(op + 70, shortName);
3990 if (smb_StoreAnsiFilenames)
3991 CharToOem(op + 70, op + 70);
3992 *(op + 68) = shortNameEnd - shortName;
3996 /* now, adjust the # of entries copied */
3999 /* NextEntryOffset and FileIndex */
4000 if (infoLevel >= 101) {
4001 int entryOffset = orbytes + align;
4002 *((u_long *)op) = entryOffset;
4003 *((u_long *)(op+4)) = nextEntryCookie;
4006 /* now we emit the attribute. This is tricky, since
4007 * we need to really stat the file to find out what
4008 * type of entry we've got. Right now, we're copying
4009 * out data from a buffer, while holding the scp
4010 * locked, so it isn't really convenient to stat
4011 * something now. We'll put in a place holder
4012 * now, and make a second pass before returning this
4013 * to get the real attributes. So, we just skip the
4014 * data for now, and adjust it later. We allocate a
4015 * patch record to make it easy to find this point
4016 * later. The replay will happen at a time when it is
4017 * safe to unlock the directory.
4019 if (infoLevel != 0x103) {
4020 curPatchp = malloc(sizeof(*curPatchp));
4021 osi_QAdd((osi_queue_t **) &dirListPatchesp,
4023 curPatchp->dptr = op;
4024 if (infoLevel >= 0x101)
4025 curPatchp->dptr += 8;
4027 if (smb_hideDotFiles && smb_IsDotFile(dep->name)) {
4028 curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
4031 curPatchp->flags = 0;
4033 curPatchp->fid.cell = scp->fid.cell;
4034 curPatchp->fid.volume = scp->fid.volume;
4035 curPatchp->fid.vnode = ntohl(dep->fid.vnode);
4036 curPatchp->fid.unique = ntohl(dep->fid.unique);
4039 curPatchp->dep = dep;
4042 if (searchFlags & 4)
4043 /* put out resume key */
4044 *((u_long *)origOp) = nextEntryCookie;
4046 /* Adjust byte ptr and count */
4047 origOp += orbytes; /* skip entire record */
4048 bytesInBuffer += orbytes;
4050 /* and pad the record out */
4051 while (--align >= 0) {
4055 } /* if we're including this name */
4056 else if (!NeedShortName &&
4059 dep->fid.vnode != 0 &&
4060 smb_V3MatchMask(dep->name, maskp, CM_FLAG_CASEFOLD)) {
4061 /* We were looking for exact matches, but here's an inexact one*/
4066 /* and adjust curOffset to be where the new cookie is */
4067 thyper.HighPart = 0;
4068 thyper.LowPart = CM_DIR_CHUNKSIZE * numDirChunks;
4069 curOffset = LargeIntegerAdd(thyper, curOffset);
4070 } /* while copying data for dir listing */
4072 /* If we didn't get a star pattern, we did an exact match during the first pass.
4073 * If there were no exact matches found, we fail over to inexact matches by
4074 * marking the query as a star pattern (matches all case permutations), and
4075 * re-running the query.
4077 if (returnedNames == 0 && !starPattern && foundInexact) {
4078 osi_Log0(afsd_logp,"T2 Search: No exact matches. Re-running for inexact matches");
4083 /* release the mutex */
4084 lock_ReleaseMutex(&scp->mx);
4085 if (bufferp) buf_Release(bufferp);
4087 /* apply and free last set of patches; if not doing a star match, this
4088 * will be empty, but better safe (and freeing everything) than sorry.
4090 smb_ApplyV3DirListPatches(scp, &dirListPatchesp, infoLevel, userp,
4093 /* now put out the final parameters */
4094 if (returnedNames == 0) eos = 1;
4095 if (p->opcode == 1) {
4097 outp->parmsp[0] = (unsigned short) dsp->cookie;
4098 outp->parmsp[1] = returnedNames;
4099 outp->parmsp[2] = eos;
4100 outp->parmsp[3] = 0; /* nothing wrong with EAS */
4101 outp->parmsp[4] = 0;
4102 /* don't need last name to continue
4103 * search, cookie is enough. Normally,
4104 * this is the offset of the file name
4105 * of the last entry returned.
4107 outp->totalParms = 10; /* in bytes */
4111 outp->parmsp[0] = returnedNames;
4112 outp->parmsp[1] = eos;
4113 outp->parmsp[2] = 0; /* EAS error */
4114 outp->parmsp[3] = 0; /* last name, as above */
4115 outp->totalParms = 8; /* in bytes */
4118 /* return # of bytes in the buffer */
4119 outp->totalData = bytesInBuffer;
4121 osi_Log2(smb_logp, "T2 search dir done, %d names, code %d",
4122 returnedNames, code);
4124 /* Return error code if unsuccessful on first request */
4125 if (code == 0 && p->opcode == 1 && returnedNames == 0)
4126 code = CM_ERROR_NOSUCHFILE;
4128 /* if we're supposed to close the search after this request, or if
4129 * we're supposed to close the search if we're done, and we're done,
4130 * or if something went wrong, close the search.
4132 /* ((searchFlags & 1) || ((searchFlags & 2) && eos) */
4133 if ((searchFlags & 1) || (returnedNames == 0) ||
4134 ((searchFlags & 2) && eos) || code != 0)
4135 smb_DeleteDirSearch(dsp);
4137 smb_SendTran2Error(vcp, p, opx, code);
4139 smb_SendTran2Packet(vcp, outp, opx);
4141 smb_FreeTran2Packet(outp);
4142 smb_ReleaseDirSearch(dsp);
4143 cm_ReleaseSCache(scp);
4144 cm_ReleaseUser(userp);
4148 long smb_ReceiveV3FindClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4151 smb_dirSearch_t *dsp;
4153 dirHandle = smb_GetSMBParm(inp, 0);
4155 osi_Log1(smb_logp, "SMB3 find close handle %d", dirHandle);
4157 dsp = smb_FindDirSearch(dirHandle);
4160 return CM_ERROR_BADFD;
4162 /* otherwise, we have an FD to destroy */
4163 smb_DeleteDirSearch(dsp);
4164 smb_ReleaseDirSearch(dsp);
4166 /* and return results */
4167 smb_SetSMBDataLength(outp, 0);
4172 long smb_ReceiveV3FindNotifyClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4174 smb_SetSMBDataLength(outp, 0);
4178 long smb_ReceiveV3OpenX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4185 cm_scache_t *dscp; /* dir we're dealing with */
4186 cm_scache_t *scp; /* file we're creating */
4188 int initialModeBits;
4198 int parmSlot; /* which parm we're dealing with */
4206 extraInfo = (smb_GetSMBParm(inp, 2) & 1); /* return extra info */
4207 openFun = smb_GetSMBParm(inp, 8); /* open function */
4208 excl = ((openFun & 3) == 0);
4209 trunc = ((openFun & 3) == 2); /* truncate it */
4210 openMode = (smb_GetSMBParm(inp, 3) & 0x7);
4211 openAction = 0; /* tracks what we did */
4213 attributes = smb_GetSMBParm(inp, 5);
4214 dosTime = smb_GetSMBParm(inp, 6) | (smb_GetSMBParm(inp, 7) << 16);
4216 /* compute initial mode bits based on read-only flag in attributes */
4217 initialModeBits = 0666;
4218 if (attributes & 1) initialModeBits &= ~0222;
4220 pathp = smb_GetSMBData(inp, NULL);
4221 if (smb_StoreAnsiFilenames)
4222 OemToChar(pathp,pathp);
4224 spacep = inp->spacep;
4225 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
4227 if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
4228 /* special case magic file name for receiving IOCTL requests
4229 * (since IOCTL calls themselves aren't getting through).
4232 osi_Log0(smb_logp, "IOCTL Open");
4235 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
4236 smb_SetupIoctlFid(fidp, spacep);
4238 /* set inp->fid so that later read calls in same msg can find fid */
4239 inp->fid = fidp->fid;
4241 /* copy out remainder of the parms */
4243 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
4245 smb_SetSMBParm(outp, parmSlot, /* attrs */ 0); parmSlot++;
4246 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* mod time */
4247 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
4248 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* len */
4249 smb_SetSMBParm(outp, parmSlot, 0x7fff); parmSlot++;
4250 smb_SetSMBParm(outp, parmSlot, openMode); parmSlot++;
4251 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* file type 0 ==> normal file or dir */
4252 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* IPC junk */
4254 /* and the final "always present" stuff */
4255 smb_SetSMBParm(outp, parmSlot, /* openAction found existing file */ 1); parmSlot++;
4256 /* next write out the "unique" ID */
4257 smb_SetSMBParm(outp, parmSlot, 0x1234); parmSlot++;
4258 smb_SetSMBParm(outp, parmSlot, 0x5678); parmSlot++;
4259 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
4260 smb_SetSMBDataLength(outp, 0);
4262 /* and clean up fid reference */
4263 smb_ReleaseFID(fidp);
4267 #ifdef DEBUG_VERBOSE
4269 char *hexp, *asciip;
4270 asciip = (lastNamep ? lastNamep : pathp );
4271 hexp = osi_HexifyString(asciip);
4272 DEBUG_EVENT2("AFS", "V3Open H[%s] A[%s]", hexp, asciip );
4276 userp = smb_GetUser(vcp, inp);
4279 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4281 cm_ReleaseUser(userp);
4282 return CM_ERROR_NOSUCHPATH;
4284 code = cm_NameI(cm_rootSCachep, pathp,
4285 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
4286 userp, tidPathp, &req, &scp);
4288 code = cm_NameI(cm_rootSCachep, spacep->data,
4289 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
4290 userp, tidPathp, &req, &dscp);
4293 cm_ReleaseUser(userp);
4297 /* otherwise, scp points to the parent directory. Do a lookup,
4298 * and truncate the file if we find it, otherwise we create the
4301 if (!lastNamep) lastNamep = pathp;
4303 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD, userp,
4305 if (code && code != CM_ERROR_NOSUCHFILE) {
4306 cm_ReleaseSCache(dscp);
4307 cm_ReleaseUser(userp);
4312 /* if we get here, if code is 0, the file exists and is represented by
4313 * scp. Otherwise, we have to create it. The dir may be represented
4314 * by dscp, or we may have found the file directly. If code is non-zero,
4318 code = cm_CheckOpen(scp, openMode, trunc, userp, &req);
4320 if (dscp) cm_ReleaseSCache(dscp);
4321 cm_ReleaseSCache(scp);
4322 cm_ReleaseUser(userp);
4327 /* oops, file shouldn't be there */
4328 if (dscp) cm_ReleaseSCache(dscp);
4329 cm_ReleaseSCache(scp);
4330 cm_ReleaseUser(userp);
4331 return CM_ERROR_EXISTS;
4335 setAttr.mask = CM_ATTRMASK_LENGTH;
4336 setAttr.length.LowPart = 0;
4337 setAttr.length.HighPart = 0;
4338 code = cm_SetAttr(scp, &setAttr, userp, &req);
4339 openAction = 3; /* truncated existing file */
4341 else openAction = 1; /* found existing file */
4343 else if (!(openFun & 0x10)) {
4344 /* don't create if not found */
4345 if (dscp) cm_ReleaseSCache(dscp);
4346 cm_ReleaseUser(userp);
4347 return CM_ERROR_NOSUCHFILE;
4350 osi_assert(dscp != NULL);
4351 osi_Log1(smb_logp, "smb_ReceiveV3OpenX creating file %s",
4352 osi_LogSaveString(smb_logp, lastNamep));
4353 openAction = 2; /* created file */
4354 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
4355 smb_UnixTimeFromDosUTime(&setAttr.clientModTime, dosTime);
4356 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
4358 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
4359 smb_NotifyChange(FILE_ACTION_ADDED,
4360 FILE_NOTIFY_CHANGE_FILE_NAME,
4361 dscp, lastNamep, NULL, TRUE);
4362 if (!excl && code == CM_ERROR_EXISTS) {
4363 /* not an exclusive create, and someone else tried
4364 * creating it already, then we open it anyway. We
4365 * don't bother retrying after this, since if this next
4366 * fails, that means that the file was deleted after we
4367 * started this call.
4369 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
4373 setAttr.mask = CM_ATTRMASK_LENGTH;
4374 setAttr.length.LowPart = 0;
4375 setAttr.length.HighPart = 0;
4376 code = cm_SetAttr(scp, &setAttr, userp, &req);
4378 } /* lookup succeeded */
4382 /* we don't need this any longer */
4383 if (dscp) cm_ReleaseSCache(dscp);
4386 /* something went wrong creating or truncating the file */
4387 if (scp) cm_ReleaseSCache(scp);
4388 cm_ReleaseUser(userp);
4392 /* make sure we're about to open a file */
4393 if (scp->fileType != CM_SCACHETYPE_FILE) {
4394 cm_ReleaseSCache(scp);
4395 cm_ReleaseUser(userp);
4396 return CM_ERROR_ISDIR;
4399 /* now all we have to do is open the file itself */
4400 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
4403 /* save a pointer to the vnode */
4406 /* compute open mode */
4407 if (openMode != 1) fidp->flags |= SMB_FID_OPENREAD;
4408 if (openMode == 1 || openMode == 2)
4409 fidp->flags |= SMB_FID_OPENWRITE;
4411 smb_ReleaseFID(fidp);
4413 cm_Open(scp, 0, userp);
4415 /* set inp->fid so that later read calls in same msg can find fid */
4416 inp->fid = fidp->fid;
4418 /* copy out remainder of the parms */
4420 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
4421 lock_ObtainMutex(&scp->mx);
4423 smb_SetSMBParm(outp, parmSlot, smb_Attributes(scp)); parmSlot++;
4424 smb_DosUTimeFromUnixTime(&dosTime, scp->clientModTime);
4425 smb_SetSMBParm(outp, parmSlot, dosTime & 0xffff); parmSlot++;
4426 smb_SetSMBParm(outp, parmSlot, (dosTime>>16) & 0xffff); parmSlot++;
4427 smb_SetSMBParm(outp, parmSlot, scp->length.LowPart & 0xffff); parmSlot++;
4428 smb_SetSMBParm(outp, parmSlot, (scp->length.LowPart >> 16) & 0xffff); parmSlot++;
4429 smb_SetSMBParm(outp, parmSlot, openMode); parmSlot++;
4430 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* file type 0 ==> normal file or dir */
4431 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* IPC junk */
4433 /* and the final "always present" stuff */
4434 smb_SetSMBParm(outp, parmSlot, openAction); parmSlot++;
4435 /* next write out the "unique" ID */
4436 smb_SetSMBParm(outp, parmSlot, scp->fid.vnode & 0xffff); parmSlot++;
4437 smb_SetSMBParm(outp, parmSlot, scp->fid.volume & 0xffff); parmSlot++;
4438 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
4439 lock_ReleaseMutex(&scp->mx);
4440 smb_SetSMBDataLength(outp, 0);
4442 osi_Log1(smb_logp, "SMB OpenX opening fid %d", fidp->fid);
4444 cm_ReleaseUser(userp);
4445 /* leave scp held since we put it in fidp->scp */
4449 long smb_ReceiveV3LockingX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4456 unsigned char LockType;
4457 unsigned short NumberOfUnlocks, NumberOfLocks;
4458 unsigned long Timeout;
4460 LARGE_INTEGER LOffset, LLength;
4461 smb_waitingLock_t *waitingLock;
4468 fid = smb_GetSMBParm(inp, 2);
4469 fid = smb_ChainFID(fid, inp);
4471 fidp = smb_FindFID(vcp, fid, 0);
4472 if (!fidp || (fidp->flags & SMB_FID_IOCTL)) {
4473 return CM_ERROR_BADFD;
4475 /* set inp->fid so that later read calls in same msg can find fid */
4478 userp = smb_GetUser(vcp, inp);
4482 lock_ObtainMutex(&scp->mx);
4483 code = cm_SyncOp(scp, NULL, userp, &req, 0,
4484 CM_SCACHESYNC_NEEDCALLBACK
4485 | CM_SCACHESYNC_GETSTATUS
4486 | CM_SCACHESYNC_LOCK);
4487 if (code) goto doneSync;
4489 LockType = smb_GetSMBParm(inp, 3) & 0xff;
4490 Timeout = (smb_GetSMBParm(inp, 5) << 16) + smb_GetSMBParm(inp, 4);
4491 NumberOfUnlocks = smb_GetSMBParm(inp, 6);
4492 NumberOfLocks = smb_GetSMBParm(inp, 7);
4494 op = smb_GetSMBData(inp, NULL);
4496 for (i=0; i<NumberOfUnlocks; i++) {
4497 if (LockType & 0x10) {
4499 LOffset.HighPart = *((LONG *)(op + 4));
4500 LOffset.LowPart = *((DWORD *)(op + 8));
4501 LLength.HighPart = *((LONG *)(op + 12));
4502 LLength.LowPart = *((DWORD *)(op + 16));
4506 /* Not Large Files */
4507 LOffset.HighPart = 0;
4508 LOffset.LowPart = *((DWORD *)(op + 2));
4509 LLength.HighPart = 0;
4510 LLength.LowPart = *((DWORD *)(op + 6));
4513 if (LargeIntegerNotEqualToZero(LOffset))
4515 /* Do not check length -- length check done in cm_Unlock */
4517 code = cm_Unlock(scp, LockType, LOffset, LLength, userp, &req);
4518 if (code) goto done;
4521 for (i=0; i<NumberOfLocks; i++) {
4522 if (LockType & 0x10) {
4524 LOffset.HighPart = *((LONG *)(op + 4));
4525 LOffset.LowPart = *((DWORD *)(op + 8));
4526 LLength.HighPart = *((LONG *)(op + 12));
4527 LLength.LowPart = *((DWORD *)(op + 16));
4531 /* Not Large Files */
4532 LOffset.HighPart = 0;
4533 LOffset.LowPart = *((DWORD *)(op + 2));
4534 LLength.HighPart = 0;
4535 LLength.LowPart = *((DWORD *)(op + 6));
4538 if (LargeIntegerNotEqualToZero(LOffset))
4540 if (LargeIntegerLessThan(LOffset, scp->length))
4543 code = cm_Lock(scp, LockType, LOffset, LLength, Timeout,
4544 userp, &req, &lockp);
4545 if (code == CM_ERROR_WOULDBLOCK && Timeout != 0) {
4546 /* Put on waiting list */
4547 waitingLock = malloc(sizeof(smb_waitingLock_t));
4548 waitingLock->vcp = vcp;
4549 waitingLock->inp = smb_CopyPacket(inp);
4550 waitingLock->outp = smb_CopyPacket(outp);
4551 waitingLock->timeRemaining = Timeout;
4552 waitingLock->lockp = lockp;
4553 lock_ObtainWrite(&smb_globalLock);
4554 osi_QAdd((osi_queue_t **)&smb_allWaitingLocks,
4556 osi_Wakeup((long) &smb_allWaitingLocks);
4557 lock_ReleaseWrite(&smb_globalLock);
4558 /* don't send reply immediately */
4559 outp->flags |= SMB_PACKETFLAG_NOSEND;
4565 /* release any locks acquired before the failure */
4568 smb_SetSMBDataLength(outp, 0);
4570 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_LOCK);
4572 lock_ReleaseMutex(&scp->mx);
4573 cm_ReleaseUser(userp);
4574 smb_ReleaseFID(fidp);
4579 long smb_ReceiveV3GetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4591 fid = smb_GetSMBParm(inp, 0);
4592 fid = smb_ChainFID(fid, inp);
4594 fidp = smb_FindFID(vcp, fid, 0);
4595 if (!fidp || (fidp->flags & SMB_FID_IOCTL)) {
4596 return CM_ERROR_BADFD;
4599 userp = smb_GetUser(vcp, inp);
4603 /* otherwise, stat the file */
4604 lock_ObtainMutex(&scp->mx);
4605 code = cm_SyncOp(scp, NULL, userp, &req, 0,
4606 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4607 if (code) goto done;
4609 /* decode times. We need a search time, but the response to this
4610 * call provides the date first, not the time, as returned in the
4611 * searchTime variable. So we take the high-order bits first.
4613 smb_SearchTimeFromUnixTime(&searchTime, scp->clientModTime);
4614 smb_SetSMBParm(outp, 0, (searchTime >> 16) & 0xffff); /* ctime */
4615 smb_SetSMBParm(outp, 1, searchTime & 0xffff);
4616 smb_SetSMBParm(outp, 2, (searchTime >> 16) & 0xffff); /* atime */
4617 smb_SetSMBParm(outp, 3, searchTime & 0xffff);
4618 smb_SetSMBParm(outp, 4, (searchTime >> 16) & 0xffff); /* mtime */
4619 smb_SetSMBParm(outp, 5, searchTime & 0xffff);
4621 /* now handle file size and allocation size */
4622 smb_SetSMBParm(outp, 6, scp->length.LowPart & 0xffff); /* file size */
4623 smb_SetSMBParm(outp, 7, (scp->length.LowPart >> 16) & 0xffff);
4624 smb_SetSMBParm(outp, 8, scp->length.LowPart & 0xffff); /* alloc size */
4625 smb_SetSMBParm(outp, 9, (scp->length.LowPart >> 16) & 0xffff);
4627 /* file attribute */
4628 smb_SetSMBParm(outp, 10, smb_Attributes(scp));
4630 /* and finalize stuff */
4631 smb_SetSMBDataLength(outp, 0);
4635 lock_ReleaseMutex(&scp->mx);
4636 cm_ReleaseUser(userp);
4637 smb_ReleaseFID(fidp);
4641 long smb_ReceiveV3SetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4655 fid = smb_GetSMBParm(inp, 0);
4656 fid = smb_ChainFID(fid, inp);
4658 fidp = smb_FindFID(vcp, fid, 0);
4659 if (!fidp || (fidp->flags & SMB_FID_IOCTL)) {
4660 return CM_ERROR_BADFD;
4663 userp = smb_GetUser(vcp, inp);
4667 /* now prepare to call cm_setattr. This message only sets various times,
4668 * and AFS only implements mtime, and we'll set the mtime if that's
4669 * requested. The others we'll ignore.
4671 searchTime = smb_GetSMBParm(inp, 5) | (smb_GetSMBParm(inp, 6) << 16);
4673 if (searchTime != 0) {
4674 smb_UnixTimeFromSearchTime(&unixTime, searchTime);
4676 if ( unixTime != -1 ) {
4677 attrs.mask = CM_ATTRMASK_CLIENTMODTIME;
4678 attrs.clientModTime = unixTime;
4679 code = cm_SetAttr(scp, &attrs, userp, &req);
4681 osi_Log1(smb_logp, "SMB receive V3SetAttributes [fid=%ld]", fid);
4683 osi_Log1(smb_logp, "**smb_UnixTimeFromSearchTime failed searchTime=%ld", searchTime);
4688 cm_ReleaseUser(userp);
4689 smb_ReleaseFID(fidp);
4694 long smb_ReceiveV3ReadX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4697 long count, finalCount;
4704 fd = smb_GetSMBParm(inp, 2);
4705 count = smb_GetSMBParm(inp, 5);
4706 offset.HighPart = 0; /* too bad */
4707 offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
4709 osi_Log3(smb_logp, "smb_ReceiveV3Read fd %d, off 0x%x, size 0x%x",
4710 fd, offset.LowPart, count);
4712 fd = smb_ChainFID(fd, inp);
4713 fidp = smb_FindFID(vcp, fd, 0);
4715 return CM_ERROR_BADFD;
4717 /* set inp->fid so that later read calls in same msg can find fid */
4720 if (fidp->flags & SMB_FID_IOCTL) {
4721 return smb_IoctlV3Read(fidp, vcp, inp, outp);
4724 userp = smb_GetUser(vcp, inp);
4726 /* 0 and 1 are reserved for request chaining, were setup by our caller,
4727 * and will be further filled in after we return.
4729 smb_SetSMBParm(outp, 2, 0); /* remaining bytes, for pipes */
4730 smb_SetSMBParm(outp, 3, 0); /* resvd */
4731 smb_SetSMBParm(outp, 4, 0); /* resvd */
4732 smb_SetSMBParm(outp, 5, count); /* # of bytes we're going to read */
4733 /* fill in #6 when we have all the parameters' space reserved */
4734 smb_SetSMBParm(outp, 7, 0); /* resv'd */
4735 smb_SetSMBParm(outp, 8, 0); /* resv'd */
4736 smb_SetSMBParm(outp, 9, 0); /* resv'd */
4737 smb_SetSMBParm(outp, 10, 0); /* resv'd */
4738 smb_SetSMBParm(outp, 11, 0); /* reserved */
4740 /* get op ptr after putting in the parms, since otherwise we don't
4741 * know where the data really is.
4743 op = smb_GetSMBData(outp, NULL);
4745 /* now fill in offset from start of SMB header to first data byte (to op) */
4746 smb_SetSMBParm(outp, 6, ((int) (op - outp->data)));
4748 /* set the packet data length the count of the # of bytes */
4749 smb_SetSMBDataLength(outp, count);
4752 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount);
4754 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount, FALSE);
4757 /* fix some things up */
4758 smb_SetSMBParm(outp, 5, finalCount);
4759 smb_SetSMBDataLength(outp, finalCount);
4761 smb_ReleaseFID(fidp);
4763 cm_ReleaseUser(userp);
4768 * Values for createDisp, copied from NTDDK.H
4770 #define FILE_SUPERSEDE 0 // (???)
4771 #define FILE_OPEN 1 // (open)
4772 #define FILE_CREATE 2 // (exclusive)
4773 #define FILE_OPEN_IF 3 // (non-exclusive)
4774 #define FILE_OVERWRITE 4 // (open & truncate, but do not create)
4775 #define FILE_OVERWRITE_IF 5 // (open & truncate, or create)
4777 long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4779 char *pathp, *realPathp;
4783 cm_scache_t *dscp; /* parent dir */
4784 cm_scache_t *scp; /* file to create or open */
4785 cm_scache_t *targetScp; /* if scp is a symlink */
4789 unsigned short nameLength;
4791 unsigned int requestOpLock;
4792 unsigned int requestBatchOpLock;
4793 unsigned int mustBeDir;
4794 unsigned int treeCreate;
4796 unsigned int desiredAccess;
4797 unsigned int extAttributes;
4798 unsigned int createDisp;
4799 unsigned int createOptions;
4800 int initialModeBits;
4801 unsigned short baseFid;
4802 smb_fid_t *baseFidp;
4804 cm_scache_t *baseDirp;
4805 unsigned short openAction;
4820 nameLength = smb_GetSMBOffsetParm(inp, 2, 1);
4821 flags = smb_GetSMBOffsetParm(inp, 3, 1)
4822 | (smb_GetSMBOffsetParm(inp, 4, 1) << 16);
4823 requestOpLock = flags & 0x02;
4824 requestBatchOpLock = flags & 0x04;
4825 mustBeDir = flags & 0x08;
4828 * Why all of a sudden 32-bit FID?
4829 * We will reject all bits higher than 16.
4831 if (smb_GetSMBOffsetParm(inp, 6, 1) != 0)
4832 return CM_ERROR_INVAL;
4833 baseFid = smb_GetSMBOffsetParm(inp, 5, 1);
4834 desiredAccess = smb_GetSMBOffsetParm(inp, 7, 1)
4835 | (smb_GetSMBOffsetParm(inp, 8, 1) << 16);
4836 extAttributes = smb_GetSMBOffsetParm(inp, 13, 1)
4837 | (smb_GetSMBOffsetParm(inp, 14, 1) << 16);
4838 createDisp = smb_GetSMBOffsetParm(inp, 17, 1)
4839 | (smb_GetSMBOffsetParm(inp, 18, 1) << 16);
4840 createOptions = smb_GetSMBOffsetParm(inp, 19, 1)
4841 | (smb_GetSMBOffsetParm(inp, 20, 1) << 16);
4843 /* mustBeDir is never set; createOptions directory bit seems to be
4846 if (createOptions & 1)
4848 else if (createOptions & 0x40)
4854 * compute initial mode bits based on read-only flag in
4855 * extended attributes
4857 initialModeBits = 0666;
4858 if (extAttributes & 1)
4859 initialModeBits &= ~0222;
4861 pathp = smb_GetSMBData(inp, NULL);
4862 /* Sometimes path is not null-terminated, so we make a copy. */
4863 realPathp = malloc(nameLength+1);
4864 memcpy(realPathp, pathp, nameLength);
4865 realPathp[nameLength] = 0;
4866 if (smb_StoreAnsiFilenames)
4867 OemToChar(realPathp,realPathp);
4869 spacep = inp->spacep;
4870 smb_StripLastComponent(spacep->data, &lastNamep, realPathp);
4872 osi_Log1(smb_logp,"NTCreateX for [%s]",osi_LogSaveString(smb_logp,realPathp));
4873 osi_Log4(smb_logp,"... da=[%x] ea=[%x] cd=[%x] co=[%x]", desiredAccess, extAttributes, createDisp, createOptions);
4874 osi_Log2(smb_logp,"... flags=[%x] lastNamep=[%s]", flags, osi_LogSaveString(smb_logp,(lastNamep?lastNamep:"null")));
4876 if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
4877 /* special case magic file name for receiving IOCTL requests
4878 * (since IOCTL calls themselves aren't getting through).
4880 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
4881 smb_SetupIoctlFid(fidp, spacep);
4882 osi_Log1(smb_logp,"NTCreateX Setting up IOCTL on fid[%d]",fidp->fid);
4884 /* set inp->fid so that later read calls in same msg can find fid */
4885 inp->fid = fidp->fid;
4889 smb_SetSMBParmByte(outp, parmSlot, 0); /* oplock */
4890 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
4891 smb_SetSMBParmLong(outp, parmSlot, 1); parmSlot += 2; /* Action */
4893 memset(&ft, 0, sizeof(ft));
4894 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
4895 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
4896 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
4897 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
4898 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2; /* attr */
4899 sz.HighPart = 0x7fff; sz.LowPart = 0;
4900 smb_SetSMBParmDouble(outp, parmSlot, (char *)&sz); parmSlot += 4; /* alen */
4901 smb_SetSMBParmDouble(outp, parmSlot, (char *)&sz); parmSlot += 4; /* len */
4902 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* filetype */
4903 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* dev state */
4904 smb_SetSMBParmByte(outp, parmSlot, 0); /* is a dir? */
4905 smb_SetSMBDataLength(outp, 0);
4907 /* clean up fid reference */
4908 smb_ReleaseFID(fidp);
4913 #ifdef DEBUG_VERBOSE
4915 char *hexp, *asciip;
4916 asciip = (lastNamep? lastNamep : realPathp);
4917 hexp = osi_HexifyString( asciip );
4918 DEBUG_EVENT2("AFS", "NTCreateX H[%s] A[%s]", hexp, asciip);
4922 userp = smb_GetUser(vcp, inp);
4924 osi_Log1(smb_logp, "NTCreateX Invalid user [%d]", ((smb_t *) inp)->uid);
4926 return CM_ERROR_INVAL;
4930 baseDirp = cm_rootSCachep;
4931 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4932 if (code == CM_ERROR_TIDIPC) {
4933 /* Attempt to use a TID allocated for IPC. The client
4934 * is probably looking for DCE RPC end points which we
4936 osi_Log0(smb_logp, "NTCreateX received IPC TID");
4938 cm_ReleaseUser(userp);
4939 return CM_ERROR_NOSUCHFILE;
4943 baseFidp = smb_FindFID(vcp, baseFid, 0);
4945 osi_Log1(smb_logp, "NTCreateX Invalid base fid [%d]", baseFid);
4947 cm_ReleaseUser(userp);
4948 return CM_ERROR_INVAL;
4950 baseDirp = baseFidp->scp;
4954 osi_Log1(smb_logp, "NTCreateX tidPathp=[%s]", (tidPathp==NULL)?"null": osi_LogSaveString(smb_logp,tidPathp));
4956 /* compute open mode */
4958 if (desiredAccess & DELETE)
4959 fidflags |= SMB_FID_OPENDELETE;
4960 if (desiredAccess & AFS_ACCESS_READ)
4961 fidflags |= SMB_FID_OPENREAD;
4962 if (desiredAccess & AFS_ACCESS_WRITE)
4963 fidflags |= SMB_FID_OPENWRITE;
4967 /* For an exclusive create, we want to do a case sensitive match for the last component. */
4968 if ( createDisp == FILE_CREATE ||
4969 createDisp == FILE_OVERWRITE ||
4970 createDisp == FILE_OVERWRITE_IF) {
4971 code = cm_NameI(baseDirp, spacep->data, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
4972 userp, tidPathp, &req, &dscp);
4974 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp, CM_FLAG_FOLLOW,
4976 if (code == CM_ERROR_NOSUCHFILE) {
4977 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp,
4978 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, &req, &scp);
4979 if (code == 0 && realDirFlag == 1) {
4980 cm_ReleaseSCache(scp);
4981 cm_ReleaseSCache(dscp);
4982 cm_ReleaseUser(userp);
4984 return CM_ERROR_EXISTS;
4990 code = cm_NameI(baseDirp, realPathp, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
4991 userp, tidPathp, &req, &scp);
4996 if (!foundscp || (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE))) {
4997 /* look up parent directory */
4998 /* If we are trying to create a path (i.e. multiple nested directories), then we don't *need*
4999 * the immediate parent. We have to work our way up realPathp until we hit something that we
5007 code = cm_NameI(baseDirp, spacep->data,
5008 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
5009 userp, tidPathp, &req, &dscp);
5012 (tp = strrchr(spacep->data,'\\')) &&
5013 (createDisp == FILE_CREATE) &&
5014 (realDirFlag == 1)) {
5017 treeStartp = realPathp + (tp - spacep->data);
5019 if (*tp && !smb_IsLegalFilename(tp)) {
5021 smb_ReleaseFID(baseFidp);
5022 cm_ReleaseUser(userp);
5024 return CM_ERROR_BADNTFILENAME;
5034 smb_ReleaseFID(baseFidp);
5037 osi_Log0(smb_logp,"NTCreateX parent not found");
5038 cm_ReleaseUser(userp);
5043 if (treeCreate && dscp->fileType == CM_SCACHETYPE_FILE) {
5044 /* A file exists where we want a directory. */
5045 cm_ReleaseSCache(dscp);
5046 cm_ReleaseUser(userp);
5048 return CM_ERROR_EXISTS;
5052 lastNamep = realPathp;
5056 if (!smb_IsLegalFilename(lastNamep)) {
5057 cm_ReleaseSCache(dscp);
5058 cm_ReleaseUser(userp);
5060 return CM_ERROR_BADNTFILENAME;
5063 if (!foundscp && !treeCreate) {
5064 if ( createDisp == FILE_CREATE ||
5065 createDisp == FILE_OVERWRITE ||
5066 createDisp == FILE_OVERWRITE_IF)
5068 code = cm_Lookup(dscp, lastNamep,
5069 CM_FLAG_FOLLOW, userp, &req, &scp);
5071 code = cm_Lookup(dscp, lastNamep,
5072 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
5075 if (code && code != CM_ERROR_NOSUCHFILE) {
5076 cm_ReleaseSCache(dscp);
5077 cm_ReleaseUser(userp);
5085 smb_ReleaseFID(baseFidp);
5088 /* if we get here, if code is 0, the file exists and is represented by
5089 * scp. Otherwise, we have to create it. The dir may be represented
5090 * by dscp, or we may have found the file directly. If code is non-zero,
5093 if (code == 0 && !treeCreate) {
5094 if (createDisp == FILE_CREATE) {
5095 /* oops, file shouldn't be there */
5096 if (dscp) cm_ReleaseSCache(dscp);
5097 cm_ReleaseSCache(scp);
5098 cm_ReleaseUser(userp);
5100 return CM_ERROR_EXISTS;
5103 if ( createDisp == FILE_OVERWRITE ||
5104 createDisp == FILE_OVERWRITE_IF) {
5105 setAttr.mask = CM_ATTRMASK_LENGTH;
5106 setAttr.length.LowPart = 0;
5107 setAttr.length.HighPart = 0;
5108 /* now watch for a symlink */
5110 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
5112 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
5114 /* we have a more accurate file to use (the
5115 * target of the symbolic link). Otherwise,
5116 * we'll just use the symlink anyway.
5118 osi_Log2(smb_logp, "symlink vp %x to vp %x",
5120 cm_ReleaseSCache(scp);
5124 code = cm_SetAttr(scp, &setAttr, userp, &req);
5125 openAction = 3; /* truncated existing file */
5128 openAction = 1; /* found existing file */
5130 code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp,
5133 if (dscp) cm_ReleaseSCache(dscp);
5134 cm_ReleaseSCache(scp);
5135 cm_ReleaseUser(userp);
5140 else if (createDisp == FILE_OPEN || createDisp == FILE_OVERWRITE) {
5141 /* don't create if not found */
5142 if (dscp) cm_ReleaseSCache(dscp);
5143 cm_ReleaseUser(userp);
5145 return CM_ERROR_NOSUCHFILE;
5147 else if (realDirFlag == 0 || realDirFlag == -1) {
5148 osi_assert(dscp != NULL);
5149 osi_Log1(smb_logp, "smb_ReceiveNTCreateX creating file %s",
5150 osi_LogSaveString(smb_logp, lastNamep));
5151 openAction = 2; /* created file */
5152 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
5153 setAttr.clientModTime = time(NULL);
5154 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
5156 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
5157 smb_NotifyChange(FILE_ACTION_ADDED,
5158 FILE_NOTIFY_CHANGE_FILE_NAME,
5159 dscp, lastNamep, NULL, TRUE);
5160 if (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE) {
5161 /* Not an exclusive create, and someone else tried
5162 * creating it already, then we open it anyway. We
5163 * don't bother retrying after this, since if this next
5164 * fails, that means that the file was deleted after we
5165 * started this call.
5167 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
5170 if (createDisp == FILE_OVERWRITE_IF) {
5171 setAttr.mask = CM_ATTRMASK_LENGTH;
5172 setAttr.length.LowPart = 0;
5173 setAttr.length.HighPart = 0;
5175 /* now watch for a symlink */
5177 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
5179 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
5181 /* we have a more accurate file to use (the
5182 * target of the symbolic link). Otherwise,
5183 * we'll just use the symlink anyway.
5185 osi_Log2(smb_logp, "symlink vp %x to vp %x",
5187 cm_ReleaseSCache(scp);
5191 code = cm_SetAttr(scp, &setAttr, userp, &req);
5193 } /* lookup succeeded */
5198 char *cp; /* This component */
5199 int clen = 0; /* length of component */
5203 /* create directory */
5205 treeStartp = lastNamep;
5206 osi_assert(dscp != NULL);
5207 osi_Log1(smb_logp, "smb_ReceiveNTCreateX creating directory [%s]",
5208 osi_LogSaveString(smb_logp, treeStartp));
5209 openAction = 2; /* created directory */
5211 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
5212 setAttr.clientModTime = time(NULL);
5219 tp = strchr(pp, '\\');
5223 isLast = 1; /* indicate last component. the supplied path never ends in a slash */
5227 strncpy(cp,pp,clen);
5234 continue; /* the supplied path can't have consecutive slashes either , but */
5236 /* cp is the next component to be created. */
5237 code = cm_MakeDir(tscp, cp, 0, &setAttr, userp, &req);
5238 if (code == 0 && (tscp->flags & CM_SCACHEFLAG_ANYWATCH))
5239 smb_NotifyChange(FILE_ACTION_ADDED,
5240 FILE_NOTIFY_CHANGE_DIR_NAME,
5241 tscp, cp, NULL, TRUE);
5243 (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE)) {
5244 /* Not an exclusive create, and someone else tried
5245 * creating it already, then we open it anyway. We
5246 * don't bother retrying after this, since if this next
5247 * fails, that means that the file was deleted after we
5248 * started this call.
5250 code = cm_Lookup(tscp, cp, CM_FLAG_CASEFOLD,
5255 if (!isLast) { /* for anything other than dscp, release it unless it's the last one */
5256 cm_ReleaseSCache(tscp);
5257 tscp = scp; /* Newly created directory will be next parent */
5262 * if we get here and code == 0, then scp is the last directory created, and tscp is the
5263 * parent of scp. dscp got released if dscp != tscp. both tscp and scp are held.
5269 /* something went wrong creating or truncating the file */
5270 if (scp) cm_ReleaseSCache(scp);
5271 if (dscp) cm_ReleaseSCache(dscp);
5272 cm_ReleaseUser(userp);
5277 /* make sure we have file vs. dir right (only applies for single component case) */
5278 if (realDirFlag == 0 && scp->fileType != CM_SCACHETYPE_FILE) {
5279 /* now watch for a symlink */
5281 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
5282 cm_scache_t * targetScp = 0;
5283 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
5285 /* we have a more accurate file to use (the
5286 * target of the symbolic link). Otherwise,
5287 * we'll just use the symlink anyway.
5289 osi_Log2(smb_logp, "symlink vp %x to vp %x",
5291 cm_ReleaseSCache(scp);
5296 if (scp->fileType != CM_SCACHETYPE_FILE) {
5297 cm_ReleaseSCache(scp);
5298 cm_ReleaseUser(userp);
5300 return CM_ERROR_ISDIR;
5304 /* (only applies to single component case) */
5305 if (realDirFlag == 1 && scp->fileType == CM_SCACHETYPE_FILE) {
5306 cm_ReleaseSCache(scp);
5307 if (dscp) cm_ReleaseSCache(dscp);
5308 cm_ReleaseUser(userp);
5310 return CM_ERROR_NOTDIR;
5313 /* open the file itself */
5314 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
5316 /* save a pointer to the vnode */
5319 fidp->flags = fidflags;
5321 /* save parent dir and pathname for delete or change notification */
5322 if (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE)) {
5323 fidp->flags |= SMB_FID_NTOPEN;
5324 fidp->NTopen_dscp = dscp;
5325 cm_HoldSCache(dscp);
5326 fidp->NTopen_pathp = strdup(lastNamep);
5328 fidp->NTopen_wholepathp = realPathp;
5330 /* we don't need this any longer */
5331 if (dscp) cm_ReleaseSCache(dscp);
5332 cm_Open(scp, 0, userp);
5334 /* set inp->fid so that later read calls in same msg can find fid */
5335 inp->fid = fidp->fid;
5339 lock_ObtainMutex(&scp->mx);
5340 smb_SetSMBParmByte(outp, parmSlot, 0); /* oplock */
5341 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
5342 smb_SetSMBParmLong(outp, parmSlot, openAction); parmSlot += 2;
5343 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
5344 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
5345 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
5346 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
5347 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
5348 smb_SetSMBParmLong(outp, parmSlot, smb_ExtAttributes(scp));
5350 smb_SetSMBParmDouble(outp, parmSlot, (char *)&scp->length); parmSlot += 4;
5351 smb_SetSMBParmDouble(outp, parmSlot, (char *)&scp->length); parmSlot += 4;
5352 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* filetype */
5353 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* dev state */
5354 smb_SetSMBParmByte(outp, parmSlot,
5355 scp->fileType == CM_SCACHETYPE_DIRECTORY); /* is a dir? */
5356 lock_ReleaseMutex(&scp->mx);
5357 smb_SetSMBDataLength(outp, 0);
5359 osi_Log2(smb_logp, "SMB NT CreateX opening fid %d path %s", fidp->fid,
5360 osi_LogSaveString(smb_logp, realPathp));
5362 smb_ReleaseFID(fidp);
5364 cm_ReleaseUser(userp);
5366 /* Can't free realPathp if we get here since fidp->NTopen_wholepathp is pointing there */
5368 /* leave scp held since we put it in fidp->scp */
5373 * A lot of stuff copied verbatim from NT Create&X to NT Tran Create.
5374 * Instead, ultimately, would like to use a subroutine for common code.
5376 long smb_ReceiveNTTranCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5378 char *pathp, *realPathp;
5382 cm_scache_t *dscp; /* parent dir */
5383 cm_scache_t *scp; /* file to create or open */
5384 cm_scache_t *targetScp; /* if scp is a symlink */
5387 unsigned long nameLength;
5389 unsigned int requestOpLock;
5390 unsigned int requestBatchOpLock;
5391 unsigned int mustBeDir;
5392 unsigned int extendedRespRequired;
5394 unsigned int desiredAccess;
5395 #ifdef DEBUG_VERBOSE
5396 unsigned int allocSize;
5397 unsigned int shareAccess;
5399 unsigned int extAttributes;
5400 unsigned int createDisp;
5401 #ifdef DEBUG_VERBOSE
5404 unsigned int createOptions;
5405 int initialModeBits;
5406 unsigned short baseFid;
5407 smb_fid_t *baseFidp;
5409 cm_scache_t *baseDirp;
5410 unsigned short openAction;
5416 int parmOffset, dataOffset;
5427 parmOffset = smb_GetSMBOffsetParm(inp, 11, 1)
5428 | (smb_GetSMBOffsetParm(inp, 12, 1) << 16);
5429 parmp = inp->data + parmOffset;
5430 lparmp = (ULONG *) parmp;
5433 requestOpLock = flags & 0x02;
5434 requestBatchOpLock = flags & 0x04;
5435 mustBeDir = flags & 0x08;
5436 extendedRespRequired = flags & 0x10;
5439 * Why all of a sudden 32-bit FID?
5440 * We will reject all bits higher than 16.
5442 if (lparmp[1] & 0xFFFF0000)
5443 return CM_ERROR_INVAL;
5444 baseFid = (unsigned short)lparmp[1];
5445 desiredAccess = lparmp[2];
5446 #ifdef DEBUG_VERBOSE
5447 allocSize = lparmp[3];
5448 #endif /* DEBUG_VERSOSE */
5449 extAttributes = lparmp[5];
5451 shareAccess = lparmp[6];
5453 createDisp = lparmp[7];
5454 createOptions = lparmp[8];
5455 #ifdef DEBUG_VERBOSE
5458 nameLength = lparmp[11];
5460 #ifdef DEBUG_VERBOSE
5461 osi_Log4(smb_logp,"NTTranCreate with da[%x],ea[%x],sa[%x],cd[%x]",desiredAccess,extAttributes,shareAccess,createDisp);
5462 osi_Log3(smb_logp,"... co[%x],sdl[%x],as[%x]",createOptions,sdLen,allocSize);
5463 osi_Log1(smb_logp,"... flags[%x]",flags);
5466 /* mustBeDir is never set; createOptions directory bit seems to be
5469 if (createOptions & 1)
5471 else if (createOptions & 0x40)
5477 * compute initial mode bits based on read-only flag in
5478 * extended attributes
5480 initialModeBits = 0666;
5481 if (extAttributes & 1)
5482 initialModeBits &= ~0222;
5484 pathp = parmp + (13 * sizeof(ULONG)) + sizeof(UCHAR);
5485 /* Sometimes path is not null-terminated, so we make a copy. */
5486 realPathp = malloc(nameLength+1);
5487 memcpy(realPathp, pathp, nameLength);
5488 realPathp[nameLength] = 0;
5489 if (smb_StoreAnsiFilenames)
5490 OemToChar(realPathp,realPathp);
5492 spacep = cm_GetSpace();
5493 smb_StripLastComponent(spacep->data, &lastNamep, realPathp);
5496 * Nothing here to handle SMB_IOCTL_FILENAME.
5497 * Will add it if necessary.
5500 #ifdef DEBUG_VERBOSE
5502 char *hexp, *asciip;
5503 asciip = (lastNamep? lastNamep : realPathp);
5504 hexp = osi_HexifyString( asciip );
5505 DEBUG_EVENT2("AFS", "NTTranCreate H[%s] A[%s]", hexp, asciip);
5510 userp = smb_GetUser(vcp, inp);
5512 osi_Log1(smb_logp, "NTTranCreate invalid user [%d]", ((smb_t *) inp)->uid);
5514 return CM_ERROR_INVAL;
5518 baseDirp = cm_rootSCachep;
5519 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5520 if(code == CM_ERROR_TIDIPC) {
5521 /* Attempt to use TID allocated for IPC. The client is
5522 * probably trying to locate DCE RPC endpoints, which we
5524 osi_Log0(smb_logp, "NTTranCreate received IPC TID");
5526 cm_ReleaseUser(userp);
5527 return CM_ERROR_NOSUCHPATH;
5531 baseFidp = smb_FindFID(vcp, baseFid, 0);
5533 osi_Log1(smb_logp, "NTTranCreate Invalid fid [%d]", baseFid);
5535 cm_ReleaseUser(userp);
5536 return CM_ERROR_INVAL;
5538 baseDirp = baseFidp->scp;
5542 /* compute open mode */
5544 if (desiredAccess & DELETE)
5545 fidflags |= SMB_FID_OPENDELETE;
5546 if (desiredAccess & AFS_ACCESS_READ)
5547 fidflags |= SMB_FID_OPENREAD;
5548 if (desiredAccess & AFS_ACCESS_WRITE)
5549 fidflags |= SMB_FID_OPENWRITE;
5553 if ( createDisp == FILE_OPEN ||
5554 createDisp == FILE_OVERWRITE ||
5555 createDisp == FILE_OVERWRITE_IF) {
5556 code = cm_NameI(baseDirp, spacep->data, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
5557 userp, tidPathp, &req, &dscp);
5559 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp, CM_FLAG_FOLLOW,
5561 if (code == CM_ERROR_NOSUCHFILE) {
5562 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp,
5563 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, &req, &scp);
5564 if (code == 0 && realDirFlag == 1) {
5565 cm_ReleaseSCache(scp);
5566 cm_ReleaseSCache(dscp);
5567 cm_ReleaseUser(userp);
5569 return CM_ERROR_EXISTS;
5575 code = cm_NameI(baseDirp, realPathp, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
5576 userp, tidPathp, &req, &scp);
5582 || (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE))) {
5583 /* look up parent directory */
5585 code = cm_NameI(baseDirp, spacep->data,
5586 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
5587 userp, tidPathp, &req, &dscp);
5591 cm_FreeSpace(spacep);
5594 smb_ReleaseFID(baseFidp);
5599 cm_ReleaseUser(userp);
5604 if (!lastNamep) lastNamep = realPathp;
5607 if (!smb_IsLegalFilename(lastNamep))
5608 return CM_ERROR_BADNTFILENAME;
5611 if (createDisp == FILE_CREATE || createDisp == FILE_OVERWRITE_IF) {
5612 code = cm_Lookup(dscp, lastNamep,
5613 CM_FLAG_FOLLOW, userp, &req, &scp);
5615 code = cm_Lookup(dscp, lastNamep,
5616 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
5619 if (code && code != CM_ERROR_NOSUCHFILE) {
5620 cm_ReleaseSCache(dscp);
5621 cm_ReleaseUser(userp);
5629 smb_ReleaseFID(baseFidp);
5632 cm_FreeSpace(spacep);
5635 /* if we get here, if code is 0, the file exists and is represented by
5636 * scp. Otherwise, we have to create it. The dir may be represented
5637 * by dscp, or we may have found the file directly. If code is non-zero,
5641 code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp,
5644 if (dscp) cm_ReleaseSCache(dscp);
5645 cm_ReleaseSCache(scp);
5646 cm_ReleaseUser(userp);
5651 if (createDisp == FILE_CREATE) {
5652 /* oops, file shouldn't be there */
5653 if (dscp) cm_ReleaseSCache(dscp);
5654 cm_ReleaseSCache(scp);
5655 cm_ReleaseUser(userp);
5657 return CM_ERROR_EXISTS;
5660 if (createDisp == FILE_OVERWRITE ||
5661 createDisp == FILE_OVERWRITE_IF) {
5662 setAttr.mask = CM_ATTRMASK_LENGTH;
5663 setAttr.length.LowPart = 0;
5664 setAttr.length.HighPart = 0;
5666 /* now watch for a symlink */
5668 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
5670 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
5672 /* we have a more accurate file to use (the
5673 * target of the symbolic link). Otherwise,
5674 * we'll just use the symlink anyway.
5676 osi_Log2(smb_logp, "symlink vp %x to vp %x",
5678 cm_ReleaseSCache(scp);
5682 code = cm_SetAttr(scp, &setAttr, userp, &req);
5683 openAction = 3; /* truncated existing file */
5685 else openAction = 1; /* found existing file */
5687 else if (createDisp == FILE_OPEN || createDisp == FILE_OVERWRITE) {
5688 /* don't create if not found */
5689 if (dscp) cm_ReleaseSCache(dscp);
5690 cm_ReleaseUser(userp);
5692 return CM_ERROR_NOSUCHFILE;
5694 else if (realDirFlag == 0 || realDirFlag == -1) {
5695 osi_assert(dscp != NULL);
5696 osi_Log1(smb_logp, "smb_ReceiveNTTranCreate creating file %s",
5697 osi_LogSaveString(smb_logp, lastNamep));
5698 openAction = 2; /* created file */
5699 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
5700 setAttr.clientModTime = time(NULL);
5701 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
5703 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
5704 smb_NotifyChange(FILE_ACTION_ADDED,
5705 FILE_NOTIFY_CHANGE_FILE_NAME,
5706 dscp, lastNamep, NULL, TRUE);
5707 if (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE) {
5708 /* Not an exclusive create, and someone else tried
5709 * creating it already, then we open it anyway. We
5710 * don't bother retrying after this, since if this next
5711 * fails, that means that the file was deleted after we
5712 * started this call.
5714 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
5717 if (createDisp == FILE_OVERWRITE_IF) {
5718 setAttr.mask = CM_ATTRMASK_LENGTH;
5719 setAttr.length.LowPart = 0;
5720 setAttr.length.HighPart = 0;
5722 /* now watch for a symlink */
5724 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
5726 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
5728 /* we have a more accurate file to use (the
5729 * target of the symbolic link). Otherwise,
5730 * we'll just use the symlink anyway.
5732 osi_Log2(smb_logp, "symlink vp %x to vp %x",
5734 cm_ReleaseSCache(scp);
5738 code = cm_SetAttr(scp, &setAttr, userp, &req);
5740 } /* lookup succeeded */
5744 /* create directory */
5745 osi_assert(dscp != NULL);
5747 "smb_ReceiveNTTranCreate creating directory %s",
5748 osi_LogSaveString(smb_logp, lastNamep));
5749 openAction = 2; /* created directory */
5750 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
5751 setAttr.clientModTime = time(NULL);
5752 code = cm_MakeDir(dscp, lastNamep, 0, &setAttr, userp, &req);
5753 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
5754 smb_NotifyChange(FILE_ACTION_ADDED,
5755 FILE_NOTIFY_CHANGE_DIR_NAME,
5756 dscp, lastNamep, NULL, TRUE);
5758 (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE)) {
5759 /* Not an exclusive create, and someone else tried
5760 * creating it already, then we open it anyway. We
5761 * don't bother retrying after this, since if this next
5762 * fails, that means that the file was deleted after we
5763 * started this call.
5765 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
5771 /* something went wrong creating or truncating the file */
5772 if (scp) cm_ReleaseSCache(scp);
5773 cm_ReleaseUser(userp);
5778 /* make sure we have file vs. dir right */
5779 if (realDirFlag == 0 && scp->fileType != CM_SCACHETYPE_FILE) {
5780 /* now watch for a symlink */
5782 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
5784 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
5786 /* we have a more accurate file to use (the
5787 * target of the symbolic link). Otherwise,
5788 * we'll just use the symlink anyway.
5790 osi_Log2(smb_logp, "symlink vp %x to vp %x",
5792 cm_ReleaseSCache(scp);
5797 if (scp->fileType != CM_SCACHETYPE_FILE) {
5798 cm_ReleaseSCache(scp);
5799 cm_ReleaseUser(userp);
5801 return CM_ERROR_ISDIR;
5805 if (realDirFlag == 1 && scp->fileType == CM_SCACHETYPE_FILE) {
5806 cm_ReleaseSCache(scp);
5807 cm_ReleaseUser(userp);
5809 return CM_ERROR_NOTDIR;
5812 /* open the file itself */
5813 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
5816 /* save a pointer to the vnode */
5819 fidp->flags = fidflags;
5821 /* save parent dir and pathname for deletion or change notification */
5822 if (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE)) {
5823 fidp->flags |= SMB_FID_NTOPEN;
5824 fidp->NTopen_dscp = dscp;
5825 cm_HoldSCache(dscp);
5826 fidp->NTopen_pathp = strdup(lastNamep);
5828 fidp->NTopen_wholepathp = realPathp;
5830 /* we don't need this any longer */
5831 if (dscp) cm_ReleaseSCache(dscp);
5833 cm_Open(scp, 0, userp);
5835 /* set inp->fid so that later read calls in same msg can find fid */
5836 inp->fid = fidp->fid;
5838 /* check whether we are required to send an extended response */
5839 if (!extendedRespRequired) {
5841 parmOffset = 8*4 + 39;
5842 parmOffset += 1; /* pad to 4 */
5843 dataOffset = parmOffset + 70;
5847 /* Total Parameter Count */
5848 smb_SetSMBParmLong(outp, parmSlot, 70); parmSlot += 2;
5849 /* Total Data Count */
5850 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
5851 /* Parameter Count */
5852 smb_SetSMBParmLong(outp, parmSlot, 70); parmSlot += 2;
5853 /* Parameter Offset */
5854 smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
5855 /* Parameter Displacement */
5856 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
5858 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
5860 smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
5861 /* Data Displacement */
5862 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
5863 smb_SetSMBParmByte(outp, parmSlot, 0); /* Setup Count */
5864 smb_SetSMBDataLength(outp, 70);
5866 lock_ObtainMutex(&scp->mx);
5867 outData = smb_GetSMBData(outp, NULL);
5868 outData++; /* round to get to parmOffset */
5869 *outData = 0; outData++; /* oplock */
5870 *outData = 0; outData++; /* reserved */
5871 *((USHORT *)outData) = fidp->fid; outData += 2; /* fid */
5872 *((ULONG *)outData) = openAction; outData += 4;
5873 *((ULONG *)outData) = 0; outData += 4; /* EA error offset */
5874 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
5875 *((FILETIME *)outData) = ft; outData += 8; /* creation time */
5876 *((FILETIME *)outData) = ft; outData += 8; /* last access time */
5877 *((FILETIME *)outData) = ft; outData += 8; /* last write time */
5878 *((FILETIME *)outData) = ft; outData += 8; /* change time */
5879 *((ULONG *)outData) = smb_ExtAttributes(scp); outData += 4;
5880 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* alloc sz */
5881 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* EOF */
5882 *((USHORT *)outData) = 0; outData += 2; /* filetype */
5883 *((USHORT *)outData) = 0; outData += 2; /* dev state */
5884 *((USHORT *)outData) = (scp->fileType == CM_SCACHETYPE_DIRECTORY);
5885 outData += 2; /* is a dir? */
5886 lock_ReleaseMutex(&scp->mx);
5889 parmOffset = 8*4 + 39;
5890 parmOffset += 1; /* pad to 4 */
5891 dataOffset = parmOffset + 104;
5895 /* Total Parameter Count */
5896 smb_SetSMBParmLong(outp, parmSlot, 101); parmSlot += 2;
5897 /* Total Data Count */
5898 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
5899 /* Parameter Count */
5900 smb_SetSMBParmLong(outp, parmSlot, 101); parmSlot += 2;
5901 /* Parameter Offset */
5902 smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
5903 /* Parameter Displacement */
5904 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
5906 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
5908 smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
5909 /* Data Displacement */
5910 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
5911 smb_SetSMBParmByte(outp, parmSlot, 0); /* Setup Count */
5912 smb_SetSMBDataLength(outp, 105);
5914 lock_ObtainMutex(&scp->mx);
5915 outData = smb_GetSMBData(outp, NULL);
5916 outData++; /* round to get to parmOffset */
5917 *outData = 0; outData++; /* oplock */
5918 *outData = 1; outData++; /* response type */
5919 *((USHORT *)outData) = fidp->fid; outData += 2; /* fid */
5920 *((ULONG *)outData) = openAction; outData += 4;
5921 *((ULONG *)outData) = 0; outData += 4; /* EA error offset */
5922 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
5923 *((FILETIME *)outData) = ft; outData += 8; /* creation time */
5924 *((FILETIME *)outData) = ft; outData += 8; /* last access time */
5925 *((FILETIME *)outData) = ft; outData += 8; /* last write time */
5926 *((FILETIME *)outData) = ft; outData += 8; /* change time */
5927 *((ULONG *)outData) = smb_ExtAttributes(scp); outData += 4;
5928 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* alloc sz */
5929 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* EOF */
5930 *((USHORT *)outData) = 0; outData += 2; /* filetype */
5931 *((USHORT *)outData) = 0; outData += 2; /* dev state */
5932 *((USHORT *)outData) = (scp->fileType == CM_SCACHETYPE_DIRECTORY);
5933 outData += 1; /* is a dir? */
5934 memset(outData,0,24); outData += 24; /* Volume ID and file ID */
5935 *((ULONG *)outData) = 0x001f01ffL; outData += 4; /* Maxmimal access rights */
5936 *((ULONG *)outData) = 0; outData += 4; /* Guest Access rights */
5937 lock_ReleaseMutex(&scp->mx);
5940 osi_Log1(smb_logp, "SMB NTTranCreate opening fid %d", fidp->fid);
5942 smb_ReleaseFID(fidp);
5944 cm_ReleaseUser(userp);
5946 /* free(realPathp); Can't free realPathp here because fidp->NTopen_wholepathp points there */
5947 /* leave scp held since we put it in fidp->scp */
5951 long smb_ReceiveNTTranNotifyChange(smb_vc_t *vcp, smb_packet_t *inp,
5954 smb_packet_t *savedPacketp;
5955 ULONG filter; USHORT fid, watchtree;
5959 filter = smb_GetSMBParm(inp, 19) |
5960 (smb_GetSMBParm(inp, 20) << 16);
5961 fid = smb_GetSMBParm(inp, 21);
5962 watchtree = smb_GetSMBParm(inp, 22) && 0xffff; /* TODO: should this be 0xff ? */
5964 fidp = smb_FindFID(vcp, fid, 0);
5966 osi_Log1(smb_logp, "ERROR: NotifyChange given invalid fid [%d]", fid);
5967 return CM_ERROR_BADFD;
5970 savedPacketp = smb_CopyPacket(inp);
5972 savedPacketp->vcp = vcp;
5973 lock_ObtainMutex(&smb_Dir_Watch_Lock);
5974 savedPacketp->nextp = smb_Directory_Watches;
5975 smb_Directory_Watches = savedPacketp;
5976 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
5978 osi_Log4(smb_logp, "Request for NotifyChange filter 0x%x fid %d wtree %d file %s",
5979 filter, fid, watchtree, osi_LogSaveString(smb_logp, fidp->NTopen_wholepathp));
5982 lock_ObtainMutex(&scp->mx);
5984 scp->flags |= CM_SCACHEFLAG_WATCHEDSUBTREE;
5986 scp->flags |= CM_SCACHEFLAG_WATCHED;
5987 lock_ReleaseMutex(&scp->mx);
5988 smb_ReleaseFID(fidp);
5990 outp->flags |= SMB_PACKETFLAG_NOSEND;
5994 unsigned char nullSecurityDesc[36] = {
5995 0x01, /* security descriptor revision */
5996 0x00, /* reserved, should be zero */
5997 0x00, 0x80, /* security descriptor control;
5998 * 0x8000 : self-relative format */
5999 0x14, 0x00, 0x00, 0x00, /* offset of owner SID */
6000 0x1c, 0x00, 0x00, 0x00, /* offset of group SID */
6001 0x00, 0x00, 0x00, 0x00, /* offset of DACL would go here */
6002 0x00, 0x00, 0x00, 0x00, /* offset of SACL would go here */
6003 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
6004 /* "null SID" owner SID */
6005 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
6006 /* "null SID" group SID */
6009 long smb_ReceiveNTTranQuerySecurityDesc(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6011 int parmOffset, parmCount, dataOffset, dataCount;
6019 ULONG securityInformation;
6021 parmOffset = smb_GetSMBOffsetParm(inp, 11, 1)
6022 | (smb_GetSMBOffsetParm(inp, 12, 1) << 16);
6023 parmp = inp->data + parmOffset;
6024 sparmp = (USHORT *) parmp;
6025 lparmp = (ULONG *) parmp;
6028 securityInformation = lparmp[1];
6030 maxData = smb_GetSMBOffsetParm(inp, 7, 1)
6031 | (smb_GetSMBOffsetParm(inp, 8, 1) << 16);
6039 parmOffset = 8*4 + 39;
6040 parmOffset += 1; /* pad to 4 */
6042 dataOffset = parmOffset + parmCount;
6046 /* Total Parameter Count */
6047 smb_SetSMBParmLong(outp, parmSlot, parmCount); parmSlot += 2;
6048 /* Total Data Count */
6049 smb_SetSMBParmLong(outp, parmSlot, dataCount); parmSlot += 2;
6050 /* Parameter Count */
6051 smb_SetSMBParmLong(outp, parmSlot, parmCount); parmSlot += 2;
6052 /* Parameter Offset */
6053 smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
6054 /* Parameter Displacement */
6055 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
6057 smb_SetSMBParmLong(outp, parmSlot, dataCount); parmSlot += 2;
6059 smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
6060 /* Data Displacement */
6061 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
6062 smb_SetSMBParmByte(outp, parmSlot, 0); /* Setup Count */
6063 smb_SetSMBDataLength(outp, 1 + parmCount + dataCount);
6065 outData = smb_GetSMBData(outp, NULL);
6066 outData++; /* round to get to parmOffset */
6067 *((ULONG *)outData) = 36; outData += 4; /* length */
6069 if (maxData >= 36) {
6070 memcpy(outData, nullSecurityDesc, 36);
6074 return CM_ERROR_BUFFERTOOSMALL;
6077 long smb_ReceiveNTTransact(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6079 unsigned short function;
6081 function = smb_GetSMBParm(inp, 18);
6083 osi_Log1(smb_logp, "SMB NT Transact function %d", function);
6085 /* We can handle long names */
6086 if (vcp->flags & SMB_VCFLAG_USENT)
6087 ((smb_t *)outp)->flg2 |= 0x40; /* IS_LONG_NAME */
6091 return smb_ReceiveNTTranQuerySecurityDesc(vcp, inp, outp);
6093 return smb_ReceiveNTTranNotifyChange(vcp, inp, outp);
6095 return smb_ReceiveNTTranCreate(vcp, inp, outp);
6097 return CM_ERROR_INVAL;
6102 * smb_NotifyChange -- find relevant change notification messages and
6105 * If we don't know the file name (i.e. a callback break), filename is
6106 * NULL, and we return a zero-length list.
6108 void smb_NotifyChange(DWORD action, DWORD notifyFilter,
6109 cm_scache_t *dscp, char *filename, char *otherFilename,
6110 BOOL isDirectParent)
6112 smb_packet_t *watch, *lastWatch, *nextWatch;
6113 ULONG parmSlot, parmCount, parmOffset, dataOffset, nameLen;
6114 char *outData, *oldOutData;
6118 BOOL twoEntries = FALSE;
6119 ULONG otherNameLen, oldParmCount = 0;
6124 /* Get ready for rename within directory */
6125 if (action == FILE_ACTION_RENAMED_OLD_NAME && otherFilename != NULL) {
6127 otherAction = FILE_ACTION_RENAMED_NEW_NAME;
6130 osi_Log2(smb_logp,"in smb_NotifyChange for file [%s] dscp [%x]",
6131 osi_LogSaveString(smb_logp,filename),dscp);
6133 lock_ObtainMutex(&smb_Dir_Watch_Lock);
6134 watch = smb_Directory_Watches;
6136 filter = smb_GetSMBParm(watch, 19)
6137 | (smb_GetSMBParm(watch, 20) << 16);
6138 fid = smb_GetSMBParm(watch, 21);
6139 wtree = smb_GetSMBParm(watch, 22) & 0xffff; /* TODO: should this be 0xff ? */
6140 maxLen = smb_GetSMBOffsetParm(watch, 5, 1)
6141 | (smb_GetSMBOffsetParm(watch, 6, 1) << 16);
6145 * Strange hack - bug in NT Client and NT Server that we
6148 if (filter == 3 && wtree)
6151 fidp = smb_FindFID(vcp, fid, 0);
6153 osi_Log1(smb_logp," no fidp for fid[%d]",fid);
6155 watch = watch->nextp;
6158 if (fidp->scp != dscp
6159 || (filter & notifyFilter) == 0
6160 || (!isDirectParent && !wtree)) {
6161 osi_Log1(smb_logp," passing fidp->scp[%x]", fidp->scp);
6162 smb_ReleaseFID(fidp);
6164 watch = watch->nextp;
6167 smb_ReleaseFID(fidp);
6170 "Sending Change Notification for fid %d filter 0x%x wtree %d file %s",
6171 fid, filter, wtree, osi_LogSaveString(smb_logp, filename));
6173 nextWatch = watch->nextp;
6174 if (watch == smb_Directory_Watches)
6175 smb_Directory_Watches = nextWatch;
6177 lastWatch->nextp = nextWatch;
6179 /* Turn off WATCHED flag in dscp */
6180 lock_ObtainMutex(&dscp->mx);
6182 dscp->flags &= ~CM_SCACHEFLAG_WATCHEDSUBTREE;
6184 dscp->flags &= ~CM_SCACHEFLAG_WATCHED;
6185 lock_ReleaseMutex(&dscp->mx);
6187 /* Convert to response packet */
6188 ((smb_t *) watch)->reb = 0x80;
6189 ((smb_t *) watch)->wct = 0;
6192 if (filename == NULL)
6195 nameLen = strlen(filename);
6196 parmCount = 3*4 + nameLen*2;
6197 parmCount = (parmCount + 3) & ~3; /* pad to 4 */
6199 otherNameLen = strlen(otherFilename);
6200 oldParmCount = parmCount;
6201 parmCount += 3*4 + otherNameLen*2;
6202 parmCount = (parmCount + 3) & ~3; /* pad to 4 */
6204 if (maxLen < parmCount)
6205 parmCount = 0; /* not enough room */
6207 parmOffset = 8*4 + 39;
6208 parmOffset += 1; /* pad to 4 */
6209 dataOffset = parmOffset + parmCount;
6213 /* Total Parameter Count */
6214 smb_SetSMBParmLong(watch, parmSlot, parmCount); parmSlot += 2;
6215 /* Total Data Count */
6216 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
6217 /* Parameter Count */
6218 smb_SetSMBParmLong(watch, parmSlot, parmCount); parmSlot += 2;
6219 /* Parameter Offset */
6220 smb_SetSMBParmLong(watch, parmSlot, parmOffset); parmSlot += 2;
6221 /* Parameter Displacement */
6222 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
6224 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
6226 smb_SetSMBParmLong(watch, parmSlot, dataOffset); parmSlot += 2;
6227 /* Data Displacement */
6228 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
6229 smb_SetSMBParmByte(watch, parmSlot, 0); /* Setup Count */
6230 smb_SetSMBDataLength(watch, parmCount + 1);
6232 if (parmCount != 0) {
6234 outData = smb_GetSMBData(watch, NULL);
6235 outData++; /* round to get to parmOffset */
6236 oldOutData = outData;
6237 *((DWORD *)outData) = oldParmCount; outData += 4;
6238 /* Next Entry Offset */
6239 *((DWORD *)outData) = action; outData += 4;
6241 *((DWORD *)outData) = nameLen*2; outData += 4;
6242 /* File Name Length */
6243 p = strdup(filename);
6244 if (smb_StoreAnsiFilenames)
6246 mbstowcs((WCHAR *)outData, p, nameLen);
6250 outData = oldOutData + oldParmCount;
6251 *((DWORD *)outData) = 0; outData += 4;
6252 /* Next Entry Offset */
6253 *((DWORD *)outData) = otherAction; outData += 4;
6255 *((DWORD *)outData) = otherNameLen*2;
6256 outData += 4; /* File Name Length */
6257 p = strdup(otherFilename);
6258 if (smb_StoreAnsiFilenames)
6260 mbstowcs((WCHAR *)outData, p, otherNameLen); /* File Name */
6266 * If filename is null, we don't know the cause of the
6267 * change notification. We return zero data (see above),
6268 * and set error code to NT_STATUS_NOTIFY_ENUM_DIR
6269 * (= 0x010C). We set the error code here by hand, without
6270 * modifying wct and bcc.
6272 if (filename == NULL) {
6273 ((smb_t *) watch)->rcls = 0x0C;
6274 ((smb_t *) watch)->reh = 0x01;
6275 ((smb_t *) watch)->errLow = 0;
6276 ((smb_t *) watch)->errHigh = 0;
6277 /* Set NT Status codes flag */
6278 ((smb_t *) watch)->flg2 |= 0x4000;
6281 smb_SendPacket(vcp, watch);
6283 smb_FreePacket(watch);
6286 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
6289 long smb_ReceiveNTCancel(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6291 unsigned char *replyWctp;
6292 smb_packet_t *watch, *lastWatch;
6293 USHORT fid, watchtree;
6297 osi_Log0(smb_logp, "SMB3 receive NT cancel");
6299 lock_ObtainMutex(&smb_Dir_Watch_Lock);
6300 watch = smb_Directory_Watches;
6302 if (((smb_t *)watch)->uid == ((smb_t *)inp)->uid
6303 && ((smb_t *)watch)->pid == ((smb_t *)inp)->pid
6304 && ((smb_t *)watch)->mid == ((smb_t *)inp)->mid
6305 && ((smb_t *)watch)->tid == ((smb_t *)inp)->tid) {
6306 if (watch == smb_Directory_Watches)
6307 smb_Directory_Watches = watch->nextp;
6309 lastWatch->nextp = watch->nextp;
6310 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
6312 /* Turn off WATCHED flag in scp */
6313 fid = smb_GetSMBParm(watch, 21);
6314 watchtree = smb_GetSMBParm(watch, 22) & 0xffff;
6316 if (vcp != watch->vcp)
6317 osi_Log2(smb_logp, "smb_ReceiveNTCancel: vcp %x not equal to watch vcp %x",
6320 fidp = smb_FindFID(vcp, fid, 0);
6322 osi_Log3(smb_logp, "Cancelling change notification for fid %d wtree %d file %s",
6324 osi_LogSaveString(smb_logp, (fidp)?fidp->NTopen_wholepathp:""));
6327 lock_ObtainMutex(&scp->mx);
6329 scp->flags &= ~CM_SCACHEFLAG_WATCHEDSUBTREE;
6331 scp->flags &= ~CM_SCACHEFLAG_WATCHED;
6332 lock_ReleaseMutex(&scp->mx);
6333 smb_ReleaseFID(fidp);
6335 osi_Log2(smb_logp,"NTCancel unable to resolve fid [%d] in vcp[%x]", fid,vcp);
6338 /* assume STATUS32; return 0xC0000120 (CANCELED) */
6339 replyWctp = watch->wctp;
6343 ((smb_t *)watch)->rcls = 0x20;
6344 ((smb_t *)watch)->reh = 0x1;
6345 ((smb_t *)watch)->errLow = 0;
6346 ((smb_t *)watch)->errHigh = 0xC0;
6347 ((smb_t *)watch)->flg2 |= 0x4000;
6348 smb_SendPacket(vcp, watch);
6350 smb_ReleaseVC(watch->vcp);
6351 smb_FreePacket(watch);
6355 watch = watch->nextp;
6357 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
6363 * NT rename also does hard links.
6366 #define RENAME_FLAG_MOVE_CLUSTER_INFORMATION 0x102
6367 #define RENAME_FLAG_HARD_LINK 0x103
6368 #define RENAME_FLAG_RENAME 0x104
6369 #define RENAME_FLAG_COPY 0x105
6371 long smb_ReceiveNTRename(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6373 char *oldPathp, *newPathp;
6380 attrs = smb_GetSMBParm(inp, 0);
6381 rename_type = smb_GetSMBParm(inp, 1);
6383 if (rename_type != RENAME_FLAG_RENAME && rename_type != RENAME_FLAG_HARD_LINK) {
6384 osi_Log1(smb_logp, "NTRename invalid infolevel [%x]", rename_type);
6385 return CM_ERROR_NOACCESS;
6388 tp = smb_GetSMBData(inp, NULL);
6389 oldPathp = smb_ParseASCIIBlock(tp, &tp);
6390 if (smb_StoreAnsiFilenames)
6391 OemToChar(oldPathp,oldPathp);
6392 newPathp = smb_ParseASCIIBlock(tp, &tp);
6393 if (smb_StoreAnsiFilenames)
6394 OemToChar(newPathp,newPathp);
6396 osi_Log3(smb_logp, "NTRename for [%s]->[%s] type [%s]",
6397 osi_LogSaveString(smb_logp, oldPathp),
6398 osi_LogSaveString(smb_logp, newPathp),
6399 ((rename_type==RENAME_FLAG_RENAME)?"rename":"hardlink"));
6401 if (rename_type == RENAME_FLAG_RENAME) {
6402 code = smb_Rename(vcp,inp,oldPathp,newPathp,attrs);
6403 } else { /* RENAME_FLAG_HARD_LINK */
6404 code = smb_Link(vcp,inp,oldPathp,newPathp);
6411 lock_InitializeMutex(&smb_Dir_Watch_Lock, "Directory Watch List Lock");
6414 cm_user_t *smb_FindCMUserByName(/*smb_vc_t *vcp,*/ char *usern, char *machine)
6417 smb_username_t *unp;
6419 unp = smb_FindUserByName(usern, machine, SMB_FLAG_CREATE);
6421 lock_ObtainMutex(&unp->mx);
6422 unp->userp = cm_NewUser();
6423 lock_ReleaseMutex(&unp->mx);
6424 osi_Log2(smb_logp,"smb_FindCMUserByName New user name[%s] machine[%s]",osi_LogSaveString(smb_logp,usern),osi_LogSaveString(smb_logp,machine));
6425 osi_LogEvent("AFS smb_FindCMUserByName : New User",NULL,"name[%s] machine[%s]",usern,machine);
6427 osi_Log2(smb_logp,"smb_FindCMUserByName Not found name[%s] machine[%s]",osi_LogSaveString(smb_logp,usern),osi_LogSaveString(smb_logp,machine));
6428 osi_LogEvent("AFS smb_FindCMUserByName : Found",NULL,"name[%s] machine[%s]",usern,machine);