Merged V2.0 to HEAD

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


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

View File

@@ -247,6 +247,15 @@
</property> </property>
</bean> </bean>
<!-- Perform index recovery before applying any patches -->
<!-- rebuild the index if required - before we check that it is there -->
<bean id="indexRecoveryBootstrap" class="org.alfresco.repo.node.index.IndexRecoveryBootstrapBean" >
<property name="indexRecoveryComponent">
<ref bean="indexRecoveryComponent"/>
</property>
</bean>
<!-- This component checks the interconnection between the metadata, indexes and content --> <!-- This component checks the interconnection between the metadata, indexes and content -->
<bean id="configurationChecker" class="org.alfresco.repo.admin.ConfigurationChecker"> <bean id="configurationChecker" class="org.alfresco.repo.admin.ConfigurationChecker">
<property name="strict"> <property name="strict">
@@ -328,6 +337,14 @@
</constructor-arg> </constructor-arg>
</bean> </bean>
<!-- Start the quartz scheduler -->
<bean id="schedulerStarter" class="org.alfresco.util.SchedulerStarterBean" >
<property name="scheduler">
<ref bean="schedulerFactory"/>
</property>
</bean>
<!-- Startup Message --> <!-- Startup Message -->
<bean id="startupLog" class="org.alfresco.repo.descriptor.DescriptorStartupLog"> <bean id="startupLog" class="org.alfresco.repo.descriptor.DescriptorStartupLog">

View File

@@ -260,7 +260,7 @@
name="org.alfresco.cache.ticketsCache" name="org.alfresco.cache.ticketsCache"
maxElementsInMemory="1000" maxElementsInMemory="1000"
eternal="true" eternal="true"
overflowToDisk="false" overflowToDisk="true"
/> />
</ehcache> </ehcache>

View File

@@ -26,7 +26,7 @@
<!-- <!--
<cacheManagerPeerListenerFactory <cacheManagerPeerListenerFactory
class="net.sf.ehcache.distribution.RMICacheManagerPeerListenerFactory" class="net.sf.ehcache.distribution.RMICacheManagerPeerListenerFactory"
properties="port=40001, socketTimeoutMillis=2000"/> properties="port=40001, socketTimeoutMillis=5000"/>
--> -->
<!-- ================================================================= --> <!-- ================================================================= -->
@@ -489,7 +489,7 @@
name="org.alfresco.cache.ticketsCache" name="org.alfresco.cache.ticketsCache"
maxElementsInMemory="1000" maxElementsInMemory="1000"
eternal="true" eternal="true"
overflowToDisk="false"> overflowToDisk="true">
<cacheEventListenerFactory <cacheEventListenerFactory
class="net.sf.ehcache.distribution.RMICacheReplicatorFactory" class="net.sf.ehcache.distribution.RMICacheReplicatorFactory"

View File

@@ -16,6 +16,10 @@
<property name="schedulerName"> <property name="schedulerName">
<value>DefaultScheduler</value> <value>DefaultScheduler</value>
</property> </property>
<!-- Do not auto start the scheduler - this is done at the end of the bootstrap process -->
<property name="autoStartup">
<value>false</value>
</property>
</bean> </bean>
<!-- --> <!-- -->
@@ -48,6 +52,8 @@
</property> </property>
</bean> </bean>
<!-- This has now been moved into the bootstrap process and is not required here -->
<!--
<bean id="indexRecoveryTrigger" class="org.alfresco.util.TriggerBean"> <bean id="indexRecoveryTrigger" class="org.alfresco.util.TriggerBean">
<property name="jobDetail"> <property name="jobDetail">
<bean class="org.springframework.scheduling.quartz.JobDetailBean"> <bean class="org.springframework.scheduling.quartz.JobDetailBean">
@@ -73,6 +79,7 @@
<value>0</value> <value>0</value>
</property> </property>
</bean> </bean>
-->
<bean id="tempFileCleanerTrigger" class="org.alfresco.util.TriggerBean"> <bean id="tempFileCleanerTrigger" class="org.alfresco.util.TriggerBean">
<property name="jobDetail"> <property name="jobDetail">

View File

@@ -529,7 +529,7 @@ public class Win32NetBIOS
String ipAddr = niEnum.nextElement(); String ipAddr = niEnum.nextElement();
NetworkInterface ni = niList.get(ipAddr); NetworkInterface ni = niList.get(ipAddr);
if (ni.getDisplayName().equalsIgnoreCase(name)) if (ni.getName().equalsIgnoreCase(name))
{ {
// Return the LANA for the network adapters TCP/IP address // Return the LANA for the network adapters TCP/IP address

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -1254,11 +1254,29 @@ public class ServerConfiguration extends AbstractLifecycleBean
String lanaStr = elem.getAttribute("lana"); String lanaStr = elem.getAttribute("lana");
if (lanaStr != null && lanaStr.length() > 0) if (lanaStr != null && lanaStr.length() > 0)
{ {
// Check if the LANA has been specified as an IP address or adapter name
// Validate the LANA number
int lana = -1; int lana = -1;
if ( IPAddress.isNumericAddress( lanaStr))
{
// Convert the IP address to a LANA id
lana = Win32NetBIOS.getLANAForIPAddress( lanaStr);
if ( lana == -1)
throw new AlfrescoRuntimeException( "Failed to convert IP address " + lanaStr + " to a LANA");
}
else if ( lanaStr.length() > 1 && Character.isLetter( lanaStr.charAt( 0))) {
// Convert the network adapter to a LANA id
lana = Win32NetBIOS.getLANAForAdapterName( lanaStr);
if ( lana == -1)
throw new AlfrescoRuntimeException( "Failed to convert network adapter " + lanaStr + " to a LANA");
}
else {
try try
{ {
lana = Integer.parseInt(lanaStr); lana = Integer.parseInt(lanaStr);
@@ -1267,6 +1285,7 @@ public class ServerConfiguration extends AbstractLifecycleBean
{ {
throw new AlfrescoRuntimeException("Invalid win32 NetBIOS LANA specified"); throw new AlfrescoRuntimeException("Invalid win32 NetBIOS LANA specified");
} }
}
// LANA should be in the range 0-255 // LANA should be in the range 0-255
@@ -2265,8 +2284,8 @@ public class ServerConfiguration extends AbstractLifecycleBean
{ {
// Check if the appropriate authentication component type is configured // Check if the appropriate authentication component type is configured
if ( ntlmMode != NTLMMode.NONE) if ( ntlmMode == NTLMMode.MD4_PROVIDER)
throw new AlfrescoRuntimeException("Wrong authentication setup for passthru authenticator (can only be used with LDAP/JAAS auth component)"); throw new AlfrescoRuntimeException("Wrong authentication setup for passthru authenticator (cannot be used with Alfresco users)");
// Load the passthru authenticator dynamically // Load the passthru authenticator dynamically

View File

@@ -3153,6 +3153,17 @@ public class NTProtocolHandler extends CoreProtocolHandler
return; return;
} }
// Check if the search is for an NTFS stream
if ( FileName.containsStreamName( srchPath))
{
// NTFS streams not supported
m_sess.sendErrorResponseSMB(SMBStatus.NTObjectNotFound, SMBStatus.SRVNonSpecificError,
SMBStatus.ErrSrv);
return;
}
// Access the shared device disk interface // Access the shared device disk interface
SearchContext ctx = null; SearchContext ctx = null;

View File

@@ -313,6 +313,16 @@ public class SMBSrvSession extends SrvSession implements Runnable
m_vcircuits.removeCircuit(uid, this); m_vcircuits.removeCircuit(uid, this);
} }
/**
* Return the count of virtual circuits on this session
*
* @return int
*/
public final int getVirtualCircuitCount()
{
return m_vcircuits != null ? m_vcircuits.getCircuitCount() : 0;
}
/** /**
* Cleanup any resources owned by this session, close files, searches and * Cleanup any resources owned by this session, close files, searches and
* change notification requests. * change notification requests.

View File

@@ -46,7 +46,9 @@ import org.alfresco.service.ServiceRegistry;
import org.alfresco.service.cmr.dictionary.DataTypeDefinition; import org.alfresco.service.cmr.dictionary.DataTypeDefinition;
import org.alfresco.service.cmr.dictionary.DictionaryService; import org.alfresco.service.cmr.dictionary.DictionaryService;
import org.alfresco.service.cmr.lock.LockStatus; import org.alfresco.service.cmr.lock.LockStatus;
import org.alfresco.service.cmr.model.FileExistsException;
import org.alfresco.service.cmr.model.FileInfo; import org.alfresco.service.cmr.model.FileInfo;
import org.alfresco.service.cmr.model.FileNotFoundException;
import org.alfresco.service.cmr.repository.AssociationRef; import org.alfresco.service.cmr.repository.AssociationRef;
import org.alfresco.service.cmr.repository.ChildAssociationRef; import org.alfresco.service.cmr.repository.ChildAssociationRef;
import org.alfresco.service.cmr.repository.ContentData; import org.alfresco.service.cmr.repository.ContentData;
@@ -298,6 +300,24 @@ public class Node implements Serializable, Scopeable
{ {
if (name != null) if (name != null)
{ {
QName typeQName = getType();
if ((services.getDictionaryService().isSubClass(typeQName, ContentModel.TYPE_FOLDER) &&
!services.getDictionaryService().isSubClass(typeQName, ContentModel.TYPE_SYSTEM_FOLDER)) ||
services.getDictionaryService().isSubClass(typeQName, ContentModel.TYPE_CONTENT))
{
try
{
this.services.getFileFolderService().rename(this.nodeRef, name);
}
catch (FileExistsException e)
{
throw new AlfrescoRuntimeException("Failed to rename node " + nodeRef + " to " + name, e);
}
catch (FileNotFoundException e)
{
throw new AlfrescoRuntimeException("Failed to rename node " + nodeRef + " to " + name, e);
}
}
this.getProperties().put(ContentModel.PROP_NAME.toString(), name.toString()); this.getProperties().put(ContentModel.PROP_NAME.toString(), name.toString());
} }
} }

View File

@@ -35,6 +35,8 @@ import javax.transaction.UserTransaction;
import org.alfresco.model.ContentModel; import org.alfresco.model.ContentModel;
import org.alfresco.repo.content.MimetypeMap; import org.alfresco.repo.content.MimetypeMap;
import org.alfresco.repo.domain.ChildAssoc;
import org.alfresco.repo.domain.Node;
import org.alfresco.repo.domain.NodeStatus; import org.alfresco.repo.domain.NodeStatus;
import org.alfresco.repo.node.BaseNodeServiceTest; import org.alfresco.repo.node.BaseNodeServiceTest;
import org.alfresco.repo.transaction.AlfrescoTransactionSupport; import org.alfresco.repo.transaction.AlfrescoTransactionSupport;
@@ -353,4 +355,29 @@ public class DbNodeServiceImplTest extends BaseNodeServiceTest
mlTextProperty, mlTextProperty,
propertiesDirect.get(BaseNodeServiceTest.PROP_QNAME_ML_TEXT_VALUE)); propertiesDirect.get(BaseNodeServiceTest.PROP_QNAME_ML_TEXT_VALUE));
} }
public void testDuplicatePrimaryParentHandling() throws Exception
{
Map<QName, ChildAssociationRef> assocRefs = buildNodeGraph();
// get the node to play with
ChildAssociationRef n1pn3Ref = assocRefs.get(QName.createQName(BaseNodeServiceTest.NAMESPACE, "n1_p_n3"));
ChildAssociationRef n6pn8Ref = assocRefs.get(QName.createQName(BaseNodeServiceTest.NAMESPACE, "n6_p_n8"));
final NodeRef n1Ref = n1pn3Ref.getParentRef();
final NodeRef n8Ref = n6pn8Ref.getChildRef();
// Add a make n1 a second primary parent of n8
Node n1 = nodeDaoService.getNode(n1Ref);
Node n8 = nodeDaoService.getNode(n8Ref);
ChildAssoc assoc = nodeDaoService.newChildAssoc(
n1,
n8,
true,
ContentModel.ASSOC_CONTAINS,
QName.createQName(NAMESPACE, "n1pn8"));
// Now get the node primary parent
nodeService.getPrimaryParent(n8Ref);
// Get it again
nodeService.getPrimaryParent(n8Ref);
}
} }

View File

@@ -900,6 +900,15 @@ public class HibernateNodeDaoServiceImpl extends HibernateDaoSupport implements
getSession().flush(); getSession().flush();
} }
private Set<NodeRef> warnedDuplicateParents = new HashSet<NodeRef>(3);
/**
* @inheritDoc
*
* This method includes a check for multiple primary parent associations.
* The check doesn't fail but will warn (once per instance) of the occurence of
* the error. It is up to the administrator to fix the issue at the moment, but
* the server will not stop working.
*/
public ChildAssoc getPrimaryParentAssoc(Node node) public ChildAssoc getPrimaryParentAssoc(Node node)
{ {
// get the assocs pointing to the node // get the assocs pointing to the node
@@ -914,12 +923,20 @@ public class HibernateNodeDaoServiceImpl extends HibernateDaoSupport implements
} }
else if (primaryAssoc != null) else if (primaryAssoc != null)
{ {
// we have more than one somehow // We have found one already.
throw new DataIntegrityViolationException( synchronized(warnedDuplicateParents)
{
NodeRef childNodeRef = node.getNodeRef();
boolean added = warnedDuplicateParents.add(childNodeRef);
if (added)
{
logger.warn(
"Multiple primary associations: \n" + "Multiple primary associations: \n" +
" child: " + node + "\n" +
" first primary assoc: " + primaryAssoc + "\n" + " first primary assoc: " + primaryAssoc + "\n" +
" second primary assoc: " + assoc); " second primary assoc: " + assoc + "\n" +
"When running in a cluster, check that the caches are properly shared.");
}
}
} }
primaryAssoc = assoc; primaryAssoc = assoc;
// we keep looping to hunt out data integrity issues // we keep looping to hunt out data integrity issues
@@ -938,10 +955,22 @@ public class HibernateNodeDaoServiceImpl extends HibernateDaoSupport implements
} }
if (!rootNode.equals(node)) if (!rootNode.equals(node))
{ {
// it wasn't the root node // Reload the node to ensure that it is properly initialized
throw new DataIntegrityViolationException("Non-root node has no primary parent: \n" + getSession().refresh(node);
// Check if it has any parents yet.
if (node.getParentAssocs().size() == 0)
{
// It wasn't the root node and definitely has no parent
throw new DataIntegrityViolationException(
"Non-root node has no primary parent: \n" +
" child: " + node); " child: " + node);
} }
else
{
// Repeat this method with confidence
primaryAssoc = getPrimaryParentAssoc(node);
}
}
} }
// done // done
return primaryAssoc; return primaryAssoc;

View File

@@ -0,0 +1,54 @@
/*
* 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.repo.node.index;
import org.alfresco.util.AbstractLifecycleBean;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.context.ApplicationEvent;
public class IndexRecoveryBootstrapBean extends AbstractLifecycleBean
{
protected final static Log log = LogFactory.getLog(IndexRecoveryBootstrapBean.class);
IndexRecovery indexRecoveryComponent;
@Override
protected void onBootstrap(ApplicationEvent event)
{
// reindex
log.info("Checking/Recovering indexes ...");
indexRecoveryComponent.reindex();
}
@Override
protected void onShutdown(ApplicationEvent event)
{
// Nothing to do
}
public IndexRecovery getIndexRecoveryComponent()
{
return indexRecoveryComponent;
}
public void setIndexRecoveryComponent(IndexRecovery indexRecoveryComponent)
{
this.indexRecoveryComponent = indexRecoveryComponent;
}
}