diff --git a/source/java/org/alfresco/filesys/server/NetworkServer.java b/source/java/org/alfresco/filesys/server/NetworkServer.java index e07482f6f7..86007136ac 100644 --- a/source/java/org/alfresco/filesys/server/NetworkServer.java +++ b/source/java/org/alfresco/filesys/server/NetworkServer.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005 Alfresco, Inc. + * Copyright (C) 2005-2006 Alfresco, Inc. * * Licensed under the Mozilla Public License version 1.1 * with a permitted attribution clause. You may obtain a @@ -19,7 +19,7 @@ package org.alfresco.filesys.server; import java.net.InetAddress; import java.util.Vector; -import org.alfresco.filesys.server.auth.SrvAuthenticator; +import org.alfresco.filesys.server.auth.CifsAuthenticator; import org.alfresco.filesys.server.auth.acl.AccessControlManager; import org.alfresco.filesys.server.config.ServerConfiguration; import org.alfresco.filesys.server.core.ShareMapper; @@ -99,9 +99,9 @@ public abstract class NetworkServer /** * Return the authenticator for this server * - * @return SrvAuthenticator + * @return CifsAuthenticator */ - public final SrvAuthenticator getAuthenticator() + public final CifsAuthenticator getAuthenticator() { return getConfiguration().getAuthenticator(); } diff --git a/source/java/org/alfresco/filesys/server/SrvSession.java b/source/java/org/alfresco/filesys/server/SrvSession.java index bd659ff8d4..097a9db9a3 100644 --- a/source/java/org/alfresco/filesys/server/SrvSession.java +++ b/source/java/org/alfresco/filesys/server/SrvSession.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005 Alfresco, Inc. + * Copyright (C) 2005-2006 Alfresco, Inc. * * Licensed under the Mozilla Public License version 1.1 * with a permitted attribution clause. You may obtain a @@ -23,6 +23,7 @@ import javax.transaction.SystemException; import javax.transaction.UserTransaction; import org.alfresco.error.AlfrescoRuntimeException; +import org.alfresco.filesys.server.auth.AuthContext; import org.alfresco.filesys.server.auth.ClientInfo; import org.alfresco.filesys.server.core.SharedDevice; import org.alfresco.filesys.server.core.SharedDeviceList; @@ -60,10 +61,6 @@ public abstract class SrvSession private ClientInfo m_clientInfo; - // Challenge key used for this session - - private byte[] m_challenge; - // Debug flags for this session private int m_debug; @@ -85,6 +82,10 @@ public abstract class SrvSession private Object m_authToken; + // Authentication context, used during the initial session setup phase + + private AuthContext m_authContext; + // List of dynamic/temporary shares created for this session private SharedDeviceList m_dynamicShares; @@ -154,26 +155,6 @@ public abstract class SrvSession return m_authToken != null ? true : false; } - /** - * Return the session challenge key - * - * @return byte[] - */ - public final byte[] getChallengeKey() - { - return m_challenge; - } - - /** - * Determine if the challenge key has been set for this session - * - * @return boolean - */ - public final boolean hasChallengeKey() - { - return m_challenge != null ? true : false; - } - /** * Return the process id * @@ -231,6 +212,26 @@ public abstract class SrvSession return m_clientInfo; } + /** + * Check if the session has an authentication context + * + * @return boolean + */ + public final boolean hasAuthenticationContext() + { + return m_authContext != null ? true : false; + } + + /** + * Return the authentication context for this sesion + * + * @return AuthContext + */ + public final AuthContext getAuthenticationContext() + { + return m_authContext; + } + /** * Determine if the session has any dynamic shares * @@ -342,6 +343,16 @@ public abstract class SrvSession m_authToken = authToken; } + /** + * Set the authentication context, used during the initial session setup phase + * + * @param ctx AuthContext + */ + public final void setAuthenticationContext( AuthContext ctx) + { + m_authContext = ctx; + } + /** * Set the client information * @@ -352,16 +363,6 @@ public abstract class SrvSession m_clientInfo = client; } - /** - * Set the session challenge key - * - * @param key byte[] - */ - public final void setChallengeKey(byte[] key) - { - m_challenge = key; - } - /** * Set the debug output interface. * diff --git a/source/java/org/alfresco/filesys/server/auth/AlfrescoAuthenticator.java b/source/java/org/alfresco/filesys/server/auth/AlfrescoAuthenticator.java index c3afddc45f..ec20bd579e 100644 --- a/source/java/org/alfresco/filesys/server/auth/AlfrescoAuthenticator.java +++ b/source/java/org/alfresco/filesys/server/auth/AlfrescoAuthenticator.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005 Alfresco, Inc. + * Copyright (C) 2005-2006 Alfresco, Inc. * * Licensed under the Mozilla Public License version 1.1 * with a permitted attribution clause. You may obtain a @@ -20,7 +20,6 @@ import java.security.NoSuchAlgorithmException; import org.alfresco.filesys.server.SrvSession; import org.alfresco.filesys.smb.server.SMBSrvSession; -import org.alfresco.filesys.util.DataPacker; import org.alfresco.repo.security.authentication.NTLMMode; /** @@ -34,7 +33,7 @@ import org.alfresco.repo.security.authentication.NTLMMode; * * @author GKSpencer */ -public class AlfrescoAuthenticator extends SrvAuthenticator +public class AlfrescoAuthenticator extends CifsAuthenticator { /** * Default Constructor @@ -43,8 +42,6 @@ public class AlfrescoAuthenticator extends SrvAuthenticator */ public AlfrescoAuthenticator() { - setAccessMode(SrvAuthenticator.USER_MODE); - setEncryptedPasswords(true); } /** @@ -82,7 +79,7 @@ public class AlfrescoAuthenticator extends SrvAuthenticator if ( logger.isDebugEnabled()) logger.debug("Null CIFS logon allowed"); - return SrvAuthenticator.AUTH_ALLOW; + return CifsAuthenticator.AUTH_ALLOW; } // Check if the client is already authenticated, and it is not a null logon @@ -175,46 +172,6 @@ public class AlfrescoAuthenticator extends SrvAuthenticator return authSts; } - /** - * Generate a challenge key - * - * @param sess SrvSession - * @return byte[] - */ - public byte[] getChallengeKey(SrvSession sess) - { - // In MD4 mode we generate the challenge locally - - byte[] key = null; - - // Check if the client is already authenticated, and it is not a null logon - - if ( sess.hasClientInformation() && sess.getClientInformation().getAuthenticationToken() != null && - sess.getClientInformation().getLogonType() != ClientInfo.LogonNull) - { - // Return the previous challenge, user is already authenticated - - key = sess.getChallengeKey(); - - // DEBUG - - if ( logger.isDebugEnabled()) - logger.debug("Re-using existing challenge, already authenticated"); - } - else if ( m_authComponent.getNTLMMode() == NTLMMode.MD4_PROVIDER) - { - // Generate a new challenge key, pack the key and return - - key = new byte[8]; - - DataPacker.putIntelLong(m_random.nextLong(), key, 0); - } - - // Return the challenge - - return key; - } - /** * Perform MD4 user authentication * @@ -234,7 +191,7 @@ public class AlfrescoAuthenticator extends SrvAuthenticator // Check if the client has supplied an NTLM hashed password, if not then do not allow access if ( client.getPassword() == null) - return SrvAuthenticator.AUTH_BADPASSWORD; + return CifsAuthenticator.AUTH_BADPASSWORD; try { @@ -244,21 +201,30 @@ public class AlfrescoAuthenticator extends SrvAuthenticator byte[] md4byts = m_md4Encoder.decodeHash(md4hash); System.arraycopy(md4byts, 0, p21, 0, 16); + // Get the challenge that was sent to the client + + NTLanManAuthContext authCtx = null; + + if ( sess.hasAuthenticationContext() && sess.getAuthenticationContext() instanceof NTLanManAuthContext) + authCtx = (NTLanManAuthContext) sess.getAuthenticationContext(); + else + return CifsAuthenticator.AUTH_DISALLOW; + // Generate the local hash of the password using the same challenge - byte[] localHash = getEncryptor().doNTLM1Encryption(p21, sess.getChallengeKey()); + byte[] localHash = getEncryptor().doNTLM1Encryption(p21, authCtx.getChallenge()); // Validate the password byte[] clientHash = client.getPassword(); if ( clientHash == null || clientHash.length != localHash.length) - return SrvAuthenticator.AUTH_BADPASSWORD; + return CifsAuthenticator.AUTH_BADPASSWORD; for ( int i = 0; i < clientHash.length; i++) { if ( clientHash[i] != localHash[i]) - return SrvAuthenticator.AUTH_BADPASSWORD; + return CifsAuthenticator.AUTH_BADPASSWORD; } // Set the current user to be authenticated, save the authentication token @@ -271,7 +237,7 @@ public class AlfrescoAuthenticator extends SrvAuthenticator // Passwords match, grant access - return SrvAuthenticator.AUTH_ALLOW; + return CifsAuthenticator.AUTH_ALLOW; } catch (NoSuchAlgorithmException ex) { @@ -279,7 +245,7 @@ public class AlfrescoAuthenticator extends SrvAuthenticator // Error during password check, do not allow access - return SrvAuthenticator.AUTH_DISALLOW; + return CifsAuthenticator.AUTH_DISALLOW; } // Check if this is an SMB/CIFS null session logon. @@ -287,10 +253,10 @@ public class AlfrescoAuthenticator extends SrvAuthenticator // The null session will only be allowed to connect to the IPC$ named pipe share. if (client.isNullSession() && sess instanceof SMBSrvSession) - return SrvAuthenticator.AUTH_ALLOW; + return CifsAuthenticator.AUTH_ALLOW; // User does not exist, check if guest access is allowed - return allowGuest() ? SrvAuthenticator.AUTH_GUEST : SrvAuthenticator.AUTH_DISALLOW; + return allowGuest() ? CifsAuthenticator.AUTH_GUEST : CifsAuthenticator.AUTH_DISALLOW; } } \ No newline at end of file diff --git a/source/java/org/alfresco/filesys/server/auth/AuthContext.java b/source/java/org/alfresco/filesys/server/auth/AuthContext.java new file mode 100644 index 0000000000..d291e1c530 --- /dev/null +++ b/source/java/org/alfresco/filesys/server/auth/AuthContext.java @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2005-2006 Alfresco, Inc. + * + * Licensed under the Mozilla Public License version 1.1 + * with a permitted attribution clause. You may obtain a + * copy of the License at + * + * http://www.alfresco.org/legal/license.txt + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, + * either express or implied. See the License for the specific + * language governing permissions and limitations under the + * License. + */ +package org.alfresco.filesys.server.auth; + +/** + * CIFS Authentication Context Class + * + *
Holds authentication specific information for the negotiate/session setup phase of a new CIFS session. + * + * @author gkspencer + */ +public class AuthContext +{ + +} diff --git a/source/java/org/alfresco/filesys/server/auth/AuthenticatorException.java b/source/java/org/alfresco/filesys/server/auth/AuthenticatorException.java new file mode 100644 index 0000000000..6fa2bc4a48 --- /dev/null +++ b/source/java/org/alfresco/filesys/server/auth/AuthenticatorException.java @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2005-2006 Alfresco, Inc. + * + * Licensed under the Mozilla Public License version 1.1 + * with a permitted attribution clause. You may obtain a + * copy of the License at + * + * http://www.alfresco.org/legal/license.txt + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, + * either express or implied. See the License for the specific + * language governing permissions and limitations under the + * License. + */ +package org.alfresco.filesys.server.auth; + +/** + * Authenticator Exception Class + * + * @author gkspencer + */ +public class AuthenticatorException extends Exception +{ + private static final long serialVersionUID = 7816213724352083486L; + + /** + * Default constructor. + */ + public AuthenticatorException() + { + super(); + } + + /** + * Class constructor. + * + * @param s String + */ + public AuthenticatorException(String s) + { + super(s); + } +} diff --git a/source/java/org/alfresco/filesys/server/auth/CifsAuthenticator.java b/source/java/org/alfresco/filesys/server/auth/CifsAuthenticator.java new file mode 100644 index 0000000000..d21b62e627 --- /dev/null +++ b/source/java/org/alfresco/filesys/server/auth/CifsAuthenticator.java @@ -0,0 +1,893 @@ +/* + * Copyright (C) 2005-2006 Alfresco, Inc. + * + * Licensed under the Mozilla Public License version 1.1 + * with a permitted attribution clause. You may obtain a + * copy of the License at + * + * http://www.alfresco.org/legal/license.txt + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, + * either express or implied. See the License for the specific + * language governing permissions and limitations under the + * License. + */ +package org.alfresco.filesys.server.auth; + +import java.security.InvalidKeyException; +import java.security.NoSuchAlgorithmException; +import java.util.Random; + +import javax.transaction.UserTransaction; + +import net.sf.acegisecurity.Authentication; + +import org.alfresco.config.ConfigElement; +import org.alfresco.filesys.server.SrvSession; +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.server.filesys.DiskDeviceContext; +import org.alfresco.filesys.server.filesys.DiskInterface; +import org.alfresco.filesys.server.filesys.DiskSharedDevice; +import org.alfresco.filesys.server.filesys.SrvDiskInfo; +import org.alfresco.filesys.smb.Capability; +import org.alfresco.filesys.smb.Dialect; +import org.alfresco.filesys.smb.DialectSelector; +import org.alfresco.filesys.smb.SMBStatus; +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.SecurityMode; +import org.alfresco.filesys.smb.server.repo.ContentContext; +import org.alfresco.filesys.util.DataPacker; +import org.alfresco.filesys.util.HexDump; +import org.alfresco.model.ContentModel; +import org.alfresco.repo.security.authentication.AuthenticationComponent; +import org.alfresco.repo.security.authentication.MD4PasswordEncoder; +import org.alfresco.repo.security.authentication.MD4PasswordEncoderImpl; +import org.alfresco.service.cmr.repository.NodeRef; +import org.alfresco.service.cmr.repository.NodeService; +import org.alfresco.service.cmr.security.AuthenticationService; +import org.alfresco.service.cmr.security.PersonService; +import org.alfresco.service.transaction.TransactionService; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +/** + * CIFS Authenticator Class + * + *
+ * An authenticator is used by the CIFS server to authenticate users when in user level access mode + * and authenticate requests to connect to a share when in share level access. + */ +public abstract class CifsAuthenticator +{ + // Logging + + protected static final Log logger = LogFactory.getLog("org.alfresco.smb.protocol.auth"); + + // Encryption algorithm types + + public static final int LANMAN = PasswordEncryptor.LANMAN; + public static final int NTLM1 = PasswordEncryptor.NTLM1; + public static final int NTLM2 = PasswordEncryptor.NTLM2; + + // Authentication status values + + public static final int AUTH_ALLOW = 0; + public static final int AUTH_GUEST = 0x10000000; + public static final int AUTH_DISALLOW = -1; + public static final int AUTH_BADPASSWORD = -2; + public static final int AUTH_BADUSER = -3; + + // Share access permissions, returned by authenticateShareConnect() + + public static final int NoAccess = 0; + public static final int ReadOnly = 1; + public static final int Writeable = 2; + + // Standard encrypted password and challenge length + + public static final int STANDARD_PASSWORD_LEN = 24; + public static final int STANDARD_CHALLENGE_LEN = 8; + + // Default guest user name + + protected static final String GUEST_USERNAME = "guest"; + + // Default SMB dialects to enable + + private DialectSelector m_dialects; + + // Security mode flags + + private int m_securityMode = SecurityMode.UserMode + SecurityMode.EncryptedPasswords; + + // Password encryption algorithms + + private PasswordEncryptor m_encryptor = new PasswordEncryptor(); + + // Flag to enable/disable the guest account, and control mapping of unknown users to the guest account + + private boolean m_allowGuest; + private boolean m_mapToGuest; + + // Default guest user name + + private String m_guestUserName = GUEST_USERNAME; + + // Random number generator used to generate challenge keys + + protected Random m_random = new Random(System.currentTimeMillis()); + + // Server configuration + + protected ServerConfiguration m_config; + + // Authentication component, used to access internal authentication functions + + protected AuthenticationComponent m_authComponent; + + // MD4 hash decoder + + protected MD4PasswordEncoder m_md4Encoder = new MD4PasswordEncoderImpl(); + + // Various services required to get user information + + protected NodeService m_nodeService; + protected PersonService m_personService; + protected TransactionService m_transactionService; + protected AuthenticationService m_authenticationService; + + /** + * 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; + } + + /** + * Authenticate a user. A user may be granted full access, guest access or no access. + * + * @param client User/client details from the session setup request. + * @param sess Server session + * @param alg Encryption algorithm + * @return int Access level or disallow status. + */ + public int authenticateUser(ClientInfo client, SrvSession sess, int alg) + { + return CifsAuthenticator.AUTH_DISALLOW; + } + + /** + * Initialize the authenticator + * + * @param config ServerConfiguration + * @param params ConfigElement + * @exception InvalidConfigurationException + */ + public void initialize(ServerConfiguration config, ConfigElement params) throws InvalidConfigurationException + { + // Save the server configuration so we can access the authentication component + + m_config = config; + + // Check that the required authentication classes are available + + m_authComponent = m_config.getAuthenticationComponent(); + + if ( m_authComponent == null) + throw new InvalidConfigurationException("Authentication component not available"); + + // Allocate the SMB dialect selector, and initialize using the default list of dialects + + m_dialects = new DialectSelector(); + + m_dialects.AddDialect(Dialect.DOSLanMan1); + m_dialects.AddDialect(Dialect.DOSLanMan2); + m_dialects.AddDialect(Dialect.LanMan1); + m_dialects.AddDialect(Dialect.LanMan2); + m_dialects.AddDialect(Dialect.LanMan2_1); + m_dialects.AddDialect(Dialect.NT); + + // Get hold of various services + + m_nodeService = config.getNodeService(); + m_personService = config.getPersonService(); + m_transactionService = config.getTransactionService(); + m_authenticationService = config.getAuthenticationService(); + + // Set the guest user name + + setGuestUserName( m_authComponent.getGuestUserName()); + + // Check that the authentication component is the required type for this authenticator + + if ( validateAuthenticationMode() == false) + throw new InvalidConfigurationException("Required authentication mode not available"); + } + + /** + * Validate that the authentication component supports the required mode + * + * @return boolean + */ + protected boolean validateAuthenticationMode() + { + return true; + } + + /** + * Encrypt the plain text password with the specified encryption key using the specified + * encryption algorithm. + * + * @param plainPwd String + * @param encryptKey byte[] + * @param alg int + * @param userName String + * @param domain String + * @return byte[] + */ + protected final byte[] generateEncryptedPassword(String plainPwd, byte[] encryptKey, int alg, String userName, String domain) + { + + // Use the password encryptor + + byte[] encPwd = null; + + try + { + // Encrypt the password + + encPwd = m_encryptor.generateEncryptedPassword(plainPwd, encryptKey, alg, userName, domain); + } + catch (NoSuchAlgorithmException ex) + { + } + catch (InvalidKeyException ex) + { + } + + // Return the encrypted password + + return encPwd; + } + + /** + * Return an authentication context for the new session + * + * @return AuthContext + */ + public AuthContext getAuthContext( SMBSrvSession sess) + { + AuthContext authCtx = null; + + if ( sess.hasAuthenticationContext() && sess.getAuthenticationContext() instanceof NTLanManAuthContext) + { + // Use the existing authentication context + + authCtx = (NTLanManAuthContext) sess.getAuthenticationContext(); + } + else + { + // Create a new authentication context for the session + + authCtx = new NTLanManAuthContext(); + sess.setAuthenticationContext( authCtx); + } + + // Return the authentication context + + return authCtx; + } + + /** + * Return the enabled SMB dialects that the server will use when negotiating sessions. + * + * @return DialectSelector + */ + public final DialectSelector getEnabledDialects() + { + return m_dialects; + } + + /** + * Return the security mode flags + * + * @return int + */ + public final int getSecurityMode() + { + return m_securityMode; + } + + /** + * 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 + { + // Pack the negotiate response for NT/LanMan challenge/response authentication + + NTLanManAuthContext authCtx = (NTLanManAuthContext) getAuthContext( sess); + + // Encryption key and primary domain string should be returned in the byte area + + int pos = respPkt.getByteOffset(); + byte[] buf = respPkt.getBuffer(); + + if ( authCtx.getChallenge() == null) + { + + // Return a dummy encryption key + + for (int i = 0; i < 8; i++) + buf[pos++] = 0; + } + else + { + + // Store the encryption key + + byte[] key = authCtx.getChallenge(); + for (int i = 0; i < key.length; i++) + buf[pos++] = key[i]; + } + + // Pack the local domain name + + String domain = sess.getServer().getConfiguration().getDomainName(); + if (domain != null) + pos = DataPacker.putString(domain, buf, pos, true, true); + + // Pack the local server name + + pos = DataPacker.putString( sess.getServer().getServerName(), buf, pos, true, true); + + // Set the packet 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(13, 0) == false) + { + throw new SMBSrvException(SMBStatus.NTInvalidParameter, SMBStatus.SRVNonSpecificError, SMBStatus.ErrSrv); + } + + // Extract the session details + + int maxBufSize = reqPkt.getParameter(2); + int maxMpx = reqPkt.getParameter(3); + int vcNum = reqPkt.getParameter(4); + int ascPwdLen = reqPkt.getParameter(7); + int uniPwdLen = reqPkt.getParameter(8); + int capabs = reqPkt.getParameterLong(11); + + // Extract the client details from the session setup request + + byte[] buf = reqPkt.getBuffer(); + + // Determine if ASCII or unicode strings are being used + + boolean isUni = reqPkt.isUnicode(); + + // Extract the password strings + + byte[] ascPwd = reqPkt.unpackBytes(ascPwdLen); + byte[] uniPwd = reqPkt.unpackBytes(uniPwdLen); + + // Extract the user name string + + String user = reqPkt.unpackString(isUni); + + if (user == null) + { + throw new SMBSrvException(SMBStatus.NTInvalidParameter, SMBStatus.SRVNonSpecificError, SMBStatus.ErrSrv); + } + + // Extract the clients primary domain name string + + 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); + } + } + + // DEBUG + + if (logger.isDebugEnabled() && sess.hasDebug(SMBSrvSession.DBG_NEGOTIATE)) + { + logger.debug("NT Session setup from user=" + user + ", password=" + + (uniPwd != null ? HexDump.hexString(uniPwd) : "none") + ", ANSIpwd=" + + (ascPwd != null ? HexDump.hexString(ascPwd) : "none") + ", domain=" + domain + ", os=" + clientOS + + ", VC=" + vcNum + ", maxBuf=" + maxBufSize + ", maxMpx=" + maxMpx + + ", authCtx=" + sess.getAuthenticationContext()); + logger.debug(" MID=" + reqPkt.getMultiplexId() + ", UID=" + reqPkt.getUserId() + ", PID=" + + reqPkt.getProcessId()); + } + + // Store the client maximum buffer size, maximum multiplexed requests count and client + // capability flags + + sess.setClientMaximumBufferSize(maxBufSize); + sess.setClientMaximumMultiplex(maxMpx); + sess.setClientCapabilities(capabs); + + // Create the client information and store in the session + + ClientInfo client = new ClientInfo(user, uniPwd); + client.setANSIPassword(ascPwd); + client.setDomain(domain); + client.setOperatingSystem(clientOS); + + if (sess.hasRemoteAddress()) + client.setClientAddress(sess.getRemoteAddress().getHostAddress()); + + // Check if this is a null session logon + + if (user.length() == 0 && domain.length() == 0 && uniPwdLen == 0 && ascPwdLen == 1) + client.setLogonType(ClientInfo.LogonNull); + + // Authenticate the user + + boolean isGuest = false; + + int sts = authenticateUser(client, sess, CifsAuthenticator.NTLM1); + + if (sts > 0 && (sts & CifsAuthenticator.AUTH_GUEST) != 0) + { + + // Guest logon + + isGuest = true; + + // DEBUG + + if (logger.isDebugEnabled() && sess.hasDebug(SMBSrvSession.DBG_NEGOTIATE)) + logger.debug("User " + user + ", logged on as guest"); + } + else if (sts != CifsAuthenticator.AUTH_ALLOW) + { + + // Check if the session already has valid client details and the new client details + // have null username/password values + + if (sess.getClientInformation() != null && client.getUserName().length() == 0) + { + + // Use the existing client information details + + client = sess.getClientInformation(); + + // DEBUG + + if (logger.isDebugEnabled() && sess.hasDebug(SMBSrvSession.DBG_NEGOTIATE)) + logger.debug("Null client information, reusing existing client=" + client); + } + else + { + // DEBUG + + if (logger.isDebugEnabled() && sess.hasDebug(SMBSrvSession.DBG_NEGOTIATE)) + logger.debug("User " + user + ", access denied"); + + // Invalid user, reject the session setup request + + throw new SMBSrvException(SMBStatus.NTLogonFailure, SMBStatus.DOSAccessDenied, SMBStatus.ErrDos); + } + } + else if (logger.isDebugEnabled() && sess.hasDebug(SMBSrvSession.DBG_NEGOTIATE)) + { + + // DEBUG + + logger.debug("User " + user + " 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); + } + + // Set the guest flag for the client, indicate that the session is logged on + + client.setGuest(isGuest); + sess.setLoggedOn(true); + + // Build the session setup response SMB + + respPkt.setParameterCount(3); + respPkt.setParameter(0, 0); // No chained response + respPkt.setParameter(1, 0); // Offset to chained response + respPkt.setParameter(2, isGuest ? 1 : 0); + respPkt.setByteCount(0); + + respPkt.setTreeId(0); + respPkt.setUserId(0); + + // Set the various flags + + int flags = respPkt.getFlags(); + flags &= ~SMBSrvPacket.FLG_CASELESS; + respPkt.setFlags(flags); + + int flags2 = SMBSrvPacket.FLG2_LONGFILENAMES; + if (isUni) + flags2 += SMBSrvPacket.FLG2_UNICODE; + respPkt.setFlags2(flags2); + + // Pack the OS, dialect and domain name strings. + + int pos = respPkt.getByteOffset(); + buf = respPkt.getBuffer(); + + 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()); + } + + /** + * Return the encryption key/challenge length + * + * @return int + */ + public int getEncryptionKeyLength() + { + return STANDARD_CHALLENGE_LEN; + } + + /** + * 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; + } + + /** + * Determine if guest access is allowed + * + * @return boolean + */ + public final boolean allowGuest() + { + return m_allowGuest; + } + + /** + * Return the guest user name + * + * @return String + */ + public final String getGuestUserName() + { + return m_guestUserName; + } + + /** + * Determine if unknown users should be mapped to the guest account + * + * @return boolean + */ + public final boolean mapUnknownUserToGuest() + { + return m_mapToGuest; + } + + /** + * Enable/disable the guest account + * + * @param ena Enable the guest account if true, only allow defined user accounts access if false + */ + public final void setAllowGuest(boolean ena) + { + m_allowGuest = ena; + } + + /** + * Set the guest user name + * + * @param guest String + */ + public final void setGuestUserName( String guest) + { + m_guestUserName = guest; + } + + /** + * Enable/disable mapping of unknown users to the guest account + * + * @param ena Enable mapping of unknown users to the guest if true + */ + public final void setMapToGuest( boolean ena) + { + m_mapToGuest = ena; + } + + /** + * Set the security mode flags + * + * @param flg int + */ + protected final void setSecurityMode(int flg) + { + m_securityMode = flg; + } + + /** + * Close the authenticator, perform any cleanup + */ + public void closeAuthenticator() + { + // Override if cleanup required + } + + /** + * Validate a password by encrypting the plain text password using the specified encryption key + * and encryption algorithm. + * + * @param plainPwd String + * @param encryptedPwd String + * @param encryptKey byte[] + * @param alg int + * @param userName String + * @param domain String + * @return boolean + */ + protected final boolean validatePassword(String plainPwd, byte[] encryptedPwd, byte[] encryptKey, int alg, String userName, String domain) + { + + // Generate an encrypted version of the plain text password + + byte[] encPwd = generateEncryptedPassword(plainPwd != null ? plainPwd : "", encryptKey, alg, userName, domain); + + // Compare the generated password with the received password + + if (encPwd != null && encryptedPwd != null && encPwd.length == STANDARD_PASSWORD_LEN + && encryptedPwd.length == STANDARD_PASSWORD_LEN) + { + + // Compare the password arrays + + for (int i = 0; i < STANDARD_PASSWORD_LEN; i++) + if (encPwd[i] != encryptedPwd[i]) + return false; + + // Password is valid + + return true; + } + + // User or password is invalid + + return false; + } + + /** + * Convert the password string to a byte array + * + * @param pwd String + * @return byte[] + */ + + protected final byte[] convertPassword(String pwd) + { + + // Create a padded/truncated 14 character string + + StringBuffer p14str = new StringBuffer(); + p14str.append(pwd); + if (p14str.length() > 14) + p14str.setLength(14); + else + { + while (p14str.length() < 14) + p14str.append((char) 0x00); + } + + // Convert the P14 string to an array of bytes. Allocate the return 16 byte array. + + return p14str.toString().getBytes(); + } + + /** + * Return the password encryptor + * + * @return PasswordEncryptor + */ + protected final PasswordEncryptor getEncryptor() + { + return m_encryptor; + } + + /** + * Return the authentication status as a string + * + * @param sts int + * @return String + */ + protected final String getStatusAsString(int sts) + { + String str = null; + + switch ( sts) + { + case AUTH_ALLOW: + str = "Allow"; + break; + case AUTH_DISALLOW: + str = "Disallow"; + break; + case AUTH_GUEST: + str = "Guest"; + break; + case AUTH_BADPASSWORD: + str = "BadPassword"; + break; + case AUTH_BADUSER: + str = "BadUser"; + break; + } + + return str; + } + + /** + * Logon using the guest user account + * + * @param client ClientInfo + * @param sess SrvSession + */ + protected final void doGuestLogon( ClientInfo client, SrvSession sess) + { + // Get a guest authentication token + + m_authenticationService.authenticateAsGuest(); + Authentication authToken = m_authComponent.getCurrentAuthentication(); + + client.setAuthenticationToken( authToken); + + // Set the home folder for the guest user + + client.setUserName( getGuestUserName()); + getHomeFolderForUser( client); + + // Mark the client as being a guest logon + + client.setGuest( true); + + // Create a dynamic share for the guest user + // Create the disk driver and context + + DiskInterface diskDrv = m_config.getDiskInterface(); + DiskDeviceContext diskCtx = new ContentContext("", "", client.getHomeFolder()); + + // Default the filesystem to look like an 80Gb sized disk with 90% free space + + diskCtx.setDiskInformation(new SrvDiskInfo(2560, 64, 512, 2304)); + + // Create a temporary shared device for the users home directory + + sess.addDynamicShare( new DiskSharedDevice( client.getUserName(), diskDrv, diskCtx, SharedDevice.Temporary)); + } + + /** + * Get the home folder for the user + * + * @param client ClientInfo + */ + protected final void getHomeFolderForUser(ClientInfo client) + { + // Get the home folder for the user + + UserTransaction tx = m_transactionService.getUserTransaction(); + NodeRef homeSpaceRef = null; + + try + { + tx.begin(); + homeSpaceRef = (NodeRef) m_nodeService.getProperty(m_personService.getPerson(client.getUserName()), + ContentModel.PROP_HOMEFOLDER); + client.setHomeFolder( homeSpaceRef); + tx.commit(); + } + catch (Throwable ex) + { + try + { + tx.rollback(); + } + catch (Throwable ex2) + { + logger.error("Failed to rollback transaction", ex2); + } + + // Re-throw the exception + if (ex instanceof RuntimeException) + { + throw (RuntimeException) ex; + } + else + { + throw new RuntimeException("Error during execution of transaction.", ex); + } + } + } + +} \ No newline at end of file diff --git a/source/java/org/alfresco/filesys/server/auth/ClientInfo.java b/source/java/org/alfresco/filesys/server/auth/ClientInfo.java index d2418ae5fa..56eec14aeb 100644 --- a/source/java/org/alfresco/filesys/server/auth/ClientInfo.java +++ b/source/java/org/alfresco/filesys/server/auth/ClientInfo.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005 Alfresco, Inc. + * Copyright (C) 2005-2006 Alfresco, Inc. * * Licensed under the Mozilla Public License version 1.1 * with a permitted attribution clause. You may obtain a @@ -74,6 +74,14 @@ public class ClientInfo // Home folder node private NodeRef m_homeNode; + + /** + * Default constructor + */ + public ClientInfo() + { + setUserName(""); + } /** * Class constructor diff --git a/source/java/org/alfresco/filesys/server/auth/DefaultAuthenticator.java b/source/java/org/alfresco/filesys/server/auth/DefaultAuthenticator.java deleted file mode 100644 index 952f234123..0000000000 --- a/source/java/org/alfresco/filesys/server/auth/DefaultAuthenticator.java +++ /dev/null @@ -1,120 +0,0 @@ -/* - * Copyright (C) 2005 Alfresco, Inc. - * - * Licensed under the Mozilla Public License version 1.1 - * with a permitted attribution clause. You may obtain a - * copy of the License at - * - * http://www.alfresco.org/legal/license.txt - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, - * either express or implied. See the License for the specific - * language governing permissions and limitations under the - * License. - */ -package org.alfresco.filesys.server.auth; - -import org.alfresco.config.ConfigElement; -import org.alfresco.filesys.server.SrvSession; -import org.alfresco.filesys.server.config.InvalidConfigurationException; -import org.alfresco.filesys.server.config.ServerConfiguration; -import org.alfresco.filesys.server.core.SharedDevice; - -/** - *
- * Default authenticator class. - *
- * The default authenticator implementation enables user level security mode and allows any user to - * connect to the server. - */ -public class DefaultAuthenticator extends SrvAuthenticator -{ - - // Server configuration - - private ServerConfiguration m_config; - - /** - * Class constructor - */ - public DefaultAuthenticator() - { - setAccessMode(USER_MODE); - setEncryptedPasswords(true); - } - - /** - * Allow any user to access the server - * - * @param client Client details. - * @param share Shared device the user is connecting to. - * @param pwd Share level password. - * @param sess Server session - * @return int - */ - public int authenticateShareConnect(ClientInfo client, SharedDevice share, String pwd, SrvSession sess) - { - return Writeable; - } - - /** - * Allow any user to access the server. - * - * @param client Client details. - * @param sess Server session - * @param alg Encryption algorithm - * @return int - */ - public int authenticateUser(ClientInfo client, SrvSession sess, int alg) - { - return AUTH_ALLOW; - } - - /** - * The default authenticator does not use encrypted passwords. - * - * @param sess SrvSession - * @return byte[] - */ - public byte[] getChallengeKey(SrvSession sess) - { - return null; - } - - /** - * Search for the requried user account details in the defined user list - * - * @param user String - * @return UserAccount - */ - public UserAccount getUserDetails(String user) - { - - // Get the user account list from the configuration - - UserAccountList userList = m_config.getUserAccounts(); - if (userList == null || userList.numberOfUsers() == 0) - return null; - - // Search for the required user account record - - return userList.findUser(user); - } - - /** - * Initialzie the authenticator - * - * @param config ServerConfiguration - * @param params ConfigElement - * @exception InvalidConfigurationException - */ - public void initialize(ServerConfiguration config, ConfigElement params) throws InvalidConfigurationException - { - - // Save the server configuration so we can access the defined user list - - m_config = config; - } -} \ No newline at end of file diff --git a/source/java/org/alfresco/filesys/server/auth/EnterpriseCifsAuthenticator.java b/source/java/org/alfresco/filesys/server/auth/EnterpriseCifsAuthenticator.java new file mode 100644 index 0000000000..3bf487c3ff --- /dev/null +++ b/source/java/org/alfresco/filesys/server/auth/EnterpriseCifsAuthenticator.java @@ -0,0 +1,2017 @@ +/* + * Copyright (C) 2005-2006 Alfresco, Inc. + * + * Licensed under the Mozilla Public License version 1.1 + * with a permitted attribution clause. You may obtain a + * copy of the License at + * + * http://www.alfresco.org/legal/license.txt + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, + * either express or implied. See the License for the specific + * language governing permissions and limitations under the + * License. + */ +package org.alfresco.filesys.server.auth; + +import java.io.IOException; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; +import java.util.Vector; + +import javax.security.auth.Subject; +import javax.security.auth.callback.Callback; +import javax.security.auth.callback.CallbackHandler; +import javax.security.auth.callback.NameCallback; +import javax.security.auth.callback.PasswordCallback; +import javax.security.auth.callback.UnsupportedCallbackException; +import javax.security.auth.login.LoginContext; +import javax.security.auth.login.LoginException; +import javax.security.sasl.RealmCallback; + +import org.alfresco.config.ConfigElement; +import org.alfresco.error.AlfrescoRuntimeException; +import org.alfresco.filesys.server.auth.AuthenticatorException; +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.auth.kerberos.KerberosDetails; +import org.alfresco.filesys.server.auth.kerberos.SessionSetupPrivilegedAction; +import org.alfresco.filesys.server.auth.ntlm.NTLM; +import org.alfresco.filesys.server.auth.ntlm.NTLMMessage; +import org.alfresco.filesys.server.auth.ntlm.NTLMv2Blob; +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.auth.spnego.NegTokenInit; +import org.alfresco.filesys.server.auth.spnego.NegTokenTarg; +import org.alfresco.filesys.server.auth.spnego.OID; +import org.alfresco.filesys.server.auth.spnego.SPNEGO; +import org.alfresco.filesys.server.config.InvalidConfigurationException; +import org.alfresco.filesys.server.config.ServerConfiguration; +import org.alfresco.filesys.smb.Capability; +import org.alfresco.filesys.smb.SMBStatus; +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.util.DataPacker; +import org.alfresco.filesys.util.HexDump; +import org.alfresco.repo.security.authentication.NTLMMode; +import org.ietf.jgss.Oid; + +/** + * Enterprise CIFS Authenticator Class + * + *
CIFS authenticator that supports NTLMSSP and Kerberos logins.
+ *
+ * @author gkspencer
+ */
+public class EnterpriseCifsAuthenticator extends CifsAuthenticator implements CallbackHandler
+{
+ // Constants
+ //
+ // Default login configuration entry name
+
+ private static final String LoginConfigEntry = "AlfrescoCIFS";
+
+ // 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.FlagNTLM2Key +
+ NTLM.FlagNegotiateUnicode;
+
+ // Use NTLMSSP or SPNEGO
+
+ private boolean m_useRawNTLMSSP;
+
+ // Flag to control whether NTLMv1 is accepted
+
+ private boolean m_acceptNTLMv1;
+
+ // Kerberos settings
+ //
+ // Account name and password for server ticket
+ //
+ // The account name must be built from the CIFS server name, in the format :-
+ //
+ // cifs/
- * Local Authenticator Class.
- *
- * The local authenticator implementation enables user level security mode and uses the user account
- * list that is part of the server configuration to determine if a user is allowed to access the
- * server/share.
- *
- * Note: Switching off encrypted password support will cause later NT4 service pack releases and
- * Win2000 to refuse to connect to the server without a registry update on the client.
- */
-public class LocalAuthenticator extends SrvAuthenticator
-{
-
- // Random number generator used to generate challenge keys
-
- private Random m_random = new Random(System.currentTimeMillis());
-
- // Server configuration
-
- private ServerConfiguration m_config;
-
- /**
- * Local Authenticator Constructor
- *
- * Default to user mode security with encrypted password support.
- */
- public LocalAuthenticator()
- {
- setAccessMode(SrvAuthenticator.USER_MODE);
- setEncryptedPasswords(true);
- }
-
- /**
- * Authenticate the connection to a share
- *
- * @param client ClienInfo
- * @param share SharedDevice
- * @param pwd Share level password.
- * @param sess Server session
- * @return Authentication status.
- */
- public int authenticateShareConnect(ClientInfo client, SharedDevice share, String pwd, SrvSession sess)
- {
-
- // If the server is in share mode security allow the user access
-
- if (this.getAccessMode() == SHARE_MODE)
- return SrvAuthenticator.Writeable;
-
- // Check if the IPC$ share is being accessed
-
- if (share.getType() == ShareType.ADMINPIPE)
- return SrvAuthenticator.Writeable;
-
- // Check if the user is allowed to access the specified shared device
- //
- // If a user does not have access to the requested share the connection will still be
- // allowed
- // but any attempts to access files or search directories will result in a 'no access
- // rights'
- // error being returned to the client.
-
- UserAccount user = null;
- if (client != null)
- user = getUserDetails(client.getUserName());
-
- if (user == null)
- {
-
- // Check if the guest account is enabled
-
- return allowGuest() ? SrvAuthenticator.Writeable : SrvAuthenticator.NoAccess;
- }
- else if (user.hasShare(share.getName()) == false)
- return SrvAuthenticator.NoAccess;
-
- // Allow user to access this share
-
- return SrvAuthenticator.Writeable;
- }
-
- /**
- * Authenticate a user
- *
- * @param client Client information
- * @param sess Server session
- * @param alg Encryption algorithm
- */
- public int authenticateUser(ClientInfo client, SrvSession sess, int alg)
- {
-
- // Check if the user exists in the user list
-
- UserAccount userAcc = getUserDetails(client.getUserName());
- if (userAcc != null)
- {
-
- // Validate the password
-
- boolean authSts = false;
-
- if (client.getPassword() != null)
- {
-
- // Validate using the Unicode password
-
- authSts = validatePassword(userAcc.getPassword(), client.getPassword(), sess.getChallengeKey(), alg);
- }
- else if (client.hasANSIPassword())
- {
-
- // Validate using the ANSI password with the LanMan encryption
-
- authSts = validatePassword(userAcc.getPassword(), client.getANSIPassword(), sess.getChallengeKey(),
- SrvAuthenticator.LANMAN);
- }
-
- // Return the authentication status
-
- return authSts == true ? SrvAuthenticator.AUTH_ALLOW : SrvAuthenticator.AUTH_BADPASSWORD;
- }
-
- // Check if this is an SMB/CIFS null session logon.
- //
- // The null session will only be allowed to connect to the IPC$ named pipe share.
-
- if (client.isNullSession() && sess instanceof SMBSrvSession)
- return SrvAuthenticator.AUTH_ALLOW;
-
- // Unknown user
-
- return allowGuest() ? SrvAuthenticator.AUTH_GUEST : SrvAuthenticator.AUTH_DISALLOW;
- }
-
- /**
- * Generate a challenge key
- *
- * @param sess SrvSession
- * @return byte[]
- */
- public byte[] getChallengeKey(SrvSession sess)
- {
-
- // Generate a new challenge key, pack the key and return
-
- byte[] key = new byte[8];
-
- DataPacker.putIntelLong(m_random.nextLong(), key, 0);
- return key;
- }
-
- /**
- * Search for the requried user account details in the defined user list
- *
- * @param user String
- * @return UserAccount
- */
- public UserAccount getUserDetails(String user)
- {
-
- // Get the user account list from the configuration
-
- UserAccountList userList = m_config.getUserAccounts();
- if (userList == null || userList.numberOfUsers() == 0)
- return null;
-
- // Search for the required user account record
-
- return userList.findUser(user);
- }
-
- /**
- * Initialize the authenticator
- *
- * @param config ServerConfiguration
- * @param params ConfigElement
- * @exception InvalidConfigurationException
- */
- public void initialize(ServerConfiguration config, ConfigElement params) throws InvalidConfigurationException
- {
-
- // Save the server configuration so we can access the defined user list
-
- m_config = config;
- }
-}
\ No newline at end of file
diff --git a/source/java/org/alfresco/filesys/server/auth/NTLanManAuthContext.java b/source/java/org/alfresco/filesys/server/auth/NTLanManAuthContext.java
new file mode 100644
index 0000000000..4e1efa12d7
--- /dev/null
+++ b/source/java/org/alfresco/filesys/server/auth/NTLanManAuthContext.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2005-2006 Alfresco, Inc.
+ *
+ * Licensed under the Mozilla Public License version 1.1
+ * with a permitted attribution clause. You may obtain a
+ * copy of the License at
+ *
+ * http://www.alfresco.org/legal/license.txt
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
+ * either express or implied. See the License for the specific
+ * language governing permissions and limitations under the
+ * License.
+ */
+package org.alfresco.filesys.server.auth;
+
+import java.util.Random;
+
+import org.alfresco.filesys.util.DataPacker;
+import org.alfresco.filesys.util.HexDump;
+
+/**
+ * NTLM1/LanMan CIFS Authentication Context Class
+ *
+ * Holds the challenge sent to the client during the negotiate phase that is used to verify the hashed password
+ * in the session setup phase.
+ *
+ * @author gkspencer
+ */
+public class NTLanManAuthContext extends AuthContext
+{
+ // Random number generator used to generate challenge
+
+ private static Random m_random = new Random(System.currentTimeMillis());
+
+ // Challenge sent to client
+
+ private byte[] m_challenge;
+
+ /**
+ * Class constructor
+ */
+ public NTLanManAuthContext()
+ {
+ // Generate a new challenge key, pack the key and return
+
+ m_challenge = new byte[8];
+ DataPacker.putIntelLong(m_random.nextLong(), m_challenge, 0);
+ }
+
+ /**
+ * Class constructor
+ *
+ * @param challenge byte[]
+ */
+ public NTLanManAuthContext( byte[] challenge)
+ {
+ m_challenge = challenge;
+ }
+
+ /**
+ * Get the challenge
+ *
+ * return byte[]
+ */
+ public final byte[] getChallenge()
+ {
+ return m_challenge;
+ }
+
+ /**
+ * Return the CIFS authentication context as a string
+ *
+ * @return String
+ */
+ public String toString()
+ {
+ StringBuilder str = new StringBuilder();
+
+ str.append("[NTLM,Challenge=");
+ str.append(HexDump.hexString(m_challenge));
+ str.append("]");
+
+ return str.toString();
+ }
+}
diff --git a/source/java/org/alfresco/filesys/server/auth/PasswordEncryptor.java b/source/java/org/alfresco/filesys/server/auth/PasswordEncryptor.java
index cde91315a5..7762907b16 100644
--- a/source/java/org/alfresco/filesys/server/auth/PasswordEncryptor.java
+++ b/source/java/org/alfresco/filesys/server/auth/PasswordEncryptor.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2005 Alfresco, Inc.
+ * Copyright (C) 2005-2006 Alfresco, Inc.
*
* Licensed under the Mozilla Public License version 1.1
* with a permitted attribution clause. You may obtain a
@@ -24,6 +24,7 @@ import java.security.NoSuchAlgorithmException;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
+import javax.crypto.Mac;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.SecretKeySpec;
@@ -75,6 +76,14 @@ public class PasswordEncryptor
// Check if DES is available
Cipher.getInstance("DES");
+
+ // Check if HMAC-MD5 is available
+
+ Mac.getInstance("HMACMD5");
+
+ // Indicate required algorithms are available
+
+ algOK = true;
}
catch (NoSuchAlgorithmException ex)
{
@@ -95,13 +104,15 @@ public class PasswordEncryptor
* @param plainPwd Plaintext password string
* @param encryptKey byte[] Encryption key
* @param alg int Encryption algorithm
+ * @param userName String
+ * @param domain String
* @return byte[] Encrypted password
* @exception NoSuchAlgorithmException If a required encryption algorithm is not available
+ * @exception InvalidKeyException Key is invalid
*/
- public byte[] generateEncryptedPassword(String plainPwd, byte[] encryptKey, int alg)
- throws NoSuchAlgorithmException
+ public byte[] generateEncryptedPassword(String plainPwd, byte[] encryptKey, int alg, String userName, String domain)
+ throws NoSuchAlgorithmException, InvalidKeyException
{
-
// Get the password
String pwd = plainPwd;
@@ -150,6 +161,41 @@ public class PasswordEncryptor
// NTLM v2 encryption
case NTLM2:
+
+ // Get the MD4 hash of the plaintext password
+
+ byte[] md4Hash = generateEncryptedPassword( plainPwd, encryptKey, MD4, null, null);
+
+ // HMAC-MD5 the username + domain string using the MD4 hash as the key
+
+ Mac hmacMd5 = Mac.getInstance("HMACMD5");
+ SecretKeySpec key = new SecretKeySpec( md4Hash, 0, md4Hash.length, "MD5");
+
+ hmacMd5.init(key);
+
+ // Build the username + domain string and convert to bytes
+
+ StringBuilder str = new StringBuilder();
+
+ str.append( userName.toUpperCase());
+ str.append( domain.toUpperCase());
+
+ byte[] dataByts = null;
+
+ try
+ {
+ // Convert the string to a byte array
+
+ String dataStr = str.toString();
+ dataByts = dataStr.getBytes("UnicodeLittleUnmarked");
+ }
+ catch ( UnsupportedEncodingException ex)
+ {
+ }
+
+ // Encrypt the username+domain bytes to generate the NTLMv2 hash
+
+ encPwd = hmacMd5.doFinal( dataByts);
break;
// MD4 encryption
@@ -414,4 +460,46 @@ public class PasswordEncryptor
{
return P24(p21, c8);
}
+
+ /**
+ * NTLM2 encryption of the MD4 hashed password
+ *
+ * @param md4Hash byte[]
+ * @param userName String
+ * @param domain String
+ * @return byte[]
+ * @exception NoSuchAlgorithmException
+ */
+ public final byte[] doNTLM2Encryption(byte[] md4Hash, String userName, String domain)
+ throws NoSuchAlgorithmException, InvalidKeyException
+ {
+ // Use the MD4 hashed password as the key for HMAC-MD5
+
+ Mac hmacMd5 = Mac.getInstance("HMACMD5");
+ SecretKeySpec key = new SecretKeySpec(md4Hash, 0, md4Hash.length, "MD5");
+
+ hmacMd5.init( key);
+
+ // Build the data to be encrypted
+
+ StringBuilder str = new StringBuilder();
+
+ str.append(userName.toUpperCase());
+ str.append(domain.toUpperCase());
+
+ String dataStr = str.toString();
+ byte[] dataByts = null;
+
+ try
+ {
+ dataByts = dataStr.getBytes("UnicodeLittleUnmarked");
+ }
+ catch ( UnsupportedEncodingException ex)
+ {
+ }
+
+ // Encrypt the data
+
+ return hmacMd5.doFinal( dataByts);
+ }
}
diff --git a/source/java/org/alfresco/filesys/server/auth/SrvAuthenticator.java b/source/java/org/alfresco/filesys/server/auth/SrvAuthenticator.java
deleted file mode 100644
index 29283800fc..0000000000
--- a/source/java/org/alfresco/filesys/server/auth/SrvAuthenticator.java
+++ /dev/null
@@ -1,596 +0,0 @@
-/*
- * Copyright (C) 2005 Alfresco, Inc.
- *
- * Licensed under the Mozilla Public License version 1.1
- * with a permitted attribution clause. You may obtain a
- * copy of the License at
- *
- * http://www.alfresco.org/legal/license.txt
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
- * either express or implied. See the License for the specific
- * language governing permissions and limitations under the
- * License.
- */
-package org.alfresco.filesys.server.auth;
-
-import java.security.NoSuchAlgorithmException;
-import java.util.Random;
-
-import javax.transaction.UserTransaction;
-
-import net.sf.acegisecurity.Authentication;
-
-import org.alfresco.config.ConfigElement;
-import org.alfresco.filesys.server.SrvSession;
-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.server.filesys.DiskDeviceContext;
-import org.alfresco.filesys.server.filesys.DiskInterface;
-import org.alfresco.filesys.server.filesys.DiskSharedDevice;
-import org.alfresco.filesys.server.filesys.SrvDiskInfo;
-import org.alfresco.filesys.smb.server.repo.ContentContext;
-import org.alfresco.model.ContentModel;
-import org.alfresco.repo.security.authentication.AuthenticationComponent;
-import org.alfresco.repo.security.authentication.MD4PasswordEncoder;
-import org.alfresco.repo.security.authentication.MD4PasswordEncoderImpl;
-import org.alfresco.repo.security.authentication.NTLMMode;
-import org.alfresco.service.cmr.repository.NodeRef;
-import org.alfresco.service.cmr.repository.NodeService;
-import org.alfresco.service.cmr.security.AuthenticationService;
-import org.alfresco.service.cmr.security.PersonService;
-import org.alfresco.service.transaction.TransactionService;
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-
-/**
- *
- * An authenticator is used by the SMB server to authenticate users when in user level access mode
- * and authenticate requests to connect to a share when in share level access.
- */
-public abstract class SrvAuthenticator
-{
- // Logging
-
- protected static final Log logger = LogFactory.getLog("org.alfresco.smb.protocol.auth");
-
- // Encryption algorithm types
-
- public static final int LANMAN = PasswordEncryptor.LANMAN;
- public static final int NTLM1 = PasswordEncryptor.NTLM1;
- public static final int NTLM2 = PasswordEncryptor.NTLM2;
-
- // Authentication status values
-
- public static final int AUTH_ALLOW = 0;
- public static final int AUTH_GUEST = 0x10000000;
- public static final int AUTH_DISALLOW = -1;
- public static final int AUTH_BADPASSWORD = -2;
- public static final int AUTH_BADUSER = -3;
-
- // Share access permissions, returned by authenticateShareConnect()
-
- public static final int NoAccess = 0;
- public static final int ReadOnly = 1;
- public static final int Writeable = 2;
-
- // Server access mode
-
- public static final int SHARE_MODE = 0;
- public static final int USER_MODE = 1;
-
- // Standard encrypted password length
-
- public static final int STANDARD_PASSWORD_LEN = 24;
-
- // Default guest user name
-
- protected static final String GUEST_USERNAME = "guest";
-
- // Server access mode
-
- private int m_accessMode = SHARE_MODE;
-
- // Use encrypted password
-
- private boolean m_encryptPwd = false;
-
- // Password encryption algorithms
-
- private PasswordEncryptor m_encryptor = new PasswordEncryptor();
-
- // Flag to enable/disable the guest account, and control mapping of unknown users to the guest account
-
- private boolean m_allowGuest;
- private boolean m_mapToGuest;
-
- // Default guest user name
-
- private String m_guestUserName = GUEST_USERNAME;
-
- // Random number generator used to generate challenge keys
-
- protected Random m_random = new Random(System.currentTimeMillis());
-
- // Server configuration
-
- protected ServerConfiguration m_config;
-
- // Authentication component, used to access internal authentication functions
-
- protected AuthenticationComponent m_authComponent;
-
- // MD4 hash decoder
-
- protected MD4PasswordEncoder m_md4Encoder = new MD4PasswordEncoderImpl();
-
- // Various services required to get user information
-
- protected NodeService m_nodeService;
- protected PersonService m_personService;
- protected TransactionService m_transactionService;
- protected AuthenticationService m_authenticationService;
-
- /**
- * 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 SrvAuthenticator.Writeable;
- }
-
- /**
- * Authenticate a user. A user may be granted full access, guest access or no access.
- *
- * @param client User/client details from the session setup request.
- * @param sess Server session
- * @param alg Encryption algorithm
- * @return int Access level or disallow status.
- */
- public abstract int authenticateUser(ClientInfo client, SrvSession sess, int alg);
-
- /**
- * Return the user account details for the specified user
- *
- * @param user String
- * @return UserAccount
- */
- public UserAccount getUserDetails(String user)
- {
- return null;
- }
-
- /**
- * Authenticate a user using a plain text password.
- *
- * @param client User/client details from the session setup request.
- * @param sess Server session
- * @return int Access level or disallow status.
- * @throws InvalidConfigurationException
- */
- public final int authenticateUserPlainText(ClientInfo client, SrvSession sess)
- {
-
- // Get a challenge key
-
- sess.setChallengeKey(getChallengeKey(sess));
-
- if (sess.hasChallengeKey() == false)
- return SrvAuthenticator.AUTH_DISALLOW;
-
- // Get the plain text password
-
- String textPwd = client.getPasswordAsString();
- if (textPwd == null)
- textPwd = client.getANSIPasswordAsString();
-
- // Encrypt the password
-
- byte[] encPwd = generateEncryptedPassword(textPwd, sess.getChallengeKey(), SrvAuthenticator.NTLM1);
- client.setPassword(encPwd);
-
- // Authenticate the user
-
- return authenticateUser(client, sess, SrvAuthenticator.NTLM1);
- }
-
- /**
- * Initialize the authenticator
- *
- * @param config ServerConfiguration
- * @param params ConfigElement
- * @exception InvalidConfigurationException
- */
- public void initialize(ServerConfiguration config, ConfigElement params) throws InvalidConfigurationException
- {
- // Save the server configuration so we can access the authentication component
-
- m_config = config;
-
- // Check that the required authentication classes are available
-
- m_authComponent = m_config.getAuthenticationComponent();
-
- if ( m_authComponent == null)
- throw new InvalidConfigurationException("Authentication component not available");
-
- // Get hold of various services
-
- m_nodeService = config.getNodeService();
- m_personService = config.getPersonService();
- m_transactionService = config.getTransactionService();
- m_authenticationService = config.getAuthenticationService();
-
- // Set the guest user name
-
- setGuestUserName( m_authComponent.getGuestUserName());
-
- // Check that the authentication component is the required type for this authenticator
-
- if ( validateAuthenticationMode() == false)
- throw new InvalidConfigurationException("Required authentication mode not available");
- }
-
- /**
- * Validate that the authentication component supports the required mode
- *
- * @return boolean
- */
- protected boolean validateAuthenticationMode()
- {
- return true;
- }
-
- /**
- * Encrypt the plain text password with the specified encryption key using the specified
- * encryption algorithm.
- *
- * @return byte[]
- * @param plainPwd java.lang.String
- * @param encryptKey byte[]
- * @param alg int
- */
- protected final byte[] generateEncryptedPassword(String plainPwd, byte[] encryptKey, int alg)
- {
-
- // Use the password encryptor
-
- byte[] encPwd = null;
-
- try
- {
-
- // Encrypt the password
-
- encPwd = m_encryptor.generateEncryptedPassword(plainPwd, encryptKey, alg);
- }
- catch (NoSuchAlgorithmException ex)
- {
- }
-
- // Return the encrypted password
-
- return encPwd;
- }
-
- /**
- * Return the access mode of the server, either SHARE_MODE or USER_MODE.
- *
- * @return int
- */
- public final int getAccessMode()
- {
- return m_accessMode;
- }
-
- /**
- * Get a challenge encryption key, when encrypted passwords are enabled.
- *
- * @param sess SrvSession
- * @return byte[]
- */
- public abstract byte[] getChallengeKey(SrvSession sess);
-
- /**
- * Determine if encrypted passwords should be used.
- *
- * @return boolean
- */
- public final boolean hasEncryptPasswords()
- {
- return m_encryptPwd;
- }
-
- /**
- * Determine if guest access is allowed
- *
- * @return boolean
- */
- public final boolean allowGuest()
- {
- return m_allowGuest;
- }
-
- /**
- * Return the guest user name
- *
- * @return String
- */
- public final String getGuestUserName()
- {
- return m_guestUserName;
- }
-
- /**
- * Determine if unknown users should be mapped to the guest account
- *
- * @return boolean
- */
- public final boolean mapUnknownUserToGuest()
- {
- return m_mapToGuest;
- }
-
- /**
- * Set the access mode of the server.
- *
- * @param mode Either SHARE_MODE or USER_MODE.
- */
- public final void setAccessMode(int mode)
- {
- m_accessMode = mode;
- }
-
- /**
- * Set/clear the encrypted passwords flag.
- *
- * @param encFlag Encrypt passwords if true, use plain text passwords if false.
- */
- public final void setEncryptedPasswords(boolean encFlag)
- {
- m_encryptPwd = encFlag;
- }
-
- /**
- * Enable/disable the guest account
- *
- * @param ena Enable the guest account if true, only allow defined user accounts access if false
- */
- public final void setAllowGuest(boolean ena)
- {
- m_allowGuest = ena;
- }
-
- /**
- * Set the guest user name
- *
- * @param guest String
- */
- public final void setGuestUserName( String guest)
- {
- m_guestUserName = guest;
- }
-
- /**
- * Enable/disable mapping of unknown users to the guest account
- *
- * @param ena Enable mapping of unknown users to the guest if true
- */
- public final void setMapToGuest( boolean ena)
- {
- m_mapToGuest = ena;
- }
-
- /**
- * Close the authenticator, perform any cleanup
- */
- public void closeAuthenticator()
- {
- // Override if cleanup required
- }
-
- /**
- * Validate a password by encrypting the plain text password using the specified encryption key
- * and encryption algorithm.
- *
- * @return boolean
- * @param plainPwd java.lang.String
- * @param encryptedPwd java.lang.String
- * @param encryptKey byte[]
- * @param alg int
- */
- protected final boolean validatePassword(String plainPwd, byte[] encryptedPwd, byte[] encryptKey, int alg)
- {
-
- // Generate an encrypted version of the plain text password
-
- byte[] encPwd = generateEncryptedPassword(plainPwd != null ? plainPwd : "", encryptKey, alg);
-
- // Compare the generated password with the received password
-
- if (encPwd != null && encryptedPwd != null && encPwd.length == STANDARD_PASSWORD_LEN
- && encryptedPwd.length == STANDARD_PASSWORD_LEN)
- {
-
- // Compare the password arrays
-
- for (int i = 0; i < STANDARD_PASSWORD_LEN; i++)
- if (encPwd[i] != encryptedPwd[i])
- return false;
-
- // Password is valid
-
- return true;
- }
-
- // User or password is invalid
-
- return false;
- }
-
- /**
- * Convert the password string to a byte array
- *
- * @param pwd String
- * @return byte[]
- */
-
- protected final byte[] convertPassword(String pwd)
- {
-
- // Create a padded/truncated 14 character string
-
- StringBuffer p14str = new StringBuffer();
- p14str.append(pwd);
- if (p14str.length() > 14)
- p14str.setLength(14);
- else
- {
- while (p14str.length() < 14)
- p14str.append((char) 0x00);
- }
-
- // Convert the P14 string to an array of bytes. Allocate the return 16 byte array.
-
- return p14str.toString().getBytes();
- }
-
- /**
- * Return the password encryptor
- *
- * @return PasswordEncryptor
- */
- protected final PasswordEncryptor getEncryptor()
- {
- return m_encryptor;
- }
-
- /**
- * Return the authentication status as a string
- *
- * @param sts int
- * @return String
- */
- protected final String getStatusAsString(int sts)
- {
- String str = null;
-
- switch ( sts)
- {
- case AUTH_ALLOW:
- str = "Allow";
- break;
- case AUTH_DISALLOW:
- str = "Disallow";
- break;
- case AUTH_GUEST:
- str = "Guest";
- break;
- case AUTH_BADPASSWORD:
- str = "BadPassword";
- break;
- case AUTH_BADUSER:
- str = "BadUser";
- break;
- }
-
- return str;
- }
-
- /**
- * Logon using the guest user account
- *
- * @param client ClientInfo
- * @param sess SrvSession
- */
- protected final void doGuestLogon( ClientInfo client, SrvSession sess)
- {
- // Get a guest authentication token
-
- m_authenticationService.authenticateAsGuest();
- Authentication authToken = m_authComponent.getCurrentAuthentication();
-
- client.setAuthenticationToken( authToken);
-
- // Set the home folder for the guest user
-
- client.setUserName( getGuestUserName());
- getHomeFolderForUser( client);
-
- // Mark the client as being a guest logon
-
- client.setGuest( true);
-
- // Create a dynamic share for the guest user
- // Create the disk driver and context
-
- DiskInterface diskDrv = m_config.getDiskInterface();
- DiskDeviceContext diskCtx = new ContentContext("", "", client.getHomeFolder());
-
- // Default the filesystem to look like an 80Gb sized disk with 90% free space
-
- diskCtx.setDiskInformation(new SrvDiskInfo(2560, 64, 512, 2304));
-
- // Create a temporary shared device for the users home directory
-
- sess.addDynamicShare( new DiskSharedDevice( client.getUserName(), diskDrv, diskCtx, SharedDevice.Temporary));
- }
-
- /**
- * Get the home folder for the user
- *
- * @param client ClientInfo
- */
- protected final void getHomeFolderForUser(ClientInfo client)
- {
- // Get the home folder for the user
-
- UserTransaction tx = m_transactionService.getUserTransaction();
- NodeRef homeSpaceRef = null;
-
- try
- {
- tx.begin();
- homeSpaceRef = (NodeRef) m_nodeService.getProperty(m_personService.getPerson(client.getUserName()),
- ContentModel.PROP_HOMEFOLDER);
- client.setHomeFolder( homeSpaceRef);
- tx.commit();
- }
- catch (Throwable ex)
- {
- try
- {
- tx.rollback();
- }
- catch (Throwable ex2)
- {
- logger.error("Failed to rollback transaction", ex2);
- }
-
- // Re-throw the exception
- if (ex instanceof RuntimeException)
- {
- throw (RuntimeException) ex;
- }
- else
- {
- throw new RuntimeException("Error during execution of transaction.", ex);
- }
- }
- }
-
-}
\ No newline at end of file
diff --git a/source/java/org/alfresco/filesys/server/auth/UserAccount.java b/source/java/org/alfresco/filesys/server/auth/UserAccount.java
deleted file mode 100644
index 0171a68e2e..0000000000
--- a/source/java/org/alfresco/filesys/server/auth/UserAccount.java
+++ /dev/null
@@ -1,331 +0,0 @@
-/*
- * Copyright (C) 2005 Alfresco, Inc.
- *
- * Licensed under the Mozilla Public License version 1.1
- * with a permitted attribution clause. You may obtain a
- * copy of the License at
- *
- * http://www.alfresco.org/legal/license.txt
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
- * either express or implied. See the License for the specific
- * language governing permissions and limitations under the
- * License.
- */
-package org.alfresco.filesys.server.auth;
-
-import org.alfresco.filesys.util.StringList;
-
-/**
- * User Account Class
- *
- * Holds the details of a user account on the server.
- */
-public class UserAccount
-{
-
- // User name and password
-
- private String m_userName;
- private String m_password;
-
- // Real user name and comment
-
- private String m_realName;
- private String m_comment;
-
- // List of shares this user is allowed to use
-
- private StringList m_shares;
-
- // Administrator flag
-
- private boolean m_admin;
-
- // Home directory
-
- private String m_homeDir;
-
- /**
- * Default constructor
- */
- public UserAccount()
- {
- super();
- }
-
- /**
- * Create a user with the specified name and password.
- *
- * @param user String
- * @param pwd String
- */
- public UserAccount(String user, String pwd)
- {
- setUserName(user);
- setPassword(pwd);
- }
-
- /**
- * Add the specified share to the list of allowed shares for this user.
- *
- * @param shr java.lang.String
- */
- public final void addShare(String shr)
- {
- if (m_shares == null)
- m_shares = new StringList();
- m_shares.addString(shr);
- }
-
- /**
- * Determine if this user is allowed to access the specified share.
- *
- * @return boolean
- * @param shr java.lang.String
- */
- public final boolean allowsShare(String shr)
- {
- if (m_shares == null)
- return true;
- else if (m_shares.containsString(shr))
- return true;
- return false;
- }
-
- /**
- * Check if the user has a home direectory configured
- *
- * @return boolean
- */
- public final boolean hasHomeDirectory()
- {
- return m_homeDir != null ? true : false;
- }
-
- /**
- * Return the home directory for this user
- *
- * @return String
- */
- public final String getHomeDirectory()
- {
- return m_homeDir;
- }
-
- /**
- * Return the password
- *
- * @return java.lang.String
- */
- public final String getPassword()
- {
- return m_password;
- }
-
- /**
- * Return the user name.
- *
- * @return java.lang.String
- */
- public final String getUserName()
- {
- return m_userName;
- }
-
- /**
- * Return the real user name
- *
- * @return String
- */
- public final String getRealName()
- {
- return m_realName;
- }
-
- /**
- * Return the user comment
- *
- * @return String
- */
- public final String getComment()
- {
- return m_comment;
- }
-
- /**
- * Check if the specified share is listed in the users allowed list.
- *
- * @return boolean
- * @param shr java.lang.String
- */
- public final boolean hasShare(String shr)
- {
- if (m_shares != null && m_shares.containsString(shr) == false)
- return false;
- return true;
- }
-
- /**
- * Detemrine if this account is restricted to using certain shares only.
- *
- * @return boolean
- */
- public final boolean hasShareRestrictions()
- {
- return m_shares == null ? false : true;
- }
-
- /**
- * Return the list of shares
- *
- * @return StringList
- */
- public final StringList getShareList()
- {
- return m_shares;
- }
-
- /**
- * Determine if this user in an administrator.
- *
- * @return boolean
- */
- public final boolean isAdministrator()
- {
- return m_admin;
- }
-
- /**
- * Remove all shares from the list of restricted shares.
- */
- public final void removeAllShares()
- {
- m_shares = null;
- }
-
- /**
- * Remove the specified share from the list of shares this user is allowed to access.
- *
- * @param shr java.lang.String
- */
- public final void removeShare(String shr)
- {
-
- // Check if the share list has been allocated
-
- if (m_shares != null)
- {
-
- // Remove the share from the list
-
- m_shares.removeString(shr);
-
- // Check if the list is empty
-
- if (m_shares.numberOfStrings() == 0)
- m_shares = null;
- }
- }
-
- /**
- * Set the administrator flag.
- *
- * @param admin boolean
- */
- public final void setAdministrator(boolean admin)
- {
- m_admin = admin;
- }
-
- /**
- * Set the user home directory
- *
- * @param home String
- */
- public final void setHomeDirectory(String home)
- {
- m_homeDir = home;
- }
-
- /**
- * Set the password for this account.
- *
- * @param pwd java.lang.String
- */
- public final void setPassword(String pwd)
- {
- m_password = pwd;
- }
-
- /**
- * Set the user name.
- *
- * @param user java.lang.String
- */
- public final void setUserName(String user)
- {
- m_userName = user;
- }
-
- /**
- * Set the real user name
- *
- * @param name String
- */
- public final void setRealName(String name)
- {
- m_realName = name;
- }
-
- /**
- * Set the comment
- *
- * @param comment String
- */
- public final void setComment(String comment)
- {
- m_comment = comment;
- }
-
- /**
- * Return the user account as a string.
- *
- * @return java.lang.String
- */
- public String toString()
- {
- StringBuffer str = new StringBuffer();
-
- str.append("[");
- str.append(getUserName());
- str.append(":");
- str.append(getPassword());
-
- if (isAdministrator())
- str.append("(ADMIN)");
-
- str.append(",Real=");
-
- str.append(getRealName());
- str.append(",Comment=");
- str.append(getComment());
- str.append(",Allow=");
-
- if (m_shares == null)
- str.append(" Holds the Kerberos response token and session details about the user.
+ *
+ * @author gkspencer
+ */
+public class KerberosDetails
+{
+ // Source and target details
+
+ private String m_krbSource;
+ private String m_krbTarget;
+
+ // Kerberos response token
+
+ private byte[] m_krbResponse;
+
+ /**
+ * Class constructor
+ *
+ * @param source GSSName
+ * @param target GSSName
+ * @param response byte[]
+ */
+ public KerberosDetails(GSSName source, GSSName target, byte[] response)
+ {
+ m_krbSource = source.toString();
+ m_krbTarget = target.toString();
+
+ m_krbResponse = response;
+ }
+
+ /**
+ * Return the context initiator for the Kerberos authentication
+ *
+ * @return String
+ */
+ public final String getSourceName()
+ {
+ return m_krbSource;
+ }
+
+ /**
+ * Return the context acceptor for the Kerberos authentication
+ *
+ * @return String
+ */
+ public final String getTargetName()
+ {
+ return m_krbTarget;
+ }
+
+ /**
+ * Return the Kerberos response token
+ *
+ * @return byte[]
+ */
+ public final byte[] getResponseToken()
+ {
+ return m_krbResponse;
+ }
+
+ /**
+ * Parse the source name to return the user name part only
+ *
+ * @return String
+ */
+ public final String getUserName()
+ {
+ String userName = m_krbSource;
+
+ if ( m_krbSource != null)
+ {
+ int pos = m_krbSource.indexOf( '@');
+ if ( pos != -1)
+ {
+ userName = m_krbSource.substring(0, pos);
+ }
+ }
+
+ return userName;
+ }
+
+ /**
+ * Return the response token length
+ *
+ * @return int
+ */
+ public final int getResponseLength()
+ {
+ return m_krbResponse != null ? m_krbResponse.length : 0;
+ }
+
+ /**
+ * Return the Kerberos authentication details as a string
+ *
+ * @return String
+ */
+ public String toString()
+ {
+ StringBuilder str = new StringBuilder();
+
+ str.append("[Source=");
+ str.append(getSourceName());
+ str.append(",Target=");
+ str.append(getTargetName());
+ str.append(":Response=");
+ str.append(getResponseLength());
+ str.append(" bytes]");
+
+ return str.toString();
+ }
+}
diff --git a/source/java/org/alfresco/filesys/server/auth/kerberos/SessionSetupPrivilegedAction.java b/source/java/org/alfresco/filesys/server/auth/kerberos/SessionSetupPrivilegedAction.java
new file mode 100644
index 0000000000..e2077a6f51
--- /dev/null
+++ b/source/java/org/alfresco/filesys/server/auth/kerberos/SessionSetupPrivilegedAction.java
@@ -0,0 +1,113 @@
+/*
+ * Copyright (C) 2005-2006 Alfresco, Inc.
+ *
+ * Licensed under the Mozilla Public License version 1.1
+ * with a permitted attribution clause. You may obtain a
+ * copy of the License at
+ *
+ * http://www.alfresco.org/legal/license.txt
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
+ * either express or implied. See the License for the specific
+ * language governing permissions and limitations under the
+ * License.
+ */
+package org.alfresco.filesys.server.auth.kerberos;
+
+import java.security.PrivilegedAction;
+
+import org.alfresco.filesys.server.auth.spnego.OID;
+import org.ietf.jgss.GSSContext;
+import org.ietf.jgss.GSSCredential;
+import org.ietf.jgss.GSSException;
+import org.ietf.jgss.GSSManager;
+import org.ietf.jgss.GSSName;
+
+/**
+ * Session Setup Privileged Action Class
+ *
+ * Handle the processing of a received SPNEGO packet in the context of the CIFS server.
+ *
+ * @author gkspencer
+ */
+public class SessionSetupPrivilegedAction implements PrivilegedAction
+{
+ // Received security blob details
+
+ private byte[] m_secBlob;
+ private int m_secOffset;
+ private int m_secLen;
+
+ // CIFS server account name
+
+ private String m_accountName;
+
+ /**
+ * Class constructor
+ *
+ * @param accountName String
+ * @param secBlob byte[]
+ */
+ public SessionSetupPrivilegedAction ( String accountName, byte[] secBlob)
+ {
+ m_accountName = accountName;
+
+ m_secBlob = secBlob;
+ m_secOffset = 0;
+ m_secLen = secBlob.length;
+ }
+
+ /**
+ * Class constructor
+ *
+ * @param accountName String
+ * @param secBlob byte[]
+ * @param secOffset int
+ * @param secLen int
+ */
+ public SessionSetupPrivilegedAction ( String accountName, byte[] secBlob, int secOffset, int secLen)
+ {
+ m_accountName = accountName;
+
+ m_secBlob = secBlob;
+ m_secOffset = secOffset;
+ m_secLen = secLen;
+ }
+
+ /**
+ * Run the privileged action
+ */
+ public Object run()
+ {
+ KerberosDetails krbDetails = null;
+
+ try
+ {
+ GSSManager gssManager = GSSManager.getInstance();
+ GSSName serverGSSName = gssManager.createName(m_accountName, GSSName.NT_USER_NAME);
+ GSSCredential serverGSSCreds = gssManager.createCredential( serverGSSName, GSSCredential.INDEFINITE_LIFETIME,
+ OID.KERBEROS5, GSSCredential.ACCEPT_ONLY);
+
+ GSSContext serverGSSContext = gssManager.createContext( serverGSSCreds);
+
+ // Accept the incoming security blob and generate the response blob
+
+ byte[] respBlob = serverGSSContext.acceptSecContext( m_secBlob, m_secOffset, m_secLen);
+
+ // Create the Kerberos response details
+
+ krbDetails = new KerberosDetails( serverGSSContext.getSrcName(), serverGSSContext.getTargName(), respBlob);
+ }
+ catch (GSSException ex)
+ {
+ System.out.println("GSSException: " + ex.getMajorString());
+ System.out.println(" " + ex.getMessage());
+ }
+
+ // Return the Kerberos response
+
+ return krbDetails;
+ }
+}
diff --git a/source/java/org/alfresco/filesys/server/auth/ntlm/AlfrescoAuthenticator.java b/source/java/org/alfresco/filesys/server/auth/ntlm/AlfrescoAuthenticator.java
index 3324f65f0c..9a65f8fea6 100644
--- a/source/java/org/alfresco/filesys/server/auth/ntlm/AlfrescoAuthenticator.java
+++ b/source/java/org/alfresco/filesys/server/auth/ntlm/AlfrescoAuthenticator.java
@@ -20,8 +20,9 @@ import java.security.NoSuchAlgorithmException;
import net.sf.acegisecurity.Authentication;
import org.alfresco.filesys.server.SrvSession;
+import org.alfresco.filesys.server.auth.CifsAuthenticator;
import org.alfresco.filesys.server.auth.ClientInfo;
-import org.alfresco.filesys.server.auth.SrvAuthenticator;
+import org.alfresco.filesys.server.auth.NTLanManAuthContext;
import org.alfresco.filesys.smb.server.SMBSrvSession;
import org.alfresco.filesys.util.DataPacker;
import org.alfresco.repo.security.authentication.NTLMMode;
@@ -38,7 +39,7 @@ import org.alfresco.repo.security.authentication.ntlm.NTLMPassthruToken;
*
* @author GKSpencer
*/
-public class AlfrescoAuthenticator extends SrvAuthenticator
+public class AlfrescoAuthenticator extends CifsAuthenticator
{
/**
* Default Constructor
@@ -47,8 +48,6 @@ public class AlfrescoAuthenticator extends SrvAuthenticator
*/
public AlfrescoAuthenticator()
{
- setAccessMode(SrvAuthenticator.USER_MODE);
- setEncryptedPasswords(true);
}
/**
@@ -86,7 +85,7 @@ public class AlfrescoAuthenticator extends SrvAuthenticator
if ( logger.isDebugEnabled())
logger.debug("Null CIFS logon allowed");
- return SrvAuthenticator.AUTH_ALLOW;
+ return CifsAuthenticator.AUTH_ALLOW;
}
// Check if the client is already authenticated, and it is not a null logon
@@ -196,12 +195,13 @@ public class AlfrescoAuthenticator extends SrvAuthenticator
// Check if the client is already authenticated, and it is not a null logon
- if ( sess.hasClientInformation() && sess.getClientInformation().getAuthenticationToken() != null &&
+ if ( sess.hasAuthenticationContext() && sess.hasAuthenticationToken() &&
sess.getClientInformation().getLogonType() != ClientInfo.LogonNull)
{
// Return the previous challenge, user is already authenticated
-
- key = sess.getChallengeKey();
+
+ NTLanManAuthContext authCtx = (NTLanManAuthContext) sess.getAuthenticationContext();
+ key = authCtx.getChallenge();
// DEBUG
@@ -260,7 +260,7 @@ public class AlfrescoAuthenticator extends SrvAuthenticator
// Check if the client has supplied an NTLM hashed password, if not then do not allow access
if ( client.getPassword() == null)
- return SrvAuthenticator.AUTH_BADPASSWORD;
+ return CifsAuthenticator.AUTH_BADPASSWORD;
try
{
@@ -270,21 +270,30 @@ public class AlfrescoAuthenticator extends SrvAuthenticator
byte[] md4byts = m_md4Encoder.decodeHash(md4hash);
System.arraycopy(md4byts, 0, p21, 0, 16);
+ // Get the challenge that was sent to the client
+
+ NTLanManAuthContext authCtx = null;
+
+ if ( sess.hasAuthenticationContext() && sess.getAuthenticationContext() instanceof NTLanManAuthContext)
+ authCtx = (NTLanManAuthContext) sess.getAuthenticationContext();
+ else
+ return CifsAuthenticator.AUTH_DISALLOW;
+
// Generate the local hash of the password using the same challenge
- byte[] localHash = getEncryptor().doNTLM1Encryption(p21, sess.getChallengeKey());
+ byte[] localHash = getEncryptor().doNTLM1Encryption(p21, authCtx.getChallenge());
// Validate the password
byte[] clientHash = client.getPassword();
if ( clientHash == null || clientHash.length != localHash.length)
- return SrvAuthenticator.AUTH_BADPASSWORD;
+ return CifsAuthenticator.AUTH_BADPASSWORD;
for ( int i = 0; i < clientHash.length; i++)
{
if ( clientHash[i] != localHash[i])
- return SrvAuthenticator.AUTH_BADPASSWORD;
+ return CifsAuthenticator.AUTH_BADPASSWORD;
}
// Set the current user to be authenticated, save the authentication token
@@ -297,7 +306,7 @@ public class AlfrescoAuthenticator extends SrvAuthenticator
// Passwords match, grant access
- return SrvAuthenticator.AUTH_ALLOW;
+ return CifsAuthenticator.AUTH_ALLOW;
}
catch (NoSuchAlgorithmException ex)
{
@@ -305,7 +314,7 @@ public class AlfrescoAuthenticator extends SrvAuthenticator
// Error during password check, do not allow access
- return SrvAuthenticator.AUTH_DISALLOW;
+ return CifsAuthenticator.AUTH_DISALLOW;
}
// Check if this is an SMB/CIFS null session logon.
@@ -313,11 +322,11 @@ public class AlfrescoAuthenticator extends SrvAuthenticator
// The null session will only be allowed to connect to the IPC$ named pipe share.
if (client.isNullSession() && sess instanceof SMBSrvSession)
- return SrvAuthenticator.AUTH_ALLOW;
+ return CifsAuthenticator.AUTH_ALLOW;
// User does not exist, check if guest access is allowed
- return allowGuest() ? SrvAuthenticator.AUTH_GUEST : SrvAuthenticator.AUTH_DISALLOW;
+ return allowGuest() ? CifsAuthenticator.AUTH_GUEST : CifsAuthenticator.AUTH_DISALLOW;
}
/**
@@ -335,11 +344,11 @@ public class AlfrescoAuthenticator extends SrvAuthenticator
NTLMPassthruToken authToken = (NTLMPassthruToken) sess.getAuthenticationToken();
if ( authToken == null)
- return SrvAuthenticator.AUTH_DISALLOW;
+ return CifsAuthenticator.AUTH_DISALLOW;
// Get the appropriate hashed password for the algorithm
- int authSts = SrvAuthenticator.AUTH_DISALLOW;
+ int authSts = CifsAuthenticator.AUTH_DISALLOW;
byte[] hashedPassword = null;
if ( alg == NTLM1)
@@ -350,7 +359,7 @@ public class AlfrescoAuthenticator extends SrvAuthenticator
{
// Invalid/unsupported algorithm specified
- return SrvAuthenticator.AUTH_DISALLOW;
+ return CifsAuthenticator.AUTH_DISALLOW;
}
// Set the username and hashed password in the authentication token
@@ -379,7 +388,7 @@ public class AlfrescoAuthenticator extends SrvAuthenticator
// Allow the user access as a guest
- authSts = SrvAuthenticator.AUTH_GUEST;
+ authSts = CifsAuthenticator.AUTH_GUEST;
}
}
else
@@ -387,7 +396,7 @@ public class AlfrescoAuthenticator extends SrvAuthenticator
// Allow the user full access to the server
- authSts = SrvAuthenticator.AUTH_ALLOW;
+ authSts = CifsAuthenticator.AUTH_ALLOW;
}
// Set the current user to be authenticated, save the authentication token
diff --git a/source/java/org/alfresco/filesys/server/auth/ntlm/NTLM.java b/source/java/org/alfresco/filesys/server/auth/ntlm/NTLM.java
index 7c9c833fb0..209accb517 100644
--- a/source/java/org/alfresco/filesys/server/auth/ntlm/NTLM.java
+++ b/source/java/org/alfresco/filesys/server/auth/ntlm/NTLM.java
@@ -42,14 +42,15 @@ public class NTLM
public static final int FlagNegotiateSeal = 0x00000020;
public static final int FlagDatagramStyle = 0x00000040;
public static final int FlagLanManKey = 0x00000080;
+ public static final int FlagNegotiateNetware = 0x00000100;
public static final int FlagNegotiateNTLM = 0x00000200;
public static final int FlagDomainSupplied = 0x00001000;
public static final int FlagWorkstationSupplied = 0x00002000;
public static final int FlagLocalCall = 0x00004000;
public static final int FlagAlwaysSign = 0x00008000;
- public static final int FlagTypeDomain = 0x00010000;
- public static final int FlagTypeServer = 0x00020000;
- public static final int FlagTypeShare = 0x00040000;
+ public static final int FlagChallengeInit = 0x00010000;
+ public static final int FlagChallengeAccept = 0x00020000;
+ public static final int FlagChallengeNonNT = 0x00040000;
public static final int FlagNTLM2Key = 0x00080000;
public static final int FlagTargetInfo = 0x00800000;
public static final int Flag128Bit = 0x20000000;
diff --git a/source/java/org/alfresco/filesys/server/auth/ntlm/NTLMMessage.java b/source/java/org/alfresco/filesys/server/auth/ntlm/NTLMMessage.java
index c67a8ab034..03d36f3fa0 100644
--- a/source/java/org/alfresco/filesys/server/auth/ntlm/NTLMMessage.java
+++ b/source/java/org/alfresco/filesys/server/auth/ntlm/NTLMMessage.java
@@ -204,7 +204,7 @@ public abstract class NTLMMessage
*/
protected final int getByteOffset(int offset)
{
- return getIntValue(m_offset + offset + 4);
+ return getIntValue(offset + 4);
}
/**
@@ -217,11 +217,11 @@ public abstract class NTLMMessage
{
// Get the byte block length
- int bLen = getShortValue(m_offset + offset);
+ int bLen = getShortValue(offset);
if ( bLen == 0)
return null;
- int bOff = getIntValue(m_offset + offset + 4);
+ int bOff = getIntValue(offset + 4);
return getRawBytes(bOff, bLen);
}
diff --git a/source/java/org/alfresco/filesys/server/auth/ntlm/NTLMv2Blob.java b/source/java/org/alfresco/filesys/server/auth/ntlm/NTLMv2Blob.java
new file mode 100644
index 0000000000..c07e7ef023
--- /dev/null
+++ b/source/java/org/alfresco/filesys/server/auth/ntlm/NTLMv2Blob.java
@@ -0,0 +1,187 @@
+/*
+ * Copyright (C) 2005-2006 Alfresco, Inc.
+ *
+ * Licensed under the Mozilla Public License version 1.1
+ * with a permitted attribution clause. You may obtain a
+ * copy of the License at
+ *
+ * http://www.alfresco.org/legal/license.txt
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
+ * either express or implied. See the License for the specific
+ * language governing permissions and limitations under the
+ * License.
+ */
+package org.alfresco.filesys.server.auth.ntlm;
+
+import java.util.Date;
+
+import javax.crypto.Mac;
+import javax.crypto.spec.SecretKeySpec;
+
+import org.alfresco.filesys.smb.NTTime;
+import org.alfresco.filesys.util.DataPacker;
+import org.alfresco.filesys.util.HexDump;
+
+/**
+ * NTLMv2 Blob Class
+ *
+ * Contains methods to pack/unpack and calculate the hash of an NTLMv2 blob.
+ *
+ * @author gkspencer
+ */
+public class NTLMv2Blob
+{
+ // Constants
+
+ public static final int HMAC_LEN = 16;
+ public static final int CHALLENGE_LEN = 8;
+
+ // Offsets
+
+ public static final int OFFSET_HMAC = 0;
+ public static final int OFFSET_HEADER = 16;
+ public static final int OFFSET_RESERVED = 20;
+ public static final int OFFSET_TIMESTAMP = 24;
+ public static final int OFFSET_CHALLENGE = 32;
+ public static final int OFFSET_UNKNOWN = 36;
+ public static final int OFFSET_TARGETINFO = 40;
+
+ // NTLMv2 blob
+
+ private byte[] m_blob;
+ private int m_offset;
+ private int m_len;
+
+ /**
+ * Class constructor
+ *
+ * @param buf byte[]
+ */
+ public NTLMv2Blob(byte[] buf)
+ {
+ m_blob = buf;
+ m_offset = 0;
+ m_len = m_blob.length;
+ }
+
+ /**
+ * Class constructor
+ *
+ * @param buf byte[]
+ * @param offset int
+ * @param len int
+ */
+ public NTLMv2Blob(byte[] buf, int offset, int len)
+ {
+ m_blob = buf;
+ m_offset = offset;
+ m_len = len;
+ }
+
+ /**
+ * Return the buffer
+ *
+ * @return byte[]
+ */
+ public final byte[] getBuffer()
+ {
+ return m_blob;
+ }
+
+ /**
+ * Return the offset
+ *
+ * @return int
+ */
+ public final int getOffset()
+ {
+ return m_offset;
+ }
+
+ /**
+ * Return the blob length
+ *
+ * @return int
+ */
+ public final int getLength()
+ {
+ return m_len;
+ }
+
+ /**
+ * Return the HMAC from the buffer
+ *
+ * @return byte[]
+ */
+ public final byte[] getHMAC()
+ {
+ byte[] hmac = new byte[HMAC_LEN];
+ System.arraycopy(m_blob, m_offset, hmac, 0, HMAC_LEN);
+
+ return hmac;
+ }
+
+ /**
+ * Return the timestamp from the buffer, in NT 64bit time format
+ *
+ * @return long
+ */
+ public final long getTimeStamp()
+ {
+ return DataPacker.getIntelLong(m_blob, m_offset + OFFSET_TIMESTAMP);
+ }
+
+ /**
+ * Return the client challenge
+ *
+ * @return byte[]
+ */
+ public final byte[] getClientChallenge()
+ {
+ byte[] challenge = new byte[CHALLENGE_LEN];
+ System.arraycopy( m_blob, m_offset + OFFSET_CHALLENGE, challenge, 0, CHALLENGE_LEN);
+
+ return challenge;
+ }
+
+ /**
+ * Calculate the HMAC of the blob using the specified NTLMv2 hash and challenge
+ *
+ * @param challenge byte[]
+ * @param v2hash byte[]
+ * @return byte[]
+ * @exception Exception
+ */
+ public final byte[] calculateHMAC( byte[] challenge, byte[] v2hash)
+ throws Exception
+ {
+ // Create a copy of the NTLMv2 blob with room for the challenge
+
+ byte[] blob = new byte[(m_len - HMAC_LEN) + CHALLENGE_LEN];
+ System.arraycopy( challenge, 0, blob, 0, CHALLENGE_LEN);
+ System.arraycopy( m_blob, m_offset + OFFSET_HEADER, blob, CHALLENGE_LEN, m_len - HMAC_LEN);
+
+ // Generate the HMAC of the blob using the v2 hash as the key
+
+ Mac hmacMd5 = Mac.getInstance( "HMACMD5");
+ SecretKeySpec blobKey = new SecretKeySpec( v2hash, 0, v2hash.length, "MD5");
+
+ hmacMd5.init( blobKey);
+ return hmacMd5.doFinal( blob);
+ }
+
+ /**
+ * Dump the NTLMv2 blob details
+ */
+ public final void Dump()
+ {
+ System.out.println("NTLMv2 blob :");
+ System.out.println(" HMAC : " + HexDump.hexString( getHMAC()));
+ System.out.println(" Header : 0x" + Integer.toHexString(DataPacker.getIntelInt( m_blob, m_offset + OFFSET_HEADER)));
+ System.out.println(" Timestamp : " + new Date(NTTime.toJavaDate( getTimeStamp())));
+ System.out.println(" Challenge : " + HexDump.hexString( getClientChallenge()));
+ }
+}
diff --git a/source/java/org/alfresco/filesys/server/auth/ntlm/Type3NTLMMessage.java b/source/java/org/alfresco/filesys/server/auth/ntlm/Type3NTLMMessage.java
index 0c82a0edd2..e77a71dd2d 100644
--- a/source/java/org/alfresco/filesys/server/auth/ntlm/Type3NTLMMessage.java
+++ b/source/java/org/alfresco/filesys/server/auth/ntlm/Type3NTLMMessage.java
@@ -92,6 +92,16 @@ public class Type3NTLMMessage extends NTLMMessage
return getIntValue(OffsetFlags);
}
+ /**
+ * Return the length of the LM hash
+ *
+ * @return int
+ */
+ public final int getLMHashLength()
+ {
+ return getShortValue(OffsetLMResponse);
+ }
+
/**
* Return the LM password hash
*
@@ -102,6 +112,16 @@ public class Type3NTLMMessage extends NTLMMessage
return getByteValue(OffsetLMResponse);
}
+ /**
+ * Return the length of the NTLM hash
+ *
+ * @return int
+ */
+ public final int getNTLMHashLength()
+ {
+ return getShortValue(OffsetNTLMResponse);
+ }
+
/**
* Return the NTLM password hash
*
diff --git a/source/java/org/alfresco/filesys/server/auth/passthru/AcegiPassthruAuthenticator.java b/source/java/org/alfresco/filesys/server/auth/passthru/AcegiPassthruAuthenticator.java
deleted file mode 100644
index 150bb13a52..0000000000
--- a/source/java/org/alfresco/filesys/server/auth/passthru/AcegiPassthruAuthenticator.java
+++ /dev/null
@@ -1,289 +0,0 @@
-/*
- * Copyright (C) 2005-2006 Alfresco, Inc.
- *
- * Licensed under the Mozilla Public License version 1.1
- * with a permitted attribution clause. You may obtain a
- * copy of the License at
- *
- * http://www.alfresco.org/legal/license.txt
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
- * either express or implied. See the License for the specific
- * language governing permissions and limitations under the
- * License.
- */
-package org.alfresco.filesys.server.auth.passthru;
-
-import java.util.List;
-
-import net.sf.acegisecurity.AuthenticationManager;
-import net.sf.acegisecurity.providers.ProviderManager;
-
-import org.alfresco.config.ConfigElement;
-import org.alfresco.filesys.server.SrvSession;
-import org.alfresco.filesys.server.auth.ClientInfo;
-import org.alfresco.filesys.server.auth.SrvAuthenticator;
-import org.alfresco.filesys.server.auth.UserAccount;
-import org.alfresco.filesys.server.config.InvalidConfigurationException;
-import org.alfresco.filesys.server.config.ServerConfiguration;
-import org.alfresco.filesys.server.core.SharedDevice;
-import org.alfresco.repo.security.authentication.ntlm.NTLMAuthenticationProvider;
-import org.alfresco.repo.security.authentication.ntlm.NTLMPassthruToken;
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-
-/**
- * Passthru authenticator implementation that uses the Acegi NTLM passthru authentication provider
- *
- * @author GKSpencer
- */
-public class AcegiPassthruAuthenticator extends SrvAuthenticator
-{
- // Debug logging
-
- private static final Log logger = LogFactory.getLog("org.alfresco.smb.protocol.auth");
-
- // Constants
- //
- // Default authentication manager bean name
-
- private static final String DefaultAuthManagerName = "authenticationManager";
-
- // Acegi authentication manager
-
- private AuthenticationManager m_authMgr;
-
- /**
- * Default constructor
- */
- public AcegiPassthruAuthenticator()
- {
- setAccessMode(SrvAuthenticator.USER_MODE);
- setEncryptedPasswords(true);
- }
-
- /**
- * Authenticate the connection to a particular share, called when the SMB server is in share
- * security mode
- *
- * @param client ClientInfo
- * @param share SharedDevice
- * @param sharePwd String
- * @param sess SrvSession
- * @return int
- */
- public int authenticateShareConnect(ClientInfo client, SharedDevice share, String sharePwd, SrvSession sess)
- {
- return SrvAuthenticator.Writeable;
- }
-
- /**
- * Authenticate a session setup by a user
- *
- * @param client ClientInfo
- * @param sess SrvSession
- * @param alg int
- * @return int
- */
- public int authenticateUser(ClientInfo client, SrvSession sess, int alg)
- {
- // Get the authentication token for the session
-
- NTLMPassthruToken authToken = (NTLMPassthruToken) sess.getAuthenticationToken();
-
- if ( authToken == null)
- return SrvAuthenticator.AUTH_DISALLOW;
-
- // Get the appropriate hashed password for the algorithm
-
- int authSts = SrvAuthenticator.AUTH_DISALLOW;
- byte[] hashedPassword = null;
-
- if ( alg == NTLM1)
- hashedPassword = client.getPassword();
- else if ( alg == LANMAN)
- hashedPassword = client.getANSIPassword();
- else
- {
- // Debug
-
- if ( logger.isDebugEnabled())
- logger.debug("Invalid algorithm specified for user authentication (" + alg + ")");
-
- // Invalid/unsupported algorithm specified
-
- return SrvAuthenticator.AUTH_DISALLOW;
- }
-
- // Set the username and hashed password in the authentication token
-
- authToken.setUserAndPassword( client.getUserName(), hashedPassword, alg);
-
- // Authenticate the user
-
- try
- {
- // Run the second stage of the passthru authentication
-
- m_authMgr.authenticate( authToken);
-
- // Check if the user has been logged on as a guest
-
- if (authToken.isGuestLogon())
- {
-
- // Check if the local server allows guest access
-
- if (allowGuest() == true)
- {
-
- // Allow the user access as a guest
-
- authSts = SrvAuthenticator.AUTH_GUEST;
-
- // Debug
-
- if (logger.isDebugEnabled())
- logger.debug("Acegi passthru authenticate user=" + client.getUserName() + ", GUEST");
- }
- }
- else
- {
-
- // Allow the user full access to the server
-
- authSts = SrvAuthenticator.AUTH_ALLOW;
-
- // Debug
-
- if (logger.isDebugEnabled())
- logger.debug("Acegi passthru authenticate user=" + client.getUserName() + ", FULL");
- }
- }
- catch ( Exception ex)
- {
- // Log the error
-
- if ( logger.isErrorEnabled())
- logger.error("Logon failure, " + ex.getMessage());
- }
-
- // Clear the authentication token
-
- sess.setAuthenticationToken(null);
-
- // Return the authentication status
-
- return authSts;
- }
-
- /**
- * Get user account details for the specified user
- *
- * @param user String
- * @return UserAccount
- */
- public UserAccount getUserDetails(String user)
- {
- // No user details to return
-
- return null;
- }
-
- /**
- * Get a challenge key for a new session
- *
- * @param sess SrvSession
- * @return byte[]
- */
- public byte[] getChallengeKey(SrvSession sess)
- {
- // Create an authentication token for the session
-
- NTLMPassthruToken authToken = new NTLMPassthruToken();
-
- // Run the first stage of the passthru authentication to get the challenge
-
- m_authMgr.authenticate( authToken);
-
- // Save the authentication token for the second stage of the authentication
-
- sess.setAuthenticationToken(authToken);
-
- // Debug
-
- if ( logger.isDebugEnabled())
- logger.debug("Created new passthru token " + authToken);
-
- // Get the challenge from the token
-
- if ( authToken.getChallenge() != null)
- return authToken.getChallenge().getBytes();
- return null;
- }
-
- /**
- * Initialzie the authenticator
- *
- * @param config ServerConfiguration
- * @param params ConfigElement
- * @exception InvalidConfigurationException
- */
- public void initialize(ServerConfiguration config, ConfigElement params) throws InvalidConfigurationException
- {
- // Call the base class
-
- super.initialize(config, params);
-
- // Check if the configuration has an associated bean factory, if not it looks like we are
- // not running inside Spring
-
- if ( config.getAuthenticationManager() == null)
- throw new InvalidConfigurationException("Acegi authentication manager not available");
-
- // Passthru authenticator only works in user mode
-
- if ( getAccessMode() != USER_MODE)
- throw new InvalidConfigurationException("Acegi authenticator only works in user mode");
-
- // Check if authentication manager is the required type and that the NTLM authentication provider
- // is available.
-
- Object authMgrObj = config.getAuthenticationManager();
-
- if ( authMgrObj instanceof ProviderManager)
- {
- // The required authentication manager is configured, now check if the NTLM provider is configured
-
- ProviderManager providerManager = (ProviderManager) authMgrObj;
- List providerList = providerManager.getProviders();
-
- if ( providerList != null)
- {
- // Check for the NTLM authentication provider
-
- int i = 0;
- boolean foundProvider = false;
-
- while ( i < providerList.size() && foundProvider == false)
- {
- if ( providerList.get(i++) instanceof NTLMAuthenticationProvider)
- foundProvider = true;
- }
-
- if (foundProvider == false)
- throw new InvalidConfigurationException("NTLM authentication provider is not available");
-
- // Save the authentication manager
-
- m_authMgr = (AuthenticationManager) authMgrObj;
- }
- else
- throw new InvalidConfigurationException("No authentication providers available");
- }
- else
- throw new InvalidConfigurationException("Required authentication manager is not configured");
- }
-}
diff --git a/source/java/org/alfresco/filesys/server/auth/passthru/PassthruAuthenticator.java b/source/java/org/alfresco/filesys/server/auth/passthru/PassthruAuthenticator.java
index f67e9711ad..634c464b77 100644
--- a/source/java/org/alfresco/filesys/server/auth/passthru/PassthruAuthenticator.java
+++ b/source/java/org/alfresco/filesys/server/auth/passthru/PassthruAuthenticator.java
@@ -24,15 +24,15 @@ import org.alfresco.config.ConfigElement;
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.ClientInfo;
-import org.alfresco.filesys.server.auth.SrvAuthenticator;
-import org.alfresco.filesys.server.auth.UserAccount;
+import org.alfresco.filesys.server.auth.CifsAuthenticator;
+import org.alfresco.filesys.server.auth.NTLanManAuthContext;
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.server.SMBServer;
import org.alfresco.filesys.smb.server.SMBSrvSession;
-import org.alfresco.filesys.util.HexDump;
import org.alfresco.model.ContentModel;
import org.alfresco.service.cmr.repository.NodeRef;
import org.apache.commons.logging.Log;
@@ -46,7 +46,7 @@ import org.apache.commons.logging.LogFactory;
*
* @author GKSpencer
*/
-public class PassthruAuthenticator extends SrvAuthenticator implements SessionListener
+public class PassthruAuthenticator extends CifsAuthenticator implements SessionListener
{
// Debug logging
@@ -77,9 +77,6 @@ public class PassthruAuthenticator extends SrvAuthenticator implements SessionLi
*/
public PassthruAuthenticator()
{
- setAccessMode(SrvAuthenticator.USER_MODE);
- setEncryptedPasswords(true);
-
// Allocate the session table
m_sessions = new Hashtable Contains the details of an SPNEGO NegTokenInit blob for use with CIFS.
+ *
+ * @author gkspencer
+ */
+public class NegTokenInit
+{
+ // Mechtypes list
+
+ private Oid[] m_mechTypes;
+
+ // Context flags
+
+ private int m_contextFlags = -1;
+
+ // Mechtoken
+
+ private byte[] m_mechToken;
+
+ // MectListMIC principal
+
+ private String m_mecListMICPrincipal;
+
+ /**
+ * Class constructor for decoding
+ */
+ public NegTokenInit()
+ {
+ }
+
+ /**
+ * Class constructor for encoding
+ *
+ * @param mechTypes Oid[]
+ * @param mechPrinciple String
+ */
+ public NegTokenInit( Oid[] mechTypes, String mechPrinciple)
+ {
+ m_mechTypes = mechTypes;
+ m_mecListMICPrincipal = mechPrinciple;
+ }
+
+ /**
+ * Class constructor for encoding
+ *
+ * @param mechTypes Vector Contains the details of an SPNEGO NegTokenTarg blob for use with CIFS.
+ *
+ * @author gkspencer
+ */
+public class NegTokenTarg
+{
+ // Result code
+
+ private int m_result;
+
+ // Supported mechanism
+
+ private Oid m_supportedMech;
+
+ // Response token
+
+ private byte[] m_responseToken;
+
+ /**
+ * Class constructor for decoding
+ */
+ public NegTokenTarg()
+ {
+ }
+
+ /**
+ * Class constructor
+ *
+ * @param result int
+ * @param mech Oid
+ * @param response byte[]
+ */
+ public NegTokenTarg(int result, Oid mech, byte[] response)
+ {
+ m_result = result;
+ m_supportedMech = mech;
+ m_responseToken = response;
+ }
+
+ /**
+ * Return the result
+ *
+ * @return int
+ */
+ public final int getResult()
+ {
+ return m_result;
+ }
+
+ /**
+ * Return the supported mech type Oid
+ *
+ * @return Oid
+ */
+ public final Oid getSupportedMech()
+ {
+ return m_supportedMech;
+ }
+
+ /**
+ * Determine if there is a valid response token
+ *
+ * @return boolean
+ */
+ public final boolean hasResponseToken()
+ {
+ return m_responseToken != null ? true : false;
+ }
+
+ /**
+ * Return the response token
+ *
+ * @return byte[]
+ */
+ public final byte[] getResponseToken()
+ {
+ return m_responseToken;
+ }
+
+ /**
+ * Decode an SPNEGO NegTokenTarg blob
+ *
+ * @param buf byte[]
+ * @param off int
+ * @param len int
+ * @exception IOException
+ */
+ public void decode(byte[] buf, int off, int len) throws IOException
+ {
+ // Create a stream around the security blob
+
+ ByteArrayInputStream bytStream = new ByteArrayInputStream( buf, off, len);
+ ASN1InputStream asnStream = new ASN1InputStream( bytStream);
+
+ // Read the top level object from the security blob
+
+ DERObject derObj = asnStream.readObject();
+
+ if ( derObj instanceof DERTaggedObject == false)
+ throw new IOException("Bad blob format (Tagged)");
+
+ // Access the sequence
+
+ DERTaggedObject derTag = (DERTaggedObject) derObj;
+ if ( derTag.getObject() instanceof DERSequence == false)
+ throw new IOException("Bad blob format (Seq)");
+
+ DERSequence derSeq = (DERSequence) derTag.getObject();
+ Enumeration seqEnum = derSeq.getObjects();
+
+ while ( seqEnum.hasMoreElements())
+ {
+ // Read an object from the sequence
+
+ derObj = (DERObject) seqEnum.nextElement();
+ if ( derObj instanceof DERTaggedObject)
+ {
+ // Tag 0 should be a status
+
+ derTag = (DERTaggedObject) derObj;
+ if ( derTag.getTagNo() == 0 && derTag.getObject() instanceof DEREnumerated)
+ {
+ // Result code
+
+ DEREnumerated derEnum = (DEREnumerated) derTag.getObject();
+ m_result = derEnum.getValue().intValue();
+ }
+ else if ( derTag.getTagNo() == 1 && derTag.getObject() instanceof DERObjectIdentifier)
+ {
+ // Mech type
+
+ DERObjectIdentifier derOid = (DERObjectIdentifier) derTag.getObject();
+ try
+ {
+ m_supportedMech = new Oid(derOid.getId());
+ }
+ catch (GSSException ex)
+ {
+ }
+ }
+ else if ( derTag.getTagNo() == 2 && derTag.getObject() instanceof DEROctetString)
+ {
+ // Unpack the response token
+
+ DEROctetString derStr = (DEROctetString) derTag.getObject();
+ m_responseToken = derStr.getOctets();
+ }
+ else if ( derTag.getTagNo() == 3 &&derTag.getObject() instanceof DEROctetString)
+ {
+ // mechListMIC
+
+ }
+ else
+ throw new IOException("Bad format, unexpected type");
+ }
+ else
+ throw new IOException("Bad format, untagged type");
+ }
+ }
+
+ /**
+ * Encode an SPNEGO NegTokenTarg blob
+ *
+ * @return byte[]
+ * @exception IOException
+ */
+ public byte[] encode() throws IOException
+ {
+ ByteArrayOutputStream tokStream = new ByteArrayOutputStream();
+
+ // Create an SPNEGO NegTokenTarg token
+
+ DEROutputStream derOut = new DEROutputStream( tokStream);
+
+ ASN1EncodableVector asnList = new ASN1EncodableVector();
+
+ // Pack the result code
+
+ asnList.add( new DERTaggedObject( true, 0, new DEREnumerated(m_result)));
+
+ // Pack the supportedMech field
+
+ if ( m_supportedMech != null)
+ asnList.add( new DERTaggedObject( true, 1, new DERObjectIdentifier( m_supportedMech.toString())));
+
+ // Pack the response token
+
+ if ( m_responseToken != null)
+ asnList.add( new DERTaggedObject( true, 2, new DEROctetString(m_responseToken)));
+
+ // Generate the SPNEGO NegTokenTarg blob
+
+ derOut.writeObject( new DERTaggedObject( true, SPNEGO.NegTokenTarg, new DERSequence( asnList)));
+ return tokStream.toByteArray();
+ }
+
+ /**
+ * Return the NegtokenTarg object as a string
+ *
+ * @return String
+ */
+ public String toString()
+ {
+ StringBuilder str = new StringBuilder();
+
+ str.append("[NegtokenTarg result=");
+ str.append( SPNEGO.asResultString( getResult()));
+
+ str.append(" oid=");
+ str.append( getSupportedMech());
+
+ str.append(" response=");
+ if ( hasResponseToken())
+ {
+ str.append(getResponseToken().length);
+ str.append(" bytes");
+ }
+ else
+ str.append("null");
+ str.append("]");
+
+ return str.toString();
+ }
+}
diff --git a/source/java/org/alfresco/filesys/server/auth/spnego/OID.java b/source/java/org/alfresco/filesys/server/auth/spnego/OID.java
new file mode 100644
index 0000000000..b77e66cb3d
--- /dev/null
+++ b/source/java/org/alfresco/filesys/server/auth/spnego/OID.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2005-2006 Alfresco, Inc.
+ *
+ * Licensed under the Mozilla Public License version 1.1
+ * with a permitted attribution clause. You may obtain a
+ * copy of the License at
+ *
+ * http://www.alfresco.org/legal/license.txt
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
+ * either express or implied. See the License for the specific
+ * language governing permissions and limitations under the
+ * License.
+ */
+package org.alfresco.filesys.server.auth.spnego;
+
+import org.ietf.jgss.GSSException;
+import org.ietf.jgss.Oid;
+
+/**
+ * OID Class
+ *
+ * Contains Oids used by SPNEGO
+ *
+ * @author gkspencer
+ */
+public class OID
+{
+ // IDs
+
+ public static final String ID_SPNEGO = "1.3.6.1.5.5.2";
+
+ // Kerberos providers
+
+ public static final String ID_KERBEROS5 = "1.2.840.113554.1.2.2";
+ public static final String ID_MSKERBEROS5 = "1.2.840.48018.1.2.2";
+
+ // Microsoft NTLM security support provider
+
+ public static final String ID_NTLMSSP = "1.3.6.1.4.1.311.2.2.10";
+
+ // OIDs
+
+ public static Oid SPNEGO;
+
+ public static Oid KERBEROS5;
+ public static Oid MSKERBEROS5;
+
+ public static Oid NTLMSSP;
+
+ /**
+ * Static initializer
+ */
+
+ static {
+
+ // Create the OIDs
+
+ try
+ {
+ SPNEGO = new Oid(ID_SPNEGO);
+
+ KERBEROS5 = new Oid(ID_KERBEROS5);
+ MSKERBEROS5 = new Oid( ID_MSKERBEROS5);
+
+ NTLMSSP = new Oid(ID_NTLMSSP);
+ }
+ catch ( GSSException ex)
+ {
+ }
+ }
+}
diff --git a/source/java/org/alfresco/filesys/server/auth/spnego/SPNEGO.java b/source/java/org/alfresco/filesys/server/auth/spnego/SPNEGO.java
new file mode 100644
index 0000000000..891c59f0b9
--- /dev/null
+++ b/source/java/org/alfresco/filesys/server/auth/spnego/SPNEGO.java
@@ -0,0 +1,132 @@
+/*
+ * Copyright (C) 2005-2006 Alfresco, Inc.
+ *
+ * Licensed under the Mozilla Public License version 1.1
+ * with a permitted attribution clause. You may obtain a
+ * copy of the License at
+ *
+ * http://www.alfresco.org/legal/license.txt
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
+ * either express or implied. See the License for the specific
+ * language governing permissions and limitations under the
+ * License.
+ */
+package org.alfresco.filesys.server.auth.spnego;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+
+import org.bouncycastle.asn1.ASN1InputStream;
+import org.bouncycastle.asn1.DERApplicationSpecific;
+import org.bouncycastle.asn1.DERObject;
+import org.bouncycastle.asn1.DERTaggedObject;
+
+/**
+ * SPNEGO Class
+ *
+ * Contains SPNEGO constants
+ *
+ * @author gkspencer
+ */
+public class SPNEGO
+{
+ // Message types
+
+ public static final int NegTokenInit = 0;
+ public static final int NegTokenTarg = 1;
+
+ // NegTokenInit context flags
+
+ public static final int ContextDelete = 0;
+ public static final int ContextMutual = 1;
+ public static final int ContextReplay = 2;
+ public static final int ContextSequence = 3;
+ public static final int ContextAnon = 4;
+ public static final int ContextConf = 5;
+ public static final int ContextInteg = 6;
+
+ // NegTokenTarg result codes
+
+ public static final int AcceptCompleted = 0;
+ public static final int AcceptIncomplete = 1;
+ public static final int Reject = 2;
+
+ /**
+ * Return a result code as a string
+ *
+ * @param res int
+ * @return String
+ */
+ public static String asResultString(int res)
+ {
+ String resStr = null;
+
+ switch ( res)
+ {
+ case AcceptCompleted:
+ resStr = "AcceptCompleted";
+ break;
+ case AcceptIncomplete:
+ resStr = "AcceptIncomplete";
+ break;
+ case Reject:
+ resStr = "Reject";
+ break;
+ default:
+ resStr = "" + res;
+ break;
+ }
+
+ return resStr;
+ }
+
+ /**
+ * Determine the SPNEGO token type
+ *
+ * @param buf byte[]
+ * @param off int
+ * @param len int
+ * @return int
+ * @exception IOException
+ */
+ public static int checkTokenType( byte[] buf, int off, int len)
+ throws IOException
+ {
+ // Create a stream around the security blob
+
+ ByteArrayInputStream bytStream = new ByteArrayInputStream( buf, off, len);
+ ASN1InputStream asnStream = new ASN1InputStream( bytStream);
+
+ // Read the top level object from the security blob
+
+ DERObject derObj = asnStream.readObject();
+ int tokType = -1;
+
+ if ( derObj instanceof DERApplicationSpecific)
+ {
+ // Looks like a NegTokenInit token
+
+ tokType = NegTokenInit;
+ }
+ else if ( derObj instanceof DERTaggedObject)
+ {
+ // Check the tag number
+
+ DERTaggedObject derTag = (DERTaggedObject) derObj;
+ if ( derTag.getTagNo() == 1)
+ tokType = NegTokenTarg;
+ }
+
+ // Close the streams
+
+ asnStream.close();
+ bytStream.close();
+
+ // Return the token type
+
+ return tokType;
+ }
+}
diff --git a/source/java/org/alfresco/filesys/server/config/ServerConfiguration.java b/source/java/org/alfresco/filesys/server/config/ServerConfiguration.java
index f7f3aaf65e..d24edcd9ea 100644
--- a/source/java/org/alfresco/filesys/server/config/ServerConfiguration.java
+++ b/source/java/org/alfresco/filesys/server/config/ServerConfiguration.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2005 Alfresco, Inc.
+ * Copyright (C) 2005-2006 Alfresco, Inc.
*
* Licensed under the Mozilla Public License version 1.1
* with a permitted attribution clause. You may obtain a
@@ -20,7 +20,6 @@ import java.io.IOException;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.Socket;
-import java.net.SocketException;
import java.net.UnknownHostException;
import java.security.Provider;
import java.security.Security;
@@ -46,10 +45,7 @@ import org.alfresco.filesys.netbios.RFCNetBIOSProtocol;
import org.alfresco.filesys.netbios.win32.Win32NetBIOS;
import org.alfresco.filesys.server.NetworkServer;
import org.alfresco.filesys.server.NetworkServerList;
-import org.alfresco.filesys.server.auth.LocalAuthenticator;
-import org.alfresco.filesys.server.auth.SrvAuthenticator;
-import org.alfresco.filesys.server.auth.UserAccount;
-import org.alfresco.filesys.server.auth.UserAccountList;
+import org.alfresco.filesys.server.auth.CifsAuthenticator;
import org.alfresco.filesys.server.auth.acl.ACLParseException;
import org.alfresco.filesys.server.auth.acl.AccessControl;
import org.alfresco.filesys.server.auth.acl.AccessControlList;
@@ -68,8 +64,6 @@ import org.alfresco.filesys.server.filesys.DiskDeviceContext;
import org.alfresco.filesys.server.filesys.DiskInterface;
import org.alfresco.filesys.server.filesys.DiskSharedDevice;
import org.alfresco.filesys.server.filesys.HomeShareMapper;
-import org.alfresco.filesys.smb.Dialect;
-import org.alfresco.filesys.smb.DialectSelector;
import org.alfresco.filesys.smb.ServerType;
import org.alfresco.filesys.util.IPAddress;
import org.alfresco.filesys.util.X64;
@@ -138,15 +132,19 @@ public class ServerConfiguration implements ApplicationListener
};
// Token name to substitute current server name into the CIFS server name
+
private static final String TokenLocalName = "${localname}";
- // Acegi authentication manager
+ // Authentication manager
+
private AuthenticationManager authenticationManager;
// Configuration service
+
private ConfigService configService;
- /** the device to connect use */
+ // Disk interface to use for shared filesystems
+
private DiskInterface diskInterface;
// Runtime platform type
@@ -159,46 +157,53 @@ public class ServerConfiguration implements ApplicationListener
private boolean m_ftpEnable = true;
// Server name
+
private String m_name;
// Server type, used by the host announcer
+
private int m_srvType = ServerType.WorkStation + ServerType.Server + ServerType.NTServer;
// Active server list
+
private NetworkServerList m_serverList;
// Server comment
+
private String m_comment;
// Server domain
+
private String m_domain;
// Network broadcast mask string
+
private String m_broadcast;
// Announce the server to network neighborhood, announcement interval in
// minutes
- private boolean m_announce;
+ private boolean m_announce;
private int m_announceInterval;
- // Default SMB dialects to enable
- private DialectSelector m_dialects;
-
// List of shared devices
+
private SharedDeviceList m_shareList;
// Authenticator, used to authenticate users and share connections.
- private SrvAuthenticator m_authenticator;
+
+ private CifsAuthenticator m_authenticator;
// Share mapper
+
private ShareMapper m_shareMapper;
// Access control manager
+
private AccessControlManager m_aclManager;
- // Global access control list, applied to all shares that do not have access
- // controls
+ // Global access control list, applied to all shares that do not have access controls
+
private AccessControlList m_globalACLs;
private boolean m_nbDebug = false;
@@ -206,31 +211,31 @@ public class ServerConfiguration implements ApplicationListener
private boolean m_announceDebug = false;
// Default session debugging setting
+
private int m_sessDebug;
// Flags to indicate if NetBIOS, native TCP/IP SMB and/or Win32 NetBIOS
// should be enabled
+
private boolean m_netBIOSEnable = true;
-
private boolean m_tcpSMBEnable = false;
-
private boolean m_win32NBEnable = false;
// Address to bind the SMB server to, if null all local addresses are used
+
private InetAddress m_smbBindAddress;
- // Address to bind the NetBIOS name server to, if null all addresses are
- // used
+ // Address to bind the NetBIOS name server to, if null all addresses are used
+
private InetAddress m_nbBindAddress;
// WINS servers
+
private InetAddress m_winsPrimary;
private InetAddress m_winsSecondary;
- // User account list
- private UserAccountList m_userList;
-
// Enable/disable Macintosh extension SMBs
+
private boolean m_macExtensions;
// --------------------------------------------------------------------------------
@@ -238,13 +243,16 @@ public class ServerConfiguration implements ApplicationListener
//
// Server name to register under Win32 NetBIOS, if not set the main server
// name is used
+
private String m_win32NBName;
// LANA to be used for Win32 NetBIOS, if not specified the first available
// is used
+
private int m_win32NBLANA = -1;
// Send out host announcements via the Win32 NetBIOS interface
+
private boolean m_win32NBAnnounce = false;
private int m_win32NBAnnounceInterval;
@@ -277,10 +285,12 @@ public class ServerConfiguration implements ApplicationListener
// Global server configuration
//
// Timezone name and offset from UTC in minutes
+
private String m_timeZone;
private int m_tzOffset;
// JCE provider class name
+
private String m_jceProviderClass;
// Local server name and domain/workgroup name
@@ -288,7 +298,8 @@ public class ServerConfiguration implements ApplicationListener
private String m_localName;
private String m_localDomain;
- /** flag indicating successful initialisation */
+ // flag to indicate successful initialization
+
private boolean initialised;
// Main authentication service, public API
@@ -314,23 +325,6 @@ public class ServerConfiguration implements ApplicationListener
m_shareList = new SharedDeviceList();
- // Allocate the SMB dialect selector, and initialize using the default
- // list of dialects
-
- m_dialects = new DialectSelector();
-
- m_dialects.AddDialect(Dialect.DOSLanMan1);
- m_dialects.AddDialect(Dialect.DOSLanMan2);
- m_dialects.AddDialect(Dialect.LanMan1);
- m_dialects.AddDialect(Dialect.LanMan2);
- m_dialects.AddDialect(Dialect.LanMan2_1);
- m_dialects.AddDialect(Dialect.NT);
-
- // Use the local authenticator, that allows locally defined users to connect to the
- // server
-
- setAuthenticator(new LocalAuthenticator(), null, true);
-
// Use the default share mapper
m_shareMapper = new DefaultShareMapper();
@@ -1328,7 +1322,7 @@ public class ServerConfiguration implements ApplicationListener
// Parse the path
- FTPPath ftpPath = new FTPPath(rootPath);
+ new FTPPath(rootPath);
// Set the root path
@@ -1419,10 +1413,32 @@ public class ServerConfiguration implements ApplicationListener
}
}
+ // Get the top level filesystems confgiruation element
+
+ ConfigElement filesystems = config.getConfigElement("filesystems");
+
// Get the filesystem configuration elements
- List