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
917 #define SMB_SHARE_IS_IN_DFS 0x0002
919 long smb_ReceiveV3TreeConnectX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
923 unsigned short newTid;
934 osi_Log0(smb_logp, "SMB3 receive tree connect");
936 /* parse input parameters */
937 tp = smb_GetSMBData(inp, NULL);
938 passwordp = smb_ParseString(tp, &tp);
939 pathp = smb_ParseString(tp, &tp);
940 if (smb_StoreAnsiFilenames)
941 OemToChar(pathp,pathp);
942 servicep = smb_ParseString(tp, &tp);
944 tp = strrchr(pathp, '\\');
946 return CM_ERROR_BADSMB;
948 strcpy(shareName, tp+1);
950 osi_Log2(smb_logp, "Tree connect pathp[%s] shareName[%s]",
951 osi_LogSaveString(smb_logp, pathp),
952 osi_LogSaveString(smb_logp, shareName));
954 if (strcmp(servicep, "IPC") == 0 || strcmp(shareName, "IPC$") == 0) {
956 osi_Log0(smb_logp, "TreeConnectX connecting to IPC$");
959 return CM_ERROR_NOIPC;
963 userp = smb_GetUser(vcp, inp);
965 lock_ObtainMutex(&vcp->mx);
966 newTid = vcp->tidCounter++;
967 lock_ReleaseMutex(&vcp->mx);
969 tidp = smb_FindTID(vcp, newTid, SMB_FLAG_CREATE);
972 uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
973 shareFound = smb_FindShare(vcp, uidp, shareName, &sharePath);
975 smb_ReleaseUID(uidp);
977 smb_ReleaseTID(tidp);
978 return CM_ERROR_BADSHARENAME;
981 if (vcp->flags & SMB_VCFLAG_USENT)
983 int policy = smb_FindShareCSCPolicy(shareName);
984 smb_SetSMBParm(outp, 2, SMB_SUPPORT_SEARCH_BITS |
986 SMB_SHARE_IS_IN_DFS |
991 smb_SetSMBParm(outp, 2, 0);
995 lock_ObtainMutex(&tidp->mx);
997 tidp->pathname = sharePath;
999 tidp->flags |= SMB_TIDFLAG_IPC;
1000 lock_ReleaseMutex(&tidp->mx);
1001 smb_ReleaseTID(tidp);
1003 ((smb_t *)outp)->tid = newTid;
1004 ((smb_t *)inp)->tid = newTid;
1005 tp = smb_GetSMBData(outp, NULL);
1007 /* XXX - why is this a drive letter? - jaltman */
1011 smb_SetSMBDataLength(outp, 3);
1014 smb_SetSMBDataLength(outp, 4);
1017 osi_Log1(smb_logp, "SMB3 tree connect created ID %d", newTid);
1021 /* must be called with global tran lock held */
1022 smb_tran2Packet_t *smb_FindTran2Packet(smb_vc_t *vcp, smb_packet_t *inp)
1024 smb_tran2Packet_t *tp;
1027 smbp = (smb_t *) inp->data;
1028 for (tp = smb_tran2AssemblyQueuep; tp; tp = (smb_tran2Packet_t *) osi_QNext(&tp->q)) {
1029 if (tp->vcp == vcp && tp->mid == smbp->mid && tp->tid == smbp->tid)
1035 smb_tran2Packet_t *smb_NewTran2Packet(smb_vc_t *vcp, smb_packet_t *inp,
1036 int totalParms, int totalData)
1038 smb_tran2Packet_t *tp;
1041 smbp = (smb_t *) inp->data;
1042 tp = malloc(sizeof(*tp));
1043 memset(tp, 0, sizeof(*tp));
1046 tp->curData = tp->curParms = 0;
1047 tp->totalData = totalData;
1048 tp->totalParms = totalParms;
1049 tp->tid = smbp->tid;
1050 tp->mid = smbp->mid;
1051 tp->uid = smbp->uid;
1052 tp->pid = smbp->pid;
1053 tp->res[0] = smbp->res[0];
1054 osi_QAdd((osi_queue_t **)&smb_tran2AssemblyQueuep, &tp->q);
1055 if (totalParms != 0)
1056 tp->parmsp = malloc(totalParms);
1058 tp->datap = malloc(totalData);
1059 if (smbp->com == 0x25 || smbp->com == 0x26)
1062 tp->opcode = smb_GetSMBParm(inp, 14);
1065 tp->flags |= SMB_TRAN2PFLAG_ALLOC;
1069 smb_tran2Packet_t *smb_GetTran2ResponsePacket(smb_vc_t *vcp,
1070 smb_tran2Packet_t *inp, smb_packet_t *outp,
1071 int totalParms, int totalData)
1073 smb_tran2Packet_t *tp;
1074 unsigned short parmOffset;
1075 unsigned short dataOffset;
1076 unsigned short dataAlign;
1078 tp = malloc(sizeof(*tp));
1079 memset(tp, 0, sizeof(*tp));
1081 tp->curData = tp->curParms = 0;
1082 tp->totalData = totalData;
1083 tp->totalParms = totalParms;
1084 tp->oldTotalParms = totalParms;
1089 tp->res[0] = inp->res[0];
1090 tp->opcode = inp->opcode;
1094 * We calculate where the parameters and data will start.
1095 * This calculation must parallel the calculation in
1096 * smb_SendTran2Packet.
1099 parmOffset = 10*2 + 35;
1100 parmOffset++; /* round to even */
1101 tp->parmsp = (unsigned short *) (outp->data + parmOffset);
1103 dataOffset = parmOffset + totalParms;
1104 dataAlign = dataOffset & 2; /* quad-align */
1105 dataOffset += dataAlign;
1106 tp->datap = outp->data + dataOffset;
1111 /* free a tran2 packet; must be called with smb_globalLock held */
1112 void smb_FreeTran2Packet(smb_tran2Packet_t *t2p)
1114 if (t2p->vcp) smb_ReleaseVC(t2p->vcp);
1115 if (t2p->flags & SMB_TRAN2PFLAG_ALLOC) {
1124 /* called with a VC, an input packet to respond to, and an error code.
1125 * sends an error response.
1127 void smb_SendTran2Error(smb_vc_t *vcp, smb_tran2Packet_t *t2p,
1128 smb_packet_t *tp, long code)
1131 unsigned short errCode;
1132 unsigned char errClass;
1133 unsigned long NTStatus;
1135 if (vcp->flags & SMB_VCFLAG_STATUS32)
1136 smb_MapNTError(code, &NTStatus);
1138 smb_MapCoreError(code, vcp, &errCode, &errClass);
1140 smb_FormatResponsePacket(vcp, NULL, tp);
1141 smbp = (smb_t *) tp;
1143 /* We can handle long names */
1144 if (vcp->flags & SMB_VCFLAG_USENT)
1145 smbp->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
1147 /* now copy important fields from the tran 2 packet */
1148 smbp->com = t2p->com;
1149 smbp->tid = t2p->tid;
1150 smbp->mid = t2p->mid;
1151 smbp->pid = t2p->pid;
1152 smbp->uid = t2p->uid;
1153 smbp->res[0] = t2p->res[0];
1154 if (vcp->flags & SMB_VCFLAG_STATUS32) {
1155 smbp->rcls = (unsigned char) (NTStatus & 0xff);
1156 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
1157 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
1158 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
1159 smbp->flg2 |= SMB_FLAGS2_ERR_STATUS;
1162 smbp->rcls = errClass;
1163 smbp->errLow = (unsigned char) (errCode & 0xff);
1164 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
1168 smb_SendPacket(vcp, tp);
1171 void smb_SendTran2Packet(smb_vc_t *vcp, smb_tran2Packet_t *t2p, smb_packet_t *tp)
1174 unsigned short parmOffset;
1175 unsigned short dataOffset;
1176 unsigned short totalLength;
1177 unsigned short dataAlign;
1180 smb_FormatResponsePacket(vcp, NULL, tp);
1181 smbp = (smb_t *) tp;
1183 /* We can handle long names */
1184 if (vcp->flags & SMB_VCFLAG_USENT)
1185 smbp->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
1187 /* now copy important fields from the tran 2 packet */
1188 smbp->com = t2p->com;
1189 smbp->tid = t2p->tid;
1190 smbp->mid = t2p->mid;
1191 smbp->pid = t2p->pid;
1192 smbp->uid = t2p->uid;
1193 smbp->res[0] = t2p->res[0];
1195 totalLength = 1 + t2p->totalData + t2p->totalParms;
1197 /* now add the core parameters (tran2 info) to the packet */
1198 smb_SetSMBParm(tp, 0, t2p->totalParms); /* parm bytes */
1199 smb_SetSMBParm(tp, 1, t2p->totalData); /* data bytes */
1200 smb_SetSMBParm(tp, 2, 0); /* reserved */
1201 smb_SetSMBParm(tp, 3, t2p->totalParms); /* parm bytes in this packet */
1202 parmOffset = 10*2 + 35; /* parm offset in packet */
1203 parmOffset++; /* round to even */
1204 smb_SetSMBParm(tp, 4, parmOffset); /* 11 parm words plus *
1205 * hdr, bcc and wct */
1206 smb_SetSMBParm(tp, 5, 0); /* parm displacement */
1207 smb_SetSMBParm(tp, 6, t2p->totalData); /* data in this packet */
1208 dataOffset = parmOffset + t2p->oldTotalParms;
1209 dataAlign = dataOffset & 2; /* quad-align */
1210 dataOffset += dataAlign;
1211 smb_SetSMBParm(tp, 7, dataOffset); /* offset of data */
1212 smb_SetSMBParm(tp, 8, 0); /* data displacement */
1213 smb_SetSMBParm(tp, 9, 0); /* low: setup word count *
1216 datap = smb_GetSMBData(tp, NULL);
1217 *datap++ = 0; /* we rounded to even */
1219 totalLength += dataAlign;
1220 smb_SetSMBDataLength(tp, totalLength);
1222 /* next, send the datagram */
1223 smb_SendPacket(vcp, tp);
1226 long smb_ReceiveV3Trans(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
1228 smb_tran2Packet_t *asp;
1241 /* We sometimes see 0 word count. What to do? */
1242 if (*inp->wctp == 0) {
1247 osi_Log0(smb_logp, "TRANSACTION word count = 0");
1249 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
1250 ptbuf[0] = "Transaction2 word count = 0";
1251 ReportEvent(h, EVENTLOG_WARNING_TYPE, 0, 1003, NULL,
1252 1, inp->ncb_length, ptbuf, inp);
1253 DeregisterEventSource(h);
1255 osi_Log0(smb_logp, "TRANSACTION word count = 0");
1258 smb_SetSMBDataLength(outp, 0);
1259 smb_SendPacket(vcp, outp);
1263 totalParms = smb_GetSMBParm(inp, 0);
1264 totalData = smb_GetSMBParm(inp, 1);
1266 firstPacket = (inp->inCom == 0x25);
1268 /* find the packet we're reassembling */
1269 lock_ObtainWrite(&smb_globalLock);
1270 asp = smb_FindTran2Packet(vcp, inp);
1272 asp = smb_NewTran2Packet(vcp, inp, totalParms, totalData);
1274 lock_ReleaseWrite(&smb_globalLock);
1276 /* now merge in this latest packet; start by looking up offsets */
1278 parmDisp = dataDisp = 0;
1279 parmOffset = smb_GetSMBParm(inp, 10);
1280 dataOffset = smb_GetSMBParm(inp, 12);
1281 parmCount = smb_GetSMBParm(inp, 9);
1282 dataCount = smb_GetSMBParm(inp, 11);
1283 asp->maxReturnParms = smb_GetSMBParm(inp, 2);
1284 asp->maxReturnData = smb_GetSMBParm(inp, 3);
1286 osi_Log3(smb_logp, "SMB3 received Trans init packet total data %d, cur data %d, max return data %d",
1287 totalData, dataCount, asp->maxReturnData);
1290 parmDisp = smb_GetSMBParm(inp, 4);
1291 parmOffset = smb_GetSMBParm(inp, 3);
1292 dataDisp = smb_GetSMBParm(inp, 7);
1293 dataOffset = smb_GetSMBParm(inp, 6);
1294 parmCount = smb_GetSMBParm(inp, 2);
1295 dataCount = smb_GetSMBParm(inp, 5);
1297 osi_Log2(smb_logp, "SMB3 received Trans aux packet parms %d, data %d",
1298 parmCount, dataCount);
1301 /* now copy the parms and data */
1302 if ( asp->totalParms > 0 && parmCount != 0 )
1304 memcpy(((char *)asp->parmsp) + parmDisp, inp->data + parmOffset, parmCount);
1306 if ( asp->totalData > 0 && dataCount != 0 ) {
1307 memcpy(asp->datap + dataDisp, inp->data + dataOffset, dataCount);
1310 /* account for new bytes */
1311 asp->curData += dataCount;
1312 asp->curParms += parmCount;
1314 /* finally, if we're done, remove the packet from the queue and dispatch it */
1315 if (asp->totalParms > 0 &&
1316 asp->curParms > 0 &&
1317 asp->totalData <= asp->curData &&
1318 asp->totalParms <= asp->curParms) {
1319 /* we've received it all */
1320 lock_ObtainWrite(&smb_globalLock);
1321 osi_QRemove((osi_queue_t **) &smb_tran2AssemblyQueuep, &asp->q);
1322 lock_ReleaseWrite(&smb_globalLock);
1324 /* now dispatch it */
1325 rapOp = asp->parmsp[0];
1327 if ( rapOp >= 0 && rapOp < SMB_RAP_NOPCODES && smb_rapDispatchTable[rapOp].procp) {
1328 osi_LogEvent("AFS-Dispatch-RAP[%s]",myCrt_RapDispatch(rapOp),"vcp[%x] lana[%d] lsn[%d]",(int)vcp,vcp->lana,vcp->lsn);
1329 osi_Log4(smb_logp,"AFS Server - Dispatch-RAP %s vcp[%x] lana[%d] lsn[%d]",myCrt_RapDispatch(rapOp),vcp,vcp->lana,vcp->lsn);
1330 code = (*smb_rapDispatchTable[rapOp].procp)(vcp, asp, outp);
1333 osi_LogEvent("AFS-Dispatch-RAP [invalid]", NULL, "op[%x] vcp[%x] lana[%d] lsn[%d]", rapOp, vcp, vcp->lana, vcp->lsn);
1334 osi_Log4(smb_logp,"AFS Server - Dispatch-RAP [INVALID] op[%x] vcp[%x] lana[%d] lsn[%d]", rapOp, vcp, vcp->lana, vcp->lsn);
1335 code = CM_ERROR_BADOP;
1338 /* if an error is returned, we're supposed to send an error packet,
1339 * otherwise the dispatched function already did the data sending.
1340 * We give dispatched proc the responsibility since it knows how much
1341 * space to allocate.
1344 smb_SendTran2Error(vcp, asp, outp, code);
1347 /* free the input tran 2 packet */
1348 lock_ObtainWrite(&smb_globalLock);
1349 smb_FreeTran2Packet(asp);
1350 lock_ReleaseWrite(&smb_globalLock);
1352 else if (firstPacket) {
1353 /* the first packet in a multi-packet request, we need to send an
1354 * ack to get more data.
1356 smb_SetSMBDataLength(outp, 0);
1357 smb_SendPacket(vcp, outp);
1363 /* ANSI versions. The unicode versions support arbitrary length
1364 share names, but we don't support unicode yet. */
1366 typedef struct smb_rap_share_info_0 {
1367 char shi0_netname[13];
1368 } smb_rap_share_info_0_t;
1370 typedef struct smb_rap_share_info_1 {
1371 char shi1_netname[13];
1374 DWORD shi1_remark; /* char *shi1_remark; data offset */
1375 } smb_rap_share_info_1_t;
1377 typedef struct smb_rap_share_info_2 {
1378 char shi2_netname[13];
1380 unsigned short shi2_type;
1381 DWORD shi2_remark; /* char *shi2_remark; data offset */
1382 unsigned short shi2_permissions;
1383 unsigned short shi2_max_uses;
1384 unsigned short shi2_current_uses;
1385 DWORD shi2_path; /* char *shi2_path; data offset */
1386 unsigned short shi2_passwd[9];
1387 unsigned short shi2_pad2;
1388 } smb_rap_share_info_2_t;
1390 #define SMB_RAP_MAX_SHARES 512
1392 typedef struct smb_rap_share_list {
1395 smb_rap_share_info_0_t * shares;
1396 } smb_rap_share_list_t;
1398 int smb_rapCollectSharesProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp) {
1399 smb_rap_share_list_t * sp;
1404 if (name[0] == '.' && (!name[1] || (name[1] == '.' && !name[2])))
1405 return 0; /* skip over '.' and '..' */
1407 sp = (smb_rap_share_list_t *) vrockp;
1409 strncpy(sp->shares[sp->cShare].shi0_netname, name, 12);
1410 sp->shares[sp->cShare].shi0_netname[12] = 0;
1414 if (sp->cShare >= sp->maxShares)
1415 return CM_ERROR_STOPNOW;
1420 long smb_ReceiveRAPNetShareEnum(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1422 smb_tran2Packet_t *outp;
1423 unsigned short * tp;
1427 int outParmsTotal; /* total parameter bytes */
1428 int outDataTotal; /* total data bytes */
1436 HKEY hkSubmount = NULL;
1437 smb_rap_share_info_1_t * shares;
1440 char thisShare[256];
1443 smb_rap_share_list_t rootShares;
1448 tp = p->parmsp + 1; /* skip over function number (always 0) */
1449 (void) smb_ParseString((char *) tp, (char **) &tp); /* skip over parm descriptor */
1450 (void) smb_ParseString((char *) tp, (char **) &tp); /* skip over data descriptor */
1454 if (infoLevel != 1) {
1455 return CM_ERROR_INVAL;
1458 /* first figure out how many shares there are */
1459 rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSConfigKeyName, 0,
1460 KEY_QUERY_VALUE, &hkParam);
1461 if (rv == ERROR_SUCCESS) {
1462 len = sizeof(allSubmount);
1463 rv = RegQueryValueEx(hkParam, "AllSubmount", NULL, NULL,
1464 (BYTE *) &allSubmount, &len);
1465 if (rv != ERROR_SUCCESS || allSubmount != 0) {
1468 RegCloseKey (hkParam);
1471 rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SOFTWARE\\OpenAFS\\Client\\Submounts",
1472 0, KEY_QUERY_VALUE, &hkSubmount);
1473 if (rv == ERROR_SUCCESS) {
1474 rv = RegQueryInfoKey(hkSubmount, NULL, NULL, NULL, NULL,
1475 NULL, NULL, &nRegShares, NULL, NULL, NULL, NULL);
1476 if (rv != ERROR_SUCCESS)
1482 /* fetch the root shares */
1483 rootShares.maxShares = SMB_RAP_MAX_SHARES;
1484 rootShares.cShare = 0;
1485 rootShares.shares = malloc( sizeof(smb_rap_share_info_0_t) * SMB_RAP_MAX_SHARES );
1489 userp = smb_GetTran2User(vcp,p);
1491 thyper.HighPart = 0;
1494 cm_HoldSCache(cm_rootSCachep);
1495 cm_ApplyDir(cm_rootSCachep, smb_rapCollectSharesProc, &rootShares, &thyper, userp, &req, NULL);
1496 cm_ReleaseSCache(cm_rootSCachep);
1498 cm_ReleaseUser(userp);
1500 nShares = rootShares.cShare + nRegShares + allSubmount;
1502 #define REMARK_LEN 1
1503 outParmsTotal = 8; /* 4 dwords */
1504 outDataTotal = (sizeof(smb_rap_share_info_1_t) + REMARK_LEN) * nShares ;
1505 if(outDataTotal > bufsize) {
1506 nSharesRet = bufsize / (sizeof(smb_rap_share_info_1_t) + REMARK_LEN);
1507 outDataTotal = (sizeof(smb_rap_share_info_1_t) + REMARK_LEN) * nSharesRet;
1510 nSharesRet = nShares;
1513 outp = smb_GetTran2ResponsePacket(vcp, p, op, outParmsTotal, outDataTotal);
1515 /* now for the submounts */
1516 shares = (smb_rap_share_info_1_t *) outp->datap;
1517 cstrp = outp->datap + sizeof(smb_rap_share_info_1_t) * nSharesRet;
1519 memset(outp->datap, 0, (sizeof(smb_rap_share_info_1_t) + REMARK_LEN) * nSharesRet);
1522 strcpy( shares[cshare].shi1_netname, "all" );
1523 shares[cshare].shi1_remark = cstrp - outp->datap;
1524 /* type and pad are zero already */
1530 for (i=0; i < nRegShares && cshare < nSharesRet; i++) {
1531 len = sizeof(thisShare);
1532 rv = RegEnumValue(hkSubmount, i, thisShare, &len, NULL, NULL, NULL, NULL);
1533 if (rv == ERROR_SUCCESS && strlen(thisShare) && (!allSubmount || stricmp(thisShare,"all"))) {
1534 strncpy(shares[cshare].shi1_netname, thisShare, sizeof(shares->shi1_netname)-1);
1535 shares[cshare].shi1_netname[sizeof(shares->shi1_netname)-1] = 0; /* unfortunate truncation */
1536 shares[cshare].shi1_remark = cstrp - outp->datap;
1541 nShares--; /* uncount key */
1544 RegCloseKey(hkSubmount);
1547 nonrootShares = cshare;
1549 for (i=0; i < rootShares.cShare && cshare < nSharesRet; i++) {
1550 /* in case there are collisions with submounts, submounts have higher priority */
1551 for (j=0; j < nonrootShares; j++)
1552 if (!stricmp(shares[j].shi1_netname, rootShares.shares[i].shi0_netname))
1555 if (j < nonrootShares) {
1556 nShares--; /* uncount */
1560 strcpy(shares[cshare].shi1_netname, rootShares.shares[i].shi0_netname);
1561 shares[cshare].shi1_remark = cstrp - outp->datap;
1566 outp->parmsp[0] = ((cshare == nShares)? ERROR_SUCCESS : ERROR_MORE_DATA);
1567 outp->parmsp[1] = 0;
1568 outp->parmsp[2] = cshare;
1569 outp->parmsp[3] = nShares;
1571 outp->totalData = cstrp - outp->datap;
1572 outp->totalParms = outParmsTotal;
1574 smb_SendTran2Packet(vcp, outp, op);
1575 smb_FreeTran2Packet(outp);
1577 free(rootShares.shares);
1582 long smb_ReceiveRAPNetShareGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1584 smb_tran2Packet_t *outp;
1585 unsigned short * tp;
1587 BOOL shareFound = FALSE;
1588 unsigned short infoLevel;
1589 unsigned short bufsize;
1599 tp = p->parmsp + 1; /* skip over function number (always 1) */
1600 (void) smb_ParseString( (char *) tp, (char **) &tp); /* skip over param descriptor */
1601 (void) smb_ParseString( (char *) tp, (char **) &tp); /* skip over data descriptor */
1602 shareName = smb_ParseString( (char *) tp, (char **) &tp);
1609 totalData = sizeof(smb_rap_share_info_0_t);
1610 else if(infoLevel == SMB_INFO_STANDARD)
1611 totalData = sizeof(smb_rap_share_info_1_t) + 1; /* + empty string */
1612 else if(infoLevel == SMB_INFO_QUERY_EA_SIZE)
1613 totalData = sizeof(smb_rap_share_info_2_t) + 2; /* + two empty strings */
1615 return CM_ERROR_INVAL;
1617 outp = smb_GetTran2ResponsePacket(vcp, p, op, totalParam, totalData);
1619 if(!stricmp(shareName,"all")) {
1620 rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSConfigKeyName, 0,
1621 KEY_QUERY_VALUE, &hkParam);
1622 if (rv == ERROR_SUCCESS) {
1623 len = sizeof(allSubmount);
1624 rv = RegQueryValueEx(hkParam, "AllSubmount", NULL, NULL,
1625 (BYTE *) &allSubmount, &len);
1626 if (rv != ERROR_SUCCESS || allSubmount != 0) {
1629 RegCloseKey (hkParam);
1636 rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SOFTWARE\\OpenAFS\\Client\\Submounts", 0,
1637 KEY_QUERY_VALUE, &hkSubmount);
1638 if (rv == ERROR_SUCCESS) {
1639 rv = RegQueryValueEx(hkSubmount, shareName, NULL, NULL, NULL, NULL);
1640 if (rv == ERROR_SUCCESS) {
1643 RegCloseKey(hkSubmount);
1648 smb_FreeTran2Packet(outp);
1649 return CM_ERROR_BADSHARENAME;
1652 memset(outp->datap, 0, totalData);
1654 outp->parmsp[0] = 0;
1655 outp->parmsp[1] = 0;
1656 outp->parmsp[2] = totalData;
1658 if (infoLevel == 0) {
1659 smb_rap_share_info_0_t * info = (smb_rap_share_info_0_t *) outp->datap;
1660 strncpy(info->shi0_netname, shareName, sizeof(info->shi0_netname)-1);
1661 info->shi0_netname[sizeof(info->shi0_netname)-1] = 0;
1662 } else if(infoLevel == SMB_INFO_STANDARD) {
1663 smb_rap_share_info_1_t * info = (smb_rap_share_info_1_t *) outp->datap;
1664 strncpy(info->shi1_netname, shareName, sizeof(info->shi1_netname)-1);
1665 info->shi1_netname[sizeof(info->shi1_netname)-1] = 0;
1666 info->shi1_remark = ((unsigned char *) (info + 1)) - outp->datap;
1667 /* type and pad are already zero */
1668 } else { /* infoLevel==2 */
1669 smb_rap_share_info_2_t * info = (smb_rap_share_info_2_t *) outp->datap;
1670 strncpy(info->shi2_netname, shareName, sizeof(info->shi2_netname)-1);
1671 info->shi2_netname[sizeof(info->shi2_netname)-1] = 0;
1672 info->shi2_remark = ((unsigned char *) (info + 1)) - outp->datap;
1673 info->shi2_permissions = ACCESS_ALL;
1674 info->shi2_max_uses = (unsigned short) -1;
1675 info->shi2_path = 1 + (((unsigned char *) (info + 1)) - outp->datap);
1678 outp->totalData = totalData;
1679 outp->totalParms = totalParam;
1681 smb_SendTran2Packet(vcp, outp, op);
1682 smb_FreeTran2Packet(outp);
1687 typedef struct smb_rap_wksta_info_10 {
1688 DWORD wki10_computername; /*char *wki10_computername;*/
1689 DWORD wki10_username; /* char *wki10_username; */
1690 DWORD wki10_langroup; /* char *wki10_langroup;*/
1691 unsigned char wki10_ver_major;
1692 unsigned char wki10_ver_minor;
1693 DWORD wki10_logon_domain; /*char *wki10_logon_domain;*/
1694 DWORD wki10_oth_domains; /* char *wki10_oth_domains;*/
1695 } smb_rap_wksta_info_10_t;
1698 long smb_ReceiveRAPNetWkstaGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1700 smb_tran2Packet_t *outp;
1704 unsigned short * tp;
1707 smb_rap_wksta_info_10_t * info;
1711 tp = p->parmsp + 1; /* Skip over function number */
1712 (void) smb_ParseString((unsigned char*) tp, (char **) &tp); /* skip over param descriptor */
1713 (void) smb_ParseString((unsigned char*) tp, (char **) &tp); /* skip over data descriptor */
1717 if (infoLevel != 10) {
1718 return CM_ERROR_INVAL;
1724 totalData = sizeof(*info) + /* info */
1725 MAX_COMPUTERNAME_LENGTH + /* wki10_computername */
1726 SMB_MAX_USERNAME_LENGTH + /* wki10_username */
1727 MAX_COMPUTERNAME_LENGTH + /* wki10_langroup */
1728 MAX_COMPUTERNAME_LENGTH + /* wki10_logon_domain */
1729 1; /* wki10_oth_domains (null)*/
1731 outp = smb_GetTran2ResponsePacket(vcp, p, op, totalParams, totalData);
1733 memset(outp->parmsp,0,totalParams);
1734 memset(outp->datap,0,totalData);
1736 info = (smb_rap_wksta_info_10_t *) outp->datap;
1737 cstrp = (char *) (info + 1);
1739 info->wki10_computername = (DWORD) (cstrp - outp->datap);
1740 strcpy(cstrp, smb_localNamep);
1741 cstrp += strlen(cstrp) + 1;
1743 info->wki10_username = (DWORD) (cstrp - outp->datap);
1744 uidp = smb_FindUID(vcp, p->uid, 0);
1746 lock_ObtainMutex(&uidp->mx);
1747 if(uidp->unp && uidp->unp->name)
1748 strcpy(cstrp, uidp->unp->name);
1749 lock_ReleaseMutex(&uidp->mx);
1750 smb_ReleaseUID(uidp);
1752 cstrp += strlen(cstrp) + 1;
1754 info->wki10_langroup = (DWORD) (cstrp - outp->datap);
1755 strcpy(cstrp, "WORKGROUP");
1756 cstrp += strlen(cstrp) + 1;
1758 /* TODO: Not sure what values these should take, but these work */
1759 info->wki10_ver_major = 5;
1760 info->wki10_ver_minor = 1;
1762 info->wki10_logon_domain = (DWORD) (cstrp - outp->datap);
1763 strcpy(cstrp, smb_ServerDomainName);
1764 cstrp += strlen(cstrp) + 1;
1766 info->wki10_oth_domains = (DWORD) (cstrp - outp->datap);
1767 cstrp ++; /* no other domains */
1769 outp->totalData = (unsigned short) (cstrp - outp->datap); /* actual data size */
1770 outp->parmsp[2] = outp->totalData;
1771 outp->totalParms = totalParams;
1773 smb_SendTran2Packet(vcp,outp,op);
1774 smb_FreeTran2Packet(outp);
1779 typedef struct smb_rap_server_info_0 {
1781 } smb_rap_server_info_0_t;
1783 typedef struct smb_rap_server_info_1 {
1785 char sv1_version_major;
1786 char sv1_version_minor;
1787 unsigned long sv1_type;
1788 DWORD *sv1_comment_or_master_browser; /* char *sv1_comment_or_master_browser;*/
1789 } smb_rap_server_info_1_t;
1791 char smb_ServerComment[] = "OpenAFS Client";
1792 int smb_ServerCommentLen = sizeof(smb_ServerComment);
1794 #define SMB_SV_TYPE_SERVER 0x00000002L
1795 #define SMB_SV_TYPE_NT 0x00001000L
1796 #define SMB_SV_TYPE_SERVER_NT 0x00008000L
1798 long smb_ReceiveRAPNetServerGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1800 smb_tran2Packet_t *outp;
1804 unsigned short * tp;
1807 smb_rap_server_info_0_t * info0;
1808 smb_rap_server_info_1_t * info1;
1811 tp = p->parmsp + 1; /* Skip over function number */
1812 (void) smb_ParseString((unsigned char*) tp, (char **) &tp); /* skip over param descriptor */
1813 (void) smb_ParseString((unsigned char*) tp, (char **) &tp); /* skip over data descriptor */
1817 if (infoLevel != 0 && infoLevel != 1) {
1818 return CM_ERROR_INVAL;
1824 (infoLevel == 0) ? sizeof(smb_rap_server_info_0_t)
1825 : (sizeof(smb_rap_server_info_1_t) + smb_ServerCommentLen);
1827 outp = smb_GetTran2ResponsePacket(vcp, p, op, totalParams, totalData);
1829 memset(outp->parmsp,0,totalParams);
1830 memset(outp->datap,0,totalData);
1832 if (infoLevel == 0) {
1833 info0 = (smb_rap_server_info_0_t *) outp->datap;
1834 cstrp = (char *) (info0 + 1);
1835 strcpy(info0->sv0_name, "AFS");
1836 } else { /* infoLevel == SMB_INFO_STANDARD */
1837 info1 = (smb_rap_server_info_1_t *) outp->datap;
1838 cstrp = (char *) (info1 + 1);
1839 strcpy(info1->sv1_name, "AFS");
1842 SMB_SV_TYPE_SERVER |
1844 SMB_SV_TYPE_SERVER_NT;
1846 info1->sv1_version_major = 5;
1847 info1->sv1_version_minor = 1;
1848 info1->sv1_comment_or_master_browser = (DWORD *) (cstrp - outp->datap);
1850 strcpy(cstrp, smb_ServerComment);
1852 cstrp += smb_ServerCommentLen;
1855 totalData = cstrp - outp->datap;
1856 outp->totalData = min(bufsize,totalData); /* actual data size */
1857 outp->parmsp[0] = (outp->totalData == totalData)? 0 : ERROR_MORE_DATA;
1858 outp->parmsp[2] = totalData;
1859 outp->totalParms = totalParams;
1861 smb_SendTran2Packet(vcp,outp,op);
1862 smb_FreeTran2Packet(outp);
1867 long smb_ReceiveV3Tran2A(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
1869 smb_tran2Packet_t *asp;
1881 /* We sometimes see 0 word count. What to do? */
1882 if (*inp->wctp == 0) {
1887 osi_Log0(smb_logp, "TRANSACTION2 word count = 0");
1889 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
1890 ptbuf[0] = "Transaction2 word count = 0";
1891 ReportEvent(h, EVENTLOG_WARNING_TYPE, 0, 1003, NULL,
1892 1, inp->ncb_length, ptbuf, inp);
1893 DeregisterEventSource(h);
1895 osi_Log0(smb_logp, "TRANSACTION2 word count = 0");
1898 smb_SetSMBDataLength(outp, 0);
1899 smb_SendPacket(vcp, outp);
1903 totalParms = smb_GetSMBParm(inp, 0);
1904 totalData = smb_GetSMBParm(inp, 1);
1906 firstPacket = (inp->inCom == 0x32);
1908 /* find the packet we're reassembling */
1909 lock_ObtainWrite(&smb_globalLock);
1910 asp = smb_FindTran2Packet(vcp, inp);
1912 asp = smb_NewTran2Packet(vcp, inp, totalParms, totalData);
1914 lock_ReleaseWrite(&smb_globalLock);
1916 /* now merge in this latest packet; start by looking up offsets */
1918 parmDisp = dataDisp = 0;
1919 parmOffset = smb_GetSMBParm(inp, 10);
1920 dataOffset = smb_GetSMBParm(inp, 12);
1921 parmCount = smb_GetSMBParm(inp, 9);
1922 dataCount = smb_GetSMBParm(inp, 11);
1923 asp->maxReturnParms = smb_GetSMBParm(inp, 2);
1924 asp->maxReturnData = smb_GetSMBParm(inp, 3);
1926 osi_Log3(smb_logp, "SMB3 received T2 init packet total data %d, cur data %d, max return data %d",
1927 totalData, dataCount, asp->maxReturnData);
1930 parmDisp = smb_GetSMBParm(inp, 4);
1931 parmOffset = smb_GetSMBParm(inp, 3);
1932 dataDisp = smb_GetSMBParm(inp, 7);
1933 dataOffset = smb_GetSMBParm(inp, 6);
1934 parmCount = smb_GetSMBParm(inp, 2);
1935 dataCount = smb_GetSMBParm(inp, 5);
1937 osi_Log2(smb_logp, "SMB3 received T2 aux packet parms %d, data %d",
1938 parmCount, dataCount);
1941 /* now copy the parms and data */
1942 if ( asp->totalParms > 0 && parmCount != 0 )
1944 memcpy(((char *)asp->parmsp) + parmDisp, inp->data + parmOffset, parmCount);
1946 if ( asp->totalData > 0 && dataCount != 0 ) {
1947 memcpy(asp->datap + dataDisp, inp->data + dataOffset, dataCount);
1950 /* account for new bytes */
1951 asp->curData += dataCount;
1952 asp->curParms += parmCount;
1954 /* finally, if we're done, remove the packet from the queue and dispatch it */
1955 if (asp->totalParms > 0 &&
1956 asp->curParms > 0 &&
1957 asp->totalData <= asp->curData &&
1958 asp->totalParms <= asp->curParms) {
1959 /* we've received it all */
1960 lock_ObtainWrite(&smb_globalLock);
1961 osi_QRemove((osi_queue_t **) &smb_tran2AssemblyQueuep, &asp->q);
1962 lock_ReleaseWrite(&smb_globalLock);
1964 /* now dispatch it */
1965 if ( asp->opcode >= 0 && asp->opcode < 20 && smb_tran2DispatchTable[asp->opcode].procp) {
1966 osi_LogEvent("AFS-Dispatch-2[%s]",myCrt_2Dispatch(asp->opcode),"vcp[%x] lana[%d] lsn[%d]",(int)vcp,vcp->lana,vcp->lsn);
1967 osi_Log4(smb_logp,"AFS Server - Dispatch-2 %s vcp[%x] lana[%d] lsn[%d]",myCrt_2Dispatch(asp->opcode),vcp,vcp->lana,vcp->lsn);
1968 code = (*smb_tran2DispatchTable[asp->opcode].procp)(vcp, asp, outp);
1971 osi_LogEvent("AFS-Dispatch-2 [invalid]", NULL, "op[%x] vcp[%x] lana[%d] lsn[%d]", asp->opcode, vcp, vcp->lana, vcp->lsn);
1972 osi_Log4(smb_logp,"AFS Server - Dispatch-2 [INVALID] op[%x] vcp[%x] lana[%d] lsn[%d]", asp->opcode, vcp, vcp->lana, vcp->lsn);
1973 code = CM_ERROR_BADOP;
1976 /* if an error is returned, we're supposed to send an error packet,
1977 * otherwise the dispatched function already did the data sending.
1978 * We give dispatched proc the responsibility since it knows how much
1979 * space to allocate.
1982 smb_SendTran2Error(vcp, asp, outp, code);
1985 /* free the input tran 2 packet */
1986 lock_ObtainWrite(&smb_globalLock);
1987 smb_FreeTran2Packet(asp);
1988 lock_ReleaseWrite(&smb_globalLock);
1990 else if (firstPacket) {
1991 /* the first packet in a multi-packet request, we need to send an
1992 * ack to get more data.
1994 smb_SetSMBDataLength(outp, 0);
1995 smb_SendPacket(vcp, outp);
2001 long smb_ReceiveTran2Open(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
2004 smb_tran2Packet_t *outp;
2009 cm_scache_t *dscp; /* dir we're dealing with */
2010 cm_scache_t *scp; /* file we're creating */
2012 int initialModeBits;
2022 int parmSlot; /* which parm we're dealing with */
2023 long returnEALength;
2031 extraInfo = (p->parmsp[0] & 1); /* return extra info */
2032 returnEALength = (p->parmsp[0] & 8); /* return extended attr length */
2034 openFun = p->parmsp[6]; /* open function */
2035 excl = ((openFun & 3) == 0);
2036 trunc = ((openFun & 3) == 2); /* truncate it */
2037 openMode = (p->parmsp[1] & 0x7);
2038 openAction = 0; /* tracks what we did */
2040 attributes = p->parmsp[3];
2041 dosTime = p->parmsp[4] | (p->parmsp[5] << 16);
2043 /* compute initial mode bits based on read-only flag in attributes */
2044 initialModeBits = 0666;
2045 if (attributes & 1) initialModeBits &= ~0222;
2047 pathp = (char *) (&p->parmsp[14]);
2048 if (smb_StoreAnsiFilenames)
2049 OemToChar(pathp,pathp);
2051 outp = smb_GetTran2ResponsePacket(vcp, p, op, 40, 0);
2053 spacep = cm_GetSpace();
2054 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
2056 if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
2057 /* special case magic file name for receiving IOCTL requests
2058 * (since IOCTL calls themselves aren't getting through).
2060 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
2061 smb_SetupIoctlFid(fidp, spacep);
2063 /* copy out remainder of the parms */
2065 outp->parmsp[parmSlot] = fidp->fid; parmSlot++;
2067 outp->parmsp[parmSlot] = /* attrs */ 0; parmSlot++;
2068 outp->parmsp[parmSlot] = 0; parmSlot++; /* mod time */
2069 outp->parmsp[parmSlot] = 0; parmSlot++;
2070 outp->parmsp[parmSlot] = 0; parmSlot++; /* len */
2071 outp->parmsp[parmSlot] = 0x7fff; parmSlot++;
2072 outp->parmsp[parmSlot] = openMode; parmSlot++;
2073 outp->parmsp[parmSlot] = 0; parmSlot++; /* file type 0 ==> normal file or dir */
2074 outp->parmsp[parmSlot] = 0; parmSlot++; /* IPC junk */
2076 /* and the final "always present" stuff */
2077 outp->parmsp[parmSlot] = /* openAction found existing file */ 1; parmSlot++;
2078 /* next write out the "unique" ID */
2079 outp->parmsp[parmSlot] = 0x1234; parmSlot++;
2080 outp->parmsp[parmSlot] = 0x5678; parmSlot++;
2081 outp->parmsp[parmSlot] = 0; parmSlot++;
2082 if (returnEALength) {
2083 outp->parmsp[parmSlot] = 0; parmSlot++;
2084 outp->parmsp[parmSlot] = 0; parmSlot++;
2087 outp->totalData = 0;
2088 outp->totalParms = parmSlot * 2;
2090 smb_SendTran2Packet(vcp, outp, op);
2092 smb_FreeTran2Packet(outp);
2094 /* and clean up fid reference */
2095 smb_ReleaseFID(fidp);
2099 #ifdef DEBUG_VERBOSE
2101 char *hexp, *asciip;
2102 asciip = (lastNamep ? lastNamep : pathp);
2103 hexp = osi_HexifyString( asciip );
2104 DEBUG_EVENT2("AFS","T2Open H[%s] A[%s]", hexp, asciip);
2109 userp = smb_GetTran2User(vcp, p);
2110 /* In the off chance that userp is NULL, we log and abandon */
2112 osi_Log1(smb_logp, "ReceiveTran2Open user [%d] not resolvable", p->uid);
2113 smb_FreeTran2Packet(outp);
2114 return CM_ERROR_BADSMB;
2117 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
2118 if (code == CM_ERROR_TIDIPC) {
2119 /* Attempt to use TID allocated for IPC. The client is
2120 probably trying to locate DCE RPC end points, which
2121 we don't support. */
2122 osi_Log0(smb_logp, "Tran2Open received IPC TID");
2123 cm_ReleaseUser(userp);
2124 smb_FreeTran2Packet(outp);
2125 return CM_ERROR_NOSUCHPATH;
2129 code = cm_NameI(cm_rootSCachep, pathp,
2130 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
2131 userp, tidPathp, &req, &scp);
2133 code = cm_NameI(cm_rootSCachep, spacep->data,
2134 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
2135 userp, tidPathp, &req, &dscp);
2136 cm_FreeSpace(spacep);
2139 cm_ReleaseUser(userp);
2140 smb_FreeTran2Packet(outp);
2144 /* otherwise, scp points to the parent directory. Do a lookup,
2145 * and truncate the file if we find it, otherwise we create the
2152 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD, userp,
2154 if (code && code != CM_ERROR_NOSUCHFILE) {
2155 cm_ReleaseSCache(dscp);
2156 cm_ReleaseUser(userp);
2157 smb_FreeTran2Packet(outp);
2162 cm_FreeSpace(spacep);
2165 /* if we get here, if code is 0, the file exists and is represented by
2166 * scp. Otherwise, we have to create it.
2169 code = cm_CheckOpen(scp, openMode, trunc, userp, &req);
2171 if (dscp) cm_ReleaseSCache(dscp);
2172 cm_ReleaseSCache(scp);
2173 cm_ReleaseUser(userp);
2174 smb_FreeTran2Packet(outp);
2179 /* oops, file shouldn't be there */
2180 if (dscp) cm_ReleaseSCache(dscp);
2181 cm_ReleaseSCache(scp);
2182 cm_ReleaseUser(userp);
2183 smb_FreeTran2Packet(outp);
2184 return CM_ERROR_EXISTS;
2188 setAttr.mask = CM_ATTRMASK_LENGTH;
2189 setAttr.length.LowPart = 0;
2190 setAttr.length.HighPart = 0;
2191 code = cm_SetAttr(scp, &setAttr, userp, &req);
2192 openAction = 3; /* truncated existing file */
2195 openAction = 1; /* found existing file */
2197 else if (!(openFun & SMB_ATTR_DIRECTORY)) {
2198 /* don't create if not found */
2199 if (dscp) cm_ReleaseSCache(dscp);
2200 osi_assert(scp == NULL);
2201 cm_ReleaseUser(userp);
2202 smb_FreeTran2Packet(outp);
2203 return CM_ERROR_NOSUCHFILE;
2206 osi_assert(dscp != NULL && scp == NULL);
2207 openAction = 2; /* created file */
2208 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
2209 smb_UnixTimeFromSearchTime(&setAttr.clientModTime, dosTime);
2210 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
2212 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
2213 smb_NotifyChange(FILE_ACTION_ADDED,
2214 FILE_NOTIFY_CHANGE_FILE_NAME,
2215 dscp, lastNamep, NULL, TRUE);
2216 if (!excl && code == CM_ERROR_EXISTS) {
2217 /* not an exclusive create, and someone else tried
2218 * creating it already, then we open it anyway. We
2219 * don't bother retrying after this, since if this next
2220 * fails, that means that the file was deleted after we
2221 * started this call.
2223 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
2227 setAttr.mask = CM_ATTRMASK_LENGTH;
2228 setAttr.length.LowPart = 0;
2229 setAttr.length.HighPart = 0;
2230 code = cm_SetAttr(scp, &setAttr, userp,
2233 } /* lookup succeeded */
2237 /* we don't need this any longer */
2238 if (dscp) cm_ReleaseSCache(dscp);
2241 /* something went wrong creating or truncating the file */
2242 if (scp) cm_ReleaseSCache(scp);
2243 cm_ReleaseUser(userp);
2244 smb_FreeTran2Packet(outp);
2248 /* make sure we're about to open a file */
2249 if (scp->fileType != CM_SCACHETYPE_FILE) {
2251 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
2252 cm_scache_t * targetScp = 0;
2253 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
2255 /* we have a more accurate file to use (the
2256 * target of the symbolic link). Otherwise,
2257 * we'll just use the symlink anyway.
2259 osi_Log2(smb_logp, "symlink vp %x to vp %x",
2261 cm_ReleaseSCache(scp);
2265 if (scp->fileType != CM_SCACHETYPE_FILE) {
2266 cm_ReleaseSCache(scp);
2267 cm_ReleaseUser(userp);
2268 smb_FreeTran2Packet(outp);
2269 return CM_ERROR_ISDIR;
2273 /* now all we have to do is open the file itself */
2274 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
2277 /* save a pointer to the vnode */
2280 /* compute open mode */
2281 if (openMode != 1) fidp->flags |= SMB_FID_OPENREAD;
2282 if (openMode == 1 || openMode == 2)
2283 fidp->flags |= SMB_FID_OPENWRITE;
2285 smb_ReleaseFID(fidp);
2287 cm_Open(scp, 0, userp);
2289 /* copy out remainder of the parms */
2291 outp->parmsp[parmSlot] = fidp->fid; parmSlot++;
2292 lock_ObtainMutex(&scp->mx);
2294 outp->parmsp[parmSlot] = smb_Attributes(scp); parmSlot++;
2295 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
2296 outp->parmsp[parmSlot] = (unsigned short)(dosTime & 0xffff); parmSlot++;
2297 outp->parmsp[parmSlot] = (unsigned short)((dosTime>>16) & 0xffff); parmSlot++;
2298 outp->parmsp[parmSlot] = (unsigned short) (scp->length.LowPart & 0xffff);
2300 outp->parmsp[parmSlot] = (unsigned short) ((scp->length.LowPart >> 16) & 0xffff);
2302 outp->parmsp[parmSlot] = openMode; parmSlot++;
2303 outp->parmsp[parmSlot] = 0; parmSlot++; /* file type 0 ==> normal file or dir */
2304 outp->parmsp[parmSlot] = 0; parmSlot++; /* IPC junk */
2306 /* and the final "always present" stuff */
2307 outp->parmsp[parmSlot] = openAction; parmSlot++;
2308 /* next write out the "unique" ID */
2309 outp->parmsp[parmSlot] = (unsigned short) (scp->fid.vnode & 0xffff); parmSlot++;
2310 outp->parmsp[parmSlot] = (unsigned short) (scp->fid.volume & 0xffff); parmSlot++;
2311 outp->parmsp[parmSlot] = 0; parmSlot++;
2312 if (returnEALength) {
2313 outp->parmsp[parmSlot] = 0; parmSlot++;
2314 outp->parmsp[parmSlot] = 0; parmSlot++;
2316 lock_ReleaseMutex(&scp->mx);
2317 outp->totalData = 0; /* total # of data bytes */
2318 outp->totalParms = parmSlot * 2; /* shorts are two bytes */
2320 smb_SendTran2Packet(vcp, outp, op);
2322 smb_FreeTran2Packet(outp);
2324 cm_ReleaseUser(userp);
2325 /* leave scp held since we put it in fidp->scp */
2329 long smb_ReceiveTran2FindFirst(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
2331 osi_Log0(smb_logp,"ReceiveTran2FindFirst - NOT_SUPPORTED");
2332 return CM_ERROR_BADOP;
2335 long smb_ReceiveTran2FindNext(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
2337 osi_Log0(smb_logp,"ReceiveTran2FindNext - NOT_SUPPORTED");
2338 return CM_ERROR_BADOP;
2341 long smb_ReceiveTran2QFSInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
2343 smb_tran2Packet_t *outp;
2344 smb_tran2QFSInfo_t qi;
2347 static char FSname[6] = {'A', 0, 'F', 0, 'S', 0};
2349 osi_Log1(smb_logp, "T2 QFSInfo type 0x%x", p->parmsp[0]);
2351 switch (p->parmsp[0]) {
2352 case 1: responseSize = sizeof(qi.u.allocInfo); break;
2353 case 2: responseSize = sizeof(qi.u.volumeInfo); break;
2354 case 0x102: responseSize = sizeof(qi.u.FSvolumeInfo); break;
2355 case 0x103: responseSize = sizeof(qi.u.FSsizeInfo); break;
2356 case 0x104: responseSize = sizeof(qi.u.FSdeviceInfo); break;
2357 case 0x105: responseSize = sizeof(qi.u.FSattributeInfo); break;
2358 case 0x200: /* CIFS Unix Info */
2359 case 0x301: /* Mac FS Info */
2360 default: return CM_ERROR_INVAL;
2363 outp = smb_GetTran2ResponsePacket(vcp, p, op, 0, responseSize);
2364 switch (p->parmsp[0]) {
2367 qi.u.allocInfo.FSID = 0;
2368 qi.u.allocInfo.sectorsPerAllocUnit = 1;
2369 qi.u.allocInfo.totalAllocUnits = 0x7fffffff;
2370 qi.u.allocInfo.availAllocUnits = 0x3fffffff;
2371 qi.u.allocInfo.bytesPerSector = 1024;
2376 qi.u.volumeInfo.vsn = 1234;
2377 qi.u.volumeInfo.vnCount = 4;
2378 /* we're supposed to pad it out with zeroes to the end */
2379 memset(&qi.u.volumeInfo.label, 0, sizeof(qi.u.volumeInfo.label));
2380 memcpy(qi.u.volumeInfo.label, "AFS", 4);
2384 /* FS volume info */
2385 memset((char *)&qi.u.FSvolumeInfo.vct, 0, sizeof(FILETIME));
2386 qi.u.FSvolumeInfo.vsn = 1234;
2387 qi.u.FSvolumeInfo.vnCount = 8;
2388 memcpy(qi.u.FSvolumeInfo.label, "A\0F\0S\0\0", 8);
2394 temp.LowPart = 0x7fffffff;
2395 qi.u.FSsizeInfo.totalAllocUnits = temp;
2396 temp.LowPart = 0x3fffffff;
2397 qi.u.FSsizeInfo.availAllocUnits = temp;
2398 qi.u.FSsizeInfo.sectorsPerAllocUnit = 1;
2399 qi.u.FSsizeInfo.bytesPerSector = 1024;
2403 /* FS device info */
2404 qi.u.FSdeviceInfo.devType = 0; /* don't have a number */
2405 qi.u.FSdeviceInfo.characteristics = 0x50; /* remote, virtual */
2409 /* FS attribute info */
2410 /* attributes, defined in WINNT.H:
2411 * FILE_CASE_SENSITIVE_SEARCH 0x1
2412 * FILE_CASE_PRESERVED_NAMES 0x2
2413 * <no name defined> 0x4000
2414 * If bit 0x4000 is not set, Windows 95 thinks
2415 * we can't handle long (non-8.3) names,
2416 * despite our protestations to the contrary.
2418 qi.u.FSattributeInfo.attributes = 0x4003;
2419 qi.u.FSattributeInfo.maxCompLength = 255;
2420 qi.u.FSattributeInfo.FSnameLength = 6;
2421 memcpy(qi.u.FSattributeInfo.FSname, FSname, 6);
2425 /* copy out return data, and set corresponding sizes */
2426 outp->totalParms = 0;
2427 outp->totalData = responseSize;
2428 memcpy(outp->datap, &qi, responseSize);
2430 /* send and free the packets */
2431 smb_SendTran2Packet(vcp, outp, op);
2432 smb_FreeTran2Packet(outp);
2437 long smb_ReceiveTran2SetFSInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
2439 osi_Log0(smb_logp,"ReceiveTran2SetFSInfo - NOT_SUPPORTED");
2440 return CM_ERROR_BADOP;
2443 struct smb_ShortNameRock {
2447 size_t shortNameLen;
2450 int cm_GetShortNameProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *vrockp,
2453 struct smb_ShortNameRock *rockp;
2457 /* compare both names and vnodes, though probably just comparing vnodes
2458 * would be safe enough.
2460 if (cm_stricmp(dep->name, rockp->maskp) != 0)
2462 if (ntohl(dep->fid.vnode) != rockp->vnode)
2464 /* This is the entry */
2465 cm_Gen8Dot3Name(dep, rockp->shortName, &shortNameEnd);
2466 rockp->shortNameLen = shortNameEnd - rockp->shortName;
2467 return CM_ERROR_STOPNOW;
2470 long cm_GetShortName(char *pathp, cm_user_t *userp, cm_req_t *reqp,
2471 char *tidPathp, int vnode, char *shortName, size_t *shortNameLenp)
2473 struct smb_ShortNameRock rock;
2477 int caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
2481 spacep = cm_GetSpace();
2482 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
2484 code = cm_NameI(cm_rootSCachep, spacep->data, caseFold, userp, tidPathp,
2486 cm_FreeSpace(spacep);
2487 if (code) return code;
2489 if (!lastNamep) lastNamep = pathp;
2492 thyper.HighPart = 0;
2493 rock.shortName = shortName;
2495 rock.maskp = lastNamep;
2496 code = cm_ApplyDir(dscp, cm_GetShortNameProc, &rock, &thyper, userp, reqp, NULL);
2498 cm_ReleaseSCache(dscp);
2501 return CM_ERROR_NOSUCHFILE;
2502 if (code == CM_ERROR_STOPNOW) {
2503 *shortNameLenp = rock.shortNameLen;
2509 long smb_ReceiveTran2QPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
2511 smb_tran2Packet_t *outp;
2514 unsigned short infoLevel;
2516 unsigned short attributes;
2517 unsigned long extAttributes;
2522 cm_scache_t *scp, *dscp;
2531 infoLevel = p->parmsp[0];
2532 if (infoLevel == SMB_INFO_IS_NAME_VALID)
2534 else if (infoLevel == SMB_INFO_STANDARD)
2535 nbytesRequired = 22;
2536 else if (infoLevel == SMB_INFO_QUERY_EA_SIZE)
2537 nbytesRequired = 26;
2538 else if (infoLevel == SMB_QUERY_FILE_BASIC_INFO)
2539 nbytesRequired = 40;
2540 else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO)
2541 nbytesRequired = 24;
2542 else if (infoLevel == SMB_QUERY_FILE_EA_INFO)
2544 else if (infoLevel == SMB_QUERY_FILE_ALT_NAME_INFO)
2545 nbytesRequired = 30;
2547 osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
2548 p->opcode, infoLevel);
2549 smb_SendTran2Error(vcp, p, opx, CM_ERROR_INVAL);
2552 osi_Log2(smb_logp, "T2 QPathInfo type 0x%x path %s", infoLevel,
2553 osi_LogSaveString(smb_logp, (char *)(&p->parmsp[3])));
2555 outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, nbytesRequired);
2557 if (infoLevel > 0x100)
2558 outp->totalParms = 2;
2560 outp->totalParms = 0;
2561 outp->totalData = nbytesRequired;
2563 /* now, if we're at infoLevel 6, we're only being asked to check
2564 * the syntax, so we just OK things now. In particular, we're *not*
2565 * being asked to verify anything about the state of any parent dirs.
2567 if (infoLevel == SMB_INFO_IS_NAME_VALID) {
2568 smb_SendTran2Packet(vcp, outp, opx);
2569 smb_FreeTran2Packet(outp);
2573 userp = smb_GetTran2User(vcp, p);
2575 osi_Log1(smb_logp, "ReceiveTran2QPathInfo unable to resolve user [%d]", p->uid);
2576 smb_FreeTran2Packet(outp);
2577 return CM_ERROR_BADSMB;
2580 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
2582 cm_ReleaseUser(userp);
2583 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOSUCHPATH);
2584 smb_FreeTran2Packet(outp);
2589 * XXX Strange hack XXX
2591 * As of Patch 7 (13 January 98), we are having the following problem:
2592 * In NT Explorer 4.0, whenever we click on a directory, AFS gets
2593 * requests to look up "desktop.ini" in all the subdirectories.
2594 * This can cause zillions of timeouts looking up non-existent cells
2595 * and volumes, especially in the top-level directory.
2597 * We have not found any way to avoid this or work around it except
2598 * to explicitly ignore the requests for mount points that haven't
2599 * yet been evaluated and for directories that haven't yet been
2602 if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
2603 spacep = cm_GetSpace();
2604 smb_StripLastComponent(spacep->data, &lastComp,
2605 (char *)(&p->parmsp[3]));
2606 #ifndef SPECIAL_FOLDERS
2607 /* Make sure that lastComp is not NULL */
2609 if (stricmp(lastComp, "\\desktop.ini") == 0) {
2610 code = cm_NameI(cm_rootSCachep, spacep->data,
2614 userp, tidPathp, &req, &dscp);
2616 if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT
2617 && !dscp->mountRootFidp)
2618 code = CM_ERROR_NOSUCHFILE;
2619 else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
2620 cm_buf_t *bp = buf_Find(dscp, &hzero);
2624 code = CM_ERROR_NOSUCHFILE;
2626 cm_ReleaseSCache(dscp);
2628 cm_FreeSpace(spacep);
2629 cm_ReleaseUser(userp);
2630 smb_SendTran2Error(vcp, p, opx, code);
2631 smb_FreeTran2Packet(outp);
2637 #endif /* SPECIAL_FOLDERS */
2639 cm_FreeSpace(spacep);
2642 /* now do namei and stat, and copy out the info */
2643 code = cm_NameI(cm_rootSCachep, (char *)(&p->parmsp[3]),
2644 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, tidPathp, &req, &scp);
2647 cm_ReleaseUser(userp);
2648 smb_SendTran2Error(vcp, p, opx, code);
2649 smb_FreeTran2Packet(outp);
2653 lock_ObtainMutex(&scp->mx);
2654 code = cm_SyncOp(scp, NULL, userp, &req, 0,
2655 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
2656 if (code) goto done;
2658 /* now we have the status in the cache entry, and everything is locked.
2659 * Marshall the output data.
2662 /* for info level 108, figure out short name */
2663 if (infoLevel == 0x108) {
2664 code = cm_GetShortName((char *)(&p->parmsp[3]), userp, &req,
2665 tidPathp, scp->fid.vnode, shortName,
2672 *((u_long *)op) = len * 2; op += 4;
2673 mbstowcs((unsigned short *)op, shortName, len);
2678 if (infoLevel == SMB_INFO_STANDARD || infoLevel == SMB_INFO_QUERY_EA_SIZE) {
2679 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
2680 *((u_long *)op) = dosTime; op += 4; /* creation time */
2681 *((u_long *)op) = dosTime; op += 4; /* access time */
2682 *((u_long *)op) = dosTime; op += 4; /* write time */
2683 *((u_long *)op) = scp->length.LowPart; op += 4; /* length */
2684 *((u_long *)op) = scp->length.LowPart; op += 4; /* alloc size */
2685 attributes = smb_Attributes(scp);
2686 *((u_short *)op) = attributes; op += 2; /* attributes */
2688 else if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
2689 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
2690 *((FILETIME *)op) = ft; op += 8; /* creation time */
2691 *((FILETIME *)op) = ft; op += 8; /* last access time */
2692 *((FILETIME *)op) = ft; op += 8; /* last write time */
2693 *((FILETIME *)op) = ft; op += 8; /* last change time */
2694 extAttributes = smb_ExtAttributes(scp);
2695 *((u_long *)op) = extAttributes; op += 4; /* extended attribs */
2696 *((u_long *)op) = 0; op += 4; /* don't know what this is */
2698 else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO) {
2699 *((LARGE_INTEGER *)op) = scp->length; op += 8; /* alloc size */
2700 *((LARGE_INTEGER *)op) = scp->length; op += 8; /* EOF */
2701 *((u_long *)op) = scp->linkCount; op += 4;
2704 *op++ = (scp->fileType == CM_SCACHETYPE_DIRECTORY ? 1 : 0);
2707 else if (infoLevel == SMB_QUERY_FILE_EA_INFO) {
2708 memset(op, 0, 4); op += 4; /* EA size */
2711 /* now, if we are being asked about extended attrs, return a 0 size */
2712 if (infoLevel == SMB_INFO_QUERY_EA_SIZE) {
2713 *((u_long *)op) = 0; op += 4;
2717 /* send and free the packets */
2719 lock_ReleaseMutex(&scp->mx);
2720 cm_ReleaseSCache(scp);
2721 cm_ReleaseUser(userp);
2723 smb_SendTran2Packet(vcp, outp, opx);
2725 smb_SendTran2Error(vcp, p, opx, code);
2726 smb_FreeTran2Packet(outp);
2731 long smb_ReceiveTran2SetPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
2733 osi_Log0(smb_logp,"ReceiveTran2SetPathInfo - NOT_SUPPORTED");
2734 return CM_ERROR_BADOP;
2737 long smb_ReceiveTran2QFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
2739 smb_tran2Packet_t *outp;
2741 unsigned long attributes;
2742 unsigned short infoLevel;
2755 fidp = smb_FindFID(vcp, fid, 0);
2758 smb_SendTran2Error(vcp, p, opx, CM_ERROR_BADFD);
2762 infoLevel = p->parmsp[1];
2763 if (infoLevel == SMB_QUERY_FILE_BASIC_INFO)
2764 nbytesRequired = 40;
2765 else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO)
2766 nbytesRequired = 24;
2767 else if (infoLevel == SMB_QUERY_FILE_EA_INFO)
2769 else if (infoLevel == SMB_QUERY_FILE_NAME_INFO)
2772 osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
2773 p->opcode, infoLevel);
2774 smb_SendTran2Error(vcp, p, opx, CM_ERROR_INVAL);
2775 smb_ReleaseFID(fidp);
2778 osi_Log2(smb_logp, "T2 QFileInfo type 0x%x fid %d", infoLevel, fid);
2780 outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, nbytesRequired);
2782 if (infoLevel > 0x100)
2783 outp->totalParms = 2;
2785 outp->totalParms = 0;
2786 outp->totalData = nbytesRequired;
2788 userp = smb_GetTran2User(vcp, p);
2790 osi_Log1(smb_logp, "ReceiveTran2QFileInfo unable to resolve user [%d]", p->uid);
2791 code = CM_ERROR_BADSMB;
2796 lock_ObtainMutex(&scp->mx);
2797 code = cm_SyncOp(scp, NULL, userp, &req, 0,
2798 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
2802 /* now we have the status in the cache entry, and everything is locked.
2803 * Marshall the output data.
2806 if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
2807 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
2808 *((FILETIME *)op) = ft; op += 8; /* creation time */
2809 *((FILETIME *)op) = ft; op += 8; /* last access time */
2810 *((FILETIME *)op) = ft; op += 8; /* last write time */
2811 *((FILETIME *)op) = ft; op += 8; /* last change time */
2812 attributes = smb_ExtAttributes(scp);
2813 *((u_long *)op) = attributes; op += 4;
2814 *((u_long *)op) = 0; op += 4;
2816 else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO) {
2817 *((LARGE_INTEGER *)op) = scp->length; op += 8; /* alloc size */
2818 *((LARGE_INTEGER *)op) = scp->length; op += 8; /* EOF */
2819 *((u_long *)op) = scp->linkCount; op += 4;
2820 *op++ = ((fidp->flags & SMB_FID_DELONCLOSE) ? 1 : 0);
2821 *op++ = (scp->fileType == CM_SCACHETYPE_DIRECTORY ? 1 : 0);
2825 else if (infoLevel == SMB_QUERY_FILE_EA_INFO) {
2826 *((u_long *)op) = 0; op += 4;
2828 else if (infoLevel == SMB_QUERY_FILE_NAME_INFO) {
2832 if (fidp->NTopen_wholepathp)
2833 name = fidp->NTopen_wholepathp;
2835 name = "\\"; /* probably can't happen */
2837 outp->totalData = (len*2) + 4; /* this is actually what we want to return */
2838 *((u_long *)op) = len * 2; op += 4;
2839 mbstowcs((unsigned short *)op, name, len); op += (len * 2);
2842 /* send and free the packets */
2844 lock_ReleaseMutex(&scp->mx);
2845 cm_ReleaseUser(userp);
2846 smb_ReleaseFID(fidp);
2848 smb_SendTran2Packet(vcp, outp, opx);
2850 smb_SendTran2Error(vcp, p, opx, code);
2851 smb_FreeTran2Packet(outp);
2856 long smb_ReceiveTran2SetFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
2861 unsigned short infoLevel;
2862 smb_tran2Packet_t *outp;
2870 fidp = smb_FindFID(vcp, fid, 0);
2873 smb_SendTran2Error(vcp, p, op, CM_ERROR_BADFD);
2877 infoLevel = p->parmsp[1];
2878 osi_Log2(smb_logp,"ReceiveTran2SetFileInfo type=[%x] fid=[%x]", infoLevel, fid);
2879 if (infoLevel > 0x104 || infoLevel < 0x101) {
2880 osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
2881 p->opcode, infoLevel);
2882 smb_SendTran2Error(vcp, p, op, CM_ERROR_INVAL);
2883 smb_ReleaseFID(fidp);
2887 if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO && !(fidp->flags & SMB_FID_OPENDELETE)) {
2888 smb_SendTran2Error(vcp, p, op, CM_ERROR_NOACCESS);
2889 smb_ReleaseFID(fidp);
2892 if ((infoLevel == SMB_QUERY_FILE_EA_INFO || infoLevel == SMB_QUERY_FILE_NAME_INFO)
2893 && !(fidp->flags & SMB_FID_OPENWRITE)) {
2894 smb_SendTran2Error(vcp, p, op, CM_ERROR_NOACCESS);
2895 smb_ReleaseFID(fidp);
2899 osi_Log1(smb_logp, "T2 SFileInfo type 0x%x", infoLevel);
2901 outp = smb_GetTran2ResponsePacket(vcp, p, op, 2, 0);
2903 outp->totalParms = 2;
2904 outp->totalData = 0;
2906 userp = smb_GetTran2User(vcp, p);
2908 osi_Log1(smb_logp,"ReceiveTran2SetFileInfo unable to resolve user [%d]", p->uid);
2909 code = CM_ERROR_BADSMB;
2915 if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
2917 unsigned int attribute;
2920 /* lock the vnode with a callback; we need the current status
2921 * to determine what the new status is, in some cases.
2923 lock_ObtainMutex(&scp->mx);
2924 code = cm_SyncOp(scp, NULL, userp, &req, 0,
2925 CM_SCACHESYNC_GETSTATUS
2926 | CM_SCACHESYNC_NEEDCALLBACK);
2928 lock_ReleaseMutex(&scp->mx);
2932 /* prepare for setattr call */
2935 lastMod = *((FILETIME *)(p->datap + 16));
2936 /* when called as result of move a b, lastMod is (-1, -1).
2937 * If the check for -1 is not present, timestamp
2938 * of the resulting file will be 1969 (-1)
2940 if (LargeIntegerNotEqualToZero(*((LARGE_INTEGER *)&lastMod)) &&
2941 lastMod.dwLowDateTime != -1 && lastMod.dwHighDateTime != -1) {
2942 attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
2943 smb_UnixTimeFromLargeSearchTime(&attr.clientModTime,
2945 fidp->flags |= SMB_FID_MTIMESETDONE;
2948 attribute = *((u_long *)(p->datap + 32));
2949 if (attribute != 0) {
2950 if ((scp->unixModeBits & 0222)
2951 && (attribute & 1) != 0) {
2952 /* make a writable file read-only */
2953 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
2954 attr.unixModeBits = scp->unixModeBits & ~0222;
2956 else if ((scp->unixModeBits & 0222) == 0
2957 && (attribute & 1) == 0) {
2958 /* make a read-only file writable */
2959 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
2960 attr.unixModeBits = scp->unixModeBits | 0222;
2963 lock_ReleaseMutex(&scp->mx);
2967 code = cm_SetAttr(scp, &attr, userp, &req);
2971 else if (infoLevel == SMB_QUERY_FILE_EA_INFO || infoLevel == SMB_QUERY_FILE_NAME_INFO) {
2972 LARGE_INTEGER size = *((LARGE_INTEGER *)(p->datap));
2975 attr.mask = CM_ATTRMASK_LENGTH;
2976 attr.length.LowPart = size.LowPart;
2977 attr.length.HighPart = size.HighPart;
2978 code = cm_SetAttr(scp, &attr, userp, &req);
2980 else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO) {
2981 if (*((char *)(p->datap))) {
2982 code = cm_CheckNTDelete(fidp->NTopen_dscp, scp, userp,
2985 fidp->flags |= SMB_FID_DELONCLOSE;
2989 fidp->flags &= ~SMB_FID_DELONCLOSE;
2994 cm_ReleaseUser(userp);
2995 smb_ReleaseFID(fidp);
2997 smb_SendTran2Packet(vcp, outp, op);
2999 smb_SendTran2Error(vcp, p, op, code);
3000 smb_FreeTran2Packet(outp);
3006 smb_ReceiveTran2FSCTL(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3008 osi_Log0(smb_logp,"ReceiveTran2FSCTL - NOT_SUPPORTED");
3009 return CM_ERROR_BADOP;
3013 smb_ReceiveTran2IOCTL(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3015 osi_Log0(smb_logp,"ReceiveTran2IOCTL - NOT_SUPPORTED");
3016 return CM_ERROR_BADOP;
3020 smb_ReceiveTran2FindNotifyFirst(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3022 osi_Log0(smb_logp,"ReceiveTran2FindNotifyFirst - NOT_SUPPORTED");
3023 return CM_ERROR_BADOP;
3027 smb_ReceiveTran2FindNotifyNext(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3029 osi_Log0(smb_logp,"ReceiveTran2FindNotifyNext - NOT_SUPPORTED");
3030 return CM_ERROR_BADOP;
3034 smb_ReceiveTran2CreateDirectory(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3036 osi_Log0(smb_logp,"ReceiveTran2CreateDirectory - NOT_SUPPORTED");
3037 return CM_ERROR_BADOP;
3041 smb_ReceiveTran2SessionSetup(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3043 osi_Log0(smb_logp,"ReceiveTran2SessionSetup - NOT_SUPPORTED");
3044 return CM_ERROR_BADOP;
3048 smb_ReceiveTran2GetDFSReferral(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3050 /* This is a UNICODE only request (bit15 of Flags2) */
3051 /* The TID must be IPC$ */
3053 /* The documentation for the Flags response field is contradictory */
3055 /* Use Version 1 Referral Element Format */
3056 /* ServerType = 0; indicates the next server should be queried for the file */
3057 /* ReferralFlags = 0x01; PathConsumed characters should be stripped */
3058 /* Node = UnicodeString of UNC path of the next share name */
3060 osi_Log0(smb_logp,"ReceiveTran2GetDFSReferral - NOT_SUPPORTED");
3061 return CM_ERROR_BADOP;
3065 smb_ReceiveTran2ReportDFSInconsistency(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3067 /* This is a UNICODE only request (bit15 of Flags2) */
3069 /* There is nothing we can do about this operation. The client is going to
3070 * tell us that there is a Version 1 Referral Element for which there is a DFS Error.
3071 * Unfortunately, there is really nothing we can do about it other then log it
3072 * somewhere. Even then I don't think there is anything for us to do.
3073 * So let's return an error value.
3076 osi_Log0(smb_logp,"ReceiveTran2ReportDFSInconsistency - NOT_SUPPORTED");
3077 return CM_ERROR_BADOP;
3081 smb_ApplyV3DirListPatches(cm_scache_t *dscp,
3082 smb_dirListPatch_t **dirPatchespp, int infoLevel, cm_user_t *userp,
3087 cm_scache_t *targetScp; /* target if scp is a symlink */
3092 unsigned short attr;
3093 unsigned long lattr;
3094 smb_dirListPatch_t *patchp;
3095 smb_dirListPatch_t *npatchp;
3097 for(patchp = *dirPatchespp; patchp; patchp =
3098 (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
3099 code = cm_GetSCache(&patchp->fid, &scp, userp, reqp);
3101 lock_ObtainMutex(&scp->mx);
3102 code = cm_SyncOp(scp, NULL, userp, reqp, 0,
3103 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3105 lock_ReleaseMutex(&scp->mx);
3106 cm_ReleaseSCache(scp);
3108 dptr = patchp->dptr;
3110 /* Plug in fake timestamps. A time stamp of 0 causes 'invalid parameter'
3111 errors in the client. */
3112 if (infoLevel >= 0x101) {
3113 /* 1969-12-31 23:59:59 +00 */
3114 ft.dwHighDateTime = 0x19DB200;
3115 ft.dwLowDateTime = 0x5BB78980;
3117 /* copy to Creation Time */
3118 *((FILETIME *)dptr) = ft;
3121 /* copy to Last Access Time */
3122 *((FILETIME *)dptr) = ft;
3125 /* copy to Last Write Time */
3126 *((FILETIME *)dptr) = ft;
3129 /* copy to Change Time */
3130 *((FILETIME *)dptr) = ft;
3133 /* merge in hidden attribute */
3134 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
3135 *((u_long *)dptr) = SMB_ATTR_HIDDEN;
3139 /* 1969-12-31 23:59:58 +00*/
3140 dosTime = 0xEBBFBF7D;
3142 /* and copy out date */
3143 shortTemp = (dosTime>>16) & 0xffff;
3144 *((u_short *)dptr) = shortTemp;
3147 /* copy out creation time */
3148 shortTemp = dosTime & 0xffff;
3149 *((u_short *)dptr) = shortTemp;
3152 /* and copy out date */
3153 shortTemp = (dosTime>>16) & 0xffff;
3154 *((u_short *)dptr) = shortTemp;
3157 /* copy out access time */
3158 shortTemp = dosTime & 0xffff;
3159 *((u_short *)dptr) = shortTemp;
3162 /* and copy out date */
3163 shortTemp = (dosTime>>16) & 0xffff;
3164 *((u_short *)dptr) = shortTemp;
3167 /* copy out mod time */
3168 shortTemp = dosTime & 0xffff;
3169 *((u_short *)dptr) = shortTemp;
3172 /* merge in hidden (dot file) attribute */
3173 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
3174 attr = SMB_ATTR_HIDDEN;
3175 *dptr++ = attr & 0xff;
3176 *dptr++ = (attr >> 8) & 0xff;
3182 /* now watch for a symlink */
3184 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
3185 lock_ReleaseMutex(&scp->mx);
3186 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, reqp);
3188 /* we have a more accurate file to use (the
3189 * target of the symbolic link). Otherwise,
3190 * we'll just use the symlink anyway.
3192 osi_Log2(smb_logp, "symlink vp %x to vp %x",
3194 cm_ReleaseSCache(scp);
3197 lock_ObtainMutex(&scp->mx);
3200 dptr = patchp->dptr;
3202 if (infoLevel >= 0x101) {
3204 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
3206 /* copy to Creation Time */
3207 *((FILETIME *)dptr) = ft;
3210 /* copy to Last Access Time */
3211 *((FILETIME *)dptr) = ft;
3214 /* copy to Last Write Time */
3215 *((FILETIME *)dptr) = ft;
3218 /* copy to Change Time */
3219 *((FILETIME *)dptr) = ft;
3222 /* Use length for both file length and alloc length */
3223 *((LARGE_INTEGER *)dptr) = scp->length;
3225 *((LARGE_INTEGER *)dptr) = scp->length;
3228 /* Copy attributes */
3229 lattr = smb_ExtAttributes(scp);
3230 /* merge in hidden (dot file) attribute */
3231 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE )
3232 lattr |= SMB_ATTR_HIDDEN;
3233 *((u_long *)dptr) = lattr;
3238 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
3240 /* and copy out date */
3241 shortTemp = (dosTime>>16) & 0xffff;
3242 *((u_short *)dptr) = shortTemp;
3245 /* copy out creation time */
3246 shortTemp = dosTime & 0xffff;
3247 *((u_short *)dptr) = shortTemp;
3250 /* and copy out date */
3251 shortTemp = (dosTime>>16) & 0xffff;
3252 *((u_short *)dptr) = shortTemp;
3255 /* copy out access time */
3256 shortTemp = dosTime & 0xffff;
3257 *((u_short *)dptr) = shortTemp;
3260 /* and copy out date */
3261 shortTemp = (dosTime>>16) & 0xffff;
3262 *((u_short *)dptr) = shortTemp;
3265 /* copy out mod time */
3266 shortTemp = dosTime & 0xffff;
3267 *((u_short *)dptr) = shortTemp;
3270 /* copy out file length and alloc length,
3271 * using the same for both
3273 *((u_long *)dptr) = scp->length.LowPart;
3275 *((u_long *)dptr) = scp->length.LowPart;
3278 /* finally copy out attributes as short */
3279 attr = smb_Attributes(scp);
3280 /* merge in hidden (dot file) attribute */
3281 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE )
3282 attr |= SMB_ATTR_HIDDEN;
3283 *dptr++ = attr & 0xff;
3284 *dptr++ = (attr >> 8) & 0xff;
3287 lock_ReleaseMutex(&scp->mx);
3288 cm_ReleaseSCache(scp);
3291 /* now free the patches */
3292 for (patchp = *dirPatchespp; patchp; patchp = npatchp) {
3293 npatchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q);
3297 /* and mark the list as empty */
3298 *dirPatchespp = NULL;
3303 #ifndef USE_OLD_MATCHING
3304 // char table for case insensitive comparison
3305 char mapCaseTable[256];
3307 VOID initUpperCaseTable(VOID)
3310 for (i = 0; i < 256; ++i)
3311 mapCaseTable[i] = toupper(i);
3312 // make '"' match '.'
3313 mapCaseTable[(int)'"'] = toupper('.');
3314 // make '<' match '*'
3315 mapCaseTable[(int)'<'] = toupper('*');
3316 // make '>' match '?'
3317 mapCaseTable[(int)'>'] = toupper('?');
3320 // Compare 'pattern' (containing metacharacters '*' and '?') with the file
3322 // Note : this procedure works recursively calling itself.
3324 // PSZ pattern : string containing metacharacters.
3325 // PSZ name : file name to be compared with 'pattern'.
3327 // BOOL : TRUE/FALSE (match/mistmatch)
3330 szWildCardMatchFileName(PSZ pattern, PSZ name)
3332 PSZ pename; // points to the last 'name' character
3334 pename = name + strlen(name) - 1;
3344 if (*pattern == '\0')
3346 for (p = pename; p >= name; --p) {
3347 if ((mapCaseTable[*p] == mapCaseTable[*pattern]) &&
3348 szWildCardMatchFileName(pattern + 1, p + 1))
3353 if (mapCaseTable[*name] != mapCaseTable[*pattern])
3360 if (*pattern == '\0' || *pattern == '*' && *(pattern+1) == '\0')
3366 /* do a case-folding search of the star name mask with the name in namep.
3367 * Return 1 if we match, otherwise 0.
3369 int smb_V3MatchMask(char *namep, char *maskp, int flags)
3372 int i, j, star, qmark, retval;
3374 /* make sure we only match 8.3 names, if requested */
3375 if ((flags & CM_FLAG_8DOT3) && !cm_Is8Dot3(namep))
3378 /* optimize the pattern:
3379 * if there is a mixture of '?' and '*',
3380 * for example the sequence "*?*?*?*"
3381 * must be turned into the form "*"
3383 newmask = (char *)malloc(strlen(maskp)+1);
3384 for ( i=0, j=0, star=0, qmark=0; maskp[i]; i++) {
3385 switch ( maskp[i] ) {
3397 } else if ( qmark ) {
3401 newmask[j++] = maskp[i];
3408 } else if ( qmark ) {
3412 newmask[j++] = '\0';
3414 retval = szWildCardMatchFileName(newmask, namep) ? 1:0;
3420 #else /* USE_OLD_MATCHING */
3421 /* do a case-folding search of the star name mask with the name in namep.
3422 * Return 1 if we match, otherwise 0.
3424 int smb_V3MatchMask(char *namep, char *maskp, int flags)
3426 unsigned char tcp1, tcp2; /* Pattern characters */
3427 unsigned char tcn1; /* Name characters */
3428 int sawDot = 0, sawStar = 0, req8dot3 = 0;
3429 char *starNamep, *starMaskp;
3430 static char nullCharp[] = {0};
3431 int casefold = flags & CM_FLAG_CASEFOLD;
3433 /* make sure we only match 8.3 names, if requested */
3434 req8dot3 = (flags & CM_FLAG_8DOT3);
3435 if (req8dot3 && !cm_Is8Dot3(namep))
3440 /* Next pattern character */
3443 /* Next name character */
3447 /* 0 - end of pattern */
3453 else if (tcp1 == '.' || tcp1 == '"') {
3463 * first dot in pattern;
3464 * must match dot or end of name
3469 else if (tcn1 == '.') {
3478 else if (tcp1 == '?') {
3479 if (tcn1 == 0 || tcn1 == '.')
3484 else if (tcp1 == '>') {
3485 if (tcn1 != 0 && tcn1 != '.')
3489 else if (tcp1 == '*' || tcp1 == '<') {
3493 else if ((req8dot3 && tcp2 == '.') || tcp2 == '"') {
3494 while (req8dot3 && tcn1 != '.' && tcn1 != 0)
3509 * pattern character after '*' is not null or
3510 * period. If it is '?' or '>', we are not
3511 * going to understand it. If it is '*' or
3512 * '<', we are going to skip over it. None of
3513 * these are likely, I hope.
3515 /* skip over '*' and '<' */
3516 while (tcp2 == '*' || tcp2 == '<')
3519 /* skip over characters that don't match tcp2 */
3520 while (req8dot3 && tcn1 != '.' && tcn1 != 0 &&
3521 ((casefold && cm_foldUpper[tcn1] != cm_foldUpper[tcp2]) ||
3522 (!casefold && tcn1 != tcp2)))
3526 if ((req8dot3 && tcn1 == '.') || tcn1 == 0)
3529 /* Remember where we are */
3539 /* tcp1 is not a wildcard */
3540 if ((casefold && cm_foldUpper[tcn1] == cm_foldUpper[tcp1]) ||
3541 (!casefold && tcn1 == tcp1)) {
3546 /* if trying to match a star pattern, go back */
3548 maskp = starMaskp - 2;
3549 namep = starNamep + 1;
3558 #endif /* USE_OLD_MATCHING */
3560 long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
3569 smb_dirListPatch_t *dirListPatchesp;
3570 smb_dirListPatch_t *curPatchp;
3573 long orbytes; /* # of bytes in this output record */
3574 long ohbytes; /* # of bytes, except file name */
3575 long onbytes; /* # of bytes in name, incl. term. null */
3576 osi_hyper_t dirLength;
3577 osi_hyper_t bufferOffset;
3578 osi_hyper_t curOffset;
3580 smb_dirSearch_t *dsp;
3584 cm_pageHeader_t *pageHeaderp;
3585 cm_user_t *userp = NULL;
3588 long nextEntryCookie;
3589 int numDirChunks; /* # of 32 byte dir chunks in this entry */
3590 char *op; /* output data ptr */
3591 char *origOp; /* original value of op */
3592 cm_space_t *spacep; /* for pathname buffer */
3593 long maxReturnData; /* max # of return data */
3594 long maxReturnParms; /* max # of return parms */
3595 long bytesInBuffer; /* # data bytes in the output buffer */
3597 char *maskp; /* mask part of path */
3601 smb_tran2Packet_t *outp; /* response packet */
3604 char shortName[13]; /* 8.3 name if needed */
3615 if (p->opcode == 1) {
3616 /* find first; obtain basic parameters from request */
3617 attribute = p->parmsp[0];
3618 maxCount = p->parmsp[1];
3619 infoLevel = p->parmsp[3];
3620 searchFlags = p->parmsp[2];
3621 dsp = smb_NewDirSearch(1);
3622 dsp->attribute = attribute;
3623 pathp = ((char *) p->parmsp) + 12; /* points to path */
3624 if (smb_StoreAnsiFilenames)
3625 OemToChar(pathp,pathp);
3627 maskp = strrchr(pathp, '\\');
3631 maskp++; /* skip over backslash */
3632 strcpy(dsp->mask, maskp); /* and save mask */
3633 /* track if this is likely to match a lot of entries */
3634 starPattern = smb_V3IsStarMask(maskp);
3637 osi_assert(p->opcode == 2);
3638 /* find next; obtain basic parameters from request or open dir file */
3639 dsp = smb_FindDirSearch(p->parmsp[0]);
3641 return CM_ERROR_BADFD;
3642 attribute = dsp->attribute;
3643 maxCount = p->parmsp[1];
3644 infoLevel = p->parmsp[2];
3645 searchFlags = p->parmsp[5];
3647 nextCookie = p->parmsp[3] | (p->parmsp[4] << 16);
3649 starPattern = 1; /* assume, since required a Find Next */
3653 "T2 search dir attr 0x%x, info level %d, max count %d, flags 0x%x",
3654 attribute, infoLevel, maxCount, searchFlags);
3656 osi_Log2(smb_logp, "...T2 search op %d, nextCookie 0x%x",
3657 p->opcode, nextCookie);
3659 if (infoLevel >= 0x101)
3660 searchFlags &= ~4; /* no resume keys */
3662 dirListPatchesp = NULL;
3664 maxReturnData = p->maxReturnData;
3665 if (p->opcode == 1) /* find first */
3666 maxReturnParms = 10; /* bytes */
3668 maxReturnParms = 8; /* bytes */
3670 #ifndef CM_CONFIG_MULTITRAN2RESPONSES
3671 if (maxReturnData > 6000)
3672 maxReturnData = 6000;
3673 #endif /* CM_CONFIG_MULTITRAN2RESPONSES */
3675 outp = smb_GetTran2ResponsePacket(vcp, p, opx, maxReturnParms,
3678 osi_Log1(smb_logp, "T2 receive search dir %s",
3679 osi_LogSaveString(smb_logp, pathp));
3681 /* bail out if request looks bad */
3682 if (p->opcode == 1 && !pathp) {
3683 smb_ReleaseDirSearch(dsp);
3684 smb_FreeTran2Packet(outp);
3685 return CM_ERROR_BADSMB;
3688 osi_Log2(smb_logp, "T2 dir search cookie 0x%x, connection %d",
3689 nextCookie, dsp->cookie);
3691 userp = smb_GetTran2User(vcp, p);
3693 osi_Log1(smb_logp, "T2 dir search unable to resolve user [%d]", p->uid);
3694 smb_ReleaseDirSearch(dsp);
3695 smb_FreeTran2Packet(outp);
3696 return CM_ERROR_BADSMB;
3699 /* try to get the vnode for the path name next */
3700 lock_ObtainMutex(&dsp->mx);
3707 spacep = cm_GetSpace();
3708 smb_StripLastComponent(spacep->data, NULL, pathp);
3709 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
3711 lock_ReleaseMutex(&dsp->mx);
3712 cm_ReleaseUser(userp);
3713 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOFILES);
3714 smb_FreeTran2Packet(outp);
3715 smb_DeleteDirSearch(dsp);
3716 smb_ReleaseDirSearch(dsp);
3719 code = cm_NameI(cm_rootSCachep, spacep->data,
3720 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
3721 userp, tidPathp, &req, &scp);
3722 cm_FreeSpace(spacep);
3726 cm_ReleaseSCache(dsp->scp);
3728 /* we need one hold for the entry we just stored into,
3729 * and one for our own processing. When we're done
3730 * with this function, we'll drop the one for our own
3731 * processing. We held it once from the namei call,
3732 * and so we do another hold now.
3735 lock_ObtainMutex(&scp->mx);
3736 if ((scp->flags & CM_SCACHEFLAG_BULKSTATTING) == 0 &&
3737 LargeIntegerGreaterOrEqualToZero(scp->bulkStatProgress)) {
3738 scp->flags |= CM_SCACHEFLAG_BULKSTATTING;
3739 dsp->flags |= SMB_DIRSEARCH_BULKST;
3741 lock_ReleaseMutex(&scp->mx);
3744 lock_ReleaseMutex(&dsp->mx);
3746 cm_ReleaseUser(userp);
3747 smb_FreeTran2Packet(outp);
3748 smb_DeleteDirSearch(dsp);
3749 smb_ReleaseDirSearch(dsp);
3753 /* get the directory size */
3754 lock_ObtainMutex(&scp->mx);
3755 code = cm_SyncOp(scp, NULL, userp, &req, 0,
3756 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3758 lock_ReleaseMutex(&scp->mx);
3759 cm_ReleaseSCache(scp);
3760 cm_ReleaseUser(userp);
3761 smb_FreeTran2Packet(outp);
3762 smb_DeleteDirSearch(dsp);
3763 smb_ReleaseDirSearch(dsp);
3768 dirLength = scp->length;
3770 bufferOffset.LowPart = bufferOffset.HighPart = 0;
3771 curOffset.HighPart = 0;
3772 curOffset.LowPart = nextCookie;
3773 origOp = outp->datap;
3781 if (searchFlags & 4)
3782 /* skip over resume key */
3785 /* make sure that curOffset.LowPart doesn't point to the first
3786 * 32 bytes in the 2nd through last dir page, and that it doesn't
3787 * point at the first 13 32-byte chunks in the first dir page,
3788 * since those are dir and page headers, and don't contain useful
3791 temp = curOffset.LowPart & (2048-1);
3792 if (curOffset.HighPart == 0 && curOffset.LowPart < 2048) {
3793 /* we're in the first page */
3794 if (temp < 13*32) temp = 13*32;
3797 /* we're in a later dir page */
3798 if (temp < 32) temp = 32;
3801 /* make sure the low order 5 bits are zero */
3804 /* now put temp bits back ito curOffset.LowPart */
3805 curOffset.LowPart &= ~(2048-1);
3806 curOffset.LowPart |= temp;
3808 /* check if we've passed the dir's EOF */
3809 if (LargeIntegerGreaterThanOrEqualTo(curOffset, dirLength)) {
3814 /* check if we've returned all the names that will fit in the
3815 * response packet; we check return count as well as the number
3816 * of bytes requested. We check the # of bytes after we find
3817 * the dir entry, since we'll need to check its size.
3819 if (returnedNames >= maxCount) {
3823 /* see if we can use the bufferp we have now; compute in which
3824 * page the current offset would be, and check whether that's
3825 * the offset of the buffer we have. If not, get the buffer.
3827 thyper.HighPart = curOffset.HighPart;
3828 thyper.LowPart = curOffset.LowPart & ~(buf_bufferSize-1);
3829 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
3832 buf_Release(bufferp);
3835 lock_ReleaseMutex(&scp->mx);
3836 lock_ObtainRead(&scp->bufCreateLock);
3837 code = buf_Get(scp, &thyper, &bufferp);
3838 lock_ReleaseRead(&scp->bufCreateLock);
3839 lock_ObtainMutex(&dsp->mx);
3841 /* now, if we're doing a star match, do bulk fetching
3842 * of all of the status info for files in the dir.
3845 smb_ApplyV3DirListPatches(scp, &dirListPatchesp,
3848 lock_ObtainMutex(&scp->mx);
3849 if ((dsp->flags & SMB_DIRSEARCH_BULKST) &&
3850 LargeIntegerGreaterThanOrEqualTo(thyper, scp->bulkStatProgress)) {
3851 /* Don't bulk stat if risking timeout */
3852 int now = GetCurrentTime();
3853 if (now - req.startTime > 5000) {
3854 scp->bulkStatProgress = thyper;
3855 scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
3856 dsp->flags &= ~SMB_DIRSEARCH_BULKST;
3858 cm_TryBulkStat(scp, &thyper, userp, &req);
3861 lock_ObtainMutex(&scp->mx);
3863 lock_ReleaseMutex(&dsp->mx);
3867 bufferOffset = thyper;
3869 /* now get the data in the cache */
3871 code = cm_SyncOp(scp, bufferp, userp, &req,
3873 CM_SCACHESYNC_NEEDCALLBACK
3874 | CM_SCACHESYNC_READ);
3877 if (cm_HaveBuffer(scp, bufferp, 0)) break;
3879 /* otherwise, load the buffer and try again */
3880 code = cm_GetBuffer(scp, bufferp, NULL, userp,
3885 buf_Release(bufferp);
3889 } /* if (wrong buffer) ... */
3891 /* now we have the buffer containing the entry we're interested
3892 * in; copy it out if it represents a non-deleted entry.
3894 entryInDir = curOffset.LowPart & (2048-1);
3895 entryInBuffer = curOffset.LowPart & (buf_bufferSize - 1);
3897 /* page header will help tell us which entries are free. Page
3898 * header can change more often than once per buffer, since
3899 * AFS 3 dir page size may be less than (but not more than)
3900 * a buffer package buffer.
3902 /* only look intra-buffer */
3903 temp = curOffset.LowPart & (buf_bufferSize - 1);
3904 temp &= ~(2048 - 1); /* turn off intra-page bits */
3905 pageHeaderp = (cm_pageHeader_t *) (bufferp->datap + temp);
3907 /* now determine which entry we're looking at in the page.
3908 * If it is free (there's a free bitmap at the start of the
3909 * dir), we should skip these 32 bytes.
3911 slotInPage = (entryInDir & 0x7e0) >> 5;
3912 if (!(pageHeaderp->freeBitmap[slotInPage>>3] &
3913 (1 << (slotInPage & 0x7)))) {
3914 /* this entry is free */
3915 numDirChunks = 1; /* only skip this guy */
3919 tp = bufferp->datap + entryInBuffer;
3920 dep = (cm_dirEntry_t *) tp; /* now points to AFS3 dir entry */
3922 /* while we're here, compute the next entry's location, too,
3923 * since we'll need it when writing out the cookie into the dir
3926 * XXXX Probably should do more sanity checking.
3928 numDirChunks = cm_NameEntries(dep->name, &onbytes);
3930 /* compute offset of cookie representing next entry */
3931 nextEntryCookie = curOffset.LowPart + (CM_DIR_CHUNKSIZE * numDirChunks);
3933 /* Need 8.3 name? */
3935 if (infoLevel == SMB_QUERY_FILE_NAME_INFO
3936 && dep->fid.vnode != 0
3937 && !cm_Is8Dot3(dep->name)) {
3938 cm_Gen8Dot3Name(dep, shortName, &shortNameEnd);
3942 /* When matching, we are using doing a case fold if we have a wildcard mask.
3943 * If we get a non-wildcard match, it's a lookup for a specific file.
3945 if (dep->fid.vnode != 0 &&
3946 (smb_V3MatchMask(dep->name, maskp, (starPattern? CM_FLAG_CASEFOLD : 0)) ||
3948 smb_V3MatchMask(shortName, maskp, CM_FLAG_CASEFOLD)))) {
3950 /* Eliminate entries that don't match requested attributes */
3951 if (smb_hideDotFiles && !(dsp->attribute & SMB_ATTR_HIDDEN) &&
3952 smb_IsDotFile(dep->name))
3953 goto nextEntry; /* no hidden files */
3955 if (!(dsp->attribute & SMB_ATTR_DIRECTORY)) /* no directories */
3957 /* We have already done the cm_TryBulkStat above */
3958 fid.cell = scp->fid.cell;
3959 fid.volume = scp->fid.volume;
3960 fid.vnode = ntohl(dep->fid.vnode);
3961 fid.unique = ntohl(dep->fid.unique);
3962 fileType = cm_FindFileType(&fid);
3963 /*osi_Log2(smb_logp, "smb_ReceiveTran2SearchDir: file %s "
3964 "has filetype %d", dep->name,
3966 if (fileType == CM_SCACHETYPE_DIRECTORY)
3970 /* finally check if this name will fit */
3972 /* standard dir entry stuff */
3973 if (infoLevel < 0x101)
3974 ohbytes = 23; /* pre-NT */
3975 else if (infoLevel == SMB_QUERY_FILE_EA_INFO)
3976 ohbytes = 12; /* NT names only */
3978 ohbytes = 64; /* NT */
3980 if (infoLevel == SMB_QUERY_FILE_NAME_INFO)
3981 ohbytes += 26; /* Short name & length */
3983 if (searchFlags & 4) {
3984 ohbytes += 4; /* if resume key required */
3988 && infoLevel != 0x101
3989 && infoLevel != 0x103)
3990 ohbytes += 4; /* EASIZE */
3992 /* add header to name & term. null */
3993 orbytes = onbytes + ohbytes + 1;
3995 /* now, we round up the record to a 4 byte alignment,
3996 * and we make sure that we have enough room here for
3997 * even the aligned version (so we don't have to worry
3998 * about an * overflow when we pad things out below).
3999 * That's the reason for the alignment arithmetic below.
4001 if (infoLevel >= 0x101)
4002 align = (4 - (orbytes & 3)) & 3;
4005 if (orbytes + bytesInBuffer + align > maxReturnData)
4008 /* this is one of the entries to use: it is not deleted
4009 * and it matches the star pattern we're looking for.
4010 * Put out the name, preceded by its length.
4012 /* First zero everything else */
4013 memset(origOp, 0, ohbytes);
4015 if (infoLevel <= 0x101)
4016 *(origOp + ohbytes - 1) = (unsigned char) onbytes;
4017 else if (infoLevel == SMB_QUERY_FILE_EA_INFO)
4018 *((u_long *)(op + 8)) = onbytes;
4020 *((u_long *)(op + 60)) = onbytes;
4021 strcpy(origOp+ohbytes, dep->name);
4022 if (smb_StoreAnsiFilenames)
4023 CharToOem(origOp+ohbytes, origOp+ohbytes);
4025 /* Short name if requested and needed */
4026 if (infoLevel == SMB_QUERY_FILE_NAME_INFO) {
4027 if (NeedShortName) {
4028 strcpy(op + 70, shortName);
4029 if (smb_StoreAnsiFilenames)
4030 CharToOem(op + 70, op + 70);
4031 *(op + 68) = shortNameEnd - shortName;
4035 /* now, adjust the # of entries copied */
4038 /* NextEntryOffset and FileIndex */
4039 if (infoLevel >= 101) {
4040 int entryOffset = orbytes + align;
4041 *((u_long *)op) = entryOffset;
4042 *((u_long *)(op+4)) = nextEntryCookie;
4045 /* now we emit the attribute. This is tricky, since
4046 * we need to really stat the file to find out what
4047 * type of entry we've got. Right now, we're copying
4048 * out data from a buffer, while holding the scp
4049 * locked, so it isn't really convenient to stat
4050 * something now. We'll put in a place holder
4051 * now, and make a second pass before returning this
4052 * to get the real attributes. So, we just skip the
4053 * data for now, and adjust it later. We allocate a
4054 * patch record to make it easy to find this point
4055 * later. The replay will happen at a time when it is
4056 * safe to unlock the directory.
4058 if (infoLevel != 0x103) {
4059 curPatchp = malloc(sizeof(*curPatchp));
4060 osi_QAdd((osi_queue_t **) &dirListPatchesp,
4062 curPatchp->dptr = op;
4063 if (infoLevel >= 0x101)
4064 curPatchp->dptr += 8;
4066 if (smb_hideDotFiles && smb_IsDotFile(dep->name)) {
4067 curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
4070 curPatchp->flags = 0;
4072 curPatchp->fid.cell = scp->fid.cell;
4073 curPatchp->fid.volume = scp->fid.volume;
4074 curPatchp->fid.vnode = ntohl(dep->fid.vnode);
4075 curPatchp->fid.unique = ntohl(dep->fid.unique);
4078 curPatchp->dep = dep;
4081 if (searchFlags & 4)
4082 /* put out resume key */
4083 *((u_long *)origOp) = nextEntryCookie;
4085 /* Adjust byte ptr and count */
4086 origOp += orbytes; /* skip entire record */
4087 bytesInBuffer += orbytes;
4089 /* and pad the record out */
4090 while (--align >= 0) {
4094 } /* if we're including this name */
4095 else if (!NeedShortName &&
4098 dep->fid.vnode != 0 &&
4099 smb_V3MatchMask(dep->name, maskp, CM_FLAG_CASEFOLD)) {
4100 /* We were looking for exact matches, but here's an inexact one*/
4105 /* and adjust curOffset to be where the new cookie is */
4106 thyper.HighPart = 0;
4107 thyper.LowPart = CM_DIR_CHUNKSIZE * numDirChunks;
4108 curOffset = LargeIntegerAdd(thyper, curOffset);
4109 } /* while copying data for dir listing */
4111 /* If we didn't get a star pattern, we did an exact match during the first pass.
4112 * If there were no exact matches found, we fail over to inexact matches by
4113 * marking the query as a star pattern (matches all case permutations), and
4114 * re-running the query.
4116 if (returnedNames == 0 && !starPattern && foundInexact) {
4117 osi_Log0(afsd_logp,"T2 Search: No exact matches. Re-running for inexact matches");
4122 /* release the mutex */
4123 lock_ReleaseMutex(&scp->mx);
4124 if (bufferp) buf_Release(bufferp);
4126 /* apply and free last set of patches; if not doing a star match, this
4127 * will be empty, but better safe (and freeing everything) than sorry.
4129 smb_ApplyV3DirListPatches(scp, &dirListPatchesp, infoLevel, userp,
4132 /* now put out the final parameters */
4133 if (returnedNames == 0) eos = 1;
4134 if (p->opcode == 1) {
4136 outp->parmsp[0] = (unsigned short) dsp->cookie;
4137 outp->parmsp[1] = returnedNames;
4138 outp->parmsp[2] = eos;
4139 outp->parmsp[3] = 0; /* nothing wrong with EAS */
4140 outp->parmsp[4] = 0;
4141 /* don't need last name to continue
4142 * search, cookie is enough. Normally,
4143 * this is the offset of the file name
4144 * of the last entry returned.
4146 outp->totalParms = 10; /* in bytes */
4150 outp->parmsp[0] = returnedNames;
4151 outp->parmsp[1] = eos;
4152 outp->parmsp[2] = 0; /* EAS error */
4153 outp->parmsp[3] = 0; /* last name, as above */
4154 outp->totalParms = 8; /* in bytes */
4157 /* return # of bytes in the buffer */
4158 outp->totalData = bytesInBuffer;
4160 osi_Log2(smb_logp, "T2 search dir done, %d names, code %d",
4161 returnedNames, code);
4163 /* Return error code if unsuccessful on first request */
4164 if (code == 0 && p->opcode == 1 && returnedNames == 0)
4165 code = CM_ERROR_NOSUCHFILE;
4167 /* if we're supposed to close the search after this request, or if
4168 * we're supposed to close the search if we're done, and we're done,
4169 * or if something went wrong, close the search.
4171 /* ((searchFlags & 1) || ((searchFlags & 2) && eos) */
4172 if ((searchFlags & 1) || (returnedNames == 0) ||
4173 ((searchFlags & 2) && eos) || code != 0)
4174 smb_DeleteDirSearch(dsp);
4176 smb_SendTran2Error(vcp, p, opx, code);
4178 smb_SendTran2Packet(vcp, outp, opx);
4180 smb_FreeTran2Packet(outp);
4181 smb_ReleaseDirSearch(dsp);
4182 cm_ReleaseSCache(scp);
4183 cm_ReleaseUser(userp);
4187 long smb_ReceiveV3FindClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4190 smb_dirSearch_t *dsp;
4192 dirHandle = smb_GetSMBParm(inp, 0);
4194 osi_Log1(smb_logp, "SMB3 find close handle %d", dirHandle);
4196 dsp = smb_FindDirSearch(dirHandle);
4199 return CM_ERROR_BADFD;
4201 /* otherwise, we have an FD to destroy */
4202 smb_DeleteDirSearch(dsp);
4203 smb_ReleaseDirSearch(dsp);
4205 /* and return results */
4206 smb_SetSMBDataLength(outp, 0);
4211 long smb_ReceiveV3FindNotifyClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4213 smb_SetSMBDataLength(outp, 0);
4217 long smb_ReceiveV3OpenX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4224 cm_scache_t *dscp; /* dir we're dealing with */
4225 cm_scache_t *scp; /* file we're creating */
4227 int initialModeBits;
4237 int parmSlot; /* which parm we're dealing with */
4245 extraInfo = (smb_GetSMBParm(inp, 2) & 1); /* return extra info */
4246 openFun = smb_GetSMBParm(inp, 8); /* open function */
4247 excl = ((openFun & 3) == 0);
4248 trunc = ((openFun & 3) == 2); /* truncate it */
4249 openMode = (smb_GetSMBParm(inp, 3) & 0x7);
4250 openAction = 0; /* tracks what we did */
4252 attributes = smb_GetSMBParm(inp, 5);
4253 dosTime = smb_GetSMBParm(inp, 6) | (smb_GetSMBParm(inp, 7) << 16);
4255 /* compute initial mode bits based on read-only flag in attributes */
4256 initialModeBits = 0666;
4257 if (attributes & 1) initialModeBits &= ~0222;
4259 pathp = smb_GetSMBData(inp, NULL);
4260 if (smb_StoreAnsiFilenames)
4261 OemToChar(pathp,pathp);
4263 spacep = inp->spacep;
4264 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
4266 if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
4267 /* special case magic file name for receiving IOCTL requests
4268 * (since IOCTL calls themselves aren't getting through).
4271 osi_Log0(smb_logp, "IOCTL Open");
4274 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
4275 smb_SetupIoctlFid(fidp, spacep);
4277 /* set inp->fid so that later read calls in same msg can find fid */
4278 inp->fid = fidp->fid;
4280 /* copy out remainder of the parms */
4282 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
4284 smb_SetSMBParm(outp, parmSlot, /* attrs */ 0); parmSlot++;
4285 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* mod time */
4286 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
4287 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* len */
4288 smb_SetSMBParm(outp, parmSlot, 0x7fff); parmSlot++;
4289 smb_SetSMBParm(outp, parmSlot, openMode); parmSlot++;
4290 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* file type 0 ==> normal file or dir */
4291 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* IPC junk */
4293 /* and the final "always present" stuff */
4294 smb_SetSMBParm(outp, parmSlot, /* openAction found existing file */ 1); parmSlot++;
4295 /* next write out the "unique" ID */
4296 smb_SetSMBParm(outp, parmSlot, 0x1234); parmSlot++;
4297 smb_SetSMBParm(outp, parmSlot, 0x5678); parmSlot++;
4298 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
4299 smb_SetSMBDataLength(outp, 0);
4301 /* and clean up fid reference */
4302 smb_ReleaseFID(fidp);
4306 #ifdef DEBUG_VERBOSE
4308 char *hexp, *asciip;
4309 asciip = (lastNamep ? lastNamep : pathp );
4310 hexp = osi_HexifyString(asciip);
4311 DEBUG_EVENT2("AFS", "V3Open H[%s] A[%s]", hexp, asciip );
4315 userp = smb_GetUser(vcp, inp);
4318 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4320 cm_ReleaseUser(userp);
4321 return CM_ERROR_NOSUCHPATH;
4323 code = cm_NameI(cm_rootSCachep, pathp,
4324 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
4325 userp, tidPathp, &req, &scp);
4327 code = cm_NameI(cm_rootSCachep, spacep->data,
4328 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
4329 userp, tidPathp, &req, &dscp);
4332 cm_ReleaseUser(userp);
4336 /* otherwise, scp points to the parent directory. Do a lookup,
4337 * and truncate the file if we find it, otherwise we create the
4340 if (!lastNamep) lastNamep = pathp;
4342 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD, userp,
4344 if (code && code != CM_ERROR_NOSUCHFILE) {
4345 cm_ReleaseSCache(dscp);
4346 cm_ReleaseUser(userp);
4351 /* if we get here, if code is 0, the file exists and is represented by
4352 * scp. Otherwise, we have to create it. The dir may be represented
4353 * by dscp, or we may have found the file directly. If code is non-zero,
4357 code = cm_CheckOpen(scp, openMode, trunc, userp, &req);
4359 if (dscp) cm_ReleaseSCache(dscp);
4360 cm_ReleaseSCache(scp);
4361 cm_ReleaseUser(userp);
4366 /* oops, file shouldn't be there */
4367 if (dscp) cm_ReleaseSCache(dscp);
4368 cm_ReleaseSCache(scp);
4369 cm_ReleaseUser(userp);
4370 return CM_ERROR_EXISTS;
4374 setAttr.mask = CM_ATTRMASK_LENGTH;
4375 setAttr.length.LowPart = 0;
4376 setAttr.length.HighPart = 0;
4377 code = cm_SetAttr(scp, &setAttr, userp, &req);
4378 openAction = 3; /* truncated existing file */
4380 else openAction = 1; /* found existing file */
4382 else if (!(openFun & 0x10)) {
4383 /* don't create if not found */
4384 if (dscp) cm_ReleaseSCache(dscp);
4385 cm_ReleaseUser(userp);
4386 return CM_ERROR_NOSUCHFILE;
4389 osi_assert(dscp != NULL);
4390 osi_Log1(smb_logp, "smb_ReceiveV3OpenX creating file %s",
4391 osi_LogSaveString(smb_logp, lastNamep));
4392 openAction = 2; /* created file */
4393 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
4394 smb_UnixTimeFromDosUTime(&setAttr.clientModTime, dosTime);
4395 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
4397 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
4398 smb_NotifyChange(FILE_ACTION_ADDED,
4399 FILE_NOTIFY_CHANGE_FILE_NAME,
4400 dscp, lastNamep, NULL, TRUE);
4401 if (!excl && code == CM_ERROR_EXISTS) {
4402 /* not an exclusive create, and someone else tried
4403 * creating it already, then we open it anyway. We
4404 * don't bother retrying after this, since if this next
4405 * fails, that means that the file was deleted after we
4406 * started this call.
4408 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
4412 setAttr.mask = CM_ATTRMASK_LENGTH;
4413 setAttr.length.LowPart = 0;
4414 setAttr.length.HighPart = 0;
4415 code = cm_SetAttr(scp, &setAttr, userp, &req);
4417 } /* lookup succeeded */
4421 /* we don't need this any longer */
4422 if (dscp) cm_ReleaseSCache(dscp);
4425 /* something went wrong creating or truncating the file */
4426 if (scp) cm_ReleaseSCache(scp);
4427 cm_ReleaseUser(userp);
4431 /* make sure we're about to open a file */
4432 if (scp->fileType != CM_SCACHETYPE_FILE) {
4433 cm_ReleaseSCache(scp);
4434 cm_ReleaseUser(userp);
4435 return CM_ERROR_ISDIR;
4438 /* now all we have to do is open the file itself */
4439 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
4442 /* save a pointer to the vnode */
4445 /* compute open mode */
4446 if (openMode != 1) fidp->flags |= SMB_FID_OPENREAD;
4447 if (openMode == 1 || openMode == 2)
4448 fidp->flags |= SMB_FID_OPENWRITE;
4450 smb_ReleaseFID(fidp);
4452 cm_Open(scp, 0, userp);
4454 /* set inp->fid so that later read calls in same msg can find fid */
4455 inp->fid = fidp->fid;
4457 /* copy out remainder of the parms */
4459 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
4460 lock_ObtainMutex(&scp->mx);
4462 smb_SetSMBParm(outp, parmSlot, smb_Attributes(scp)); parmSlot++;
4463 smb_DosUTimeFromUnixTime(&dosTime, scp->clientModTime);
4464 smb_SetSMBParm(outp, parmSlot, dosTime & 0xffff); parmSlot++;
4465 smb_SetSMBParm(outp, parmSlot, (dosTime>>16) & 0xffff); parmSlot++;
4466 smb_SetSMBParm(outp, parmSlot, scp->length.LowPart & 0xffff); parmSlot++;
4467 smb_SetSMBParm(outp, parmSlot, (scp->length.LowPart >> 16) & 0xffff); parmSlot++;
4468 smb_SetSMBParm(outp, parmSlot, openMode); parmSlot++;
4469 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* file type 0 ==> normal file or dir */
4470 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* IPC junk */
4472 /* and the final "always present" stuff */
4473 smb_SetSMBParm(outp, parmSlot, openAction); parmSlot++;
4474 /* next write out the "unique" ID */
4475 smb_SetSMBParm(outp, parmSlot, scp->fid.vnode & 0xffff); parmSlot++;
4476 smb_SetSMBParm(outp, parmSlot, scp->fid.volume & 0xffff); parmSlot++;
4477 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
4478 lock_ReleaseMutex(&scp->mx);
4479 smb_SetSMBDataLength(outp, 0);
4481 osi_Log1(smb_logp, "SMB OpenX opening fid %d", fidp->fid);
4483 cm_ReleaseUser(userp);
4484 /* leave scp held since we put it in fidp->scp */
4488 long smb_ReceiveV3LockingX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4495 unsigned char LockType;
4496 unsigned short NumberOfUnlocks, NumberOfLocks;
4497 unsigned long Timeout;
4499 LARGE_INTEGER LOffset, LLength;
4500 smb_waitingLock_t *waitingLock;
4507 fid = smb_GetSMBParm(inp, 2);
4508 fid = smb_ChainFID(fid, inp);
4510 fidp = smb_FindFID(vcp, fid, 0);
4511 if (!fidp || (fidp->flags & SMB_FID_IOCTL)) {
4512 return CM_ERROR_BADFD;
4514 /* set inp->fid so that later read calls in same msg can find fid */
4517 userp = smb_GetUser(vcp, inp);
4521 lock_ObtainMutex(&scp->mx);
4522 code = cm_SyncOp(scp, NULL, userp, &req, 0,
4523 CM_SCACHESYNC_NEEDCALLBACK
4524 | CM_SCACHESYNC_GETSTATUS
4525 | CM_SCACHESYNC_LOCK);
4526 if (code) goto doneSync;
4528 LockType = smb_GetSMBParm(inp, 3) & 0xff;
4529 Timeout = (smb_GetSMBParm(inp, 5) << 16) + smb_GetSMBParm(inp, 4);
4530 NumberOfUnlocks = smb_GetSMBParm(inp, 6);
4531 NumberOfLocks = smb_GetSMBParm(inp, 7);
4533 op = smb_GetSMBData(inp, NULL);
4535 for (i=0; i<NumberOfUnlocks; i++) {
4536 if (LockType & 0x10) {
4538 LOffset.HighPart = *((LONG *)(op + 4));
4539 LOffset.LowPart = *((DWORD *)(op + 8));
4540 LLength.HighPart = *((LONG *)(op + 12));
4541 LLength.LowPart = *((DWORD *)(op + 16));
4545 /* Not Large Files */
4546 LOffset.HighPart = 0;
4547 LOffset.LowPart = *((DWORD *)(op + 2));
4548 LLength.HighPart = 0;
4549 LLength.LowPart = *((DWORD *)(op + 6));
4552 if (LargeIntegerNotEqualToZero(LOffset))
4554 /* Do not check length -- length check done in cm_Unlock */
4556 code = cm_Unlock(scp, LockType, LOffset, LLength, userp, &req);
4557 if (code) goto done;
4560 for (i=0; i<NumberOfLocks; i++) {
4561 if (LockType & 0x10) {
4563 LOffset.HighPart = *((LONG *)(op + 4));
4564 LOffset.LowPart = *((DWORD *)(op + 8));
4565 LLength.HighPart = *((LONG *)(op + 12));
4566 LLength.LowPart = *((DWORD *)(op + 16));
4570 /* Not Large Files */
4571 LOffset.HighPart = 0;
4572 LOffset.LowPart = *((DWORD *)(op + 2));
4573 LLength.HighPart = 0;
4574 LLength.LowPart = *((DWORD *)(op + 6));
4577 if (LargeIntegerNotEqualToZero(LOffset))
4579 if (LargeIntegerLessThan(LOffset, scp->length))
4582 code = cm_Lock(scp, LockType, LOffset, LLength, Timeout,
4583 userp, &req, &lockp);
4584 if (code == CM_ERROR_WOULDBLOCK && Timeout != 0) {
4585 /* Put on waiting list */
4586 waitingLock = malloc(sizeof(smb_waitingLock_t));
4587 waitingLock->vcp = vcp;
4588 waitingLock->inp = smb_CopyPacket(inp);
4589 waitingLock->outp = smb_CopyPacket(outp);
4590 waitingLock->timeRemaining = Timeout;
4591 waitingLock->lockp = lockp;
4592 lock_ObtainWrite(&smb_globalLock);
4593 osi_QAdd((osi_queue_t **)&smb_allWaitingLocks,
4595 osi_Wakeup((long) &smb_allWaitingLocks);
4596 lock_ReleaseWrite(&smb_globalLock);
4597 /* don't send reply immediately */
4598 outp->flags |= SMB_PACKETFLAG_NOSEND;
4604 /* release any locks acquired before the failure */
4607 smb_SetSMBDataLength(outp, 0);
4609 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_LOCK);
4611 lock_ReleaseMutex(&scp->mx);
4612 cm_ReleaseUser(userp);
4613 smb_ReleaseFID(fidp);
4618 long smb_ReceiveV3GetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4630 fid = smb_GetSMBParm(inp, 0);
4631 fid = smb_ChainFID(fid, inp);
4633 fidp = smb_FindFID(vcp, fid, 0);
4634 if (!fidp || (fidp->flags & SMB_FID_IOCTL)) {
4635 return CM_ERROR_BADFD;
4638 userp = smb_GetUser(vcp, inp);
4642 /* otherwise, stat the file */
4643 lock_ObtainMutex(&scp->mx);
4644 code = cm_SyncOp(scp, NULL, userp, &req, 0,
4645 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4646 if (code) goto done;
4648 /* decode times. We need a search time, but the response to this
4649 * call provides the date first, not the time, as returned in the
4650 * searchTime variable. So we take the high-order bits first.
4652 smb_SearchTimeFromUnixTime(&searchTime, scp->clientModTime);
4653 smb_SetSMBParm(outp, 0, (searchTime >> 16) & 0xffff); /* ctime */
4654 smb_SetSMBParm(outp, 1, searchTime & 0xffff);
4655 smb_SetSMBParm(outp, 2, (searchTime >> 16) & 0xffff); /* atime */
4656 smb_SetSMBParm(outp, 3, searchTime & 0xffff);
4657 smb_SetSMBParm(outp, 4, (searchTime >> 16) & 0xffff); /* mtime */
4658 smb_SetSMBParm(outp, 5, searchTime & 0xffff);
4660 /* now handle file size and allocation size */
4661 smb_SetSMBParm(outp, 6, scp->length.LowPart & 0xffff); /* file size */
4662 smb_SetSMBParm(outp, 7, (scp->length.LowPart >> 16) & 0xffff);
4663 smb_SetSMBParm(outp, 8, scp->length.LowPart & 0xffff); /* alloc size */
4664 smb_SetSMBParm(outp, 9, (scp->length.LowPart >> 16) & 0xffff);
4666 /* file attribute */
4667 smb_SetSMBParm(outp, 10, smb_Attributes(scp));
4669 /* and finalize stuff */
4670 smb_SetSMBDataLength(outp, 0);
4674 lock_ReleaseMutex(&scp->mx);
4675 cm_ReleaseUser(userp);
4676 smb_ReleaseFID(fidp);
4680 long smb_ReceiveV3SetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4694 fid = smb_GetSMBParm(inp, 0);
4695 fid = smb_ChainFID(fid, inp);
4697 fidp = smb_FindFID(vcp, fid, 0);
4698 if (!fidp || (fidp->flags & SMB_FID_IOCTL)) {
4699 return CM_ERROR_BADFD;
4702 userp = smb_GetUser(vcp, inp);
4706 /* now prepare to call cm_setattr. This message only sets various times,
4707 * and AFS only implements mtime, and we'll set the mtime if that's
4708 * requested. The others we'll ignore.
4710 searchTime = smb_GetSMBParm(inp, 5) | (smb_GetSMBParm(inp, 6) << 16);
4712 if (searchTime != 0) {
4713 smb_UnixTimeFromSearchTime(&unixTime, searchTime);
4715 if ( unixTime != -1 ) {
4716 attrs.mask = CM_ATTRMASK_CLIENTMODTIME;
4717 attrs.clientModTime = unixTime;
4718 code = cm_SetAttr(scp, &attrs, userp, &req);
4720 osi_Log1(smb_logp, "SMB receive V3SetAttributes [fid=%ld]", fid);
4722 osi_Log1(smb_logp, "**smb_UnixTimeFromSearchTime failed searchTime=%ld", searchTime);
4727 cm_ReleaseUser(userp);
4728 smb_ReleaseFID(fidp);
4733 long smb_ReceiveV3ReadX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4736 long count, finalCount;
4743 fd = smb_GetSMBParm(inp, 2);
4744 count = smb_GetSMBParm(inp, 5);
4745 offset.HighPart = 0; /* too bad */
4746 offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
4748 osi_Log3(smb_logp, "smb_ReceiveV3Read fd %d, off 0x%x, size 0x%x",
4749 fd, offset.LowPart, count);
4751 fd = smb_ChainFID(fd, inp);
4752 fidp = smb_FindFID(vcp, fd, 0);
4754 return CM_ERROR_BADFD;
4756 /* set inp->fid so that later read calls in same msg can find fid */
4759 if (fidp->flags & SMB_FID_IOCTL) {
4760 return smb_IoctlV3Read(fidp, vcp, inp, outp);
4763 userp = smb_GetUser(vcp, inp);
4765 /* 0 and 1 are reserved for request chaining, were setup by our caller,
4766 * and will be further filled in after we return.
4768 smb_SetSMBParm(outp, 2, 0); /* remaining bytes, for pipes */
4769 smb_SetSMBParm(outp, 3, 0); /* resvd */
4770 smb_SetSMBParm(outp, 4, 0); /* resvd */
4771 smb_SetSMBParm(outp, 5, count); /* # of bytes we're going to read */
4772 /* fill in #6 when we have all the parameters' space reserved */
4773 smb_SetSMBParm(outp, 7, 0); /* resv'd */
4774 smb_SetSMBParm(outp, 8, 0); /* resv'd */
4775 smb_SetSMBParm(outp, 9, 0); /* resv'd */
4776 smb_SetSMBParm(outp, 10, 0); /* resv'd */
4777 smb_SetSMBParm(outp, 11, 0); /* reserved */
4779 /* get op ptr after putting in the parms, since otherwise we don't
4780 * know where the data really is.
4782 op = smb_GetSMBData(outp, NULL);
4784 /* now fill in offset from start of SMB header to first data byte (to op) */
4785 smb_SetSMBParm(outp, 6, ((int) (op - outp->data)));
4787 /* set the packet data length the count of the # of bytes */
4788 smb_SetSMBDataLength(outp, count);
4791 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount);
4793 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount, FALSE);
4796 /* fix some things up */
4797 smb_SetSMBParm(outp, 5, finalCount);
4798 smb_SetSMBDataLength(outp, finalCount);
4800 smb_ReleaseFID(fidp);
4802 cm_ReleaseUser(userp);
4807 * Values for createDisp, copied from NTDDK.H
4809 #define FILE_SUPERSEDE 0 // (???)
4810 #define FILE_OPEN 1 // (open)
4811 #define FILE_CREATE 2 // (exclusive)
4812 #define FILE_OPEN_IF 3 // (non-exclusive)
4813 #define FILE_OVERWRITE 4 // (open & truncate, but do not create)
4814 #define FILE_OVERWRITE_IF 5 // (open & truncate, or create)
4816 long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4818 char *pathp, *realPathp;
4822 cm_scache_t *dscp; /* parent dir */
4823 cm_scache_t *scp; /* file to create or open */
4824 cm_scache_t *targetScp; /* if scp is a symlink */
4828 unsigned short nameLength;
4830 unsigned int requestOpLock;
4831 unsigned int requestBatchOpLock;
4832 unsigned int mustBeDir;
4833 unsigned int treeCreate;
4835 unsigned int desiredAccess;
4836 unsigned int extAttributes;
4837 unsigned int createDisp;
4838 unsigned int createOptions;
4839 int initialModeBits;
4840 unsigned short baseFid;
4841 smb_fid_t *baseFidp;
4843 cm_scache_t *baseDirp;
4844 unsigned short openAction;
4859 nameLength = smb_GetSMBOffsetParm(inp, 2, 1);
4860 flags = smb_GetSMBOffsetParm(inp, 3, 1)
4861 | (smb_GetSMBOffsetParm(inp, 4, 1) << 16);
4862 requestOpLock = flags & 0x02;
4863 requestBatchOpLock = flags & 0x04;
4864 mustBeDir = flags & 0x08;
4867 * Why all of a sudden 32-bit FID?
4868 * We will reject all bits higher than 16.
4870 if (smb_GetSMBOffsetParm(inp, 6, 1) != 0)
4871 return CM_ERROR_INVAL;
4872 baseFid = smb_GetSMBOffsetParm(inp, 5, 1);
4873 desiredAccess = smb_GetSMBOffsetParm(inp, 7, 1)
4874 | (smb_GetSMBOffsetParm(inp, 8, 1) << 16);
4875 extAttributes = smb_GetSMBOffsetParm(inp, 13, 1)
4876 | (smb_GetSMBOffsetParm(inp, 14, 1) << 16);
4877 createDisp = smb_GetSMBOffsetParm(inp, 17, 1)
4878 | (smb_GetSMBOffsetParm(inp, 18, 1) << 16);
4879 createOptions = smb_GetSMBOffsetParm(inp, 19, 1)
4880 | (smb_GetSMBOffsetParm(inp, 20, 1) << 16);
4882 /* mustBeDir is never set; createOptions directory bit seems to be
4885 if (createOptions & 1)
4887 else if (createOptions & 0x40)
4893 * compute initial mode bits based on read-only flag in
4894 * extended attributes
4896 initialModeBits = 0666;
4897 if (extAttributes & 1)
4898 initialModeBits &= ~0222;
4900 pathp = smb_GetSMBData(inp, NULL);
4901 /* Sometimes path is not null-terminated, so we make a copy. */
4902 realPathp = malloc(nameLength+1);
4903 memcpy(realPathp, pathp, nameLength);
4904 realPathp[nameLength] = 0;
4905 if (smb_StoreAnsiFilenames)
4906 OemToChar(realPathp,realPathp);
4908 spacep = inp->spacep;
4909 smb_StripLastComponent(spacep->data, &lastNamep, realPathp);
4911 osi_Log1(smb_logp,"NTCreateX for [%s]",osi_LogSaveString(smb_logp,realPathp));
4912 osi_Log4(smb_logp,"... da=[%x] ea=[%x] cd=[%x] co=[%x]", desiredAccess, extAttributes, createDisp, createOptions);
4913 osi_Log2(smb_logp,"... flags=[%x] lastNamep=[%s]", flags, osi_LogSaveString(smb_logp,(lastNamep?lastNamep:"null")));
4915 if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
4916 /* special case magic file name for receiving IOCTL requests
4917 * (since IOCTL calls themselves aren't getting through).
4919 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
4920 smb_SetupIoctlFid(fidp, spacep);
4921 osi_Log1(smb_logp,"NTCreateX Setting up IOCTL on fid[%d]",fidp->fid);
4923 /* set inp->fid so that later read calls in same msg can find fid */
4924 inp->fid = fidp->fid;
4928 smb_SetSMBParmByte(outp, parmSlot, 0); /* oplock */
4929 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
4930 smb_SetSMBParmLong(outp, parmSlot, 1); parmSlot += 2; /* Action */
4932 memset(&ft, 0, sizeof(ft));
4933 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
4934 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
4935 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
4936 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
4937 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2; /* attr */
4938 sz.HighPart = 0x7fff; sz.LowPart = 0;
4939 smb_SetSMBParmDouble(outp, parmSlot, (char *)&sz); parmSlot += 4; /* alen */
4940 smb_SetSMBParmDouble(outp, parmSlot, (char *)&sz); parmSlot += 4; /* len */
4941 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* filetype */
4942 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* dev state */
4943 smb_SetSMBParmByte(outp, parmSlot, 0); /* is a dir? */
4944 smb_SetSMBDataLength(outp, 0);
4946 /* clean up fid reference */
4947 smb_ReleaseFID(fidp);
4952 #ifdef DEBUG_VERBOSE
4954 char *hexp, *asciip;
4955 asciip = (lastNamep? lastNamep : realPathp);
4956 hexp = osi_HexifyString( asciip );
4957 DEBUG_EVENT2("AFS", "NTCreateX H[%s] A[%s]", hexp, asciip);
4961 userp = smb_GetUser(vcp, inp);
4963 osi_Log1(smb_logp, "NTCreateX Invalid user [%d]", ((smb_t *) inp)->uid);
4965 return CM_ERROR_INVAL;
4969 baseDirp = cm_rootSCachep;
4970 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4971 if (code == CM_ERROR_TIDIPC) {
4972 /* Attempt to use a TID allocated for IPC. The client
4973 * is probably looking for DCE RPC end points which we
4975 osi_Log0(smb_logp, "NTCreateX received IPC TID");
4977 cm_ReleaseUser(userp);
4978 return CM_ERROR_NOSUCHFILE;
4982 baseFidp = smb_FindFID(vcp, baseFid, 0);
4984 osi_Log1(smb_logp, "NTCreateX Invalid base fid [%d]", baseFid);
4986 cm_ReleaseUser(userp);
4987 return CM_ERROR_INVAL;
4989 baseDirp = baseFidp->scp;
4993 osi_Log1(smb_logp, "NTCreateX tidPathp=[%s]", (tidPathp==NULL)?"null": osi_LogSaveString(smb_logp,tidPathp));
4995 /* compute open mode */
4997 if (desiredAccess & DELETE)
4998 fidflags |= SMB_FID_OPENDELETE;
4999 if (desiredAccess & AFS_ACCESS_READ)
5000 fidflags |= SMB_FID_OPENREAD;
5001 if (desiredAccess & AFS_ACCESS_WRITE)
5002 fidflags |= SMB_FID_OPENWRITE;
5006 /* For an exclusive create, we want to do a case sensitive match for the last component. */
5007 if ( createDisp == FILE_CREATE ||
5008 createDisp == FILE_OVERWRITE ||
5009 createDisp == FILE_OVERWRITE_IF) {
5010 code = cm_NameI(baseDirp, spacep->data, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
5011 userp, tidPathp, &req, &dscp);
5013 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp, CM_FLAG_FOLLOW,
5015 if (code == CM_ERROR_NOSUCHFILE) {
5016 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp,
5017 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, &req, &scp);
5018 if (code == 0 && realDirFlag == 1) {
5019 cm_ReleaseSCache(scp);
5020 cm_ReleaseSCache(dscp);
5021 cm_ReleaseUser(userp);
5023 return CM_ERROR_EXISTS;
5029 code = cm_NameI(baseDirp, realPathp, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
5030 userp, tidPathp, &req, &scp);
5035 if (!foundscp || (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE))) {
5036 /* look up parent directory */
5037 /* If we are trying to create a path (i.e. multiple nested directories), then we don't *need*
5038 * the immediate parent. We have to work our way up realPathp until we hit something that we
5046 code = cm_NameI(baseDirp, spacep->data,
5047 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
5048 userp, tidPathp, &req, &dscp);
5051 (tp = strrchr(spacep->data,'\\')) &&
5052 (createDisp == FILE_CREATE) &&
5053 (realDirFlag == 1)) {
5056 treeStartp = realPathp + (tp - spacep->data);
5058 if (*tp && !smb_IsLegalFilename(tp)) {
5060 smb_ReleaseFID(baseFidp);
5061 cm_ReleaseUser(userp);
5063 return CM_ERROR_BADNTFILENAME;
5073 smb_ReleaseFID(baseFidp);
5076 osi_Log0(smb_logp,"NTCreateX parent not found");
5077 cm_ReleaseUser(userp);
5082 if (treeCreate && dscp->fileType == CM_SCACHETYPE_FILE) {
5083 /* A file exists where we want a directory. */
5084 cm_ReleaseSCache(dscp);
5085 cm_ReleaseUser(userp);
5087 return CM_ERROR_EXISTS;
5091 lastNamep = realPathp;
5095 if (!smb_IsLegalFilename(lastNamep)) {
5096 cm_ReleaseSCache(dscp);
5097 cm_ReleaseUser(userp);
5099 return CM_ERROR_BADNTFILENAME;
5102 if (!foundscp && !treeCreate) {
5103 if ( createDisp == FILE_CREATE ||
5104 createDisp == FILE_OVERWRITE ||
5105 createDisp == FILE_OVERWRITE_IF)
5107 code = cm_Lookup(dscp, lastNamep,
5108 CM_FLAG_FOLLOW, userp, &req, &scp);
5110 code = cm_Lookup(dscp, lastNamep,
5111 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
5114 if (code && code != CM_ERROR_NOSUCHFILE) {
5115 cm_ReleaseSCache(dscp);
5116 cm_ReleaseUser(userp);
5124 smb_ReleaseFID(baseFidp);
5127 /* if we get here, if code is 0, the file exists and is represented by
5128 * scp. Otherwise, we have to create it. The dir may be represented
5129 * by dscp, or we may have found the file directly. If code is non-zero,
5132 if (code == 0 && !treeCreate) {
5133 if (createDisp == FILE_CREATE) {
5134 /* oops, file shouldn't be there */
5135 if (dscp) cm_ReleaseSCache(dscp);
5136 cm_ReleaseSCache(scp);
5137 cm_ReleaseUser(userp);
5139 return CM_ERROR_EXISTS;
5142 if ( createDisp == FILE_OVERWRITE ||
5143 createDisp == FILE_OVERWRITE_IF) {
5144 setAttr.mask = CM_ATTRMASK_LENGTH;
5145 setAttr.length.LowPart = 0;
5146 setAttr.length.HighPart = 0;
5147 /* now watch for a symlink */
5149 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
5151 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
5153 /* we have a more accurate file to use (the
5154 * target of the symbolic link). Otherwise,
5155 * we'll just use the symlink anyway.
5157 osi_Log2(smb_logp, "symlink vp %x to vp %x",
5159 cm_ReleaseSCache(scp);
5163 code = cm_SetAttr(scp, &setAttr, userp, &req);
5164 openAction = 3; /* truncated existing file */
5167 openAction = 1; /* found existing file */
5169 code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp,
5172 if (dscp) cm_ReleaseSCache(dscp);
5173 cm_ReleaseSCache(scp);
5174 cm_ReleaseUser(userp);
5179 else if (createDisp == FILE_OPEN || createDisp == FILE_OVERWRITE) {
5180 /* don't create if not found */
5181 if (dscp) cm_ReleaseSCache(dscp);
5182 cm_ReleaseUser(userp);
5184 return CM_ERROR_NOSUCHFILE;
5186 else if (realDirFlag == 0 || realDirFlag == -1) {
5187 osi_assert(dscp != NULL);
5188 osi_Log1(smb_logp, "smb_ReceiveNTCreateX creating file %s",
5189 osi_LogSaveString(smb_logp, lastNamep));
5190 openAction = 2; /* created file */
5191 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
5192 setAttr.clientModTime = time(NULL);
5193 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
5195 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
5196 smb_NotifyChange(FILE_ACTION_ADDED,
5197 FILE_NOTIFY_CHANGE_FILE_NAME,
5198 dscp, lastNamep, NULL, TRUE);
5199 if (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE) {
5200 /* Not an exclusive create, and someone else tried
5201 * creating it already, then we open it anyway. We
5202 * don't bother retrying after this, since if this next
5203 * fails, that means that the file was deleted after we
5204 * started this call.
5206 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
5209 if (createDisp == FILE_OVERWRITE_IF) {
5210 setAttr.mask = CM_ATTRMASK_LENGTH;
5211 setAttr.length.LowPart = 0;
5212 setAttr.length.HighPart = 0;
5214 /* now watch for a symlink */
5216 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
5218 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
5220 /* we have a more accurate file to use (the
5221 * target of the symbolic link). Otherwise,
5222 * we'll just use the symlink anyway.
5224 osi_Log2(smb_logp, "symlink vp %x to vp %x",
5226 cm_ReleaseSCache(scp);
5230 code = cm_SetAttr(scp, &setAttr, userp, &req);
5232 } /* lookup succeeded */
5237 char *cp; /* This component */
5238 int clen = 0; /* length of component */
5242 /* create directory */
5244 treeStartp = lastNamep;
5245 osi_assert(dscp != NULL);
5246 osi_Log1(smb_logp, "smb_ReceiveNTCreateX creating directory [%s]",
5247 osi_LogSaveString(smb_logp, treeStartp));
5248 openAction = 2; /* created directory */
5250 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
5251 setAttr.clientModTime = time(NULL);
5258 tp = strchr(pp, '\\');
5262 isLast = 1; /* indicate last component. the supplied path never ends in a slash */
5266 strncpy(cp,pp,clen);
5273 continue; /* the supplied path can't have consecutive slashes either , but */
5275 /* cp is the next component to be created. */
5276 code = cm_MakeDir(tscp, cp, 0, &setAttr, userp, &req);
5277 if (code == 0 && (tscp->flags & CM_SCACHEFLAG_ANYWATCH))
5278 smb_NotifyChange(FILE_ACTION_ADDED,
5279 FILE_NOTIFY_CHANGE_DIR_NAME,
5280 tscp, cp, NULL, TRUE);
5282 (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE)) {
5283 /* Not an exclusive create, and someone else tried
5284 * creating it already, then we open it anyway. We
5285 * don't bother retrying after this, since if this next
5286 * fails, that means that the file was deleted after we
5287 * started this call.
5289 code = cm_Lookup(tscp, cp, CM_FLAG_CASEFOLD,
5294 if (!isLast) { /* for anything other than dscp, release it unless it's the last one */
5295 cm_ReleaseSCache(tscp);
5296 tscp = scp; /* Newly created directory will be next parent */
5301 * if we get here and code == 0, then scp is the last directory created, and tscp is the
5302 * parent of scp. dscp got released if dscp != tscp. both tscp and scp are held.
5308 /* something went wrong creating or truncating the file */
5309 if (scp) cm_ReleaseSCache(scp);
5310 if (dscp) cm_ReleaseSCache(dscp);
5311 cm_ReleaseUser(userp);
5316 /* make sure we have file vs. dir right (only applies for single component case) */
5317 if (realDirFlag == 0 && scp->fileType != CM_SCACHETYPE_FILE) {
5318 /* now watch for a symlink */
5320 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
5321 cm_scache_t * targetScp = 0;
5322 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
5324 /* we have a more accurate file to use (the
5325 * target of the symbolic link). Otherwise,
5326 * we'll just use the symlink anyway.
5328 osi_Log2(smb_logp, "symlink vp %x to vp %x",
5330 cm_ReleaseSCache(scp);
5335 if (scp->fileType != CM_SCACHETYPE_FILE) {
5336 cm_ReleaseSCache(scp);
5337 cm_ReleaseUser(userp);
5339 return CM_ERROR_ISDIR;
5343 /* (only applies to single component case) */
5344 if (realDirFlag == 1 && scp->fileType == CM_SCACHETYPE_FILE) {
5345 cm_ReleaseSCache(scp);
5346 if (dscp) cm_ReleaseSCache(dscp);
5347 cm_ReleaseUser(userp);
5349 return CM_ERROR_NOTDIR;
5352 /* open the file itself */
5353 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
5355 /* save a pointer to the vnode */
5358 fidp->flags = fidflags;
5360 /* save parent dir and pathname for delete or change notification */
5361 if (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE)) {
5362 fidp->flags |= SMB_FID_NTOPEN;
5363 fidp->NTopen_dscp = dscp;
5364 cm_HoldSCache(dscp);
5365 fidp->NTopen_pathp = strdup(lastNamep);
5367 fidp->NTopen_wholepathp = realPathp;
5369 /* we don't need this any longer */
5370 if (dscp) cm_ReleaseSCache(dscp);
5371 cm_Open(scp, 0, userp);
5373 /* set inp->fid so that later read calls in same msg can find fid */
5374 inp->fid = fidp->fid;
5378 lock_ObtainMutex(&scp->mx);
5379 smb_SetSMBParmByte(outp, parmSlot, 0); /* oplock */
5380 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
5381 smb_SetSMBParmLong(outp, parmSlot, openAction); parmSlot += 2;
5382 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
5383 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
5384 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
5385 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
5386 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
5387 smb_SetSMBParmLong(outp, parmSlot, smb_ExtAttributes(scp));
5389 smb_SetSMBParmDouble(outp, parmSlot, (char *)&scp->length); parmSlot += 4;
5390 smb_SetSMBParmDouble(outp, parmSlot, (char *)&scp->length); parmSlot += 4;
5391 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* filetype */
5392 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* dev state */
5393 smb_SetSMBParmByte(outp, parmSlot,
5394 scp->fileType == CM_SCACHETYPE_DIRECTORY); /* is a dir? */
5395 lock_ReleaseMutex(&scp->mx);
5396 smb_SetSMBDataLength(outp, 0);
5398 osi_Log2(smb_logp, "SMB NT CreateX opening fid %d path %s", fidp->fid,
5399 osi_LogSaveString(smb_logp, realPathp));
5401 smb_ReleaseFID(fidp);
5403 cm_ReleaseUser(userp);
5405 /* Can't free realPathp if we get here since fidp->NTopen_wholepathp is pointing there */
5407 /* leave scp held since we put it in fidp->scp */
5412 * A lot of stuff copied verbatim from NT Create&X to NT Tran Create.
5413 * Instead, ultimately, would like to use a subroutine for common code.
5415 long smb_ReceiveNTTranCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5417 char *pathp, *realPathp;
5421 cm_scache_t *dscp; /* parent dir */
5422 cm_scache_t *scp; /* file to create or open */
5423 cm_scache_t *targetScp; /* if scp is a symlink */
5426 unsigned long nameLength;
5428 unsigned int requestOpLock;
5429 unsigned int requestBatchOpLock;
5430 unsigned int mustBeDir;
5431 unsigned int extendedRespRequired;
5433 unsigned int desiredAccess;
5434 #ifdef DEBUG_VERBOSE
5435 unsigned int allocSize;
5436 unsigned int shareAccess;
5438 unsigned int extAttributes;
5439 unsigned int createDisp;
5440 #ifdef DEBUG_VERBOSE
5443 unsigned int createOptions;
5444 int initialModeBits;
5445 unsigned short baseFid;
5446 smb_fid_t *baseFidp;
5448 cm_scache_t *baseDirp;
5449 unsigned short openAction;
5455 int parmOffset, dataOffset;
5466 parmOffset = smb_GetSMBOffsetParm(inp, 11, 1)
5467 | (smb_GetSMBOffsetParm(inp, 12, 1) << 16);
5468 parmp = inp->data + parmOffset;
5469 lparmp = (ULONG *) parmp;
5472 requestOpLock = flags & 0x02;
5473 requestBatchOpLock = flags & 0x04;
5474 mustBeDir = flags & 0x08;
5475 extendedRespRequired = flags & 0x10;
5478 * Why all of a sudden 32-bit FID?
5479 * We will reject all bits higher than 16.
5481 if (lparmp[1] & 0xFFFF0000)
5482 return CM_ERROR_INVAL;
5483 baseFid = (unsigned short)lparmp[1];
5484 desiredAccess = lparmp[2];
5485 #ifdef DEBUG_VERBOSE
5486 allocSize = lparmp[3];
5487 #endif /* DEBUG_VERSOSE */
5488 extAttributes = lparmp[5];
5490 shareAccess = lparmp[6];
5492 createDisp = lparmp[7];
5493 createOptions = lparmp[8];
5494 #ifdef DEBUG_VERBOSE
5497 nameLength = lparmp[11];
5499 #ifdef DEBUG_VERBOSE
5500 osi_Log4(smb_logp,"NTTranCreate with da[%x],ea[%x],sa[%x],cd[%x]",desiredAccess,extAttributes,shareAccess,createDisp);
5501 osi_Log3(smb_logp,"... co[%x],sdl[%x],as[%x]",createOptions,sdLen,allocSize);
5502 osi_Log1(smb_logp,"... flags[%x]",flags);
5505 /* mustBeDir is never set; createOptions directory bit seems to be
5508 if (createOptions & 1)
5510 else if (createOptions & 0x40)
5516 * compute initial mode bits based on read-only flag in
5517 * extended attributes
5519 initialModeBits = 0666;
5520 if (extAttributes & 1)
5521 initialModeBits &= ~0222;
5523 pathp = parmp + (13 * sizeof(ULONG)) + sizeof(UCHAR);
5524 /* Sometimes path is not null-terminated, so we make a copy. */
5525 realPathp = malloc(nameLength+1);
5526 memcpy(realPathp, pathp, nameLength);
5527 realPathp[nameLength] = 0;
5528 if (smb_StoreAnsiFilenames)
5529 OemToChar(realPathp,realPathp);
5531 spacep = cm_GetSpace();
5532 smb_StripLastComponent(spacep->data, &lastNamep, realPathp);
5535 * Nothing here to handle SMB_IOCTL_FILENAME.
5536 * Will add it if necessary.
5539 #ifdef DEBUG_VERBOSE
5541 char *hexp, *asciip;
5542 asciip = (lastNamep? lastNamep : realPathp);
5543 hexp = osi_HexifyString( asciip );
5544 DEBUG_EVENT2("AFS", "NTTranCreate H[%s] A[%s]", hexp, asciip);
5549 userp = smb_GetUser(vcp, inp);
5551 osi_Log1(smb_logp, "NTTranCreate invalid user [%d]", ((smb_t *) inp)->uid);
5553 return CM_ERROR_INVAL;
5557 baseDirp = cm_rootSCachep;
5558 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5559 if(code == CM_ERROR_TIDIPC) {
5560 /* Attempt to use TID allocated for IPC. The client is
5561 * probably trying to locate DCE RPC endpoints, which we
5563 osi_Log0(smb_logp, "NTTranCreate received IPC TID");
5565 cm_ReleaseUser(userp);
5566 return CM_ERROR_NOSUCHPATH;
5570 baseFidp = smb_FindFID(vcp, baseFid, 0);
5572 osi_Log1(smb_logp, "NTTranCreate Invalid fid [%d]", baseFid);
5574 cm_ReleaseUser(userp);
5575 return CM_ERROR_INVAL;
5577 baseDirp = baseFidp->scp;
5581 /* compute open mode */
5583 if (desiredAccess & DELETE)
5584 fidflags |= SMB_FID_OPENDELETE;
5585 if (desiredAccess & AFS_ACCESS_READ)
5586 fidflags |= SMB_FID_OPENREAD;
5587 if (desiredAccess & AFS_ACCESS_WRITE)
5588 fidflags |= SMB_FID_OPENWRITE;
5592 if ( createDisp == FILE_OPEN ||
5593 createDisp == FILE_OVERWRITE ||
5594 createDisp == FILE_OVERWRITE_IF) {
5595 code = cm_NameI(baseDirp, spacep->data, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
5596 userp, tidPathp, &req, &dscp);
5598 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp, CM_FLAG_FOLLOW,
5600 if (code == CM_ERROR_NOSUCHFILE) {
5601 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp,
5602 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, &req, &scp);
5603 if (code == 0 && realDirFlag == 1) {
5604 cm_ReleaseSCache(scp);
5605 cm_ReleaseSCache(dscp);
5606 cm_ReleaseUser(userp);
5608 return CM_ERROR_EXISTS;
5614 code = cm_NameI(baseDirp, realPathp, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
5615 userp, tidPathp, &req, &scp);
5621 || (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE))) {
5622 /* look up parent directory */
5624 code = cm_NameI(baseDirp, spacep->data,
5625 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
5626 userp, tidPathp, &req, &dscp);
5630 cm_FreeSpace(spacep);
5633 smb_ReleaseFID(baseFidp);
5638 cm_ReleaseUser(userp);
5643 if (!lastNamep) lastNamep = realPathp;
5646 if (!smb_IsLegalFilename(lastNamep))
5647 return CM_ERROR_BADNTFILENAME;
5650 if (createDisp == FILE_CREATE || createDisp == FILE_OVERWRITE_IF) {
5651 code = cm_Lookup(dscp, lastNamep,
5652 CM_FLAG_FOLLOW, userp, &req, &scp);
5654 code = cm_Lookup(dscp, lastNamep,
5655 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
5658 if (code && code != CM_ERROR_NOSUCHFILE) {
5659 cm_ReleaseSCache(dscp);
5660 cm_ReleaseUser(userp);
5668 smb_ReleaseFID(baseFidp);
5671 cm_FreeSpace(spacep);
5674 /* if we get here, if code is 0, the file exists and is represented by
5675 * scp. Otherwise, we have to create it. The dir may be represented
5676 * by dscp, or we may have found the file directly. If code is non-zero,
5680 code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp,
5683 if (dscp) cm_ReleaseSCache(dscp);
5684 cm_ReleaseSCache(scp);
5685 cm_ReleaseUser(userp);
5690 if (createDisp == FILE_CREATE) {
5691 /* oops, file shouldn't be there */
5692 if (dscp) cm_ReleaseSCache(dscp);
5693 cm_ReleaseSCache(scp);
5694 cm_ReleaseUser(userp);
5696 return CM_ERROR_EXISTS;
5699 if (createDisp == FILE_OVERWRITE ||
5700 createDisp == FILE_OVERWRITE_IF) {
5701 setAttr.mask = CM_ATTRMASK_LENGTH;
5702 setAttr.length.LowPart = 0;
5703 setAttr.length.HighPart = 0;
5705 /* now watch for a symlink */
5707 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
5709 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
5711 /* we have a more accurate file to use (the
5712 * target of the symbolic link). Otherwise,
5713 * we'll just use the symlink anyway.
5715 osi_Log2(smb_logp, "symlink vp %x to vp %x",
5717 cm_ReleaseSCache(scp);
5721 code = cm_SetAttr(scp, &setAttr, userp, &req);
5722 openAction = 3; /* truncated existing file */
5724 else openAction = 1; /* found existing file */
5726 else if (createDisp == FILE_OPEN || createDisp == FILE_OVERWRITE) {
5727 /* don't create if not found */
5728 if (dscp) cm_ReleaseSCache(dscp);
5729 cm_ReleaseUser(userp);
5731 return CM_ERROR_NOSUCHFILE;
5733 else if (realDirFlag == 0 || realDirFlag == -1) {
5734 osi_assert(dscp != NULL);
5735 osi_Log1(smb_logp, "smb_ReceiveNTTranCreate creating file %s",
5736 osi_LogSaveString(smb_logp, lastNamep));
5737 openAction = 2; /* created file */
5738 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
5739 setAttr.clientModTime = time(NULL);
5740 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
5742 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
5743 smb_NotifyChange(FILE_ACTION_ADDED,
5744 FILE_NOTIFY_CHANGE_FILE_NAME,
5745 dscp, lastNamep, NULL, TRUE);
5746 if (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE) {
5747 /* Not an exclusive create, and someone else tried
5748 * creating it already, then we open it anyway. We
5749 * don't bother retrying after this, since if this next
5750 * fails, that means that the file was deleted after we
5751 * started this call.
5753 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
5756 if (createDisp == FILE_OVERWRITE_IF) {
5757 setAttr.mask = CM_ATTRMASK_LENGTH;
5758 setAttr.length.LowPart = 0;
5759 setAttr.length.HighPart = 0;
5761 /* now watch for a symlink */
5763 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
5765 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
5767 /* we have a more accurate file to use (the
5768 * target of the symbolic link). Otherwise,
5769 * we'll just use the symlink anyway.
5771 osi_Log2(smb_logp, "symlink vp %x to vp %x",
5773 cm_ReleaseSCache(scp);
5777 code = cm_SetAttr(scp, &setAttr, userp, &req);
5779 } /* lookup succeeded */
5783 /* create directory */
5784 osi_assert(dscp != NULL);
5786 "smb_ReceiveNTTranCreate creating directory %s",
5787 osi_LogSaveString(smb_logp, lastNamep));
5788 openAction = 2; /* created directory */
5789 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
5790 setAttr.clientModTime = time(NULL);
5791 code = cm_MakeDir(dscp, lastNamep, 0, &setAttr, userp, &req);
5792 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
5793 smb_NotifyChange(FILE_ACTION_ADDED,
5794 FILE_NOTIFY_CHANGE_DIR_NAME,
5795 dscp, lastNamep, NULL, TRUE);
5797 (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE)) {
5798 /* Not an exclusive create, and someone else tried
5799 * creating it already, then we open it anyway. We
5800 * don't bother retrying after this, since if this next
5801 * fails, that means that the file was deleted after we
5802 * started this call.
5804 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
5810 /* something went wrong creating or truncating the file */
5811 if (scp) cm_ReleaseSCache(scp);
5812 cm_ReleaseUser(userp);
5817 /* make sure we have file vs. dir right */
5818 if (realDirFlag == 0 && scp->fileType != CM_SCACHETYPE_FILE) {
5819 /* now watch for a symlink */
5821 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
5823 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
5825 /* we have a more accurate file to use (the
5826 * target of the symbolic link). Otherwise,
5827 * we'll just use the symlink anyway.
5829 osi_Log2(smb_logp, "symlink vp %x to vp %x",
5831 cm_ReleaseSCache(scp);
5836 if (scp->fileType != CM_SCACHETYPE_FILE) {
5837 cm_ReleaseSCache(scp);
5838 cm_ReleaseUser(userp);
5840 return CM_ERROR_ISDIR;
5844 if (realDirFlag == 1 && scp->fileType == CM_SCACHETYPE_FILE) {
5845 cm_ReleaseSCache(scp);
5846 cm_ReleaseUser(userp);
5848 return CM_ERROR_NOTDIR;
5851 /* open the file itself */
5852 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
5855 /* save a pointer to the vnode */
5858 fidp->flags = fidflags;
5860 /* save parent dir and pathname for deletion or change notification */
5861 if (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE)) {
5862 fidp->flags |= SMB_FID_NTOPEN;
5863 fidp->NTopen_dscp = dscp;
5864 cm_HoldSCache(dscp);
5865 fidp->NTopen_pathp = strdup(lastNamep);
5867 fidp->NTopen_wholepathp = realPathp;
5869 /* we don't need this any longer */
5870 if (dscp) cm_ReleaseSCache(dscp);
5872 cm_Open(scp, 0, userp);
5874 /* set inp->fid so that later read calls in same msg can find fid */
5875 inp->fid = fidp->fid;
5877 /* check whether we are required to send an extended response */
5878 if (!extendedRespRequired) {
5880 parmOffset = 8*4 + 39;
5881 parmOffset += 1; /* pad to 4 */
5882 dataOffset = parmOffset + 70;
5886 /* Total Parameter Count */
5887 smb_SetSMBParmLong(outp, parmSlot, 70); parmSlot += 2;
5888 /* Total Data Count */
5889 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
5890 /* Parameter Count */
5891 smb_SetSMBParmLong(outp, parmSlot, 70); parmSlot += 2;
5892 /* Parameter Offset */
5893 smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
5894 /* Parameter Displacement */
5895 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
5897 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
5899 smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
5900 /* Data Displacement */
5901 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
5902 smb_SetSMBParmByte(outp, parmSlot, 0); /* Setup Count */
5903 smb_SetSMBDataLength(outp, 70);
5905 lock_ObtainMutex(&scp->mx);
5906 outData = smb_GetSMBData(outp, NULL);
5907 outData++; /* round to get to parmOffset */
5908 *outData = 0; outData++; /* oplock */
5909 *outData = 0; outData++; /* reserved */
5910 *((USHORT *)outData) = fidp->fid; outData += 2; /* fid */
5911 *((ULONG *)outData) = openAction; outData += 4;
5912 *((ULONG *)outData) = 0; outData += 4; /* EA error offset */
5913 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
5914 *((FILETIME *)outData) = ft; outData += 8; /* creation time */
5915 *((FILETIME *)outData) = ft; outData += 8; /* last access time */
5916 *((FILETIME *)outData) = ft; outData += 8; /* last write time */
5917 *((FILETIME *)outData) = ft; outData += 8; /* change time */
5918 *((ULONG *)outData) = smb_ExtAttributes(scp); outData += 4;
5919 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* alloc sz */
5920 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* EOF */
5921 *((USHORT *)outData) = 0; outData += 2; /* filetype */
5922 *((USHORT *)outData) = 0; outData += 2; /* dev state */
5923 *((USHORT *)outData) = (scp->fileType == CM_SCACHETYPE_DIRECTORY);
5924 outData += 2; /* is a dir? */
5925 lock_ReleaseMutex(&scp->mx);
5928 parmOffset = 8*4 + 39;
5929 parmOffset += 1; /* pad to 4 */
5930 dataOffset = parmOffset + 104;
5934 /* Total Parameter Count */
5935 smb_SetSMBParmLong(outp, parmSlot, 101); parmSlot += 2;
5936 /* Total Data Count */
5937 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
5938 /* Parameter Count */
5939 smb_SetSMBParmLong(outp, parmSlot, 101); parmSlot += 2;
5940 /* Parameter Offset */
5941 smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
5942 /* Parameter Displacement */
5943 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
5945 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
5947 smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
5948 /* Data Displacement */
5949 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
5950 smb_SetSMBParmByte(outp, parmSlot, 0); /* Setup Count */
5951 smb_SetSMBDataLength(outp, 105);
5953 lock_ObtainMutex(&scp->mx);
5954 outData = smb_GetSMBData(outp, NULL);
5955 outData++; /* round to get to parmOffset */
5956 *outData = 0; outData++; /* oplock */
5957 *outData = 1; outData++; /* response type */
5958 *((USHORT *)outData) = fidp->fid; outData += 2; /* fid */
5959 *((ULONG *)outData) = openAction; outData += 4;
5960 *((ULONG *)outData) = 0; outData += 4; /* EA error offset */
5961 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
5962 *((FILETIME *)outData) = ft; outData += 8; /* creation time */
5963 *((FILETIME *)outData) = ft; outData += 8; /* last access time */
5964 *((FILETIME *)outData) = ft; outData += 8; /* last write time */
5965 *((FILETIME *)outData) = ft; outData += 8; /* change time */
5966 *((ULONG *)outData) = smb_ExtAttributes(scp); outData += 4;
5967 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* alloc sz */
5968 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* EOF */
5969 *((USHORT *)outData) = 0; outData += 2; /* filetype */
5970 *((USHORT *)outData) = 0; outData += 2; /* dev state */
5971 *((USHORT *)outData) = (scp->fileType == CM_SCACHETYPE_DIRECTORY);
5972 outData += 1; /* is a dir? */
5973 memset(outData,0,24); outData += 24; /* Volume ID and file ID */
5974 *((ULONG *)outData) = 0x001f01ffL; outData += 4; /* Maxmimal access rights */
5975 *((ULONG *)outData) = 0; outData += 4; /* Guest Access rights */
5976 lock_ReleaseMutex(&scp->mx);
5979 osi_Log1(smb_logp, "SMB NTTranCreate opening fid %d", fidp->fid);
5981 smb_ReleaseFID(fidp);
5983 cm_ReleaseUser(userp);
5985 /* free(realPathp); Can't free realPathp here because fidp->NTopen_wholepathp points there */
5986 /* leave scp held since we put it in fidp->scp */
5990 long smb_ReceiveNTTranNotifyChange(smb_vc_t *vcp, smb_packet_t *inp,
5993 smb_packet_t *savedPacketp;
5994 ULONG filter; USHORT fid, watchtree;
5998 filter = smb_GetSMBParm(inp, 19) |
5999 (smb_GetSMBParm(inp, 20) << 16);
6000 fid = smb_GetSMBParm(inp, 21);
6001 watchtree = smb_GetSMBParm(inp, 22) && 0xffff; /* TODO: should this be 0xff ? */
6003 fidp = smb_FindFID(vcp, fid, 0);
6005 osi_Log1(smb_logp, "ERROR: NotifyChange given invalid fid [%d]", fid);
6006 return CM_ERROR_BADFD;
6009 savedPacketp = smb_CopyPacket(inp);
6011 savedPacketp->vcp = vcp;
6012 lock_ObtainMutex(&smb_Dir_Watch_Lock);
6013 savedPacketp->nextp = smb_Directory_Watches;
6014 smb_Directory_Watches = savedPacketp;
6015 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
6017 osi_Log4(smb_logp, "Request for NotifyChange filter 0x%x fid %d wtree %d file %s",
6018 filter, fid, watchtree, osi_LogSaveString(smb_logp, fidp->NTopen_wholepathp));
6021 lock_ObtainMutex(&scp->mx);
6023 scp->flags |= CM_SCACHEFLAG_WATCHEDSUBTREE;
6025 scp->flags |= CM_SCACHEFLAG_WATCHED;
6026 lock_ReleaseMutex(&scp->mx);
6027 smb_ReleaseFID(fidp);
6029 outp->flags |= SMB_PACKETFLAG_NOSEND;
6033 unsigned char nullSecurityDesc[36] = {
6034 0x01, /* security descriptor revision */
6035 0x00, /* reserved, should be zero */
6036 0x00, 0x80, /* security descriptor control;
6037 * 0x8000 : self-relative format */
6038 0x14, 0x00, 0x00, 0x00, /* offset of owner SID */
6039 0x1c, 0x00, 0x00, 0x00, /* offset of group SID */
6040 0x00, 0x00, 0x00, 0x00, /* offset of DACL would go here */
6041 0x00, 0x00, 0x00, 0x00, /* offset of SACL would go here */
6042 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
6043 /* "null SID" owner SID */
6044 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
6045 /* "null SID" group SID */
6048 long smb_ReceiveNTTranQuerySecurityDesc(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6050 int parmOffset, parmCount, dataOffset, dataCount;
6058 ULONG securityInformation;
6060 parmOffset = smb_GetSMBOffsetParm(inp, 11, 1)
6061 | (smb_GetSMBOffsetParm(inp, 12, 1) << 16);
6062 parmp = inp->data + parmOffset;
6063 sparmp = (USHORT *) parmp;
6064 lparmp = (ULONG *) parmp;
6067 securityInformation = lparmp[1];
6069 maxData = smb_GetSMBOffsetParm(inp, 7, 1)
6070 | (smb_GetSMBOffsetParm(inp, 8, 1) << 16);
6078 parmOffset = 8*4 + 39;
6079 parmOffset += 1; /* pad to 4 */
6081 dataOffset = parmOffset + parmCount;
6085 /* Total Parameter Count */
6086 smb_SetSMBParmLong(outp, parmSlot, parmCount); parmSlot += 2;
6087 /* Total Data Count */
6088 smb_SetSMBParmLong(outp, parmSlot, dataCount); parmSlot += 2;
6089 /* Parameter Count */
6090 smb_SetSMBParmLong(outp, parmSlot, parmCount); parmSlot += 2;
6091 /* Parameter Offset */
6092 smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
6093 /* Parameter Displacement */
6094 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
6096 smb_SetSMBParmLong(outp, parmSlot, dataCount); parmSlot += 2;
6098 smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
6099 /* Data Displacement */
6100 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
6101 smb_SetSMBParmByte(outp, parmSlot, 0); /* Setup Count */
6102 smb_SetSMBDataLength(outp, 1 + parmCount + dataCount);
6104 outData = smb_GetSMBData(outp, NULL);
6105 outData++; /* round to get to parmOffset */
6106 *((ULONG *)outData) = 36; outData += 4; /* length */
6108 if (maxData >= 36) {
6109 memcpy(outData, nullSecurityDesc, 36);
6113 return CM_ERROR_BUFFERTOOSMALL;
6116 long smb_ReceiveNTTransact(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6118 unsigned short function;
6120 function = smb_GetSMBParm(inp, 18);
6122 osi_Log1(smb_logp, "SMB NT Transact function %d", function);
6124 /* We can handle long names */
6125 if (vcp->flags & SMB_VCFLAG_USENT)
6126 ((smb_t *)outp)->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
6130 return smb_ReceiveNTTranQuerySecurityDesc(vcp, inp, outp);
6132 return smb_ReceiveNTTranNotifyChange(vcp, inp, outp);
6134 return smb_ReceiveNTTranCreate(vcp, inp, outp);
6136 return CM_ERROR_INVAL;
6141 * smb_NotifyChange -- find relevant change notification messages and
6144 * If we don't know the file name (i.e. a callback break), filename is
6145 * NULL, and we return a zero-length list.
6147 void smb_NotifyChange(DWORD action, DWORD notifyFilter,
6148 cm_scache_t *dscp, char *filename, char *otherFilename,
6149 BOOL isDirectParent)
6151 smb_packet_t *watch, *lastWatch, *nextWatch;
6152 ULONG parmSlot, parmCount, parmOffset, dataOffset, nameLen;
6153 char *outData, *oldOutData;
6157 BOOL twoEntries = FALSE;
6158 ULONG otherNameLen, oldParmCount = 0;
6163 /* Get ready for rename within directory */
6164 if (action == FILE_ACTION_RENAMED_OLD_NAME && otherFilename != NULL) {
6166 otherAction = FILE_ACTION_RENAMED_NEW_NAME;
6169 osi_Log2(smb_logp,"in smb_NotifyChange for file [%s] dscp [%x]",
6170 osi_LogSaveString(smb_logp,filename),dscp);
6172 lock_ObtainMutex(&smb_Dir_Watch_Lock);
6173 watch = smb_Directory_Watches;
6175 filter = smb_GetSMBParm(watch, 19)
6176 | (smb_GetSMBParm(watch, 20) << 16);
6177 fid = smb_GetSMBParm(watch, 21);
6178 wtree = smb_GetSMBParm(watch, 22) & 0xffff; /* TODO: should this be 0xff ? */
6179 maxLen = smb_GetSMBOffsetParm(watch, 5, 1)
6180 | (smb_GetSMBOffsetParm(watch, 6, 1) << 16);
6184 * Strange hack - bug in NT Client and NT Server that we
6187 if (filter == 3 && wtree)
6190 fidp = smb_FindFID(vcp, fid, 0);
6192 osi_Log1(smb_logp," no fidp for fid[%d]",fid);
6194 watch = watch->nextp;
6197 if (fidp->scp != dscp
6198 || (filter & notifyFilter) == 0
6199 || (!isDirectParent && !wtree)) {
6200 osi_Log1(smb_logp," passing fidp->scp[%x]", fidp->scp);
6201 smb_ReleaseFID(fidp);
6203 watch = watch->nextp;
6206 smb_ReleaseFID(fidp);
6209 "Sending Change Notification for fid %d filter 0x%x wtree %d file %s",
6210 fid, filter, wtree, osi_LogSaveString(smb_logp, filename));
6212 nextWatch = watch->nextp;
6213 if (watch == smb_Directory_Watches)
6214 smb_Directory_Watches = nextWatch;
6216 lastWatch->nextp = nextWatch;
6218 /* Turn off WATCHED flag in dscp */
6219 lock_ObtainMutex(&dscp->mx);
6221 dscp->flags &= ~CM_SCACHEFLAG_WATCHEDSUBTREE;
6223 dscp->flags &= ~CM_SCACHEFLAG_WATCHED;
6224 lock_ReleaseMutex(&dscp->mx);
6226 /* Convert to response packet */
6227 ((smb_t *) watch)->reb = 0x80;
6228 ((smb_t *) watch)->wct = 0;
6231 if (filename == NULL)
6234 nameLen = strlen(filename);
6235 parmCount = 3*4 + nameLen*2;
6236 parmCount = (parmCount + 3) & ~3; /* pad to 4 */
6238 otherNameLen = strlen(otherFilename);
6239 oldParmCount = parmCount;
6240 parmCount += 3*4 + otherNameLen*2;
6241 parmCount = (parmCount + 3) & ~3; /* pad to 4 */
6243 if (maxLen < parmCount)
6244 parmCount = 0; /* not enough room */
6246 parmOffset = 8*4 + 39;
6247 parmOffset += 1; /* pad to 4 */
6248 dataOffset = parmOffset + parmCount;
6252 /* Total Parameter Count */
6253 smb_SetSMBParmLong(watch, parmSlot, parmCount); parmSlot += 2;
6254 /* Total Data Count */
6255 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
6256 /* Parameter Count */
6257 smb_SetSMBParmLong(watch, parmSlot, parmCount); parmSlot += 2;
6258 /* Parameter Offset */
6259 smb_SetSMBParmLong(watch, parmSlot, parmOffset); parmSlot += 2;
6260 /* Parameter Displacement */
6261 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
6263 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
6265 smb_SetSMBParmLong(watch, parmSlot, dataOffset); parmSlot += 2;
6266 /* Data Displacement */
6267 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
6268 smb_SetSMBParmByte(watch, parmSlot, 0); /* Setup Count */
6269 smb_SetSMBDataLength(watch, parmCount + 1);
6271 if (parmCount != 0) {
6273 outData = smb_GetSMBData(watch, NULL);
6274 outData++; /* round to get to parmOffset */
6275 oldOutData = outData;
6276 *((DWORD *)outData) = oldParmCount; outData += 4;
6277 /* Next Entry Offset */
6278 *((DWORD *)outData) = action; outData += 4;
6280 *((DWORD *)outData) = nameLen*2; outData += 4;
6281 /* File Name Length */
6282 p = strdup(filename);
6283 if (smb_StoreAnsiFilenames)
6285 mbstowcs((WCHAR *)outData, p, nameLen);
6289 outData = oldOutData + oldParmCount;
6290 *((DWORD *)outData) = 0; outData += 4;
6291 /* Next Entry Offset */
6292 *((DWORD *)outData) = otherAction; outData += 4;
6294 *((DWORD *)outData) = otherNameLen*2;
6295 outData += 4; /* File Name Length */
6296 p = strdup(otherFilename);
6297 if (smb_StoreAnsiFilenames)
6299 mbstowcs((WCHAR *)outData, p, otherNameLen); /* File Name */
6305 * If filename is null, we don't know the cause of the
6306 * change notification. We return zero data (see above),
6307 * and set error code to NT_STATUS_NOTIFY_ENUM_DIR
6308 * (= 0x010C). We set the error code here by hand, without
6309 * modifying wct and bcc.
6311 if (filename == NULL) {
6312 ((smb_t *) watch)->rcls = 0x0C;
6313 ((smb_t *) watch)->reh = 0x01;
6314 ((smb_t *) watch)->errLow = 0;
6315 ((smb_t *) watch)->errHigh = 0;
6316 /* Set NT Status codes flag */
6317 ((smb_t *) watch)->flg2 |= SMB_FLAGS2_ERR_STATUS;
6320 smb_SendPacket(vcp, watch);
6322 smb_FreePacket(watch);
6325 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
6328 long smb_ReceiveNTCancel(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6330 unsigned char *replyWctp;
6331 smb_packet_t *watch, *lastWatch;
6332 USHORT fid, watchtree;
6336 osi_Log0(smb_logp, "SMB3 receive NT cancel");
6338 lock_ObtainMutex(&smb_Dir_Watch_Lock);
6339 watch = smb_Directory_Watches;
6341 if (((smb_t *)watch)->uid == ((smb_t *)inp)->uid
6342 && ((smb_t *)watch)->pid == ((smb_t *)inp)->pid
6343 && ((smb_t *)watch)->mid == ((smb_t *)inp)->mid
6344 && ((smb_t *)watch)->tid == ((smb_t *)inp)->tid) {
6345 if (watch == smb_Directory_Watches)
6346 smb_Directory_Watches = watch->nextp;
6348 lastWatch->nextp = watch->nextp;
6349 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
6351 /* Turn off WATCHED flag in scp */
6352 fid = smb_GetSMBParm(watch, 21);
6353 watchtree = smb_GetSMBParm(watch, 22) & 0xffff;
6355 if (vcp != watch->vcp)
6356 osi_Log2(smb_logp, "smb_ReceiveNTCancel: vcp %x not equal to watch vcp %x",
6359 fidp = smb_FindFID(vcp, fid, 0);
6361 osi_Log3(smb_logp, "Cancelling change notification for fid %d wtree %d file %s",
6363 osi_LogSaveString(smb_logp, (fidp)?fidp->NTopen_wholepathp:""));
6366 lock_ObtainMutex(&scp->mx);
6368 scp->flags &= ~CM_SCACHEFLAG_WATCHEDSUBTREE;
6370 scp->flags &= ~CM_SCACHEFLAG_WATCHED;
6371 lock_ReleaseMutex(&scp->mx);
6372 smb_ReleaseFID(fidp);
6374 osi_Log2(smb_logp,"NTCancel unable to resolve fid [%d] in vcp[%x]", fid,vcp);
6377 /* assume STATUS32; return 0xC0000120 (CANCELED) */
6378 replyWctp = watch->wctp;
6382 ((smb_t *)watch)->rcls = 0x20;
6383 ((smb_t *)watch)->reh = 0x1;
6384 ((smb_t *)watch)->errLow = 0;
6385 ((smb_t *)watch)->errHigh = 0xC0;
6386 ((smb_t *)watch)->flg2 |= SMB_FLAGS2_ERR_STATUS;
6387 smb_SendPacket(vcp, watch);
6389 smb_ReleaseVC(watch->vcp);
6390 smb_FreePacket(watch);
6394 watch = watch->nextp;
6396 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
6402 * NT rename also does hard links.
6405 #define RENAME_FLAG_MOVE_CLUSTER_INFORMATION 0x102
6406 #define RENAME_FLAG_HARD_LINK 0x103
6407 #define RENAME_FLAG_RENAME 0x104
6408 #define RENAME_FLAG_COPY 0x105
6410 long smb_ReceiveNTRename(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6412 char *oldPathp, *newPathp;
6419 attrs = smb_GetSMBParm(inp, 0);
6420 rename_type = smb_GetSMBParm(inp, 1);
6422 if (rename_type != RENAME_FLAG_RENAME && rename_type != RENAME_FLAG_HARD_LINK) {
6423 osi_Log1(smb_logp, "NTRename invalid infolevel [%x]", rename_type);
6424 return CM_ERROR_NOACCESS;
6427 tp = smb_GetSMBData(inp, NULL);
6428 oldPathp = smb_ParseASCIIBlock(tp, &tp);
6429 if (smb_StoreAnsiFilenames)
6430 OemToChar(oldPathp,oldPathp);
6431 newPathp = smb_ParseASCIIBlock(tp, &tp);
6432 if (smb_StoreAnsiFilenames)
6433 OemToChar(newPathp,newPathp);
6435 osi_Log3(smb_logp, "NTRename for [%s]->[%s] type [%s]",
6436 osi_LogSaveString(smb_logp, oldPathp),
6437 osi_LogSaveString(smb_logp, newPathp),
6438 ((rename_type==RENAME_FLAG_RENAME)?"rename":"hardlink"));
6440 if (rename_type == RENAME_FLAG_RENAME) {
6441 code = smb_Rename(vcp,inp,oldPathp,newPathp,attrs);
6442 } else { /* RENAME_FLAG_HARD_LINK */
6443 code = smb_Link(vcp,inp,oldPathp,newPathp);
6450 lock_InitializeMutex(&smb_Dir_Watch_Lock, "Directory Watch List Lock");
6453 cm_user_t *smb_FindCMUserByName(/*smb_vc_t *vcp,*/ char *usern, char *machine)
6456 smb_username_t *unp;
6458 unp = smb_FindUserByName(usern, machine, SMB_FLAG_CREATE);
6460 lock_ObtainMutex(&unp->mx);
6461 unp->userp = cm_NewUser();
6462 lock_ReleaseMutex(&unp->mx);
6463 osi_Log2(smb_logp,"smb_FindCMUserByName New user name[%s] machine[%s]",osi_LogSaveString(smb_logp,usern),osi_LogSaveString(smb_logp,machine));
6464 osi_LogEvent("AFS smb_FindCMUserByName : New User",NULL,"name[%s] machine[%s]",usern,machine);
6466 osi_Log2(smb_logp,"smb_FindCMUserByName Not found name[%s] machine[%s]",osi_LogSaveString(smb_logp,usern),osi_LogSaveString(smb_logp,machine));
6467 osi_LogEvent("AFS smb_FindCMUserByName : Found",NULL,"name[%s] machine[%s]",usern,machine);