Merged V2.0 to HEAD

5450: (from V1.4)
      5423 (V1.4): CIFS authentication
   5451: (from V1.4)
      5432 (V1.4): 'No root node' fix
      5437 (V1.4): EHCache upgrade
      5440 (V1.4): AR-1355 - Ticket cache config fix
      5442 (V1.4): Bootstrap reorganization
      5446 (V1.4): AR-1353
   5452: (from V1.4)
      5391: AR-1310 (script rename fix)
   5453: Win32NetBIOS LANA
   5454: CIFS unused code


git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@5483 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
Derek Hulley
2007-04-11 23:41:00 +00:00
parent 4ea83f7f2b
commit ad80d96da3
20 changed files with 1138 additions and 126 deletions

View File

@@ -25,6 +25,7 @@
package org.alfresco.filesys.server.auth;
import java.security.NoSuchAlgorithmException;
import net.sf.acegisecurity.Authentication;
import org.alfresco.filesys.server.SrvSession;
@@ -32,6 +33,7 @@ import org.alfresco.filesys.server.auth.AuthContext;
import org.alfresco.filesys.server.auth.CifsAuthenticator;
import org.alfresco.filesys.server.auth.ClientInfo;
import org.alfresco.filesys.server.auth.NTLanManAuthContext;
import org.alfresco.filesys.server.core.SharedDevice;
import org.alfresco.filesys.smb.server.SMBSrvSession;
import org.alfresco.filesys.util.HexDump;
import org.alfresco.repo.security.authentication.NTLMMode;
@@ -190,6 +192,25 @@ public class AlfrescoAuthenticator extends CifsAuthenticator
return authSts;
}
/**
* Authenticate a connection to a share.
*
* @param client User/client details from the tree connect request.
* @param share Shared device the client wants to connect to.
* @param pwd Share password.
* @param sess Server session.
* @return int Granted file permission level or disallow status if negative. See the
* FilePermission class.
*/
public int authenticateShareConnect(ClientInfo client, SharedDevice share, String sharePwd, SrvSession sess)
{
// Allow write access
//
// Main authentication is handled by authenticateUser()
return CifsAuthenticator.Writeable;
}
/**
* Return an authentication context for the new session
*
@@ -278,7 +299,9 @@ public class AlfrescoAuthenticator extends CifsAuthenticator
// Generate the local encrypted password using the challenge that was sent to the client
byte[] p21 = new byte[21];
byte[] md4byts = m_md4Encoder.decodeHash(md4hash);
byte[] md4byts = null;
md4byts = m_md4Encoder.decodeHash(md4hash);
System.arraycopy(md4byts, 0, p21, 0, 16);
// Get the challenge that was sent to the client
@@ -321,6 +344,11 @@ public class AlfrescoAuthenticator extends CifsAuthenticator
return CifsAuthenticator.AUTH_BADPASSWORD;
}
// Logging
if ( logger.isInfoEnabled())
logger.info( "Logged on user " + client.getUserName() + " (" + sess.getRemoteAddress() + ") using auto-logon shared password");
// Set the current user to be authenticated, save the authentication token
client.setAuthenticationToken( m_authComponent.setCurrentUser(client.getUserName()));
@@ -368,6 +396,10 @@ public class AlfrescoAuthenticator extends CifsAuthenticator
sess.beginReadTransaction( m_transactionService);
// Default logon status to disallow
int authSts = CifsAuthenticator.AUTH_DISALLOW;
// Get the authentication token for the session
NTLMPassthruToken authToken = (NTLMPassthruToken) sess.getAuthenticationToken();
@@ -377,7 +409,6 @@ public class AlfrescoAuthenticator extends CifsAuthenticator
// Get the appropriate hashed password for the algorithm
int authSts = CifsAuthenticator.AUTH_DISALLOW;
byte[] hashedPassword = null;
if ( alg == NTLM1)

View File

@@ -495,7 +495,7 @@ public abstract class CifsAuthenticator
// Check if this is a null session logon
if (user.length() == 0 && domain.length() == 0 && uniPwdLen == 0 && ascPwdLen == 1)
if (user.length() == 0 && uniPwdLen == 0 && ascPwdLen <= 1)
client.setLogonType(ClientInfo.LogonNull);
// Authenticate the user

View File

@@ -136,10 +136,11 @@ public final class AuthSessionFactory
* @param pkt SMBPacket to build the negotiate request
* @param dlct SMB dialects to negotiate
* @param pid Process id to be used by this new session
* @param extSec Enable/disable extended security negotiation
* @return StringList
*/
private final static StringList BuildNegotiatePacket(SMBPacket pkt, DialectSelector dlct, int pid)
private final static StringList BuildNegotiatePacket(SMBPacket pkt, DialectSelector dlct, int pid, boolean extSec)
{
// Initialize the SMB packet header fields
@@ -147,14 +148,14 @@ public final class AuthSessionFactory
pkt.setCommand(PacketType.Negotiate);
pkt.setProcessId(pid);
// If the NT dialect is enabled set the Unicode flag in the request flags
// If the NT dialect is enabled set the Unicode flag
int flags2 = 0;
if (dlct.hasDialect(Dialect.NT))
flags2 += SMBPacket.FLG2_UNICODE;
if ( useExtendedSecurity())
if ( useExtendedSecurity() && extSec == true)
flags2 += SMBPacket.FLG2_EXTENDEDSECURITY;
pkt.setFlags2(flags2);
@@ -486,7 +487,7 @@ public final class AuthSessionFactory
// Build the negotiate SMB dialect packet and exchange with the remote server
StringList diaList = BuildNegotiatePacket(pkt, selDialect, pid);
StringList diaList = BuildNegotiatePacket(pkt, selDialect, pid, shr.hasExtendedSecurityFlags());
pkt.ExchangeLowLevelSMB(netSession, pkt, true);
// Determine the selected SMB dialect

View File

@@ -1016,7 +1016,7 @@ public class AuthenticateSession
*/
public final void doSessionSetup(String userName, byte[] ascPwd, byte[] uniPwd) throws IOException, SMBException
{
doSessionSetup(null, userName, null, ascPwd, uniPwd);
doSessionSetup(null, userName, null, ascPwd, uniPwd, 0);
}
/**
@@ -1029,7 +1029,7 @@ public class AuthenticateSession
public final void doSessionSetup(Type3NTLMMessage type3Msg) throws IOException, SMBException
{
doSessionSetup(type3Msg.getDomain(), type3Msg.getUserName(), type3Msg.getWorkstation(),
type3Msg.getLMHash(), type3Msg.getNTLMHash());
type3Msg.getLMHash(), type3Msg.getNTLMHash(), 0);
}
/**
@@ -1040,11 +1040,13 @@ public class AuthenticateSession
* @param wksName String
* @param ascPwd ASCII password hash
* @param uniPwd Unicode password hash
* @param vcNum Virtual circuit number
* @exception IOException If a network error occurs
* @exception SMBException If a CIFS error occurs
*/
public final void doSessionSetup(String domain, String userName, String wksName,
byte[] ascPwd, byte[] uniPwd) throws IOException, SMBException
byte[] ascPwd, byte[] uniPwd, int vcNum)
throws IOException, SMBException
{
// Check if we are using extended security
@@ -1052,7 +1054,7 @@ public class AuthenticateSession
{
// Run the second phase of the extended security session setup
doExtendedSessionSetupPhase2(domain, userName, wksName, ascPwd, uniPwd);
doExtendedSessionSetupPhase2(domain, userName, wksName, ascPwd, uniPwd, vcNum);
return;
}
@@ -1074,7 +1076,7 @@ public class AuthenticateSession
pkt.setParameter(1, 0); // offset to next command
pkt.setParameter(2, DefaultPacketSize);
pkt.setParameter(3, 1);
pkt.setParameter(4, 0); // virtual circuit number
pkt.setParameter(4, vcNum);
pkt.setParameterLong(5, 0); // session key
// Set the share password length(s)
@@ -1121,7 +1123,7 @@ public class AuthenticateSession
pkt.packString("?", false);
pkt.packString("Java VM", false);
pkt.packString("JLAN", false);
pkt.packString("Alfresco CIFS", false);
// Set the packet length
@@ -1175,7 +1177,7 @@ public class AuthenticateSession
clbuf.append("Java VM");
clbuf.append((char) 0x00);
clbuf.append("JLAN");
clbuf.append("Alfresco CIFS");
clbuf.append((char) 0x00);
// Copy the remaining data to the SMB packet
@@ -1275,7 +1277,6 @@ public class AuthenticateSession
if (getDialect() == Dialect.NT)
{
// Read the returned negotiate parameters, for NT dialect the parameters are not aligned
m_pkt.resetParameterPointer();
@@ -1324,7 +1325,7 @@ public class AuthenticateSession
// Set the default flags for subsequent SMB requests
defFlags2 = SMBPacket.FLG2_LONGFILENAMES + SMBPacket.FLG2_UNICODE + SMBPacket.FLG2_LONGERRORCODE;
defFlags2 = SMBPacket.FLG2_LONGFILENAMES + SMBPacket.FLG2_UNICODE + SMBPacket.FLG2_LONGERRORCODE + SMBPacket.FLG2_SECURITYSIG;
if ( isUsingExtendedSecurity())
defFlags2 += SMBPacket.FLG2_EXTENDEDSECURITY;
@@ -1485,7 +1486,7 @@ public class AuthenticateSession
// Pack the OS details
pkt.packString("Java VM", true);
pkt.packString("JLAN", true);
pkt.packString("Alfresco CIFS", true);
pkt.packString("", true);
@@ -1555,11 +1556,12 @@ public class AuthenticateSession
* @param wksName String
* @param lmPwd byte[]
* @param ntlmPwd byte[]
* @param vcNum int
* @exception IOException If a network error occurs
* @eception SMBException If a CIFS error occurs
*/
private final void doExtendedSessionSetupPhase2(String domain, String userName, String wksName,
byte[] lmPwd, byte[] ntlmPwd) throws IOException, SMBException
byte[] lmPwd, byte[] ntlmPwd, int vcNum) throws IOException, SMBException
{
// Check if the domain name has been specified, if not then use the domain name from the
// original connection details or the servers domain name
@@ -1590,7 +1592,7 @@ public class AuthenticateSession
pkt.setParameter(1, 0); // offset to next command
pkt.setParameter(2, DefaultPacketSize);
pkt.setParameter(3, 1);
pkt.setParameter(4, 0); // virtual circuit number
pkt.setParameter(4, vcNum);
pkt.setParameterLong(5, 0); // session key
// Clear the security blob length and reserved area
@@ -1629,7 +1631,7 @@ public class AuthenticateSession
// Pack the OS details
pkt.packString("Java VM", true);
pkt.packString("JLAN", true);
pkt.packString("Alfresco CIFS", true);
pkt.packString("", true);
@@ -1645,4 +1647,5 @@ public class AuthenticateSession
setGuest(pkt.getParameter(2) != 0 ? true : false);
}
}

View File

@@ -24,7 +24,10 @@
*/
package org.alfresco.filesys.server.auth.passthru;
import java.util.ArrayList;
import java.util.Hashtable;
import java.util.List;
import java.util.UUID;
import javax.transaction.UserTransaction;
@@ -33,14 +36,28 @@ import org.alfresco.error.AlfrescoRuntimeException;
import org.alfresco.filesys.server.SessionListener;
import org.alfresco.filesys.server.SrvSession;
import org.alfresco.filesys.server.auth.AuthContext;
import org.alfresco.filesys.server.auth.AuthenticatorException;
import org.alfresco.filesys.server.auth.ClientInfo;
import org.alfresco.filesys.server.auth.CifsAuthenticator;
import org.alfresco.filesys.server.auth.NTLanManAuthContext;
import org.alfresco.filesys.server.auth.ntlm.NTLM;
import org.alfresco.filesys.server.auth.ntlm.NTLMMessage;
import org.alfresco.filesys.server.auth.ntlm.TargetInfo;
import org.alfresco.filesys.server.auth.ntlm.Type1NTLMMessage;
import org.alfresco.filesys.server.auth.ntlm.Type2NTLMMessage;
import org.alfresco.filesys.server.auth.ntlm.Type3NTLMMessage;
import org.alfresco.filesys.server.config.InvalidConfigurationException;
import org.alfresco.filesys.server.config.ServerConfiguration;
import org.alfresco.filesys.server.core.SharedDevice;
import org.alfresco.filesys.smb.Capability;
import org.alfresco.filesys.smb.SMBStatus;
import org.alfresco.filesys.smb.server.SMBServer;
import org.alfresco.filesys.smb.server.SMBSrvException;
import org.alfresco.filesys.smb.server.SMBSrvPacket;
import org.alfresco.filesys.smb.server.SMBSrvSession;
import org.alfresco.filesys.smb.server.VirtualCircuit;
import org.alfresco.filesys.util.DataPacker;
import org.alfresco.filesys.util.HexDump;
import org.alfresco.model.ContentModel;
import org.alfresco.service.cmr.repository.NodeRef;
import org.apache.commons.logging.Log;
@@ -66,6 +83,18 @@ public class PassthruAuthenticator extends CifsAuthenticator implements SessionL
public final static int MinSessionTmo = 2000; // 2 seconds
public final static int MaxSessionTmo = 30000; // 30 seconds
// Passthru keep alive interval
public final static long PassthruKeepAliveInterval = 60000L; // 60 seconds
// NTLM flags mask, used to mask out features that are not supported
private static final int NTLM_FLAGS = NTLM.Flag56Bit +
NTLM.Flag128Bit +
NTLM.FlagLanManKey +
NTLM.FlagNegotiateNTLM +
NTLM.FlagNegotiateUnicode;
// Passthru servers used to authenticate users
private PassthruServers m_passthruServers;
@@ -192,7 +221,7 @@ public class PassthruAuthenticator extends CifsAuthenticator implements SessionL
// using the session that has already been setup.
AuthenticateSession authSess = passDetails.getAuthenticateSession();
authSess.doSessionSetup(client.getDomain(), client.getUserName(), null, client.getANSIPassword(), client.getPassword());
authSess.doSessionSetup(client.getDomain(), client.getUserName(), null, client.getANSIPassword(), client.getPassword(), 0);
// Check if the user has been logged on as a guest
@@ -311,51 +340,43 @@ public class PassthruAuthenticator extends CifsAuthenticator implements SessionL
*/
public AuthContext getAuthContext( SMBSrvSession sess)
{
// Make sure the SMB server listener is installed
// Check for an SMB session
if ( m_server == null && sess instanceof SMBSrvSession)
{
SMBSrvSession smbSess = (SMBSrvSession) sess;
m_server = smbSess.getSMBServer();
// Install the server listener
m_server.addSessionListener(this);
}
// Open a connection to the authentication server, use normal session setup
AuthContext authCtx = null;
// Check if the client is already authenticated, and it is not a null logon
if ( sess.hasAuthenticationContext() && sess.hasClientInformation() &&
sess.getClientInformation().getAuthenticationToken() != null &&
sess.getClientInformation().getLogonType() != ClientInfo.LogonNull)
{
// DEBUG
if ( logger.isDebugEnabled())
logger.debug("Re-using existing challenge, already authenticated");
// Return the previous challenge, user is already authenticated
return sess.getAuthenticationContext();
}
try
{
// Open a connection to the authentication server
AuthenticateSession authSess = m_passthruServers.openSession();
if (authSess != null)
{
// Create an entry in the active sessions table for the new session
PassthruDetails passDetails = new PassthruDetails(sess, authSess);
m_sessions.put(sess.getUniqueId(), passDetails);
// Use the challenge key returned from the authentication server
authCtx = new NTLanManAuthContext( authSess.getEncryptionKey());
sess.setAuthenticationContext( authCtx);
// DEBUG
if (logger.isDebugEnabled())
logger.debug("Passthru sessId=" + authSess.getSessionId() + ", auth ctx=" + authCtx);
}
AuthenticateSession authSess = m_passthruServers.openSession();
if (authSess != null)
{
// Create an entry in the active sessions table for the new session
PassthruDetails passDetails = new PassthruDetails(sess, authSess, false);
m_sessions.put(sess.getUniqueId(), passDetails);
// Use the challenge key returned from the authentication server
authCtx = new NTLanManAuthContext( authSess.getEncryptionKey());
sess.setAuthenticationContext( authCtx);
// DEBUG
if (logger.isDebugEnabled())
logger.debug("Passthru sessId=" + authSess.getSessionId() + ", auth ctx=" + authCtx);
}
}
catch (Exception ex)
{
@@ -370,6 +391,685 @@ public class PassthruAuthenticator extends CifsAuthenticator implements SessionL
return authCtx;
}
/**
* Generate the CIFS negotiate response packet, the authenticator should add authentication specific fields
* to the response.
*
* @param sess SMBSrvSession
* @param respPkt SMBSrvPacket
* @param extendedSecurity boolean
* @exception AuthenticatorException
*/
public void generateNegotiateResponse(SMBSrvSession sess, SMBSrvPacket respPkt, boolean extendedSecurity)
throws AuthenticatorException
{
// If the client does not support extended security then return a standard negotiate response
// with an 8 byte challenge
if ( extendedSecurity == false)
{
super.generateNegotiateResponse( sess, respPkt, extendedSecurity);
return;
}
// Make sure the extended security negotiation flag is set
if (( respPkt.getFlags2() & SMBSrvPacket.FLG2_EXTENDEDSECURITY) == 0)
respPkt.setFlags2( respPkt.getFlags2() + SMBSrvPacket.FLG2_EXTENDEDSECURITY);
// Get the negotiate response byte area position
int pos = respPkt.getByteOffset();
byte[] buf = respPkt.getBuffer();
// Pack the CIFS server GUID into the negotiate response
UUID serverGUID = sess.getSMBServer().getServerGUID();
DataPacker.putIntelLong( serverGUID.getLeastSignificantBits(), buf, pos);
DataPacker.putIntelLong( serverGUID.getMostSignificantBits(), buf, pos + 8);
pos += 16;
// Set the negotiate response length
respPkt.setByteCount(pos - respPkt.getByteOffset());
}
/**
* Process the CIFS session setup request packet and build the session setup response
*
* @param sess SMBSrvSession
* @param reqPkt SMBSrvPacket
* @param respPkt SMBSrvPacket
* @exception SMBSrvException
*/
public void processSessionSetup(SMBSrvSession sess, SMBSrvPacket reqPkt, SMBSrvPacket respPkt)
throws SMBSrvException
{
// Check that the received packet looks like a valid NT session setup andX request
if (reqPkt.checkPacketIsValid(12, 0) == false)
throw new SMBSrvException(SMBStatus.NTInvalidParameter, SMBStatus.SRVNonSpecificError, SMBStatus.ErrSrv);
// Check if the request is using security blobs or the older hashed password format
if ( reqPkt.getParameterCount() == 13)
{
// Process the standard password session setup
super.processSessionSetup( sess, reqPkt, respPkt);
return;
}
// Extract the session details
int maxBufSize = reqPkt.getParameter(2);
int maxMpx = reqPkt.getParameter(3);
int vcNum = reqPkt.getParameter(4);
int secBlobLen = reqPkt.getParameter(7);
int capabs = reqPkt.getParameterLong(10);
// Extract the client details from the session setup request
int dataPos = reqPkt.getByteOffset();
byte[] buf = reqPkt.getBuffer();
// Determine if ASCII or unicode strings are being used
boolean isUni = reqPkt.isUnicode();
// Make a note of the security blob position
int secBlobPos = dataPos;
// Extract the clients primary domain name string
dataPos += secBlobLen;
reqPkt.setPosition( dataPos);
String domain = "";
if (reqPkt.hasMoreData()) {
// Extract the callers domain name
domain = reqPkt.unpackString(isUni);
if (domain == null)
throw new SMBSrvException(SMBStatus.NTInvalidParameter, SMBStatus.SRVNonSpecificError, SMBStatus.ErrSrv);
}
// Extract the clients native operating system
String clientOS = "";
if (reqPkt.hasMoreData()) {
// Extract the callers operating system name
clientOS = reqPkt.unpackString(isUni);
if (clientOS == null)
throw new SMBSrvException( SMBStatus.NTInvalidParameter, SMBStatus.SRVNonSpecificError, SMBStatus.ErrSrv);
}
// Store the client maximum buffer size, maximum multiplexed requests count and client capability flags
sess.setClientMaximumBufferSize(maxBufSize != 0 ? maxBufSize : SMBSrvSession.DefaultBufferSize);
sess.setClientMaximumMultiplex(maxMpx);
sess.setClientCapabilities(capabs);
// Create the client information and store in the session
ClientInfo client = new ClientInfo();
client.setDomain(domain);
client.setOperatingSystem(clientOS);
client.setLogonType( ClientInfo.LogonNormal);
// Set the remote address, if available
if ( sess.hasRemoteAddress())
client.setClientAddress(sess.getRemoteAddress().getHostAddress());
// Set the process id for this client, for multi-stage logons
client.setProcessId( reqPkt.getProcessId());
// Get the current sesion setup object, or null
Object setupObj = sess.getSetupObject( client.getProcessId());
// Process the security blob
byte[] respBlob = null;
boolean isNTLMSSP = false;
try
{
// Check if the blob has the NTLMSSP signature
if ( secBlobLen >= NTLM.Signature.length) {
// Check for the NTLMSSP signature
int idx = 0;
while ( idx < NTLM.Signature.length && buf[secBlobPos + idx] == NTLM.Signature[ idx])
idx++;
if ( idx == NTLM.Signature.length)
isNTLMSSP = true;
}
// Process the security blob
if ( isNTLMSSP == true)
{
// DEBUG
if (logger.isDebugEnabled())
logger.debug("NT Session setup NTLMSSP, MID=" + reqPkt.getMultiplexId() + ", UID=" + reqPkt.getUserId() + ", PID=" + reqPkt.getProcessId());
// Process an NTLMSSP security blob
respBlob = doNtlmsspSessionSetup( sess, client, buf, secBlobPos, secBlobLen, isUni);
}
else
{
// Invalid blob type
throw new SMBSrvException( SMBStatus.NTInvalidParameter, SMBStatus.SRVNonSpecificError, SMBStatus.ErrSrv);
}
}
catch (SMBSrvException ex)
{
// Cleanup any stored context
sess.removeSetupObject( client.getProcessId());
// Rethrow the exception
throw ex;
}
// Debug
if ( logger.isDebugEnabled() && sess.hasDebug(SMBSrvSession.DBG_NEGOTIATE))
logger.debug("User " + client.getUserName() + " logged on " + (client != null ? " (type " + client.getLogonTypeString() + ")" : ""));
// Update the client information if not already set
if ( sess.getClientInformation() == null ||
sess.getClientInformation().getUserName().length() == 0) {
// Set the client details for the session
sess.setClientInformation(client);
}
// Get the response blob length, it can be null
int respLen = respBlob != null ? respBlob.length : 0;
// Check if there is/was a session setup object stored in the session, this indicates a multi-stage session
// setup so set the status code accordingly
boolean loggedOn = false;
if ( isNTLMSSP == true || sess.hasSetupObject( client.getProcessId()) || setupObj != null)
{
// NTLMSSP has two stages, if there is a stored setup object then indicate more processing
// required
if ( sess.hasSetupObject( client.getProcessId()))
respPkt.setLongErrorCode( SMBStatus.NTMoreProcessingRequired);
else
{
respPkt.setLongErrorCode( SMBStatus.NTSuccess);
// Indicate that the user is logged on
loggedOn = true;
}
respPkt.setParameterCount(4);
respPkt.setParameter(0, 0xFF); // No chained response
respPkt.setParameter(1, 0); // Offset to chained response
respPkt.setParameter(2, 0); // Action
respPkt.setParameter(3, respLen);
}
else
{
// Build a completed session setup response
respPkt.setLongErrorCode( SMBStatus.NTSuccess);
// Build the session setup response SMB
respPkt.setParameterCount(12);
respPkt.setParameter(0, 0xFF); // No chained response
respPkt.setParameter(1, 0); // Offset to chained response
respPkt.setParameter(2, SMBSrvSession.DefaultBufferSize);
respPkt.setParameter(3, SMBSrvSession.NTMaxMultiplexed);
respPkt.setParameter(4, 0); // virtual circuit number
respPkt.setParameterLong(5, 0); // session key
respPkt.setParameter(7, respLen);
// security blob length
respPkt.setParameterLong(8, 0); // reserved
respPkt.setParameterLong(10, getServerCapabilities());
// Indicate that the user is logged on
loggedOn = true;
}
// If the user is logged on then allocate a virtual circuit
int uid = 0;
if ( loggedOn == true) {
// Clear any stored session setup object for the logon
sess.removeSetupObject( client.getProcessId());
// Create a virtual circuit for the new logon
VirtualCircuit vc = new VirtualCircuit( vcNum, client);
uid = sess.addVirtualCircuit( vc);
if ( uid == VirtualCircuit.InvalidUID)
{
// DEBUG
if ( logger.isDebugEnabled() && sess.hasDebug( SMBSrvSession.DBG_NEGOTIATE))
logger.debug("Failed to allocate UID for virtual circuit, " + vc);
// Failed to allocate a UID
throw new SMBSrvException(SMBStatus.NTLogonFailure, SMBStatus.DOSAccessDenied, SMBStatus.ErrDos);
}
else if ( logger.isDebugEnabled() && sess.hasDebug( SMBSrvSession.DBG_NEGOTIATE)) {
// DEBUG
logger.debug("Allocated UID=" + uid + " for VC=" + vc);
}
}
// Common session setup response
respPkt.setCommand( reqPkt.getCommand());
respPkt.setByteCount(0);
respPkt.setTreeId( 0);
respPkt.setUserId( uid);
// Set the various flags
int flags = respPkt.getFlags();
flags &= ~SMBSrvPacket.FLG_CASELESS;
respPkt.setFlags(flags);
int flags2 = SMBSrvPacket.FLG2_LONGFILENAMES + SMBSrvPacket.FLG2_EXTENDEDSECURITY + SMBSrvPacket.FLG2_LONGERRORCODE;
if ( isUni)
flags2 += SMBSrvPacket.FLG2_UNICODE;
respPkt.setFlags2( flags2);
// Pack the security blob
int pos = respPkt.getByteOffset();
buf = respPkt.getBuffer();
if ( respBlob != null)
{
System.arraycopy( respBlob, 0, buf, pos, respBlob.length);
pos += respBlob.length;
}
// Pack the OS, dialect and domain name strings
if ( isUni)
pos = DataPacker.wordAlign(pos);
pos = DataPacker.putString("Java", buf, pos, true, isUni);
pos = DataPacker.putString("Alfresco CIFS Server " + sess.getServer().isVersion(), buf, pos, true, isUni);
pos = DataPacker.putString(sess.getServer().getConfiguration().getDomainName(), buf, pos, true, isUni);
respPkt.setByteCount(pos - respPkt.getByteOffset());
}
/**
* Process an NTLMSSP security blob
*
* @param sess SMBSrvSession
* @param client ClientInfo
* @param secbuf byte[]
* @param secpos int
* @param seclen int
* @param unicode boolean
* @exception SMBSrvException
*/
private final byte[] doNtlmsspSessionSetup( SMBSrvSession sess, ClientInfo client,
byte[] secbuf, int secpos, int seclen, boolean unicode) throws SMBSrvException
{
// Determine the NTLmSSP message type
int msgType = NTLMMessage.isNTLMType( secbuf, secpos);
byte[] respBlob = null;
if ( msgType == -1)
{
// DEBUG
if ( logger.isDebugEnabled())
{
logger.debug("Invalid NTLMSSP token received");
logger.debug(" Token=" + HexDump.hexString( secbuf, secpos, seclen, " "));
}
// Return a logon failure status
throw new SMBSrvException( SMBStatus.NTLogonFailure, SMBStatus.DOSAccessDenied, SMBStatus.ErrDos);
}
// Check for a type 1 NTLMSSP message
else if ( msgType == NTLM.Type1)
{
// Create the type 1 NTLM message from the token
Type1NTLMMessage type1Msg = new Type1NTLMMessage( secbuf, secpos, seclen);
// Build the type 2 NTLM response message
//
// Get the flags from the client request and mask out unsupported features
int ntlmFlags = type1Msg.getFlags() & NTLM_FLAGS;
// Generate a challenge for the response
NTLanManAuthContext ntlmCtx = (NTLanManAuthContext) getAuthContext( sess);
// Build a type2 message to send back to the client, containing the challenge
String domain = sess.getSMBServer().getServerName();
List<TargetInfo> tList = new ArrayList<TargetInfo>();
tList.add(new TargetInfo(NTLM.TargetDomain, domain));
tList.add(new TargetInfo(NTLM.TargetServer, sess.getServerName()));
tList.add(new TargetInfo(NTLM.TargetDNSDomain, domain));
tList.add(new TargetInfo(NTLM.TargetFullDNS, domain));
ntlmFlags = NTLM.FlagChallengeAccept + NTLM.FlagRequestTarget +
NTLM.FlagNegotiateNTLM + NTLM.FlagNegotiateUnicode +
NTLM.FlagKeyExchange + NTLM.FlagTargetInfo + NTLM.Flag56Bit;
// NTLM.FlagAlwaysSign + NTLM.FlagNegotiateSign +
Type2NTLMMessage type2Msg = new Type2NTLMMessage();
type2Msg.buildType2(ntlmFlags, domain, ntlmCtx.getChallenge(), null, tList);
// Store the type 2 message in the session until the session setup is complete
sess.setSetupObject( client.getProcessId(), type2Msg);
// Set the response blob using the type 2 message
respBlob = type2Msg.getBytes();
}
else if ( msgType == NTLM.Type3)
{
// Create the type 3 NTLM message from the token
Type3NTLMMessage type3Msg = new Type3NTLMMessage( secbuf, secpos, seclen, unicode);
// Make sure a type 2 message was stored in the first stage of the session setup
if ( sess.hasSetupObject( client.getProcessId()) == false || sess.getSetupObject( client.getProcessId()) instanceof Type2NTLMMessage == false)
{
// Clear the setup object
sess.removeSetupObject( client.getProcessId());
// Return a logon failure
throw new SMBSrvException( SMBStatus.NTLogonFailure, SMBStatus.DOSAccessDenied, SMBStatus.ErrDos);
}
// Determine if the client sent us NTLMv1 or NTLMv2
if ( type3Msg.hasFlag( NTLM.Flag128Bit) && type3Msg.hasFlag( NTLM.FlagNTLM2Key))
{
// Debug
if ( logger.isDebugEnabled())
logger.debug("Received NTLMSSP/NTLMv2, not supported");
// Return a logon failure
throw new SMBSrvException( SMBStatus.NTLogonFailure, SMBStatus.DOSAccessDenied, SMBStatus.ErrDos);
}
else
{
// Looks like an NTLMv1 blob
doNTLMv1Logon( sess, client, type3Msg);
// Debug
if ( logger.isDebugEnabled())
logger.debug("Logged on using NTLMSSP/NTLMv1");
}
}
// Return the response blob
return respBlob;
}
/**
* Perform an NTLMv1 logon using the NTLMSSP type3 message
*
* @param sess SMBSrvSession
* @param client ClientInfo
* @param type3Msg Type3NTLMMessage
* @exception SMBSrvException
*/
private final void doNTLMv1Logon(SMBSrvSession sess, ClientInfo client, Type3NTLMMessage type3Msg)
throws SMBSrvException
{
// Get the type 2 message that contains the challenge sent to the client
Type2NTLMMessage type2Msg = (Type2NTLMMessage) sess.getSetupObject( client.getProcessId());
sess.removeSetupObject( client.getProcessId());
// Get the NTLM logon details
String userName = type3Msg.getUserName();
// Check for a null logon
if ( userName.length() == 0)
{
// DEBUG
if ( logger.isDebugEnabled())
logger.debug("Null logon");
// Indicate a null logon in the client information
client.setLogonType( ClientInfo.LogonNull);
return;
}
// Find the active authentication session details for the server session
PassthruDetails passDetails = m_sessions.get(sess.getUniqueId());
if (passDetails != null)
{
try
{
// Authenticate the user by passing the hashed password to the authentication server
// using the session that has already been setup.
AuthenticateSession authSess = passDetails.getAuthenticateSession();
authSess.doSessionSetup( type3Msg.getDomain(), userName, null, type3Msg.getLMHash(), type3Msg.getNTLMHash(), 0);
// Check if the user has been logged on as a guest
if (authSess.isGuest())
{
// Check if the local server allows guest access
if (allowGuest() == true)
{
// Get a guest authentication token
doGuestLogon( client, sess);
// Debug
if (logger.isDebugEnabled())
logger.debug("Passthru authenticate user=" + userName + ", GUEST");
}
}
else
{
// Wrap the service calls in a transaction
UserTransaction tx = m_transactionService.getUserTransaction( false);
try
{
// Start the transaction
tx.begin();
// Map the passthru username to an Alfresco person
NodeRef userNode = m_personService.getPerson(userName);
if ( userNode != null)
{
// Get the person name and use that as the current user to line up with permission checks
String personName = (String) m_nodeService.getProperty(userNode, ContentModel.PROP_USERNAME);
m_authComponent.setCurrentUser(personName);
// DEBUG
if ( logger.isDebugEnabled())
logger.debug("Setting current user using person " + personName + " (username " + userName + ")");
}
else
{
// Set using the user name
m_authComponent.setCurrentUser( userName);
// DEBUG
if ( logger.isDebugEnabled())
logger.debug("Setting current user using username " + userName);
}
// Get the authentication token and store
client.setAuthenticationToken( m_authComponent.getCurrentAuthentication());
// Indicate that the client is logged on
client.setLogonType( ClientInfo.LogonNormal);
// Debug
if (logger.isDebugEnabled())
logger.debug("Passthru authenticate user=" + userName + ", FULL");
}
finally
{
// Commit the transaction
if ( tx != null)
{
try {
tx.commit();
}
catch (Exception ex)
{
// Sink it
}
}
}
}
// Update the client details
client.setDomain( type3Msg.getDomain());
client.setUserName( userName);
}
catch (Exception ex)
{
// Debug
logger.error(ex.getMessage());
// Indicate logon failure
throw new SMBSrvException( SMBStatus.NTErr, SMBStatus.NTLogonFailure);
}
finally
{
// Remove the passthru session from the active list
m_sessions.remove(sess.getUniqueId());
// Close the passthru authentication session
try
{
// Close the authentication session
AuthenticateSession authSess = passDetails.getAuthenticateSession();
authSess.CloseSession();
// DEBUG
if (logger.isDebugEnabled())
logger.debug("Closed auth session, sessId=" + authSess.getSessionId());
}
catch (Exception ex)
{
// Debug
logger.error("Passthru error closing session (auth user)", ex);
}
}
}
else
{
// DEBUG
if (logger.isDebugEnabled())
logger.debug(" No PassthruDetails for " + sess.getUniqueId());
// Indicate logon failure
throw new SMBSrvException( SMBStatus.NTErr, SMBStatus.NTLogonFailure);
}
}
/**
* Initialzie the authenticator
*
@@ -510,6 +1210,18 @@ public class PassthruAuthenticator extends CifsAuthenticator implements SessionL
smbServer.addSessionListener(this);
}
/**
* Return the server capability flags
*
* @return int
*/
public int getServerCapabilities()
{
return Capability.Unicode + Capability.RemoteAPIs + Capability.NTSMBs + Capability.NTFind +
Capability.NTStatus + Capability.LargeFiles + Capability.LargeRead + Capability.LargeWrite +
Capability.ExtendedSecurity;
}
/**
* Close the authenticator, perform cleanup
*/
@@ -520,7 +1232,7 @@ public class PassthruAuthenticator extends CifsAuthenticator implements SessionL
if ( m_passthruServers != null)
m_passthruServers.shutdown();
}
/**
* SMB server session closed notification
*
@@ -582,48 +1294,37 @@ public class PassthruAuthenticator extends CifsAuthenticator implements SessionL
*/
public void sessionLoggedOn(SrvSession sess)
{
// Check if there is an active session to the authentication server for this local
// session
// Check if the client information has an empty user name, if so then do not close the
// authentication session
PassthruDetails passDetails = m_sessions.get(sess.getUniqueId());
if (sess.hasClientInformation() && sess.getClientInformation().getUserName() != null
&& sess.getClientInformation().getUserName().length() > 0)
if (passDetails != null && passDetails.hasKeepAlive() == false)
{
// Remove the passthru session from the active list
// Check if there is an active session to the authentication server for this local
// session
m_sessions.remove(sess.getUniqueId());
PassthruDetails passDetails = m_sessions.get(sess.getUniqueId());
// Close the passthru authentication session
if (passDetails != null)
try
{
// Close the authentication session
AuthenticateSession authSess = passDetails.getAuthenticateSession();
authSess.CloseSession();
// DEBUG
if (logger.isDebugEnabled())
logger.debug("Closed auth session, sessId=" + authSess.getSessionId());
}
catch (Exception ex)
{
// Remove the passthru session from the active list
// Debug
m_sessions.remove(sess.getUniqueId());
// Close the passthru authentication session
try
{
// Close the authentication session
AuthenticateSession authSess = passDetails.getAuthenticateSession();
authSess.CloseSession();
// DEBUG
if (logger.isDebugEnabled())
logger.debug("Closed auth session, sessId=" + authSess.getSessionId());
}
catch (Exception ex)
{
// Debug
logger.error("Passthru error closing session (logon)", ex);
}
logger.error("Passthru error closing session (logon)", ex);
}
}
}

View File

@@ -34,7 +34,6 @@ import org.alfresco.filesys.server.SrvSession;
*/
class PassthruDetails
{
// Server session
private SrvSession m_sess;
@@ -43,6 +42,10 @@ class PassthruDetails
private AuthenticateSession m_authSess;
// Flag to indicate if session should be kept alive
private boolean m_keepAlive;
/**
* Class constructor
*
@@ -55,6 +58,21 @@ class PassthruDetails
m_authSess = authSess;
}
/**
* Class constructor
*
* @param sess SrvSession
* @param authSess AuthenticateSession
* @param keepAlive boolean
*/
public PassthruDetails(SrvSession sess, AuthenticateSession authSess, boolean keepAlive)
{
m_sess = sess;
m_authSess = authSess;
m_keepAlive = keepAlive;
}
/**
* Return the session details
*
@@ -74,4 +92,14 @@ class PassthruDetails
{
return m_authSess;
}
/**
* Check if the authentication session should be kept alive
*
* @return boolean
*/
public final boolean hasKeepAlive()
{
return m_keepAlive;
}
}

View File

@@ -306,16 +306,16 @@ public class PassthruServers
*/
public final AuthenticateSession openSession()
{
return openSession( 0);
return openSession( false);
}
/**
* Open a new session to an authentication server
*
* @param extFlags int
* @param useExtSec boolean
* @return AuthenticateSession
*/
public final AuthenticateSession openSession(int extFlags)
public final AuthenticateSession openSession(boolean useExtSec)
{
// Get the details of an authentication server to connect to
@@ -331,7 +331,8 @@ public class PassthruServers
// Open a new authentication session to the server
PCShare authShare = new PCShare(passthruServer.getAddress().getHostAddress(), "IPC$", "", "");
authShare.setExtendedSecurityFlags( extFlags);
if ( useExtSec == true)
authShare.setExtendedSecurityFlags( SMBPacket.FLG2_EXTENDEDSECURITY);
AuthenticateSession authSess = null;

View File

@@ -88,6 +88,7 @@ public class SMBPacket
public static final int FLG2_LONGFILENAMES = 0x0001;
public static final int FLG2_EXTENDEDATTRIB = 0x0002;
public static final int FLG2_SECURITYSIG = 0x0004;
public static final int FLG2_EXTENDEDSECURITY = 0x0800;
public static final int FLG2_READIFEXE = 0x2000;
public static final int FLG2_LONGERRORCODE = 0x4000;
@@ -589,6 +590,16 @@ public class SMBPacket
}
/**
* Get the SMB signing value, as a long value
*
* @return long
*/
public final long getSignature()
{
return DataPacker.getIntelLong( m_smbbuf, SIGNATURE);
}
/**
* Get the tree identifier (TID)
*
* @return Tree identifier (TID)
@@ -1131,6 +1142,16 @@ public class SMBPacket
}
/**
* Set a long error code (NT status code)
*
* @param sts int
*/
public final void setLongErrorCode(int lsts)
{
DataPacker.putIntelInt(lsts, m_smbbuf, ERRORCODE);
}
/**
* Set the SMB flags value.
*
* @param flg SMB flags value.
@@ -1225,6 +1246,38 @@ public class SMBPacket
DataPacker.putIntelShort(sid, m_smbbuf, SID);
}
/**
* Set the SMB signing signature
*
* @param ival int
*/
public final void setSignature( int ival)
{
DataPacker.putIntelInt( ival, m_smbbuf, SIGNATURE);
DataPacker.putZeros( m_smbbuf, SIGNATURE + 4, 4);
}
/**
* Set the SMB signing signature
*
* @param lval long
*/
public final void setSignature( long lval)
{
DataPacker.putIntelLong( lval, m_smbbuf, SIGNATURE);
}
/**
* Set the SMB signing signature
*
* @param byts byte[]
* @param offset int
*/
public final void setSignature( byte[] byts, int offset)
{
System.arraycopy( byts, offset, m_smbbuf, SIGNATURE, 8);
}
/**
* Set the tree identifier (TID)
*