#ifndef DJGPP
#include <windows.h>
+#include <ntstatus.h>
+#define SECURITY_WIN32
+#include <security.h>
+#include <lmaccess.h>
#endif /* !DJGPP */
#include <stdlib.h>
#include <malloc.h>
#include <string.h>
#include <stdio.h>
#include <time.h>
-
#include <osi.h>
#include "afsd.h"
+#include <WINNT\afsreg.h>
#include "smb.h"
-extern smb_vc_t *dead_vcp;
-
extern osi_hyper_t hzero;
smb_packet_t *smb_Directory_Watches = NULL;
smb_tran2Dispatch_t smb_tran2DispatchTable[SMB_TRAN2_NOPCODES];
+smb_tran2Dispatch_t smb_rapDispatchTable[SMB_RAP_NOPCODES];
+
/* protected by the smb_globalLock */
smb_tran2Packet_t *smb_tran2AssemblyQueuep;
* request */
cm_user_t *smb_GetTran2User(smb_vc_t *vcp, smb_tran2Packet_t *inp)
{
- smb_user_t *uidp;
- cm_user_t *up = NULL;
+ smb_user_t *uidp;
+ cm_user_t *up = NULL;
- uidp = smb_FindUID(vcp, inp->uid, 0);
- if (!uidp) return NULL;
+ uidp = smb_FindUID(vcp, inp->uid, 0);
+ if (!uidp)
+ return NULL;
- lock_ObtainMutex(&uidp->mx);
- if (uidp->unp) {
- up = uidp->unp->userp;
- cm_HoldUser(up);
- }
- lock_ReleaseMutex(&uidp->mx);
+ lock_ObtainMutex(&uidp->mx);
+ if (uidp->unp) {
+ up = uidp->unp->userp;
+ cm_HoldUser(up);
+ }
+ lock_ReleaseMutex(&uidp->mx);
- smb_ReleaseUID(uidp);
-
- return up;
+ smb_ReleaseUID(uidp);
+
+ return up;
}
/*
*/
unsigned long smb_ExtAttributes(cm_scache_t *scp)
{
- unsigned long attrs;
-
- if (scp->fileType == CM_SCACHETYPE_DIRECTORY
- || scp->fileType == CM_SCACHETYPE_MOUNTPOINT)
- attrs = SMB_ATTR_DIRECTORY;
- else
- attrs = 0;
- /*
- * We used to mark a file RO if it was in an RO volume, but that
- * turns out to be impolitic in NT. See defect 10007.
- */
+ unsigned long attrs;
+
+ if (scp->fileType == CM_SCACHETYPE_DIRECTORY ||
+ scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
+ scp->fileType == CM_SCACHETYPE_INVALID)
+ {
+ attrs = SMB_ATTR_DIRECTORY;
+#ifdef SPECIAL_FOLDERS
+ attrs |= SMB_ATTR_SYSTEM; /* FILE_ATTRIBUTE_SYSTEM */
+#endif /* SPECIAL_FOLDERS */
+ } else if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
+ attrs = SMB_ATTR_DIRECTORY | SMB_ATTR_SPARSE_FILE;
+ } else
+ attrs = 0;
+ /*
+ * We used to mark a file RO if it was in an RO volume, but that
+ * turns out to be impolitic in NT. See defect 10007.
+ */
#ifdef notdef
- if ((scp->unixModeBits & 0222) == 0 || (scp->flags & CM_SCACHEFLAG_RO))
+ if ((scp->unixModeBits & 0222) == 0 || (scp->flags & CM_SCACHEFLAG_RO))
+ attrs |= SMB_ATTR_READONLY; /* Read-only */
+#else
+ if ((scp->unixModeBits & 0222) == 0)
+ attrs |= SMB_ATTR_READONLY; /* Read-only */
#endif
- if ((scp->unixModeBits & 0222) == 0)
- attrs |= SMB_ATTR_READONLY; /* Read-only */
- if (attrs == 0)
- attrs = SMB_ATTR_NORMAL; /* FILE_ATTRIBUTE_NORMAL */
+ if (attrs == 0)
+ attrs = SMB_ATTR_NORMAL; /* FILE_ATTRIBUTE_NORMAL */
- return attrs;
+ return attrs;
}
int smb_V3IsStarMask(char *maskp)
{
- char tc;
+ char tc;
- while (tc = *maskp++)
- if (tc == '?' || tc == '*') return 1;
- return 0;
+ while (tc = *maskp++)
+ if (tc == '?' || tc == '*' || tc == '<' || tc == '>')
+ return 1;
+ return 0;
}
unsigned char *smb_ParseString(unsigned char *inp, char **chainpp)
{
- if (chainpp) {
- /* skip over null-terminated string */
- *chainpp = inp + strlen(inp) + 1;
+ if (chainpp) {
+ /* skip over null-terminated string */
+ *chainpp = inp + strlen(inp) + 1;
+ }
+ return inp;
+}
+
+void OutputDebugF(char * format, ...) {
+ va_list args;
+ int len;
+ char * buffer;
+
+ va_start( args, format );
+ len = _vscprintf( format, args ) // _vscprintf doesn't count
+ + 3; // terminating '\0' + '\n'
+ buffer = malloc( len * sizeof(char) );
+ vsprintf( buffer, format, args );
+ osi_Log0(smb_logp, osi_LogSaveString(smb_logp, buffer));
+ strcat(buffer, "\n");
+ OutputDebugString(buffer);
+ free( buffer );
+}
+
+void OutputDebugHexDump(unsigned char * buffer, int len) {
+ int i,j,k;
+ char buf[256];
+ static char tr[16] = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
+
+ OutputDebugF("Hexdump length [%d]",len);
+
+ for (i=0;i<len;i++) {
+ if(!(i%16)) {
+ if(i) {
+ osi_Log0(smb_logp, osi_LogSaveString(smb_logp, buf));
+ strcat(buf,"\n");
+ OutputDebugString(buf);
+ }
+ sprintf(buf,"%5x",i);
+ memset(buf+5,' ',80);
+ buf[85] = 0;
+ }
+
+ j = (i%16);
+ j = j*3 + 7 + ((j>7)?1:0);
+ k = buffer[i];
+
+ buf[j] = tr[k / 16]; buf[j+1] = tr[k % 16];
+
+ j = (i%16);
+ j = j + 56 + ((j>7)?1:0);
+
+ buf[j] = (k>32 && k<127)?k:'.';
+ }
+ if(i) {
+ osi_Log0(smb_logp, osi_LogSaveString(smb_logp, buf));
+ strcat(buf,"\n");
+ OutputDebugString(buf);
+ }
+}
+
+#define SMB_EXT_SEC_PACKAGE_NAME "Negotiate"
+
+void smb_NegotiateExtendedSecurity(void ** secBlob, int * secBlobLength) {
+ SECURITY_STATUS status, istatus;
+ CredHandle creds = {0,0};
+ TimeStamp expiry;
+ SecBufferDesc secOut;
+ SecBuffer secTok;
+ CtxtHandle ctx;
+ ULONG flags;
+
+ *secBlob = NULL;
+ *secBlobLength = 0;
+
+ OutputDebugF("Negotiating Extended Security");
+
+ status = AcquireCredentialsHandle( NULL,
+ SMB_EXT_SEC_PACKAGE_NAME,
+ SECPKG_CRED_INBOUND,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ &creds,
+ &expiry);
+
+ if (status != SEC_E_OK) {
+ /* Really bad. We return an empty security blob */
+ OutputDebugF("AcquireCredentialsHandle failed with %lX", status);
+ goto nes_0;
+ }
+
+ secOut.cBuffers = 1;
+ secOut.pBuffers = &secTok;
+ secOut.ulVersion = SECBUFFER_VERSION;
+
+ secTok.BufferType = SECBUFFER_TOKEN;
+ secTok.cbBuffer = 0;
+ secTok.pvBuffer = NULL;
+
+ ctx.dwLower = ctx.dwUpper = 0;
+
+ status = AcceptSecurityContext( &creds,
+ NULL,
+ NULL,
+ ASC_REQ_CONNECTION | ASC_REQ_EXTENDED_ERROR | ASC_REQ_ALLOCATE_MEMORY,
+ SECURITY_NETWORK_DREP,
+ &ctx,
+ &secOut,
+ &flags,
+ &expiry
+ );
+
+ if (status == SEC_I_COMPLETE_NEEDED || status == SEC_I_COMPLETE_AND_CONTINUE) {
+ OutputDebugF("Completing token...");
+ istatus = CompleteAuthToken(&ctx, &secOut);
+ if ( istatus != SEC_E_OK )
+ OutputDebugF("Token completion failed: %x", istatus);
+ }
+
+ if (status == SEC_I_COMPLETE_AND_CONTINUE || status == SEC_I_CONTINUE_NEEDED) {
+ if (secTok.pvBuffer) {
+ *secBlobLength = secTok.cbBuffer;
+ *secBlob = malloc( secTok.cbBuffer );
+ memcpy(*secBlob, secTok.pvBuffer, secTok.cbBuffer );
+ }
+ } else {
+ if ( status != SEC_E_OK )
+ OutputDebugF("AcceptSecurityContext status != CONTINUE %lX", status);
+ }
+
+ /* Discard partial security context */
+ DeleteSecurityContext(&ctx);
+
+ if (secTok.pvBuffer) FreeContextBuffer( secTok.pvBuffer );
+
+ /* Discard credentials handle. We'll reacquire one when we get the session setup X */
+ FreeCredentialsHandle(&creds);
+
+ nes_0:
+ return;
+}
+
+struct smb_ext_context {
+ CredHandle creds;
+ CtxtHandle ctx;
+ int partialTokenLen;
+ void * partialToken;
+};
+
+long smb_AuthenticateUserExt(smb_vc_t * vcp, char * usern, char * secBlobIn, int secBlobInLength, char ** secBlobOut, int * secBlobOutLength) {
+ SECURITY_STATUS status, istatus;
+ CredHandle creds;
+ TimeStamp expiry;
+ long code = 0;
+ SecBufferDesc secBufIn;
+ SecBuffer secTokIn;
+ SecBufferDesc secBufOut;
+ SecBuffer secTokOut;
+ CtxtHandle ctx;
+ struct smb_ext_context * secCtx = NULL;
+ struct smb_ext_context * newSecCtx = NULL;
+ void * assembledBlob = NULL;
+ int assembledBlobLength = 0;
+ ULONG flags;
+
+ OutputDebugF("In smb_AuthenticateUserExt");
+
+ *secBlobOut = NULL;
+ *secBlobOutLength = 0;
+
+ if (vcp->flags & SMB_VCFLAG_AUTH_IN_PROGRESS) {
+ secCtx = vcp->secCtx;
+ lock_ObtainMutex(&vcp->mx);
+ vcp->flags &= ~SMB_VCFLAG_AUTH_IN_PROGRESS;
+ vcp->secCtx = NULL;
+ lock_ReleaseMutex(&vcp->mx);
+ }
+
+ if (secBlobIn) {
+ OutputDebugF("Received incoming token:");
+ OutputDebugHexDump(secBlobIn,secBlobInLength);
+ }
+
+ if (secCtx) {
+ OutputDebugF("Continuing with existing context.");
+ creds = secCtx->creds;
+ ctx = secCtx->ctx;
+
+ if (secCtx->partialToken) {
+ assembledBlobLength = secCtx->partialTokenLen + secBlobInLength;
+ assembledBlob = malloc(assembledBlobLength);
+ memcpy(assembledBlob,secCtx->partialToken, secCtx->partialTokenLen);
+ memcpy(((BYTE *)assembledBlob) + secCtx->partialTokenLen, secBlobIn, secBlobInLength);
+ }
+ } else {
+ status = AcquireCredentialsHandle( NULL,
+ SMB_EXT_SEC_PACKAGE_NAME,
+ SECPKG_CRED_INBOUND,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ &creds,
+ &expiry);
+
+ if (status != SEC_E_OK) {
+ OutputDebugF("Can't acquire Credentials handle [%lX]", status);
+ code = CM_ERROR_BADPASSWORD; /* means "try again when I'm sober" */
+ goto aue_0;
+ }
+
+ ctx.dwLower = 0;
+ ctx.dwUpper = 0;
+ }
+
+ secBufIn.cBuffers = 1;
+ secBufIn.pBuffers = &secTokIn;
+ secBufIn.ulVersion = SECBUFFER_VERSION;
+
+ secTokIn.BufferType = SECBUFFER_TOKEN;
+ if (assembledBlob) {
+ secTokIn.cbBuffer = assembledBlobLength;
+ secTokIn.pvBuffer = assembledBlob;
+ } else {
+ secTokIn.cbBuffer = secBlobInLength;
+ secTokIn.pvBuffer = secBlobIn;
+ }
+
+ secBufOut.cBuffers = 1;
+ secBufOut.pBuffers = &secTokOut;
+ secBufOut.ulVersion = SECBUFFER_VERSION;
+
+ secTokOut.BufferType = SECBUFFER_TOKEN;
+ secTokOut.cbBuffer = 0;
+ secTokOut.pvBuffer = NULL;
+
+ status = AcceptSecurityContext( &creds,
+ ((secCtx)?&ctx:NULL),
+ &secBufIn,
+ ASC_REQ_CONNECTION | ASC_REQ_EXTENDED_ERROR | ASC_REQ_ALLOCATE_MEMORY,
+ SECURITY_NETWORK_DREP,
+ &ctx,
+ &secBufOut,
+ &flags,
+ &expiry
+ );
+
+ if (status == SEC_I_COMPLETE_NEEDED || status == SEC_I_COMPLETE_AND_CONTINUE) {
+ OutputDebugF("Completing token...");
+ istatus = CompleteAuthToken(&ctx, &secBufOut);
+ if ( istatus != SEC_E_OK )
+ OutputDebugF("Token completion failed: %lX", istatus);
+ }
+
+ if (status == SEC_I_COMPLETE_AND_CONTINUE || status == SEC_I_CONTINUE_NEEDED) {
+ OutputDebugF("Continue needed");
+
+ newSecCtx = malloc(sizeof(*newSecCtx));
+
+ newSecCtx->creds = creds;
+ newSecCtx->ctx = ctx;
+ newSecCtx->partialToken = NULL;
+ newSecCtx->partialTokenLen = 0;
+
+ lock_ObtainMutex( &vcp->mx );
+ vcp->flags |= SMB_VCFLAG_AUTH_IN_PROGRESS;
+ vcp->secCtx = newSecCtx;
+ lock_ReleaseMutex( &vcp->mx );
+
+ code = CM_ERROR_GSSCONTINUE;
+ }
+
+ if ((status == SEC_I_COMPLETE_NEEDED || status == SEC_E_OK ||
+ status == SEC_I_COMPLETE_AND_CONTINUE || status == SEC_I_CONTINUE_NEEDED) &&
+ secTokOut.pvBuffer) {
+ OutputDebugF("Need to send token back to client");
+
+ *secBlobOutLength = secTokOut.cbBuffer;
+ *secBlobOut = malloc(secTokOut.cbBuffer);
+ memcpy(*secBlobOut, secTokOut.pvBuffer, secTokOut.cbBuffer);
+
+ OutputDebugF("Outgoing token:");
+ OutputDebugHexDump(*secBlobOut,*secBlobOutLength);
+ } else if (status == SEC_E_INCOMPLETE_MESSAGE) {
+ OutputDebugF("Incomplete message");
+
+ newSecCtx = malloc(sizeof(*newSecCtx));
+
+ newSecCtx->creds = creds;
+ newSecCtx->ctx = ctx;
+ newSecCtx->partialToken = malloc(secTokOut.cbBuffer);
+ memcpy(newSecCtx->partialToken, secTokOut.pvBuffer, secTokOut.cbBuffer);
+ newSecCtx->partialTokenLen = secTokOut.cbBuffer;
+
+ lock_ObtainMutex( &vcp->mx );
+ vcp->flags |= SMB_VCFLAG_AUTH_IN_PROGRESS;
+ vcp->secCtx = newSecCtx;
+ lock_ReleaseMutex( &vcp->mx );
+
+ code = CM_ERROR_GSSCONTINUE;
+ }
+
+ if (status == SEC_E_OK || status == SEC_I_COMPLETE_NEEDED) {
+ /* woo hoo! */
+ SecPkgContext_Names names;
+
+ OutputDebugF("Authentication completed");
+ OutputDebugF("Returned flags : [%lX]", flags);
+
+ if (!QueryContextAttributes(&ctx, SECPKG_ATTR_NAMES, &names)) {
+ OutputDebugF("Received name [%s]", names.sUserName);
+ strcpy(usern, names.sUserName);
+ strlwr(usern); /* in tandem with smb_GetNormalizedUsername */
+ FreeContextBuffer(names.sUserName);
+ } else {
+ /* Force the user to retry if the context is invalid */
+ OutputDebugF("QueryContextAttributes Names failed [%x]", GetLastError());
+ code = CM_ERROR_BADPASSWORD;
+ }
+ } else if (!code) {
+ switch ( status ) {
+ case SEC_E_INVALID_TOKEN:
+ OutputDebugF("Returning bad password :: INVALID_TOKEN");
+ break;
+ case SEC_E_INVALID_HANDLE:
+ OutputDebugF("Returning bad password :: INVALID_HANDLE");
+ break;
+ case SEC_E_LOGON_DENIED:
+ OutputDebugF("Returning bad password :: LOGON_DENIED");
+ break;
+ case SEC_E_UNKNOWN_CREDENTIALS:
+ OutputDebugF("Returning bad password :: UNKNOWN_CREDENTIALS");
+ break;
+ case SEC_E_NO_CREDENTIALS:
+ OutputDebugF("Returning bad password :: NO_CREDENTIALS");
+ break;
+ case SEC_E_CONTEXT_EXPIRED:
+ OutputDebugF("Returning bad password :: CONTEXT_EXPIRED");
+ break;
+ case SEC_E_INCOMPLETE_CREDENTIALS:
+ OutputDebugF("Returning bad password :: INCOMPLETE_CREDENTIALS");
+ break;
+ case SEC_E_WRONG_PRINCIPAL:
+ OutputDebugF("Returning bad password :: WRONG_PRINCIPAL");
+ break;
+ case SEC_E_TIME_SKEW:
+ OutputDebugF("Returning bad password :: TIME_SKEW");
+ break;
+ default:
+ OutputDebugF("Returning bad password :: Status == %lX", status);
}
- return inp;
+ code = CM_ERROR_BADPASSWORD;
+ }
+
+ if (secCtx) {
+ if (secCtx->partialToken) free(secCtx->partialToken);
+ free(secCtx);
+ }
+
+ if (assembledBlob) {
+ free(assembledBlob);
+ }
+
+ if (secTokOut.pvBuffer)
+ FreeContextBuffer(secTokOut.pvBuffer);
+
+ if (code != CM_ERROR_GSSCONTINUE) {
+ DeleteSecurityContext(&ctx);
+ FreeCredentialsHandle(&creds);
+ }
+
+ aue_0:
+ return code;
+}
+
+#define P_LEN 256
+#define P_RESP_LEN 128
+
+/* LsaLogonUser expects input parameters to be in a contiguous block of memory.
+ So put stuff in a struct. */
+struct Lm20AuthBlob {
+ MSV1_0_LM20_LOGON lmlogon;
+ BYTE ciResponse[P_RESP_LEN]; /* Unicode representation */
+ BYTE csResponse[P_RESP_LEN]; /* ANSI representation */
+ WCHAR accountNameW[P_LEN];
+ WCHAR primaryDomainW[P_LEN];
+ WCHAR workstationW[MAX_COMPUTERNAME_LENGTH + 1];
+ TOKEN_GROUPS tgroups;
+ TOKEN_SOURCE tsource;
+};
+
+long smb_AuthenticateUserLM(smb_vc_t *vcp, char * accountName, char * primaryDomain, char * ciPwd, unsigned ciPwdLength, char * csPwd, unsigned csPwdLength)
+{
+ NTSTATUS nts, ntsEx;
+ struct Lm20AuthBlob lmAuth;
+ PMSV1_0_LM20_LOGON_PROFILE lmprofilep;
+ QUOTA_LIMITS quotaLimits;
+ DWORD size;
+ ULONG lmprofilepSize;
+ LUID lmSession;
+ HANDLE lmToken;
+
+ OutputDebugF("In smb_AuthenticateUser for user [%s] domain [%s]", accountName, primaryDomain);
+ OutputDebugF("ciPwdLength is %d and csPwdLength is %d", ciPwdLength, csPwdLength);
+
+ if (ciPwdLength > P_RESP_LEN || csPwdLength > P_RESP_LEN) {
+ OutputDebugF("ciPwdLength or csPwdLength is too long");
+ return CM_ERROR_BADPASSWORD;
+ }
+
+ memset(&lmAuth,0,sizeof(lmAuth));
+
+ lmAuth.lmlogon.MessageType = MsV1_0NetworkLogon;
+
+ lmAuth.lmlogon.LogonDomainName.Buffer = lmAuth.primaryDomainW;
+ mbstowcs(lmAuth.primaryDomainW, primaryDomain, P_LEN);
+ lmAuth.lmlogon.LogonDomainName.Length = (USHORT)(wcslen(lmAuth.primaryDomainW) * sizeof(WCHAR));
+ lmAuth.lmlogon.LogonDomainName.MaximumLength = P_LEN * sizeof(WCHAR);
+
+ lmAuth.lmlogon.UserName.Buffer = lmAuth.accountNameW;
+ mbstowcs(lmAuth.accountNameW, accountName, P_LEN);
+ lmAuth.lmlogon.UserName.Length = (USHORT)(wcslen(lmAuth.accountNameW) * sizeof(WCHAR));
+ lmAuth.lmlogon.UserName.MaximumLength = P_LEN * sizeof(WCHAR);
+
+ lmAuth.lmlogon.Workstation.Buffer = lmAuth.workstationW;
+ lmAuth.lmlogon.Workstation.MaximumLength = (MAX_COMPUTERNAME_LENGTH + 1) * sizeof(WCHAR);
+ size = MAX_COMPUTERNAME_LENGTH + 1;
+ GetComputerNameW(lmAuth.workstationW, &size);
+ lmAuth.lmlogon.Workstation.Length = (USHORT)(wcslen(lmAuth.workstationW) * sizeof(WCHAR));
+
+ memcpy(lmAuth.lmlogon.ChallengeToClient, vcp->encKey, MSV1_0_CHALLENGE_LENGTH);
+
+ lmAuth.lmlogon.CaseInsensitiveChallengeResponse.Buffer = lmAuth.ciResponse;
+ lmAuth.lmlogon.CaseInsensitiveChallengeResponse.Length = ciPwdLength;
+ lmAuth.lmlogon.CaseInsensitiveChallengeResponse.MaximumLength = P_RESP_LEN;
+ memcpy(lmAuth.ciResponse, ciPwd, ciPwdLength);
+
+ lmAuth.lmlogon.CaseSensitiveChallengeResponse.Buffer = lmAuth.csResponse;
+ lmAuth.lmlogon.CaseSensitiveChallengeResponse.Length = csPwdLength;
+ lmAuth.lmlogon.CaseSensitiveChallengeResponse.MaximumLength = P_RESP_LEN;
+ memcpy(lmAuth.csResponse, csPwd, csPwdLength);
+
+ lmAuth.lmlogon.ParameterControl = 0;
+
+ lmAuth.tgroups.GroupCount = 0;
+ lmAuth.tgroups.Groups[0].Sid = NULL;
+ lmAuth.tgroups.Groups[0].Attributes = 0;
+
+ lmAuth.tsource.SourceIdentifier.HighPart = (DWORD)((LONG_PTR)vcp << 32);
+ lmAuth.tsource.SourceIdentifier.LowPart = (DWORD)((LONG_PTR)vcp & _UI32_MAX);
+ strcpy(lmAuth.tsource.SourceName,"OpenAFS"); /* 8 char limit */
+
+ nts = LsaLogonUser( smb_lsaHandle,
+ &smb_lsaLogonOrigin,
+ Network, /*3*/
+ smb_lsaSecPackage,
+ &lmAuth,
+ sizeof(lmAuth),
+ &lmAuth.tgroups,
+ &lmAuth.tsource,
+ &lmprofilep,
+ &lmprofilepSize,
+ &lmSession,
+ &lmToken,
+ "aLimits,
+ &ntsEx);
+
+ if (nts != STATUS_SUCCESS || ntsEx != STATUS_SUCCESS)
+ osi_Log2(smb_logp,"LsaLogonUser failure: nts %u ntsEx %u",
+ nts, ntsEx);
+
+ OutputDebugF("Return from LsaLogonUser is 0x%lX", nts);
+ OutputDebugF("Extended status is 0x%lX", ntsEx);
+
+ if (nts == ERROR_SUCCESS) {
+ /* free the token */
+ LsaFreeReturnBuffer(lmprofilep);
+ CloseHandle(lmToken);
+ return 0;
+ } else {
+ /* No AFS for you */
+ if (nts == 0xC000015BL)
+ return CM_ERROR_BADLOGONTYPE;
+ else /* our catchall is a bad password though we could be more specific */
+ return CM_ERROR_BADPASSWORD;
+ }
+}
+
+/* The buffer pointed to by usern is assumed to be at least SMB_MAX_USERNAME_LENGTH bytes */
+long smb_GetNormalizedUsername(char * usern, const char * accountName, const char * domainName)
+{
+ char * atsign;
+ const char * domain;
+
+ /* check if we have sane input */
+ if ((strlen(accountName) + strlen(domainName) + 1) > SMB_MAX_USERNAME_LENGTH)
+ return 1;
+
+ /* we could get : [accountName][domainName]
+ [user][domain]
+ [user@domain][]
+ [user][]/[user][?]
+ [][]/[][?] */
+
+ atsign = strchr(accountName, '@');
+
+ if (atsign) /* [user@domain][] -> [user@domain][domain] */
+ domain = atsign + 1;
+ else
+ domain = domainName;
+
+ /* if for some reason the client doesn't know what domain to use,
+ it will either return an empty string or a '?' */
+ if (!domain[0] || domain[0] == '?')
+ /* Empty domains and empty usernames are usually sent from tokenless contexts.
+ This way such logins will get an empty username (easy to check). I don't know
+ when a non-empty username would be supplied with an anonymous domain, but *shrug* */
+ strcpy(usern,accountName);
+ else {
+ /* TODO: what about WIN.MIT.EDU\user vs. WIN\user? */
+ strcpy(usern,domain);
+ strcat(usern,"\\");
+ if (atsign)
+ strncat(usern,accountName,atsign - accountName);
+ else
+ strcat(usern,accountName);
+ }
+
+ strlwr(usern);
+
+ return 0;
}
+/* When using SMB auth, all SMB sessions have to pass through here
+ * first to authenticate the user.
+ *
+ * Caveat: If not using SMB auth, the protocol does not require
+ * sending a session setup packet, which means that we can't rely on a
+ * UID in subsequent packets. Though in practice we get one anyway.
+ */
long smb_ReceiveV3SessionSetupX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
{
char *tp;
- char *usern, *pwd, *pwdx;
- smb_user_t *uidp, *dead_uidp;
+ smb_user_t *uidp;
unsigned short newUid;
- unsigned long caps;
+ unsigned long caps = 0;
cm_user_t *userp;
smb_username_t *unp;
char *s1 = " ";
+ long code = 0;
+ char usern[SMB_MAX_USERNAME_LENGTH];
+ char *secBlobOut = NULL;
+ int secBlobOutLength = 0;
/* Check for bad conns */
if (vcp->flags & SMB_VCFLAG_REMOTECONN)
return CM_ERROR_REMOTECONN;
- /* For NT LM 0.12 and up, get capabilities */
if (vcp->flags & SMB_VCFLAG_USENT) {
- caps = smb_GetSMBParm(inp, 11);
- if (caps & 0x40)
+ if (smb_authType == SMB_AUTH_EXTENDED) {
+ /* extended authentication */
+ char *secBlobIn;
+ int secBlobInLength;
+
+ OutputDebugF("NT Session Setup: Extended");
+
+ if (!(vcp->flags & SMB_VCFLAG_SESSX_RCVD)) {
+ caps = smb_GetSMBParm(inp,10) | (((unsigned long) smb_GetSMBParm(inp,11)) << 16);
+ }
+
+ secBlobInLength = smb_GetSMBParm(inp, 7);
+ secBlobIn = smb_GetSMBData(inp, NULL);
+
+ code = smb_AuthenticateUserExt(vcp, usern, secBlobIn, secBlobInLength, &secBlobOut, &secBlobOutLength);
+
+ if (code == CM_ERROR_GSSCONTINUE) {
+ smb_SetSMBParm(outp, 2, 0);
+ smb_SetSMBParm(outp, 3, secBlobOutLength);
+ smb_SetSMBDataLength(outp, secBlobOutLength + smb_ServerOSLength + smb_ServerLanManagerLength + smb_ServerDomainNameLength);
+ tp = smb_GetSMBData(outp, NULL);
+ if (secBlobOutLength) {
+ memcpy(tp, secBlobOut, secBlobOutLength);
+ free(secBlobOut);
+ tp += secBlobOutLength;
+ }
+ memcpy(tp,smb_ServerOS,smb_ServerOSLength);
+ tp += smb_ServerOSLength;
+ memcpy(tp,smb_ServerLanManager,smb_ServerLanManagerLength);
+ tp += smb_ServerLanManagerLength;
+ memcpy(tp,smb_ServerDomainName,smb_ServerDomainNameLength);
+ tp += smb_ServerDomainNameLength;
+ }
+
+ /* TODO: handle return code and continue auth. Also free secBlobOut if applicable. */
+ } else {
+ unsigned ciPwdLength, csPwdLength;
+ char *ciPwd, *csPwd;
+ char *accountName;
+ char *primaryDomain;
+ int datalen;
+
+ if (smb_authType == SMB_AUTH_NTLM)
+ OutputDebugF("NT Session Setup: NTLM");
+ else
+ OutputDebugF("NT Session Setup: None");
+
+ /* TODO: parse for extended auth as well */
+ ciPwdLength = smb_GetSMBParm(inp, 7); /* case insensitive password length */
+ csPwdLength = smb_GetSMBParm(inp, 8); /* case sensitive password length */
+
+ tp = smb_GetSMBData(inp, &datalen);
+
+ OutputDebugF("Session packet data size [%d]",datalen);
+
+ ciPwd = tp;
+ tp += ciPwdLength;
+ csPwd = tp;
+ tp += csPwdLength;
+
+ accountName = smb_ParseString(tp, &tp);
+ primaryDomain = smb_ParseString(tp, NULL);
+
+ OutputDebugF("Account Name: %s",accountName);
+ OutputDebugF("Primary Domain: %s", primaryDomain);
+ OutputDebugF("Case Sensitive Password: %s", csPwd && csPwd[0] ? "yes" : "no");
+ OutputDebugF("Case Insensitive Password: %s", ciPwd && ciPwd[0] ? "yes" : "no");
+
+ if (smb_GetNormalizedUsername(usern, accountName, primaryDomain)) {
+ /* shouldn't happen */
+ code = CM_ERROR_BADSMB;
+ goto after_read_packet;
+ }
+
+ /* capabilities are only valid for first session packet */
+ if (!(vcp->flags & SMB_VCFLAG_SESSX_RCVD)) {
+ caps = smb_GetSMBParm(inp, 11) | (((unsigned long)smb_GetSMBParm(inp, 12)) << 16);
+ }
+
+ if (smb_authType == SMB_AUTH_NTLM) {
+ code = smb_AuthenticateUserLM(vcp, accountName, primaryDomain, ciPwd, ciPwdLength, csPwd, csPwdLength);
+ if ( code )
+ OutputDebugF("LM authentication failed [%d]", code);
+ else
+ OutputDebugF("LM authentication succeeded");
+ }
+ }
+ } else { /* V3 */
+ unsigned ciPwdLength;
+ char *ciPwd;
+ char *accountName;
+ char *primaryDomain;
+
+ switch ( smb_authType ) {
+ case SMB_AUTH_EXTENDED:
+ OutputDebugF("V3 Session Setup: Extended");
+ break;
+ case SMB_AUTH_NTLM:
+ OutputDebugF("V3 Session Setup: NTLM");
+ break;
+ default:
+ OutputDebugF("V3 Session Setup: None");
+ }
+ ciPwdLength = smb_GetSMBParm(inp, 7);
+ tp = smb_GetSMBData(inp, NULL);
+ ciPwd = tp;
+ tp += ciPwdLength;
+
+ accountName = smb_ParseString(tp, &tp);
+ primaryDomain = smb_ParseString(tp, NULL);
+
+ OutputDebugF("Account Name: %s",accountName);
+ OutputDebugF("Primary Domain: %s", primaryDomain);
+ OutputDebugF("Case Insensitive Password: %s", ciPwd && ciPwd[0] ? "yes" : "no");
+
+ if ( smb_GetNormalizedUsername(usern, accountName, primaryDomain)) {
+ /* shouldn't happen */
+ code = CM_ERROR_BADSMB;
+ goto after_read_packet;
+ }
+
+ /* even if we wanted extended auth, if we only negotiated V3, we have to fallback
+ * to NTLM.
+ */
+ if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
+ code = smb_AuthenticateUserLM(vcp,accountName,primaryDomain,ciPwd,ciPwdLength,"",0);
+ if ( code )
+ OutputDebugF("LM authentication failed [%d]", code);
+ else
+ OutputDebugF("LM authentication succeeded");
+ }
+ }
+
+ after_read_packet:
+ /* note down that we received a session setup X and set the capabilities flag */
+ if (!(vcp->flags & SMB_VCFLAG_SESSX_RCVD)) {
+ lock_ObtainMutex(&vcp->mx);
+ vcp->flags |= SMB_VCFLAG_SESSX_RCVD;
+ /* for the moment we can only deal with NTSTATUS */
+ if (caps & NTNEGOTIATE_CAPABILITY_NTSTATUS) {
vcp->flags |= SMB_VCFLAG_STATUS32;
- /* for now, ignore other capability bits */
+ }
+ lock_ReleaseMutex(&vcp->mx);
}
- /* Parse the data */
- tp = smb_GetSMBData(inp, NULL);
- if (vcp->flags & SMB_VCFLAG_USENT)
- pwdx = smb_ParseString(tp, &tp);
- pwd = smb_ParseString(tp, &tp);
- usern = smb_ParseString(tp, &tp);
+ /* code would be non-zero if there was an authentication failure.
+ Ideally we would like to invalidate the uid for this session or break
+ early to avoid accidently stealing someone else's tokens. */
+
+ if (code) {
+ return code;
+ }
+
+ OutputDebugF("Received username=[%s]", usern);
/* On Windows 2000, this function appears to be called more often than
it is expected to be called. This resulted in multiple smb_user_t
if (uidp) { /* already there, so don't create a new one */
unp = uidp->unp;
userp = unp->userp;
- newUid = (unsigned short)uidp->userID; /* For some reason these are different types!*/
- osi_LogEvent("AFS smb_ReceiveV3SessionSetupX",NULL,"FindUserByName:Lana[%d],lsn[%d],userid[%d],name[%s]",vcp->lana,vcp->lsn,newUid,usern);
- osi_Log3(afsd_logp,"smb_ReceiveV3SessionSetupX FindUserByName:Lana[%d],lsn[%d],userid[%d]",vcp->lana,vcp->lsn,newUid);
+ newUid = uidp->userID;
+ osi_Log3(smb_logp,"smb_ReceiveV3SessionSetupX FindUserByName:Lana[%d],lsn[%d],userid[%d]",vcp->lana,vcp->lsn,newUid);
smb_ReleaseUID(uidp);
}
else {
/* Create a new UID and cm_user_t structure */
userp = unp->userp;
if (!userp)
- userp = cm_NewUser();
+ userp = cm_NewUser();
lock_ObtainMutex(&vcp->mx);
- if(!vcp->uidCounter) vcp->uidCounter++; /* handle unlikely wraparounds */
- newUid = (strlen(usern)==0)?0:vcp->uidCounter++;
- lock_ReleaseMutex(&vcp->mx);
+ if (!vcp->uidCounter)
+ vcp->uidCounter++; /* handle unlikely wraparounds */
+ newUid = (strlen(usern)==0)?0:vcp->uidCounter++;
+ lock_ReleaseMutex(&vcp->mx);
/* Create a new smb_user_t structure and connect them up */
lock_ObtainMutex(&unp->mx);
uidp = smb_FindUID(vcp, newUid, SMB_FLAG_CREATE);
lock_ObtainMutex(&uidp->mx);
uidp->unp = unp;
- osi_LogEvent("AFS smb_ReceiveV3SessionSetupX",NULL,"MakeNewUser:VCP[%x],Lana[%d],lsn[%d],userid[%d],TicketKTCName[%s]",vcp,vcp->lana,vcp->lsn,newUid,usern);
- osi_Log4(afsd_logp,"smb_ReceiveV3SessionSetupX MakeNewUser:VCP[%x],Lana[%d],lsn[%d],userid[%d]",vcp,vcp->lana,vcp->lsn,newUid);
+ osi_Log4(smb_logp,"smb_ReceiveV3SessionSetupX MakeNewUser:VCP[%p],Lana[%d],lsn[%d],userid[%d]",vcp,vcp->lana,vcp->lsn,newUid);
lock_ReleaseMutex(&uidp->mx);
smb_ReleaseUID(uidp);
}
/* Also to the next chained message */
((smb_t *)inp)->uid = newUid;
- osi_Log3(afsd_logp, "SMB3 session setup name %s creating ID %d%s",
- osi_LogSaveString(afsd_logp, usern), newUid, osi_LogSaveString(afsd_logp, s1));
+ osi_Log3(smb_logp, "SMB3 session setup name %s creating ID %d%s",
+ osi_LogSaveString(smb_logp, usern), newUid, osi_LogSaveString(smb_logp, s1));
+
smb_SetSMBParm(outp, 2, 0);
- smb_SetSMBDataLength(outp, 0);
+
+ if (vcp->flags & SMB_VCFLAG_USENT) {
+ if (smb_authType == SMB_AUTH_EXTENDED) {
+ smb_SetSMBParm(outp, 3, secBlobOutLength);
+ smb_SetSMBDataLength(outp, secBlobOutLength + smb_ServerOSLength + smb_ServerLanManagerLength + smb_ServerDomainNameLength);
+ tp = smb_GetSMBData(outp, NULL);
+ if (secBlobOutLength) {
+ memcpy(tp, secBlobOut, secBlobOutLength);
+ free(secBlobOut);
+ tp += secBlobOutLength;
+ }
+ memcpy(tp,smb_ServerOS,smb_ServerOSLength);
+ tp += smb_ServerOSLength;
+ memcpy(tp,smb_ServerLanManager,smb_ServerLanManagerLength);
+ tp += smb_ServerLanManagerLength;
+ memcpy(tp,smb_ServerDomainName,smb_ServerDomainNameLength);
+ tp += smb_ServerDomainNameLength;
+ } else {
+ smb_SetSMBDataLength(outp, 0);
+ }
+ } else {
+ if (smb_authType == SMB_AUTH_EXTENDED) {
+ smb_SetSMBDataLength(outp, smb_ServerOSLength + smb_ServerLanManagerLength + smb_ServerDomainNameLength);
+ tp = smb_GetSMBData(outp, NULL);
+ memcpy(tp,smb_ServerOS,smb_ServerOSLength);
+ tp += smb_ServerOSLength;
+ memcpy(tp,smb_ServerLanManager,smb_ServerLanManagerLength);
+ tp += smb_ServerLanManagerLength;
+ memcpy(tp,smb_ServerDomainName,smb_ServerDomainNameLength);
+ tp += smb_ServerDomainNameLength;
+ } else {
+ smb_SetSMBDataLength(outp, 0);
+ }
+ }
+
return 0;
}
long smb_ReceiveV3UserLogoffX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
{
- smb_user_t *uidp;
+ smb_user_t *uidp;
- /* don't get tokens from this VC */
- vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
+ /* don't get tokens from this VC */
+ vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
- inp->flags |= SMB_PACKETFLAG_PROFILE_UPDATE_OK;
+ inp->flags |= SMB_PACKETFLAG_PROFILE_UPDATE_OK;
- /* find the tree and free it */
- uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
- /* TODO: smb_ReleaseUID? */
- if (uidp) {
- char *s1 = NULL, *s2 = NULL;
-
- if (s2 == NULL) s2 = " ";
- if (s1 == NULL) {s1 = s2; s2 = " ";}
-
- osi_Log4(afsd_logp, "SMB3 user logoffX uid %d name %s%s%s",
- uidp->userID,
- osi_LogSaveString(afsd_logp,
- (uidp->unp) ? uidp->unp->name: " "), s1, s2);
-
- lock_ObtainMutex(&uidp->mx);
- uidp->flags |= SMB_USERFLAG_DELETE;
- /*
- * it doesn't get deleted right away
- * because the vcp points to it
- */
- lock_ReleaseMutex(&uidp->mx);
- }
- else
- osi_Log0(afsd_logp, "SMB3 user logoffX");
+ /* find the tree and free it */
+ uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
+ if (uidp) {
+ char *s1 = NULL, *s2 = NULL;
- smb_SetSMBDataLength(outp, 0);
- return 0;
+ if (s2 == NULL) s2 = " ";
+ if (s1 == NULL) {s1 = s2; s2 = " ";}
+
+ osi_Log4(smb_logp, "SMB3 user logoffX uid %d name %s%s%s", uidp->userID,
+ osi_LogSaveString(smb_logp, (uidp->unp) ? uidp->unp->name: " "),
+ osi_LogSaveString(smb_logp,s1), osi_LogSaveString(smb_logp,s2));
+
+ lock_ObtainMutex(&uidp->mx);
+ uidp->flags |= SMB_USERFLAG_DELETE;
+ /*
+ * it doesn't get deleted right away
+ * because the vcp points to it
+ */
+ lock_ReleaseMutex(&uidp->mx);
+ smb_ReleaseUID(uidp);
+ }
+ else
+ osi_Log0(smb_logp, "SMB3 user logoffX");
+
+ smb_SetSMBDataLength(outp, 0);
+ return 0;
}
+#define SMB_SUPPORT_SEARCH_BITS 0x0001
+#define SMB_SHARE_IS_IN_DFS 0x0002
+
long smb_ReceiveV3TreeConnectX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
{
- smb_tid_t *tidp;
- unsigned short newTid;
- char shareName[256];
- char *sharePath;
- int shareFound;
- char *tp;
- char *pathp;
- char *passwordp;
- char *servicep;
- cm_user_t *userp;
+ smb_tid_t *tidp;
+ smb_user_t *uidp;
+ unsigned short newTid;
+ char shareName[256];
+ char *sharePath;
+ int shareFound;
+ char *tp;
+ char *pathp;
+ char *passwordp;
+ char *servicep;
+ cm_user_t *userp;
+ int ipc = 0;
- osi_Log0(afsd_logp, "SMB3 receive tree connect");
-
- /* parse input parameters */
- tp = smb_GetSMBData(inp, NULL);
- passwordp = smb_ParseString(tp, &tp);
- pathp = smb_ParseString(tp, &tp);
- servicep = smb_ParseString(tp, &tp);
-
- tp = strrchr(pathp, '\\');
- if (!tp) {
- return CM_ERROR_BADSMB;
- }
- strcpy(shareName, tp+1);
+ osi_Log0(smb_logp, "SMB3 receive tree connect");
- if (strcmp(servicep, "IPC") == 0 || strcmp(shareName, "IPC$") == 0)
- return CM_ERROR_NOIPC;
+ /* parse input parameters */
+ tp = smb_GetSMBData(inp, NULL);
+ passwordp = smb_ParseString(tp, &tp);
+ pathp = smb_ParseString(tp, &tp);
+ if (smb_StoreAnsiFilenames)
+ OemToChar(pathp,pathp);
+ servicep = smb_ParseString(tp, &tp);
+
+ tp = strrchr(pathp, '\\');
+ if (!tp) {
+ return CM_ERROR_BADSMB;
+ }
+ strcpy(shareName, tp+1);
+
+ osi_Log2(smb_logp, "Tree connect pathp[%s] shareName[%s]",
+ osi_LogSaveString(smb_logp, pathp),
+ osi_LogSaveString(smb_logp, shareName));
+
+ if (strcmp(servicep, "IPC") == 0 || strcmp(shareName, "IPC$") == 0) {
+#ifndef NO_IPC
+ osi_Log0(smb_logp, "TreeConnectX connecting to IPC$");
+ ipc = 1;
+#else
+ return CM_ERROR_NOIPC;
+#endif
+ }
- userp = smb_GetUser(vcp, inp);
+ userp = smb_GetUser(vcp, inp);
- lock_ObtainMutex(&vcp->mx);
- newTid = vcp->tidCounter++;
- lock_ReleaseMutex(&vcp->mx);
+ lock_ObtainMutex(&vcp->mx);
+ newTid = vcp->tidCounter++;
+ lock_ReleaseMutex(&vcp->mx);
- tidp = smb_FindTID(vcp, newTid, SMB_FLAG_CREATE);
- shareFound = smb_FindShare(vcp, inp, shareName, &sharePath);
+ tidp = smb_FindTID(vcp, newTid, SMB_FLAG_CREATE);
+
+ if (!ipc) {
+ uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
+ shareFound = smb_FindShare(vcp, uidp, shareName, &sharePath);
+ if (uidp)
+ smb_ReleaseUID(uidp);
if (!shareFound) {
- smb_ReleaseTID(tidp);
- return CM_ERROR_BADSHARENAME;
+ smb_ReleaseTID(tidp);
+ return CM_ERROR_BADSHARENAME;
}
- lock_ObtainMutex(&tidp->mx);
- tidp->userp = userp;
- tidp->pathname = sharePath;
- lock_ReleaseMutex(&tidp->mx);
- smb_ReleaseTID(tidp);
if (vcp->flags & SMB_VCFLAG_USENT)
- smb_SetSMBParm(outp, 2, 0); /* OptionalSupport bits */
+ {
+ int policy = smb_FindShareCSCPolicy(shareName);
+ smb_SetSMBParm(outp, 2, SMB_SUPPORT_SEARCH_BITS |
+#ifdef DFS_SUPPORT
+ SMB_SHARE_IS_IN_DFS |
+#endif
+ (policy << 2));
+ }
+ } else {
+ smb_SetSMBParm(outp, 2, 0);
+ sharePath = NULL;
+ }
- ((smb_t *)outp)->tid = newTid;
- ((smb_t *)inp)->tid = newTid;
- tp = smb_GetSMBData(outp, NULL);
+ lock_ObtainMutex(&tidp->mx);
+ tidp->userp = userp;
+ tidp->pathname = sharePath;
+ if (ipc)
+ tidp->flags |= SMB_TIDFLAG_IPC;
+ lock_ReleaseMutex(&tidp->mx);
+ smb_ReleaseTID(tidp);
+
+ ((smb_t *)outp)->tid = newTid;
+ ((smb_t *)inp)->tid = newTid;
+ tp = smb_GetSMBData(outp, NULL);
+ if (!ipc) {
+ /* XXX - why is this a drive letter? */
*tp++ = 'A';
*tp++ = ':';
*tp++ = 0;
- smb_SetSMBDataLength(outp, 3);
-
- osi_Log1(afsd_logp, "SMB3 tree connect created ID %d", newTid);
- return 0;
+ *tp++ = 'N';
+ *tp++ = 'T';
+ *tp++ = 'F';
+ *tp++ = 'S';
+ *tp++ = 0;
+ smb_SetSMBDataLength(outp, 8);
+ } else {
+ strcpy(tp, "IPC");
+ smb_SetSMBDataLength(outp, 4);
+ }
+
+ osi_Log1(smb_logp, "SMB3 tree connect created ID %d", newTid);
+ return 0;
}
/* must be called with global tran lock held */
smb_tran2Packet_t *smb_FindTran2Packet(smb_vc_t *vcp, smb_packet_t *inp)
{
- smb_tran2Packet_t *tp;
- smb_t *smbp;
+ smb_tran2Packet_t *tp;
+ smb_t *smbp;
- smbp = (smb_t *) inp->data;
- for(tp = smb_tran2AssemblyQueuep; tp; tp = (smb_tran2Packet_t *) osi_QNext(&tp->q)) {
- if (tp->vcp == vcp && tp->mid == smbp->mid && tp->tid == smbp->tid)
- return tp;
- }
- return NULL;
+ smbp = (smb_t *) inp->data;
+ for (tp = smb_tran2AssemblyQueuep; tp; tp = (smb_tran2Packet_t *) osi_QNext(&tp->q)) {
+ if (tp->vcp == vcp && tp->mid == smbp->mid && tp->tid == smbp->tid)
+ return tp;
+ }
+ return NULL;
}
smb_tran2Packet_t *smb_NewTran2Packet(smb_vc_t *vcp, smb_packet_t *inp,
int totalParms, int totalData)
{
- smb_tran2Packet_t *tp;
- smb_t *smbp;
+ smb_tran2Packet_t *tp;
+ smb_t *smbp;
- smbp = (smb_t *) inp->data;
- tp = malloc(sizeof(*tp));
- memset(tp, 0, sizeof(*tp));
- tp->vcp = vcp;
- smb_HoldVC(vcp);
- tp->curData = tp->curParms = 0;
- tp->totalData = totalData;
- tp->totalParms = totalParms;
- tp->tid = smbp->tid;
- tp->mid = smbp->mid;
- tp->uid = smbp->uid;
- tp->pid = smbp->pid;
- tp->res[0] = smbp->res[0];
- osi_QAdd((osi_queue_t **)&smb_tran2AssemblyQueuep, &tp->q);
+ smbp = (smb_t *) inp->data;
+ tp = malloc(sizeof(*tp));
+ memset(tp, 0, sizeof(*tp));
+ tp->vcp = vcp;
+ smb_HoldVC(vcp);
+ tp->curData = tp->curParms = 0;
+ tp->totalData = totalData;
+ tp->totalParms = totalParms;
+ tp->tid = smbp->tid;
+ tp->mid = smbp->mid;
+ tp->uid = smbp->uid;
+ tp->pid = smbp->pid;
+ tp->res[0] = smbp->res[0];
+ osi_QAdd((osi_queue_t **)&smb_tran2AssemblyQueuep, &tp->q);
+ if (totalParms != 0)
+ tp->parmsp = malloc(totalParms);
+ if (totalData != 0)
+ tp->datap = malloc(totalData);
+ if (smbp->com == 0x25 || smbp->com == 0x26)
+ tp->com = 0x25;
+ else {
tp->opcode = smb_GetSMBParm(inp, 14);
- if (totalParms != 0)
- tp->parmsp = malloc(totalParms);
- if (totalData != 0)
- tp->datap = malloc(totalData);
- tp->flags |= SMB_TRAN2PFLAG_ALLOC;
- return tp;
+ tp->com = 0x32;
+ }
+ tp->flags |= SMB_TRAN2PFLAG_ALLOC;
+ return tp;
}
smb_tran2Packet_t *smb_GetTran2ResponsePacket(smb_vc_t *vcp,
- smb_tran2Packet_t *inp, smb_packet_t *outp,
- int totalParms, int totalData)
+ smb_tran2Packet_t *inp, smb_packet_t *outp,
+ int totalParms, int totalData)
{
- smb_tran2Packet_t *tp;
- unsigned short parmOffset;
- unsigned short dataOffset;
- unsigned short dataAlign;
+ smb_tran2Packet_t *tp;
+ unsigned short parmOffset;
+ unsigned short dataOffset;
+ unsigned short dataAlign;
- tp = malloc(sizeof(*tp));
- memset(tp, 0, sizeof(*tp));
- tp->vcp = NULL;
- tp->curData = tp->curParms = 0;
- tp->totalData = totalData;
- tp->totalParms = totalParms;
- tp->oldTotalParms = totalParms;
- tp->tid = inp->tid;
- tp->mid = inp->mid;
- tp->uid = inp->uid;
- tp->pid = inp->pid;
- tp->res[0] = inp->res[0];
- tp->opcode = inp->opcode;
-
- /*
- * We calculate where the parameters and data will start.
- * This calculation must parallel the calculation in
- * smb_SendTran2Packet.
- */
-
- parmOffset = 10*2 + 35;
- parmOffset++; /* round to even */
- tp->parmsp = (unsigned short *) (outp->data + parmOffset);
-
- dataOffset = parmOffset + totalParms;
- dataAlign = dataOffset & 2; /* quad-align */
- dataOffset += dataAlign;
- tp->datap = outp->data + dataOffset;
-
- return tp;
-}
+ tp = malloc(sizeof(*tp));
+ memset(tp, 0, sizeof(*tp));
+ smb_HoldVC(vcp);
+ tp->vcp = vcp;
+ tp->curData = tp->curParms = 0;
+ tp->totalData = totalData;
+ tp->totalParms = totalParms;
+ tp->oldTotalParms = totalParms;
+ tp->tid = inp->tid;
+ tp->mid = inp->mid;
+ tp->uid = inp->uid;
+ tp->pid = inp->pid;
+ tp->res[0] = inp->res[0];
+ tp->opcode = inp->opcode;
+ tp->com = inp->com;
+
+ /*
+ * We calculate where the parameters and data will start.
+ * This calculation must parallel the calculation in
+ * smb_SendTran2Packet.
+ */
+
+ parmOffset = 10*2 + 35;
+ parmOffset++; /* round to even */
+ tp->parmsp = (unsigned short *) (outp->data + parmOffset);
+
+ dataOffset = parmOffset + totalParms;
+ dataAlign = dataOffset & 2; /* quad-align */
+ dataOffset += dataAlign;
+ tp->datap = outp->data + dataOffset;
+
+ return tp;
+}
/* free a tran2 packet; must be called with smb_globalLock held */
void smb_FreeTran2Packet(smb_tran2Packet_t *t2p)
{
- if (t2p->vcp) smb_ReleaseVC(t2p->vcp);
- if (t2p->flags & SMB_TRAN2PFLAG_ALLOC) {
- if (t2p->parmsp)
- free(t2p->parmsp);
- if (t2p->datap)
- free(t2p->datap);
- }
- free(t2p);
+ if (t2p->vcp)
+ smb_ReleaseVC(t2p->vcp);
+ if (t2p->flags & SMB_TRAN2PFLAG_ALLOC) {
+ if (t2p->parmsp)
+ free(t2p->parmsp);
+ if (t2p->datap)
+ free(t2p->datap);
+ }
+ free(t2p);
}
/* called with a VC, an input packet to respond to, and an error code.
void smb_SendTran2Error(smb_vc_t *vcp, smb_tran2Packet_t *t2p,
smb_packet_t *tp, long code)
{
- smb_t *smbp;
- unsigned short errCode;
- unsigned char errClass;
- unsigned long NTStatus;
-
- if (vcp->flags & SMB_VCFLAG_STATUS32)
- smb_MapNTError(code, &NTStatus);
- else
- smb_MapCoreError(code, vcp, &errCode, &errClass);
-
- smb_FormatResponsePacket(vcp, NULL, tp);
- smbp = (smb_t *) tp;
-
- /* We can handle long names */
- if (vcp->flags & SMB_VCFLAG_USENT)
- smbp->flg2 |= 0x40; /* IS_LONG_NAME */
+ smb_t *smbp;
+ unsigned short errCode;
+ unsigned char errClass;
+ unsigned long NTStatus;
+
+ if (vcp->flags & SMB_VCFLAG_STATUS32)
+ smb_MapNTError(code, &NTStatus);
+ else
+ smb_MapCoreError(code, vcp, &errCode, &errClass);
+
+ smb_FormatResponsePacket(vcp, NULL, tp);
+ smbp = (smb_t *) tp;
+
+ /* We can handle long names */
+ if (vcp->flags & SMB_VCFLAG_USENT)
+ smbp->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
- /* now copy important fields from the tran 2 packet */
- smbp->com = 0x32; /* tran 2 response */
- smbp->tid = t2p->tid;
- smbp->mid = t2p->mid;
- smbp->pid = t2p->pid;
- smbp->uid = t2p->uid;
- smbp->res[0] = t2p->res[0];
- if (vcp->flags & SMB_VCFLAG_STATUS32) {
- smbp->rcls = (unsigned char) (NTStatus & 0xff);
- smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
- smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
- smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
- smbp->flg2 |= 0x4000;
- }
- else {
- smbp->rcls = errClass;
- smbp->errLow = (unsigned char) (errCode & 0xff);
- smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
- }
+ /* now copy important fields from the tran 2 packet */
+ smbp->com = t2p->com;
+ smbp->tid = t2p->tid;
+ smbp->mid = t2p->mid;
+ smbp->pid = t2p->pid;
+ smbp->uid = t2p->uid;
+ smbp->res[0] = t2p->res[0];
+ if (vcp->flags & SMB_VCFLAG_STATUS32) {
+ smbp->rcls = (unsigned char) (NTStatus & 0xff);
+ smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
+ smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
+ smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
+ smbp->flg2 |= SMB_FLAGS2_32BIT_STATUS;
+ }
+ else {
+ smbp->rcls = errClass;
+ smbp->errLow = (unsigned char) (errCode & 0xff);
+ smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
+ }
- /* send packet */
- smb_SendPacket(vcp, tp);
+ /* send packet */
+ smb_SendPacket(vcp, tp);
}
void smb_SendTran2Packet(smb_vc_t *vcp, smb_tran2Packet_t *t2p, smb_packet_t *tp)
{
- smb_t *smbp;
- unsigned short parmOffset;
- unsigned short dataOffset;
- unsigned short totalLength;
- unsigned short dataAlign;
- char *datap;
-
- smb_FormatResponsePacket(vcp, NULL, tp);
- smbp = (smb_t *) tp;
+ smb_t *smbp;
+ unsigned short parmOffset;
+ unsigned short dataOffset;
+ unsigned short totalLength;
+ unsigned short dataAlign;
+ char *datap;
- /* We can handle long names */
- if (vcp->flags & SMB_VCFLAG_USENT)
- smbp->flg2 |= 0x40; /* IS_LONG_NAME */
-
- /* now copy important fields from the tran 2 packet */
- smbp->com = 0x32; /* tran 2 response */
- smbp->tid = t2p->tid;
- smbp->mid = t2p->mid;
- smbp->pid = t2p->pid;
- smbp->uid = t2p->uid;
- smbp->res[0] = t2p->res[0];
-
- totalLength = 1 + t2p->totalData + t2p->totalParms;
-
- /* now add the core parameters (tran2 info) to the packet */
- smb_SetSMBParm(tp, 0, t2p->totalParms); /* parm bytes */
- smb_SetSMBParm(tp, 1, t2p->totalData); /* data bytes */
- smb_SetSMBParm(tp, 2, 0); /* reserved */
- smb_SetSMBParm(tp, 3, t2p->totalParms); /* parm bytes in this packet */
- parmOffset = 10*2 + 35; /* parm offset in packet */
- parmOffset++; /* round to even */
- smb_SetSMBParm(tp, 4, parmOffset); /* 11 parm words plus *
- * hdr, bcc and wct */
- smb_SetSMBParm(tp, 5, 0); /* parm displacement */
- smb_SetSMBParm(tp, 6, t2p->totalData); /* data in this packet */
- dataOffset = parmOffset + t2p->oldTotalParms;
- dataAlign = dataOffset & 2; /* quad-align */
- dataOffset += dataAlign;
- smb_SetSMBParm(tp, 7, dataOffset); /* offset of data */
- smb_SetSMBParm(tp, 8, 0); /* data displacement */
- smb_SetSMBParm(tp, 9, 0); /* low: setup word count *
- * high: resvd */
-
- datap = smb_GetSMBData(tp, NULL);
- *datap++ = 0; /* we rounded to even */
+ smb_FormatResponsePacket(vcp, NULL, tp);
+ smbp = (smb_t *) tp;
- totalLength += dataAlign;
- smb_SetSMBDataLength(tp, totalLength);
+ /* We can handle long names */
+ if (vcp->flags & SMB_VCFLAG_USENT)
+ smbp->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
+
+ /* now copy important fields from the tran 2 packet */
+ smbp->com = t2p->com;
+ smbp->tid = t2p->tid;
+ smbp->mid = t2p->mid;
+ smbp->pid = t2p->pid;
+ smbp->uid = t2p->uid;
+ smbp->res[0] = t2p->res[0];
+
+ totalLength = 1 + t2p->totalData + t2p->totalParms;
+
+ /* now add the core parameters (tran2 info) to the packet */
+ smb_SetSMBParm(tp, 0, t2p->totalParms); /* parm bytes */
+ smb_SetSMBParm(tp, 1, t2p->totalData); /* data bytes */
+ smb_SetSMBParm(tp, 2, 0); /* reserved */
+ smb_SetSMBParm(tp, 3, t2p->totalParms); /* parm bytes in this packet */
+ parmOffset = 10*2 + 35; /* parm offset in packet */
+ parmOffset++; /* round to even */
+ smb_SetSMBParm(tp, 4, parmOffset); /* 11 parm words plus *
+ * hdr, bcc and wct */
+ smb_SetSMBParm(tp, 5, 0); /* parm displacement */
+ smb_SetSMBParm(tp, 6, t2p->totalData); /* data in this packet */
+ dataOffset = parmOffset + t2p->oldTotalParms;
+ dataAlign = dataOffset & 2; /* quad-align */
+ dataOffset += dataAlign;
+ smb_SetSMBParm(tp, 7, dataOffset); /* offset of data */
+ smb_SetSMBParm(tp, 8, 0); /* data displacement */
+ smb_SetSMBParm(tp, 9, 0); /* low: setup word count *
+ * high: resvd */
+
+ datap = smb_GetSMBData(tp, NULL);
+ *datap++ = 0; /* we rounded to even */
+
+ totalLength += dataAlign;
+ smb_SetSMBDataLength(tp, totalLength);
- /* next, send the datagram */
- smb_SendPacket(vcp, tp);
-}
+ /* next, send the datagram */
+ smb_SendPacket(vcp, tp);
+}
-long smb_ReceiveV3Tran2A(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
+long smb_ReceiveV3Trans(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
{
- smb_tran2Packet_t *asp;
- int totalParms;
- int totalData;
- int parmDisp;
- int dataDisp;
- int parmOffset;
- int dataOffset;
- int parmCount;
- int dataCount;
- int firstPacket;
- long code;
-
- /* We sometimes see 0 word count. What to do? */
- if (*inp->wctp == 0) {
+ smb_tran2Packet_t *asp;
+ int totalParms;
+ int totalData;
+ int parmDisp;
+ int dataDisp;
+ int parmOffset;
+ int dataOffset;
+ int parmCount;
+ int dataCount;
+ int firstPacket;
+ int rapOp;
+ long code = 0;
+
+ /* We sometimes see 0 word count. What to do? */
+ if (*inp->wctp == 0) {
+ osi_Log0(smb_logp, "Transaction2 word count = 0");
#ifndef DJGPP
- HANDLE h;
- char *ptbuf[1];
-
- osi_Log0(afsd_logp, "TRANSACTION2 word count = 0");
-
- h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
- ptbuf[0] = "Transaction2 word count = 0";
- ReportEvent(h, EVENTLOG_WARNING_TYPE, 0, 1003, NULL,
- 1, inp->ncb_length, ptbuf, inp);
- DeregisterEventSource(h);
-#else /* DJGPP */
- osi_Log0(afsd_logp, "TRANSACTION2 word count = 0");
+ LogEvent(EVENTLOG_WARNING_TYPE, MSG_SMB_ZERO_TRANSACTION_COUNT);
#endif /* !DJGPP */
- smb_SetSMBDataLength(outp, 0);
- smb_SendPacket(vcp, outp);
- return 0;
- }
-
- totalParms = smb_GetSMBParm(inp, 0);
- totalData = smb_GetSMBParm(inp, 1);
+ smb_SetSMBDataLength(outp, 0);
+ smb_SendPacket(vcp, outp);
+ return 0;
+ }
- firstPacket = (inp->inCom == 0x32);
+ totalParms = smb_GetSMBParm(inp, 0);
+ totalData = smb_GetSMBParm(inp, 1);
+
+ firstPacket = (inp->inCom == 0x25);
+
+ /* find the packet we're reassembling */
+ lock_ObtainWrite(&smb_globalLock);
+ asp = smb_FindTran2Packet(vcp, inp);
+ if (!asp) {
+ asp = smb_NewTran2Packet(vcp, inp, totalParms, totalData);
+ }
+ lock_ReleaseWrite(&smb_globalLock);
+
+ /* now merge in this latest packet; start by looking up offsets */
+ if (firstPacket) {
+ parmDisp = dataDisp = 0;
+ parmOffset = smb_GetSMBParm(inp, 10);
+ dataOffset = smb_GetSMBParm(inp, 12);
+ parmCount = smb_GetSMBParm(inp, 9);
+ dataCount = smb_GetSMBParm(inp, 11);
+ asp->maxReturnParms = smb_GetSMBParm(inp, 2);
+ asp->maxReturnData = smb_GetSMBParm(inp, 3);
+
+ osi_Log3(smb_logp, "SMB3 received Trans init packet total data %d, cur data %d, max return data %d",
+ totalData, dataCount, asp->maxReturnData);
+ }
+ else {
+ parmDisp = smb_GetSMBParm(inp, 4);
+ parmOffset = smb_GetSMBParm(inp, 3);
+ dataDisp = smb_GetSMBParm(inp, 7);
+ dataOffset = smb_GetSMBParm(inp, 6);
+ parmCount = smb_GetSMBParm(inp, 2);
+ dataCount = smb_GetSMBParm(inp, 5);
+
+ osi_Log2(smb_logp, "SMB3 received Trans aux packet parms %d, data %d",
+ parmCount, dataCount);
+ }
+
+ /* now copy the parms and data */
+ if ( asp->totalParms > 0 && parmCount != 0 )
+ {
+ memcpy(((char *)asp->parmsp) + parmDisp, inp->data + parmOffset, parmCount);
+ }
+ if ( asp->totalData > 0 && dataCount != 0 ) {
+ memcpy(asp->datap + dataDisp, inp->data + dataOffset, dataCount);
+ }
- /* find the packet we're reassembling */
- lock_ObtainWrite(&smb_globalLock);
- asp = smb_FindTran2Packet(vcp, inp);
- if (!asp) {
- asp = smb_NewTran2Packet(vcp, inp, totalParms, totalData);
- }
- lock_ReleaseWrite(&smb_globalLock);
-
- /* now merge in this latest packet; start by looking up offsets */
- if (firstPacket) {
- parmDisp = dataDisp = 0;
- parmOffset = smb_GetSMBParm(inp, 10);
- dataOffset = smb_GetSMBParm(inp, 12);
- parmCount = smb_GetSMBParm(inp, 9);
- dataCount = smb_GetSMBParm(inp, 11);
- asp->maxReturnParms = smb_GetSMBParm(inp, 2);
- asp->maxReturnData = smb_GetSMBParm(inp, 3);
-
- osi_Log3(afsd_logp, "SMB3 received T2 init packet total data %d, cur data %d, max return data %d",
- totalData, dataCount, asp->maxReturnData);
- }
- else {
- parmDisp = smb_GetSMBParm(inp, 4);
- parmOffset = smb_GetSMBParm(inp, 3);
- dataDisp = smb_GetSMBParm(inp, 7);
- dataOffset = smb_GetSMBParm(inp, 6);
- parmCount = smb_GetSMBParm(inp, 2);
- dataCount = smb_GetSMBParm(inp, 5);
-
- osi_Log2(afsd_logp, "SMB3 received T2 aux packet parms %d, data %d",
- parmCount, dataCount);
- }
+ /* account for new bytes */
+ asp->curData += dataCount;
+ asp->curParms += parmCount;
+
+ /* finally, if we're done, remove the packet from the queue and dispatch it */
+ if (asp->totalParms > 0 &&
+ asp->curParms > 0 &&
+ asp->totalData <= asp->curData &&
+ asp->totalParms <= asp->curParms) {
+ /* we've received it all */
+ lock_ObtainWrite(&smb_globalLock);
+ osi_QRemove((osi_queue_t **) &smb_tran2AssemblyQueuep, &asp->q);
+ lock_ReleaseWrite(&smb_globalLock);
+
+ /* now dispatch it */
+ rapOp = asp->parmsp[0];
+
+ if ( rapOp >= 0 && rapOp < SMB_RAP_NOPCODES && smb_rapDispatchTable[rapOp].procp) {
+ osi_Log4(smb_logp,"AFS Server - Dispatch-RAP %s vcp[%p] lana[%d] lsn[%d]",myCrt_RapDispatch(rapOp),vcp,vcp->lana,vcp->lsn);
+ code = (*smb_rapDispatchTable[rapOp].procp)(vcp, asp, outp);
+ osi_Log4(smb_logp,"AFS Server - Dispatch-RAP return code 0x%x vcp[%x] lana[%d] lsn[%d]",code,vcp,vcp->lana,vcp->lsn);
+ }
+ else {
+ osi_Log4(smb_logp,"AFS Server - Dispatch-RAP [INVALID] op[%x] vcp[%p] lana[%d] lsn[%d]", rapOp, vcp, vcp->lana, vcp->lsn);
+ code = CM_ERROR_BADOP;
+ }
- /* now copy the parms and data */
- if( parmCount != 0 )
- {
- memcpy(((char *)asp->parmsp) + parmDisp, inp->data + parmOffset, parmCount);
- }
- if( dataCount != 0 )
- {
- memcpy(asp->datap + dataDisp, inp->data + dataOffset, dataCount);
- }
+ /* if an error is returned, we're supposed to send an error packet,
+ * otherwise the dispatched function already did the data sending.
+ * We give dispatched proc the responsibility since it knows how much
+ * space to allocate.
+ */
+ if (code != 0) {
+ smb_SendTran2Error(vcp, asp, outp, code);
+ }
- /* account for new bytes */
- asp->curData += dataCount;
- asp->curParms += parmCount;
-
- /* finally, if we're done, remove the packet from the queue and dispatch it */
- if (asp->totalData <= asp->curData && asp->totalParms <= asp->curParms) {
- /* we've received it all */
- lock_ObtainWrite(&smb_globalLock);
- osi_QRemove((osi_queue_t **) &smb_tran2AssemblyQueuep, &asp->q);
- lock_ReleaseWrite(&smb_globalLock);
-
- /* now dispatch it */
- if(asp->opcode >= 0 && asp->opcode < 20 && smb_tran2DispatchTable[asp->opcode].procp) {
- osi_LogEvent("AFS-Dispatch-2[%s]",myCrt_2Dispatch(asp->opcode),"vcp[%x] lana[%d] lsn[%d]",vcp,vcp->lana,vcp->lsn);
- osi_Log4(afsd_logp,"AFS Server - Dispatch-2 %s vcp[%x] lana[%d] lsn[%d]",myCrt_2Dispatch(asp->opcode),vcp,vcp->lana,vcp->lsn);
- code = (*smb_tran2DispatchTable[asp->opcode].procp)(vcp, asp, outp);
- }
- else {
- osi_LogEvent("AFS-Dispatch-2 [invalid]", NULL, "op[%x] vcp[%x] lana[%d] lsn[%d]", asp->opcode, vcp, vcp->lana, vcp->lsn);
- osi_Log4(afsd_logp,"AFS Server - Dispatch-2 [INVALID] op[%x] vcp[%x] lana[%d] lsn[%d]", asp->opcode, vcp, vcp->lana, vcp->lsn);
- code = CM_ERROR_BADOP;
- }
-
- /* if an error is returned, we're supposed to send an error packet,
- * otherwise the dispatched function already did the data sending.
- * We give dispatched proc the responsibility since it knows how much
- * space to allocate.
- */
- if (code != 0) {
- smb_SendTran2Error(vcp, asp, outp, code);
- }
-
- /* free the input tran 2 packet */
- lock_ObtainWrite(&smb_globalLock);
- smb_FreeTran2Packet(asp);
- lock_ReleaseWrite(&smb_globalLock);
- }
- else if (firstPacket) {
- /* the first packet in a multi-packet request, we need to send an
- * ack to get more data.
- */
- smb_SetSMBDataLength(outp, 0);
- smb_SendPacket(vcp, outp);
- }
+ /* free the input tran 2 packet */
+ lock_ObtainWrite(&smb_globalLock);
+ smb_FreeTran2Packet(asp);
+ lock_ReleaseWrite(&smb_globalLock);
+ }
+ else if (firstPacket) {
+ /* the first packet in a multi-packet request, we need to send an
+ * ack to get more data.
+ */
+ smb_SetSMBDataLength(outp, 0);
+ smb_SendPacket(vcp, outp);
+ }
- return 0;
+ return 0;
}
-long smb_ReceiveTran2Open(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
-{
- char *pathp;
- smb_tran2Packet_t *outp;
- long code;
- cm_space_t *spacep;
- int excl;
- cm_user_t *userp;
- cm_scache_t *dscp; /* dir we're dealing with */
- cm_scache_t *scp; /* file we're creating */
- cm_attr_t setAttr;
- int initialModeBits;
- smb_fid_t *fidp;
- int attributes;
- char *lastNamep;
- long dosTime;
- int openFun;
- int trunc;
- int openMode;
- int extraInfo;
- int openAction;
- int parmSlot; /* which parm we're dealing with */
- long returnEALength;
- char *tidPathp;
- cm_req_t req;
-
- cm_InitReq(&req);
-
- scp = NULL;
-
- extraInfo = (p->parmsp[0] & 1); /* return extra info */
- returnEALength = (p->parmsp[0] & 8); /* return extended attr length */
-
- openFun = p->parmsp[6]; /* open function */
- excl = ((openFun & 3) == 0);
- trunc = ((openFun & 3) == 2); /* truncate it */
- openMode = (p->parmsp[1] & 0x7);
- openAction = 0; /* tracks what we did */
-
- attributes = p->parmsp[3];
- dosTime = p->parmsp[4] | (p->parmsp[5] << 16);
-
- /* compute initial mode bits based on read-only flag in attributes */
- initialModeBits = 0666;
- if (attributes & 1) initialModeBits &= ~0222;
-
- pathp = (char *) (&p->parmsp[14]);
-
- outp = smb_GetTran2ResponsePacket(vcp, p, op, 40, 0);
-
- spacep = cm_GetSpace();
- smb_StripLastComponent(spacep->data, &lastNamep, pathp);
-
- if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
- /* special case magic file name for receiving IOCTL requests
- * (since IOCTL calls themselves aren't getting through).
- */
- fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
- smb_SetupIoctlFid(fidp, spacep);
-
- /* copy out remainder of the parms */
- parmSlot = 0;
- outp->parmsp[parmSlot] = fidp->fid; parmSlot++;
- if (extraInfo) {
- outp->parmsp[parmSlot] = /* attrs */ 0; parmSlot++;
- outp->parmsp[parmSlot] = 0; parmSlot++; /* mod time */
- outp->parmsp[parmSlot] = 0; parmSlot++;
- outp->parmsp[parmSlot] = 0; parmSlot++; /* len */
- outp->parmsp[parmSlot] = 0x7fff; parmSlot++;
- outp->parmsp[parmSlot] = openMode; parmSlot++;
- outp->parmsp[parmSlot] = 0; parmSlot++; /* file type 0 ==> normal file or dir */
- outp->parmsp[parmSlot] = 0; parmSlot++; /* IPC junk */
- }
- /* and the final "always present" stuff */
- outp->parmsp[parmSlot] = /* openAction found existing file */ 1; parmSlot++;
- /* next write out the "unique" ID */
- outp->parmsp[parmSlot] = 0x1234; parmSlot++;
- outp->parmsp[parmSlot] = 0x5678; parmSlot++;
- outp->parmsp[parmSlot] = 0; parmSlot++;
- if (returnEALength) {
- outp->parmsp[parmSlot] = 0; parmSlot++;
- outp->parmsp[parmSlot] = 0; parmSlot++;
- }
-
- outp->totalData = 0;
- outp->totalParms = parmSlot * 2;
-
- smb_SendTran2Packet(vcp, outp, op);
-
- smb_FreeTran2Packet(outp);
-
- /* and clean up fid reference */
- smb_ReleaseFID(fidp);
- return 0;
- }
+/* ANSI versions. The unicode versions support arbitrary length
+ share names, but we don't support unicode yet. */
-#ifdef DEBUG_VERBOSE
- {
- char *hexp, *asciip;
- asciip = (lastNamep ? lastNamep : pathp);
- hexp = osi_HexifyString( asciip );
- DEBUG_EVENT2("AFS","T2Open H[%s] A[%s]", hexp, asciip);
- free(hexp);
- }
-#endif
+typedef struct smb_rap_share_info_0 {
+ char shi0_netname[13];
+} smb_rap_share_info_0_t;
- userp = smb_GetTran2User(vcp, p);
- /* In the off chance that userp is NULL, we log and abandon */
- if(!userp) {
- osi_Log1(afsd_logp, "ReceiveTran2Open user [%d] not resolvable", p->uid);
- smb_FreeTran2Packet(outp);
- return CM_ERROR_BADSMB;
- }
+typedef struct smb_rap_share_info_1 {
+ char shi1_netname[13];
+ char shi1_pad;
+ WORD shi1_type;
+ DWORD shi1_remark; /* char *shi1_remark; data offset */
+} smb_rap_share_info_1_t;
- tidPathp = smb_GetTIDPath(vcp, p->tid);
-
- dscp = NULL;
- code = cm_NameI(cm_rootSCachep, pathp,
- CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
- userp, tidPathp, &req, &scp);
- if (code != 0) {
- code = cm_NameI(cm_rootSCachep, spacep->data,
- CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
- userp, tidPathp, &req, &dscp);
- cm_FreeSpace(spacep);
-
- if (code) {
- cm_ReleaseUser(userp);
- smb_FreeTran2Packet(outp);
- return code;
- }
-
- /* otherwise, scp points to the parent directory. Do a lookup,
- * and truncate the file if we find it, otherwise we create the
- * file.
- */
- if (!lastNamep) lastNamep = pathp;
- else lastNamep++;
- code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD, userp,
- &req, &scp);
- if (code && code != CM_ERROR_NOSUCHFILE) {
- cm_ReleaseSCache(dscp);
- cm_ReleaseUser(userp);
- smb_FreeTran2Packet(outp);
- return code;
- }
- }
- else {
- cm_FreeSpace(spacep);
- }
+typedef struct smb_rap_share_info_2 {
+ char shi2_netname[13];
+ char shi2_pad;
+ unsigned short shi2_type;
+ DWORD shi2_remark; /* char *shi2_remark; data offset */
+ unsigned short shi2_permissions;
+ unsigned short shi2_max_uses;
+ unsigned short shi2_current_uses;
+ DWORD shi2_path; /* char *shi2_path; data offset */
+ unsigned short shi2_passwd[9];
+ unsigned short shi2_pad2;
+} smb_rap_share_info_2_t;
- /* if we get here, if code is 0, the file exists and is represented by
- * scp. Otherwise, we have to create it.
- */
- if (code == 0) {
- code = cm_CheckOpen(scp, openMode, trunc, userp, &req);
- if (code) {
- if (dscp) cm_ReleaseSCache(dscp);
- cm_ReleaseSCache(scp);
- cm_ReleaseUser(userp);
- smb_FreeTran2Packet(outp);
- return code;
- }
-
- if (excl) {
- /* oops, file shouldn't be there */
- if (dscp) cm_ReleaseSCache(dscp);
- cm_ReleaseSCache(scp);
- cm_ReleaseUser(userp);
- smb_FreeTran2Packet(outp);
- return CM_ERROR_EXISTS;
- }
-
- if (trunc) {
- setAttr.mask = CM_ATTRMASK_LENGTH;
- setAttr.length.LowPart = 0;
- setAttr.length.HighPart = 0;
- code = cm_SetAttr(scp, &setAttr, userp, &req);
- openAction = 3; /* truncated existing file */
- }
- else openAction = 1; /* found existing file */
- }
- else if (!(openFun & SMB_ATTR_DIRECTORY)) {
- /* don't create if not found */
- if (dscp) cm_ReleaseSCache(dscp);
- osi_assert(scp == NULL);
- cm_ReleaseUser(userp);
- smb_FreeTran2Packet(outp);
- return CM_ERROR_NOSUCHFILE;
- }
- else {
- osi_assert(dscp != NULL && scp == NULL);
- openAction = 2; /* created file */
- setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
- smb_UnixTimeFromSearchTime(&setAttr.clientModTime, dosTime);
- code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
- &req);
- if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
- smb_NotifyChange(FILE_ACTION_ADDED,
- FILE_NOTIFY_CHANGE_FILE_NAME,
- dscp, lastNamep, NULL, TRUE);
- if (!excl && code == CM_ERROR_EXISTS) {
- /* not an exclusive create, and someone else tried
- * creating it already, then we open it anyway. We
- * don't bother retrying after this, since if this next
- * fails, that means that the file was deleted after we
- * started this call.
- */
- code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
- userp, &req, &scp);
- if (code == 0) {
- if (trunc) {
- setAttr.mask = CM_ATTRMASK_LENGTH;
- setAttr.length.LowPart = 0;
- setAttr.length.HighPart = 0;
- code = cm_SetAttr(scp, &setAttr, userp,
- &req);
- }
- } /* lookup succeeded */
- }
- }
+#define SMB_RAP_MAX_SHARES 512
- /* we don't need this any longer */
- if (dscp) cm_ReleaseSCache(dscp);
+typedef struct smb_rap_share_list {
+ int cShare;
+ int maxShares;
+ smb_rap_share_info_0_t * shares;
+} smb_rap_share_list_t;
- if (code) {
- /* something went wrong creating or truncating the file */
- if (scp) cm_ReleaseSCache(scp);
- cm_ReleaseUser(userp);
- smb_FreeTran2Packet(outp);
- return code;
- }
+int smb_rapCollectSharesProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp) {
+ smb_rap_share_list_t * sp;
+ char * name;
- /* make sure we're about to open a file */
- if (scp->fileType != CM_SCACHETYPE_FILE) {
- cm_ReleaseSCache(scp);
- cm_ReleaseUser(userp);
- smb_FreeTran2Packet(outp);
- return CM_ERROR_ISDIR;
- }
+ name = dep->name;
- /* now all we have to do is open the file itself */
- fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
- osi_assert(fidp);
-
- /* save a pointer to the vnode */
- fidp->scp = scp;
-
- /* compute open mode */
- if (openMode != 1) fidp->flags |= SMB_FID_OPENREAD;
- if (openMode == 1 || openMode == 2)
- fidp->flags |= SMB_FID_OPENWRITE;
-
- smb_ReleaseFID(fidp);
-
- cm_Open(scp, 0, userp);
-
- /* copy out remainder of the parms */
- parmSlot = 0;
- outp->parmsp[parmSlot] = fidp->fid; parmSlot++;
- lock_ObtainMutex(&scp->mx);
- if (extraInfo) {
- outp->parmsp[parmSlot] = smb_Attributes(scp); parmSlot++;
- smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
- outp->parmsp[parmSlot] = dosTime & 0xffff; parmSlot++;
- outp->parmsp[parmSlot] = (dosTime>>16) & 0xffff; parmSlot++;
- outp->parmsp[parmSlot] = (unsigned short) (scp->length.LowPart & 0xffff);
- parmSlot++;
- outp->parmsp[parmSlot] = (unsigned short) ((scp->length.LowPart >> 16) & 0xffff);
- parmSlot++;
- outp->parmsp[parmSlot] = openMode; parmSlot++;
- outp->parmsp[parmSlot] = 0; parmSlot++; /* file type 0 ==> normal file or dir */
- outp->parmsp[parmSlot] = 0; parmSlot++; /* IPC junk */
- }
- /* and the final "always present" stuff */
- outp->parmsp[parmSlot] = openAction; parmSlot++;
- /* next write out the "unique" ID */
- outp->parmsp[parmSlot] = (unsigned short) (scp->fid.vnode & 0xffff); parmSlot++;
- outp->parmsp[parmSlot] = (unsigned short) (scp->fid.volume & 0xffff); parmSlot++;
- outp->parmsp[parmSlot] = 0; parmSlot++;
- if (returnEALength) {
- outp->parmsp[parmSlot] = 0; parmSlot++;
- outp->parmsp[parmSlot] = 0; parmSlot++;
- }
- lock_ReleaseMutex(&scp->mx);
- outp->totalData = 0; /* total # of data bytes */
- outp->totalParms = parmSlot * 2; /* shorts are two bytes */
+ if (name[0] == '.' && (!name[1] || (name[1] == '.' && !name[2])))
+ return 0; /* skip over '.' and '..' */
- smb_SendTran2Packet(vcp, outp, op);
+ sp = (smb_rap_share_list_t *) vrockp;
- smb_FreeTran2Packet(outp);
+ strncpy(sp->shares[sp->cShare].shi0_netname, name, 12);
+ sp->shares[sp->cShare].shi0_netname[12] = 0;
- cm_ReleaseUser(userp);
- /* leave scp held since we put it in fidp->scp */
- return 0;
-}
+ sp->cShare++;
-long smb_ReceiveTran2FindFirst(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
-{
- return CM_ERROR_BADOP;
-}
+ if (sp->cShare >= sp->maxShares)
+ return CM_ERROR_STOPNOW;
+ else
+ return 0;
+}
-long smb_ReceiveTran2FindNext(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
+long smb_ReceiveRAPNetShareEnum(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
{
- return CM_ERROR_BADOP;
-}
+ smb_tran2Packet_t *outp;
+ unsigned short * tp;
+ int len;
+ int infoLevel;
+ int bufsize;
+ int outParmsTotal; /* total parameter bytes */
+ int outDataTotal; /* total data bytes */
+ int code = 0;
+ DWORD rv;
+ DWORD allSubmount;
+ USHORT nShares;
+ DWORD nRegShares;
+ DWORD nSharesRet;
+ HKEY hkParam;
+ HKEY hkSubmount = NULL;
+ smb_rap_share_info_1_t * shares;
+ USHORT cshare = 0;
+ char * cstrp;
+ char thisShare[256];
+ int i,j;
+ int nonrootShares;
+ smb_rap_share_list_t rootShares;
+ cm_req_t req;
+ cm_user_t * userp;
+ osi_hyper_t thyper;
+
+ tp = p->parmsp + 1; /* skip over function number (always 0) */
+ (void) smb_ParseString((char *) tp, (char **) &tp); /* skip over parm descriptor */
+ (void) smb_ParseString((char *) tp, (char **) &tp); /* skip over data descriptor */
+ infoLevel = tp[0];
+ bufsize = tp[1];
+
+ if (infoLevel != 1) {
+ return CM_ERROR_INVAL;
+ }
-long smb_ReceiveTran2QFSInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
-{
- smb_tran2Packet_t *outp;
- smb_tran2QFSInfo_t qi;
- int responseSize;
- osi_hyper_t temp;
- static char FSname[6] = {'A', 0, 'F', 0, 'S', 0};
-
- osi_Log1(afsd_logp, "T2 QFSInfo type 0x%x", p->parmsp[0]);
-
- switch (p->parmsp[0]) {
- case 1: responseSize = sizeof(qi.u.allocInfo); break;
- case 2: responseSize = sizeof(qi.u.volumeInfo); break;
- case 0x102: responseSize = sizeof(qi.u.FSvolumeInfo); break;
- case 0x103: responseSize = sizeof(qi.u.FSsizeInfo); break;
- case 0x104: responseSize = sizeof(qi.u.FSdeviceInfo); break;
- case 0x105: responseSize = sizeof(qi.u.FSattributeInfo); break;
- default: return CM_ERROR_INVAL;
- }
+ /* first figure out how many shares there are */
+ rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY, 0,
+ KEY_QUERY_VALUE, &hkParam);
+ if (rv == ERROR_SUCCESS) {
+ len = sizeof(allSubmount);
+ rv = RegQueryValueEx(hkParam, "AllSubmount", NULL, NULL,
+ (BYTE *) &allSubmount, &len);
+ if (rv != ERROR_SUCCESS || allSubmount != 0) {
+ allSubmount = 1;
+ }
+ RegCloseKey (hkParam);
+ }
- outp = smb_GetTran2ResponsePacket(vcp, p, op, 0, responseSize);
- switch (p->parmsp[0]) {
- case 1:
- /* alloc info */
- qi.u.allocInfo.FSID = 0;
- qi.u.allocInfo.sectorsPerAllocUnit = 1;
- qi.u.allocInfo.totalAllocUnits = 0x7fffffff;
- qi.u.allocInfo.availAllocUnits = 0x3fffffff;
- qi.u.allocInfo.bytesPerSector = 1024;
- break;
-
- case 2:
- /* volume info */
- qi.u.volumeInfo.vsn = 1234;
- qi.u.volumeInfo.vnCount = 4;
- /* we're supposed to pad it out with zeroes to the end */
- memset(&qi.u.volumeInfo.label, 0, sizeof(qi.u.volumeInfo.label));
- memcpy(qi.u.volumeInfo.label, "AFS", 4);
- break;
-
- case 0x102:
- /* FS volume info */
- memset((char *)&qi.u.FSvolumeInfo.vct, 0, sizeof(FILETIME));
- qi.u.FSvolumeInfo.vsn = 1234;
- qi.u.FSvolumeInfo.vnCount = 8;
- memcpy(qi.u.FSvolumeInfo.label, "A\0F\0S\0\0", 8);
- break;
-
- case 0x103:
- /* FS size info */
- temp.HighPart = 0;
- temp.LowPart = 0x7fffffff;
- qi.u.FSsizeInfo.totalAllocUnits = temp;
- temp.LowPart = 0x3fffffff;
- qi.u.FSsizeInfo.availAllocUnits = temp;
- qi.u.FSsizeInfo.sectorsPerAllocUnit = 1;
- qi.u.FSsizeInfo.bytesPerSector = 1024;
- break;
-
- case 0x104:
- /* FS device info */
- qi.u.FSdeviceInfo.devType = 0; /* don't have a number */
- qi.u.FSdeviceInfo.characteristics = 0x50; /* remote, virtual */
- break;
+ rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_OPENAFS_SUBKEY "\\Submounts",
+ 0, KEY_QUERY_VALUE, &hkSubmount);
+ if (rv == ERROR_SUCCESS) {
+ rv = RegQueryInfoKey(hkSubmount, NULL, NULL, NULL, NULL,
+ NULL, NULL, &nRegShares, NULL, NULL, NULL, NULL);
+ if (rv != ERROR_SUCCESS)
+ nRegShares = 0;
+ } else {
+ hkSubmount = NULL;
+ }
- case 0x105:
- /* FS attribute info */
- /* attributes, defined in WINNT.H:
- * FILE_CASE_SENSITIVE_SEARCH 0x1
- * FILE_CASE_PRESERVED_NAMES 0x2
- * <no name defined> 0x4000
- * If bit 0x4000 is not set, Windows 95 thinks
- * we can't handle long (non-8.3) names,
- * despite our protestations to the contrary.
- */
- qi.u.FSattributeInfo.attributes = 0x4003;
- qi.u.FSattributeInfo.maxCompLength = 255;
- qi.u.FSattributeInfo.FSnameLength = 6;
- memcpy(qi.u.FSattributeInfo.FSname, FSname, 6);
- break;
- }
-
- /* copy out return data, and set corresponding sizes */
- outp->totalParms = 0;
- outp->totalData = responseSize;
- memcpy(outp->datap, &qi, responseSize);
+ /* fetch the root shares */
+ rootShares.maxShares = SMB_RAP_MAX_SHARES;
+ rootShares.cShare = 0;
+ rootShares.shares = malloc( sizeof(smb_rap_share_info_0_t) * SMB_RAP_MAX_SHARES );
- /* send and free the packets */
- smb_SendTran2Packet(vcp, outp, op);
- smb_FreeTran2Packet(outp);
+ cm_InitReq(&req);
- return 0;
-}
+ userp = smb_GetTran2User(vcp,p);
-long smb_ReceiveTran2SetFSInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
-{
- return CM_ERROR_BADOP;
-}
+ thyper.HighPart = 0;
+ thyper.LowPart = 0;
-struct smb_ShortNameRock {
- char *maskp;
- unsigned int vnode;
- char *shortName;
- size_t shortNameLen;
-};
+ cm_HoldSCache(cm_data.rootSCachep);
+ cm_ApplyDir(cm_data.rootSCachep, smb_rapCollectSharesProc, &rootShares, &thyper, userp, &req, NULL);
+ cm_ReleaseSCache(cm_data.rootSCachep);
-int cm_GetShortNameProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *vrockp,
- osi_hyper_t *offp)
-{
- struct smb_ShortNameRock *rockp;
- char *shortNameEnd;
+ cm_ReleaseUser(userp);
- rockp = vrockp;
- /* compare both names and vnodes, though probably just comparing vnodes
- * would be safe enough.
- */
- if (stricmp(dep->name, rockp->maskp) != 0)
- return 0;
- if (ntohl(dep->fid.vnode) != rockp->vnode)
- return 0;
- /* This is the entry */
- cm_Gen8Dot3Name(dep, rockp->shortName, &shortNameEnd);
- rockp->shortNameLen = shortNameEnd - rockp->shortName;
- return CM_ERROR_STOPNOW;
-}
+ nShares = (USHORT)(rootShares.cShare + nRegShares + allSubmount);
-long cm_GetShortName(char *pathp, cm_user_t *userp, cm_req_t *reqp,
- char *tidPathp, int vnode, char *shortName, size_t *shortNameLenp)
-{
- struct smb_ShortNameRock rock;
- char *lastNamep;
- cm_space_t *spacep;
- cm_scache_t *dscp;
- int caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
- long code;
- osi_hyper_t thyper;
-
- spacep = cm_GetSpace();
- smb_StripLastComponent(spacep->data, &lastNamep, pathp);
-
- code = cm_NameI(cm_rootSCachep, spacep->data, caseFold, userp, tidPathp,
- reqp, &dscp);
- cm_FreeSpace(spacep);
- if (code) return code;
-
- if (!lastNamep) lastNamep = pathp;
- else lastNamep++;
- thyper.LowPart = 0;
- thyper.HighPart = 0;
- rock.shortName = shortName;
- rock.vnode = vnode;
- rock.maskp = lastNamep;
- code = cm_ApplyDir(dscp, cm_GetShortNameProc, &rock, &thyper, userp,
- reqp, NULL);
-
- cm_ReleaseSCache(dscp);
-
- if (code == 0)
- return CM_ERROR_NOSUCHFILE;
- if (code == CM_ERROR_STOPNOW) {
- *shortNameLenp = rock.shortNameLen;
- return 0;
- }
- return code;
-}
+#define REMARK_LEN 1
+ outParmsTotal = 8; /* 4 dwords */
+ outDataTotal = (sizeof(smb_rap_share_info_1_t) + REMARK_LEN) * nShares ;
+ if(outDataTotal > bufsize) {
+ nSharesRet = bufsize / (sizeof(smb_rap_share_info_1_t) + REMARK_LEN);
+ outDataTotal = (sizeof(smb_rap_share_info_1_t) + REMARK_LEN) * nSharesRet;
+ }
+ else {
+ nSharesRet = nShares;
+ }
+
+ outp = smb_GetTran2ResponsePacket(vcp, p, op, outParmsTotal, outDataTotal);
-long smb_ReceiveTran2QPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
-{
- smb_tran2Packet_t *outp;
- unsigned long dosTime;
- FILETIME ft;
- unsigned short infoLevel;
- int nbytesRequired;
- unsigned short attributes;
- unsigned long extAttributes;
- char shortName[13];
- unsigned int len;
- cm_user_t *userp;
- cm_space_t *spacep;
- cm_scache_t *scp, *dscp;
- long code;
- char *op;
- char *tidPathp;
- char *lastComp;
- cm_req_t req;
-
- cm_InitReq(&req);
-
- infoLevel = p->parmsp[0];
- if (infoLevel == 6) nbytesRequired = 0;
- else if (infoLevel == 1) nbytesRequired = 22;
- else if (infoLevel == 2) nbytesRequired = 26;
- else if (infoLevel == 0x101) nbytesRequired = 40;
- else if (infoLevel == 0x102) nbytesRequired = 24;
- else if (infoLevel == 0x103) nbytesRequired = 4;
- else if (infoLevel == 0x108) nbytesRequired = 30;
- else {
- osi_Log2(afsd_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
- p->opcode, infoLevel);
- smb_SendTran2Error(vcp, p, opx, CM_ERROR_INVAL);
- return 0;
- }
- osi_Log2(afsd_logp, "T2 QPathInfo type 0x%x path %s", infoLevel,
- osi_LogSaveString(afsd_logp, (char *)(&p->parmsp[3])));
+ /* now for the submounts */
+ shares = (smb_rap_share_info_1_t *) outp->datap;
+ cstrp = outp->datap + sizeof(smb_rap_share_info_1_t) * nSharesRet;
- outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, nbytesRequired);
+ memset(outp->datap, 0, (sizeof(smb_rap_share_info_1_t) + REMARK_LEN) * nSharesRet);
- if (infoLevel > 0x100)
- outp->totalParms = 2;
- else
- outp->totalParms = 0;
- outp->totalData = nbytesRequired;
-
- /* now, if we're at infoLevel 6, we're only being asked to check
- * the syntax, so we just OK things now. In particular, we're *not*
- * being asked to verify anything about the state of any parent dirs.
- */
- if (infoLevel == 6) {
- smb_SendTran2Packet(vcp, outp, opx);
- smb_FreeTran2Packet(outp);
- return 0;
+ if (allSubmount) {
+ strcpy( shares[cshare].shi1_netname, "all" );
+ shares[cshare].shi1_remark = (DWORD)(cstrp - outp->datap);
+ /* type and pad are zero already */
+ cshare++;
+ cstrp+=REMARK_LEN;
+ }
+
+ if (hkSubmount) {
+ for (i=0; i < nRegShares && cshare < nSharesRet; i++) {
+ len = sizeof(thisShare);
+ rv = RegEnumValue(hkSubmount, i, thisShare, &len, NULL, NULL, NULL, NULL);
+ if (rv == ERROR_SUCCESS && strlen(thisShare) && (!allSubmount || stricmp(thisShare,"all"))) {
+ strncpy(shares[cshare].shi1_netname, thisShare, sizeof(shares->shi1_netname)-1);
+ shares[cshare].shi1_netname[sizeof(shares->shi1_netname)-1] = 0; /* unfortunate truncation */
+ shares[cshare].shi1_remark = (DWORD)(cstrp - outp->datap);
+ cshare++;
+ cstrp+=REMARK_LEN;
+ }
+ else
+ nShares--; /* uncount key */
}
-
- userp = smb_GetTran2User(vcp, p);
- if(!userp) {
- osi_Log1(afsd_logp, "ReceiveTran2QPathInfo unable to resolve user [%d]", p->uid);
- smb_FreeTran2Packet(outp);
- return CM_ERROR_BADSMB;
- }
-
- tidPathp = smb_GetTIDPath(vcp, p->tid);
-
- /*
- * XXX Strange hack XXX
- *
- * As of Patch 7 (13 January 98), we are having the following problem:
- * In NT Explorer 4.0, whenever we click on a directory, AFS gets
- * requests to look up "desktop.ini" in all the subdirectories.
- * This can cause zillions of timeouts looking up non-existent cells
- * and volumes, especially in the top-level directory.
- *
- * We have not found any way to avoid this or work around it except
- * to explicitly ignore the requests for mount points that haven't
- * yet been evaluated and for directories that haven't yet been
- * fetched.
- */
- if (infoLevel == 0x101) {
- spacep = cm_GetSpace();
- smb_StripLastComponent(spacep->data, &lastComp,
- (char *)(&p->parmsp[3]));
- if(lastComp) {
- if (strcmp(lastComp, "\\desktop.ini") == 0) {
- code = cm_NameI(cm_rootSCachep, spacep->data,
- CM_FLAG_CASEFOLD
- | CM_FLAG_DIRSEARCH
- | CM_FLAG_FOLLOW,
- userp, tidPathp, &req, &dscp);
- if (code == 0) {
- if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT
- && !dscp->mountRootFidp)
- code = CM_ERROR_NOSUCHFILE;
- else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
- cm_buf_t *bp = buf_Find(dscp, &hzero);
- if (bp)
- buf_Release(bp);
- else
- code = CM_ERROR_NOSUCHFILE;
- }
- cm_ReleaseSCache(dscp);
- if (code) {
- cm_FreeSpace(spacep);
- cm_ReleaseUser(userp);
- smb_SendTran2Error(vcp, p, opx, code);
- smb_FreeTran2Packet(outp);
- return 0;
- }
- }
- }
- }
- cm_FreeSpace(spacep);
- }
- /* now do namei and stat, and copy out the info */
- code = cm_NameI(cm_rootSCachep, (char *)(&p->parmsp[3]),
- CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, tidPathp, &req, &scp);
+ RegCloseKey(hkSubmount);
+ }
- if (code) {
- cm_ReleaseUser(userp);
- smb_SendTran2Error(vcp, p, opx, code);
- smb_FreeTran2Packet(outp);
- return 0;
+ nonrootShares = cshare;
+
+ for (i=0; i < rootShares.cShare && cshare < nSharesRet; i++) {
+ /* in case there are collisions with submounts, submounts have higher priority */
+ for (j=0; j < nonrootShares; j++)
+ if (!stricmp(shares[j].shi1_netname, rootShares.shares[i].shi0_netname))
+ break;
+
+ if (j < nonrootShares) {
+ nShares--; /* uncount */
+ continue;
}
- lock_ObtainMutex(&scp->mx);
- code = cm_SyncOp(scp, NULL, userp, &req, 0,
- CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
- if (code) goto done;
-
- /* now we have the status in the cache entry, and everything is locked.
- * Marshall the output data.
- */
- op = outp->datap;
- /* for info level 108, figure out short name */
- if (infoLevel == 0x108) {
- code = cm_GetShortName((char *)(&p->parmsp[3]), userp, &req,
- tidPathp, scp->fid.vnode, shortName,
- (size_t *) &len);
- if (code) {
- goto done;
- }
-
- op = outp->datap;
- *((u_long *)op) = len * 2; op += 4;
- mbstowcs((unsigned short *)op, shortName, len);
- op += (len * 2);
-
- goto done;
- }
- if (infoLevel == 1 || infoLevel == 2) {
- smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
- *((u_long *)op) = dosTime; op += 4; /* creation time */
- *((u_long *)op) = dosTime; op += 4; /* access time */
- *((u_long *)op) = dosTime; op += 4; /* write time */
- *((u_long *)op) = scp->length.LowPart; op += 4; /* length */
- *((u_long *)op) = scp->length.LowPart; op += 4; /* alloc size */
- attributes = smb_Attributes(scp);
- *((u_short *)op) = attributes; op += 2; /* attributes */
- }
- else if (infoLevel == 0x101) {
- smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
- *((FILETIME *)op) = ft; op += 8; /* creation time */
- *((FILETIME *)op) = ft; op += 8; /* last access time */
- *((FILETIME *)op) = ft; op += 8; /* last write time */
- *((FILETIME *)op) = ft; op += 8; /* last change time */
- extAttributes = smb_ExtAttributes(scp);
- *((u_long *)op) = extAttributes; op += 4; /* extended attribs */
- *((u_long *)op) = 0; op += 4; /* don't know what this is */
- }
- else if (infoLevel == 0x102) {
- *((LARGE_INTEGER *)op) = scp->length; op += 8; /* alloc size */
- *((LARGE_INTEGER *)op) = scp->length; op += 8; /* EOF */
- *((u_long *)op) = scp->linkCount; op += 4;
- *op++ = 0;
- *op++ = 0;
- *op++ = (scp->fileType == CM_SCACHETYPE_DIRECTORY ? 1 : 0);
- *op++ = 0;
- }
- else if (infoLevel == 0x103) {
- memset(op, 0, 4); op += 4; /* EA size */
- }
+ strcpy(shares[cshare].shi1_netname, rootShares.shares[i].shi0_netname);
+ shares[cshare].shi1_remark = (DWORD)(cstrp - outp->datap);
+ cshare++;
+ cstrp+=REMARK_LEN;
+ }
- /* now, if we are being asked about extended attrs, return a 0 size */
- if (infoLevel == 2) {
- *((u_long *)op) = 0; op += 4;
- }
-
+ outp->parmsp[0] = ((cshare == nShares)? ERROR_SUCCESS : ERROR_MORE_DATA);
+ outp->parmsp[1] = 0;
+ outp->parmsp[2] = cshare;
+ outp->parmsp[3] = nShares;
- /* send and free the packets */
-done:
- lock_ReleaseMutex(&scp->mx);
- cm_ReleaseSCache(scp);
- cm_ReleaseUser(userp);
- if (code == 0) smb_SendTran2Packet(vcp, outp, opx);
- else smb_SendTran2Error(vcp, p, opx, code);
- smb_FreeTran2Packet(outp);
+ outp->totalData = (int)(cstrp - outp->datap);
+ outp->totalParms = outParmsTotal;
- return 0;
-}
+ smb_SendTran2Packet(vcp, outp, op);
+ smb_FreeTran2Packet(outp);
-long smb_ReceiveTran2SetPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
-{
- return CM_ERROR_BADOP;
+ free(rootShares.shares);
+
+ return code;
}
-long smb_ReceiveTran2QFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
+long smb_ReceiveRAPNetShareGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
{
- smb_tran2Packet_t *outp;
- FILETIME ft;
- unsigned long attributes;
- unsigned short infoLevel;
- int nbytesRequired;
- unsigned short fid;
- cm_user_t *userp;
- smb_fid_t *fidp;
- cm_scache_t *scp;
- char *op;
- long code;
- cm_req_t req;
-
- cm_InitReq(&req);
-
- fid = p->parmsp[0];
- fidp = smb_FindFID(vcp, fid, 0);
-
- if (fidp == NULL) {
- smb_SendTran2Error(vcp, p, opx, CM_ERROR_BADFD);
- return 0;
- }
+ smb_tran2Packet_t *outp;
+ unsigned short * tp;
+ char * shareName;
+ BOOL shareFound = FALSE;
+ unsigned short infoLevel;
+ unsigned short bufsize;
+ int totalData;
+ int totalParam;
+ DWORD len;
+ HKEY hkParam;
+ HKEY hkSubmount;
+ DWORD allSubmount;
+ LONG rv;
+ long code = 0;
+
+ tp = p->parmsp + 1; /* skip over function number (always 1) */
+ (void) smb_ParseString( (char *) tp, (char **) &tp); /* skip over param descriptor */
+ (void) smb_ParseString( (char *) tp, (char **) &tp); /* skip over data descriptor */
+ shareName = smb_ParseString( (char *) tp, (char **) &tp);
+ infoLevel = *tp++;
+ bufsize = *tp++;
+
+ totalParam = 6;
+
+ if (infoLevel == 0)
+ totalData = sizeof(smb_rap_share_info_0_t);
+ else if(infoLevel == SMB_INFO_STANDARD)
+ totalData = sizeof(smb_rap_share_info_1_t) + 1; /* + empty string */
+ else if(infoLevel == SMB_INFO_QUERY_EA_SIZE)
+ totalData = sizeof(smb_rap_share_info_2_t) + 2; /* + two empty strings */
+ else
+ return CM_ERROR_INVAL;
+
+ outp = smb_GetTran2ResponsePacket(vcp, p, op, totalParam, totalData);
+
+ if(!stricmp(shareName,"all")) {
+ rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY, 0,
+ KEY_QUERY_VALUE, &hkParam);
+ if (rv == ERROR_SUCCESS) {
+ len = sizeof(allSubmount);
+ rv = RegQueryValueEx(hkParam, "AllSubmount", NULL, NULL,
+ (BYTE *) &allSubmount, &len);
+ if (rv != ERROR_SUCCESS || allSubmount != 0) {
+ allSubmount = 1;
+ }
+ RegCloseKey (hkParam);
+ }
- infoLevel = p->parmsp[1];
- if (infoLevel == 0x101) nbytesRequired = 40;
- else if (infoLevel == 0x102) nbytesRequired = 24;
- else if (infoLevel == 0x103) nbytesRequired = 4;
- else if (infoLevel == 0x104) nbytesRequired = 6;
- else {
- osi_Log2(afsd_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
- p->opcode, infoLevel);
- smb_SendTran2Error(vcp, p, opx, CM_ERROR_INVAL);
- smb_ReleaseFID(fidp);
- return 0;
- }
- osi_Log2(afsd_logp, "T2 QFileInfo type 0x%x fid %d", infoLevel, fid);
+ if (allSubmount)
+ shareFound = TRUE;
+
+ } else {
+ rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY "\\Submounts", 0,
+ KEY_QUERY_VALUE, &hkSubmount);
+ if (rv == ERROR_SUCCESS) {
+ rv = RegQueryValueEx(hkSubmount, shareName, NULL, NULL, NULL, NULL);
+ if (rv == ERROR_SUCCESS) {
+ shareFound = TRUE;
+ }
+ RegCloseKey(hkSubmount);
+ }
+ }
- outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, nbytesRequired);
+ if (!shareFound) {
+ smb_FreeTran2Packet(outp);
+ return CM_ERROR_BADSHARENAME;
+ }
- if (infoLevel > 0x100)
- outp->totalParms = 2;
- else
- outp->totalParms = 0;
- outp->totalData = nbytesRequired;
+ memset(outp->datap, 0, totalData);
+
+ outp->parmsp[0] = 0;
+ outp->parmsp[1] = 0;
+ outp->parmsp[2] = totalData;
+
+ if (infoLevel == 0) {
+ smb_rap_share_info_0_t * info = (smb_rap_share_info_0_t *) outp->datap;
+ strncpy(info->shi0_netname, shareName, sizeof(info->shi0_netname)-1);
+ info->shi0_netname[sizeof(info->shi0_netname)-1] = 0;
+ } else if(infoLevel == SMB_INFO_STANDARD) {
+ smb_rap_share_info_1_t * info = (smb_rap_share_info_1_t *) outp->datap;
+ strncpy(info->shi1_netname, shareName, sizeof(info->shi1_netname)-1);
+ info->shi1_netname[sizeof(info->shi1_netname)-1] = 0;
+ info->shi1_remark = (DWORD)(((unsigned char *) (info + 1)) - outp->datap);
+ /* type and pad are already zero */
+ } else { /* infoLevel==2 */
+ smb_rap_share_info_2_t * info = (smb_rap_share_info_2_t *) outp->datap;
+ strncpy(info->shi2_netname, shareName, sizeof(info->shi2_netname)-1);
+ info->shi2_netname[sizeof(info->shi2_netname)-1] = 0;
+ info->shi2_remark = (DWORD)(((unsigned char *) (info + 1)) - outp->datap);
+ info->shi2_permissions = ACCESS_ALL;
+ info->shi2_max_uses = (unsigned short) -1;
+ info->shi2_path = (DWORD)(1 + (((unsigned char *) (info + 1)) - outp->datap));
+ }
- userp = smb_GetTran2User(vcp, p);
- if(!userp) {
- osi_Log1(afsd_logp, "ReceiveTran2QFileInfo unable to resolve user [%d]", p->uid);
- code = CM_ERROR_BADSMB;
- goto done;
- }
+ outp->totalData = totalData;
+ outp->totalParms = totalParam;
- scp = fidp->scp;
- lock_ObtainMutex(&scp->mx);
- code = cm_SyncOp(scp, NULL, userp, &req, 0,
- CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
- if (code) goto done;
+ smb_SendTran2Packet(vcp, outp, op);
+ smb_FreeTran2Packet(outp);
- /* now we have the status in the cache entry, and everything is locked.
- * Marshall the output data.
- */
- op = outp->datap;
- if (infoLevel == 0x101) {
- smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
- *((FILETIME *)op) = ft; op += 8; /* creation time */
- *((FILETIME *)op) = ft; op += 8; /* last access time */
- *((FILETIME *)op) = ft; op += 8; /* last write time */
- *((FILETIME *)op) = ft; op += 8; /* last change time */
- attributes = smb_ExtAttributes(scp);
- *((u_long *)op) = attributes; op += 4;
- *((u_long *)op) = 0; op += 4;
- }
- else if (infoLevel == 0x102) {
- *((LARGE_INTEGER *)op) = scp->length; op += 8; /* alloc size */
- *((LARGE_INTEGER *)op) = scp->length; op += 8; /* EOF */
- *((u_long *)op) = scp->linkCount; op += 4;
- *op++ = ((fidp->flags & SMB_FID_DELONCLOSE) ? 1 : 0);
- *op++ = (scp->fileType == CM_SCACHETYPE_DIRECTORY ? 1 : 0);
- *op++ = 0;
- *op++ = 0;
- }
- else if (infoLevel == 0x103) {
- *((u_long *)op) = 0; op += 4;
- }
- else if (infoLevel == 0x104) {
- unsigned long len;
- char *name;
-
- if (fidp->NTopen_wholepathp)
- name = fidp->NTopen_wholepathp;
- else
- name = "\\"; /* probably can't happen */
- len = strlen(name);
- outp->totalData = (len*2) + 4; /* this is actually what we want to return */
- *((u_long *)op) = len * 2; op += 4;
- mbstowcs((unsigned short *)op, name, len); op += (len * 2);
- }
+ return code;
+}
- /* send and free the packets */
-done:
- lock_ReleaseMutex(&scp->mx);
- cm_ReleaseUser(userp);
- smb_ReleaseFID(fidp);
- if (code == 0) smb_SendTran2Packet(vcp, outp, opx);
- else smb_SendTran2Error(vcp, p, opx, code);
- smb_FreeTran2Packet(outp);
+typedef struct smb_rap_wksta_info_10 {
+ DWORD wki10_computername; /*char *wki10_computername;*/
+ DWORD wki10_username; /* char *wki10_username; */
+ DWORD wki10_langroup; /* char *wki10_langroup;*/
+ unsigned char wki10_ver_major;
+ unsigned char wki10_ver_minor;
+ DWORD wki10_logon_domain; /*char *wki10_logon_domain;*/
+ DWORD wki10_oth_domains; /* char *wki10_oth_domains;*/
+} smb_rap_wksta_info_10_t;
- return 0;
-}
-long smb_ReceiveTran2SetFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
+long smb_ReceiveRAPNetWkstaGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
{
- long code;
- unsigned short fid;
- smb_fid_t *fidp;
- unsigned short infoLevel;
- smb_tran2Packet_t *outp;
- cm_user_t *userp;
- cm_scache_t *scp;
- cm_req_t req;
-
- cm_InitReq(&req);
-
- fid = p->parmsp[0];
- fidp = smb_FindFID(vcp, fid, 0);
-
- if (fidp == NULL) {
- smb_SendTran2Error(vcp, p, op, CM_ERROR_BADFD);
- return 0;
- }
+ smb_tran2Packet_t *outp;
+ long code = 0;
+ int infoLevel;
+ int bufsize;
+ unsigned short * tp;
+ int totalData;
+ int totalParams;
+ smb_rap_wksta_info_10_t * info;
+ char * cstrp;
+ smb_user_t *uidp;
+
+ tp = p->parmsp + 1; /* Skip over function number */
+ (void) smb_ParseString((unsigned char*) tp, (char **) &tp); /* skip over param descriptor */
+ (void) smb_ParseString((unsigned char*) tp, (char **) &tp); /* skip over data descriptor */
+ infoLevel = *tp++;
+ bufsize = *tp++;
+
+ if (infoLevel != 10) {
+ return CM_ERROR_INVAL;
+ }
- infoLevel = p->parmsp[1];
- if (infoLevel > 0x104 || infoLevel < 0x101) {
- osi_Log2(afsd_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
- p->opcode, infoLevel);
- smb_SendTran2Error(vcp, p, op, CM_ERROR_INVAL);
- smb_ReleaseFID(fidp);
- return 0;
- }
+ totalParams = 6;
+
+ /* infolevel 10 */
+ totalData = sizeof(*info) + /* info */
+ MAX_COMPUTERNAME_LENGTH + /* wki10_computername */
+ SMB_MAX_USERNAME_LENGTH + /* wki10_username */
+ MAX_COMPUTERNAME_LENGTH + /* wki10_langroup */
+ MAX_COMPUTERNAME_LENGTH + /* wki10_logon_domain */
+ 1; /* wki10_oth_domains (null)*/
- if (infoLevel == 0x102 && !(fidp->flags & SMB_FID_OPENDELETE)) {
- smb_SendTran2Error(vcp, p, op, CM_ERROR_NOACCESS);
- smb_ReleaseFID(fidp);
- return 0;
- }
- if ((infoLevel == 0x103 || infoLevel == 0x104)
- && !(fidp->flags & SMB_FID_OPENWRITE)) {
- smb_SendTran2Error(vcp, p, op, CM_ERROR_NOACCESS);
- smb_ReleaseFID(fidp);
- return 0;
- }
+ outp = smb_GetTran2ResponsePacket(vcp, p, op, totalParams, totalData);
- osi_Log1(afsd_logp, "T2 SFileInfo type 0x%x", infoLevel);
+ memset(outp->parmsp,0,totalParams);
+ memset(outp->datap,0,totalData);
- outp = smb_GetTran2ResponsePacket(vcp, p, op, 2, 0);
+ info = (smb_rap_wksta_info_10_t *) outp->datap;
+ cstrp = (char *) (info + 1);
- outp->totalParms = 2;
- outp->totalData = 0;
+ info->wki10_computername = (DWORD) (cstrp - outp->datap);
+ strcpy(cstrp, smb_localNamep);
+ cstrp += strlen(cstrp) + 1;
- userp = smb_GetTran2User(vcp, p);
- if(!userp) {
- osi_Log1(afsd_logp,"ReceiveTran2SetFileInfo unable to resolve user [%d]", p->uid);
- code = CM_ERROR_BADSMB;
- goto done;
- }
+ info->wki10_username = (DWORD) (cstrp - outp->datap);
+ uidp = smb_FindUID(vcp, p->uid, 0);
+ if (uidp) {
+ lock_ObtainMutex(&uidp->mx);
+ if(uidp->unp && uidp->unp->name)
+ strcpy(cstrp, uidp->unp->name);
+ lock_ReleaseMutex(&uidp->mx);
+ smb_ReleaseUID(uidp);
+ }
+ cstrp += strlen(cstrp) + 1;
- scp = fidp->scp;
-
- if (infoLevel == 0x101) {
- FILETIME lastMod;
- unsigned int attribute;
- cm_attr_t attr;
-
- /* lock the vnode with a callback; we need the current status
- * to determine what the new status is, in some cases.
- */
- lock_ObtainMutex(&scp->mx);
- code = cm_SyncOp(scp, NULL, userp, &req, 0,
- CM_SCACHESYNC_GETSTATUS
- | CM_SCACHESYNC_NEEDCALLBACK);
- if (code) {
- lock_ReleaseMutex(&scp->mx);
- goto done;
- }
-
- /* prepare for setattr call */
- attr.mask = 0;
- lastMod = *((FILETIME *)(p->datap + 16));
- /* when called as result of move a b, lastMod is (-1, -1). If the check for -1
- is not present, timestamp
- of the resulting file will be 1969 (-1)
- */
+ info->wki10_langroup = (DWORD) (cstrp - outp->datap);
+ strcpy(cstrp, "WORKGROUP");
+ cstrp += strlen(cstrp) + 1;
- if (LargeIntegerNotEqualToZero(*((LARGE_INTEGER *)&lastMod)) &&
- lastMod.dwLowDateTime != -1 &&
- lastMod.dwHighDateTime != -1)
- {
- attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
- smb_UnixTimeFromLargeSearchTime(&attr.clientModTime,
- &lastMod);
- fidp->flags |= SMB_FID_MTIMESETDONE;
- }
-
- attribute = *((u_long *)(p->datap + 32));
- if (attribute != 0) {
- if ((scp->unixModeBits & 0222)
- && (attribute & 1) != 0) {
- /* make a writable file read-only */
- attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
- attr.unixModeBits = scp->unixModeBits & ~0222;
- }
- else if ((scp->unixModeBits & 0222) == 0
- && (attribute & 1) == 0) {
- /* make a read-only file writable */
- attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
- attr.unixModeBits = scp->unixModeBits | 0222;
- }
- }
- lock_ReleaseMutex(&scp->mx);
-
- /* call setattr */
- if (attr.mask)
- code = cm_SetAttr(scp, &attr, userp, &req);
- else
- code = 0;
- }
- else if (infoLevel == 0x103 || infoLevel == 0x104) {
- LARGE_INTEGER size = *((LARGE_INTEGER *)(p->datap));
- cm_attr_t attr;
-
- attr.mask = CM_ATTRMASK_LENGTH;
- attr.length.LowPart = size.LowPart;
- attr.length.HighPart = size.HighPart;
- code = cm_SetAttr(scp, &attr, userp, &req);
- }
- else if (infoLevel == 0x102) {
- if (*((char *)(p->datap))) {
- code = cm_CheckNTDelete(fidp->NTopen_dscp, scp, userp,
- &req);
- if (code == 0)
- fidp->flags |= SMB_FID_DELONCLOSE;
- }
- else {
- code = 0;
- fidp->flags &= ~SMB_FID_DELONCLOSE;
- }
- }
-done:
- cm_ReleaseUser(userp);
- smb_ReleaseFID(fidp);
- if (code == 0) smb_SendTran2Packet(vcp, outp, op);
- else smb_SendTran2Error(vcp, p, op, code);
- smb_FreeTran2Packet(outp);
-
- return 0;
-}
+ /* TODO: Not sure what values these should take, but these work */
+ info->wki10_ver_major = 5;
+ info->wki10_ver_minor = 1;
-long smb_ReceiveTran2FSCTL(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
-{
- return CM_ERROR_BADOP;
-}
+ info->wki10_logon_domain = (DWORD) (cstrp - outp->datap);
+ strcpy(cstrp, smb_ServerDomainName);
+ cstrp += strlen(cstrp) + 1;
-long smb_ReceiveTran2IOCTL(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
-{
- return CM_ERROR_BADOP;
-}
+ info->wki10_oth_domains = (DWORD) (cstrp - outp->datap);
+ cstrp ++; /* no other domains */
-long smb_ReceiveTran2FindNotifyFirst(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
-{
- return CM_ERROR_BADOP;
-}
+ outp->totalData = (unsigned short) (cstrp - outp->datap); /* actual data size */
+ outp->parmsp[2] = outp->totalData;
+ outp->totalParms = totalParams;
-long smb_ReceiveTran2FindNotifyNext(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
-{
- return CM_ERROR_BADOP;
-}
+ smb_SendTran2Packet(vcp,outp,op);
+ smb_FreeTran2Packet(outp);
-long smb_ReceiveTran2MKDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
-{
- return CM_ERROR_BADOP;
+ return code;
}
-long smb_ApplyV3DirListPatches(cm_scache_t *dscp,
- smb_dirListPatch_t **dirPatchespp, int infoLevel, cm_user_t *userp,
- cm_req_t *reqp)
-{
- long code;
- cm_scache_t *scp;
- cm_scache_t *targetScp; /* target if scp is a symlink */
- char *dptr;
- long dosTime;
- FILETIME ft;
- int shortTemp;
- unsigned short attr;
- unsigned long lattr;
- smb_dirListPatch_t *patchp;
- smb_dirListPatch_t *npatchp;
-
- for(patchp = *dirPatchespp; patchp; patchp =
- (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
- code = cm_GetSCache(&patchp->fid, &scp, userp, reqp);
- if (code) continue;
- lock_ObtainMutex(&scp->mx);
- code = cm_SyncOp(scp, NULL, userp, reqp, 0,
- CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
- if (code) {
- lock_ReleaseMutex(&scp->mx);
- cm_ReleaseSCache(scp);
- continue;
- }
-
- /* now watch for a symlink */
- if (scp->fileType == CM_SCACHETYPE_SYMLINK) {
- lock_ReleaseMutex(&scp->mx);
- code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp,
- reqp);
- if (code == 0) {
- /* we have a more accurate file to use (the
- * target of the symbolic link). Otherwise,
- * we'll just use the symlink anyway.
- */
- osi_Log2(afsd_logp, "symlink vp %x to vp %x",
- scp, targetScp);
- cm_ReleaseSCache(scp);
- scp = targetScp;
- }
- lock_ObtainMutex(&scp->mx);
- }
-
- dptr = patchp->dptr;
-
- if (infoLevel >= 0x101) {
- /* get filetime */
- smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
-
- /* copy to Creation Time */
- *((FILETIME *)dptr) = ft;
- dptr += 8;
-
- /* copy to Last Access Time */
- *((FILETIME *)dptr) = ft;
- dptr += 8;
-
- /* copy to Last Write Time */
- *((FILETIME *)dptr) = ft;
- dptr += 8;
-
- /* copy to Change Time */
- *((FILETIME *)dptr) = ft;
- dptr += 8;
-
- /* Use length for both file length and alloc length */
- *((LARGE_INTEGER *)dptr) = scp->length;
- dptr += 8;
- *((LARGE_INTEGER *)dptr) = scp->length;
- dptr += 8;
-
- /* Copy attributes */
- lattr = smb_ExtAttributes(scp);
- /* merge in hidden (dot file) attribute */
- if( patchp->flags & SMB_DIRLISTPATCH_DOTFILE )
- lattr |= SMB_ATTR_HIDDEN;
-
- *((u_long *)dptr) = lattr;
- dptr += 4;
- }
- else {
- /* get dos time */
- smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
-
- /* and copy out date */
- shortTemp = (dosTime>>16) & 0xffff;
- *((u_short *)dptr) = shortTemp;
- dptr += 2;
-
- /* copy out creation time */
- shortTemp = dosTime & 0xffff;
- *((u_short *)dptr) = shortTemp;
- dptr += 2;
-
- /* and copy out date */
- shortTemp = (dosTime>>16) & 0xffff;
- *((u_short *)dptr) = shortTemp;
- dptr += 2;
-
- /* copy out access time */
- shortTemp = dosTime & 0xffff;
- *((u_short *)dptr) = shortTemp;
- dptr += 2;
-
- /* and copy out date */
- shortTemp = (dosTime>>16) & 0xffff;
- *((u_short *)dptr) = shortTemp;
- dptr += 2;
-
- /* copy out mod time */
- shortTemp = dosTime & 0xffff;
- *((u_short *)dptr) = shortTemp;
- dptr += 2;
-
- /* copy out file length and alloc length,
- * using the same for both
- */
- *((u_long *)dptr) = scp->length.LowPart;
- dptr += 4;
- *((u_long *)dptr) = scp->length.LowPart;
- dptr += 4;
-
- /* finally copy out attributes as short */
- attr = smb_Attributes(scp);
- /* merge in hidden (dot file) attribute */
- if( patchp->flags & SMB_DIRLISTPATCH_DOTFILE )
- attr |= SMB_ATTR_HIDDEN;
-
- *dptr++ = attr & 0xff;
- *dptr++ = (attr >> 8) & 0xff;
- }
+typedef struct smb_rap_server_info_0 {
+ char sv0_name[16];
+} smb_rap_server_info_0_t;
- lock_ReleaseMutex(&scp->mx);
- cm_ReleaseSCache(scp);
- }
-
- /* now free the patches */
- for(patchp = *dirPatchespp; patchp; patchp = npatchp) {
- npatchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q);
- free(patchp);
- }
-
- /* and mark the list as empty */
- *dirPatchespp = NULL;
+typedef struct smb_rap_server_info_1 {
+ char sv1_name[16];
+ char sv1_version_major;
+ char sv1_version_minor;
+ unsigned long sv1_type;
+ DWORD *sv1_comment_or_master_browser; /* char *sv1_comment_or_master_browser;*/
+} smb_rap_server_info_1_t;
- return code;
-}
+char smb_ServerComment[] = "OpenAFS Client";
+int smb_ServerCommentLen = sizeof(smb_ServerComment);
-/* do a case-folding search of the star name mask with the name in namep.
- * Return 1 if we match, otherwise 0.
- */
-int smb_V3MatchMask(char *namep, char *maskp, int flags)
-{
- unsigned char tcp1, tcp2; /* Pattern characters */
- unsigned char tcn1; /* Name characters */
- int sawDot = 0, sawStar = 0;
- char *starNamep, *starMaskp;
- static char nullCharp[] = {0};
-
- /* make sure we only match 8.3 names, if requested */
- if ((flags & CM_FLAG_8DOT3) && !cm_Is8Dot3(namep)) return 0;
-
- /* loop */
- while (1) {
- /* Next pattern character */
- tcp1 = *maskp++;
-
- /* Next name character */
- tcn1 = *namep;
-
- if (tcp1 == 0) {
- /* 0 - end of pattern */
- if (tcn1 == 0)
- return 1;
- else
- return 0;
- }
- else if (tcp1 == '.' || tcp1 == '"') {
- if (sawDot) {
- if (tcn1 == '.') {
- namep++;
- continue;
- } else
- return 0;
- }
- else {
- /*
- * first dot in pattern;
- * must match dot or end of name
- */
- sawDot = 1;
- if (tcn1 == 0)
- continue;
- else if (tcn1 == '.') {
- sawStar = 0;
- namep++;
- continue;
- }
- else
- return 0;
- }
- }
- else if (tcp1 == '?') {
- if (tcn1 == 0 || tcn1 == '.')
- return 0;
- namep++;
- continue;
- }
- else if (tcp1 == '>') {
- if (tcn1 != 0 && tcn1 != '.')
- namep++;
- continue;
- }
- else if (tcp1 == '*' || tcp1 == '<') {
- tcp2 = *maskp++;
- if (tcp2 == 0)
- return 1;
- else if (tcp2 == '.' || tcp2 == '"') {
- while (tcn1 != '.' && tcn1 != 0)
- tcn1 = *++namep;
- if (tcn1 == 0) {
- if (sawDot)
- return 0;
- else
- continue;
- }
- else {
- namep++;
- continue;
- }
- }
- else {
- /*
- * pattern character after '*' is not null or
- * period. If it is '?' or '>', we are not
- * going to understand it. If it is '*' or
- * '<', we are going to skip over it. None of
- * these are likely, I hope.
- */
- /* skip over '*' and '<' */
- while (tcp2 == '*' || tcp2 == '<')
- tcp2 = *maskp++;
-
- /* skip over characters that don't match tcp2 */
- while (tcn1 != '.' && tcn1 != 0
- && cm_foldUpper[tcn1] != cm_foldUpper[tcp2])
- tcn1 = *++namep;
-
- /* No match */
- if (tcn1 == '.' || tcn1 == 0)
- return 0;
-
- /* Remember where we are */
- sawStar = 1;
- starMaskp = maskp;
- starNamep = namep;
-
- namep++;
- continue;
- }
- }
- else {
- /* tcp1 is not a wildcard */
- if (cm_foldUpper[tcn1] == cm_foldUpper[tcp1]) {
- /* they match */
- namep++;
- continue;
- }
- /* if trying to match a star pattern, go back */
- if (sawStar) {
- maskp = starMaskp - 2;
- namep = starNamep + 1;
- sawStar = 0;
- continue;
- }
- /* that's all */
- return 0;
- }
- }
-}
+#define SMB_SV_TYPE_SERVER 0x00000002L
+#define SMB_SV_TYPE_NT 0x00001000L
+#define SMB_SV_TYPE_SERVER_NT 0x00008000L
-long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
+long smb_ReceiveRAPNetServerGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
{
- int attribute;
- long nextCookie;
- char *tp;
- long code;
- char *pathp;
- cm_dirEntry_t *dep;
- int maxCount;
- smb_dirListPatch_t *dirListPatchesp;
- smb_dirListPatch_t *curPatchp;
- cm_buf_t *bufferp;
- long temp;
- long orbytes; /* # of bytes in this output record */
- long ohbytes; /* # of bytes, except file name */
- long onbytes; /* # of bytes in name, incl. term. null */
- osi_hyper_t dirLength;
- osi_hyper_t bufferOffset;
- osi_hyper_t curOffset;
- osi_hyper_t thyper;
- smb_dirSearch_t *dsp;
- cm_scache_t *scp;
- long entryInDir;
- long entryInBuffer;
- cm_pageHeader_t *pageHeaderp;
- cm_user_t *userp = NULL;
- int slotInPage;
- int returnedNames;
- long nextEntryCookie;
- int numDirChunks; /* # of 32 byte dir chunks in this entry */
- char *op; /* output data ptr */
- char *origOp; /* original value of op */
- cm_space_t *spacep; /* for pathname buffer */
- long maxReturnData; /* max # of return data */
- long maxReturnParms; /* max # of return parms */
- long bytesInBuffer; /* # data bytes in the output buffer */
- int starPattern;
- char *maskp; /* mask part of path */
- int infoLevel;
- int searchFlags;
- int eos;
- smb_tran2Packet_t *outp; /* response packet */
- char *tidPathp;
- int align;
- char shortName[13]; /* 8.3 name if needed */
- int NeedShortName;
- char *shortNameEnd;
- int fileType;
- cm_fid_t fid;
-
- cm_req_t req;
-
- cm_InitReq(&req);
-
- eos = 0;
- if (p->opcode == 1) {
- /* find first; obtain basic parameters from request */
- attribute = p->parmsp[0];
- maxCount = p->parmsp[1];
- infoLevel = p->parmsp[3];
- searchFlags = p->parmsp[2];
- dsp = smb_NewDirSearch(1);
- dsp->attribute = attribute;
- pathp = ((char *) p->parmsp) + 12; /* points to path */
- nextCookie = 0;
- maskp = strrchr(pathp, '\\');
- if (maskp == NULL) maskp = pathp;
- else maskp++; /* skip over backslash */
- strcpy(dsp->mask, maskp); /* and save mask */
- /* track if this is likely to match a lot of entries */
- starPattern = smb_V3IsStarMask(maskp);
- }
- else {
- osi_assert(p->opcode == 2);
- /* find next; obtain basic parameters from request or open dir file */
- dsp = smb_FindDirSearch(p->parmsp[0]);
- if (!dsp) return CM_ERROR_BADFD;
- attribute = dsp->attribute;
- maxCount = p->parmsp[1];
- infoLevel = p->parmsp[2];
- searchFlags = p->parmsp[5];
- pathp = NULL;
- nextCookie = p->parmsp[3] | (p->parmsp[4] << 16);
- maskp = dsp->mask;
- starPattern = 1; /* assume, since required a Find Next */
- }
-
- osi_Log4(afsd_logp,
- "T2 search dir attr 0x%x, info level %d, max count %d, flags 0x%x",
- attribute, infoLevel, maxCount, searchFlags);
-
- osi_Log2(afsd_logp, "...T2 search op %d, nextCookie 0x%x",
- p->opcode, nextCookie);
-
- if (infoLevel >= 0x101)
- searchFlags &= ~4; /* no resume keys */
+ smb_tran2Packet_t *outp;
+ long code = 0;
+ int infoLevel;
+ int bufsize;
+ unsigned short * tp;
+ int totalData;
+ int totalParams;
+ smb_rap_server_info_0_t * info0;
+ smb_rap_server_info_1_t * info1;
+ char * cstrp;
+
+ tp = p->parmsp + 1; /* Skip over function number */
+ (void) smb_ParseString((unsigned char*) tp, (char **) &tp); /* skip over param descriptor */
+ (void) smb_ParseString((unsigned char*) tp, (char **) &tp); /* skip over data descriptor */
+ infoLevel = *tp++;
+ bufsize = *tp++;
+
+ if (infoLevel != 0 && infoLevel != 1) {
+ return CM_ERROR_INVAL;
+ }
- dirListPatchesp = NULL;
+ totalParams = 6;
- maxReturnData = p->maxReturnData;
- if (p->opcode == 1) /* find first */
- maxReturnParms = 10; /* bytes */
- else
- maxReturnParms = 8; /* bytes */
+ totalData =
+ (infoLevel == 0) ? sizeof(smb_rap_server_info_0_t)
+ : (sizeof(smb_rap_server_info_1_t) + smb_ServerCommentLen);
-#ifndef CM_CONFIG_MULTITRAN2RESPONSES
- if (maxReturnData > 6000) maxReturnData = 6000;
-#endif /* CM_CONFIG_MULTITRAN2RESPONSES */
+ outp = smb_GetTran2ResponsePacket(vcp, p, op, totalParams, totalData);
- outp = smb_GetTran2ResponsePacket(vcp, p, opx, maxReturnParms,
- maxReturnData);
+ memset(outp->parmsp,0,totalParams);
+ memset(outp->datap,0,totalData);
- osi_Log1(afsd_logp, "T2 receive search dir %s",
- osi_LogSaveString(afsd_logp, pathp));
+ if (infoLevel == 0) {
+ info0 = (smb_rap_server_info_0_t *) outp->datap;
+ cstrp = (char *) (info0 + 1);
+ strcpy(info0->sv0_name, "AFS");
+ } else { /* infoLevel == SMB_INFO_STANDARD */
+ info1 = (smb_rap_server_info_1_t *) outp->datap;
+ cstrp = (char *) (info1 + 1);
+ strcpy(info1->sv1_name, "AFS");
- /* bail out if request looks bad */
- if (p->opcode == 1 && !pathp) {
- smb_ReleaseDirSearch(dsp);
- smb_FreeTran2Packet(outp);
- return CM_ERROR_BADSMB;
- }
+ info1->sv1_type =
+ SMB_SV_TYPE_SERVER |
+ SMB_SV_TYPE_NT |
+ SMB_SV_TYPE_SERVER_NT;
- osi_Log2(afsd_logp, "T2 dir search cookie 0x%x, connection %d",
- nextCookie, dsp->cookie);
+ info1->sv1_version_major = 5;
+ info1->sv1_version_minor = 1;
+ info1->sv1_comment_or_master_browser = (DWORD *) (cstrp - outp->datap);
- userp = smb_GetTran2User(vcp, p);
- if(!userp) {
- osi_Log1(afsd_logp, "T2 dir search unable to resolve user [%d]", p->uid);
- smb_ReleaseDirSearch(dsp);
- smb_FreeTran2Packet(outp);
- return CM_ERROR_BADSMB;
- }
+ strcpy(cstrp, smb_ServerComment);
- /* try to get the vnode for the path name next */
- lock_ObtainMutex(&dsp->mx);
- if (dsp->scp) {
- scp = dsp->scp;
- cm_HoldSCache(scp);
- code = 0;
- }
- else {
- spacep = cm_GetSpace();
- smb_StripLastComponent(spacep->data, NULL, pathp);
- lock_ReleaseMutex(&dsp->mx);
-
- tidPathp = smb_GetTIDPath(vcp, p->tid);
- code = cm_NameI(cm_rootSCachep, spacep->data,
- CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
- userp, tidPathp, &req, &scp);
- cm_FreeSpace(spacep);
-
- lock_ObtainMutex(&dsp->mx);
- if (code == 0) {
- if (dsp->scp != 0) cm_ReleaseSCache(dsp->scp);
- dsp->scp = scp;
- /* we need one hold for the entry we just stored into,
- * and one for our own processing. When we're done
- * with this function, we'll drop the one for our own
- * processing. We held it once from the namei call,
- * and so we do another hold now.
- */
- cm_HoldSCache(scp);
- lock_ObtainMutex(&scp->mx);
- if ((scp->flags & CM_SCACHEFLAG_BULKSTATTING) == 0
- && LargeIntegerGreaterOrEqualToZero(scp->bulkStatProgress)) {
- scp->flags |= CM_SCACHEFLAG_BULKSTATTING;
- dsp->flags |= SMB_DIRSEARCH_BULKST;
- }
- lock_ReleaseMutex(&scp->mx);
- }
- }
- lock_ReleaseMutex(&dsp->mx);
- if (code) {
- cm_ReleaseUser(userp);
- smb_FreeTran2Packet(outp);
- smb_DeleteDirSearch(dsp);
- smb_ReleaseDirSearch(dsp);
- return code;
- }
+ cstrp += smb_ServerCommentLen;
+ }
- /* get the directory size */
- lock_ObtainMutex(&scp->mx);
- code = cm_SyncOp(scp, NULL, userp, &req, 0,
- CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
- if (code) {
- lock_ReleaseMutex(&scp->mx);
- cm_ReleaseSCache(scp);
- cm_ReleaseUser(userp);
- smb_FreeTran2Packet(outp);
- smb_DeleteDirSearch(dsp);
- smb_ReleaseDirSearch(dsp);
- return code;
- }
+ totalData = (DWORD)(cstrp - outp->datap);
+ outp->totalData = min(bufsize,totalData); /* actual data size */
+ outp->parmsp[0] = (outp->totalData == totalData)? 0 : ERROR_MORE_DATA;
+ outp->parmsp[2] = totalData;
+ outp->totalParms = totalParams;
- dirLength = scp->length;
- bufferp = NULL;
- bufferOffset.LowPart = bufferOffset.HighPart = 0;
- curOffset.HighPart = 0;
- curOffset.LowPart = nextCookie;
- origOp = outp->datap;
-
- code = 0;
- returnedNames = 0;
- bytesInBuffer = 0;
- while (1) {
- op = origOp;
- if (searchFlags & 4)
- /* skip over resume key */
- op += 4;
-
- /* make sure that curOffset.LowPart doesn't point to the first
- * 32 bytes in the 2nd through last dir page, and that it doesn't
- * point at the first 13 32-byte chunks in the first dir page,
- * since those are dir and page headers, and don't contain useful
- * information.
- */
- temp = curOffset.LowPart & (2048-1);
- if (curOffset.HighPart == 0 && curOffset.LowPart < 2048) {
- /* we're in the first page */
- if (temp < 13*32) temp = 13*32;
- }
- else {
- /* we're in a later dir page */
- if (temp < 32) temp = 32;
- }
-
- /* make sure the low order 5 bits are zero */
- temp &= ~(32-1);
-
- /* now put temp bits back ito curOffset.LowPart */
- curOffset.LowPart &= ~(2048-1);
- curOffset.LowPart |= temp;
-
- /* check if we've passed the dir's EOF */
- if (LargeIntegerGreaterThanOrEqualTo(curOffset, dirLength)) {
- eos = 1;
- break;
- }
-
- /* check if we've returned all the names that will fit in the
- * response packet; we check return count as well as the number
- * of bytes requested. We check the # of bytes after we find
- * the dir entry, since we'll need to check its size.
- */
- if (returnedNames >= maxCount) {
- break;
- }
-
- /* see if we can use the bufferp we have now; compute in which
- * page the current offset would be, and check whether that's
- * the offset of the buffer we have. If not, get the buffer.
- */
- thyper.HighPart = curOffset.HighPart;
- thyper.LowPart = curOffset.LowPart & ~(buf_bufferSize-1);
- if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
- /* wrong buffer */
- if (bufferp) {
- buf_Release(bufferp);
- bufferp = NULL;
- }
- lock_ReleaseMutex(&scp->mx);
- lock_ObtainRead(&scp->bufCreateLock);
- code = buf_Get(scp, &thyper, &bufferp);
- lock_ReleaseRead(&scp->bufCreateLock);
-
- /* now, if we're doing a star match, do bulk fetching
- * of all of the status info for files in the dir.
- */
- if (starPattern) {
- smb_ApplyV3DirListPatches(scp, &dirListPatchesp,
- infoLevel, userp,
- &req);
- if ((dsp->flags & SMB_DIRSEARCH_BULKST)
- && LargeIntegerGreaterThanOrEqualTo(
- thyper, scp->bulkStatProgress)) {
- /* Don't bulk stat if risking timeout */
- int now = GetCurrentTime();
- if (now - req.startTime > 5000) {
- scp->bulkStatProgress = thyper;
- scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
- dsp->flags &= ~SMB_DIRSEARCH_BULKST;
- } else
- cm_TryBulkStat(scp, &thyper,
- userp, &req);
- }
- }
-
- lock_ObtainMutex(&scp->mx);
- if (code) break;
- bufferOffset = thyper;
-
- /* now get the data in the cache */
- while (1) {
- code = cm_SyncOp(scp, bufferp, userp, &req,
- PRSFS_LOOKUP,
- CM_SCACHESYNC_NEEDCALLBACK
- | CM_SCACHESYNC_READ);
- if (code) break;
-
- if (cm_HaveBuffer(scp, bufferp, 0)) break;
-
- /* otherwise, load the buffer and try again */
- code = cm_GetBuffer(scp, bufferp, NULL, userp,
- &req);
- if (code) break;
- }
- if (code) {
- buf_Release(bufferp);
- bufferp = NULL;
- break;
- }
- } /* if (wrong buffer) ... */
-
- /* now we have the buffer containing the entry we're interested
- * in; copy it out if it represents a non-deleted entry.
- */
- entryInDir = curOffset.LowPart & (2048-1);
- entryInBuffer = curOffset.LowPart & (buf_bufferSize - 1);
-
- /* page header will help tell us which entries are free. Page
- * header can change more often than once per buffer, since
- * AFS 3 dir page size may be less than (but not more than)
- * a buffer package buffer.
- */
- /* only look intra-buffer */
- temp = curOffset.LowPart & (buf_bufferSize - 1);
- temp &= ~(2048 - 1); /* turn off intra-page bits */
- pageHeaderp = (cm_pageHeader_t *) (bufferp->datap + temp);
-
- /* now determine which entry we're looking at in the page.
- * If it is free (there's a free bitmap at the start of the
- * dir), we should skip these 32 bytes.
- */
- slotInPage = (entryInDir & 0x7e0) >> 5;
- if (!(pageHeaderp->freeBitmap[slotInPage>>3]
- & (1 << (slotInPage & 0x7)))) {
- /* this entry is free */
- numDirChunks = 1; /* only skip this guy */
- goto nextEntry;
- }
-
- tp = bufferp->datap + entryInBuffer;
- dep = (cm_dirEntry_t *) tp; /* now points to AFS3 dir entry */
-
- /* while we're here, compute the next entry's location, too,
- * since we'll need it when writing out the cookie into the dir
- * listing stream.
- *
- * XXXX Probably should do more sanity checking.
- */
- numDirChunks = cm_NameEntries(dep->name, &onbytes);
-
- /* compute offset of cookie representing next entry */
- nextEntryCookie = curOffset.LowPart
- + (CM_DIR_CHUNKSIZE * numDirChunks);
-
- /* Need 8.3 name? */
- NeedShortName = 0;
- if (infoLevel == 0x104
- && dep->fid.vnode != 0
- && !cm_Is8Dot3(dep->name)) {
- cm_Gen8Dot3Name(dep, shortName, &shortNameEnd);
- NeedShortName = 1;
- }
-
- if (dep->fid.vnode != 0
- && (smb_V3MatchMask(dep->name, maskp, CM_FLAG_CASEFOLD)
- || (NeedShortName
- && smb_V3MatchMask(shortName, maskp,
- CM_FLAG_CASEFOLD)))) {
-
- /* Eliminate entries that don't match requested
- attributes */
- if (smb_hideDotFiles && !(dsp->attribute & SMB_ATTR_HIDDEN) && smb_IsDotFile(dep->name))
- goto nextEntry; /* no hidden files */
-
- if (!(dsp->attribute & SMB_ATTR_DIRECTORY)) /* no directories */
- {
- /* We have already done the cm_TryBulkStat above */
- fid.cell = scp->fid.cell;
- fid.volume = scp->fid.volume;
- fid.vnode = ntohl(dep->fid.vnode);
- fid.unique = ntohl(dep->fid.unique);
- fileType = cm_FindFileType(&fid);
- /*osi_Log2(afsd_logp, "smb_ReceiveTran2SearchDir: file %s "
- "has filetype %d", dep->name,
- fileType);*/
- if (fileType == CM_SCACHETYPE_DIRECTORY)
- goto nextEntry;
- }
-
- /* finally check if this name will fit */
-
- /* standard dir entry stuff */
- if (infoLevel < 0x101)
- ohbytes = 23; /* pre-NT */
- else if (infoLevel == 0x103)
- ohbytes = 12; /* NT names only */
- else
- ohbytes = 64; /* NT */
-
- if (infoLevel == 0x104)
- ohbytes += 26; /* Short name & length */
-
- if (searchFlags & 4) {
- ohbytes += 4; /* if resume key required */
- }
-
- if (infoLevel != 1
- && infoLevel != 0x101
- && infoLevel != 0x103)
- ohbytes += 4; /* EASIZE */
-
- /* add header to name & term. null */
- orbytes = onbytes + ohbytes + 1;
-
- /* now, we round up the record to a 4 byte alignment,
- * and we make sure that we have enough room here for
- * even the aligned version (so we don't have to worry
- * about an * overflow when we pad things out below).
- * That's the reason for the alignment arithmetic below.
- */
- if (infoLevel >= 0x101)
- align = (4 - (orbytes & 3)) & 3;
- else
- align = 0;
- if (orbytes + bytesInBuffer + align > maxReturnData)
- break;
-
- /* this is one of the entries to use: it is not deleted
- * and it matches the star pattern we're looking for.
- * Put out the name, preceded by its length.
- */
- /* First zero everything else */
- memset(origOp, 0, ohbytes);
-
- if (infoLevel <= 0x101)
- *(origOp + ohbytes - 1) = (unsigned char) onbytes;
- else if (infoLevel == 0x103)
- *((u_long *)(op + 8)) = onbytes;
- else
- *((u_long *)(op + 60)) = onbytes;
- strcpy(origOp+ohbytes, dep->name);
-
- /* Short name if requested and needed */
- if (infoLevel == 0x104) {
- if (NeedShortName) {
- strcpy(op + 70, shortName);
- *(op + 68) = shortNameEnd - shortName;
- }
- }
-
- /* now, adjust the # of entries copied */
- returnedNames++;
-
- /* NextEntryOffset and FileIndex */
- if (infoLevel >= 101) {
- int entryOffset = orbytes + align;
- *((u_long *)op) = entryOffset;
- *((u_long *)(op+4)) = nextEntryCookie;
- }
-
- /* now we emit the attribute. This is tricky, since
- * we need to really stat the file to find out what
- * type of entry we've got. Right now, we're copying
- * out data from * a buffer, while holding the scp
- * locked, so it isn't really convenient to stat
- * something now. We'll put in a place holder
- * now, and make a second pass before returning this
- * to get the real attributes. So, we just skip the
- * data for now, and adjust it later. We allocate a
- * patch record to make it easy to find this point
- * later. The replay will happen at a time when it is
- * safe to unlock the directory.
- */
- if (infoLevel != 0x103) {
- curPatchp = malloc(sizeof(*curPatchp));
- osi_QAdd((osi_queue_t **) &dirListPatchesp,
- &curPatchp->q);
- curPatchp->dptr = op;
- if (infoLevel >= 0x101)
- curPatchp->dptr += 8;
-
- if (smb_hideDotFiles && smb_IsDotFile(dep->name)) {
- curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
- }
- else
- curPatchp->flags = 0;
-
- curPatchp->fid.cell = scp->fid.cell;
- curPatchp->fid.volume = scp->fid.volume;
- curPatchp->fid.vnode = ntohl(dep->fid.vnode);
- curPatchp->fid.unique = ntohl(dep->fid.unique);
-
- /* temp */
- curPatchp->dep = dep;
- }
-
- if (searchFlags & 4)
- /* put out resume key */
- *((u_long *)origOp) = nextEntryCookie;
-
- /* Adjust byte ptr and count */
- origOp += orbytes; /* skip entire record */
- bytesInBuffer += orbytes;
-
- /* and pad the record out */
- while (--align >= 0) {
- *origOp++ = 0;
- bytesInBuffer++;
- }
-
- } /* if we're including this name */
-
-nextEntry:
- /* and adjust curOffset to be where the new cookie is */
- thyper.HighPart = 0;
- thyper.LowPart = CM_DIR_CHUNKSIZE * numDirChunks;
- curOffset = LargeIntegerAdd(thyper, curOffset);
- } /* while copying data for dir listing */
-
- /* release the mutex */
- lock_ReleaseMutex(&scp->mx);
- if (bufferp) buf_Release(bufferp);
-
- /* apply and free last set of patches; if not doing a star match, this
- * will be empty, but better safe (and freeing everything) than sorry.
- */
- smb_ApplyV3DirListPatches(scp, &dirListPatchesp, infoLevel, userp,
- &req);
-
- /* now put out the final parameters */
- if (returnedNames == 0) eos = 1;
- if (p->opcode == 1) {
- /* find first */
- outp->parmsp[0] = (unsigned short) dsp->cookie;
- outp->parmsp[1] = returnedNames;
- outp->parmsp[2] = eos;
- outp->parmsp[3] = 0; /* nothing wrong with EAS */
- outp->parmsp[4] = 0; /* don't need last name to continue
- * search, cookie is enough. Normally,
- * this is the offset of the file name
- * of the last entry returned.
- */
- outp->totalParms = 10; /* in bytes */
- }
- else {
- /* find next */
- outp->parmsp[0] = returnedNames;
- outp->parmsp[1] = eos;
- outp->parmsp[2] = 0; /* EAS error */
- outp->parmsp[3] = 0; /* last name, as above */
- outp->totalParms = 8; /* in bytes */
- }
+ smb_SendTran2Packet(vcp,outp,op);
+ smb_FreeTran2Packet(outp);
- /* return # of bytes in the buffer */
- outp->totalData = bytesInBuffer;
-
- osi_Log2(afsd_logp, "T2 search dir done, %d names, code %d",
- returnedNames, code);
-
- /* Return error code if unsuccessful on first request */
- if (code == 0 && p->opcode == 1 && returnedNames == 0)
- code = CM_ERROR_NOSUCHFILE;
-
- /* if we're supposed to close the search after this request, or if
- * we're supposed to close the search if we're done, and we're done,
- * or if something went wrong, close the search.
- */
- /* ((searchFlags & 1) || ((searchFlags & 2) && eos) */
- /* pbh - added patch submitted to openafs-dev from James Petterson on 26 Feb, 2003 */
- if ((searchFlags & 1) || (returnedNames == 0) || ((searchFlags & 2) && eos)
- || code != 0)
- smb_DeleteDirSearch(dsp);
- if (code)
- smb_SendTran2Error(vcp, p, opx, code);
- else {
- smb_SendTran2Packet(vcp, outp, opx);
- }
- smb_FreeTran2Packet(outp);
- smb_ReleaseDirSearch(dsp);
- cm_ReleaseSCache(scp);
- cm_ReleaseUser(userp);
- return 0;
+ return code;
}
-long smb_ReceiveV3FindClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
+long smb_ReceiveV3Tran2A(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
{
- int dirHandle;
- smb_dirSearch_t *dsp;
+ smb_tran2Packet_t *asp;
+ int totalParms;
+ int totalData;
+ int parmDisp;
+ int dataDisp;
+ int parmOffset;
+ int dataOffset;
+ int parmCount;
+ int dataCount;
+ int firstPacket;
+ long code = 0;
+
+ /* We sometimes see 0 word count. What to do? */
+ if (*inp->wctp == 0) {
+ osi_Log0(smb_logp, "Transaction2 word count = 0");
+#ifndef DJGPP
+ LogEvent(EVENTLOG_WARNING_TYPE, MSG_SMB_ZERO_TRANSACTION_COUNT);
+#endif /* !DJGPP */
- dirHandle = smb_GetSMBParm(inp, 0);
-
- osi_Log1(afsd_logp, "SMB3 find close handle %d", dirHandle);
+ smb_SetSMBDataLength(outp, 0);
+ smb_SendPacket(vcp, outp);
+ return 0;
+ }
- dsp = smb_FindDirSearch(dirHandle);
+ totalParms = smb_GetSMBParm(inp, 0);
+ totalData = smb_GetSMBParm(inp, 1);
- if (!dsp)
- return CM_ERROR_BADFD;
-
- /* otherwise, we have an FD to destroy */
- smb_DeleteDirSearch(dsp);
- smb_ReleaseDirSearch(dsp);
+ firstPacket = (inp->inCom == 0x32);
+
+ /* find the packet we're reassembling */
+ lock_ObtainWrite(&smb_globalLock);
+ asp = smb_FindTran2Packet(vcp, inp);
+ if (!asp) {
+ asp = smb_NewTran2Packet(vcp, inp, totalParms, totalData);
+ }
+ lock_ReleaseWrite(&smb_globalLock);
- /* and return results */
- smb_SetSMBDataLength(outp, 0);
+ /* now merge in this latest packet; start by looking up offsets */
+ if (firstPacket) {
+ parmDisp = dataDisp = 0;
+ parmOffset = smb_GetSMBParm(inp, 10);
+ dataOffset = smb_GetSMBParm(inp, 12);
+ parmCount = smb_GetSMBParm(inp, 9);
+ dataCount = smb_GetSMBParm(inp, 11);
+ asp->maxReturnParms = smb_GetSMBParm(inp, 2);
+ asp->maxReturnData = smb_GetSMBParm(inp, 3);
+
+ osi_Log3(smb_logp, "SMB3 received T2 init packet total data %d, cur data %d, max return data %d",
+ totalData, dataCount, asp->maxReturnData);
+ }
+ else {
+ parmDisp = smb_GetSMBParm(inp, 4);
+ parmOffset = smb_GetSMBParm(inp, 3);
+ dataDisp = smb_GetSMBParm(inp, 7);
+ dataOffset = smb_GetSMBParm(inp, 6);
+ parmCount = smb_GetSMBParm(inp, 2);
+ dataCount = smb_GetSMBParm(inp, 5);
+
+ osi_Log2(smb_logp, "SMB3 received T2 aux packet parms %d, data %d",
+ parmCount, dataCount);
+ }
+
+ /* now copy the parms and data */
+ if ( asp->totalParms > 0 && parmCount != 0 )
+ {
+ memcpy(((char *)asp->parmsp) + parmDisp, inp->data + parmOffset, parmCount);
+ }
+ if ( asp->totalData > 0 && dataCount != 0 ) {
+ memcpy(asp->datap + dataDisp, inp->data + dataOffset, dataCount);
+ }
- return 0;
-}
+ /* account for new bytes */
+ asp->curData += dataCount;
+ asp->curParms += parmCount;
+
+ /* finally, if we're done, remove the packet from the queue and dispatch it */
+ if (asp->totalParms > 0 &&
+ asp->curParms > 0 &&
+ asp->totalData <= asp->curData &&
+ asp->totalParms <= asp->curParms) {
+ /* we've received it all */
+ lock_ObtainWrite(&smb_globalLock);
+ osi_QRemove((osi_queue_t **) &smb_tran2AssemblyQueuep, &asp->q);
+ lock_ReleaseWrite(&smb_globalLock);
+
+ /* now dispatch it */
+ if ( asp->opcode >= 0 && asp->opcode < 20 && smb_tran2DispatchTable[asp->opcode].procp) {
+ osi_Log4(smb_logp,"AFS Server - Dispatch-2 %s vcp[%p] lana[%d] lsn[%d]",myCrt_2Dispatch(asp->opcode),vcp,vcp->lana,vcp->lsn);
+ code = (*smb_tran2DispatchTable[asp->opcode].procp)(vcp, asp, outp);
+ }
+ else {
+ osi_Log4(smb_logp,"AFS Server - Dispatch-2 [INVALID] op[%x] vcp[%p] lana[%d] lsn[%d]", asp->opcode, vcp, vcp->lana, vcp->lsn);
+ code = CM_ERROR_BADOP;
+ }
-long smb_ReceiveV3FindNotifyClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
-{
- smb_SetSMBDataLength(outp, 0);
- return 0;
+ /* if an error is returned, we're supposed to send an error packet,
+ * otherwise the dispatched function already did the data sending.
+ * We give dispatched proc the responsibility since it knows how much
+ * space to allocate.
+ */
+ if (code != 0) {
+ smb_SendTran2Error(vcp, asp, outp, code);
+ }
+
+ /* free the input tran 2 packet */
+ lock_ObtainWrite(&smb_globalLock);
+ smb_FreeTran2Packet(asp);
+ lock_ReleaseWrite(&smb_globalLock);
+ }
+ else if (firstPacket) {
+ /* the first packet in a multi-packet request, we need to send an
+ * ack to get more data.
+ */
+ smb_SetSMBDataLength(outp, 0);
+ smb_SendPacket(vcp, outp);
+ }
+
+ return 0;
}
-long smb_ReceiveV3OpenX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
+long smb_ReceiveTran2Open(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
{
- char *pathp;
- long code;
- cm_space_t *spacep;
- int excl;
- cm_user_t *userp;
- cm_scache_t *dscp; /* dir we're dealing with */
- cm_scache_t *scp; /* file we're creating */
- cm_attr_t setAttr;
- int initialModeBits;
- smb_fid_t *fidp;
- int attributes;
- char *lastNamep;
- long dosTime;
- int openFun;
- int trunc;
- int openMode;
- int extraInfo;
- int openAction;
- int parmSlot; /* which parm we're dealing with */
- char *tidPathp;
- cm_req_t req;
-
- cm_InitReq(&req);
-
- scp = NULL;
+ char *pathp;
+ smb_tran2Packet_t *outp;
+ long code = 0;
+ cm_space_t *spacep;
+ int excl;
+ cm_user_t *userp;
+ cm_scache_t *dscp; /* dir we're dealing with */
+ cm_scache_t *scp; /* file we're creating */
+ cm_attr_t setAttr;
+ int initialModeBits;
+ smb_fid_t *fidp;
+ int attributes;
+ char *lastNamep;
+ afs_uint32 dosTime;
+ int openFun;
+ int trunc;
+ int openMode;
+ int extraInfo;
+ int openAction;
+ int parmSlot; /* which parm we're dealing with */
+ long returnEALength;
+ char *tidPathp;
+ cm_req_t req;
+
+ cm_InitReq(&req);
+
+ scp = NULL;
- extraInfo = (smb_GetSMBParm(inp, 2) & 1); /* return extra info */
- openFun = smb_GetSMBParm(inp, 8); /* open function */
- excl = ((openFun & 3) == 0);
- trunc = ((openFun & 3) == 2); /* truncate it */
- openMode = (smb_GetSMBParm(inp, 3) & 0x7);
- openAction = 0; /* tracks what we did */
-
- attributes = smb_GetSMBParm(inp, 5);
- dosTime = smb_GetSMBParm(inp, 6) | (smb_GetSMBParm(inp, 7) << 16);
+ extraInfo = (p->parmsp[0] & 1); /* return extra info */
+ returnEALength = (p->parmsp[0] & 8); /* return extended attr length */
+
+ openFun = p->parmsp[6]; /* open function */
+ excl = ((openFun & 3) == 0);
+ trunc = ((openFun & 3) == 2); /* truncate it */
+ openMode = (p->parmsp[1] & 0x7);
+ openAction = 0; /* tracks what we did */
+
+ attributes = p->parmsp[3];
+ dosTime = p->parmsp[4] | (p->parmsp[5] << 16);
- /* compute initial mode bits based on read-only flag in attributes */
- initialModeBits = 0666;
- if (attributes & 1) initialModeBits &= ~0222;
+ /* compute initial mode bits based on read-only flag in attributes */
+ initialModeBits = 0666;
+ if (attributes & 1)
+ initialModeBits &= ~0222;
- pathp = smb_GetSMBData(inp, NULL);
-
- spacep = inp->spacep;
- smb_StripLastComponent(spacep->data, &lastNamep, pathp);
+ pathp = (char *) (&p->parmsp[14]);
+ if (smb_StoreAnsiFilenames)
+ OemToChar(pathp,pathp);
+
+ outp = smb_GetTran2ResponsePacket(vcp, p, op, 40, 0);
+
+ spacep = cm_GetSpace();
+ smb_StripLastComponent(spacep->data, &lastNamep, pathp);
+
+ if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
+ /* special case magic file name for receiving IOCTL requests
+ * (since IOCTL calls themselves aren't getting through).
+ */
+ fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
+ smb_SetupIoctlFid(fidp, spacep);
- if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
- /* special case magic file name for receiving IOCTL requests
- * (since IOCTL calls themselves aren't getting through).
- */
-#ifdef NOTSERVICE
- osi_Log0(afsd_logp, "IOCTL Open");
-#endif
- fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
- smb_SetupIoctlFid(fidp, spacep);
+ /* copy out remainder of the parms */
+ parmSlot = 0;
+ outp->parmsp[parmSlot++] = fidp->fid;
+ if (extraInfo) {
+ outp->parmsp[parmSlot++] = 0; /* attrs */
+ outp->parmsp[parmSlot++] = 0; /* mod time */
+ outp->parmsp[parmSlot++] = 0;
+ outp->parmsp[parmSlot++] = 0; /* len */
+ outp->parmsp[parmSlot++] = 0x7fff;
+ outp->parmsp[parmSlot++] = openMode;
+ outp->parmsp[parmSlot++] = 0; /* file type 0 ==> normal file or dir */
+ outp->parmsp[parmSlot++] = 0; /* IPC junk */
+ }
+ /* and the final "always present" stuff */
+ outp->parmsp[parmSlot++] = 1; /* openAction found existing file */
+ /* next write out the "unique" ID */
+ outp->parmsp[parmSlot++] = 0x1234;
+ outp->parmsp[parmSlot++] = 0x5678;
+ outp->parmsp[parmSlot++] = 0;
+ if (returnEALength) {
+ outp->parmsp[parmSlot++] = 0;
+ outp->parmsp[parmSlot++] = 0;
+ }
+
+ outp->totalData = 0;
+ outp->totalParms = parmSlot * 2;
+
+ smb_SendTran2Packet(vcp, outp, op);
+
+ smb_FreeTran2Packet(outp);
- /* set inp->fid so that later read calls in same msg can find fid */
- inp->fid = fidp->fid;
-
- /* copy out remainder of the parms */
- parmSlot = 2;
- smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
- if (extraInfo) {
- smb_SetSMBParm(outp, parmSlot, /* attrs */ 0); parmSlot++;
- smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* mod time */
- smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
- smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* len */
- smb_SetSMBParm(outp, parmSlot, 0x7fff); parmSlot++;
- smb_SetSMBParm(outp, parmSlot, openMode); parmSlot++;
- smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* file type 0 ==> normal file or dir */
- smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* IPC junk */
- }
- /* and the final "always present" stuff */
- smb_SetSMBParm(outp, parmSlot, /* openAction found existing file */ 1); parmSlot++;
- /* next write out the "unique" ID */
- smb_SetSMBParm(outp, parmSlot, 0x1234); parmSlot++;
- smb_SetSMBParm(outp, parmSlot, 0x5678); parmSlot++;
- smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
- smb_SetSMBDataLength(outp, 0);
-
- /* and clean up fid reference */
- smb_ReleaseFID(fidp);
- return 0;
- }
+ /* and clean up fid reference */
+ smb_ReleaseFID(fidp);
+ return 0;
+ }
#ifdef DEBUG_VERBOSE
- {
- char *hexp, *asciip;
- asciip = (lastNamep ? lastNamep : pathp );
- hexp = osi_HexifyString(asciip);
- DEBUG_EVENT2("AFS", "V3Open H[%s] A[%s]", hexp, asciip );
- free(hexp);
- }
+ {
+ char *hexp, *asciip;
+ asciip = (lastNamep ? lastNamep : pathp);
+ hexp = osi_HexifyString( asciip );
+ DEBUG_EVENT2("AFS","T2Open H[%s] A[%s]", hexp, asciip);
+ free(hexp);
+ }
#endif
- userp = smb_GetUser(vcp, inp);
-
- dscp = NULL;
- tidPathp = smb_GetTIDPath(vcp, ((smb_t *)inp)->tid);
- code = cm_NameI(cm_rootSCachep, pathp,
- CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
- userp, tidPathp, &req, &scp);
- if (code != 0) {
- code = cm_NameI(cm_rootSCachep, spacep->data,
- CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
- userp, tidPathp, &req, &dscp);
-
- if (code) {
- cm_ReleaseUser(userp);
- return code;
- }
-
- /* otherwise, scp points to the parent directory. Do a lookup,
- * and truncate the file if we find it, otherwise we create the
- * file.
- */
- if (!lastNamep) lastNamep = pathp;
- else lastNamep++;
- code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD, userp,
- &req, &scp);
- if (code && code != CM_ERROR_NOSUCHFILE) {
- cm_ReleaseSCache(dscp);
- cm_ReleaseUser(userp);
- return code;
- }
- }
-
- /* if we get here, if code is 0, the file exists and is represented by
- * scp. Otherwise, we have to create it. The dir may be represented
- * by dscp, or we may have found the file directly. If code is non-zero,
- * scp is NULL.
+ userp = smb_GetTran2User(vcp, p);
+ /* In the off chance that userp is NULL, we log and abandon */
+ if (!userp) {
+ osi_Log1(smb_logp, "ReceiveTran2Open user [%d] not resolvable", p->uid);
+ smb_FreeTran2Packet(outp);
+ return CM_ERROR_BADSMB;
+ }
+
+ code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
+ if (code == CM_ERROR_TIDIPC) {
+ /* Attempt to use a TID allocated for IPC. The client
+ * is probably looking for DCE RPC end points which we
+ * don't support OR it could be looking to make a DFS
+ * referral request.
*/
- if (code == 0) {
- code = cm_CheckOpen(scp, openMode, trunc, userp, &req);
- if (code) {
- if (dscp) cm_ReleaseSCache(dscp);
- cm_ReleaseSCache(scp);
- cm_ReleaseUser(userp);
- return code;
- }
+ osi_Log0(smb_logp, "Tran2Open received IPC TID");
+#ifndef DFS_SUPPORT
+ cm_ReleaseUser(userp);
+ smb_FreeTran2Packet(outp);
+ return CM_ERROR_NOSUCHPATH;
+#endif
+ }
- if (excl) {
- /* oops, file shouldn't be there */
- if (dscp) cm_ReleaseSCache(dscp);
- cm_ReleaseSCache(scp);
- cm_ReleaseUser(userp);
- return CM_ERROR_EXISTS;
- }
+ dscp = NULL;
+ code = cm_NameI(cm_data.rootSCachep, pathp,
+ CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
+ userp, tidPathp, &req, &scp);
+ if (code != 0) {
+ code = cm_NameI(cm_data.rootSCachep, spacep->data,
+ CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
+ userp, tidPathp, &req, &dscp);
+ cm_FreeSpace(spacep);
- if (trunc) {
- setAttr.mask = CM_ATTRMASK_LENGTH;
- setAttr.length.LowPart = 0;
- setAttr.length.HighPart = 0;
- code = cm_SetAttr(scp, &setAttr, userp, &req);
- openAction = 3; /* truncated existing file */
- }
- else openAction = 1; /* found existing file */
+ if (code) {
+ cm_ReleaseUser(userp);
+ smb_FreeTran2Packet(outp);
+ return code;
}
- else if (!(openFun & 0x10)) {
- /* don't create if not found */
- if (dscp) cm_ReleaseSCache(dscp);
- cm_ReleaseUser(userp);
- return CM_ERROR_NOSUCHFILE;
+
+#ifdef DFS_SUPPORT
+ if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
+ cm_ReleaseSCache(dscp);
+ cm_ReleaseUser(userp);
+ smb_FreeTran2Packet(outp);
+ if ( WANTS_DFS_PATHNAMES(p) )
+ return CM_ERROR_PATH_NOT_COVERED;
+ else
+ return CM_ERROR_BADSHARENAME;
}
- else {
- osi_assert(dscp != NULL);
- osi_Log1(afsd_logp, "smb_ReceiveV3OpenX creating file %s",
- osi_LogSaveString(afsd_logp, lastNamep));
- openAction = 2; /* created file */
- setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
- smb_UnixTimeFromDosUTime(&setAttr.clientModTime, dosTime);
- code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
- &req);
- if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
- smb_NotifyChange(FILE_ACTION_ADDED,
- FILE_NOTIFY_CHANGE_FILE_NAME,
- dscp, lastNamep, NULL, TRUE);
- if (!excl && code == CM_ERROR_EXISTS) {
- /* not an exclusive create, and someone else tried
- * creating it already, then we open it anyway. We
- * don't bother retrying after this, since if this next
- * fails, that means that the file was deleted after we
- * started this call.
- */
- code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
- userp, &req, &scp);
- if (code == 0) {
- if (trunc) {
- setAttr.mask = CM_ATTRMASK_LENGTH;
- setAttr.length.LowPart = 0;
- setAttr.length.HighPart = 0;
- code = cm_SetAttr(scp, &setAttr, userp,
- &req);
- }
- } /* lookup succeeded */
- }
+#endif /* DFS_SUPPORT */
+
+ /* otherwise, scp points to the parent directory. Do a lookup,
+ * and truncate the file if we find it, otherwise we create the
+ * file.
+ */
+ if (!lastNamep)
+ lastNamep = pathp;
+ else
+ lastNamep++;
+ code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD, userp,
+ &req, &scp);
+ if (code && code != CM_ERROR_NOSUCHFILE) {
+ cm_ReleaseSCache(dscp);
+ cm_ReleaseUser(userp);
+ smb_FreeTran2Packet(outp);
+ return code;
}
-
- /* we don't need this any longer */
- if (dscp) cm_ReleaseSCache(dscp);
+ } else {
+#ifdef DFS_SUPPORT
+ if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
+ cm_ReleaseSCache(scp);
+ cm_ReleaseUser(userp);
+ smb_FreeTran2Packet(outp);
+ if ( WANTS_DFS_PATHNAMES(p) )
+ return CM_ERROR_PATH_NOT_COVERED;
+ else
+ return CM_ERROR_BADSHARENAME;
+ }
+#endif /* DFS_SUPPORT */
+ /* macintosh is expensive to program for it */
+ cm_FreeSpace(spacep);
+ }
+
+ /* if we get here, if code is 0, the file exists and is represented by
+ * scp. Otherwise, we have to create it.
+ */
+ if (code == 0) {
+ code = cm_CheckOpen(scp, openMode, trunc, userp, &req);
if (code) {
- /* something went wrong creating or truncating the file */
- if (scp) cm_ReleaseSCache(scp);
- cm_ReleaseUser(userp);
- return code;
+ if (dscp)
+ cm_ReleaseSCache(dscp);
+ cm_ReleaseSCache(scp);
+ cm_ReleaseUser(userp);
+ smb_FreeTran2Packet(outp);
+ return code;
+ }
+
+ if (excl) {
+ /* oops, file shouldn't be there */
+ if (dscp)
+ cm_ReleaseSCache(dscp);
+ cm_ReleaseSCache(scp);
+ cm_ReleaseUser(userp);
+ smb_FreeTran2Packet(outp);
+ return CM_ERROR_EXISTS;
+ }
+
+ if (trunc) {
+ setAttr.mask = CM_ATTRMASK_LENGTH;
+ setAttr.length.LowPart = 0;
+ setAttr.length.HighPart = 0;
+ code = cm_SetAttr(scp, &setAttr, userp, &req);
+ openAction = 3; /* truncated existing file */
+ }
+ else
+ openAction = 1; /* found existing file */
+ }
+ else if (!(openFun & 0x10)) {
+ /* don't create if not found */
+ if (dscp)
+ cm_ReleaseSCache(dscp);
+ osi_assert(scp == NULL);
+ cm_ReleaseUser(userp);
+ smb_FreeTran2Packet(outp);
+ return CM_ERROR_NOSUCHFILE;
+ }
+ else {
+ osi_assert(dscp != NULL && scp == NULL);
+ openAction = 2; /* created file */
+ setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
+ smb_UnixTimeFromSearchTime(&setAttr.clientModTime, dosTime);
+ code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
+ &req);
+ if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
+ smb_NotifyChange(FILE_ACTION_ADDED,
+ FILE_NOTIFY_CHANGE_FILE_NAME,
+ dscp, lastNamep, NULL, TRUE);
+ if (!excl && code == CM_ERROR_EXISTS) {
+ /* not an exclusive create, and someone else tried
+ * creating it already, then we open it anyway. We
+ * don't bother retrying after this, since if this next
+ * fails, that means that the file was deleted after we
+ * started this call.
+ */
+ code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
+ userp, &req, &scp);
+ if (code == 0) {
+ if (trunc) {
+ setAttr.mask = CM_ATTRMASK_LENGTH;
+ setAttr.length.LowPart = 0;
+ setAttr.length.HighPart = 0;
+ code = cm_SetAttr(scp, &setAttr, userp,
+ &req);
+ }
+ } /* lookup succeeded */
}
+ }
- /* make sure we're about to open a file */
- if (scp->fileType != CM_SCACHETYPE_FILE) {
- cm_ReleaseSCache(scp);
- cm_ReleaseUser(userp);
- return CM_ERROR_ISDIR;
- }
+ /* we don't need this any longer */
+ if (dscp)
+ cm_ReleaseSCache(dscp);
+
+ if (code) {
+ /* something went wrong creating or truncating the file */
+ if (scp)
+ cm_ReleaseSCache(scp);
+ cm_ReleaseUser(userp);
+ smb_FreeTran2Packet(outp);
+ return code;
+ }
+
+ /* make sure we're about to open a file */
+ if (scp->fileType != CM_SCACHETYPE_FILE) {
+ code = 0;
+ while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
+ cm_scache_t * targetScp = 0;
+ code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
+ if (code == 0) {
+ /* we have a more accurate file to use (the
+ * target of the symbolic link). Otherwise,
+ * we'll just use the symlink anyway.
+ */
+ osi_Log2(smb_logp, "symlink vp %x to vp %x",
+ scp, targetScp);
+ cm_ReleaseSCache(scp);
+ scp = targetScp;
+ }
+ }
+ if (scp->fileType != CM_SCACHETYPE_FILE) {
+ cm_ReleaseSCache(scp);
+ cm_ReleaseUser(userp);
+ smb_FreeTran2Packet(outp);
+ return CM_ERROR_ISDIR;
+ }
+ }
- /* now all we have to do is open the file itself */
- fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
- osi_assert(fidp);
+ /* now all we have to do is open the file itself */
+ fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
+ osi_assert(fidp);
- /* save a pointer to the vnode */
- fidp->scp = scp;
+ /* save a pointer to the vnode */
+ fidp->scp = scp;
+ /* and the user */
+ cm_HoldUser(userp);
+ fidp->userp = userp;
- /* compute open mode */
- if (openMode != 1) fidp->flags |= SMB_FID_OPENREAD;
- if (openMode == 1 || openMode == 2)
- fidp->flags |= SMB_FID_OPENWRITE;
+ /* compute open mode */
+ if (openMode != 1) fidp->flags |= SMB_FID_OPENREAD;
+ if (openMode == 1 || openMode == 2)
+ fidp->flags |= SMB_FID_OPENWRITE;
- smb_ReleaseFID(fidp);
+ smb_ReleaseFID(fidp);
- cm_Open(scp, 0, userp);
+ cm_Open(scp, 0, userp);
+
+ /* copy out remainder of the parms */
+ parmSlot = 0;
+ outp->parmsp[parmSlot++] = fidp->fid;
+ lock_ObtainMutex(&scp->mx);
+ if (extraInfo) {
+ outp->parmsp[parmSlot++] = smb_Attributes(scp);
+ smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
+ outp->parmsp[parmSlot++] = (unsigned short)(dosTime & 0xffff);
+ outp->parmsp[parmSlot++] = (unsigned short)((dosTime>>16) & 0xffff);
+ outp->parmsp[parmSlot++] = (unsigned short) (scp->length.LowPart & 0xffff);
+ outp->parmsp[parmSlot++] = (unsigned short) ((scp->length.LowPart >> 16) & 0xffff);
+ outp->parmsp[parmSlot++] = openMode;
+ outp->parmsp[parmSlot++] = 0; /* file type 0 ==> normal file or dir */
+ outp->parmsp[parmSlot++] = 0; /* IPC junk */
+ }
+ /* and the final "always present" stuff */
+ outp->parmsp[parmSlot++] = openAction;
+ /* next write out the "unique" ID */
+ outp->parmsp[parmSlot++] = (unsigned short) (scp->fid.vnode & 0xffff);
+ outp->parmsp[parmSlot++] = (unsigned short) (scp->fid.volume & 0xffff);
+ outp->parmsp[parmSlot++] = 0;
+ if (returnEALength) {
+ outp->parmsp[parmSlot++] = 0;
+ outp->parmsp[parmSlot++] = 0;
+ }
+ lock_ReleaseMutex(&scp->mx);
+ outp->totalData = 0; /* total # of data bytes */
+ outp->totalParms = parmSlot * 2; /* shorts are two bytes */
+
+ smb_SendTran2Packet(vcp, outp, op);
+
+ smb_FreeTran2Packet(outp);
+
+ cm_ReleaseUser(userp);
+ /* leave scp held since we put it in fidp->scp */
+ return 0;
+}
- /* set inp->fid so that later read calls in same msg can find fid */
- inp->fid = fidp->fid;
-
- /* copy out remainder of the parms */
- parmSlot = 2;
- smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
- lock_ObtainMutex(&scp->mx);
- if (extraInfo) {
- smb_SetSMBParm(outp, parmSlot, smb_Attributes(scp)); parmSlot++;
- smb_DosUTimeFromUnixTime(&dosTime, scp->clientModTime);
- smb_SetSMBParm(outp, parmSlot, dosTime & 0xffff); parmSlot++;
- smb_SetSMBParm(outp, parmSlot, (dosTime>>16) & 0xffff); parmSlot++;
- smb_SetSMBParm(outp, parmSlot, scp->length.LowPart & 0xffff); parmSlot++;
- smb_SetSMBParm(outp, parmSlot, (scp->length.LowPart >> 16) & 0xffff); parmSlot++;
- smb_SetSMBParm(outp, parmSlot, openMode); parmSlot++;
- smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* file type 0 ==> normal file or dir */
- smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* IPC junk */
- }
- /* and the final "always present" stuff */
- smb_SetSMBParm(outp, parmSlot, openAction); parmSlot++;
- /* next write out the "unique" ID */
- smb_SetSMBParm(outp, parmSlot, scp->fid.vnode & 0xffff); parmSlot++;
- smb_SetSMBParm(outp, parmSlot, scp->fid.volume & 0xffff); parmSlot++;
- smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
- lock_ReleaseMutex(&scp->mx);
+long smb_ReceiveTran2FindFirst(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
+{
+ osi_Log0(smb_logp,"ReceiveTran2FindFirst - NOT_SUPPORTED");
+ return CM_ERROR_BADOP;
+}
+
+long smb_ReceiveTran2FindNext(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
+{
+ osi_Log0(smb_logp,"ReceiveTran2FindNext - NOT_SUPPORTED");
+ return CM_ERROR_BADOP;
+}
+
+long smb_ReceiveTran2QFSInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
+{
+ smb_tran2Packet_t *outp;
+ smb_tran2QFSInfo_t qi;
+ int responseSize;
+ osi_hyper_t temp;
+ static char FSname[6] = {'A', 0, 'F', 0, 'S', 0};
+
+ osi_Log1(smb_logp, "T2 QFSInfo type 0x%x", p->parmsp[0]);
+
+ switch (p->parmsp[0]) {
+ case 1: responseSize = sizeof(qi.u.allocInfo); break;
+ case 2: responseSize = sizeof(qi.u.volumeInfo); break;
+ case 0x102: responseSize = sizeof(qi.u.FSvolumeInfo); break;
+ case 0x103: responseSize = sizeof(qi.u.FSsizeInfo); break;
+ case 0x104: responseSize = sizeof(qi.u.FSdeviceInfo); break;
+ case 0x105: responseSize = sizeof(qi.u.FSattributeInfo); break;
+ case 0x200: /* CIFS Unix Info */
+ case 0x301: /* Mac FS Info */
+ default: return CM_ERROR_INVAL;
+ }
+
+ outp = smb_GetTran2ResponsePacket(vcp, p, op, 0, responseSize);
+ switch (p->parmsp[0]) {
+ case 1:
+ /* alloc info */
+ qi.u.allocInfo.FSID = 0;
+ qi.u.allocInfo.sectorsPerAllocUnit = 1;
+ qi.u.allocInfo.totalAllocUnits = 0x7fffffff;
+ qi.u.allocInfo.availAllocUnits = 0x3fffffff;
+ qi.u.allocInfo.bytesPerSector = 1024;
+ break;
+
+ case 2:
+ /* volume info */
+ qi.u.volumeInfo.vsn = 1234;
+ qi.u.volumeInfo.vnCount = 4;
+ /* we're supposed to pad it out with zeroes to the end */
+ memset(&qi.u.volumeInfo.label, 0, sizeof(qi.u.volumeInfo.label));
+ memcpy(qi.u.volumeInfo.label, "AFS", 4);
+ break;
+
+ case 0x102:
+ /* FS volume info */
+ memset((char *)&qi.u.FSvolumeInfo.vct, 0, sizeof(FILETIME));
+ qi.u.FSvolumeInfo.vsn = 1234;
+ qi.u.FSvolumeInfo.vnCount = 8;
+ memcpy(qi.u.FSvolumeInfo.label, "A\0F\0S\0\0", 8);
+ break;
+
+ case 0x103:
+ /* FS size info */
+ temp.HighPart = 0;
+ temp.LowPart = 0x7fffffff;
+ qi.u.FSsizeInfo.totalAllocUnits = temp;
+ temp.LowPart = 0x3fffffff;
+ qi.u.FSsizeInfo.availAllocUnits = temp;
+ qi.u.FSsizeInfo.sectorsPerAllocUnit = 1;
+ qi.u.FSsizeInfo.bytesPerSector = 1024;
+ break;
+
+ case 0x104:
+ /* FS device info */
+ qi.u.FSdeviceInfo.devType = 0; /* don't have a number */
+ qi.u.FSdeviceInfo.characteristics = 0x50; /* remote, virtual */
+ break;
+
+ case 0x105:
+ /* FS attribute info */
+ /* attributes, defined in WINNT.H:
+ * FILE_CASE_SENSITIVE_SEARCH 0x1
+ * FILE_CASE_PRESERVED_NAMES 0x2
+ * <no name defined> 0x4000
+ * If bit 0x4000 is not set, Windows 95 thinks
+ * we can't handle long (non-8.3) names,
+ * despite our protestations to the contrary.
+ */
+ qi.u.FSattributeInfo.attributes = 0x4003;
+ qi.u.FSattributeInfo.maxCompLength = 255;
+ qi.u.FSattributeInfo.FSnameLength = 6;
+ memcpy(qi.u.FSattributeInfo.FSname, FSname, 6);
+ break;
+ }
+
+ /* copy out return data, and set corresponding sizes */
+ outp->totalParms = 0;
+ outp->totalData = responseSize;
+ memcpy(outp->datap, &qi, responseSize);
+
+ /* send and free the packets */
+ smb_SendTran2Packet(vcp, outp, op);
+ smb_FreeTran2Packet(outp);
+
+ return 0;
+}
+
+long smb_ReceiveTran2SetFSInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
+{
+ osi_Log0(smb_logp,"ReceiveTran2SetFSInfo - NOT_SUPPORTED");
+ return CM_ERROR_BADOP;
+}
+
+struct smb_ShortNameRock {
+ char *maskp;
+ unsigned int vnode;
+ char *shortName;
+ size_t shortNameLen;
+};
+
+int cm_GetShortNameProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *vrockp,
+ osi_hyper_t *offp)
+{
+ struct smb_ShortNameRock *rockp;
+ char *shortNameEnd;
+
+ rockp = vrockp;
+ /* compare both names and vnodes, though probably just comparing vnodes
+ * would be safe enough.
+ */
+ if (cm_stricmp(dep->name, rockp->maskp) != 0)
+ return 0;
+ if (ntohl(dep->fid.vnode) != rockp->vnode)
+ return 0;
+ /* This is the entry */
+ cm_Gen8Dot3Name(dep, rockp->shortName, &shortNameEnd);
+ rockp->shortNameLen = shortNameEnd - rockp->shortName;
+ return CM_ERROR_STOPNOW;
+}
+
+long cm_GetShortName(char *pathp, cm_user_t *userp, cm_req_t *reqp,
+ char *tidPathp, int vnode, char *shortName, size_t *shortNameLenp)
+{
+ struct smb_ShortNameRock rock;
+ char *lastNamep;
+ cm_space_t *spacep;
+ cm_scache_t *dscp;
+ int caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
+ long code = 0;
+ osi_hyper_t thyper;
+
+ spacep = cm_GetSpace();
+ smb_StripLastComponent(spacep->data, &lastNamep, pathp);
+
+ code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold, userp, tidPathp,
+ reqp, &dscp);
+ cm_FreeSpace(spacep);
+ if (code)
+ return code;
+
+#ifdef DFS_SUPPORT
+ if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
+ cm_ReleaseSCache(dscp);
+ cm_ReleaseUser(userp);
+ return CM_ERROR_PATH_NOT_COVERED;
+ }
+#endif /* DFS_SUPPORT */
+
+ if (!lastNamep) lastNamep = pathp;
+ else lastNamep++;
+ thyper.LowPart = 0;
+ thyper.HighPart = 0;
+ rock.shortName = shortName;
+ rock.vnode = vnode;
+ rock.maskp = lastNamep;
+ code = cm_ApplyDir(dscp, cm_GetShortNameProc, &rock, &thyper, userp, reqp, NULL);
+
+ cm_ReleaseSCache(dscp);
+
+ if (code == 0)
+ return CM_ERROR_NOSUCHFILE;
+ if (code == CM_ERROR_STOPNOW) {
+ *shortNameLenp = rock.shortNameLen;
+ return 0;
+ }
+ return code;
+}
+
+long smb_ReceiveTran2QPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
+{
+ smb_tran2Packet_t *outp;
+ afs_uint32 dosTime;
+ FILETIME ft;
+ unsigned short infoLevel;
+ int nbytesRequired;
+ unsigned short attributes;
+ unsigned long extAttributes;
+ char shortName[13];
+ unsigned int len;
+ cm_user_t *userp;
+ cm_space_t *spacep;
+ cm_scache_t *scp, *dscp;
+ long code = 0;
+ char *op;
+ char *tidPathp;
+ char *lastComp;
+ cm_req_t req;
+
+ cm_InitReq(&req);
+
+ infoLevel = p->parmsp[0];
+ if (infoLevel == SMB_INFO_IS_NAME_VALID)
+ nbytesRequired = 0;
+ else if (infoLevel == SMB_INFO_STANDARD)
+ nbytesRequired = 22;
+ else if (infoLevel == SMB_INFO_QUERY_EA_SIZE)
+ nbytesRequired = 26;
+ else if (infoLevel == SMB_QUERY_FILE_BASIC_INFO)
+ nbytesRequired = 40;
+ else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO)
+ nbytesRequired = 24;
+ else if (infoLevel == SMB_QUERY_FILE_EA_INFO)
+ nbytesRequired = 4;
+ else if (infoLevel == SMB_QUERY_FILE_ALT_NAME_INFO)
+ nbytesRequired = 30;
+ else {
+ osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
+ p->opcode, infoLevel);
+ smb_SendTran2Error(vcp, p, opx, CM_ERROR_INVAL);
+ return 0;
+ }
+ osi_Log2(smb_logp, "T2 QPathInfo type 0x%x path %s", infoLevel,
+ osi_LogSaveString(smb_logp, (char *)(&p->parmsp[3])));
+
+ outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, nbytesRequired);
+
+ if (infoLevel > 0x100)
+ outp->totalParms = 2;
+ else
+ outp->totalParms = 0;
+ outp->totalData = nbytesRequired;
+
+ /* now, if we're at infoLevel 6, we're only being asked to check
+ * the syntax, so we just OK things now. In particular, we're *not*
+ * being asked to verify anything about the state of any parent dirs.
+ */
+ if (infoLevel == SMB_INFO_IS_NAME_VALID) {
+ smb_SendTran2Packet(vcp, outp, opx);
+ smb_FreeTran2Packet(outp);
+ return 0;
+ }
+
+ userp = smb_GetTran2User(vcp, p);
+ if (!userp) {
+ osi_Log1(smb_logp, "ReceiveTran2QPathInfo unable to resolve user [%d]", p->uid);
+ smb_FreeTran2Packet(outp);
+ return CM_ERROR_BADSMB;
+ }
+
+ code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
+ if(code) {
+ cm_ReleaseUser(userp);
+ smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOSUCHPATH);
+ smb_FreeTran2Packet(outp);
+ return 0;
+ }
+
+ /*
+ * XXX Strange hack XXX
+ *
+ * As of Patch 7 (13 January 98), we are having the following problem:
+ * In NT Explorer 4.0, whenever we click on a directory, AFS gets
+ * requests to look up "desktop.ini" in all the subdirectories.
+ * This can cause zillions of timeouts looking up non-existent cells
+ * and volumes, especially in the top-level directory.
+ *
+ * We have not found any way to avoid this or work around it except
+ * to explicitly ignore the requests for mount points that haven't
+ * yet been evaluated and for directories that haven't yet been
+ * fetched.
+ */
+ if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
+ spacep = cm_GetSpace();
+ smb_StripLastComponent(spacep->data, &lastComp,
+ (char *)(&p->parmsp[3]));
+#ifndef SPECIAL_FOLDERS
+ /* Make sure that lastComp is not NULL */
+ if (lastComp) {
+ if (stricmp(lastComp, "\\desktop.ini") == 0) {
+ code = cm_NameI(cm_data.rootSCachep, spacep->data,
+ CM_FLAG_CASEFOLD
+ | CM_FLAG_DIRSEARCH
+ | CM_FLAG_FOLLOW,
+ userp, tidPathp, &req, &dscp);
+ if (code == 0) {
+#ifdef DFS_SUPPORT
+ if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
+ if ( WANTS_DFS_PATHNAMES(p) )
+ code = CM_ERROR_PATH_NOT_COVERED;
+ else
+ code = CM_ERROR_BADSHARENAME;
+ } else
+#endif /* DFS_SUPPORT */
+ if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT && !dscp->mountRootFid.volume)
+ code = CM_ERROR_NOSUCHFILE;
+ else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
+ cm_buf_t *bp = buf_Find(dscp, &hzero);
+ if (bp)
+ buf_Release(bp);
+ else
+ code = CM_ERROR_NOSUCHFILE;
+ }
+ cm_ReleaseSCache(dscp);
+ if (code) {
+ cm_FreeSpace(spacep);
+ cm_ReleaseUser(userp);
+ smb_SendTran2Error(vcp, p, opx, code);
+ smb_FreeTran2Packet(outp);
+ return 0;
+ }
+ }
+ }
+ }
+#endif /* SPECIAL_FOLDERS */
+
+ cm_FreeSpace(spacep);
+ }
+
+ /* now do namei and stat, and copy out the info */
+ code = cm_NameI(cm_data.rootSCachep, (char *)(&p->parmsp[3]),
+ CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, tidPathp, &req, &scp);
+
+ if (code) {
+ cm_ReleaseUser(userp);
+ smb_SendTran2Error(vcp, p, opx, code);
+ smb_FreeTran2Packet(outp);
+ return 0;
+ }
+
+#ifdef DFS_SUPPORT
+ if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
+ cm_ReleaseSCache(scp);
+ cm_ReleaseUser(userp);
+ if ( WANTS_DFS_PATHNAMES(p) )
+ code = CM_ERROR_PATH_NOT_COVERED;
+ else
+ code = CM_ERROR_BADSHARENAME;
+ smb_SendTran2Error(vcp, p, opx, code);
+ smb_FreeTran2Packet(outp);
+ return 0;
+ }
+#endif /* DFS_SUPPORT */
+
+ lock_ObtainMutex(&scp->mx);
+ code = cm_SyncOp(scp, NULL, userp, &req, 0,
+ CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
+ if (code) goto done;
+
+ /* now we have the status in the cache entry, and everything is locked.
+ * Marshall the output data.
+ */
+ op = outp->datap;
+ /* for info level 108, figure out short name */
+ if (infoLevel == 0x108) {
+ code = cm_GetShortName((char *)(&p->parmsp[3]), userp, &req,
+ tidPathp, scp->fid.vnode, shortName,
+ (size_t *) &len);
+ if (code) {
+ goto done;
+ }
+
+ op = outp->datap;
+ *((u_long *)op) = len * 2; op += 4;
+ mbstowcs((unsigned short *)op, shortName, len);
+ op += (len * 2);
+
+ goto done;
+ }
+ if (infoLevel == SMB_INFO_STANDARD || infoLevel == SMB_INFO_QUERY_EA_SIZE) {
+ smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
+ *((u_long *)op) = dosTime; op += 4; /* creation time */
+ *((u_long *)op) = dosTime; op += 4; /* access time */
+ *((u_long *)op) = dosTime; op += 4; /* write time */
+ *((u_long *)op) = scp->length.LowPart; op += 4; /* length */
+ *((u_long *)op) = scp->length.LowPart; op += 4; /* alloc size */
+ attributes = smb_Attributes(scp);
+ *((u_short *)op) = attributes; op += 2; /* attributes */
+ }
+ else if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
+ smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
+ *((FILETIME *)op) = ft; op += 8; /* creation time */
+ *((FILETIME *)op) = ft; op += 8; /* last access time */
+ *((FILETIME *)op) = ft; op += 8; /* last write time */
+ *((FILETIME *)op) = ft; op += 8; /* last change time */
+ extAttributes = smb_ExtAttributes(scp);
+ *((u_long *)op) = extAttributes; op += 4; /* extended attribs */
+ *((u_long *)op) = 0; op += 4; /* don't know what this is */
+ }
+ else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO) {
+ *((LARGE_INTEGER *)op) = scp->length; op += 8; /* alloc size */
+ *((LARGE_INTEGER *)op) = scp->length; op += 8; /* EOF */
+ *((u_long *)op) = scp->linkCount; op += 4;
+ *op++ = 0;
+ *op++ = 0;
+ *op++ = (scp->fileType == CM_SCACHETYPE_DIRECTORY ? 1 : 0);
+ *op++ = 0;
+ }
+ else if (infoLevel == SMB_QUERY_FILE_EA_INFO) {
+ memset(op, 0, 4); op += 4; /* EA size */
+ }
+
+ /* now, if we are being asked about extended attrs, return a 0 size */
+ if (infoLevel == SMB_INFO_QUERY_EA_SIZE) {
+ *((u_long *)op) = 0; op += 4;
+ }
+
+
+ /* send and free the packets */
+ done:
+ lock_ReleaseMutex(&scp->mx);
+ cm_ReleaseSCache(scp);
+ cm_ReleaseUser(userp);
+ if (code == 0)
+ smb_SendTran2Packet(vcp, outp, opx);
+ else
+ smb_SendTran2Error(vcp, p, opx, code);
+ smb_FreeTran2Packet(outp);
+
+ return 0;
+}
+
+long smb_ReceiveTran2SetPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
+{
+ osi_Log0(smb_logp,"ReceiveTran2SetPathInfo - NOT_SUPPORTED");
+ return CM_ERROR_BADOP;
+}
+
+long smb_ReceiveTran2QFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
+{
+ smb_tran2Packet_t *outp;
+ FILETIME ft;
+ unsigned long attributes;
+ unsigned short infoLevel;
+ int nbytesRequired;
+ unsigned short fid;
+ cm_user_t *userp;
+ smb_fid_t *fidp;
+ cm_scache_t *scp;
+ char *op;
+ long code = 0;
+ cm_req_t req;
+
+ cm_InitReq(&req);
+
+ fid = p->parmsp[0];
+ fidp = smb_FindFID(vcp, fid, 0);
+
+ if (fidp == NULL) {
+ smb_SendTran2Error(vcp, p, opx, CM_ERROR_BADFD);
+ return 0;
+ }
+
+ infoLevel = p->parmsp[1];
+ if (infoLevel == SMB_QUERY_FILE_BASIC_INFO)
+ nbytesRequired = 40;
+ else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO)
+ nbytesRequired = 24;
+ else if (infoLevel == SMB_QUERY_FILE_EA_INFO)
+ nbytesRequired = 4;
+ else if (infoLevel == SMB_QUERY_FILE_NAME_INFO)
+ nbytesRequired = 6;
+ else {
+ osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
+ p->opcode, infoLevel);
+ smb_SendTran2Error(vcp, p, opx, CM_ERROR_INVAL);
+ smb_ReleaseFID(fidp);
+ return 0;
+ }
+ osi_Log2(smb_logp, "T2 QFileInfo type 0x%x fid %d", infoLevel, fid);
+
+ outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, nbytesRequired);
+
+ if (infoLevel > 0x100)
+ outp->totalParms = 2;
+ else
+ outp->totalParms = 0;
+ outp->totalData = nbytesRequired;
+
+ userp = smb_GetTran2User(vcp, p);
+ if (!userp) {
+ osi_Log1(smb_logp, "ReceiveTran2QFileInfo unable to resolve user [%d]", p->uid);
+ code = CM_ERROR_BADSMB;
+ goto done;
+ }
+
+ scp = fidp->scp;
+ lock_ObtainMutex(&scp->mx);
+ code = cm_SyncOp(scp, NULL, userp, &req, 0,
+ CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
+ if (code)
+ goto done;
+
+ /* now we have the status in the cache entry, and everything is locked.
+ * Marshall the output data.
+ */
+ op = outp->datap;
+ if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
+ smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
+ *((FILETIME *)op) = ft; op += 8; /* creation time */
+ *((FILETIME *)op) = ft; op += 8; /* last access time */
+ *((FILETIME *)op) = ft; op += 8; /* last write time */
+ *((FILETIME *)op) = ft; op += 8; /* last change time */
+ attributes = smb_ExtAttributes(scp);
+ *((u_long *)op) = attributes; op += 4;
+ *((u_long *)op) = 0; op += 4;
+ }
+ else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO) {
+ *((LARGE_INTEGER *)op) = scp->length; op += 8; /* alloc size */
+ *((LARGE_INTEGER *)op) = scp->length; op += 8; /* EOF */
+ *((u_long *)op) = scp->linkCount; op += 4;
+ *op++ = ((fidp->flags & SMB_FID_DELONCLOSE) ? 1 : 0);
+ *op++ = (scp->fileType == CM_SCACHETYPE_DIRECTORY ? 1 : 0);
+ *op++ = 0;
+ *op++ = 0;
+ }
+ else if (infoLevel == SMB_QUERY_FILE_EA_INFO) {
+ *((u_long *)op) = 0; op += 4;
+ }
+ else if (infoLevel == SMB_QUERY_FILE_NAME_INFO) {
+ unsigned long len;
+ char *name;
+
+ if (fidp->NTopen_wholepathp)
+ name = fidp->NTopen_wholepathp;
+ else
+ name = "\\"; /* probably can't happen */
+ len = (unsigned long)strlen(name);
+ outp->totalData = (len*2) + 4; /* this is actually what we want to return */
+ *((u_long *)op) = len * 2; op += 4;
+ mbstowcs((unsigned short *)op, name, len); op += (len * 2);
+ }
+
+ /* send and free the packets */
+ done:
+ lock_ReleaseMutex(&scp->mx);
+ cm_ReleaseUser(userp);
+ smb_ReleaseFID(fidp);
+ if (code == 0)
+ smb_SendTran2Packet(vcp, outp, opx);
+ else
+ smb_SendTran2Error(vcp, p, opx, code);
+ smb_FreeTran2Packet(outp);
+
+ return 0;
+}
+
+long smb_ReceiveTran2SetFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
+{
+ long code = 0;
+ unsigned short fid;
+ smb_fid_t *fidp;
+ unsigned short infoLevel;
+ smb_tran2Packet_t *outp;
+ cm_user_t *userp;
+ cm_scache_t *scp;
+ cm_req_t req;
+
+ cm_InitReq(&req);
+
+ fid = p->parmsp[0];
+ fidp = smb_FindFID(vcp, fid, 0);
+
+ if (fidp == NULL) {
+ smb_SendTran2Error(vcp, p, op, CM_ERROR_BADFD);
+ return 0;
+ }
+
+ infoLevel = p->parmsp[1];
+ osi_Log2(smb_logp,"ReceiveTran2SetFileInfo type=[%x] fid=[%x]", infoLevel, fid);
+ if (infoLevel > 0x104 || infoLevel < 0x101) {
+ osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
+ p->opcode, infoLevel);
+ smb_SendTran2Error(vcp, p, op, CM_ERROR_INVAL);
+ smb_ReleaseFID(fidp);
+ return 0;
+ }
+
+ if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO && !(fidp->flags & SMB_FID_OPENDELETE)) {
+ smb_SendTran2Error(vcp, p, op, CM_ERROR_NOACCESS);
+ smb_ReleaseFID(fidp);
+ return 0;
+ }
+ if ((infoLevel == SMB_QUERY_FILE_EA_INFO || infoLevel == SMB_QUERY_FILE_NAME_INFO)
+ && !(fidp->flags & SMB_FID_OPENWRITE)) {
+ smb_SendTran2Error(vcp, p, op, CM_ERROR_NOACCESS);
+ smb_ReleaseFID(fidp);
+ return 0;
+ }
+
+ osi_Log1(smb_logp, "T2 SFileInfo type 0x%x", infoLevel);
+
+ outp = smb_GetTran2ResponsePacket(vcp, p, op, 2, 0);
+
+ outp->totalParms = 2;
+ outp->totalData = 0;
+
+ userp = smb_GetTran2User(vcp, p);
+ if (!userp) {
+ osi_Log1(smb_logp,"ReceiveTran2SetFileInfo unable to resolve user [%d]", p->uid);
+ code = CM_ERROR_BADSMB;
+ goto done;
+ }
+
+ scp = fidp->scp;
+
+ if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
+ FILETIME lastMod;
+ unsigned int attribute;
+ cm_attr_t attr;
+
+ /* lock the vnode with a callback; we need the current status
+ * to determine what the new status is, in some cases.
+ */
+ lock_ObtainMutex(&scp->mx);
+ code = cm_SyncOp(scp, NULL, userp, &req, 0,
+ CM_SCACHESYNC_GETSTATUS
+ | CM_SCACHESYNC_NEEDCALLBACK);
+ if (code) {
+ lock_ReleaseMutex(&scp->mx);
+ goto done;
+ }
+
+ /* prepare for setattr call */
+ attr.mask = 0;
+
+ lastMod = *((FILETIME *)(p->datap + 16));
+ /* when called as result of move a b, lastMod is (-1, -1).
+ * If the check for -1 is not present, timestamp
+ * of the resulting file will be 1969 (-1)
+ */
+ if (LargeIntegerNotEqualToZero(*((LARGE_INTEGER *)&lastMod)) &&
+ lastMod.dwLowDateTime != -1 && lastMod.dwHighDateTime != -1) {
+ attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
+ smb_UnixTimeFromLargeSearchTime(&attr.clientModTime, &lastMod);
+ fidp->flags |= SMB_FID_MTIMESETDONE;
+ }
+
+ attribute = *((u_long *)(p->datap + 32));
+ if (attribute != 0) {
+ if ((scp->unixModeBits & 0222)
+ && (attribute & 1) != 0) {
+ /* make a writable file read-only */
+ attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
+ attr.unixModeBits = scp->unixModeBits & ~0222;
+ }
+ else if ((scp->unixModeBits & 0222) == 0
+ && (attribute & 1) == 0) {
+ /* make a read-only file writable */
+ attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
+ attr.unixModeBits = scp->unixModeBits | 0222;
+ }
+ }
+ lock_ReleaseMutex(&scp->mx);
+
+ /* call setattr */
+ if (attr.mask)
+ code = cm_SetAttr(scp, &attr, userp, &req);
+ else
+ code = 0;
+ }
+ else if (infoLevel == SMB_QUERY_FILE_EA_INFO || infoLevel == SMB_QUERY_FILE_NAME_INFO) {
+ LARGE_INTEGER size = *((LARGE_INTEGER *)(p->datap));
+ cm_attr_t attr;
+
+ attr.mask = CM_ATTRMASK_LENGTH;
+ attr.length.LowPart = size.LowPart;
+ attr.length.HighPart = size.HighPart;
+ code = cm_SetAttr(scp, &attr, userp, &req);
+ }
+ else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO) {
+ if (*((char *)(p->datap))) {
+ code = cm_CheckNTDelete(fidp->NTopen_dscp, scp, userp,
+ &req);
+ if (code == 0)
+ fidp->flags |= SMB_FID_DELONCLOSE;
+ }
+ else {
+ code = 0;
+ fidp->flags &= ~SMB_FID_DELONCLOSE;
+ }
+ }
+
+ done:
+ cm_ReleaseUser(userp);
+ smb_ReleaseFID(fidp);
+ if (code == 0)
+ smb_SendTran2Packet(vcp, outp, op);
+ else
+ smb_SendTran2Error(vcp, p, op, code);
+ smb_FreeTran2Packet(outp);
+
+ return 0;
+}
+
+long
+smb_ReceiveTran2FSCTL(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
+{
+ osi_Log0(smb_logp,"ReceiveTran2FSCTL - NOT_SUPPORTED");
+ return CM_ERROR_BADOP;
+}
+
+long
+smb_ReceiveTran2IOCTL(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
+{
+ osi_Log0(smb_logp,"ReceiveTran2IOCTL - NOT_SUPPORTED");
+ return CM_ERROR_BADOP;
+}
+
+long
+smb_ReceiveTran2FindNotifyFirst(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
+{
+ osi_Log0(smb_logp,"ReceiveTran2FindNotifyFirst - NOT_SUPPORTED");
+ return CM_ERROR_BADOP;
+}
+
+long
+smb_ReceiveTran2FindNotifyNext(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
+{
+ osi_Log0(smb_logp,"ReceiveTran2FindNotifyNext - NOT_SUPPORTED");
+ return CM_ERROR_BADOP;
+}
+
+long
+smb_ReceiveTran2CreateDirectory(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
+{
+ osi_Log0(smb_logp,"ReceiveTran2CreateDirectory - NOT_SUPPORTED");
+ return CM_ERROR_BADOP;
+}
+
+long
+smb_ReceiveTran2SessionSetup(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
+{
+ osi_Log0(smb_logp,"ReceiveTran2SessionSetup - NOT_SUPPORTED");
+ return CM_ERROR_BADOP;
+}
+
+struct smb_v2_referral {
+ USHORT ServerType;
+ USHORT ReferralFlags;
+ ULONG Proximity;
+ ULONG TimeToLive;
+ USHORT DfsPathOffset;
+ USHORT DfsAlternativePathOffset;
+ USHORT NetworkAddressOffset;
+};
+
+long
+smb_ReceiveTran2GetDFSReferral(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
+{
+ /* This is a UNICODE only request (bit15 of Flags2) */
+ /* The TID must be IPC$ */
+
+ /* The documentation for the Flags response field is contradictory */
+
+ /* Use Version 1 Referral Element Format */
+ /* ServerType = 0; indicates the next server should be queried for the file */
+ /* ReferralFlags = 0x01; PathConsumed characters should be stripped */
+ /* Node = UnicodeString of UNC path of the next share name */
+#ifdef DFS_SUPPORT
+ long code = 0;
+ int maxReferralLevel = 0;
+ char requestFileName[1024] = "";
+ smb_tran2Packet_t *outp = 0;
+ cm_user_t *userp = 0;
+ cm_req_t req;
+ CPINFO CodePageInfo;
+ int i, nbnLen, reqLen;
+ int idx;
+
+ cm_InitReq(&req);
+
+ maxReferralLevel = p->parmsp[0];
+
+ GetCPInfo(CP_ACP, &CodePageInfo);
+ WideCharToMultiByte(CP_ACP, 0, (LPCWSTR) &p->parmsp[1], -1,
+ requestFileName, 1024, NULL, NULL);
+
+ osi_Log2(smb_logp,"ReceiveTran2GetDfsReferral [%d][%s]",
+ maxReferralLevel, osi_LogSaveString(smb_logp, requestFileName));
+
+ nbnLen = strlen(cm_NetbiosName);
+ reqLen = strlen(requestFileName);
+
+ if (reqLen == nbnLen + 5 &&
+ requestFileName[0] == '\\' &&
+ !_strnicmp(cm_NetbiosName,&requestFileName[1],nbnLen) &&
+ requestFileName[nbnLen+1] == '\\' &&
+ !_strnicmp("all",&requestFileName[nbnLen+2],3))
+ {
+ USHORT * sp;
+ struct smb_v2_referral * v2ref;
+ outp = smb_GetTran2ResponsePacket(vcp, p, op, 0, 2 * (reqLen + 8));
+
+ sp = (USHORT *)outp->datap;
+ idx = 0;
+ sp[idx++] = reqLen; /* path consumed */
+ sp[idx++] = 1; /* number of referrals */
+ sp[idx++] = 0x03; /* flags */
+#ifdef DFS_VERSION_1
+ sp[idx++] = 1; /* Version Number */
+ sp[idx++] = reqLen + 4; /* Referral Size */
+ sp[idx++] = 1; /* Type = SMB Server */
+ sp[idx++] = 0; /* Do not strip path consumed */
+ for ( i=0;i<=reqLen; i++ )
+ sp[i+idx] = requestFileName[i];
+#else /* DFS_VERSION_2 */
+ sp[idx++] = 2; /* Version Number */
+ sp[idx++] = sizeof(struct smb_v2_referral); /* Referral Size */
+ idx += (sizeof(struct smb_v2_referral) / 2);
+ v2ref = (struct smb_v2_referral *) &sp[5];
+ v2ref->ServerType = 1; /* SMB Server */
+ v2ref->ReferralFlags = 0x03;
+ v2ref->Proximity = 0; /* closest */
+ v2ref->TimeToLive = 3600; /* seconds */
+ v2ref->DfsPathOffset = idx * 2;
+ v2ref->DfsAlternativePathOffset = idx * 2;
+ v2ref->NetworkAddressOffset = 0;
+ for ( i=0;i<=reqLen; i++ )
+ sp[i+idx] = requestFileName[i];
+#endif
+ } else {
+ userp = smb_GetTran2User(vcp, p);
+ if (!userp) {
+ osi_Log1(smb_logp,"ReceiveTran2GetDfsReferral unable to resolve user [%d]", p->uid);
+ code = CM_ERROR_BADSMB;
+ goto done;
+ }
+
+ /* not done yet */
+ code = CM_ERROR_NOSUCHPATH;
+ }
+
+ done:
+ if (userp)
+ cm_ReleaseUser(userp);
+ if (code == 0)
+ smb_SendTran2Packet(vcp, outp, op);
+ else
+ smb_SendTran2Error(vcp, p, op, code);
+ if (outp)
+ smb_FreeTran2Packet(outp);
+
+ return 0;
+#else /* DFS_SUPPORT */
+ osi_Log0(smb_logp,"ReceiveTran2GetDfsReferral - NOT_SUPPORTED");
+ return CM_ERROR_BADOP;
+#endif /* DFS_SUPPORT */
+}
+
+long
+smb_ReceiveTran2ReportDFSInconsistency(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
+{
+ /* This is a UNICODE only request (bit15 of Flags2) */
+
+ /* There is nothing we can do about this operation. The client is going to
+ * tell us that there is a Version 1 Referral Element for which there is a DFS Error.
+ * Unfortunately, there is really nothing we can do about it other then log it
+ * somewhere. Even then I don't think there is anything for us to do.
+ * So let's return an error value.
+ */
+
+ osi_Log0(smb_logp,"ReceiveTran2ReportDFSInconsistency - NOT_SUPPORTED");
+ return CM_ERROR_BADOP;
+}
+
+long
+smb_ApplyV3DirListPatches(cm_scache_t *dscp,
+ smb_dirListPatch_t **dirPatchespp, int infoLevel, cm_user_t *userp,
+ cm_req_t *reqp)
+{
+ long code = 0;
+ cm_scache_t *scp;
+ cm_scache_t *targetScp; /* target if scp is a symlink */
+ char *dptr;
+ afs_uint32 dosTime;
+ FILETIME ft;
+ int shortTemp;
+ unsigned short attr;
+ unsigned long lattr;
+ smb_dirListPatch_t *patchp;
+ smb_dirListPatch_t *npatchp;
+
+ for(patchp = *dirPatchespp; patchp; patchp =
+ (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
+ code = cm_GetSCache(&patchp->fid, &scp, userp, reqp);
+ if (code) continue;
+ lock_ObtainMutex(&scp->mx);
+ code = cm_SyncOp(scp, NULL, userp, reqp, 0,
+ CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
+ if (code) {
+ lock_ReleaseMutex(&scp->mx);
+ cm_ReleaseSCache(scp);
+
+ dptr = patchp->dptr;
+
+ /* Plug in fake timestamps. A time stamp of 0 causes 'invalid parameter'
+ errors in the client. */
+ if (infoLevel >= 0x101) {
+ /* 1969-12-31 23:59:59 +00 */
+ ft.dwHighDateTime = 0x19DB200;
+ ft.dwLowDateTime = 0x5BB78980;
+
+ /* copy to Creation Time */
+ *((FILETIME *)dptr) = ft;
+ dptr += 8;
+
+ /* copy to Last Access Time */
+ *((FILETIME *)dptr) = ft;
+ dptr += 8;
+
+ /* copy to Last Write Time */
+ *((FILETIME *)dptr) = ft;
+ dptr += 8;
+
+ /* copy to Change Time */
+ *((FILETIME *)dptr) = ft;
+ dptr += 24;
+
+ /* merge in hidden attribute */
+ if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
+ *((u_long *)dptr) = SMB_ATTR_HIDDEN;
+ }
+ dptr += 4;
+ } else {
+ /* 1969-12-31 23:59:58 +00*/
+ dosTime = 0xEBBFBF7D;
+
+ /* and copy out date */
+ shortTemp = (dosTime>>16) & 0xffff;
+ *((u_short *)dptr) = shortTemp;
+ dptr += 2;
+
+ /* copy out creation time */
+ shortTemp = dosTime & 0xffff;
+ *((u_short *)dptr) = shortTemp;
+ dptr += 2;
+
+ /* and copy out date */
+ shortTemp = (dosTime>>16) & 0xffff;
+ *((u_short *)dptr) = shortTemp;
+ dptr += 2;
+
+ /* copy out access time */
+ shortTemp = dosTime & 0xffff;
+ *((u_short *)dptr) = shortTemp;
+ dptr += 2;
+
+ /* and copy out date */
+ shortTemp = (dosTime>>16) & 0xffff;
+ *((u_short *)dptr) = shortTemp;
+ dptr += 2;
+
+ /* copy out mod time */
+ shortTemp = dosTime & 0xffff;
+ *((u_short *)dptr) = shortTemp;
+ dptr += 10;
+
+ /* merge in hidden (dot file) attribute */
+ if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
+ attr = SMB_ATTR_HIDDEN;
+ *dptr++ = attr & 0xff;
+ *dptr++ = (attr >> 8) & 0xff;
+ }
+ }
+ continue;
+ }
+
+ /* now watch for a symlink */
+ code = 0;
+ while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
+ lock_ReleaseMutex(&scp->mx);
+ code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, reqp);
+ if (code == 0) {
+ /* we have a more accurate file to use (the
+ * target of the symbolic link). Otherwise,
+ * we'll just use the symlink anyway.
+ */
+ osi_Log2(smb_logp, "symlink vp %x to vp %x",
+ scp, targetScp);
+ cm_ReleaseSCache(scp);
+ scp = targetScp;
+ }
+ lock_ObtainMutex(&scp->mx);
+ }
+
+ dptr = patchp->dptr;
+
+ if (infoLevel >= 0x101) {
+ /* get filetime */
+ smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
+
+ /* copy to Creation Time */
+ *((FILETIME *)dptr) = ft;
+ dptr += 8;
+
+ /* copy to Last Access Time */
+ *((FILETIME *)dptr) = ft;
+ dptr += 8;
+
+ /* copy to Last Write Time */
+ *((FILETIME *)dptr) = ft;
+ dptr += 8;
+
+ /* copy to Change Time */
+ *((FILETIME *)dptr) = ft;
+ dptr += 8;
+
+ /* Use length for both file length and alloc length */
+ *((LARGE_INTEGER *)dptr) = scp->length;
+ dptr += 8;
+ *((LARGE_INTEGER *)dptr) = scp->length;
+ dptr += 8;
+
+ /* Copy attributes */
+ lattr = smb_ExtAttributes(scp);
+ if (code == CM_ERROR_NOSUCHPATH && scp->fileType == CM_SCACHETYPE_SYMLINK) {
+ if (lattr == SMB_ATTR_NORMAL)
+ lattr = SMB_ATTR_DIRECTORY;
+ else
+ lattr |= SMB_ATTR_DIRECTORY;
+ }
+ /* merge in hidden (dot file) attribute */
+ if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
+ if (lattr == SMB_ATTR_NORMAL)
+ lattr = SMB_ATTR_HIDDEN;
+ else
+ lattr |= SMB_ATTR_HIDDEN;
+ }
+ *((u_long *)dptr) = lattr;
+ dptr += 4;
+ } else {
+ /* get dos time */
+ smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
+
+ /* and copy out date */
+ shortTemp = (dosTime>>16) & 0xffff;
+ *((u_short *)dptr) = shortTemp;
+ dptr += 2;
+
+ /* copy out creation time */
+ shortTemp = dosTime & 0xffff;
+ *((u_short *)dptr) = shortTemp;
+ dptr += 2;
+
+ /* and copy out date */
+ shortTemp = (dosTime>>16) & 0xffff;
+ *((u_short *)dptr) = shortTemp;
+ dptr += 2;
+
+ /* copy out access time */
+ shortTemp = dosTime & 0xffff;
+ *((u_short *)dptr) = shortTemp;
+ dptr += 2;
+
+ /* and copy out date */
+ shortTemp = (dosTime>>16) & 0xffff;
+ *((u_short *)dptr) = shortTemp;
+ dptr += 2;
+
+ /* copy out mod time */
+ shortTemp = dosTime & 0xffff;
+ *((u_short *)dptr) = shortTemp;
+ dptr += 2;
+
+ /* copy out file length and alloc length,
+ * using the same for both
+ */
+ *((u_long *)dptr) = scp->length.LowPart;
+ dptr += 4;
+ *((u_long *)dptr) = scp->length.LowPart;
+ dptr += 4;
+
+ /* finally copy out attributes as short */
+ attr = smb_Attributes(scp);
+ /* merge in hidden (dot file) attribute */
+ if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
+ if (lattr == SMB_ATTR_NORMAL)
+ lattr = SMB_ATTR_HIDDEN;
+ else
+ lattr |= SMB_ATTR_HIDDEN;
+ }
+ *dptr++ = attr & 0xff;
+ *dptr++ = (attr >> 8) & 0xff;
+ }
+
+ lock_ReleaseMutex(&scp->mx);
+ cm_ReleaseSCache(scp);
+ }
+
+ /* now free the patches */
+ for (patchp = *dirPatchespp; patchp; patchp = npatchp) {
+ npatchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q);
+ free(patchp);
+ }
+
+ /* and mark the list as empty */
+ *dirPatchespp = NULL;
+
+ return code;
+}
+
+#ifndef USE_OLD_MATCHING
+// char table for case insensitive comparison
+char mapCaseTable[256];
+
+VOID initUpperCaseTable(VOID)
+{
+ int i;
+ for (i = 0; i < 256; ++i)
+ mapCaseTable[i] = toupper(i);
+ // make '"' match '.'
+ mapCaseTable[(int)'"'] = toupper('.');
+ // make '<' match '*'
+ mapCaseTable[(int)'<'] = toupper('*');
+ // make '>' match '?'
+ mapCaseTable[(int)'>'] = toupper('?');
+}
+
+// Compare 'pattern' (containing metacharacters '*' and '?') with the file
+// name 'name'.
+// Note : this procedure works recursively calling itself.
+// Parameters
+// PSZ pattern : string containing metacharacters.
+// PSZ name : file name to be compared with 'pattern'.
+// Return value
+// BOOL : TRUE/FALSE (match/mistmatch)
+
+BOOL
+szWildCardMatchFileName(PSZ pattern, PSZ name, int casefold)
+{
+ PSZ pename; // points to the last 'name' character
+ PSZ p;
+ pename = name + strlen(name) - 1;
+ while (*name) {
+ switch (*pattern) {
+ case '?':
+ ++pattern;
+ if (*name == '.')
+ continue;
+ ++name;
+ break;
+ case '*':
+ ++pattern;
+ if (*pattern == '\0')
+ return TRUE;
+ for (p = pename; p >= name; --p) {
+ if ((casefold && (mapCaseTable[*p] == mapCaseTable[*pattern]) ||
+ !casefold && (*p == *pattern)) &&
+ szWildCardMatchFileName(pattern + 1, p + 1, casefold))
+ return TRUE;
+ } /* endfor */
+ return FALSE;
+ default:
+ if ((casefold && mapCaseTable[*name] != mapCaseTable[*pattern]) ||
+ (!casefold && *name != *pattern))
+ return FALSE;
+ ++pattern, ++name;
+ break;
+ } /* endswitch */
+ } /* endwhile */
+
+ /* if all we have left are wildcards, then we match */
+ for (;*pattern; pattern++) {
+ if (*pattern != '*' && *pattern != '?')
+ return FALSE;
+ }
+ return TRUE;
+}
+
+/* do a case-folding search of the star name mask with the name in namep.
+ * Return 1 if we match, otherwise 0.
+ */
+int smb_V3MatchMask(char *namep, char *maskp, int flags)
+{
+ char * newmask;
+ int i, j, star, qmark, casefold, retval;
+
+ /* make sure we only match 8.3 names, if requested */
+ if ((flags & CM_FLAG_8DOT3) && !cm_Is8Dot3(namep))
+ return 0;
+
+ casefold = (flags & CM_FLAG_CASEFOLD) ? 1 : 0;
+
+ /* optimize the pattern:
+ * if there is a mixture of '?' and '*',
+ * for example the sequence "*?*?*?*"
+ * must be turned into the form "*"
+ */
+ newmask = (char *)malloc(strlen(maskp)+1);
+ for ( i=0, j=0, star=0, qmark=0; maskp[i]; i++) {
+ switch ( maskp[i] ) {
+ case '?':
+ case '>':
+ qmark++;
+ break;
+ case '<':
+ case '*':
+ star++;
+ break;
+ default:
+ if ( star ) {
+ newmask[j++] = '*';
+ } else if ( qmark ) {
+ while ( qmark-- )
+ newmask[j++] = '?';
+ }
+ newmask[j++] = maskp[i];
+ star = 0;
+ qmark = 0;
+ }
+ }
+ if ( star ) {
+ newmask[j++] = '*';
+ } else if ( qmark ) {
+ while ( qmark-- )
+ newmask[j++] = '?';
+ }
+ newmask[j++] = '\0';
+
+ retval = szWildCardMatchFileName(newmask, namep, casefold) ? 1:0;
+
+ free(newmask);
+ return retval;
+}
+
+#else /* USE_OLD_MATCHING */
+/* do a case-folding search of the star name mask with the name in namep.
+ * Return 1 if we match, otherwise 0.
+ */
+int smb_V3MatchMask(char *namep, char *maskp, int flags)
+{
+ unsigned char tcp1, tcp2; /* Pattern characters */
+ unsigned char tcn1; /* Name characters */
+ int sawDot = 0, sawStar = 0, req8dot3 = 0;
+ char *starNamep, *starMaskp;
+ static char nullCharp[] = {0};
+ int casefold = flags & CM_FLAG_CASEFOLD;
+
+ /* make sure we only match 8.3 names, if requested */
+ req8dot3 = (flags & CM_FLAG_8DOT3);
+ if (req8dot3 && !cm_Is8Dot3(namep))
+ return 0;
+
+ /* loop */
+ while (1) {
+ /* Next pattern character */
+ tcp1 = *maskp++;
+
+ /* Next name character */
+ tcn1 = *namep;
+
+ if (tcp1 == 0) {
+ /* 0 - end of pattern */
+ if (tcn1 == 0)
+ return 1;
+ else
+ return 0;
+ }
+ else if (tcp1 == '.' || tcp1 == '"') {
+ if (sawDot) {
+ if (tcn1 == '.') {
+ namep++;
+ continue;
+ } else
+ return 0;
+ }
+ else {
+ /*
+ * first dot in pattern;
+ * must match dot or end of name
+ */
+ sawDot = 1;
+ if (tcn1 == 0)
+ continue;
+ else if (tcn1 == '.') {
+ sawStar = 0;
+ namep++;
+ continue;
+ }
+ else
+ return 0;
+ }
+ }
+ else if (tcp1 == '?') {
+ if (tcn1 == 0 || tcn1 == '.')
+ return 0;
+ namep++;
+ continue;
+ }
+ else if (tcp1 == '>') {
+ if (tcn1 != 0 && tcn1 != '.')
+ namep++;
+ continue;
+ }
+ else if (tcp1 == '*' || tcp1 == '<') {
+ tcp2 = *maskp++;
+ if (tcp2 == 0)
+ return 1;
+ else if ((req8dot3 && tcp2 == '.') || tcp2 == '"') {
+ while (req8dot3 && tcn1 != '.' && tcn1 != 0)
+ tcn1 = *++namep;
+ if (tcn1 == 0) {
+ if (sawDot)
+ return 0;
+ else
+ continue;
+ }
+ else {
+ namep++;
+ continue;
+ }
+ }
+ else {
+ /*
+ * pattern character after '*' is not null or
+ * period. If it is '?' or '>', we are not
+ * going to understand it. If it is '*' or
+ * '<', we are going to skip over it. None of
+ * these are likely, I hope.
+ */
+ /* skip over '*' and '<' */
+ while (tcp2 == '*' || tcp2 == '<')
+ tcp2 = *maskp++;
+
+ /* skip over characters that don't match tcp2 */
+ while (req8dot3 && tcn1 != '.' && tcn1 != 0 &&
+ ((casefold && cm_foldUpper[tcn1] != cm_foldUpper[tcp2]) ||
+ (!casefold && tcn1 != tcp2)))
+ tcn1 = *++namep;
+
+ /* No match */
+ if ((req8dot3 && tcn1 == '.') || tcn1 == 0)
+ return 0;
+
+ /* Remember where we are */
+ sawStar = 1;
+ starMaskp = maskp;
+ starNamep = namep;
+
+ namep++;
+ continue;
+ }
+ }
+ else {
+ /* tcp1 is not a wildcard */
+ if ((casefold && cm_foldUpper[tcn1] == cm_foldUpper[tcp1]) ||
+ (!casefold && tcn1 == tcp1)) {
+ /* they match */
+ namep++;
+ continue;
+ }
+ /* if trying to match a star pattern, go back */
+ if (sawStar) {
+ maskp = starMaskp - 2;
+ namep = starNamep + 1;
+ sawStar = 0;
+ continue;
+ }
+ /* that's all */
+ return 0;
+ }
+ }
+}
+#endif /* USE_OLD_MATCHING */
+
+long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
+{
+ int attribute;
+ long nextCookie;
+ char *tp;
+ long code = 0, code2 = 0;
+ char *pathp;
+ cm_dirEntry_t *dep;
+ int maxCount;
+ smb_dirListPatch_t *dirListPatchesp;
+ smb_dirListPatch_t *curPatchp;
+ cm_buf_t *bufferp;
+ long temp;
+ long orbytes; /* # of bytes in this output record */
+ long ohbytes; /* # of bytes, except file name */
+ long onbytes; /* # of bytes in name, incl. term. null */
+ osi_hyper_t dirLength;
+ osi_hyper_t bufferOffset;
+ osi_hyper_t curOffset;
+ osi_hyper_t thyper;
+ smb_dirSearch_t *dsp;
+ cm_scache_t *scp;
+ long entryInDir;
+ long entryInBuffer;
+ cm_pageHeader_t *pageHeaderp;
+ cm_user_t *userp = NULL;
+ int slotInPage;
+ int returnedNames;
+ long nextEntryCookie;
+ int numDirChunks; /* # of 32 byte dir chunks in this entry */
+ char *op; /* output data ptr */
+ char *origOp; /* original value of op */
+ cm_space_t *spacep; /* for pathname buffer */
+ long maxReturnData; /* max # of return data */
+ long maxReturnParms; /* max # of return parms */
+ long bytesInBuffer; /* # data bytes in the output buffer */
+ int starPattern;
+ char *maskp; /* mask part of path */
+ int infoLevel;
+ int searchFlags;
+ int eos;
+ smb_tran2Packet_t *outp; /* response packet */
+ char *tidPathp;
+ int align;
+ char shortName[13]; /* 8.3 name if needed */
+ int NeedShortName;
+ int foundInexact;
+ char *shortNameEnd;
+ int fileType;
+ cm_fid_t fid;
+ cm_req_t req;
+
+ cm_InitReq(&req);
+
+ eos = 0;
+ if (p->opcode == 1) {
+ /* find first; obtain basic parameters from request */
+ attribute = p->parmsp[0];
+ maxCount = p->parmsp[1];
+ infoLevel = p->parmsp[3];
+ searchFlags = p->parmsp[2];
+ dsp = smb_NewDirSearch(1);
+ dsp->attribute = attribute;
+ pathp = ((char *) p->parmsp) + 12; /* points to path */
+ if (smb_StoreAnsiFilenames)
+ OemToChar(pathp,pathp);
+ nextCookie = 0;
+ maskp = strrchr(pathp, '\\');
+ if (maskp == NULL)
+ maskp = pathp;
+ else
+ maskp++; /* skip over backslash */
+ strcpy(dsp->mask, maskp); /* and save mask */
+ /* track if this is likely to match a lot of entries */
+ starPattern = smb_V3IsStarMask(maskp);
+ }
+ else {
+ osi_assert(p->opcode == 2);
+ /* find next; obtain basic parameters from request or open dir file */
+ dsp = smb_FindDirSearch(p->parmsp[0]);
+ maxCount = p->parmsp[1];
+ infoLevel = p->parmsp[2];
+ nextCookie = p->parmsp[3] | (p->parmsp[4] << 16);
+ searchFlags = p->parmsp[5];
+ if (!dsp) {
+ osi_Log2(smb_logp, "T2 search dir bad search ID: id %d nextCookie 0x%x",
+ p->parmsp[0], nextCookie);
+ return CM_ERROR_BADFD;
+ }
+ attribute = dsp->attribute;
+ pathp = NULL;
+ maskp = dsp->mask;
+ starPattern = 1; /* assume, since required a Find Next */
+ }
+
+ osi_Log4(smb_logp,
+ "T2 search dir attr 0x%x, info level %d, max count %d, flags 0x%x",
+ attribute, infoLevel, maxCount, searchFlags);
+
+ osi_Log3(smb_logp, "...T2 search op %d, id %d, nextCookie 0x%x",
+ p->opcode, dsp->cookie, nextCookie);
+
+ if (infoLevel >= 0x101)
+ searchFlags &= ~4; /* no resume keys */
+
+ dirListPatchesp = NULL;
+
+ maxReturnData = p->maxReturnData;
+ if (p->opcode == 1) /* find first */
+ maxReturnParms = 10; /* bytes */
+ else
+ maxReturnParms = 8; /* bytes */
+
+#ifndef CM_CONFIG_MULTITRAN2RESPONSES
+ if (maxReturnData > 6000)
+ maxReturnData = 6000;
+#endif /* CM_CONFIG_MULTITRAN2RESPONSES */
+
+ outp = smb_GetTran2ResponsePacket(vcp, p, opx, maxReturnParms,
+ maxReturnData);
+
+ osi_Log2(smb_logp, "T2 receive search dir count %d [%s]",
+ maxCount, osi_LogSaveString(smb_logp, pathp));
+
+ /* bail out if request looks bad */
+ if (p->opcode == 1 && !pathp) {
+ smb_ReleaseDirSearch(dsp);
+ smb_FreeTran2Packet(outp);
+ return CM_ERROR_BADSMB;
+ }
+
+ osi_Log3(smb_logp, "T2 search dir id %d, nextCookie 0x%x, attr 0x%x",
+ dsp->cookie, nextCookie, attribute);
+
+ userp = smb_GetTran2User(vcp, p);
+ if (!userp) {
+ osi_Log1(smb_logp, "T2 search dir unable to resolve user [%d]", p->uid);
+ smb_ReleaseDirSearch(dsp);
+ smb_FreeTran2Packet(outp);
+ return CM_ERROR_BADSMB;
+ }
+
+ /* try to get the vnode for the path name next */
+ lock_ObtainMutex(&dsp->mx);
+ if (dsp->scp) {
+ scp = dsp->scp;
+ cm_HoldSCache(scp);
+ code = 0;
+ } else {
+ spacep = cm_GetSpace();
+ smb_StripLastComponent(spacep->data, NULL, pathp);
+ code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
+ if (code) {
+ cm_ReleaseUser(userp);
+ smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOFILES);
+ smb_FreeTran2Packet(outp);
+ lock_ReleaseMutex(&dsp->mx);
+ smb_DeleteDirSearch(dsp);
+ smb_ReleaseDirSearch(dsp);
+ return 0;
+ }
+ code = cm_NameI(cm_data.rootSCachep, spacep->data,
+ CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
+ userp, tidPathp, &req, &scp);
+ cm_FreeSpace(spacep);
+
+ if (code == 0) {
+#ifdef DFS_SUPPORT_BUT_NOT_FIND_FIRST
+ if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
+ cm_ReleaseSCache(scp);
+ cm_ReleaseUser(userp);
+ if ( WANTS_DFS_PATHNAMES(p) )
+ code = CM_ERROR_PATH_NOT_COVERED;
+ else
+ code = CM_ERROR_BADSHARENAME;
+ smb_SendTran2Error(vcp, p, opx, code);
+ smb_FreeTran2Packet(outp);
+ lock_ReleaseMutex(&dsp->mx);
+ smb_DeleteDirSearch(dsp);
+ smb_ReleaseDirSearch(dsp);
+ return 0;
+ }
+#endif /* DFS_SUPPORT */
+ dsp->scp = scp;
+ /* we need one hold for the entry we just stored into,
+ * and one for our own processing. When we're done
+ * with this function, we'll drop the one for our own
+ * processing. We held it once from the namei call,
+ * and so we do another hold now.
+ */
+ cm_HoldSCache(scp);
+ lock_ObtainMutex(&scp->mx);
+ if ((scp->flags & CM_SCACHEFLAG_BULKSTATTING) == 0 &&
+ LargeIntegerGreaterOrEqualToZero(scp->bulkStatProgress)) {
+ scp->flags |= CM_SCACHEFLAG_BULKSTATTING;
+ dsp->flags |= SMB_DIRSEARCH_BULKST;
+ }
+ lock_ReleaseMutex(&scp->mx);
+ }
+ }
+ lock_ReleaseMutex(&dsp->mx);
+ if (code) {
+ cm_ReleaseUser(userp);
+ smb_FreeTran2Packet(outp);
+ smb_DeleteDirSearch(dsp);
+ smb_ReleaseDirSearch(dsp);
+ return code;
+ }
+
+ /* get the directory size */
+ lock_ObtainMutex(&scp->mx);
+ code = cm_SyncOp(scp, NULL, userp, &req, 0,
+ CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
+ if (code) {
+ lock_ReleaseMutex(&scp->mx);
+ cm_ReleaseSCache(scp);
+ cm_ReleaseUser(userp);
+ smb_FreeTran2Packet(outp);
+ smb_DeleteDirSearch(dsp);
+ smb_ReleaseDirSearch(dsp);
+ return code;
+ }
+
+ startsearch:
+ dirLength = scp->length;
+ bufferp = NULL;
+ bufferOffset.LowPart = bufferOffset.HighPart = 0;
+ curOffset.HighPart = 0;
+ curOffset.LowPart = nextCookie;
+ origOp = outp->datap;
+
+ foundInexact = 0;
+ code = 0;
+ returnedNames = 0;
+ bytesInBuffer = 0;
+ while (1) {
+ op = origOp;
+ if (searchFlags & 4)
+ /* skip over resume key */
+ op += 4;
+
+ /* make sure that curOffset.LowPart doesn't point to the first
+ * 32 bytes in the 2nd through last dir page, and that it doesn't
+ * point at the first 13 32-byte chunks in the first dir page,
+ * since those are dir and page headers, and don't contain useful
+ * information.
+ */
+ temp = curOffset.LowPart & (2048-1);
+ if (curOffset.HighPart == 0 && curOffset.LowPart < 2048) {
+ /* we're in the first page */
+ if (temp < 13*32) temp = 13*32;
+ }
+ else {
+ /* we're in a later dir page */
+ if (temp < 32) temp = 32;
+ }
+
+ /* make sure the low order 5 bits are zero */
+ temp &= ~(32-1);
+
+ /* now put temp bits back ito curOffset.LowPart */
+ curOffset.LowPart &= ~(2048-1);
+ curOffset.LowPart |= temp;
+
+ /* check if we've passed the dir's EOF */
+ if (LargeIntegerGreaterThanOrEqualTo(curOffset, dirLength)) {
+ osi_Log0(smb_logp, "T2 search dir passed eof");
+ eos = 1;
+ break;
+ }
+
+ /* check if we've returned all the names that will fit in the
+ * response packet; we check return count as well as the number
+ * of bytes requested. We check the # of bytes after we find
+ * the dir entry, since we'll need to check its size.
+ */
+ if (returnedNames >= maxCount) {
+ osi_Log2(smb_logp, "T2 search dir returnedNames %d >= maxCount %d",
+ returnedNames, maxCount);
+ break;
+ }
+
+ /* see if we can use the bufferp we have now; compute in which
+ * page the current offset would be, and check whether that's
+ * the offset of the buffer we have. If not, get the buffer.
+ */
+ thyper.HighPart = curOffset.HighPart;
+ thyper.LowPart = curOffset.LowPart & ~(cm_data.buf_blockSize-1);
+ if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
+ /* wrong buffer */
+ if (bufferp) {
+ buf_Release(bufferp);
+ bufferp = NULL;
+ }
+ lock_ReleaseMutex(&scp->mx);
+ lock_ObtainRead(&scp->bufCreateLock);
+ code = buf_Get(scp, &thyper, &bufferp);
+ lock_ReleaseRead(&scp->bufCreateLock);
+ lock_ObtainMutex(&dsp->mx);
+
+ /* now, if we're doing a star match, do bulk fetching
+ * of all of the status info for files in the dir.
+ */
+ if (starPattern) {
+ smb_ApplyV3DirListPatches(scp, &dirListPatchesp,
+ infoLevel, userp,
+ &req);
+ lock_ObtainMutex(&scp->mx);
+ if ((dsp->flags & SMB_DIRSEARCH_BULKST) &&
+ LargeIntegerGreaterThanOrEqualTo(thyper, scp->bulkStatProgress)) {
+ /* Don't bulk stat if risking timeout */
+ int now = GetTickCount();
+ if (now - req.startTime > 5000) {
+ scp->bulkStatProgress = thyper;
+ scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
+ dsp->flags &= ~SMB_DIRSEARCH_BULKST;
+ } else
+ cm_TryBulkStat(scp, &thyper, userp, &req);
+ }
+ } else {
+ lock_ObtainMutex(&scp->mx);
+ }
+ lock_ReleaseMutex(&dsp->mx);
+ if (code) {
+ osi_Log2(smb_logp, "T2 search dir buf_Get scp %x failed %d", scp, code);
+ break;
+ }
+
+ bufferOffset = thyper;
+
+ /* now get the data in the cache */
+ while (1) {
+ code = cm_SyncOp(scp, bufferp, userp, &req,
+ PRSFS_LOOKUP,
+ CM_SCACHESYNC_NEEDCALLBACK
+ | CM_SCACHESYNC_READ);
+ if (code) {
+ osi_Log2(smb_logp, "T2 search dir cm_SyncOp scp %x failed %d", scp, code);
+ break;
+ }
+
+ if (cm_HaveBuffer(scp, bufferp, 0)) {
+ osi_Log2(smb_logp, "T2 search dir !HaveBuffer scp %x bufferp %x", scp, bufferp);
+ break;
+ }
+
+ /* otherwise, load the buffer and try again */
+ code = cm_GetBuffer(scp, bufferp, NULL, userp,
+ &req);
+ if (code) {
+ osi_Log3(smb_logp, "T2 search dir cm_GetBuffer failed scp %x bufferp %x code %d",
+ scp, bufferp, code);
+ break;
+ }
+ }
+ if (code) {
+ buf_Release(bufferp);
+ bufferp = NULL;
+ break;
+ }
+ } /* if (wrong buffer) ... */
+
+ /* now we have the buffer containing the entry we're interested
+ * in; copy it out if it represents a non-deleted entry.
+ */
+ entryInDir = curOffset.LowPart & (2048-1);
+ entryInBuffer = curOffset.LowPart & (cm_data.buf_blockSize - 1);
+
+ /* page header will help tell us which entries are free. Page
+ * header can change more often than once per buffer, since
+ * AFS 3 dir page size may be less than (but not more than)
+ * a buffer package buffer.
+ */
+ /* only look intra-buffer */
+ temp = curOffset.LowPart & (cm_data.buf_blockSize - 1);
+ temp &= ~(2048 - 1); /* turn off intra-page bits */
+ pageHeaderp = (cm_pageHeader_t *) (bufferp->datap + temp);
+
+ /* now determine which entry we're looking at in the page.
+ * If it is free (there's a free bitmap at the start of the
+ * dir), we should skip these 32 bytes.
+ */
+ slotInPage = (entryInDir & 0x7e0) >> 5;
+ if (!(pageHeaderp->freeBitmap[slotInPage>>3] &
+ (1 << (slotInPage & 0x7)))) {
+ /* this entry is free */
+ numDirChunks = 1; /* only skip this guy */
+ goto nextEntry;
+ }
+
+ tp = bufferp->datap + entryInBuffer;
+ dep = (cm_dirEntry_t *) tp; /* now points to AFS3 dir entry */
+
+ /* while we're here, compute the next entry's location, too,
+ * since we'll need it when writing out the cookie into the dir
+ * listing stream.
+ *
+ * XXXX Probably should do more sanity checking.
+ */
+ numDirChunks = cm_NameEntries(dep->name, &onbytes);
+
+ /* compute offset of cookie representing next entry */
+ nextEntryCookie = curOffset.LowPart + (CM_DIR_CHUNKSIZE * numDirChunks);
+
+ /* Need 8.3 name? */
+ NeedShortName = 0;
+ if (infoLevel == SMB_QUERY_FILE_NAME_INFO
+ && dep->fid.vnode != 0
+ && !cm_Is8Dot3(dep->name)) {
+ cm_Gen8Dot3Name(dep, shortName, &shortNameEnd);
+ NeedShortName = 1;
+ }
+
+ osi_Log3(smb_logp, "T2 search dir vn %u name %s (%s)",
+ dep->fid.vnode, osi_LogSaveString(smb_logp, dep->name),
+ NeedShortName ? osi_LogSaveString(smb_logp, shortName) : "");
+
+ /* When matching, we are using doing a case fold if we have a wildcard mask.
+ * If we get a non-wildcard match, it's a lookup for a specific file.
+ */
+ if (dep->fid.vnode != 0 &&
+ (smb_V3MatchMask(dep->name, maskp, (starPattern? CM_FLAG_CASEFOLD : 0)) ||
+ (NeedShortName &&
+ smb_V3MatchMask(shortName, maskp, CM_FLAG_CASEFOLD)))) {
+
+ /* Eliminate entries that don't match requested attributes */
+ if (smb_hideDotFiles && !(dsp->attribute & SMB_ATTR_HIDDEN) &&
+ smb_IsDotFile(dep->name)) {
+ osi_Log0(smb_logp, "T2 search dir skipping hidden");
+ goto nextEntry; /* no hidden files */
+ }
+ if (!(dsp->attribute & SMB_ATTR_DIRECTORY)) /* no directories */
+ {
+ /* We have already done the cm_TryBulkStat above */
+ fid.cell = scp->fid.cell;
+ fid.volume = scp->fid.volume;
+ fid.vnode = ntohl(dep->fid.vnode);
+ fid.unique = ntohl(dep->fid.unique);
+ fileType = cm_FindFileType(&fid);
+ /*osi_Log2(smb_logp, "smb_ReceiveTran2SearchDir: file %s "
+ "has filetype %d", dep->name,
+ fileType);*/
+ if (fileType == CM_SCACHETYPE_DIRECTORY ||
+ fileType == CM_SCACHETYPE_DFSLINK ||
+ fileType == CM_SCACHETYPE_INVALID)
+ osi_Log0(smb_logp, "T2 search dir skipping directory or bad link");
+ goto nextEntry;
+ }
+
+ /* finally check if this name will fit */
+
+ /* standard dir entry stuff */
+ if (infoLevel < 0x101)
+ ohbytes = 23; /* pre-NT */
+ else if (infoLevel == SMB_QUERY_FILE_EA_INFO)
+ ohbytes = 12; /* NT names only */
+ else
+ ohbytes = 64; /* NT */
+
+ if (infoLevel == SMB_QUERY_FILE_NAME_INFO)
+ ohbytes += 26; /* Short name & length */
+
+ if (searchFlags & 4) {
+ ohbytes += 4; /* if resume key required */
+ }
+
+ if (infoLevel != 1
+ && infoLevel != 0x101
+ && infoLevel != 0x103)
+ ohbytes += 4; /* EASIZE */
+
+ /* add header to name & term. null */
+ orbytes = onbytes + ohbytes + 1;
+
+ /* now, we round up the record to a 4 byte alignment,
+ * and we make sure that we have enough room here for
+ * even the aligned version (so we don't have to worry
+ * about an * overflow when we pad things out below).
+ * That's the reason for the alignment arithmetic below.
+ */
+ if (infoLevel >= 0x101)
+ align = (4 - (orbytes & 3)) & 3;
+ else
+ align = 0;
+ if (orbytes + bytesInBuffer + align > maxReturnData) {
+ osi_Log1(smb_logp, "T2 dir search exceed max return data %d",
+ maxReturnData);
+ break;
+ }
+
+ /* this is one of the entries to use: it is not deleted
+ * and it matches the star pattern we're looking for.
+ * Put out the name, preceded by its length.
+ */
+ /* First zero everything else */
+ memset(origOp, 0, ohbytes);
+
+ if (infoLevel <= 0x101)
+ *(origOp + ohbytes - 1) = (unsigned char) onbytes;
+ else if (infoLevel == SMB_QUERY_FILE_EA_INFO)
+ *((u_long *)(op + 8)) = onbytes;
+ else
+ *((u_long *)(op + 60)) = onbytes;
+ strcpy(origOp+ohbytes, dep->name);
+ if (smb_StoreAnsiFilenames)
+ CharToOem(origOp+ohbytes, origOp+ohbytes);
+
+ /* Short name if requested and needed */
+ if (infoLevel == SMB_QUERY_FILE_NAME_INFO) {
+ if (NeedShortName) {
+ strcpy(op + 70, shortName);
+ if (smb_StoreAnsiFilenames)
+ CharToOem(op + 70, op + 70);
+ *(op + 68) = (char)(shortNameEnd - shortName);
+ }
+ }
+
+ /* now, adjust the # of entries copied */
+ returnedNames++;
+
+ /* NextEntryOffset and FileIndex */
+ if (infoLevel >= 101) {
+ int entryOffset = orbytes + align;
+ *((u_long *)op) = entryOffset;
+ *((u_long *)(op+4)) = nextEntryCookie;
+ }
+
+ /* now we emit the attribute. This is tricky, since
+ * we need to really stat the file to find out what
+ * type of entry we've got. Right now, we're copying
+ * out data from a buffer, while holding the scp
+ * locked, so it isn't really convenient to stat
+ * something now. We'll put in a place holder
+ * now, and make a second pass before returning this
+ * to get the real attributes. So, we just skip the
+ * data for now, and adjust it later. We allocate a
+ * patch record to make it easy to find this point
+ * later. The replay will happen at a time when it is
+ * safe to unlock the directory.
+ */
+ if (infoLevel != 0x103) {
+ curPatchp = malloc(sizeof(*curPatchp));
+ osi_QAdd((osi_queue_t **) &dirListPatchesp,
+ &curPatchp->q);
+ curPatchp->dptr = op;
+ if (infoLevel >= 0x101)
+ curPatchp->dptr += 8;
+
+ if (smb_hideDotFiles && smb_IsDotFile(dep->name)) {
+ curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
+ }
+ else
+ curPatchp->flags = 0;
+
+ curPatchp->fid.cell = scp->fid.cell;
+ curPatchp->fid.volume = scp->fid.volume;
+ curPatchp->fid.vnode = ntohl(dep->fid.vnode);
+ curPatchp->fid.unique = ntohl(dep->fid.unique);
+
+ /* temp */
+ curPatchp->dep = dep;
+ }
+
+ if (searchFlags & 4)
+ /* put out resume key */
+ *((u_long *)origOp) = nextEntryCookie;
+
+ /* Adjust byte ptr and count */
+ origOp += orbytes; /* skip entire record */
+ bytesInBuffer += orbytes;
+
+ /* and pad the record out */
+ while (--align >= 0) {
+ *origOp++ = 0;
+ bytesInBuffer++;
+ }
+ } /* if we're including this name */
+ else if (!starPattern &&
+ !foundInexact &&
+ dep->fid.vnode != 0 &&
+ smb_V3MatchMask(dep->name, maskp, CM_FLAG_CASEFOLD)) {
+ /* We were looking for exact matches, but here's an inexact one*/
+ foundInexact = 1;
+ }
+
+ nextEntry:
+ /* and adjust curOffset to be where the new cookie is */
+ thyper.HighPart = 0;
+ thyper.LowPart = CM_DIR_CHUNKSIZE * numDirChunks;
+ curOffset = LargeIntegerAdd(thyper, curOffset);
+ } /* while copying data for dir listing */
+
+ /* If we didn't get a star pattern, we did an exact match during the first pass.
+ * If there were no exact matches found, we fail over to inexact matches by
+ * marking the query as a star pattern (matches all case permutations), and
+ * re-running the query.
+ */
+ if (returnedNames == 0 && !starPattern && foundInexact) {
+ osi_Log0(afsd_logp,"T2 Search: No exact matches. Re-running for inexact matches");
+ starPattern = 1;
+ goto startsearch;
+ }
+
+ /* release the mutex */
+ lock_ReleaseMutex(&scp->mx);
+ if (bufferp)
+ buf_Release(bufferp);
+
+ /* apply and free last set of patches; if not doing a star match, this
+ * will be empty, but better safe (and freeing everything) than sorry.
+ */
+ code2 = smb_ApplyV3DirListPatches(scp, &dirListPatchesp, infoLevel, userp,
+ &req);
+
+ /* now put out the final parameters */
+ if (returnedNames == 0)
+ eos = 1;
+ if (p->opcode == 1) {
+ /* find first */
+ outp->parmsp[0] = (unsigned short) dsp->cookie;
+ outp->parmsp[1] = returnedNames;
+ outp->parmsp[2] = eos;
+ outp->parmsp[3] = 0; /* nothing wrong with EAS */
+ outp->parmsp[4] = 0;
+ /* don't need last name to continue
+ * search, cookie is enough. Normally,
+ * this is the offset of the file name
+ * of the last entry returned.
+ */
+ outp->totalParms = 10; /* in bytes */
+ }
+ else {
+ /* find next */
+ outp->parmsp[0] = returnedNames;
+ outp->parmsp[1] = eos;
+ outp->parmsp[2] = 0; /* EAS error */
+ outp->parmsp[3] = 0; /* last name, as above */
+ outp->totalParms = 8; /* in bytes */
+ }
+
+ /* return # of bytes in the buffer */
+ outp->totalData = bytesInBuffer;
+
+ /* Return error code if unsuccessful on first request */
+ if (code == 0 && p->opcode == 1 && returnedNames == 0)
+ code = CM_ERROR_NOSUCHFILE;
+
+ osi_Log4(smb_logp, "T2 search dir done, opcode %d, id %d, %d names, code %d",
+ p->opcode, dsp->cookie, returnedNames, code);
+
+ /* if we're supposed to close the search after this request, or if
+ * we're supposed to close the search if we're done, and we're done,
+ * or if something went wrong, close the search.
+ */
+ /* ((searchFlags & 1) || ((searchFlags & 2) && eos) */
+ if ((searchFlags & 1) || (returnedNames == 0) ||
+ ((searchFlags & 2) && eos) || code != 0)
+ smb_DeleteDirSearch(dsp);
+ if (code)
+ smb_SendTran2Error(vcp, p, opx, code);
+ else
+ smb_SendTran2Packet(vcp, outp, opx);
+
+ smb_FreeTran2Packet(outp);
+ smb_ReleaseDirSearch(dsp);
+ cm_ReleaseSCache(scp);
+ cm_ReleaseUser(userp);
+ return 0;
+}
+
+long smb_ReceiveV3FindClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
+{
+ int dirHandle;
+ smb_dirSearch_t *dsp;
+
+ dirHandle = smb_GetSMBParm(inp, 0);
+
+ osi_Log1(smb_logp, "SMB3 find close handle %d", dirHandle);
+
+ dsp = smb_FindDirSearch(dirHandle);
+
+ if (!dsp)
+ return CM_ERROR_BADFD;
+
+ /* otherwise, we have an FD to destroy */
+ smb_DeleteDirSearch(dsp);
+ smb_ReleaseDirSearch(dsp);
+
+ /* and return results */
+ smb_SetSMBDataLength(outp, 0);
+
+ return 0;
+}
+
+long smb_ReceiveV3FindNotifyClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
+{
+ smb_SetSMBDataLength(outp, 0);
+ return 0;
+}
+
+long smb_ReceiveV3OpenX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
+{
+ char *pathp;
+ long code = 0;
+ cm_space_t *spacep;
+ int excl;
+ cm_user_t *userp;
+ cm_scache_t *dscp; /* dir we're dealing with */
+ cm_scache_t *scp; /* file we're creating */
+ cm_attr_t setAttr;
+ int initialModeBits;
+ smb_fid_t *fidp;
+ int attributes;
+ char *lastNamep;
+ afs_uint32 dosTime;
+ int openFun;
+ int trunc;
+ int openMode;
+ int extraInfo;
+ int openAction;
+ int parmSlot; /* which parm we're dealing with */
+ char *tidPathp;
+ cm_req_t req;
+
+ cm_InitReq(&req);
+
+ scp = NULL;
+
+ extraInfo = (smb_GetSMBParm(inp, 2) & 1); /* return extra info */
+ openFun = smb_GetSMBParm(inp, 8); /* open function */
+ excl = ((openFun & 3) == 0);
+ trunc = ((openFun & 3) == 2); /* truncate it */
+ openMode = (smb_GetSMBParm(inp, 3) & 0x7);
+ openAction = 0; /* tracks what we did */
+
+ attributes = smb_GetSMBParm(inp, 5);
+ dosTime = smb_GetSMBParm(inp, 6) | (smb_GetSMBParm(inp, 7) << 16);
+
+ /* compute initial mode bits based on read-only flag in attributes */
+ initialModeBits = 0666;
+ if (attributes & 1) initialModeBits &= ~0222;
+
+ pathp = smb_GetSMBData(inp, NULL);
+ if (smb_StoreAnsiFilenames)
+ OemToChar(pathp,pathp);
+
+ spacep = inp->spacep;
+ smb_StripLastComponent(spacep->data, &lastNamep, pathp);
+
+ if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
+ /* special case magic file name for receiving IOCTL requests
+ * (since IOCTL calls themselves aren't getting through).
+ */
+#ifdef NOTSERVICE
+ osi_Log0(smb_logp, "IOCTL Open");
+#endif
+
+ fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
+ smb_SetupIoctlFid(fidp, spacep);
+
+ /* set inp->fid so that later read calls in same msg can find fid */
+ inp->fid = fidp->fid;
+
+ /* copy out remainder of the parms */
+ parmSlot = 2;
+ smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
+ if (extraInfo) {
+ smb_SetSMBParm(outp, parmSlot, /* attrs */ 0); parmSlot++;
+ smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* mod time */
+ smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
+ smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* len */
+ smb_SetSMBParm(outp, parmSlot, 0x7fff); parmSlot++;
+ smb_SetSMBParm(outp, parmSlot, openMode); parmSlot++;
+ smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* file type 0 ==> normal file or dir */
+ smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* IPC junk */
+ }
+ /* and the final "always present" stuff */
+ smb_SetSMBParm(outp, parmSlot, /* openAction found existing file */ 1); parmSlot++;
+ /* next write out the "unique" ID */
+ smb_SetSMBParm(outp, parmSlot, 0x1234); parmSlot++;
+ smb_SetSMBParm(outp, parmSlot, 0x5678); parmSlot++;
+ smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
smb_SetSMBDataLength(outp, 0);
- osi_Log1(afsd_logp, "SMB OpenX opening fid %d", fidp->fid);
+ /* and clean up fid reference */
+ smb_ReleaseFID(fidp);
+ return 0;
+ }
+
+#ifdef DEBUG_VERBOSE
+ {
+ char *hexp, *asciip;
+ asciip = (lastNamep ? lastNamep : pathp );
+ hexp = osi_HexifyString(asciip);
+ DEBUG_EVENT2("AFS", "V3Open H[%s] A[%s]", hexp, asciip );
+ free(hexp);
+ }
+#endif
+ userp = smb_GetUser(vcp, inp);
+ dscp = NULL;
+ code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
+ if (code) {
cm_ReleaseUser(userp);
- /* leave scp held since we put it in fidp->scp */
- return 0;
+ return CM_ERROR_NOSUCHPATH;
+ }
+ code = cm_NameI(cm_data.rootSCachep, pathp,
+ CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
+ userp, tidPathp, &req, &scp);
+
+#ifdef DFS_SUPPORT
+ if (code == 0 && scp->fileType == CM_SCACHETYPE_DFSLINK) {
+ cm_ReleaseSCache(scp);
+ cm_ReleaseUser(userp);
+ if ( WANTS_DFS_PATHNAMES(inp) )
+ return CM_ERROR_PATH_NOT_COVERED;
+ else
+ return CM_ERROR_BADSHARENAME;
+ }
+#endif /* DFS_SUPPORT */
+
+ if (code != 0) {
+ code = cm_NameI(cm_data.rootSCachep, spacep->data,
+ CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
+ userp, tidPathp, &req, &dscp);
+ if (code) {
+ cm_ReleaseUser(userp);
+ return code;
+ }
+
+#ifdef DFS_SUPPORT
+ if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
+ cm_ReleaseSCache(dscp);
+ cm_ReleaseUser(userp);
+ if ( WANTS_DFS_PATHNAMES(inp) )
+ return CM_ERROR_PATH_NOT_COVERED;
+ else
+ return CM_ERROR_BADSHARENAME;
+ }
+#endif /* DFS_SUPPORT */
+
+ /* otherwise, scp points to the parent directory. Do a lookup,
+ * and truncate the file if we find it, otherwise we create the
+ * file.
+ */
+ if (!lastNamep)
+ lastNamep = pathp;
+ else
+ lastNamep++;
+ code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD, userp,
+ &req, &scp);
+ if (code && code != CM_ERROR_NOSUCHFILE) {
+ cm_ReleaseSCache(dscp);
+ cm_ReleaseUser(userp);
+ return code;
+ }
+ }
+
+ /* if we get here, if code is 0, the file exists and is represented by
+ * scp. Otherwise, we have to create it. The dir may be represented
+ * by dscp, or we may have found the file directly. If code is non-zero,
+ * scp is NULL.
+ */
+ if (code == 0) {
+ code = cm_CheckOpen(scp, openMode, trunc, userp, &req);
+ if (code) {
+ if (dscp) cm_ReleaseSCache(dscp);
+ cm_ReleaseSCache(scp);
+ cm_ReleaseUser(userp);
+ return code;
+ }
+
+ if (excl) {
+ /* oops, file shouldn't be there */
+ if (dscp)
+ cm_ReleaseSCache(dscp);
+ cm_ReleaseSCache(scp);
+ cm_ReleaseUser(userp);
+ return CM_ERROR_EXISTS;
+ }
+
+ if (trunc) {
+ setAttr.mask = CM_ATTRMASK_LENGTH;
+ setAttr.length.LowPart = 0;
+ setAttr.length.HighPart = 0;
+ code = cm_SetAttr(scp, &setAttr, userp, &req);
+ openAction = 3; /* truncated existing file */
+ }
+ else openAction = 1; /* found existing file */
+ }
+ else if (!(openFun & SMB_ATTR_DIRECTORY)) {
+ /* don't create if not found */
+ if (dscp) cm_ReleaseSCache(dscp);
+ cm_ReleaseUser(userp);
+ return CM_ERROR_NOSUCHFILE;
+ }
+ else {
+ osi_assert(dscp != NULL);
+ osi_Log1(smb_logp, "smb_ReceiveV3OpenX creating file %s",
+ osi_LogSaveString(smb_logp, lastNamep));
+ openAction = 2; /* created file */
+ setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
+ smb_UnixTimeFromDosUTime(&setAttr.clientModTime, dosTime);
+ code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
+ &req);
+ if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
+ smb_NotifyChange(FILE_ACTION_ADDED,
+ FILE_NOTIFY_CHANGE_FILE_NAME,
+ dscp, lastNamep, NULL, TRUE);
+ if (!excl && code == CM_ERROR_EXISTS) {
+ /* not an exclusive create, and someone else tried
+ * creating it already, then we open it anyway. We
+ * don't bother retrying after this, since if this next
+ * fails, that means that the file was deleted after we
+ * started this call.
+ */
+ code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
+ userp, &req, &scp);
+ if (code == 0) {
+ if (trunc) {
+ setAttr.mask = CM_ATTRMASK_LENGTH;
+ setAttr.length.LowPart = 0;
+ setAttr.length.HighPart = 0;
+ code = cm_SetAttr(scp, &setAttr, userp, &req);
+ }
+ } /* lookup succeeded */
+ }
+ }
+
+ /* we don't need this any longer */
+ if (dscp)
+ cm_ReleaseSCache(dscp);
+
+ if (code) {
+ /* something went wrong creating or truncating the file */
+ if (scp)
+ cm_ReleaseSCache(scp);
+ cm_ReleaseUser(userp);
+ return code;
+ }
+
+ /* make sure we're about to open a file */
+ if (scp->fileType != CM_SCACHETYPE_FILE) {
+ cm_ReleaseSCache(scp);
+ cm_ReleaseUser(userp);
+ return CM_ERROR_ISDIR;
+ }
+
+ /* now all we have to do is open the file itself */
+ fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
+ osi_assert(fidp);
+
+ /* save a pointer to the vnode */
+ fidp->scp = scp;
+ /* also the user */
+ cm_HoldUser(userp);
+ fidp->userp = userp;
+
+ /* compute open mode */
+ if (openMode != 1)
+ fidp->flags |= SMB_FID_OPENREAD;
+ if (openMode == 1 || openMode == 2)
+ fidp->flags |= SMB_FID_OPENWRITE;
+
+ smb_ReleaseFID(fidp);
+
+ cm_Open(scp, 0, userp);
+
+ /* set inp->fid so that later read calls in same msg can find fid */
+ inp->fid = fidp->fid;
+
+ /* copy out remainder of the parms */
+ parmSlot = 2;
+ smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
+ lock_ObtainMutex(&scp->mx);
+ if (extraInfo) {
+ smb_SetSMBParm(outp, parmSlot, smb_Attributes(scp)); parmSlot++;
+ smb_DosUTimeFromUnixTime(&dosTime, scp->clientModTime);
+ smb_SetSMBParm(outp, parmSlot, dosTime & 0xffff); parmSlot++;
+ smb_SetSMBParm(outp, parmSlot, (dosTime>>16) & 0xffff); parmSlot++;
+ smb_SetSMBParm(outp, parmSlot, scp->length.LowPart & 0xffff); parmSlot++;
+ smb_SetSMBParm(outp, parmSlot, (scp->length.LowPart >> 16) & 0xffff); parmSlot++;
+ smb_SetSMBParm(outp, parmSlot, openMode); parmSlot++;
+ smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* file type 0 ==> normal file or dir */
+ smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* IPC junk */
+ }
+ /* and the final "always present" stuff */
+ smb_SetSMBParm(outp, parmSlot, openAction); parmSlot++;
+ /* next write out the "unique" ID */
+ smb_SetSMBParm(outp, parmSlot, scp->fid.vnode & 0xffff); parmSlot++;
+ smb_SetSMBParm(outp, parmSlot, scp->fid.volume & 0xffff); parmSlot++;
+ smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
+ lock_ReleaseMutex(&scp->mx);
+ smb_SetSMBDataLength(outp, 0);
+
+ osi_Log1(smb_logp, "SMB OpenX opening fid %d", fidp->fid);
+
+ cm_ReleaseUser(userp);
+ /* leave scp held since we put it in fidp->scp */
+ return 0;
+}
+
+static void smb_GetLockParams(unsigned char LockType,
+ char ** buf,
+ unsigned int * ppid,
+ LARGE_INTEGER * pOffset,
+ LARGE_INTEGER * pLength)
+{
+ if (LockType & LOCKING_ANDX_LARGE_FILES) {
+ /* Large Files */
+ *ppid = *((USHORT *) *buf);
+ pOffset->HighPart = *((LONG *)(*buf + 4));
+ pOffset->LowPart = *((DWORD *)(*buf + 8));
+ pLength->HighPart = *((LONG *)(*buf + 12));
+ pLength->LowPart = *((DWORD *)(*buf + 16));
+ *buf += 20;
+ }
+ else {
+ /* Not Large Files */
+ *ppid = *((USHORT *) *buf);
+ pOffset->HighPart = 0;
+ pOffset->LowPart = *((DWORD *)(*buf + 2));
+ pLength->HighPart = 0;
+ pLength->LowPart = *((DWORD *)(*buf + 6));
+ *buf += 10;
+ }
}
long smb_ReceiveV3LockingX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
{
- cm_req_t req;
- cm_user_t *userp;
- unsigned short fid;
- smb_fid_t *fidp;
- cm_scache_t *scp;
- unsigned char LockType;
- unsigned short NumberOfUnlocks, NumberOfLocks;
- unsigned long Timeout;
- char *op;
- LARGE_INTEGER LOffset, LLength;
- smb_waitingLock_t *waitingLock;
- void *lockp;
- long code;
- int i;
-
- cm_InitReq(&req);
-
- fid = smb_GetSMBParm(inp, 2);
- fid = smb_ChainFID(fid, inp);
-
- fidp = smb_FindFID(vcp, fid, 0);
- if (!fidp || (fidp->flags & SMB_FID_IOCTL)) {
- return CM_ERROR_BADFD;
- }
- /* set inp->fid so that later read calls in same msg can find fid */
- inp->fid = fid;
+ cm_req_t req;
+ cm_user_t *userp;
+ unsigned short fid;
+ smb_fid_t *fidp;
+ cm_scache_t *scp;
+ unsigned char LockType;
+ unsigned short NumberOfUnlocks, NumberOfLocks;
+ long Timeout;
+ char *op;
+ char *op_locks;
+ LARGE_INTEGER LOffset, LLength;
+ smb_waitingLockRequest_t *wlRequest = NULL;
+ cm_file_lock_t *lockp;
+ long code = 0;
+ int i;
+ cm_key_t key;
+ unsigned int pid;
+
+ cm_InitReq(&req);
+
+ fid = smb_GetSMBParm(inp, 2);
+ fid = smb_ChainFID(fid, inp);
+
+ fidp = smb_FindFID(vcp, fid, 0);
+ if (!fidp || (fidp->flags & SMB_FID_IOCTL)) {
+ osi_Log0(smb_logp, "smb_ReceiveV3Locking BadFD");
+ return CM_ERROR_BADFD;
+ }
+ /* set inp->fid so that later read calls in same msg can find fid */
+ inp->fid = fid;
- userp = smb_GetUser(vcp, inp);
+ userp = smb_GetUser(vcp, inp);
- scp = fidp->scp;
+ scp = fidp->scp;
- lock_ObtainMutex(&scp->mx);
- code = cm_SyncOp(scp, NULL, userp, &req, 0,
- CM_SCACHESYNC_NEEDCALLBACK
+ lock_ObtainMutex(&scp->mx);
+ code = cm_SyncOp(scp, NULL, userp, &req, 0,
+ CM_SCACHESYNC_NEEDCALLBACK
| CM_SCACHESYNC_GETSTATUS
| CM_SCACHESYNC_LOCK);
- if (code) goto doneSync;
-
- LockType = smb_GetSMBParm(inp, 3) & 0xff;
- Timeout = (smb_GetSMBParm(inp, 5) << 16) + smb_GetSMBParm(inp, 4);
- NumberOfUnlocks = smb_GetSMBParm(inp, 6);
- NumberOfLocks = smb_GetSMBParm(inp, 7);
-
- op = smb_GetSMBData(inp, NULL);
-
- for (i=0; i<NumberOfUnlocks; i++) {
- if (LockType & 0x10) {
- /* Large Files */
- LOffset.HighPart = *((LONG *)(op + 4));
- LOffset.LowPart = *((DWORD *)(op + 8));
- LLength.HighPart = *((LONG *)(op + 12));
- LLength.LowPart = *((DWORD *)(op + 16));
- op += 20;
- }
- else {
- /* Not Large Files */
- LOffset.HighPart = 0;
- LOffset.LowPart = *((DWORD *)(op + 2));
- LLength.HighPart = 0;
- LLength.LowPart = *((DWORD *)(op + 6));
- op += 10;
- }
- if (LargeIntegerNotEqualToZero(LOffset))
- continue;
- /* Do not check length -- length check done in cm_Unlock */
-
- code = cm_Unlock(scp, LockType, LOffset, LLength, userp, &req);
- if (code) goto done;
- }
+ if (code) {
+ osi_Log1(smb_logp, "smb_ReceiveV3Locking SyncOp failure code 0x%x", code);
+ goto doneSync;
+ }
+
+ LockType = smb_GetSMBParm(inp, 3) & 0xff;
+ Timeout = (smb_GetSMBParm(inp, 5) << 16) + smb_GetSMBParm(inp, 4);
+ NumberOfUnlocks = smb_GetSMBParm(inp, 6);
+ NumberOfLocks = smb_GetSMBParm(inp, 7);
+
+ if ((LockType & LOCKING_ANDX_CANCEL_LOCK) ||
+ (LockType & LOCKING_ANDX_CHANGE_LOCKTYPE)) {
+
+ /* We don't support these requests. Apparently, we can safely
+ not deal with them too. */
+ osi_Log1(smb_logp, "smb_ReceiveV3Locking received unsupported request [%s]",
+ ((LockType & LOCKING_ANDX_CANCEL_LOCK)?
+ "LOCKING_ANDX_CANCEL_LOCK":
+ "LOCKING_ANDX_CHANGE_LOCKTYPE"));
+ /* No need to call osi_LogSaveString since these are string
+ constants.*/
+
+ code = CM_ERROR_BADOP;
+ goto done;
+
+ }
+
+ op = smb_GetSMBData(inp, NULL);
+
+ for (i=0; i<NumberOfUnlocks; i++) {
+ smb_GetLockParams(LockType, &op, &pid, &LOffset, &LLength);
+
+ key = cm_GenerateKey(vcp->vcID, pid, fidp->fid);
+
+ code = cm_Unlock(scp, LockType, LOffset, LLength, key, userp, &req);
+
+ if (code)
+ goto done;
+ }
+
+ op_locks = op;
+
+ for (i=0; i<NumberOfLocks; i++) {
+ smb_GetLockParams(LockType, &op, &pid, &LOffset, &LLength);
+
+ key = cm_GenerateKey(vcp->vcID, pid, fidp->fid);
+
+ code = cm_Lock(scp, LockType, LOffset, LLength, key, (Timeout != 0),
+ userp, &req, &lockp);
+
+ if (code == CM_ERROR_WOULDBLOCK && Timeout != 0) {
+ smb_waitingLock_t * wLock;
+
+ /* Put on waiting list */
+ if(wlRequest == NULL) {
+ int j;
+ char * opt;
+ cm_key_t tkey;
+ LARGE_INTEGER tOffset, tLength;
+
+ wlRequest = malloc(sizeof(smb_waitingLockRequest_t));
+
+ osi_assert(wlRequest != NULL);
+
+ wlRequest->vcp = vcp;
+ smb_HoldVC(vcp);
+ wlRequest->scp = scp;
+ cm_HoldSCache(scp);
+ wlRequest->inp = smb_CopyPacket(inp);
+ wlRequest->outp = smb_CopyPacket(outp);
+ wlRequest->lockType = LockType;
+ wlRequest->timeRemaining = Timeout;
+ wlRequest->locks = NULL;
+
+ /* The waiting lock request needs to have enough
+ information to undo all the locks in the request.
+ We do the following to store info about locks that
+ have already been granted. Sure, we can get most
+ of the info from the packet, but the packet doesn't
+ hold the result of cm_Lock call. In practice we
+ only receive packets with one or two locks, so we
+ are only wasting a few bytes here and there and
+ only for a limited period of time until the waiting
+ lock times out or is freed. */
+
+ for(opt = op_locks, j=i; j > 0; j--) {
+ smb_GetLockParams(LockType, &opt, &pid, &tOffset, &tLength);
+
+ tkey = cm_GenerateKey(vcp->vcID, pid, fidp->fid);
+
+ wLock = malloc(sizeof(smb_waitingLock_t));
+
+ osi_assert(wLock != NULL);
+
+ wLock->key = tkey;
+ wLock->LOffset = tOffset;
+ wLock->LLength = tLength;
+ wLock->lockp = NULL;
+ wLock->state = SMB_WAITINGLOCKSTATE_DONE;
+ osi_QAdd((osi_queue_t **) &wlRequest->locks,
+ &wLock->q);
+ }
+ }
+
+ wLock = malloc(sizeof(smb_waitingLock_t));
+
+ osi_assert(wLock != NULL);
+
+ wLock->key = key;
+ wLock->LOffset = LOffset;
+ wLock->LLength = LLength;
+ wLock->lockp = lockp;
+ wLock->state = SMB_WAITINGLOCKSTATE_WAITING;
+ osi_QAdd((osi_queue_t **) &wlRequest->locks,
+ &wLock->q);
+
+ osi_Log1(smb_logp, "smb_ReceiveV3Locking WaitingLock created 0x%p",
+ wLock);
+
+ code = 0;
+ continue;
+ }
+
+ if (code) {
+ osi_Log1(smb_logp, "smb_ReceiveV3Locking cm_Lock failure code 0x%x", code);
+ break;
+ }
+ }
+
+ if (code) {
+
+ /* Since something went wrong with the lock number i, we now
+ have to go ahead and release any locks acquired before the
+ failure. All locks before lock number i (of which there
+ are i of them) have either been successful or are waiting.
+ Either case requires calling cm_Unlock(). */
+
+ /* And purge the waiting lock */
+ if(wlRequest != NULL) {
+ smb_waitingLock_t * wl;
+ smb_waitingLock_t * wlNext;
+ long ul_code;
+
+ for(wl = wlRequest->locks; wl; wl = wlNext) {
+
+ wlNext = (smb_waitingLock_t *) osi_QNext(&wl->q);
+
+ ul_code = cm_Unlock(scp, LockType, wl->LOffset, wl->LLength, wl->key, userp, &req);
+
+ if(ul_code != 0) {
+ osi_Log1(smb_logp, "smb_ReceiveV3Locking cm_Unlock returns code %d", ul_code);
+ } else {
+ osi_Log0(smb_logp, "smb_ReceiveV3Locking cm_Unlock successful");
+ }
+
+ osi_QRemove((osi_queue_t **) &wlRequest->locks, &wl->q);
+ free(wl);
+
+ }
+
+ smb_ReleaseVC(wlRequest->vcp);
+ cm_ReleaseSCache(wlRequest->scp);
+ smb_FreePacket(wlRequest->inp);
+ smb_FreePacket(wlRequest->outp);
+
+ free(wlRequest);
+
+ wlRequest = NULL;
+ }
+
+ } else {
+
+ if (wlRequest != NULL) {
+
+ lock_ObtainWrite(&smb_globalLock);
+ osi_QAdd((osi_queue_t **)&smb_allWaitingLocks,
+ &wlRequest->q);
+ osi_Wakeup((LONG_PTR)&smb_allWaitingLocks);
+ lock_ReleaseWrite(&smb_globalLock);
+
+ /* don't send reply immediately */
+ outp->flags |= SMB_PACKETFLAG_NOSEND;
+ }
+
+ smb_SetSMBDataLength(outp, 0);
+ }
+
+ done:
+ cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_LOCK);
+
+ doneSync:
+ lock_ReleaseMutex(&scp->mx);
+ cm_ReleaseUser(userp);
+ smb_ReleaseFID(fidp);
+
+ return code;
+}
+
+long smb_ReceiveV3GetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
+{
+ unsigned short fid;
+ smb_fid_t *fidp;
+ cm_scache_t *scp;
+ long code = 0;
+ afs_uint32 searchTime;
+ cm_user_t *userp;
+ cm_req_t req;
+
+ cm_InitReq(&req);
+
+ fid = smb_GetSMBParm(inp, 0);
+ fid = smb_ChainFID(fid, inp);
+
+ fidp = smb_FindFID(vcp, fid, 0);
+ if (!fidp || (fidp->flags & SMB_FID_IOCTL)) {
+ return CM_ERROR_BADFD;
+ }
+
+ userp = smb_GetUser(vcp, inp);
+
+ scp = fidp->scp;
+
+ /* otherwise, stat the file */
+ lock_ObtainMutex(&scp->mx);
+ code = cm_SyncOp(scp, NULL, userp, &req, 0,
+ CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
+ if (code) goto done;
+
+ /* decode times. We need a search time, but the response to this
+ * call provides the date first, not the time, as returned in the
+ * searchTime variable. So we take the high-order bits first.
+ */
+ smb_SearchTimeFromUnixTime(&searchTime, scp->clientModTime);
+ smb_SetSMBParm(outp, 0, (searchTime >> 16) & 0xffff); /* ctime */
+ smb_SetSMBParm(outp, 1, searchTime & 0xffff);
+ smb_SetSMBParm(outp, 2, (searchTime >> 16) & 0xffff); /* atime */
+ smb_SetSMBParm(outp, 3, searchTime & 0xffff);
+ smb_SetSMBParm(outp, 4, (searchTime >> 16) & 0xffff); /* mtime */
+ smb_SetSMBParm(outp, 5, searchTime & 0xffff);
+
+ /* now handle file size and allocation size */
+ smb_SetSMBParm(outp, 6, scp->length.LowPart & 0xffff); /* file size */
+ smb_SetSMBParm(outp, 7, (scp->length.LowPart >> 16) & 0xffff);
+ smb_SetSMBParm(outp, 8, scp->length.LowPart & 0xffff); /* alloc size */
+ smb_SetSMBParm(outp, 9, (scp->length.LowPart >> 16) & 0xffff);
+
+ /* file attribute */
+ smb_SetSMBParm(outp, 10, smb_Attributes(scp));
+
+ /* and finalize stuff */
+ smb_SetSMBDataLength(outp, 0);
+ code = 0;
+
+ done:
+ lock_ReleaseMutex(&scp->mx);
+ cm_ReleaseUser(userp);
+ smb_ReleaseFID(fidp);
+ return code;
+}
+
+long smb_ReceiveV3SetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
+{
+ unsigned short fid;
+ smb_fid_t *fidp;
+ cm_scache_t *scp;
+ long code = 0;
+ afs_uint32 searchTime;
+ time_t unixTime;
+ cm_user_t *userp;
+ cm_attr_t attrs;
+ cm_req_t req;
+
+ cm_InitReq(&req);
+
+ fid = smb_GetSMBParm(inp, 0);
+ fid = smb_ChainFID(fid, inp);
+
+ fidp = smb_FindFID(vcp, fid, 0);
+ if (!fidp || (fidp->flags & SMB_FID_IOCTL)) {
+ return CM_ERROR_BADFD;
+ }
+
+ userp = smb_GetUser(vcp, inp);
+
+ scp = fidp->scp;
+
+ /* now prepare to call cm_setattr. This message only sets various times,
+ * and AFS only implements mtime, and we'll set the mtime if that's
+ * requested. The others we'll ignore.
+ */
+ searchTime = smb_GetSMBParm(inp, 5) | (smb_GetSMBParm(inp, 6) << 16);
+
+ if (searchTime != 0) {
+ smb_UnixTimeFromSearchTime(&unixTime, searchTime);
+
+ if ( unixTime != -1 ) {
+ attrs.mask = CM_ATTRMASK_CLIENTMODTIME;
+ attrs.clientModTime = unixTime;
+ code = cm_SetAttr(scp, &attrs, userp, &req);
+
+ osi_Log1(smb_logp, "SMB receive V3SetAttributes [fid=%ld]", fid);
+ } else {
+ osi_Log1(smb_logp, "**smb_UnixTimeFromSearchTime failed searchTime=%ld", searchTime);
+ }
+ }
+ else code = 0;
+
+ cm_ReleaseUser(userp);
+ smb_ReleaseFID(fidp);
+ return code;
+}
+
+
+long smb_ReceiveV3ReadX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
+{
+ osi_hyper_t offset;
+ long count;
+ long finalCount = 0;
+ unsigned short fd;
+ unsigned pid;
+ smb_fid_t *fidp;
+ long code = 0;
+ cm_user_t *userp;
+ cm_key_t key;
+ char *op;
+
+ fd = smb_GetSMBParm(inp, 2);
+ count = smb_GetSMBParm(inp, 5);
+ offset.HighPart = 0; /* too bad */
+ offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
+
+ osi_Log3(smb_logp, "smb_ReceiveV3Read fd %d, off 0x%x, size 0x%x",
+ fd, offset.LowPart, count);
+
+ fd = smb_ChainFID(fd, inp);
+ fidp = smb_FindFID(vcp, fd, 0);
+ if (!fidp) {
+ return CM_ERROR_BADFD;
+ }
+
+ pid = ((smb_t *) inp)->pid;
+ key = cm_GenerateKey(vcp->vcID, pid, fd);
+ {
+ LARGE_INTEGER LOffset, LLength;
+
+ LOffset.HighPart = offset.HighPart;
+ LOffset.LowPart = offset.LowPart;
+ LLength.HighPart = 0;
+ LLength.LowPart = count;
+
+ lock_ObtainMutex(&fidp->scp->mx);
+ code = cm_LockCheckRead(fidp->scp, LOffset, LLength, key);
+ lock_ReleaseMutex(&fidp->scp->mx);
+ }
+
+ if (code) {
+ smb_ReleaseFID(fidp);
+ return code;
+ }
+
+ /* set inp->fid so that later read calls in same msg can find fid */
+ inp->fid = fd;
+
+ if (fidp->flags & SMB_FID_IOCTL) {
+ return smb_IoctlV3Read(fidp, vcp, inp, outp);
+ }
+
+ userp = smb_GetUser(vcp, inp);
+
+ /* 0 and 1 are reserved for request chaining, were setup by our caller,
+ * and will be further filled in after we return.
+ */
+ smb_SetSMBParm(outp, 2, 0); /* remaining bytes, for pipes */
+ smb_SetSMBParm(outp, 3, 0); /* resvd */
+ smb_SetSMBParm(outp, 4, 0); /* resvd */
+ smb_SetSMBParm(outp, 5, count); /* # of bytes we're going to read */
+ /* fill in #6 when we have all the parameters' space reserved */
+ smb_SetSMBParm(outp, 7, 0); /* resv'd */
+ smb_SetSMBParm(outp, 8, 0); /* resv'd */
+ smb_SetSMBParm(outp, 9, 0); /* resv'd */
+ smb_SetSMBParm(outp, 10, 0); /* resv'd */
+ smb_SetSMBParm(outp, 11, 0); /* reserved */
+
+ /* get op ptr after putting in the parms, since otherwise we don't
+ * know where the data really is.
+ */
+ op = smb_GetSMBData(outp, NULL);
+
+ /* now fill in offset from start of SMB header to first data byte (to op) */
+ smb_SetSMBParm(outp, 6, ((int) (op - outp->data)));
+
+ /* set the packet data length the count of the # of bytes */
+ smb_SetSMBDataLength(outp, count);
+
+#ifndef DJGPP
+ code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount);
+#else /* DJGPP */
+ code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount, FALSE);
+#endif /* !DJGPP */
+
+ /* fix some things up */
+ smb_SetSMBParm(outp, 5, finalCount);
+ smb_SetSMBDataLength(outp, finalCount);
+
+ smb_ReleaseFID(fidp);
+
+ cm_ReleaseUser(userp);
+ return code;
+}
+
+/*
+ * Values for createDisp, copied from NTDDK.H
+ */
+#define FILE_SUPERSEDE 0 // (???)
+#define FILE_OPEN 1 // (open)
+#define FILE_CREATE 2 // (exclusive)
+#define FILE_OPEN_IF 3 // (non-exclusive)
+#define FILE_OVERWRITE 4 // (open & truncate, but do not create)
+#define FILE_OVERWRITE_IF 5 // (open & truncate, or create)
+
+/* Flags field */
+#define REQUEST_OPLOCK 2
+#define REQUEST_BATCH_OPLOCK 4
+#define OPEN_DIRECTORY 8
+#define EXTENDED_RESPONSE_REQUIRED 0x10
+
+/* CreateOptions field. */
+#define FILE_DIRECTORY_FILE 0x0001
+#define FILE_WRITE_THROUGH 0x0002
+#define FILE_SEQUENTIAL_ONLY 0x0004
+#define FILE_NON_DIRECTORY_FILE 0x0040
+#define FILE_NO_EA_KNOWLEDGE 0x0200
+#define FILE_EIGHT_DOT_THREE_ONLY 0x0400
+#define FILE_RANDOM_ACCESS 0x0800
+#define FILE_DELETE_ON_CLOSE 0x1000
+#define FILE_OPEN_BY_FILE_ID 0x2000
+
+long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
+{
+ char *pathp, *realPathp;
+ long code = 0;
+ cm_space_t *spacep;
+ cm_user_t *userp;
+ cm_scache_t *dscp; /* parent dir */
+ cm_scache_t *scp; /* file to create or open */
+ cm_scache_t *targetScp; /* if scp is a symlink */
+ cm_attr_t setAttr;
+ char *lastNamep;
+ char *treeStartp;
+ unsigned short nameLength;
+ unsigned int flags;
+ unsigned int requestOpLock;
+ unsigned int requestBatchOpLock;
+ unsigned int mustBeDir;
+ unsigned int extendedRespRequired;
+ unsigned int treeCreate;
+ int realDirFlag;
+ unsigned int desiredAccess;
+ unsigned int extAttributes;
+ unsigned int createDisp;
+ unsigned int createOptions;
+ unsigned int shareAccess;
+ int initialModeBits;
+ unsigned short baseFid;
+ smb_fid_t *baseFidp;
+ smb_fid_t *fidp;
+ cm_scache_t *baseDirp;
+ unsigned short openAction;
+ int parmSlot;
+ long fidflags;
+ FILETIME ft;
+ LARGE_INTEGER sz;
+ char *tidPathp;
+ BOOL foundscp;
+ cm_req_t req;
+
+ cm_InitReq(&req);
+
+ /* This code is very long and has a lot of if-then-else clauses
+ * scp and dscp get reused frequently and we need to ensure that
+ * we don't lose a reference. Start by ensuring that they are NULL.
+ */
+ scp = NULL;
+ dscp = NULL;
+ treeCreate = FALSE;
+ foundscp = FALSE;
+
+ nameLength = smb_GetSMBOffsetParm(inp, 2, 1);
+ flags = smb_GetSMBOffsetParm(inp, 3, 1)
+ | (smb_GetSMBOffsetParm(inp, 4, 1) << 16);
+ requestOpLock = flags & REQUEST_OPLOCK;
+ requestBatchOpLock = flags & REQUEST_BATCH_OPLOCK;
+ mustBeDir = flags & OPEN_DIRECTORY;
+ extendedRespRequired = flags & EXTENDED_RESPONSE_REQUIRED;
+
+ /*
+ * Why all of a sudden 32-bit FID?
+ * We will reject all bits higher than 16.
+ */
+ if (smb_GetSMBOffsetParm(inp, 6, 1) != 0)
+ return CM_ERROR_INVAL;
+ baseFid = smb_GetSMBOffsetParm(inp, 5, 1);
+ desiredAccess = smb_GetSMBOffsetParm(inp, 7, 1)
+ | (smb_GetSMBOffsetParm(inp, 8, 1) << 16);
+ extAttributes = smb_GetSMBOffsetParm(inp, 13, 1)
+ | (smb_GetSMBOffsetParm(inp, 14, 1) << 16);
+ shareAccess = smb_GetSMBOffsetParm(inp, 15, 1)
+ | (smb_GetSMBOffsetParm(inp, 16, 1) << 16);
+ createDisp = smb_GetSMBOffsetParm(inp, 17, 1)
+ | (smb_GetSMBOffsetParm(inp, 18, 1) << 16);
+ createOptions = smb_GetSMBOffsetParm(inp, 19, 1)
+ | (smb_GetSMBOffsetParm(inp, 20, 1) << 16);
+
+ /* mustBeDir is never set; createOptions directory bit seems to be
+ * more important
+ */
+ if (createOptions & FILE_DIRECTORY_FILE)
+ realDirFlag = 1;
+ else if (createOptions & FILE_NON_DIRECTORY_FILE)
+ realDirFlag = 0;
+ else
+ realDirFlag = -1;
+
+ /*
+ * compute initial mode bits based on read-only flag in
+ * extended attributes
+ */
+ initialModeBits = 0666;
+ if (extAttributes & SMB_ATTR_READONLY)
+ initialModeBits &= ~0222;
+
+ pathp = smb_GetSMBData(inp, NULL);
+ /* Sometimes path is not null-terminated, so we make a copy. */
+ realPathp = malloc(nameLength+1);
+ memcpy(realPathp, pathp, nameLength);
+ realPathp[nameLength] = 0;
+ if (smb_StoreAnsiFilenames)
+ OemToChar(realPathp,realPathp);
+
+ spacep = inp->spacep;
+ smb_StripLastComponent(spacep->data, &lastNamep, realPathp);
+
+ osi_Log1(smb_logp,"NTCreateX for [%s]",osi_LogSaveString(smb_logp,realPathp));
+ osi_Log4(smb_logp,"... da=[%x] ea=[%x] cd=[%x] co=[%x]", desiredAccess, extAttributes, createDisp, createOptions);
+ osi_Log3(smb_logp,"... share=[%x] flags=[%x] lastNamep=[%s]", shareAccess, flags, osi_LogSaveString(smb_logp,(lastNamep?lastNamep:"null")));
+
+ if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
+ /* special case magic file name for receiving IOCTL requests
+ * (since IOCTL calls themselves aren't getting through).
+ */
+ fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
+ smb_SetupIoctlFid(fidp, spacep);
+ osi_Log1(smb_logp,"NTCreateX Setting up IOCTL on fid[%d]",fidp->fid);
+
+ /* set inp->fid so that later read calls in same msg can find fid */
+ inp->fid = fidp->fid;
+
+ /* out parms */
+ parmSlot = 2;
+ smb_SetSMBParmByte(outp, parmSlot, 0); /* oplock */
+ smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
+ smb_SetSMBParmLong(outp, parmSlot, 1); parmSlot += 2; /* Action */
+ /* times */
+ memset(&ft, 0, sizeof(ft));
+ smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
+ smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
+ smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
+ smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
+ smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2; /* attr */
+ sz.HighPart = 0x7fff; sz.LowPart = 0;
+ smb_SetSMBParmDouble(outp, parmSlot, (char *)&sz); parmSlot += 4; /* alen */
+ smb_SetSMBParmDouble(outp, parmSlot, (char *)&sz); parmSlot += 4; /* len */
+ smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* filetype */
+ smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* dev state */
+ smb_SetSMBParmByte(outp, parmSlot, 0); /* is a dir? */
+ smb_SetSMBDataLength(outp, 0);
+
+ /* clean up fid reference */
+ smb_ReleaseFID(fidp);
+ free(realPathp);
+ return 0;
+ }
+
+#ifdef DEBUG_VERBOSE
+ {
+ char *hexp, *asciip;
+ asciip = (lastNamep? lastNamep : realPathp);
+ hexp = osi_HexifyString( asciip );
+ DEBUG_EVENT2("AFS", "NTCreateX H[%s] A[%s]", hexp, asciip);
+ free(hexp);
+ }
+#endif
+
+ userp = smb_GetUser(vcp, inp);
+ if (!userp) {
+ osi_Log1(smb_logp, "NTCreateX Invalid user [%d]", ((smb_t *) inp)->uid);
+ free(realPathp);
+ return CM_ERROR_INVAL;
+ }
+
+ if (baseFid == 0) {
+ baseDirp = cm_data.rootSCachep;
+ code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
+ if (code == CM_ERROR_TIDIPC) {
+ /* Attempt to use a TID allocated for IPC. The client
+ * is probably looking for DCE RPC end points which we
+ * don't support OR it could be looking to make a DFS
+ * referral request.
+ */
+ osi_Log0(smb_logp, "NTCreateX received IPC TID");
+#ifndef DFS_SUPPORT
+ free(realPathp);
+ cm_ReleaseUser(userp);
+ return CM_ERROR_NOSUCHFILE;
+#endif /* DFS_SUPPORT */
+ }
+ } else {
+ baseFidp = smb_FindFID(vcp, baseFid, 0);
+ if (!baseFidp) {
+ osi_Log1(smb_logp, "NTCreateX Invalid base fid [%d]", baseFid);
+ free(realPathp);
+ cm_ReleaseUser(userp);
+ return CM_ERROR_INVAL;
+ }
+ baseDirp = baseFidp->scp;
+ tidPathp = NULL;
+ }
+
+ osi_Log1(smb_logp, "NTCreateX tidPathp=[%s]", (tidPathp==NULL)?"null": osi_LogSaveString(smb_logp,tidPathp));
+
+ /* compute open mode */
+ fidflags = 0;
+ if (desiredAccess & DELETE)
+ fidflags |= SMB_FID_OPENDELETE;
+ if (desiredAccess & AFS_ACCESS_READ)
+ fidflags |= SMB_FID_OPENREAD;
+ if (desiredAccess & AFS_ACCESS_WRITE)
+ fidflags |= SMB_FID_OPENWRITE;
+ if (createOptions & FILE_DELETE_ON_CLOSE)
+ fidflags |= SMB_FID_DELONCLOSE;
+
+ /* and the share mode */
+ if (shareAccess & FILE_SHARE_READ)
+ fidflags |= SMB_FID_SHARE_READ;
+ if (shareAccess & FILE_SHARE_WRITE)
+ fidflags |= SMB_FID_SHARE_WRITE;
+
+ code = 0;
+
+ /* For an exclusive create, we want to do a case sensitive match for the last component. */
+ if ( createDisp == FILE_CREATE ||
+ createDisp == FILE_OVERWRITE ||
+ createDisp == FILE_OVERWRITE_IF) {
+ code = cm_NameI(baseDirp, spacep->data, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
+ userp, tidPathp, &req, &dscp);
+ if (code == 0) {
+#ifdef DFS_SUPPORT
+ if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
+ cm_ReleaseSCache(dscp);
+ cm_ReleaseUser(userp);
+ free(realPathp);
+ if ( WANTS_DFS_PATHNAMES(inp) )
+ return CM_ERROR_PATH_NOT_COVERED;
+ else
+ return CM_ERROR_BADSHARENAME;
+ }
+#endif /* DFS_SUPPORT */
+ code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp, CM_FLAG_FOLLOW,
+ userp, &req, &scp);
+ if (code == CM_ERROR_NOSUCHFILE) {
+ code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp,
+ CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, &req, &scp);
+ if (code == 0 && realDirFlag == 1) {
+ cm_ReleaseSCache(scp);
+ cm_ReleaseSCache(dscp);
+ cm_ReleaseUser(userp);
+ free(realPathp);
+ return CM_ERROR_EXISTS;
+ }
+ }
+ }
+ /* we have both scp and dscp */
+ } else {
+ code = cm_NameI(baseDirp, realPathp, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
+ userp, tidPathp, &req, &scp);
+#ifdef DFS_SUPPORT
+ if (code == 0 && scp->fileType == CM_SCACHETYPE_DFSLINK) {
+ cm_ReleaseSCache(scp);
+ cm_ReleaseUser(userp);
+ free(realPathp);
+ if ( WANTS_DFS_PATHNAMES(inp) )
+ return CM_ERROR_PATH_NOT_COVERED;
+ else
+ return CM_ERROR_BADSHARENAME;
+ }
+#endif /* DFS_SUPPORT */
+ /* we might have scp but not dscp */
+ }
+
+ if (scp)
+ foundscp = TRUE;
+
+ if (!foundscp || (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE))) {
+ /* look up parent directory */
+ /* If we are trying to create a path (i.e. multiple nested directories), then we don't *need*
+ * the immediate parent. We have to work our way up realPathp until we hit something that we
+ * recognize.
+ */
+
+ /* we might or might not have scp */
+
+ if (dscp == NULL) {
+ do {
+ char *tp;
+
+ code = cm_NameI(baseDirp, spacep->data,
+ CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
+ userp, tidPathp, &req, &dscp);
+
+#ifdef DFS_SUPPORT
+ if (code == 0 && dscp->fileType == CM_SCACHETYPE_DFSLINK) {
+ if (scp)
+ cm_ReleaseSCache(scp);
+ cm_ReleaseSCache(dscp);
+ cm_ReleaseUser(userp);
+ free(realPathp);
+ if ( WANTS_DFS_PATHNAMES(inp) )
+ return CM_ERROR_PATH_NOT_COVERED;
+ else
+ return CM_ERROR_BADSHARENAME;
+ }
+#endif /* DFS_SUPPORT */
+
+ if (code &&
+ (tp = strrchr(spacep->data,'\\')) &&
+ (createDisp == FILE_CREATE) &&
+ (realDirFlag == 1)) {
+ *tp++ = 0;
+ treeCreate = TRUE;
+ treeStartp = realPathp + (tp - spacep->data);
+
+ if (*tp && !smb_IsLegalFilename(tp)) {
+ if (baseFid != 0)
+ smb_ReleaseFID(baseFidp);
+ cm_ReleaseUser(userp);
+ free(realPathp);
+ if (scp)
+ cm_ReleaseSCache(scp);
+ return CM_ERROR_BADNTFILENAME;
+ }
+ code = 0;
+ }
+ } while (dscp == NULL && code == 0);
+ } else
+ code = 0;
- for (i=0; i<NumberOfLocks; i++) {
- if (LockType & 0x10) {
- /* Large Files */
- LOffset.HighPart = *((LONG *)(op + 4));
- LOffset.LowPart = *((DWORD *)(op + 8));
- LLength.HighPart = *((LONG *)(op + 12));
- LLength.LowPart = *((DWORD *)(op + 16));
- op += 20;
- }
- else {
- /* Not Large Files */
- LOffset.HighPart = 0;
- LOffset.LowPart = *((DWORD *)(op + 2));
- LLength.HighPart = 0;
- LLength.LowPart = *((DWORD *)(op + 6));
- op += 10;
- }
- if (LargeIntegerNotEqualToZero(LOffset))
- continue;
- if (LargeIntegerLessThan(LOffset, scp->length))
- continue;
-
- code = cm_Lock(scp, LockType, LOffset, LLength, Timeout,
- userp, &req, &lockp);
- if (code == CM_ERROR_WOULDBLOCK && Timeout != 0) {
- /* Put on waiting list */
- waitingLock = malloc(sizeof(smb_waitingLock_t));
- waitingLock->vcp = vcp;
- waitingLock->inp = smb_CopyPacket(inp);
- waitingLock->outp = smb_CopyPacket(outp);
- waitingLock->timeRemaining = Timeout;
- waitingLock->lockp = lockp;
- lock_ObtainWrite(&smb_globalLock);
- osi_QAdd((osi_queue_t **)&smb_allWaitingLocks,
- &waitingLock->q);
- osi_Wakeup((long) &smb_allWaitingLocks);
- lock_ReleaseWrite(&smb_globalLock);
- /* don't send reply immediately */
- outp->flags |= SMB_PACKETFLAG_NOSEND;
- }
- if (code) break;
- }
+ /* we might have scp and we might have dscp */
- if (code) {
- /* release any locks acquired before the failure */
- }
- else
- smb_SetSMBDataLength(outp, 0);
-done:
- cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_LOCK);
-doneSync:
- lock_ReleaseMutex(&scp->mx);
- cm_ReleaseUser(userp);
- smb_ReleaseFID(fidp);
-
- return code;
-}
+ if (baseFid != 0)
+ smb_ReleaseFID(baseFidp);
-long smb_ReceiveV3GetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
-{
- unsigned short fid;
- smb_fid_t *fidp;
- cm_scache_t *scp;
- long code;
- long searchTime;
- cm_user_t *userp;
- cm_req_t req;
-
- cm_InitReq(&req);
-
- fid = smb_GetSMBParm(inp, 0);
- fid = smb_ChainFID(fid, inp);
-
- fidp = smb_FindFID(vcp, fid, 0);
- if (!fidp || (fidp->flags & SMB_FID_IOCTL)) {
- return CM_ERROR_BADFD;
+ if (code) {
+ osi_Log0(smb_logp,"NTCreateX parent not found");
+ if (scp)
+ cm_ReleaseSCache(scp);
+ if (dscp)
+ cm_ReleaseSCache(dscp);
+ cm_ReleaseUser(userp);
+ free(realPathp);
+ return code;
}
-
- userp = smb_GetUser(vcp, inp);
-
- scp = fidp->scp;
-
- /* otherwise, stat the file */
- lock_ObtainMutex(&scp->mx);
- code = cm_SyncOp(scp, NULL, userp, &req, 0,
- CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
- if (code) goto done;
- /* decode times. We need a search time, but the response to this
- * call provides the date first, not the time, as returned in the
- * searchTime variable. So we take the high-order bits first.
- */
- smb_SearchTimeFromUnixTime(&searchTime, scp->clientModTime);
- smb_SetSMBParm(outp, 0, (searchTime >> 16) & 0xffff); /* ctime */
- smb_SetSMBParm(outp, 1, searchTime & 0xffff);
- smb_SetSMBParm(outp, 2, (searchTime >> 16) & 0xffff); /* atime */
- smb_SetSMBParm(outp, 3, searchTime & 0xffff);
- smb_SetSMBParm(outp, 4, (searchTime >> 16) & 0xffff); /* mtime */
- smb_SetSMBParm(outp, 5, searchTime & 0xffff);
-
- /* now handle file size and allocation size */
- smb_SetSMBParm(outp, 6, scp->length.LowPart & 0xffff); /* file size */
- smb_SetSMBParm(outp, 7, (scp->length.LowPart >> 16) & 0xffff);
- smb_SetSMBParm(outp, 8, scp->length.LowPart & 0xffff); /* alloc size */
- smb_SetSMBParm(outp, 9, (scp->length.LowPart >> 16) & 0xffff);
-
- /* file attribute */
- smb_SetSMBParm(outp, 10, smb_Attributes(scp));
-
- /* and finalize stuff */
- smb_SetSMBDataLength(outp, 0);
- code = 0;
+ if (treeCreate && dscp->fileType == CM_SCACHETYPE_FILE) {
+ /* A file exists where we want a directory. */
+ if (scp)
+ cm_ReleaseSCache(scp);
+ cm_ReleaseSCache(dscp);
+ cm_ReleaseUser(userp);
+ free(realPathp);
+ return CM_ERROR_EXISTS;
+ }
-done:
- lock_ReleaseMutex(&scp->mx);
- cm_ReleaseUser(userp);
- smb_ReleaseFID(fidp);
- return code;
-}
+ if (!lastNamep)
+ lastNamep = realPathp;
+ else
+ lastNamep++;
-long smb_ReceiveV3SetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
-{
- unsigned short fid;
- smb_fid_t *fidp;
- cm_scache_t *scp;
- long code;
- long searchTime;
- long unixTime;
- cm_user_t *userp;
- cm_attr_t attrs;
- cm_req_t req;
-
- cm_InitReq(&req);
-
- fid = smb_GetSMBParm(inp, 0);
- fid = smb_ChainFID(fid, inp);
-
- fidp = smb_FindFID(vcp, fid, 0);
- if (!fidp || (fidp->flags & SMB_FID_IOCTL)) {
- return CM_ERROR_BADFD;
+ if (!smb_IsLegalFilename(lastNamep)) {
+ if (scp)
+ cm_ReleaseSCache(scp);
+ if (dscp)
+ cm_ReleaseSCache(dscp);
+ cm_ReleaseUser(userp);
+ free(realPathp);
+ return CM_ERROR_BADNTFILENAME;
}
-
- userp = smb_GetUser(vcp, inp);
-
- scp = fidp->scp;
-
- /* now prepare to call cm_setattr. This message only sets various times,
- * and AFS only implements mtime, and we'll set the mtime if that's
- * requested. The others we'll ignore.
- */
- searchTime = smb_GetSMBParm(inp, 5) | (smb_GetSMBParm(inp, 6) << 16);
-
- if (searchTime != 0) {
- smb_UnixTimeFromSearchTime(&unixTime, searchTime);
-
- if (unixTime != -1) {
- attrs.mask = CM_ATTRMASK_CLIENTMODTIME;
- attrs.clientModTime = unixTime;
- code = cm_SetAttr(scp, &attrs, userp, &req);
-
- osi_Log1(afsd_logp, "SMB receive V3SetAttributes [fid=%ld]", fid);
- }
- else {
- osi_Log1(afsd_logp, "**smb_UnixTimeFromSearchTime failed searchTime=%ld", searchTime);
- }
-
- }
- else code = 0;
- cm_ReleaseUser(userp);
- smb_ReleaseFID(fidp);
- return code;
-}
+ if (!foundscp && !treeCreate) {
+ if ( createDisp == FILE_CREATE ||
+ createDisp == FILE_OVERWRITE ||
+ createDisp == FILE_OVERWRITE_IF)
+ {
+ code = cm_Lookup(dscp, lastNamep,
+ CM_FLAG_FOLLOW, userp, &req, &scp);
+ } else {
+ code = cm_Lookup(dscp, lastNamep,
+ CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
+ userp, &req, &scp);
+ }
+ if (code && code != CM_ERROR_NOSUCHFILE) {
+ if (dscp)
+ cm_ReleaseSCache(dscp);
+ cm_ReleaseUser(userp);
+ free(realPathp);
+ return code;
+ }
+ }
+ /* we have scp and dscp */
+ } else {
+ /* we have scp but not dscp */
+ if (baseFid != 0)
+ smb_ReleaseFID(baseFidp);
+ }
+ /* if we get here, if code is 0, the file exists and is represented by
+ * scp. Otherwise, we have to create it. The dir may be represented
+ * by dscp, or we may have found the file directly. If code is non-zero,
+ * scp is NULL.
+ */
+ if (code == 0 && !treeCreate) {
+ if (createDisp == FILE_CREATE) {
+ /* oops, file shouldn't be there */
+ if (dscp)
+ cm_ReleaseSCache(dscp);
+ if (scp)
+ cm_ReleaseSCache(scp);
+ cm_ReleaseUser(userp);
+ free(realPathp);
+ return CM_ERROR_EXISTS;
+ }
-long smb_ReceiveV3ReadX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
-{
- osi_hyper_t offset;
- long count, finalCount;
- unsigned short fd;
- smb_fid_t *fidp;
- long code;
- cm_user_t *userp;
- char *op;
-
- fd = smb_GetSMBParm(inp, 2);
- count = smb_GetSMBParm(inp, 5);
- offset.HighPart = 0; /* too bad */
- offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
-
- osi_Log3(afsd_logp, "smb_ReceiveV3Read fd %d, off 0x%x, size 0x%x",
- fd, offset.LowPart, count);
-
- fd = smb_ChainFID(fd, inp);
- fidp = smb_FindFID(vcp, fd, 0);
- if (!fidp) {
- return CM_ERROR_BADFD;
+ if ( createDisp == FILE_OVERWRITE ||
+ createDisp == FILE_OVERWRITE_IF) {
+
+ setAttr.mask = CM_ATTRMASK_LENGTH;
+ setAttr.length.LowPart = 0;
+ setAttr.length.HighPart = 0;
+ /* now watch for a symlink */
+ code = 0;
+ while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
+ targetScp = 0;
+ osi_assert(dscp != NULL);
+ code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
+ if (code == 0) {
+ /* we have a more accurate file to use (the
+ * target of the symbolic link). Otherwise,
+ * we'll just use the symlink anyway.
+ */
+ osi_Log2(smb_logp, "symlink vp %x to vp %x",
+ scp, targetScp);
+ cm_ReleaseSCache(scp);
+ scp = targetScp;
+ }
+ }
+ code = cm_SetAttr(scp, &setAttr, userp, &req);
+ openAction = 3; /* truncated existing file */
}
- /* set inp->fid so that later read calls in same msg can find fid */
- inp->fid = fd;
+ else
+ openAction = 1; /* found existing file */
- if (fidp->flags & SMB_FID_IOCTL) {
- return smb_IoctlV3Read(fidp, vcp, inp, outp);
+ code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp, &req);
+ if (code) {
+ if (dscp)
+ cm_ReleaseSCache(dscp);
+ if (scp)
+ cm_ReleaseSCache(scp);
+ cm_ReleaseUser(userp);
+ free(realPathp);
+ return code;
+ }
+ } else if (createDisp == FILE_OPEN || createDisp == FILE_OVERWRITE) {
+ /* don't create if not found */
+ if (dscp)
+ cm_ReleaseSCache(dscp);
+ if (scp)
+ cm_ReleaseSCache(scp);
+ cm_ReleaseUser(userp);
+ free(realPathp);
+ return CM_ERROR_NOSUCHFILE;
+ } else if (realDirFlag == 0 || realDirFlag == -1) {
+ osi_assert(dscp != NULL);
+ osi_Log1(smb_logp, "smb_ReceiveNTCreateX creating file %s",
+ osi_LogSaveString(smb_logp, lastNamep));
+ openAction = 2; /* created file */
+ setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
+ setAttr.clientModTime = time(NULL);
+ code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp, &req);
+ if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
+ smb_NotifyChange(FILE_ACTION_ADDED,
+ FILE_NOTIFY_CHANGE_FILE_NAME,
+ dscp, lastNamep, NULL, TRUE);
+ if (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE) {
+ /* Not an exclusive create, and someone else tried
+ * creating it already, then we open it anyway. We
+ * don't bother retrying after this, since if this next
+ * fails, that means that the file was deleted after we
+ * started this call.
+ */
+ code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
+ userp, &req, &scp);
+ if (code == 0) {
+ if (createDisp == FILE_OVERWRITE_IF) {
+ setAttr.mask = CM_ATTRMASK_LENGTH;
+ setAttr.length.LowPart = 0;
+ setAttr.length.HighPart = 0;
+
+ /* now watch for a symlink */
+ code = 0;
+ while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
+ targetScp = 0;
+ code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
+ if (code == 0) {
+ /* we have a more accurate file to use (the
+ * target of the symbolic link). Otherwise,
+ * we'll just use the symlink anyway.
+ */
+ osi_Log2(smb_logp, "symlink vp %x to vp %x",
+ scp, targetScp);
+ cm_ReleaseSCache(scp);
+ scp = targetScp;
+ }
+ }
+ code = cm_SetAttr(scp, &setAttr, userp, &req);
+ }
+ } /* lookup succeeded */
+ }
+ } else {
+ char *tp, *pp;
+ char *cp; /* This component */
+ int clen = 0; /* length of component */
+ cm_scache_t *tscp1, *tscp2;
+ int isLast = 0;
+
+ /* create directory */
+ if ( !treeCreate )
+ treeStartp = lastNamep;
+ osi_assert(dscp != NULL);
+ osi_Log1(smb_logp, "smb_ReceiveNTCreateX creating directory [%s]",
+ osi_LogSaveString(smb_logp, treeStartp));
+ openAction = 2; /* created directory */
+
+ /* if the request is to create the root directory
+ * it will appear as a directory name of the nul-string
+ * and a code of CM_ERROR_NOSUCHFILE
+ */
+ if ( !*treeStartp && code == CM_ERROR_NOSUCHFILE)
+ code = CM_ERROR_EXISTS;
+
+ setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
+ setAttr.clientModTime = time(NULL);
+
+ pp = treeStartp;
+ cp = spacep->data;
+ tscp1 = dscp;
+ cm_HoldSCache(tscp1);
+ tscp2 = NULL;
+
+ while (pp && *pp) {
+ tp = strchr(pp, '\\');
+ if (!tp) {
+ strcpy(cp,pp);
+ clen = (int)strlen(cp);
+ isLast = 1; /* indicate last component. the supplied path never ends in a slash */
+ } else {
+ clen = (int)(tp - pp);
+ strncpy(cp,pp,clen);
+ *(cp + clen) = 0;
+ tp++;
+ }
+ pp = tp;
+
+ if (clen == 0)
+ continue; /* the supplied path can't have consecutive slashes either , but */
+
+ /* cp is the next component to be created. */
+ code = cm_MakeDir(tscp1, cp, 0, &setAttr, userp, &req);
+ if (code == 0 && (tscp1->flags & CM_SCACHEFLAG_ANYWATCH))
+ smb_NotifyChange(FILE_ACTION_ADDED,
+ FILE_NOTIFY_CHANGE_DIR_NAME,
+ tscp1, cp, NULL, TRUE);
+ if (code == 0 ||
+ (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE)) {
+ /* Not an exclusive create, and someone else tried
+ * creating it already, then we open it anyway. We
+ * don't bother retrying after this, since if this next
+ * fails, that means that the file was deleted after we
+ * started this call.
+ */
+ code = cm_Lookup(tscp1, cp, CM_FLAG_CASEFOLD,
+ userp, &req, &tscp2);
+ }
+ if (code)
+ break;
+
+ if (!isLast) { /* for anything other than dscp, release it unless it's the last one */
+ cm_ReleaseSCache(tscp1);
+ tscp1 = tscp2; /* Newly created directory will be next parent */
+ /* the hold is transfered to tscp1 from tscp2 */
+ }
}
-
- userp = smb_GetUser(vcp, inp);
- /* 0 and 1 are reserved for request chaining, were setup by our caller,
- * and will be further filled in after we return.
+ if (dscp)
+ cm_ReleaseSCache(dscp);
+ dscp = tscp1;
+ if (scp)
+ cm_ReleaseSCache(scp);
+ scp = tscp2;
+ /*
+ * if we get here and code == 0, then scp is the last directory created, and dscp is the
+ * parent of scp.
*/
- smb_SetSMBParm(outp, 2, 0); /* remaining bytes, for pipes */
- smb_SetSMBParm(outp, 3, 0); /* resvd */
- smb_SetSMBParm(outp, 4, 0); /* resvd */
- smb_SetSMBParm(outp, 5, count); /* # of bytes we're going to read */
- /* fill in #6 when we have all the parameters' space reserved */
- smb_SetSMBParm(outp, 7, 0); /* resv'd */
- smb_SetSMBParm(outp, 8, 0); /* resv'd */
- smb_SetSMBParm(outp, 9, 0); /* resv'd */
- smb_SetSMBParm(outp, 10, 0); /* resv'd */
- smb_SetSMBParm(outp, 11, 0); /* reserved */
-
- /* get op ptr after putting in the parms, since otherwise we don't
- * know where the data really is.
- */
- op = smb_GetSMBData(outp, NULL);
-
- /* now fill in offset from start of SMB header to first data byte (to op) */
- smb_SetSMBParm(outp, 6, ((int) (op - outp->data)));
-
- /* set the packet data length the count of the # of bytes */
- smb_SetSMBDataLength(outp, count);
+ }
-#ifndef DJGPP
- code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount);
-#else /* DJGPP */
- code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount, FALSE);
-#endif /* !DJGPP */
+ if (code) {
+ /* something went wrong creating or truncating the file */
+ if (scp)
+ cm_ReleaseSCache(scp);
+ if (dscp)
+ cm_ReleaseSCache(dscp);
+ cm_ReleaseUser(userp);
+ free(realPathp);
+ return code;
+ }
- /* fix some things up */
- smb_SetSMBParm(outp, 5, finalCount);
- smb_SetSMBDataLength(outp, finalCount);
+ /* make sure we have file vs. dir right (only applies for single component case) */
+ if (realDirFlag == 0 && scp->fileType != CM_SCACHETYPE_FILE) {
+ /* now watch for a symlink */
+ code = 0;
+ while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
+ cm_scache_t * targetScp = 0;
+ code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
+ if (code == 0) {
+ /* we have a more accurate file to use (the
+ * target of the symbolic link). Otherwise,
+ * we'll just use the symlink anyway.
+ */
+ osi_Log2(smb_logp, "symlink vp %x to vp %x", scp, targetScp);
+ cm_ReleaseSCache(scp);
+ scp = targetScp;
+ }
+ }
- smb_ReleaseFID(fidp);
+ if (scp->fileType != CM_SCACHETYPE_FILE) {
+ if (dscp)
+ cm_ReleaseSCache(dscp);
+ cm_ReleaseSCache(scp);
+ cm_ReleaseUser(userp);
+ free(realPathp);
+ return CM_ERROR_ISDIR;
+ }
+ }
+ /* (only applies to single component case) */
+ if (realDirFlag == 1 && scp->fileType == CM_SCACHETYPE_FILE) {
+ cm_ReleaseSCache(scp);
+ if (dscp)
+ cm_ReleaseSCache(dscp);
cm_ReleaseUser(userp);
- return code;
-}
-
-/*
- * Values for createDisp, copied from NTDDK.H
- *
- * FILE_SUPERSEDE 0 (???)
- * FILE_OPEN 1 (open)
- * FILE_CREATE 2 (exclusive)
- * FILE_OPEN_IF 3 (non-exclusive)
- * FILE_OVERWRITE 4 (open & truncate, but do not create)
- * FILE_OVERWRITE_IF 5 (open & truncate, or create)
- */
+ free(realPathp);
+ return CM_ERROR_NOTDIR;
+ }
-long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
-{
- char *pathp, *realPathp;
- long code;
- cm_space_t *spacep;
- cm_user_t *userp;
- cm_scache_t *dscp; /* parent dir */
- cm_scache_t *scp; /* file to create or open */
- cm_attr_t setAttr;
- char *lastNamep;
- char *treeStartp;
- unsigned short nameLength;
- unsigned int flags;
- unsigned int requestOpLock;
- unsigned int requestBatchOpLock;
- unsigned int mustBeDir;
- unsigned int treeCreate;
- int realDirFlag;
- unsigned int desiredAccess;
- unsigned int extAttributes;
- unsigned int createDisp;
- unsigned int createOptions;
- int initialModeBits;
- unsigned short baseFid;
- smb_fid_t *baseFidp;
- smb_fid_t *fidp;
- cm_scache_t *baseDirp;
- unsigned short openAction;
- int parmSlot;
- long fidflags;
- FILETIME ft;
- LARGE_INTEGER sz;
- char *tidPathp;
- BOOL foundscp;
- cm_req_t req;
-
- cm_InitReq(&req);
-
- treeCreate = FALSE;
- foundscp = FALSE;
- scp = NULL;
-
- nameLength = smb_GetSMBOffsetParm(inp, 2, 1);
- flags = smb_GetSMBOffsetParm(inp, 3, 1)
- | (smb_GetSMBOffsetParm(inp, 4, 1) << 16);
- requestOpLock = flags & 0x02;
- requestBatchOpLock = flags & 0x04;
- mustBeDir = flags & 0x08;
-
- /*
- * Why all of a sudden 32-bit FID?
- * We will reject all bits higher than 16.
- */
- if (smb_GetSMBOffsetParm(inp, 6, 1) != 0)
- return CM_ERROR_INVAL;
- baseFid = smb_GetSMBOffsetParm(inp, 5, 1);
- desiredAccess = smb_GetSMBOffsetParm(inp, 7, 1)
- | (smb_GetSMBOffsetParm(inp, 8, 1) << 16);
- extAttributes = smb_GetSMBOffsetParm(inp, 13, 1)
- | (smb_GetSMBOffsetParm(inp, 14, 1) << 16);
- createDisp = smb_GetSMBOffsetParm(inp, 17, 1)
- | (smb_GetSMBOffsetParm(inp, 18, 1) << 16);
- createOptions = smb_GetSMBOffsetParm(inp, 19, 1)
- | (smb_GetSMBOffsetParm(inp, 20, 1) << 16);
-
- /* mustBeDir is never set; createOptions directory bit seems to be
- * more important
- */
- if (createOptions & 1)
- realDirFlag = 1;
- else if (createOptions & 0x40)
- realDirFlag = 0;
- else
- realDirFlag = -1;
-
- /*
- * compute initial mode bits based on read-only flag in
- * extended attributes
- */
- initialModeBits = 0666;
- if (extAttributes & 1) initialModeBits &= ~0222;
-
- pathp = smb_GetSMBData(inp, NULL);
- /* Sometimes path is not null-terminated, so we make a copy. */
- realPathp = malloc(nameLength+1);
- memcpy(realPathp, pathp, nameLength);
- realPathp[nameLength] = 0;
-
- spacep = inp->spacep;
- smb_StripLastComponent(spacep->data, &lastNamep, realPathp);
-
- osi_Log1(afsd_logp,"NTCreateX for [%s]",osi_LogSaveString(afsd_logp,realPathp));
- osi_Log4(afsd_logp,"NTCreateX da=[%x] ea=[%x] cd=[%x] co=[%x]", desiredAccess, extAttributes, createDisp, createOptions);
-
- if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
- /* special case magic file name for receiving IOCTL requests
- * (since IOCTL calls themselves aren't getting through).
- */
- fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
- smb_SetupIoctlFid(fidp, spacep);
-
- /* set inp->fid so that later read calls in same msg can find fid */
- inp->fid = fidp->fid;
-
- /* out parms */
- parmSlot = 2;
- smb_SetSMBParmByte(outp, parmSlot, 0); /* oplock */
- smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
- smb_SetSMBParmLong(outp, parmSlot, 1); parmSlot += 2; /* Action */
- /* times */
- memset(&ft, 0, sizeof(ft));
- smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
- smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
- smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
- smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
- smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2; /* attr */
- sz.HighPart = 0x7fff; sz.LowPart = 0;
- smb_SetSMBParmDouble(outp, parmSlot, (char *)&sz); parmSlot += 4; /* alen */
- smb_SetSMBParmDouble(outp, parmSlot, (char *)&sz); parmSlot += 4; /* len */
- smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* filetype */
- smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* dev state */
- smb_SetSMBParmByte(outp, parmSlot, 0); /* is a dir? */
- smb_SetSMBDataLength(outp, 0);
-
- /* clean up fid reference */
- smb_ReleaseFID(fidp);
- free(realPathp);
- return 0;
- }
+ /* open the file itself */
+ fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
+ osi_assert(fidp);
+
+ /* save a reference to the user */
+ cm_HoldUser(userp);
+ fidp->userp = userp;
+
+ /* If we are restricting sharing, we should do so with a suitable
+ share lock. */
+ if (scp->fileType == CM_SCACHETYPE_FILE &&
+ !(fidflags & SMB_FID_SHARE_WRITE)) {
+ cm_key_t key;
+ LARGE_INTEGER LOffset, LLength;
+ int sLockType;
+
+ LOffset.HighPart = SMB_FID_QLOCK_HIGH;
+ LOffset.LowPart = SMB_FID_QLOCK_LOW;
+ LLength.HighPart = 0;
+ LLength.LowPart = SMB_FID_QLOCK_LENGTH;
+
+ if (fidflags & SMB_FID_SHARE_READ) {
+ sLockType = LOCKING_ANDX_SHARED_LOCK;
+ } else {
+ sLockType = 0;
+ }
-#ifdef DEBUG_VERBOSE
- {
- char *hexp, *asciip;
- asciip = (lastNamep? lastNamep : realPathp);
- hexp = osi_HexifyString( asciip );
- DEBUG_EVENT2("AFS", "NTCreateX H[%s] A[%s]", hexp, asciip);
- free(hexp);
- }
-#endif
+ key = cm_GenerateKey(vcp->vcID, SMB_FID_QLOCK_PID, fidp->fid);
+
+ lock_ObtainMutex(&scp->mx);
+ code = cm_Lock(scp, sLockType, LOffset, LLength, key, 0, userp, &req, NULL);
+ lock_ReleaseMutex(&scp->mx);
+
+ if (code) {
+ fidp->flags = SMB_FID_DELETE;
+ smb_ReleaseFID(fidp);
+
+ cm_ReleaseSCache(scp);
+ if (dscp)
+ cm_ReleaseSCache(dscp);
+ cm_ReleaseUser(userp);
+ free(realPathp);
+
+ return code;
+ }
+ }
- userp = smb_GetUser(vcp, inp);
+ /* save a pointer to the vnode */
+ fidp->scp = scp; /* Hold transfered to fidp->scp and no longer needed */
- if(!userp) {
- osi_Log1(afsd_logp, "NTCreateX Invalid user [%d]", ((smb_t *) inp)->uid);
- free(realPathp);
- return CM_ERROR_INVAL;
- }
+ fidp->flags = fidflags;
- if (baseFid == 0) {
- baseDirp = cm_rootSCachep;
- tidPathp = smb_GetTIDPath(vcp, ((smb_t *)inp)->tid);
- }
- else {
- baseFidp = smb_FindFID(vcp, baseFid, 0);
- if(!baseFidp) {
- osi_Log1(afsd_logp, "NTCreateX Invalid base fid [%d]", baseFid);
- free(realPathp);
- cm_ReleaseUser(userp);
- return CM_ERROR_INVAL;
- }
- baseDirp = baseFidp->scp;
- tidPathp = NULL;
- }
+ /* save parent dir and pathname for delete or change notification */
+ if (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE)) {
+ fidp->flags |= SMB_FID_NTOPEN;
+ fidp->NTopen_dscp = dscp;
+ cm_HoldSCache(dscp);
+ fidp->NTopen_pathp = strdup(lastNamep);
+ }
+ fidp->NTopen_wholepathp = realPathp;
- osi_Log1(afsd_logp, "NTCreateX tidPathp=[%s]", (tidPathp==NULL)?"null": osi_LogSaveString(afsd_logp,tidPathp));
-
- /* compute open mode */
- fidflags = 0;
- if (desiredAccess & DELETE)
- fidflags |= SMB_FID_OPENDELETE;
- if (desiredAccess & AFS_ACCESS_READ)
- fidflags |= SMB_FID_OPENREAD;
- if (desiredAccess & AFS_ACCESS_WRITE)
- fidflags |= SMB_FID_OPENWRITE;
-
- dscp = NULL;
- code = 0;
- code = cm_NameI(baseDirp, realPathp, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
- userp, tidPathp, &req, &scp);
- if (code == 0) foundscp = TRUE;
- if (code != 0
- || (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE))) {
- /* look up parent directory */
- /* If we are trying to create a path (i.e. multiple nested directories), then we don't *need*
- the immediate parent. We have to work our way up realPathp until we hit something that we
- recognize.
- */
-
- while(1) {
- char *tp;
-
- code = cm_NameI(baseDirp, spacep->data,
- CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
- userp, tidPathp, &req, &dscp);
-
- if(code &&
- (tp = strrchr(spacep->data,'\\')) &&
- (createDisp == 2) &&
- (realDirFlag == 1)) {
- *tp++ = 0;
- treeCreate = TRUE;
- treeStartp = realPathp + (tp - spacep->data);
-
- if(*tp && !smb_IsLegalFilename(tp)) {
- if(baseFid != 0) smb_ReleaseFID(baseFidp);
- cm_ReleaseUser(userp);
- free(realPathp);
- return CM_ERROR_BADNTFILENAME;
- }
- }
- else
- break;
- }
-
- if (baseFid != 0) smb_ReleaseFID(baseFidp);
-
- if (code) {
- osi_Log0(afsd_logp,"NTCreateX parent not found");
- cm_ReleaseUser(userp);
- free(realPathp);
- return code;
- }
-
- if(treeCreate && dscp->fileType == CM_SCACHETYPE_FILE) {
- /* A file exists where we want a directory. */
- cm_ReleaseSCache(dscp);
- cm_ReleaseUser(userp);
- free(realPathp);
- return CM_ERROR_EXISTS;
- }
-
- if (!lastNamep) lastNamep = realPathp;
- else lastNamep++;
-
- if (!smb_IsLegalFilename(lastNamep)) {
- cm_ReleaseSCache(dscp);
- cm_ReleaseUser(userp);
- free(realPathp);
- return CM_ERROR_BADNTFILENAME;
- }
-
- if (!foundscp && !treeCreate) {
- code = cm_Lookup(dscp, lastNamep,
- CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
- userp, &req, &scp);
- if (code && code != CM_ERROR_NOSUCHFILE) {
- cm_ReleaseSCache(dscp);
- cm_ReleaseUser(userp);
- free(realPathp);
- return code;
- }
- }
- }
- else {
- if (baseFid != 0) smb_ReleaseFID(baseFidp);
- }
+ /* we don't need this any longer */
+ if (dscp) {
+ cm_ReleaseSCache(dscp);
+ dscp = NULL;
+ }
- /* if we get here, if code is 0, the file exists and is represented by
- * scp. Otherwise, we have to create it. The dir may be represented
- * by dscp, or we may have found the file directly. If code is non-zero,
- * scp is NULL.
- */
- if (code == 0 && !treeCreate) {
- code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp,
- &req);
- if (code) {
- if (dscp) cm_ReleaseSCache(dscp);
- cm_ReleaseSCache(scp);
- cm_ReleaseUser(userp);
- free(realPathp);
- return code;
- }
-
- if (createDisp == 2) {
- /* oops, file shouldn't be there */
- if (dscp) cm_ReleaseSCache(dscp);
- cm_ReleaseSCache(scp);
- cm_ReleaseUser(userp);
- free(realPathp);
- return CM_ERROR_EXISTS;
- }
-
- if (createDisp == 4
- || createDisp == 5) {
- setAttr.mask = CM_ATTRMASK_LENGTH;
- setAttr.length.LowPart = 0;
- setAttr.length.HighPart = 0;
- code = cm_SetAttr(scp, &setAttr, userp, &req);
- openAction = 3; /* truncated existing file */
- }
- else openAction = 1; /* found existing file */
- }
- else if (createDisp == 1 || createDisp == 4) {
- /* don't create if not found */
- if (dscp) cm_ReleaseSCache(dscp);
- cm_ReleaseUser(userp);
- free(realPathp);
- return CM_ERROR_NOSUCHFILE;
- }
- else if (realDirFlag == 0 || realDirFlag == -1) {
- osi_assert(dscp != NULL);
- osi_Log1(afsd_logp, "smb_ReceiveNTCreateX creating file %s",
- osi_LogSaveString(afsd_logp, lastNamep));
- openAction = 2; /* created file */
- setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
- setAttr.clientModTime = time(NULL);
- code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
- &req);
- if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
- smb_NotifyChange(FILE_ACTION_ADDED,
- FILE_NOTIFY_CHANGE_FILE_NAME,
- dscp, lastNamep, NULL, TRUE);
- if (code == CM_ERROR_EXISTS && createDisp != 2) {
- /* Not an exclusive create, and someone else tried
- * creating it already, then we open it anyway. We
- * don't bother retrying after this, since if this next
- * fails, that means that the file was deleted after we
- * started this call.
- */
- code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
- userp, &req, &scp);
- if (code == 0) {
- if (createDisp == 5) {
- setAttr.mask = CM_ATTRMASK_LENGTH;
- setAttr.length.LowPart = 0;
- setAttr.length.HighPart = 0;
- code = cm_SetAttr(scp, &setAttr, userp,
- &req);
- }
- } /* lookup succeeded */
- }
- }
- else {
- char *tp, *pp;
- char *cp; /* This component */
- int clen; /* length of component */
- cm_scache_t *tscp;
- int isLast = 0;
-
- /* create directory */
- if(!treeCreate) treeStartp = lastNamep;
- osi_assert(dscp != NULL);
- osi_Log1(afsd_logp, "smb_ReceiveNTCreateX creating directory [%s]",
- osi_LogSaveString(afsd_logp, treeStartp));
- openAction = 2; /* created directory */
-
- setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
- setAttr.clientModTime = time(NULL);
-
- pp = treeStartp;
- cp = spacep->data;
- tscp = dscp;
-
- while(pp && *pp) {
- tp = strchr(pp, '\\');
- if(!tp) {
- strcpy(cp,pp);
- isLast = 1; /* indicate last component. the supplied path never ends in a slash */
- }
- else {
- clen = tp - pp;
- strncpy(cp,pp,clen);
- *(cp + clen) = 0;
- tp++;
- }
- pp = tp;
-
- if(clen == 0) continue; /* the supplied path can't have consecutive slashes either , but */
-
- /* cp is the next component to be created. */
- code = cm_MakeDir(tscp, cp, 0, &setAttr, userp, &req);
- if (code == 0 && (tscp->flags & CM_SCACHEFLAG_ANYWATCH))
- smb_NotifyChange(FILE_ACTION_ADDED,
- FILE_NOTIFY_CHANGE_DIR_NAME,
- tscp, cp, NULL, TRUE);
- if (code == 0 ||
- (code == CM_ERROR_EXISTS && createDisp != 2)) {
- /* Not an exclusive create, and someone else tried
- * creating it already, then we open it anyway. We
- * don't bother retrying after this, since if this next
- * fails, that means that the file was deleted after we
- * started this call.
- */
- code = cm_Lookup(tscp, cp, CM_FLAG_CASEFOLD,
- userp, &req, &scp);
- }
- if(code) break;
-
- if(!isLast) { /* for anything other than dscp, release it unless it's the last one */
- cm_ReleaseSCache(tscp);
- tscp = scp; /* Newly created directory will be next parent */
- }
- }
-
- /*
- if we get here and code == 0, then scp is the last directory created, and tscp is the
- parent of scp. dscp got released if dscp != tscp. both tscp and scp are held.
- */
- dscp = tscp;
- }
+ cm_Open(scp, 0, userp);
+
+ /* set inp->fid so that later read calls in same msg can find fid */
+ inp->fid = fidp->fid;
+
+ /* out parms */
+ parmSlot = 2;
+ lock_ObtainMutex(&scp->mx);
+ smb_SetSMBParmByte(outp, parmSlot, 0); /* oplock */
+ smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
+ smb_SetSMBParmLong(outp, parmSlot, openAction); parmSlot += 2;
+ smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
+ smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
+ smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
+ smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
+ smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
+ smb_SetSMBParmLong(outp, parmSlot, smb_ExtAttributes(scp));
+ parmSlot += 2;
+ smb_SetSMBParmDouble(outp, parmSlot, (char *)&scp->length); parmSlot += 4;
+ smb_SetSMBParmDouble(outp, parmSlot, (char *)&scp->length); parmSlot += 4;
+ smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* filetype */
+ smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* dev state */
+ smb_SetSMBParmByte(outp, parmSlot,
+ scp->fileType == CM_SCACHETYPE_DIRECTORY); /* is a dir? */
+ lock_ReleaseMutex(&scp->mx);
+ smb_SetSMBDataLength(outp, 0);
- if (code) {
- /* something went wrong creating or truncating the file */
- if (scp) cm_ReleaseSCache(scp);
- if (dscp) cm_ReleaseSCache(dscp);
- cm_ReleaseUser(userp);
- free(realPathp);
- return code;
- }
+ osi_Log2(smb_logp, "SMB NT CreateX opening fid %d path %s", fidp->fid,
+ osi_LogSaveString(smb_logp, realPathp));
- /* make sure we have file vs. dir right (only applies for single component case) */
- if (realDirFlag == 0 && scp->fileType != CM_SCACHETYPE_FILE) {
- cm_ReleaseSCache(scp);
- if (dscp) cm_ReleaseSCache(dscp);
- cm_ReleaseUser(userp);
- free(realPathp);
- return CM_ERROR_ISDIR;
- }
- /* (only applies for single component case) */
- if (realDirFlag == 1 && scp->fileType == CM_SCACHETYPE_FILE) {
- cm_ReleaseSCache(scp);
- if (dscp) cm_ReleaseSCache(dscp);
- cm_ReleaseUser(userp);
- free(realPathp);
- return CM_ERROR_NOTDIR;
- }
+ smb_ReleaseFID(fidp);
- /* open the file itself */
- fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
- osi_assert(fidp);
- /* save a pointer to the vnode */
- fidp->scp = scp;
+ cm_ReleaseUser(userp);
- fidp->flags = fidflags;
+ /* Can't free realPathp if we get here since
+ fidp->NTopen_wholepathp is pointing there */
- /* save parent dir and pathname for delete or change notification */
- if (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE)) {
- fidp->flags |= SMB_FID_NTOPEN;
- fidp->NTopen_dscp = dscp;
- cm_HoldSCache(dscp);
- fidp->NTopen_pathp = strdup(lastNamep);
- }
- fidp->NTopen_wholepathp = realPathp;
-
- /* we don't need this any longer */
- if (dscp) cm_ReleaseSCache(dscp);
- cm_Open(scp, 0, userp);
-
- /* set inp->fid so that later read calls in same msg can find fid */
- inp->fid = fidp->fid;
-
- /* out parms */
- parmSlot = 2;
- lock_ObtainMutex(&scp->mx);
- smb_SetSMBParmByte(outp, parmSlot, 0); /* oplock */
- smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
- smb_SetSMBParmLong(outp, parmSlot, openAction); parmSlot += 2;
- smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
- smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
- smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
- smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
- smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
- smb_SetSMBParmLong(outp, parmSlot, smb_ExtAttributes(scp));
- parmSlot += 2;
- smb_SetSMBParmDouble(outp, parmSlot, (char *)&scp->length); parmSlot += 4;
- smb_SetSMBParmDouble(outp, parmSlot, (char *)&scp->length); parmSlot += 4;
- smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* filetype */
- smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* dev state */
- smb_SetSMBParmByte(outp, parmSlot,
- scp->fileType == CM_SCACHETYPE_DIRECTORY); /* is a dir? */
- lock_ReleaseMutex(&scp->mx);
- smb_SetSMBDataLength(outp, 0);
-
- osi_Log2(afsd_logp, "SMB NT CreateX opening fid %d path %s", fidp->fid,
- osi_LogSaveString(afsd_logp, realPathp));
-
- smb_ReleaseFID(fidp);
-
- cm_ReleaseUser(userp);
-
- /* Can't free realPathp if we get here since fidp->NTopen_wholepathp is pointing there */
-
- /* leave scp held since we put it in fidp->scp */
- return 0;
-}
+ /* leave scp held since we put it in fidp->scp */
+ return 0;
+}
/*
* A lot of stuff copied verbatim from NT Create&X to NT Tran Create.
*/
long smb_ReceiveNTTranCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
{
- char *pathp, *realPathp;
- long code;
- cm_space_t *spacep;
- cm_user_t *userp;
- cm_scache_t *dscp; /* parent dir */
- cm_scache_t *scp; /* file to create or open */
- cm_attr_t setAttr;
- char *lastNamep;
- unsigned long nameLength;
- unsigned int flags;
- unsigned int requestOpLock;
- unsigned int requestBatchOpLock;
- unsigned int mustBeDir;
- unsigned int extendedRespRequired;
- int realDirFlag;
- unsigned int desiredAccess;
- /*unsigned int allocSize;*/
- /*unsigned int shareAccess;*/
- unsigned int extAttributes;
- unsigned int createDisp;
- /*unsigned int sdLen;*/
- unsigned int createOptions;
- int initialModeBits;
- unsigned short baseFid;
- smb_fid_t *baseFidp;
- smb_fid_t *fidp;
- cm_scache_t *baseDirp;
- unsigned short openAction;
- int parmSlot;
- long fidflags;
- FILETIME ft;
- char *tidPathp;
- BOOL foundscp;
- int parmOffset, dataOffset;
- char *parmp;
- ULONG *lparmp;
- char *outData;
- cm_req_t req;
-
- cm_InitReq(&req);
-
- foundscp = FALSE;
- scp = NULL;
-
- parmOffset = smb_GetSMBOffsetParm(inp, 11, 1)
- | (smb_GetSMBOffsetParm(inp, 12, 1) << 16);
- parmp = inp->data + parmOffset;
- lparmp = (ULONG *) parmp;
-
- flags = lparmp[0];
- requestOpLock = flags & 0x02;
- requestBatchOpLock = flags & 0x04;
- mustBeDir = flags & 0x08;
- extendedRespRequired = flags & 0x10;
-
- /*
- * Why all of a sudden 32-bit FID?
- * We will reject all bits higher than 16.
- */
- if (lparmp[1] & 0xFFFF0000)
- return CM_ERROR_INVAL;
- baseFid = (unsigned short)lparmp[1];
- desiredAccess = lparmp[2];
- /*allocSize = lparmp[3];*/
- extAttributes = lparmp[5];
- /*shareAccess = lparmp[6];*/
- createDisp = lparmp[7];
- createOptions = lparmp[8];
- /*sdLen = lparmp[9];*/
- nameLength = lparmp[11];
-
- /*
- osi_Log4(afsd_logp,"NTTransCreate with da[%x],ea[%x],sa[%x],cd[%x]",desiredAccess,extAttributes,shareAccess,createDisp);
- osi_Log2(afsd_logp,"... co[%x],sdl[%x],as[%x]",createOptions,sdLen,allocSize);
- osi_Log1(afsd_logp,"... flags[%x]",flags);
- */
-
- /* mustBeDir is never set; createOptions directory bit seems to be
- * more important
- */
- if (createOptions & 1)
- realDirFlag = 1;
- else if (createOptions & 0x40)
- realDirFlag = 0;
- else
- realDirFlag = -1;
-
- /*
- * compute initial mode bits based on read-only flag in
- * extended attributes
- */
- initialModeBits = 0666;
- if (extAttributes & 1) initialModeBits &= ~0222;
+ char *pathp, *realPathp;
+ long code = 0;
+ cm_space_t *spacep;
+ cm_user_t *userp;
+ cm_scache_t *dscp; /* parent dir */
+ cm_scache_t *scp; /* file to create or open */
+ cm_scache_t *targetScp; /* if scp is a symlink */
+ cm_attr_t setAttr;
+ char *lastNamep;
+ unsigned long nameLength;
+ unsigned int flags;
+ unsigned int requestOpLock;
+ unsigned int requestBatchOpLock;
+ unsigned int mustBeDir;
+ unsigned int extendedRespRequired;
+ int realDirFlag;
+ unsigned int desiredAccess;
+#ifdef DEBUG_VERBOSE
+ unsigned int allocSize;
+#endif
+ unsigned int shareAccess;
+ unsigned int extAttributes;
+ unsigned int createDisp;
+#ifdef DEBUG_VERBOSE
+ unsigned int sdLen;
+#endif
+ unsigned int createOptions;
+ int initialModeBits;
+ unsigned short baseFid;
+ smb_fid_t *baseFidp;
+ smb_fid_t *fidp;
+ cm_scache_t *baseDirp;
+ unsigned short openAction;
+ int parmSlot;
+ long fidflags;
+ FILETIME ft;
+ char *tidPathp;
+ BOOL foundscp;
+ int parmOffset, dataOffset;
+ char *parmp;
+ ULONG *lparmp;
+ char *outData;
+ cm_req_t req;
+
+ cm_InitReq(&req);
+
+ foundscp = FALSE;
+ scp = NULL;
+
+ parmOffset = smb_GetSMBOffsetParm(inp, 11, 1)
+ | (smb_GetSMBOffsetParm(inp, 12, 1) << 16);
+ parmp = inp->data + parmOffset;
+ lparmp = (ULONG *) parmp;
+
+ flags = lparmp[0];
+ requestOpLock = flags & REQUEST_OPLOCK;
+ requestBatchOpLock = flags & REQUEST_BATCH_OPLOCK;
+ mustBeDir = flags & OPEN_DIRECTORY;
+ extendedRespRequired = flags & EXTENDED_RESPONSE_REQUIRED;
+
+ /*
+ * Why all of a sudden 32-bit FID?
+ * We will reject all bits higher than 16.
+ */
+ if (lparmp[1] & 0xFFFF0000)
+ return CM_ERROR_INVAL;
+ baseFid = (unsigned short)lparmp[1];
+ desiredAccess = lparmp[2];
+#ifdef DEBUG_VERBOSE
+ allocSize = lparmp[3];
+#endif /* DEBUG_VERSOSE */
+ extAttributes = lparmp[5];
+ shareAccess = lparmp[6];
+ createDisp = lparmp[7];
+ createOptions = lparmp[8];
+#ifdef DEBUG_VERBOSE
+ sdLen = lparmp[9];
+#endif
+ nameLength = lparmp[11];
- pathp = parmp + (13 * sizeof(ULONG)) + sizeof(UCHAR);
- /* Sometimes path is not null-terminated, so we make a copy. */
- realPathp = malloc(nameLength+1);
- memcpy(realPathp, pathp, nameLength);
- realPathp[nameLength] = 0;
+#ifdef DEBUG_VERBOSE
+ osi_Log4(smb_logp,"NTTranCreate with da[%x],ea[%x],sa[%x],cd[%x]",desiredAccess,extAttributes,shareAccess,createDisp);
+ osi_Log3(smb_logp,"... co[%x],sdl[%x],as[%x]",createOptions,sdLen,allocSize);
+ osi_Log1(smb_logp,"... flags[%x]",flags);
+#endif
- spacep = cm_GetSpace();
- smb_StripLastComponent(spacep->data, &lastNamep, realPathp);
+ /* mustBeDir is never set; createOptions directory bit seems to be
+ * more important
+ */
+ if (createOptions & FILE_DIRECTORY_FILE)
+ realDirFlag = 1;
+ else if (createOptions & FILE_NON_DIRECTORY_FILE)
+ realDirFlag = 0;
+ else
+ realDirFlag = -1;
+
+ /*
+ * compute initial mode bits based on read-only flag in
+ * extended attributes
+ */
+ initialModeBits = 0666;
+ if (extAttributes & 1)
+ initialModeBits &= ~0222;
+
+ pathp = parmp + (13 * sizeof(ULONG)) + sizeof(UCHAR);
+ /* Sometimes path is not null-terminated, so we make a copy. */
+ realPathp = malloc(nameLength+1);
+ memcpy(realPathp, pathp, nameLength);
+ realPathp[nameLength] = 0;
+ if (smb_StoreAnsiFilenames)
+ OemToChar(realPathp,realPathp);
+
+ spacep = cm_GetSpace();
+ smb_StripLastComponent(spacep->data, &lastNamep, realPathp);
+
+ /*
+ * Nothing here to handle SMB_IOCTL_FILENAME.
+ * Will add it if necessary.
+ */
- /*
- * Nothing here to handle SMB_IOCTL_FILENAME.
- * Will add it if necessary.
- */
#ifdef DEBUG_VERBOSE
- {
- char *hexp, *asciip;
- asciip = (lastNamep? lastNamep : realPathp);
- hexp = osi_HexifyString( asciip );
- DEBUG_EVENT2("AFS", "NTTranCreate H[%s] A[%s]", hexp, asciip);
- free(hexp);
- }
+ {
+ char *hexp, *asciip;
+ asciip = (lastNamep? lastNamep : realPathp);
+ hexp = osi_HexifyString( asciip );
+ DEBUG_EVENT2("AFS", "NTTranCreate H[%s] A[%s]", hexp, asciip);
+ free(hexp);
+ }
#endif
- userp = smb_GetUser(vcp, inp);
- if(!userp) {
- osi_Log1(afsd_logp, "NTTranCreate invalid user [%d]", ((smb_t *) inp)->uid);
- free(realPathp);
- return CM_ERROR_INVAL;
- }
+ userp = smb_GetUser(vcp, inp);
+ if (!userp) {
+ osi_Log1(smb_logp, "NTTranCreate invalid user [%d]", ((smb_t *) inp)->uid);
+ free(realPathp);
+ return CM_ERROR_INVAL;
+ }
- if (baseFid == 0) {
- baseDirp = cm_rootSCachep;
- tidPathp = smb_GetTIDPath(vcp, ((smb_t *)inp)->tid);
- }
- else {
- baseFidp = smb_FindFID(vcp, baseFid, 0);
- if(!baseFidp) {
- osi_Log1(afsd_logp, "NTTranCreate Invalid fid [%d]", baseFid);
- free(realPathp);
- cm_ReleaseUser(userp);
- return CM_ERROR_INVAL;
- }
- baseDirp = baseFidp->scp;
- tidPathp = NULL;
- }
+ if (baseFid == 0) {
+ baseDirp = cm_data.rootSCachep;
+ code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
+ if (code == CM_ERROR_TIDIPC) {
+ /* Attempt to use a TID allocated for IPC. The client
+ * is probably looking for DCE RPC end points which we
+ * don't support OR it could be looking to make a DFS
+ * referral request.
+ */
+ osi_Log0(smb_logp, "NTTranCreate received IPC TID");
+#ifndef DFS_SUPPORT
+ free(realPathp);
+ cm_ReleaseUser(userp);
+ return CM_ERROR_NOSUCHPATH;
+#endif
+ }
+ } else {
+ baseFidp = smb_FindFID(vcp, baseFid, 0);
+ if (!baseFidp) {
+ osi_Log1(smb_logp, "NTTranCreate Invalid fid [%d]", baseFid);
+ free(realPathp);
+ cm_ReleaseUser(userp);
+ return CM_ERROR_INVAL;
+ }
+ baseDirp = baseFidp->scp;
+ tidPathp = NULL;
+ }
- /* compute open mode */
- fidflags = 0;
- if (desiredAccess & DELETE)
- fidflags |= SMB_FID_OPENDELETE;
- if (desiredAccess & AFS_ACCESS_READ)
- fidflags |= SMB_FID_OPENREAD;
- if (desiredAccess & AFS_ACCESS_WRITE)
- fidflags |= SMB_FID_OPENWRITE;
-
- dscp = NULL;
- code = 0;
- code = cm_NameI(baseDirp, realPathp, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
- userp, tidPathp, &req, &scp);
- if (code == 0) foundscp = TRUE;
- if (code != 0
- || (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE))) {
- /* look up parent directory */
- code = cm_NameI(baseDirp, spacep->data,
- CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
- userp, tidPathp, &req, &dscp);
- cm_FreeSpace(spacep);
-
- if (baseFid != 0) {
- smb_ReleaseFID(baseFidp);
- baseFidp = 0;
+ /* compute open mode */
+ fidflags = 0;
+ if (desiredAccess & DELETE)
+ fidflags |= SMB_FID_OPENDELETE;
+ if (desiredAccess & AFS_ACCESS_READ)
+ fidflags |= SMB_FID_OPENREAD;
+ if (desiredAccess & AFS_ACCESS_WRITE)
+ fidflags |= SMB_FID_OPENWRITE;
+ if (createOptions & FILE_DELETE_ON_CLOSE)
+ fidflags |= SMB_FID_DELONCLOSE;
+
+ /* And the share mode */
+ if (shareAccess & FILE_SHARE_READ)
+ fidflags |= SMB_FID_SHARE_READ;
+ if (shareAccess & FILE_SHARE_WRITE)
+ fidflags |= SMB_FID_SHARE_WRITE;
+
+ dscp = NULL;
+ code = 0;
+ if ( createDisp == FILE_OPEN ||
+ createDisp == FILE_OVERWRITE ||
+ createDisp == FILE_OVERWRITE_IF) {
+ code = cm_NameI(baseDirp, spacep->data, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
+ userp, tidPathp, &req, &dscp);
+ if (code == 0) {
+#ifdef DFS_SUPPORT
+ if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
+ cm_ReleaseSCache(dscp);
+ cm_ReleaseUser(userp);
+ free(realPathp);
+ if ( WANTS_DFS_PATHNAMES(inp) )
+ return CM_ERROR_PATH_NOT_COVERED;
+ else
+ return CM_ERROR_BADSHARENAME;
+ }
+#endif /* DFS_SUPPORT */
+ code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp, CM_FLAG_FOLLOW,
+ userp, &req, &scp);
+ if (code == CM_ERROR_NOSUCHFILE) {
+ code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp,
+ CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, &req, &scp);
+ if (code == 0 && realDirFlag == 1) {
+ cm_ReleaseSCache(scp);
+ cm_ReleaseSCache(dscp);
+ cm_ReleaseUser(userp);
+ free(realPathp);
+ return CM_ERROR_EXISTS;
+ }
+ }
+ } else
+ dscp = NULL;
+ } else {
+ code = cm_NameI(baseDirp, realPathp, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
+ userp, tidPathp, &req, &scp);
+#ifdef DFS_SUPPORT
+ if (code == 0 && scp->fileType == CM_SCACHETYPE_DFSLINK) {
+ cm_ReleaseSCache(scp);
+ cm_ReleaseUser(userp);
+ free(realPathp);
+ if ( WANTS_DFS_PATHNAMES(inp) )
+ return CM_ERROR_PATH_NOT_COVERED;
+ else
+ return CM_ERROR_BADSHARENAME;
}
+#endif /* DFS_SUPPORT */
+ }
- if (code) {
- cm_ReleaseUser(userp);
- free(realPathp);
- return code;
- }
+ if (code == 0)
+ foundscp = TRUE;
+
+ if (code != 0 || (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE))) {
+ /* look up parent directory */
+ if ( !dscp ) {
+ code = cm_NameI(baseDirp, spacep->data,
+ CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
+ userp, tidPathp, &req, &dscp);
+#ifdef DFS_SUPPORT
+ if (code == 0 && dscp->fileType == CM_SCACHETYPE_DFSLINK) {
+ cm_ReleaseSCache(dscp);
+ cm_ReleaseUser(userp);
+ free(realPathp);
+ if ( WANTS_DFS_PATHNAMES(inp) )
+ return CM_ERROR_PATH_NOT_COVERED;
+ else
+ return CM_ERROR_BADSHARENAME;
+ }
+#endif /* DFS_SUPPORT */
+ } else
+ code = 0;
+
+ cm_FreeSpace(spacep);
- if (!lastNamep) lastNamep = realPathp;
- else lastNamep++;
+ if (baseFid != 0) {
+ smb_ReleaseFID(baseFidp);
+ baseFidp = 0;
+ }
- if (!smb_IsLegalFilename(lastNamep))
- return CM_ERROR_BADNTFILENAME;
+ if (code) {
+ cm_ReleaseUser(userp);
+ free(realPathp);
+ return code;
+ }
- if (!foundscp) {
- code = cm_Lookup(dscp, lastNamep,
- CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
- userp, &req, &scp);
- if (code && code != CM_ERROR_NOSUCHFILE) {
- cm_ReleaseSCache(dscp);
- cm_ReleaseUser(userp);
- free(realPathp);
- return code;
- }
- }
- }
- else {
- if (baseFid != 0) {
+ if (!lastNamep) lastNamep = realPathp;
+ else lastNamep++;
+
+ if (!smb_IsLegalFilename(lastNamep))
+ return CM_ERROR_BADNTFILENAME;
+
+ if (!foundscp) {
+ if (createDisp == FILE_CREATE || createDisp == FILE_OVERWRITE_IF) {
+ code = cm_Lookup(dscp, lastNamep,
+ CM_FLAG_FOLLOW, userp, &req, &scp);
+ } else {
+ code = cm_Lookup(dscp, lastNamep,
+ CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
+ userp, &req, &scp);
+ }
+ if (code && code != CM_ERROR_NOSUCHFILE) {
+ cm_ReleaseSCache(dscp);
+ cm_ReleaseUser(userp);
+ free(realPathp);
+ return code;
+ }
+ }
+ } else {
+ if (baseFid != 0) {
smb_ReleaseFID(baseFidp);
baseFidp = 0;
}
- cm_FreeSpace(spacep);
- }
-
- /* if we get here, if code is 0, the file exists and is represented by
- * scp. Otherwise, we have to create it. The dir may be represented
- * by dscp, or we may have found the file directly. If code is non-zero,
- * scp is NULL.
- */
- if (code == 0) {
- code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp,
- &req);
- if (code) {
- if (dscp) cm_ReleaseSCache(dscp);
- cm_ReleaseSCache(scp);
- cm_ReleaseUser(userp);
- free(realPathp);
- return code;
- }
-
- if (createDisp == 2) {
- /* oops, file shouldn't be there */
- if (dscp) cm_ReleaseSCache(dscp);
- cm_ReleaseSCache(scp);
- cm_ReleaseUser(userp);
- free(realPathp);
- return CM_ERROR_EXISTS;
- }
-
- if (createDisp == 4
- || createDisp == 5) {
- setAttr.mask = CM_ATTRMASK_LENGTH;
- setAttr.length.LowPart = 0;
- setAttr.length.HighPart = 0;
- code = cm_SetAttr(scp, &setAttr, userp, &req);
- openAction = 3; /* truncated existing file */
- }
- else openAction = 1; /* found existing file */
- }
- else if (createDisp == 1 || createDisp == 4) {
- /* don't create if not found */
- if (dscp) cm_ReleaseSCache(dscp);
- cm_ReleaseUser(userp);
- free(realPathp);
- return CM_ERROR_NOSUCHFILE;
- }
- else if (realDirFlag == 0 || realDirFlag == -1) {
- osi_assert(dscp != NULL);
- osi_Log1(afsd_logp, "smb_ReceiveNTTranCreate creating file %s",
- osi_LogSaveString(afsd_logp, lastNamep));
- openAction = 2; /* created file */
- setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
- setAttr.clientModTime = time(NULL);
- code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
- &req);
- if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
- smb_NotifyChange(FILE_ACTION_ADDED,
- FILE_NOTIFY_CHANGE_FILE_NAME,
- dscp, lastNamep, NULL, TRUE);
- if (code == CM_ERROR_EXISTS && createDisp != 2) {
- /* Not an exclusive create, and someone else tried
- * creating it already, then we open it anyway. We
- * don't bother retrying after this, since if this next
- * fails, that means that the file was deleted after we
- * started this call.
- */
- code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
- userp, &req, &scp);
- if (code == 0) {
- if (createDisp == 5) {
- setAttr.mask = CM_ATTRMASK_LENGTH;
- setAttr.length.LowPart = 0;
- setAttr.length.HighPart = 0;
- code = cm_SetAttr(scp, &setAttr, userp,
- &req);
- }
- } /* lookup succeeded */
- }
- }
- else {
- /* create directory */
- osi_assert(dscp != NULL);
- osi_Log1(afsd_logp,
- "smb_ReceiveNTTranCreate creating directory %s",
- osi_LogSaveString(afsd_logp, lastNamep));
- openAction = 2; /* created directory */
- setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
- setAttr.clientModTime = time(NULL);
- code = cm_MakeDir(dscp, lastNamep, 0, &setAttr, userp, &req);
- if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
- smb_NotifyChange(FILE_ACTION_ADDED,
- FILE_NOTIFY_CHANGE_DIR_NAME,
- dscp, lastNamep, NULL, TRUE);
- if (code == 0
- || (code == CM_ERROR_EXISTS && createDisp != 2)) {
- /* Not an exclusive create, and someone else tried
- * creating it already, then we open it anyway. We
- * don't bother retrying after this, since if this next
- * fails, that means that the file was deleted after we
- * started this call.
- */
- code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
- userp, &req, &scp);
- }
- }
+ cm_FreeSpace(spacep);
+ }
- if (code) {
- /* something went wrong creating or truncating the file */
- if (scp) cm_ReleaseSCache(scp);
- cm_ReleaseUser(userp);
- free(realPathp);
- return code;
- }
+ /* if we get here, if code is 0, the file exists and is represented by
+ * scp. Otherwise, we have to create it. The dir may be represented
+ * by dscp, or we may have found the file directly. If code is non-zero,
+ * scp is NULL.
+ */
+ if (code == 0) {
+ code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp,
+ &req);
+ if (code) {
+ if (dscp)
+ cm_ReleaseSCache(dscp);
+ cm_ReleaseSCache(scp);
+ cm_ReleaseUser(userp);
+ free(realPathp);
+ return code;
+ }
- /* make sure we have file vs. dir right */
- if (realDirFlag == 0 && scp->fileType != CM_SCACHETYPE_FILE) {
- cm_ReleaseSCache(scp);
- cm_ReleaseUser(userp);
- free(realPathp);
- return CM_ERROR_ISDIR;
- }
- if (realDirFlag == 1 && scp->fileType == CM_SCACHETYPE_FILE) {
- cm_ReleaseSCache(scp);
- cm_ReleaseUser(userp);
- free(realPathp);
- return CM_ERROR_NOTDIR;
- }
+ if (createDisp == FILE_CREATE) {
+ /* oops, file shouldn't be there */
+ if (dscp)
+ cm_ReleaseSCache(dscp);
+ cm_ReleaseSCache(scp);
+ cm_ReleaseUser(userp);
+ free(realPathp);
+ return CM_ERROR_EXISTS;
+ }
- /* open the file itself */
- fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
- osi_assert(fidp);
+ if (createDisp == FILE_OVERWRITE ||
+ createDisp == FILE_OVERWRITE_IF) {
+ setAttr.mask = CM_ATTRMASK_LENGTH;
+ setAttr.length.LowPart = 0;
+ setAttr.length.HighPart = 0;
+
+ /* now watch for a symlink */
+ code = 0;
+ while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
+ targetScp = 0;
+ code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
+ if (code == 0) {
+ /* we have a more accurate file to use (the
+ * target of the symbolic link). Otherwise,
+ * we'll just use the symlink anyway.
+ */
+ osi_Log2(smb_logp, "symlink vp %x to vp %x",
+ scp, targetScp);
+ cm_ReleaseSCache(scp);
+ scp = targetScp;
+ }
+ }
+ code = cm_SetAttr(scp, &setAttr, userp, &req);
+ openAction = 3; /* truncated existing file */
+ }
+ else openAction = 1; /* found existing file */
+ }
+ else if (createDisp == FILE_OPEN || createDisp == FILE_OVERWRITE) {
+ /* don't create if not found */
+ if (dscp)
+ cm_ReleaseSCache(dscp);
+ cm_ReleaseUser(userp);
+ free(realPathp);
+ return CM_ERROR_NOSUCHFILE;
+ }
+ else if (realDirFlag == 0 || realDirFlag == -1) {
+ osi_assert(dscp != NULL);
+ osi_Log1(smb_logp, "smb_ReceiveNTTranCreate creating file %s",
+ osi_LogSaveString(smb_logp, lastNamep));
+ openAction = 2; /* created file */
+ setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
+ setAttr.clientModTime = time(NULL);
+ code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
+ &req);
+ if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
+ smb_NotifyChange(FILE_ACTION_ADDED,
+ FILE_NOTIFY_CHANGE_FILE_NAME,
+ dscp, lastNamep, NULL, TRUE);
+ if (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE) {
+ /* Not an exclusive create, and someone else tried
+ * creating it already, then we open it anyway. We
+ * don't bother retrying after this, since if this next
+ * fails, that means that the file was deleted after we
+ * started this call.
+ */
+ code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
+ userp, &req, &scp);
+ if (code == 0) {
+ if (createDisp == FILE_OVERWRITE_IF) {
+ setAttr.mask = CM_ATTRMASK_LENGTH;
+ setAttr.length.LowPart = 0;
+ setAttr.length.HighPart = 0;
+
+ /* now watch for a symlink */
+ code = 0;
+ while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
+ targetScp = 0;
+ code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
+ if (code == 0) {
+ /* we have a more accurate file to use (the
+ * target of the symbolic link). Otherwise,
+ * we'll just use the symlink anyway.
+ */
+ osi_Log2(smb_logp, "symlink vp %x to vp %x",
+ scp, targetScp);
+ cm_ReleaseSCache(scp);
+ scp = targetScp;
+ }
+ }
+ code = cm_SetAttr(scp, &setAttr, userp, &req);
+ }
+ } /* lookup succeeded */
+ }
+ } else {
+ /* create directory */
+ osi_assert(dscp != NULL);
+ osi_Log1(smb_logp,
+ "smb_ReceiveNTTranCreate creating directory %s",
+ osi_LogSaveString(smb_logp, lastNamep));
+ openAction = 2; /* created directory */
+ setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
+ setAttr.clientModTime = time(NULL);
+ code = cm_MakeDir(dscp, lastNamep, 0, &setAttr, userp, &req);
+ if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
+ smb_NotifyChange(FILE_ACTION_ADDED,
+ FILE_NOTIFY_CHANGE_DIR_NAME,
+ dscp, lastNamep, NULL, TRUE);
+ if (code == 0 ||
+ (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE)) {
+ /* Not an exclusive create, and someone else tried
+ * creating it already, then we open it anyway. We
+ * don't bother retrying after this, since if this next
+ * fails, that means that the file was deleted after we
+ * started this call.
+ */
+ code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
+ userp, &req, &scp);
+ }
+ }
- /* save a pointer to the vnode */
- fidp->scp = scp;
+ if (code) {
+ /* something went wrong creating or truncating the file */
+ if (scp)
+ cm_ReleaseSCache(scp);
+ cm_ReleaseUser(userp);
+ free(realPathp);
+ return code;
+ }
- fidp->flags = fidflags;
+ /* make sure we have file vs. dir right */
+ if (realDirFlag == 0 && scp->fileType != CM_SCACHETYPE_FILE) {
+ /* now watch for a symlink */
+ code = 0;
+ while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
+ targetScp = 0;
+ code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
+ if (code == 0) {
+ /* we have a more accurate file to use (the
+ * target of the symbolic link). Otherwise,
+ * we'll just use the symlink anyway.
+ */
+ osi_Log2(smb_logp, "symlink vp %x to vp %x",
+ scp, targetScp);
+ cm_ReleaseSCache(scp);
+ scp = targetScp;
+ }
+ }
- /* save parent dir and pathname for deletion or change notification */
- if (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE)) {
- fidp->flags |= SMB_FID_NTOPEN;
- fidp->NTopen_dscp = dscp;
- cm_HoldSCache(dscp);
- fidp->NTopen_pathp = strdup(lastNamep);
+ if (scp->fileType != CM_SCACHETYPE_FILE) {
+ cm_ReleaseSCache(scp);
+ cm_ReleaseUser(userp);
+ free(realPathp);
+ return CM_ERROR_ISDIR;
}
- fidp->NTopen_wholepathp = realPathp;
-
- /* we don't need this any longer */
- if (dscp) cm_ReleaseSCache(dscp);
-
- cm_Open(scp, 0, userp);
-
- /* set inp->fid so that later read calls in same msg can find fid */
- inp->fid = fidp->fid;
-
- /* check whether we are required to send and extended response */
- if(!extendedRespRequired) {
- /* out parms */
- parmOffset = 8*4 + 39;
- parmOffset += 1; /* pad to 4 */
- dataOffset = parmOffset + 70;
-
- parmSlot = 1;
- outp->oddByte = 1;
- /* Total Parameter Count */
- smb_SetSMBParmLong(outp, parmSlot, 70); parmSlot += 2;
- /* Total Data Count */
- smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
- /* Parameter Count */
- smb_SetSMBParmLong(outp, parmSlot, 70); parmSlot += 2;
- /* Parameter Offset */
- smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
- /* Parameter Displacement */
- smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
- /* Data Count */
- smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
- /* Data Offset */
- smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
- /* Data Displacement */
- smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
- smb_SetSMBParmByte(outp, parmSlot, 0); /* Setup Count */
- smb_SetSMBDataLength(outp, 70);
-
- lock_ObtainMutex(&scp->mx);
- outData = smb_GetSMBData(outp, NULL);
- outData++; /* round to get to parmOffset */
- *outData = 0; outData++; /* oplock */
- *outData = 0; outData++; /* reserved */
- *((USHORT *)outData) = fidp->fid; outData += 2; /* fid */
- *((ULONG *)outData) = openAction; outData += 4;
- *((ULONG *)outData) = 0; outData += 4; /* EA error offset */
- smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
- *((FILETIME *)outData) = ft; outData += 8; /* creation time */
- *((FILETIME *)outData) = ft; outData += 8; /* last access time */
- *((FILETIME *)outData) = ft; outData += 8; /* last write time */
- *((FILETIME *)outData) = ft; outData += 8; /* change time */
- *((ULONG *)outData) = smb_ExtAttributes(scp); outData += 4;
- *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* alloc sz */
- *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* EOF */
- *((USHORT *)outData) = 0; outData += 2; /* filetype */
- *((USHORT *)outData) = 0; outData += 2; /* dev state */
- *((USHORT *)outData) = (scp->fileType == CM_SCACHETYPE_DIRECTORY);
- outData += 2; /* is a dir? */
- lock_ReleaseMutex(&scp->mx);
-
- } else { /* extended response required */
-
- /* out parms */
- parmOffset = 8*4 + 39;
- parmOffset += 1; /* pad to 4 */
- dataOffset = parmOffset + 104;
-
- parmSlot = 1;
- outp->oddByte = 1;
- /* Total Parameter Count */
- smb_SetSMBParmLong(outp, parmSlot, 101); parmSlot += 2;
- /* Total Data Count */
- smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
- /* Parameter Count */
- smb_SetSMBParmLong(outp, parmSlot, 101); parmSlot += 2;
- /* Parameter Offset */
- smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
- /* Parameter Displacement */
- smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
- /* Data Count */
- smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
- /* Data Offset */
- smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
- /* Data Displacement */
- smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
- smb_SetSMBParmByte(outp, parmSlot, 0); /* Setup Count */
- smb_SetSMBDataLength(outp, 105);
-
- lock_ObtainMutex(&scp->mx);
- outData = smb_GetSMBData(outp, NULL);
- outData++; /* round to get to parmOffset */
- *outData = 0; outData++; /* oplock */
- *outData = 1; outData++; /* response type */
- *((USHORT *)outData) = fidp->fid; outData += 2; /* fid */
- *((ULONG *)outData) = openAction; outData += 4;
- *((ULONG *)outData) = 0; outData += 4; /* EA error offset */
- smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
- *((FILETIME *)outData) = ft; outData += 8; /* creation time */
- *((FILETIME *)outData) = ft; outData += 8; /* last access time */
- *((FILETIME *)outData) = ft; outData += 8; /* last write time */
- *((FILETIME *)outData) = ft; outData += 8; /* change time */
- *((ULONG *)outData) = smb_ExtAttributes(scp); outData += 4;
- *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* alloc sz */
- *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* EOF */
- *((USHORT *)outData) = 0; outData += 2; /* filetype */
- *((USHORT *)outData) = 0; outData += 2; /* dev state */
- *((USHORT *)outData) = (scp->fileType == CM_SCACHETYPE_DIRECTORY);
- outData += 1; /* is a dir? */
- memset(outData,0,24); outData += 24; /* Volume ID and file ID */
- *((ULONG *)outData) = 0x001f01ffL; outData += 4; /* Maxmimal access rights */
- *((ULONG *)outData) = 0; outData += 4; /* Guest Access rights */
- lock_ReleaseMutex(&scp->mx);
- }
+ }
- osi_Log1(afsd_logp, "SMB NTTranCreate opening fid %d", fidp->fid);
+ if (realDirFlag == 1 && scp->fileType == CM_SCACHETYPE_FILE) {
+ cm_ReleaseSCache(scp);
+ cm_ReleaseUser(userp);
+ free(realPathp);
+ return CM_ERROR_NOTDIR;
+ }
- smb_ReleaseFID(fidp);
+ /* open the file itself */
+ fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
+ osi_assert(fidp);
+
+ /* save a reference to the user */
+ cm_HoldUser(userp);
+ fidp->userp = userp;
+
+ /* If we are restricting sharing, we should do so with a suitable
+ share lock. */
+ if (scp->fileType == CM_SCACHETYPE_FILE &&
+ !(fidflags & SMB_FID_SHARE_WRITE)) {
+ cm_key_t key;
+ LARGE_INTEGER LOffset, LLength;
+ int sLockType;
+
+ LOffset.HighPart = SMB_FID_QLOCK_HIGH;
+ LOffset.LowPart = SMB_FID_QLOCK_LOW;
+ LLength.HighPart = 0;
+ LLength.LowPart = SMB_FID_QLOCK_LENGTH;
+
+ if (fidflags & SMB_FID_SHARE_READ) {
+ sLockType = LOCKING_ANDX_SHARED_LOCK;
+ } else {
+ sLockType = 0;
+ }
- cm_ReleaseUser(userp);
+ key = cm_GenerateKey(vcp->vcID, SMB_FID_QLOCK_PID, fidp->fid);
+
+ lock_ObtainMutex(&scp->mx);
+ code = cm_Lock(scp, sLockType, LOffset, LLength, key, 0, userp, &req, NULL);
+ lock_ReleaseMutex(&scp->mx);
- /* free(realPathp); Can't free realPathp here because fidp->NTopen_wholepathp points there */
+ if (code) {
+ fidp->flags = SMB_FID_DELETE;
+ smb_ReleaseFID(fidp);
+
+ cm_ReleaseSCache(scp);
+ cm_ReleaseUser(userp);
+ free(realPathp);
+
+ return CM_ERROR_SHARING_VIOLATION;
+ }
+ }
- /* leave scp held since we put it in fidp->scp */
- return 0;
-}
+ /* save a pointer to the vnode */
+ fidp->scp = scp;
-long smb_ReceiveNTTranNotifyChange(smb_vc_t *vcp, smb_packet_t *inp,
- smb_packet_t *outp)
-{
- smb_packet_t *savedPacketp;
- ULONG filter; USHORT fid, watchtree;
- smb_fid_t *fidp;
- cm_scache_t *scp;
+ fidp->flags = fidflags;
- filter = smb_GetSMBParm(inp, 19)
- | (smb_GetSMBParm(inp, 20) << 16);
- fid = smb_GetSMBParm(inp, 21);
- watchtree = smb_GetSMBParm(inp, 22) && 0xffff; /* TODO: should this be 0xff ? */
+ /* save parent dir and pathname for deletion or change notification */
+ if (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE)) {
+ fidp->flags |= SMB_FID_NTOPEN;
+ fidp->NTopen_dscp = dscp;
+ cm_HoldSCache(dscp);
+ fidp->NTopen_pathp = strdup(lastNamep);
+ }
+ fidp->NTopen_wholepathp = realPathp;
+
+ /* we don't need this any longer */
+ if (dscp)
+ cm_ReleaseSCache(dscp);
+
+ cm_Open(scp, 0, userp);
+
+ /* set inp->fid so that later read calls in same msg can find fid */
+ inp->fid = fidp->fid;
+
+ /* check whether we are required to send an extended response */
+ if (!extendedRespRequired) {
+ /* out parms */
+ parmOffset = 8*4 + 39;
+ parmOffset += 1; /* pad to 4 */
+ dataOffset = parmOffset + 70;
+
+ parmSlot = 1;
+ outp->oddByte = 1;
+ /* Total Parameter Count */
+ smb_SetSMBParmLong(outp, parmSlot, 70); parmSlot += 2;
+ /* Total Data Count */
+ smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
+ /* Parameter Count */
+ smb_SetSMBParmLong(outp, parmSlot, 70); parmSlot += 2;
+ /* Parameter Offset */
+ smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
+ /* Parameter Displacement */
+ smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
+ /* Data Count */
+ smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
+ /* Data Offset */
+ smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
+ /* Data Displacement */
+ smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
+ smb_SetSMBParmByte(outp, parmSlot, 0); /* Setup Count */
+ smb_SetSMBDataLength(outp, 70);
- fidp = smb_FindFID(vcp, fid, 0);
+ lock_ObtainMutex(&scp->mx);
+ outData = smb_GetSMBData(outp, NULL);
+ outData++; /* round to get to parmOffset */
+ *outData = 0; outData++; /* oplock */
+ *outData = 0; outData++; /* reserved */
+ *((USHORT *)outData) = fidp->fid; outData += 2; /* fid */
+ *((ULONG *)outData) = openAction; outData += 4;
+ *((ULONG *)outData) = 0; outData += 4; /* EA error offset */
+ smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
+ *((FILETIME *)outData) = ft; outData += 8; /* creation time */
+ *((FILETIME *)outData) = ft; outData += 8; /* last access time */
+ *((FILETIME *)outData) = ft; outData += 8; /* last write time */
+ *((FILETIME *)outData) = ft; outData += 8; /* change time */
+ *((ULONG *)outData) = smb_ExtAttributes(scp); outData += 4;
+ *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* alloc sz */
+ *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* EOF */
+ *((USHORT *)outData) = 0; outData += 2; /* filetype */
+ *((USHORT *)outData) = 0; outData += 2; /* dev state */
+ *((USHORT *)outData) = (scp->fileType == CM_SCACHETYPE_DIRECTORY);
+ outData += 2; /* is a dir? */
+ lock_ReleaseMutex(&scp->mx);
+ } else {
+ /* out parms */
+ parmOffset = 8*4 + 39;
+ parmOffset += 1; /* pad to 4 */
+ dataOffset = parmOffset + 104;
+
+ parmSlot = 1;
+ outp->oddByte = 1;
+ /* Total Parameter Count */
+ smb_SetSMBParmLong(outp, parmSlot, 101); parmSlot += 2;
+ /* Total Data Count */
+ smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
+ /* Parameter Count */
+ smb_SetSMBParmLong(outp, parmSlot, 101); parmSlot += 2;
+ /* Parameter Offset */
+ smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
+ /* Parameter Displacement */
+ smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
+ /* Data Count */
+ smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
+ /* Data Offset */
+ smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
+ /* Data Displacement */
+ smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
+ smb_SetSMBParmByte(outp, parmSlot, 0); /* Setup Count */
+ smb_SetSMBDataLength(outp, 105);
+
+ lock_ObtainMutex(&scp->mx);
+ outData = smb_GetSMBData(outp, NULL);
+ outData++; /* round to get to parmOffset */
+ *outData = 0; outData++; /* oplock */
+ *outData = 1; outData++; /* response type */
+ *((USHORT *)outData) = fidp->fid; outData += 2; /* fid */
+ *((ULONG *)outData) = openAction; outData += 4;
+ *((ULONG *)outData) = 0; outData += 4; /* EA error offset */
+ smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
+ *((FILETIME *)outData) = ft; outData += 8; /* creation time */
+ *((FILETIME *)outData) = ft; outData += 8; /* last access time */
+ *((FILETIME *)outData) = ft; outData += 8; /* last write time */
+ *((FILETIME *)outData) = ft; outData += 8; /* change time */
+ *((ULONG *)outData) = smb_ExtAttributes(scp); outData += 4;
+ *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* alloc sz */
+ *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* EOF */
+ *((USHORT *)outData) = 0; outData += 2; /* filetype */
+ *((USHORT *)outData) = 0; outData += 2; /* dev state */
+ *((USHORT *)outData) = (scp->fileType == CM_SCACHETYPE_DIRECTORY);
+ outData += 1; /* is a dir? */
+ memset(outData,0,24); outData += 24; /* Volume ID and file ID */
+ *((ULONG *)outData) = 0x001f01ffL; outData += 4; /* Maxmimal access rights */
+ *((ULONG *)outData) = 0; outData += 4; /* Guest Access rights */
+ lock_ReleaseMutex(&scp->mx);
+ }
- if(!fidp) {
- osi_Log1(afsd_logp, "ERROR: NotifyChange given invalid fid [%d]", fid);
- return CM_ERROR_BADFD;
- }
+ osi_Log1(smb_logp, "SMB NTTranCreate opening fid %d", fidp->fid);
- savedPacketp = smb_CopyPacket(inp);
- savedPacketp->vcp = vcp; /* TODO: refcount vcp? */
- lock_ObtainMutex(&smb_Dir_Watch_Lock);
- savedPacketp->nextp = smb_Directory_Watches;
- smb_Directory_Watches = savedPacketp;
- lock_ReleaseMutex(&smb_Dir_Watch_Lock);
+ smb_ReleaseFID(fidp);
- osi_Log4(afsd_logp, "Request for NotifyChange filter 0x%x fid %d wtree %d file %s",
- filter, fid, watchtree, osi_LogSaveString(afsd_logp, fidp->NTopen_wholepathp));
+ cm_ReleaseUser(userp);
- scp = fidp->scp;
- lock_ObtainMutex(&scp->mx);
- if (watchtree)
- scp->flags |= CM_SCACHEFLAG_WATCHEDSUBTREE;
- else
- scp->flags |= CM_SCACHEFLAG_WATCHED;
- lock_ReleaseMutex(&scp->mx);
- smb_ReleaseFID(fidp);
+ /* free(realPathp); Can't free realPathp here because fidp->NTopen_wholepathp points there */
+ /* leave scp held since we put it in fidp->scp */
+ return 0;
+}
- outp->flags |= SMB_PACKETFLAG_NOSEND;
+long smb_ReceiveNTTranNotifyChange(smb_vc_t *vcp, smb_packet_t *inp,
+ smb_packet_t *outp)
+{
+ smb_packet_t *savedPacketp;
+ ULONG filter; USHORT fid, watchtree;
+ smb_fid_t *fidp;
+ cm_scache_t *scp;
+
+ filter = smb_GetSMBParm(inp, 19) |
+ (smb_GetSMBParm(inp, 20) << 16);
+ fid = smb_GetSMBParm(inp, 21);
+ watchtree = smb_GetSMBParm(inp, 22) && 0xffff; /* TODO: should this be 0xff ? */
+
+ fidp = smb_FindFID(vcp, fid, 0);
+ if (!fidp) {
+ osi_Log1(smb_logp, "ERROR: NotifyChange given invalid fid [%d]", fid);
+ return CM_ERROR_BADFD;
+ }
- return 0;
+ savedPacketp = smb_CopyPacket(inp);
+ smb_HoldVC(vcp);
+ if (savedPacketp->vcp)
+ smb_ReleaseVC(savedPacketp->vcp);
+ savedPacketp->vcp = vcp;
+ lock_ObtainMutex(&smb_Dir_Watch_Lock);
+ savedPacketp->nextp = smb_Directory_Watches;
+ smb_Directory_Watches = savedPacketp;
+ lock_ReleaseMutex(&smb_Dir_Watch_Lock);
+
+ osi_Log4(smb_logp, "Request for NotifyChange filter 0x%x fid %d wtree %d file %s",
+ filter, fid, watchtree, osi_LogSaveString(smb_logp, fidp->NTopen_wholepathp));
+
+ scp = fidp->scp;
+ lock_ObtainMutex(&scp->mx);
+ if (watchtree)
+ scp->flags |= CM_SCACHEFLAG_WATCHEDSUBTREE;
+ else
+ scp->flags |= CM_SCACHEFLAG_WATCHED;
+ lock_ReleaseMutex(&scp->mx);
+ smb_ReleaseFID(fidp);
+
+ outp->flags |= SMB_PACKETFLAG_NOSEND;
+ return 0;
}
unsigned char nullSecurityDesc[36] = {
- 0x01, /* security descriptor revision */
- 0x00, /* reserved, should be zero */
- 0x00, 0x80, /* security descriptor control;
- * 0x8000 : self-relative format */
- 0x14, 0x00, 0x00, 0x00, /* offset of owner SID */
- 0x1c, 0x00, 0x00, 0x00, /* offset of group SID */
- 0x00, 0x00, 0x00, 0x00, /* offset of DACL would go here */
- 0x00, 0x00, 0x00, 0x00, /* offset of SACL would go here */
- 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- /* "null SID" owner SID */
- 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
- /* "null SID" group SID */
-};
+ 0x01, /* security descriptor revision */
+ 0x00, /* reserved, should be zero */
+ 0x00, 0x80, /* security descriptor control;
+ * 0x8000 : self-relative format */
+ 0x14, 0x00, 0x00, 0x00, /* offset of owner SID */
+ 0x1c, 0x00, 0x00, 0x00, /* offset of group SID */
+ 0x00, 0x00, 0x00, 0x00, /* offset of DACL would go here */
+ 0x00, 0x00, 0x00, 0x00, /* offset of SACL would go here */
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ /* "null SID" owner SID */
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+ /* "null SID" group SID */
+};
long smb_ReceiveNTTranQuerySecurityDesc(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
{
- int parmOffset, parmCount, dataOffset, dataCount;
- int parmSlot;
- int maxData;
- char *outData;
- char *parmp;
- USHORT *sparmp;
- ULONG *lparmp;
- USHORT fid;
- ULONG securityInformation;
-
- parmOffset = smb_GetSMBOffsetParm(inp, 11, 1)
- | (smb_GetSMBOffsetParm(inp, 12, 1) << 16);
- parmp = inp->data + parmOffset;
- sparmp = (USHORT *) parmp;
- lparmp = (ULONG *) parmp;
-
- fid = sparmp[0];
- securityInformation = lparmp[1];
-
- maxData = smb_GetSMBOffsetParm(inp, 7, 1)
- | (smb_GetSMBOffsetParm(inp, 8, 1) << 16);
-
- if (maxData < 36)
- dataCount = 0;
- else
- dataCount = 36;
-
- /* out parms */
- parmOffset = 8*4 + 39;
- parmOffset += 1; /* pad to 4 */
- parmCount = 4;
- dataOffset = parmOffset + parmCount;
-
- parmSlot = 1;
- outp->oddByte = 1;
- /* Total Parameter Count */
- smb_SetSMBParmLong(outp, parmSlot, parmCount); parmSlot += 2;
- /* Total Data Count */
- smb_SetSMBParmLong(outp, parmSlot, dataCount); parmSlot += 2;
- /* Parameter Count */
- smb_SetSMBParmLong(outp, parmSlot, parmCount); parmSlot += 2;
- /* Parameter Offset */
- smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
- /* Parameter Displacement */
- smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
- /* Data Count */
- smb_SetSMBParmLong(outp, parmSlot, dataCount); parmSlot += 2;
- /* Data Offset */
- smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
- /* Data Displacement */
- smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
- smb_SetSMBParmByte(outp, parmSlot, 0); /* Setup Count */
- smb_SetSMBDataLength(outp, 1 + parmCount + dataCount);
-
- outData = smb_GetSMBData(outp, NULL);
- outData++; /* round to get to parmOffset */
- *((ULONG *)outData) = 36; outData += 4; /* length */
-
- if (maxData >= 36) {
- memcpy(outData, nullSecurityDesc, 36);
- outData += 36;
- return 0;
- } else
- return CM_ERROR_BUFFERTOOSMALL;
+ int parmOffset, parmCount, dataOffset, dataCount;
+ int parmSlot;
+ int maxData;
+ char *outData;
+ char *parmp;
+ USHORT *sparmp;
+ ULONG *lparmp;
+ USHORT fid;
+ ULONG securityInformation;
+
+ parmOffset = smb_GetSMBOffsetParm(inp, 11, 1)
+ | (smb_GetSMBOffsetParm(inp, 12, 1) << 16);
+ parmp = inp->data + parmOffset;
+ sparmp = (USHORT *) parmp;
+ lparmp = (ULONG *) parmp;
+
+ fid = sparmp[0];
+ securityInformation = lparmp[1];
+
+ maxData = smb_GetSMBOffsetParm(inp, 7, 1)
+ | (smb_GetSMBOffsetParm(inp, 8, 1) << 16);
+
+ if (maxData < 36)
+ dataCount = 0;
+ else
+ dataCount = 36;
+
+ /* out parms */
+ parmOffset = 8*4 + 39;
+ parmOffset += 1; /* pad to 4 */
+ parmCount = 4;
+ dataOffset = parmOffset + parmCount;
+
+ parmSlot = 1;
+ outp->oddByte = 1;
+ /* Total Parameter Count */
+ smb_SetSMBParmLong(outp, parmSlot, parmCount); parmSlot += 2;
+ /* Total Data Count */
+ smb_SetSMBParmLong(outp, parmSlot, dataCount); parmSlot += 2;
+ /* Parameter Count */
+ smb_SetSMBParmLong(outp, parmSlot, parmCount); parmSlot += 2;
+ /* Parameter Offset */
+ smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
+ /* Parameter Displacement */
+ smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
+ /* Data Count */
+ smb_SetSMBParmLong(outp, parmSlot, dataCount); parmSlot += 2;
+ /* Data Offset */
+ smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
+ /* Data Displacement */
+ smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
+ smb_SetSMBParmByte(outp, parmSlot, 0); /* Setup Count */
+ smb_SetSMBDataLength(outp, 1 + parmCount + dataCount);
+
+ outData = smb_GetSMBData(outp, NULL);
+ outData++; /* round to get to parmOffset */
+ *((ULONG *)outData) = 36; outData += 4; /* length */
+
+ if (maxData >= 36) {
+ memcpy(outData, nullSecurityDesc, 36);
+ outData += 36;
+ return 0;
+ } else
+ return CM_ERROR_BUFFERTOOSMALL;
}
long smb_ReceiveNTTransact(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
{
- unsigned short function;
+ unsigned short function;
- function = smb_GetSMBParm(inp, 18);
+ function = smb_GetSMBParm(inp, 18);
- osi_Log1(afsd_logp, "SMB NT Transact function %d", function);
+ osi_Log1(smb_logp, "SMB NT Transact function %d", function);
- /* We can handle long names */
- if (vcp->flags & SMB_VCFLAG_USENT)
- ((smb_t *)outp)->flg2 |= 0x40; /* IS_LONG_NAME */
+ /* We can handle long names */
+ if (vcp->flags & SMB_VCFLAG_USENT)
+ ((smb_t *)outp)->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
- switch (function) {
-
- case 6: return smb_ReceiveNTTranQuerySecurityDesc(vcp, inp, outp);
-
- case 4: return smb_ReceiveNTTranNotifyChange(vcp, inp, outp);
-
- case 1: return smb_ReceiveNTTranCreate(vcp, inp, outp);
-
- default: return CM_ERROR_INVAL;
- }
+ switch (function) {
+ case 1:
+ return smb_ReceiveNTTranCreate(vcp, inp, outp);
+ case 2:
+ osi_Log0(smb_logp, "SMB NT Transact Ioctl - not implemented");
+ break;
+ case 3:
+ osi_Log0(smb_logp, "SMB NT Transact SetSecurityDesc - not implemented");
+ break;
+ case 4:
+ return smb_ReceiveNTTranNotifyChange(vcp, inp, outp);
+ case 5:
+ osi_Log0(smb_logp, "SMB NT Transact Rename - not implemented");
+ break;
+ case 6:
+ return smb_ReceiveNTTranQuerySecurityDesc(vcp, inp, outp);
+ }
+ return CM_ERROR_INVAL;
}
/*
cm_scache_t *dscp, char *filename, char *otherFilename,
BOOL isDirectParent)
{
- smb_packet_t *watch, *lastWatch, *nextWatch;
- ULONG parmSlot, parmCount, parmOffset, dataOffset, nameLen;
- char *outData, *oldOutData;
- ULONG filter;
- USHORT fid, wtree;
- ULONG maxLen;
- BOOL twoEntries = FALSE;
- ULONG otherNameLen, oldParmCount = 0;
- DWORD otherAction;
- smb_vc_t *vcp;
- smb_fid_t *fidp;
-
- /* Get ready for rename within directory */
- if (action == FILE_ACTION_RENAMED_OLD_NAME && otherFilename != NULL) {
- twoEntries = TRUE;
- otherAction = FILE_ACTION_RENAMED_NEW_NAME;
- }
+ smb_packet_t *watch, *lastWatch, *nextWatch;
+ ULONG parmSlot, parmCount, parmOffset, dataOffset, nameLen;
+ char *outData, *oldOutData;
+ ULONG filter;
+ USHORT fid, wtree;
+ ULONG maxLen;
+ BOOL twoEntries = FALSE;
+ ULONG otherNameLen, oldParmCount = 0;
+ DWORD otherAction;
+ smb_fid_t *fidp;
+
+ /* Get ready for rename within directory */
+ if (action == FILE_ACTION_RENAMED_OLD_NAME && otherFilename != NULL) {
+ twoEntries = TRUE;
+ otherAction = FILE_ACTION_RENAMED_NEW_NAME;
+ }
- lock_ObtainMutex(&smb_Dir_Watch_Lock);
- watch = smb_Directory_Watches;
- while (watch) {
- filter = smb_GetSMBParm(watch, 19)
- | (smb_GetSMBParm(watch, 20) << 16);
- fid = smb_GetSMBParm(watch, 21);
- wtree = smb_GetSMBParm(watch, 22) & 0xffff; /* TODO: should this be 0xff ? */
- maxLen = smb_GetSMBOffsetParm(watch, 5, 1)
- | (smb_GetSMBOffsetParm(watch, 6, 1) << 16);
- vcp = watch->vcp;
-
- /*
- * Strange hack - bug in NT Client and NT Server that we
- * must emulate?
- */
- if (filter == 3 && wtree)
- filter = 0x17;
-
- fidp = smb_FindFID(vcp, fid, 0);
- if(!fidp) {
- lastWatch = watch;
- watch = watch->nextp;
- continue;
- }
- if (fidp->scp != dscp
- || (filter & notifyFilter) == 0
- || (!isDirectParent && !wtree)) {
- smb_ReleaseFID(fidp);
- lastWatch = watch;
- watch = watch->nextp;
- continue;
- }
- smb_ReleaseFID(fidp);
-
- osi_Log4(afsd_logp,
- "Sending Change Notification for fid %d filter 0x%x wtree %d file %s",
- fid, filter, wtree, osi_LogSaveString(afsd_logp, filename));
-
- nextWatch = watch->nextp;
- if (watch == smb_Directory_Watches)
- smb_Directory_Watches = nextWatch;
- else
- lastWatch->nextp = nextWatch;
-
- /* Turn off WATCHED flag in dscp */
- lock_ObtainMutex(&dscp->mx);
- if (wtree)
- dscp->flags &= ~CM_SCACHEFLAG_WATCHEDSUBTREE;
- else
- dscp->flags &= ~CM_SCACHEFLAG_WATCHED;
- lock_ReleaseMutex(&dscp->mx);
-
- /* Convert to response packet */
- ((smb_t *) watch)->reb = 0x80;
- ((smb_t *) watch)->wct = 0;
-
- /* out parms */
- if (filename == NULL)
- parmCount = 0;
- else {
- nameLen = strlen(filename);
- parmCount = 3*4 + nameLen*2;
- parmCount = (parmCount + 3) & ~3; /* pad to 4 */
- if (twoEntries) {
- otherNameLen = strlen(otherFilename);
- oldParmCount = parmCount;
- parmCount += 3*4 + otherNameLen*2;
- parmCount = (parmCount + 3) & ~3; /* pad to 4 */
- }
- if (maxLen < parmCount)
- parmCount = 0; /* not enough room */
- }
- parmOffset = 8*4 + 39;
- parmOffset += 1; /* pad to 4 */
- dataOffset = parmOffset + parmCount;
-
- parmSlot = 1;
- watch->oddByte = 1;
- /* Total Parameter Count */
- smb_SetSMBParmLong(watch, parmSlot, parmCount); parmSlot += 2;
- /* Total Data Count */
- smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
- /* Parameter Count */
- smb_SetSMBParmLong(watch, parmSlot, parmCount); parmSlot += 2;
- /* Parameter Offset */
- smb_SetSMBParmLong(watch, parmSlot, parmOffset); parmSlot += 2;
- /* Parameter Displacement */
- smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
- /* Data Count */
- smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
- /* Data Offset */
- smb_SetSMBParmLong(watch, parmSlot, dataOffset); parmSlot += 2;
- /* Data Displacement */
- smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
- smb_SetSMBParmByte(watch, parmSlot, 0); /* Setup Count */
- smb_SetSMBDataLength(watch, parmCount + 1);
-
- if (parmCount != 0) {
- outData = smb_GetSMBData(watch, NULL);
- outData++; /* round to get to parmOffset */
- oldOutData = outData;
- *((DWORD *)outData) = oldParmCount; outData += 4;
- /* Next Entry Offset */
- *((DWORD *)outData) = action; outData += 4;
- /* Action */
- *((DWORD *)outData) = nameLen*2; outData += 4;
- /* File Name Length */
- mbstowcs((WCHAR *)outData, filename, nameLen);
- /* File Name */
- if (twoEntries) {
- outData = oldOutData + oldParmCount;
- *((DWORD *)outData) = 0; outData += 4;
- /* Next Entry Offset */
- *((DWORD *)outData) = otherAction; outData += 4;
- /* Action */
- *((DWORD *)outData) = otherNameLen*2;
- outData += 4; /* File Name Length */
- mbstowcs((WCHAR *)outData, otherFilename,
- otherNameLen); /* File Name */
- }
- }
-
- /*
- * If filename is null, we don't know the cause of the
- * change notification. We return zero data (see above),
- * and set error code to NT_STATUS_NOTIFY_ENUM_DIR
- * (= 0x010C). We set the error code here by hand, without
- * modifying wct and bcc.
- */
- if (filename == NULL) {
- ((smb_t *) watch)->rcls = 0x0C;
- ((smb_t *) watch)->reh = 0x01;
- ((smb_t *) watch)->errLow = 0;
- ((smb_t *) watch)->errHigh = 0;
- /* Set NT Status codes flag */
- ((smb_t *) watch)->flg2 |= 0x4000;
- }
-
- smb_SendPacket(vcp, watch);
- smb_FreePacket(watch);
- watch = nextWatch;
- }
- lock_ReleaseMutex(&smb_Dir_Watch_Lock);
-}
+ osi_Log2(smb_logp,"in smb_NotifyChange for file [%s] dscp [%x]",
+ osi_LogSaveString(smb_logp,filename),dscp);
+
+ lock_ObtainMutex(&smb_Dir_Watch_Lock);
+ watch = smb_Directory_Watches;
+ while (watch) {
+ filter = smb_GetSMBParm(watch, 19)
+ | (smb_GetSMBParm(watch, 20) << 16);
+ fid = smb_GetSMBParm(watch, 21);
+ wtree = smb_GetSMBParm(watch, 22) & 0xffff; /* TODO: should this be 0xff ? */
+ maxLen = smb_GetSMBOffsetParm(watch, 5, 1)
+ | (smb_GetSMBOffsetParm(watch, 6, 1) << 16);
+
+ /*
+ * Strange hack - bug in NT Client and NT Server that we
+ * must emulate?
+ */
+ if (filter == 3 && wtree)
+ filter = 0x17;
+
+ fidp = smb_FindFID(watch->vcp, fid, 0);
+ if (!fidp) {
+ osi_Log1(smb_logp," no fidp for fid[%d]",fid);
+ lastWatch = watch;
+ watch = watch->nextp;
+ continue;
+ }
+ if (fidp->scp != dscp
+ || (filter & notifyFilter) == 0
+ || (!isDirectParent && !wtree)) {
+ osi_Log1(smb_logp," passing fidp->scp[%x]", fidp->scp);
+ smb_ReleaseFID(fidp);
+ lastWatch = watch;
+ watch = watch->nextp;
+ continue;
+ }
+ smb_ReleaseFID(fidp);
+
+ osi_Log4(smb_logp,
+ "Sending Change Notification for fid %d filter 0x%x wtree %d file %s",
+ fid, filter, wtree, osi_LogSaveString(smb_logp, filename));
+
+ nextWatch = watch->nextp;
+ if (watch == smb_Directory_Watches)
+ smb_Directory_Watches = nextWatch;
+ else
+ lastWatch->nextp = nextWatch;
+
+ /* Turn off WATCHED flag in dscp */
+ lock_ObtainMutex(&dscp->mx);
+ if (wtree)
+ dscp->flags &= ~CM_SCACHEFLAG_WATCHEDSUBTREE;
+ else
+ dscp->flags &= ~CM_SCACHEFLAG_WATCHED;
+ lock_ReleaseMutex(&dscp->mx);
+
+ /* Convert to response packet */
+ ((smb_t *) watch)->reb = SMB_FLAGS_SERVER_TO_CLIENT | SMB_FLAGS_CANONICAL_PATHNAMES;
+ ((smb_t *) watch)->wct = 0;
+
+ /* out parms */
+ if (filename == NULL)
+ parmCount = 0;
+ else {
+ nameLen = (ULONG)strlen(filename);
+ parmCount = 3*4 + nameLen*2;
+ parmCount = (parmCount + 3) & ~3; /* pad to 4 */
+ if (twoEntries) {
+ otherNameLen = (ULONG)strlen(otherFilename);
+ oldParmCount = parmCount;
+ parmCount += 3*4 + otherNameLen*2;
+ parmCount = (parmCount + 3) & ~3; /* pad to 4 */
+ }
+ if (maxLen < parmCount)
+ parmCount = 0; /* not enough room */
+ }
+ parmOffset = 8*4 + 39;
+ parmOffset += 1; /* pad to 4 */
+ dataOffset = parmOffset + parmCount;
+
+ parmSlot = 1;
+ watch->oddByte = 1;
+ /* Total Parameter Count */
+ smb_SetSMBParmLong(watch, parmSlot, parmCount); parmSlot += 2;
+ /* Total Data Count */
+ smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
+ /* Parameter Count */
+ smb_SetSMBParmLong(watch, parmSlot, parmCount); parmSlot += 2;
+ /* Parameter Offset */
+ smb_SetSMBParmLong(watch, parmSlot, parmOffset); parmSlot += 2;
+ /* Parameter Displacement */
+ smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
+ /* Data Count */
+ smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
+ /* Data Offset */
+ smb_SetSMBParmLong(watch, parmSlot, dataOffset); parmSlot += 2;
+ /* Data Displacement */
+ smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
+ smb_SetSMBParmByte(watch, parmSlot, 0); /* Setup Count */
+ smb_SetSMBDataLength(watch, parmCount + 1);
+
+ if (parmCount != 0) {
+ char * p;
+ outData = smb_GetSMBData(watch, NULL);
+ outData++; /* round to get to parmOffset */
+ oldOutData = outData;
+ *((DWORD *)outData) = oldParmCount; outData += 4;
+ /* Next Entry Offset */
+ *((DWORD *)outData) = action; outData += 4;
+ /* Action */
+ *((DWORD *)outData) = nameLen*2; outData += 4;
+ /* File Name Length */
+ p = strdup(filename);
+ if (smb_StoreAnsiFilenames)
+ CharToOem(p,p);
+ mbstowcs((WCHAR *)outData, p, nameLen);
+ free(p);
+ /* File Name */
+ if (twoEntries) {
+ outData = oldOutData + oldParmCount;
+ *((DWORD *)outData) = 0; outData += 4;
+ /* Next Entry Offset */
+ *((DWORD *)outData) = otherAction; outData += 4;
+ /* Action */
+ *((DWORD *)outData) = otherNameLen*2;
+ outData += 4; /* File Name Length */
+ p = strdup(otherFilename);
+ if (smb_StoreAnsiFilenames)
+ CharToOem(p,p);
+ mbstowcs((WCHAR *)outData, p, otherNameLen); /* File Name */
+ free(p);
+ }
+ }
+
+ /*
+ * If filename is null, we don't know the cause of the
+ * change notification. We return zero data (see above),
+ * and set error code to NT_STATUS_NOTIFY_ENUM_DIR
+ * (= 0x010C). We set the error code here by hand, without
+ * modifying wct and bcc.
+ */
+ if (filename == NULL) {
+ ((smb_t *) watch)->rcls = 0x0C;
+ ((smb_t *) watch)->reh = 0x01;
+ ((smb_t *) watch)->errLow = 0;
+ ((smb_t *) watch)->errHigh = 0;
+ /* Set NT Status codes flag */
+ ((smb_t *) watch)->flg2 |= SMB_FLAGS2_32BIT_STATUS;
+ }
+
+ smb_SendPacket(watch->vcp, watch);
+ smb_FreePacket(watch);
+ watch = nextWatch;
+ }
+ lock_ReleaseMutex(&smb_Dir_Watch_Lock);
+}
long smb_ReceiveNTCancel(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
{
- unsigned char *replyWctp;
- smb_packet_t *watch, *lastWatch;
- USHORT fid, watchtree;
- smb_fid_t *fidp;
- cm_scache_t *scp;
-
- osi_Log0(afsd_logp, "SMB3 receive NT cancel");
-
- lock_ObtainMutex(&smb_Dir_Watch_Lock);
- watch = smb_Directory_Watches;
- while (watch) {
- if (((smb_t *)watch)->uid == ((smb_t *)inp)->uid
- && ((smb_t *)watch)->pid == ((smb_t *)inp)->pid
- && ((smb_t *)watch)->mid == ((smb_t *)inp)->mid
- && ((smb_t *)watch)->tid == ((smb_t *)inp)->tid) {
- if (watch == smb_Directory_Watches)
- smb_Directory_Watches = watch->nextp;
- else
- lastWatch->nextp = watch->nextp;
- lock_ReleaseMutex(&smb_Dir_Watch_Lock);
-
- /* Turn off WATCHED flag in scp */
- fid = smb_GetSMBParm(watch, 21);
- watchtree = smb_GetSMBParm(watch, 22) & 0xffff;
-
- fidp = smb_FindFID(vcp, fid, 0);
- if(fidp) {
- osi_Log3(afsd_logp, "Cancelling change notification for fid %d wtree %d file %s",
- fid, watchtree,
- osi_LogSaveString(afsd_logp, fidp->NTopen_wholepathp));
-
- scp = fidp->scp;
- lock_ObtainMutex(&scp->mx);
- if (watchtree)
- scp->flags &= ~CM_SCACHEFLAG_WATCHEDSUBTREE;
- else
- scp->flags &= ~CM_SCACHEFLAG_WATCHED;
- lock_ReleaseMutex(&scp->mx);
- smb_ReleaseFID(fidp);
- } else {
- osi_Log2(afsd_logp,"NTCancel unable to resolve fid [%d] in vcp[%x]", fid,vcp);
- }
-
- /* assume STATUS32; return 0xC0000120 (CANCELED) */
- replyWctp = watch->wctp;
- *replyWctp++ = 0;
- *replyWctp++ = 0;
- *replyWctp++ = 0;
- ((smb_t *)watch)->rcls = 0x20;
- ((smb_t *)watch)->reh = 0x1;
- ((smb_t *)watch)->errLow = 0;
- ((smb_t *)watch)->errHigh = 0xC0;
- ((smb_t *)watch)->flg2 |= 0x4000;
- smb_SendPacket(vcp, watch);
- smb_FreePacket(watch);
- return 0;
- }
- lastWatch = watch;
- watch = watch->nextp;
- }
- lock_ReleaseMutex(&smb_Dir_Watch_Lock);
+ unsigned char *replyWctp;
+ smb_packet_t *watch, *lastWatch;
+ USHORT fid, watchtree;
+ smb_fid_t *fidp;
+ cm_scache_t *scp;
+
+ osi_Log0(smb_logp, "SMB3 receive NT cancel");
+
+ lock_ObtainMutex(&smb_Dir_Watch_Lock);
+ watch = smb_Directory_Watches;
+ while (watch) {
+ if (((smb_t *)watch)->uid == ((smb_t *)inp)->uid
+ && ((smb_t *)watch)->pid == ((smb_t *)inp)->pid
+ && ((smb_t *)watch)->mid == ((smb_t *)inp)->mid
+ && ((smb_t *)watch)->tid == ((smb_t *)inp)->tid) {
+ if (watch == smb_Directory_Watches)
+ smb_Directory_Watches = watch->nextp;
+ else
+ lastWatch->nextp = watch->nextp;
+ lock_ReleaseMutex(&smb_Dir_Watch_Lock);
+
+ /* Turn off WATCHED flag in scp */
+ fid = smb_GetSMBParm(watch, 21);
+ watchtree = smb_GetSMBParm(watch, 22) & 0xffff;
+
+ if (vcp != watch->vcp)
+ osi_Log2(smb_logp, "smb_ReceiveNTCancel: vcp %x not equal to watch vcp %x",
+ vcp, watch->vcp);
+
+ fidp = smb_FindFID(vcp, fid, 0);
+ if (fidp) {
+ osi_Log3(smb_logp, "Cancelling change notification for fid %d wtree %d file %s",
+ fid, watchtree,
+ osi_LogSaveString(smb_logp, (fidp)?fidp->NTopen_wholepathp:""));
+
+ scp = fidp->scp;
+ lock_ObtainMutex(&scp->mx);
+ if (watchtree)
+ scp->flags &= ~CM_SCACHEFLAG_WATCHEDSUBTREE;
+ else
+ scp->flags &= ~CM_SCACHEFLAG_WATCHED;
+ lock_ReleaseMutex(&scp->mx);
+ smb_ReleaseFID(fidp);
+ } else {
+ osi_Log2(smb_logp,"NTCancel unable to resolve fid [%d] in vcp[%x]", fid,vcp);
+ }
+
+ /* assume STATUS32; return 0xC0000120 (CANCELED) */
+ replyWctp = watch->wctp;
+ *replyWctp++ = 0;
+ *replyWctp++ = 0;
+ *replyWctp++ = 0;
+ ((smb_t *)watch)->rcls = 0x20;
+ ((smb_t *)watch)->reh = 0x1;
+ ((smb_t *)watch)->errLow = 0;
+ ((smb_t *)watch)->errHigh = 0xC0;
+ ((smb_t *)watch)->flg2 |= SMB_FLAGS2_32BIT_STATUS;
+ smb_SendPacket(vcp, watch);
+ smb_FreePacket(watch);
+ return 0;
+ }
+ lastWatch = watch;
+ watch = watch->nextp;
+ }
+ lock_ReleaseMutex(&smb_Dir_Watch_Lock);
+
+ return 0;
+}
+
+/*
+ * NT rename also does hard links.
+ */
+
+#define RENAME_FLAG_MOVE_CLUSTER_INFORMATION 0x102
+#define RENAME_FLAG_HARD_LINK 0x103
+#define RENAME_FLAG_RENAME 0x104
+#define RENAME_FLAG_COPY 0x105
- return 0;
+long smb_ReceiveNTRename(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
+{
+ char *oldPathp, *newPathp;
+ long code = 0;
+ char * tp;
+ int attrs;
+ int rename_type;
+
+ attrs = smb_GetSMBParm(inp, 0);
+ rename_type = smb_GetSMBParm(inp, 1);
+
+ if (rename_type != RENAME_FLAG_RENAME && rename_type != RENAME_FLAG_HARD_LINK) {
+ osi_Log1(smb_logp, "NTRename invalid infolevel [%x]", rename_type);
+ return CM_ERROR_NOACCESS;
+ }
+
+ tp = smb_GetSMBData(inp, NULL);
+ oldPathp = smb_ParseASCIIBlock(tp, &tp);
+ if (smb_StoreAnsiFilenames)
+ OemToChar(oldPathp,oldPathp);
+ newPathp = smb_ParseASCIIBlock(tp, &tp);
+ if (smb_StoreAnsiFilenames)
+ OemToChar(newPathp,newPathp);
+
+ osi_Log3(smb_logp, "NTRename for [%s]->[%s] type [%s]",
+ osi_LogSaveString(smb_logp, oldPathp),
+ osi_LogSaveString(smb_logp, newPathp),
+ ((rename_type==RENAME_FLAG_RENAME)?"rename":"hardlink"));
+
+ if (rename_type == RENAME_FLAG_RENAME) {
+ code = smb_Rename(vcp,inp,oldPathp,newPathp,attrs);
+ } else { /* RENAME_FLAG_HARD_LINK */
+ code = smb_Link(vcp,inp,oldPathp,newPathp);
+ }
+ return code;
}
void smb3_Init()
{
- lock_InitializeMutex(&smb_Dir_Watch_Lock, "Directory Watch List Lock");
+ lock_InitializeMutex(&smb_Dir_Watch_Lock, "Directory Watch List Lock");
}
-cm_user_t *smb_FindCMUserByName(/*smb_vc_t *vcp,*/ char *usern, char *machine)
+cm_user_t *smb_FindCMUserByName(char *usern, char *machine)
{
- cm_user_t *userp;
- /*int newUid;*/
smb_username_t *unp;
+ cm_user_t * userp;
unp = smb_FindUserByName(usern, machine, SMB_FLAG_CREATE);
if (!unp->userp) {
lock_ObtainMutex(&unp->mx);
unp->userp = cm_NewUser();
lock_ReleaseMutex(&unp->mx);
- osi_LogEvent("AFS smb_FindCMUserByName New User",NULL,"name[%s] machine[%s]",usern,machine);
+ osi_Log2(smb_logp,"smb_FindCMUserByName New user name[%s] machine[%s]",osi_LogSaveString(smb_logp,usern),osi_LogSaveString(smb_logp,machine));
} else {
- osi_LogEvent("AFS smb_FindCMUserByName Found",NULL,"name[%s] machine[%s]",usern,machine);
- }
- return unp->userp;
+ osi_Log2(smb_logp,"smb_FindCMUserByName Not found name[%s] machine[%s]",osi_LogSaveString(smb_logp,usern),osi_LogSaveString(smb_logp,machine));
+ }
+ userp = unp->userp;
+ cm_HoldUser(userp);
+ smb_ReleaseUsername(unp);
+ return userp;
}