diff --git a/config/alfresco/bootstrap-context.xml b/config/alfresco/bootstrap-context.xml
index 3bcc1068aa..dd062783d4 100644
--- a/config/alfresco/bootstrap-context.xml
+++ b/config/alfresco/bootstrap-context.xml
@@ -247,6 +247,15 @@
+
+
+
+
+
+
+
+
+
@@ -278,7 +287,7 @@
-
+
@@ -328,6 +337,14 @@
+
+
+
+
+
+
+
+
diff --git a/config/alfresco/ehcache-default.xml b/config/alfresco/ehcache-default.xml
index cc54b27fc2..4a6d51ff4d 100644
--- a/config/alfresco/ehcache-default.xml
+++ b/config/alfresco/ehcache-default.xml
@@ -260,7 +260,7 @@
name="org.alfresco.cache.ticketsCache"
maxElementsInMemory="1000"
eternal="true"
- overflowToDisk="false"
+ overflowToDisk="true"
/>
\ No newline at end of file
diff --git a/config/alfresco/extension/ehcache-custom.xml.sample.cluster b/config/alfresco/extension/ehcache-custom.xml.sample.cluster
index 57d6a92ec4..c0a694f3f1 100644
--- a/config/alfresco/extension/ehcache-custom.xml.sample.cluster
+++ b/config/alfresco/extension/ehcache-custom.xml.sample.cluster
@@ -26,7 +26,7 @@
@@ -489,7 +489,7 @@
name="org.alfresco.cache.ticketsCache"
maxElementsInMemory="1000"
eternal="true"
- overflowToDisk="false">
+ overflowToDisk="true">
DefaultScheduler
+
+
+ false
+
@@ -48,6 +52,8 @@
+
+
diff --git a/source/java/org/alfresco/filesys/netbios/win32/Win32NetBIOS.java b/source/java/org/alfresco/filesys/netbios/win32/Win32NetBIOS.java
index be12551e8f..45c1f5980d 100644
--- a/source/java/org/alfresco/filesys/netbios/win32/Win32NetBIOS.java
+++ b/source/java/org/alfresco/filesys/netbios/win32/Win32NetBIOS.java
@@ -529,7 +529,7 @@ public class Win32NetBIOS
String ipAddr = niEnum.nextElement();
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
diff --git a/source/java/org/alfresco/filesys/server/auth/AlfrescoAuthenticator.java b/source/java/org/alfresco/filesys/server/auth/AlfrescoAuthenticator.java
index 312d2d3110..10b40b4895 100644
--- a/source/java/org/alfresco/filesys/server/auth/AlfrescoAuthenticator.java
+++ b/source/java/org/alfresco/filesys/server/auth/AlfrescoAuthenticator.java
@@ -25,6 +25,7 @@
package org.alfresco.filesys.server.auth;
import java.security.NoSuchAlgorithmException;
+
import net.sf.acegisecurity.Authentication;
import org.alfresco.filesys.server.SrvSession;
@@ -32,6 +33,7 @@ import org.alfresco.filesys.server.auth.AuthContext;
import org.alfresco.filesys.server.auth.CifsAuthenticator;
import org.alfresco.filesys.server.auth.ClientInfo;
import org.alfresco.filesys.server.auth.NTLanManAuthContext;
+import org.alfresco.filesys.server.core.SharedDevice;
import org.alfresco.filesys.smb.server.SMBSrvSession;
import org.alfresco.filesys.util.HexDump;
import org.alfresco.repo.security.authentication.NTLMMode;
@@ -190,6 +192,25 @@ public class AlfrescoAuthenticator extends CifsAuthenticator
return authSts;
}
+ /**
+ * Authenticate a connection to a share.
+ *
+ * @param client User/client details from the tree connect request.
+ * @param share Shared device the client wants to connect to.
+ * @param pwd Share password.
+ * @param sess Server session.
+ * @return int Granted file permission level or disallow status if negative. See the
+ * FilePermission class.
+ */
+ public int authenticateShareConnect(ClientInfo client, SharedDevice share, String sharePwd, SrvSession sess)
+ {
+ // Allow write access
+ //
+ // Main authentication is handled by authenticateUser()
+
+ return CifsAuthenticator.Writeable;
+ }
+
/**
* Return an authentication context for the new session
*
@@ -278,7 +299,9 @@ public class AlfrescoAuthenticator extends CifsAuthenticator
// Generate the local encrypted password using the challenge that was sent to the client
byte[] p21 = new byte[21];
- byte[] md4byts = m_md4Encoder.decodeHash(md4hash);
+ byte[] md4byts = null;
+
+ md4byts = m_md4Encoder.decodeHash(md4hash);
System.arraycopy(md4byts, 0, p21, 0, 16);
// Get the challenge that was sent to the client
@@ -321,6 +344,11 @@ public class AlfrescoAuthenticator extends CifsAuthenticator
return CifsAuthenticator.AUTH_BADPASSWORD;
}
+ // Logging
+
+ if ( logger.isInfoEnabled())
+ logger.info( "Logged on user " + client.getUserName() + " (" + sess.getRemoteAddress() + ") using auto-logon shared password");
+
// Set the current user to be authenticated, save the authentication token
client.setAuthenticationToken( m_authComponent.setCurrentUser(client.getUserName()));
@@ -368,6 +396,10 @@ public class AlfrescoAuthenticator extends CifsAuthenticator
sess.beginReadTransaction( m_transactionService);
+ // Default logon status to disallow
+
+ int authSts = CifsAuthenticator.AUTH_DISALLOW;
+
// Get the authentication token for the session
NTLMPassthruToken authToken = (NTLMPassthruToken) sess.getAuthenticationToken();
@@ -377,7 +409,6 @@ public class AlfrescoAuthenticator extends CifsAuthenticator
// Get the appropriate hashed password for the algorithm
- int authSts = CifsAuthenticator.AUTH_DISALLOW;
byte[] hashedPassword = null;
if ( alg == NTLM1)
diff --git a/source/java/org/alfresco/filesys/server/auth/CifsAuthenticator.java b/source/java/org/alfresco/filesys/server/auth/CifsAuthenticator.java
index 0e43af00a8..4197d26d83 100644
--- a/source/java/org/alfresco/filesys/server/auth/CifsAuthenticator.java
+++ b/source/java/org/alfresco/filesys/server/auth/CifsAuthenticator.java
@@ -495,7 +495,7 @@ public abstract class CifsAuthenticator
// Check if this is a null session logon
- if (user.length() == 0 && domain.length() == 0 && uniPwdLen == 0 && ascPwdLen == 1)
+ if (user.length() == 0 && uniPwdLen == 0 && ascPwdLen <= 1)
client.setLogonType(ClientInfo.LogonNull);
// Authenticate the user
diff --git a/source/java/org/alfresco/filesys/server/auth/passthru/AuthSessionFactory.java b/source/java/org/alfresco/filesys/server/auth/passthru/AuthSessionFactory.java
index a97dede76b..efacda7ec5 100644
--- a/source/java/org/alfresco/filesys/server/auth/passthru/AuthSessionFactory.java
+++ b/source/java/org/alfresco/filesys/server/auth/passthru/AuthSessionFactory.java
@@ -136,10 +136,11 @@ public final class AuthSessionFactory
* @param pkt SMBPacket to build the negotiate request
* @param dlct SMB dialects to negotiate
* @param pid Process id to be used by this new session
+ * @param extSec Enable/disable extended security negotiation
* @return StringList
*/
- private final static StringList BuildNegotiatePacket(SMBPacket pkt, DialectSelector dlct, int pid)
+ private final static StringList BuildNegotiatePacket(SMBPacket pkt, DialectSelector dlct, int pid, boolean extSec)
{
// Initialize the SMB packet header fields
@@ -147,14 +148,14 @@ public final class AuthSessionFactory
pkt.setCommand(PacketType.Negotiate);
pkt.setProcessId(pid);
- // If the NT dialect is enabled set the Unicode flag in the request flags
+ // If the NT dialect is enabled set the Unicode flag
int flags2 = 0;
if (dlct.hasDialect(Dialect.NT))
flags2 += SMBPacket.FLG2_UNICODE;
- if ( useExtendedSecurity())
+ if ( useExtendedSecurity() && extSec == true)
flags2 += SMBPacket.FLG2_EXTENDEDSECURITY;
pkt.setFlags2(flags2);
@@ -486,7 +487,7 @@ public final class AuthSessionFactory
// Build the negotiate SMB dialect packet and exchange with the remote server
- StringList diaList = BuildNegotiatePacket(pkt, selDialect, pid);
+ StringList diaList = BuildNegotiatePacket(pkt, selDialect, pid, shr.hasExtendedSecurityFlags());
pkt.ExchangeLowLevelSMB(netSession, pkt, true);
// Determine the selected SMB dialect
diff --git a/source/java/org/alfresco/filesys/server/auth/passthru/AuthenticateSession.java b/source/java/org/alfresco/filesys/server/auth/passthru/AuthenticateSession.java
index 3ca07748e5..2ee9618192 100644
--- a/source/java/org/alfresco/filesys/server/auth/passthru/AuthenticateSession.java
+++ b/source/java/org/alfresco/filesys/server/auth/passthru/AuthenticateSession.java
@@ -1016,7 +1016,7 @@ public class AuthenticateSession
*/
public final void doSessionSetup(String userName, byte[] ascPwd, byte[] uniPwd) throws IOException, SMBException
{
- doSessionSetup(null, userName, null, ascPwd, uniPwd);
+ doSessionSetup(null, userName, null, ascPwd, uniPwd, 0);
}
/**
@@ -1029,7 +1029,7 @@ public class AuthenticateSession
public final void doSessionSetup(Type3NTLMMessage type3Msg) throws IOException, SMBException
{
doSessionSetup(type3Msg.getDomain(), type3Msg.getUserName(), type3Msg.getWorkstation(),
- type3Msg.getLMHash(), type3Msg.getNTLMHash());
+ type3Msg.getLMHash(), type3Msg.getNTLMHash(), 0);
}
/**
@@ -1040,11 +1040,13 @@ public class AuthenticateSession
* @param wksName String
* @param ascPwd ASCII password hash
* @param uniPwd Unicode password hash
+ * @param vcNum Virtual circuit number
* @exception IOException If a network error occurs
* @exception SMBException If a CIFS error occurs
*/
public final void doSessionSetup(String domain, String userName, String wksName,
- byte[] ascPwd, byte[] uniPwd) throws IOException, SMBException
+ byte[] ascPwd, byte[] uniPwd, int vcNum)
+ throws IOException, SMBException
{
// Check if we are using extended security
@@ -1052,7 +1054,7 @@ public class AuthenticateSession
{
// Run the second phase of the extended security session setup
- doExtendedSessionSetupPhase2(domain, userName, wksName, ascPwd, uniPwd);
+ doExtendedSessionSetupPhase2(domain, userName, wksName, ascPwd, uniPwd, vcNum);
return;
}
@@ -1074,7 +1076,7 @@ public class AuthenticateSession
pkt.setParameter(1, 0); // offset to next command
pkt.setParameter(2, DefaultPacketSize);
pkt.setParameter(3, 1);
- pkt.setParameter(4, 0); // virtual circuit number
+ pkt.setParameter(4, vcNum);
pkt.setParameterLong(5, 0); // session key
// Set the share password length(s)
@@ -1121,7 +1123,7 @@ public class AuthenticateSession
pkt.packString("?", false);
pkt.packString("Java VM", false);
- pkt.packString("JLAN", false);
+ pkt.packString("Alfresco CIFS", false);
// Set the packet length
@@ -1175,7 +1177,7 @@ public class AuthenticateSession
clbuf.append("Java VM");
clbuf.append((char) 0x00);
- clbuf.append("JLAN");
+ clbuf.append("Alfresco CIFS");
clbuf.append((char) 0x00);
// Copy the remaining data to the SMB packet
@@ -1275,7 +1277,6 @@ public class AuthenticateSession
if (getDialect() == Dialect.NT)
{
-
// Read the returned negotiate parameters, for NT dialect the parameters are not aligned
m_pkt.resetParameterPointer();
@@ -1324,7 +1325,7 @@ public class AuthenticateSession
// Set the default flags for subsequent SMB requests
- defFlags2 = SMBPacket.FLG2_LONGFILENAMES + SMBPacket.FLG2_UNICODE + SMBPacket.FLG2_LONGERRORCODE;
+ defFlags2 = SMBPacket.FLG2_LONGFILENAMES + SMBPacket.FLG2_UNICODE + SMBPacket.FLG2_LONGERRORCODE + SMBPacket.FLG2_SECURITYSIG;
if ( isUsingExtendedSecurity())
defFlags2 += SMBPacket.FLG2_EXTENDEDSECURITY;
@@ -1485,7 +1486,7 @@ public class AuthenticateSession
// Pack the OS details
pkt.packString("Java VM", true);
- pkt.packString("JLAN", true);
+ pkt.packString("Alfresco CIFS", true);
pkt.packString("", true);
@@ -1555,11 +1556,12 @@ public class AuthenticateSession
* @param wksName String
* @param lmPwd byte[]
* @param ntlmPwd byte[]
+ * @param vcNum int
* @exception IOException If a network error occurs
* @eception SMBException If a CIFS error occurs
*/
private final void doExtendedSessionSetupPhase2(String domain, String userName, String wksName,
- byte[] lmPwd, byte[] ntlmPwd) throws IOException, SMBException
+ byte[] lmPwd, byte[] ntlmPwd, int vcNum) throws IOException, SMBException
{
// Check if the domain name has been specified, if not then use the domain name from the
// original connection details or the servers domain name
@@ -1590,7 +1592,7 @@ public class AuthenticateSession
pkt.setParameter(1, 0); // offset to next command
pkt.setParameter(2, DefaultPacketSize);
pkt.setParameter(3, 1);
- pkt.setParameter(4, 0); // virtual circuit number
+ pkt.setParameter(4, vcNum);
pkt.setParameterLong(5, 0); // session key
// Clear the security blob length and reserved area
@@ -1629,7 +1631,7 @@ public class AuthenticateSession
// Pack the OS details
pkt.packString("Java VM", true);
- pkt.packString("JLAN", true);
+ pkt.packString("Alfresco CIFS", true);
pkt.packString("", true);
@@ -1645,4 +1647,5 @@ public class AuthenticateSession
setGuest(pkt.getParameter(2) != 0 ? true : false);
}
+
}
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 96730a9f51..b9638b4d4a 100644
--- a/source/java/org/alfresco/filesys/server/auth/passthru/PassthruAuthenticator.java
+++ b/source/java/org/alfresco/filesys/server/auth/passthru/PassthruAuthenticator.java
@@ -24,7 +24,10 @@
*/
package org.alfresco.filesys.server.auth.passthru;
+import java.util.ArrayList;
import java.util.Hashtable;
+import java.util.List;
+import java.util.UUID;
import javax.transaction.UserTransaction;
@@ -33,14 +36,28 @@ import org.alfresco.error.AlfrescoRuntimeException;
import org.alfresco.filesys.server.SessionListener;
import org.alfresco.filesys.server.SrvSession;
import org.alfresco.filesys.server.auth.AuthContext;
+import org.alfresco.filesys.server.auth.AuthenticatorException;
import org.alfresco.filesys.server.auth.ClientInfo;
import org.alfresco.filesys.server.auth.CifsAuthenticator;
import org.alfresco.filesys.server.auth.NTLanManAuthContext;
+import org.alfresco.filesys.server.auth.ntlm.NTLM;
+import org.alfresco.filesys.server.auth.ntlm.NTLMMessage;
+import org.alfresco.filesys.server.auth.ntlm.TargetInfo;
+import org.alfresco.filesys.server.auth.ntlm.Type1NTLMMessage;
+import org.alfresco.filesys.server.auth.ntlm.Type2NTLMMessage;
+import org.alfresco.filesys.server.auth.ntlm.Type3NTLMMessage;
import org.alfresco.filesys.server.config.InvalidConfigurationException;
import org.alfresco.filesys.server.config.ServerConfiguration;
import org.alfresco.filesys.server.core.SharedDevice;
+import org.alfresco.filesys.smb.Capability;
+import org.alfresco.filesys.smb.SMBStatus;
import org.alfresco.filesys.smb.server.SMBServer;
+import org.alfresco.filesys.smb.server.SMBSrvException;
+import org.alfresco.filesys.smb.server.SMBSrvPacket;
import org.alfresco.filesys.smb.server.SMBSrvSession;
+import org.alfresco.filesys.smb.server.VirtualCircuit;
+import org.alfresco.filesys.util.DataPacker;
+import org.alfresco.filesys.util.HexDump;
import org.alfresco.model.ContentModel;
import org.alfresco.service.cmr.repository.NodeRef;
import org.apache.commons.logging.Log;
@@ -66,6 +83,18 @@ public class PassthruAuthenticator extends CifsAuthenticator implements SessionL
public final static int MinSessionTmo = 2000; // 2 seconds
public final static int MaxSessionTmo = 30000; // 30 seconds
+ // Passthru keep alive interval
+
+ public final static long PassthruKeepAliveInterval = 60000L; // 60 seconds
+
+ // NTLM flags mask, used to mask out features that are not supported
+
+ private static final int NTLM_FLAGS = NTLM.Flag56Bit +
+ NTLM.Flag128Bit +
+ NTLM.FlagLanManKey +
+ NTLM.FlagNegotiateNTLM +
+ NTLM.FlagNegotiateUnicode;
+
// Passthru servers used to authenticate users
private PassthruServers m_passthruServers;
@@ -192,7 +221,7 @@ public class PassthruAuthenticator extends CifsAuthenticator implements SessionL
// using the session that has already been setup.
AuthenticateSession authSess = passDetails.getAuthenticateSession();
- authSess.doSessionSetup(client.getDomain(), client.getUserName(), null, client.getANSIPassword(), client.getPassword());
+ authSess.doSessionSetup(client.getDomain(), client.getUserName(), null, client.getANSIPassword(), client.getPassword(), 0);
// Check if the user has been logged on as a guest
@@ -311,51 +340,43 @@ public class PassthruAuthenticator extends CifsAuthenticator implements SessionL
*/
public AuthContext getAuthContext( SMBSrvSession sess)
{
+ // Make sure the SMB server listener is installed
- // Check for an SMB session
+ if ( m_server == null && sess instanceof SMBSrvSession)
+ {
+ SMBSrvSession smbSess = (SMBSrvSession) sess;
+ m_server = smbSess.getSMBServer();
+
+ // Install the server listener
+
+ m_server.addSessionListener(this);
+ }
+
+ // Open a connection to the authentication server, use normal session setup
AuthContext authCtx = null;
-
- // Check if the client is already authenticated, and it is not a null logon
-
- if ( sess.hasAuthenticationContext() && sess.hasClientInformation() &&
- sess.getClientInformation().getAuthenticationToken() != null &&
- sess.getClientInformation().getLogonType() != ClientInfo.LogonNull)
- {
- // DEBUG
-
- if ( logger.isDebugEnabled())
- logger.debug("Re-using existing challenge, already authenticated");
-
- // Return the previous challenge, user is already authenticated
-
- return sess.getAuthenticationContext();
- }
-
+
try
{
-
- // Open a connection to the authentication server
-
- AuthenticateSession authSess = m_passthruServers.openSession();
- if (authSess != null)
- {
-
- // Create an entry in the active sessions table for the new session
-
- PassthruDetails passDetails = new PassthruDetails(sess, authSess);
- m_sessions.put(sess.getUniqueId(), passDetails);
-
- // Use the challenge key returned from the authentication server
-
- authCtx = new NTLanManAuthContext( authSess.getEncryptionKey());
- sess.setAuthenticationContext( authCtx);
-
- // DEBUG
-
- if (logger.isDebugEnabled())
- logger.debug("Passthru sessId=" + authSess.getSessionId() + ", auth ctx=" + authCtx);
- }
+ AuthenticateSession authSess = m_passthruServers.openSession();
+ if (authSess != null)
+ {
+
+ // Create an entry in the active sessions table for the new session
+
+ PassthruDetails passDetails = new PassthruDetails(sess, authSess, false);
+ m_sessions.put(sess.getUniqueId(), passDetails);
+
+ // Use the challenge key returned from the authentication server
+
+ authCtx = new NTLanManAuthContext( authSess.getEncryptionKey());
+ sess.setAuthenticationContext( authCtx);
+
+ // DEBUG
+
+ if (logger.isDebugEnabled())
+ logger.debug("Passthru sessId=" + authSess.getSessionId() + ", auth ctx=" + authCtx);
+ }
}
catch (Exception ex)
{
@@ -370,6 +391,685 @@ public class PassthruAuthenticator extends CifsAuthenticator implements SessionL
return authCtx;
}
+ /**
+ * Generate the CIFS negotiate response packet, the authenticator should add authentication specific fields
+ * to the response.
+ *
+ * @param sess SMBSrvSession
+ * @param respPkt SMBSrvPacket
+ * @param extendedSecurity boolean
+ * @exception AuthenticatorException
+ */
+ public void generateNegotiateResponse(SMBSrvSession sess, SMBSrvPacket respPkt, boolean extendedSecurity)
+ throws AuthenticatorException
+ {
+ // If the client does not support extended security then return a standard negotiate response
+ // with an 8 byte challenge
+
+ if ( extendedSecurity == false)
+ {
+ super.generateNegotiateResponse( sess, respPkt, extendedSecurity);
+ return;
+ }
+
+ // Make sure the extended security negotiation flag is set
+
+ if (( respPkt.getFlags2() & SMBSrvPacket.FLG2_EXTENDEDSECURITY) == 0)
+ respPkt.setFlags2( respPkt.getFlags2() + SMBSrvPacket.FLG2_EXTENDEDSECURITY);
+
+ // Get the negotiate response byte area position
+
+ int pos = respPkt.getByteOffset();
+ byte[] buf = respPkt.getBuffer();
+
+ // Pack the CIFS server GUID into the negotiate response
+
+ UUID serverGUID = sess.getSMBServer().getServerGUID();
+
+ DataPacker.putIntelLong( serverGUID.getLeastSignificantBits(), buf, pos);
+ DataPacker.putIntelLong( serverGUID.getMostSignificantBits(), buf, pos + 8);
+
+ pos += 16;
+
+ // Set the negotiate response length
+
+ respPkt.setByteCount(pos - respPkt.getByteOffset());
+ }
+
+ /**
+ * Process the CIFS session setup request packet and build the session setup response
+ *
+ * @param sess SMBSrvSession
+ * @param reqPkt SMBSrvPacket
+ * @param respPkt SMBSrvPacket
+ * @exception SMBSrvException
+ */
+ public void processSessionSetup(SMBSrvSession sess, SMBSrvPacket reqPkt, SMBSrvPacket respPkt)
+ throws SMBSrvException
+ {
+ // Check that the received packet looks like a valid NT session setup andX request
+
+ if (reqPkt.checkPacketIsValid(12, 0) == false)
+ throw new SMBSrvException(SMBStatus.NTInvalidParameter, SMBStatus.SRVNonSpecificError, SMBStatus.ErrSrv);
+
+ // Check if the request is using security blobs or the older hashed password format
+
+ if ( reqPkt.getParameterCount() == 13)
+ {
+ // Process the standard password session setup
+
+ super.processSessionSetup( sess, reqPkt, respPkt);
+ return;
+ }
+
+ // Extract the session details
+
+ int maxBufSize = reqPkt.getParameter(2);
+ int maxMpx = reqPkt.getParameter(3);
+ int vcNum = reqPkt.getParameter(4);
+ int secBlobLen = reqPkt.getParameter(7);
+ int capabs = reqPkt.getParameterLong(10);
+
+ // Extract the client details from the session setup request
+
+ int dataPos = reqPkt.getByteOffset();
+ byte[] buf = reqPkt.getBuffer();
+
+ // Determine if ASCII or unicode strings are being used
+
+ boolean isUni = reqPkt.isUnicode();
+
+ // Make a note of the security blob position
+
+ int secBlobPos = dataPos;
+
+ // Extract the clients primary domain name string
+
+ dataPos += secBlobLen;
+ reqPkt.setPosition( dataPos);
+
+ String domain = "";
+
+ if (reqPkt.hasMoreData()) {
+
+ // Extract the callers domain name
+
+ domain = reqPkt.unpackString(isUni);
+
+ if (domain == null)
+ throw new SMBSrvException(SMBStatus.NTInvalidParameter, SMBStatus.SRVNonSpecificError, SMBStatus.ErrSrv);
+ }
+
+ // Extract the clients native operating system
+
+ String clientOS = "";
+
+ if (reqPkt.hasMoreData()) {
+
+ // Extract the callers operating system name
+
+ clientOS = reqPkt.unpackString(isUni);
+
+ if (clientOS == null)
+ throw new SMBSrvException( SMBStatus.NTInvalidParameter, SMBStatus.SRVNonSpecificError, SMBStatus.ErrSrv);
+ }
+
+ // Store the client maximum buffer size, maximum multiplexed requests count and client capability flags
+
+ sess.setClientMaximumBufferSize(maxBufSize != 0 ? maxBufSize : SMBSrvSession.DefaultBufferSize);
+ sess.setClientMaximumMultiplex(maxMpx);
+ sess.setClientCapabilities(capabs);
+
+ // Create the client information and store in the session
+
+ ClientInfo client = new ClientInfo();
+ client.setDomain(domain);
+ client.setOperatingSystem(clientOS);
+
+ client.setLogonType( ClientInfo.LogonNormal);
+
+ // Set the remote address, if available
+
+ if ( sess.hasRemoteAddress())
+ client.setClientAddress(sess.getRemoteAddress().getHostAddress());
+
+ // Set the process id for this client, for multi-stage logons
+
+ client.setProcessId( reqPkt.getProcessId());
+
+ // Get the current sesion setup object, or null
+
+ Object setupObj = sess.getSetupObject( client.getProcessId());
+
+ // Process the security blob
+
+ byte[] respBlob = null;
+ boolean isNTLMSSP = false;
+
+ try
+ {
+
+ // Check if the blob has the NTLMSSP signature
+
+ if ( secBlobLen >= NTLM.Signature.length) {
+
+ // Check for the NTLMSSP signature
+
+ int idx = 0;
+ while ( idx < NTLM.Signature.length && buf[secBlobPos + idx] == NTLM.Signature[ idx])
+ idx++;
+
+ if ( idx == NTLM.Signature.length)
+ isNTLMSSP = true;
+ }
+
+ // Process the security blob
+
+ if ( isNTLMSSP == true)
+ {
+ // DEBUG
+
+ if (logger.isDebugEnabled())
+ logger.debug("NT Session setup NTLMSSP, MID=" + reqPkt.getMultiplexId() + ", UID=" + reqPkt.getUserId() + ", PID=" + reqPkt.getProcessId());
+
+ // Process an NTLMSSP security blob
+
+ respBlob = doNtlmsspSessionSetup( sess, client, buf, secBlobPos, secBlobLen, isUni);
+ }
+ else
+ {
+ // Invalid blob type
+
+ throw new SMBSrvException( SMBStatus.NTInvalidParameter, SMBStatus.SRVNonSpecificError, SMBStatus.ErrSrv);
+ }
+ }
+ catch (SMBSrvException ex)
+ {
+ // Cleanup any stored context
+
+ sess.removeSetupObject( client.getProcessId());
+
+ // Rethrow the exception
+
+ throw ex;
+ }
+
+ // Debug
+
+ if ( logger.isDebugEnabled() && sess.hasDebug(SMBSrvSession.DBG_NEGOTIATE))
+ logger.debug("User " + client.getUserName() + " logged on " + (client != null ? " (type " + client.getLogonTypeString() + ")" : ""));
+
+ // Update the client information if not already set
+
+ if ( sess.getClientInformation() == null ||
+ sess.getClientInformation().getUserName().length() == 0) {
+
+ // Set the client details for the session
+
+ sess.setClientInformation(client);
+ }
+
+ // Get the response blob length, it can be null
+
+ int respLen = respBlob != null ? respBlob.length : 0;
+
+ // Check if there is/was a session setup object stored in the session, this indicates a multi-stage session
+ // setup so set the status code accordingly
+
+ boolean loggedOn = false;
+
+ if ( isNTLMSSP == true || sess.hasSetupObject( client.getProcessId()) || setupObj != null)
+ {
+ // NTLMSSP has two stages, if there is a stored setup object then indicate more processing
+ // required
+
+ if ( sess.hasSetupObject( client.getProcessId()))
+ respPkt.setLongErrorCode( SMBStatus.NTMoreProcessingRequired);
+ else
+ {
+ respPkt.setLongErrorCode( SMBStatus.NTSuccess);
+
+ // Indicate that the user is logged on
+
+ loggedOn = true;
+ }
+
+ respPkt.setParameterCount(4);
+ respPkt.setParameter(0, 0xFF); // No chained response
+ respPkt.setParameter(1, 0); // Offset to chained response
+
+ respPkt.setParameter(2, 0); // Action
+ respPkt.setParameter(3, respLen);
+ }
+ else
+ {
+ // Build a completed session setup response
+
+ respPkt.setLongErrorCode( SMBStatus.NTSuccess);
+
+ // Build the session setup response SMB
+
+ respPkt.setParameterCount(12);
+ respPkt.setParameter(0, 0xFF); // No chained response
+ respPkt.setParameter(1, 0); // Offset to chained response
+
+ respPkt.setParameter(2, SMBSrvSession.DefaultBufferSize);
+ respPkt.setParameter(3, SMBSrvSession.NTMaxMultiplexed);
+ respPkt.setParameter(4, 0); // virtual circuit number
+ respPkt.setParameterLong(5, 0); // session key
+ respPkt.setParameter(7, respLen);
+ // security blob length
+ respPkt.setParameterLong(8, 0); // reserved
+ respPkt.setParameterLong(10, getServerCapabilities());
+
+ // Indicate that the user is logged on
+
+ loggedOn = true;
+ }
+
+ // If the user is logged on then allocate a virtual circuit
+
+ int uid = 0;
+
+ if ( loggedOn == true) {
+
+ // Clear any stored session setup object for the logon
+
+ sess.removeSetupObject( client.getProcessId());
+
+ // Create a virtual circuit for the new logon
+
+ VirtualCircuit vc = new VirtualCircuit( vcNum, client);
+ uid = sess.addVirtualCircuit( vc);
+
+ if ( uid == VirtualCircuit.InvalidUID)
+ {
+ // DEBUG
+
+ if ( logger.isDebugEnabled() && sess.hasDebug( SMBSrvSession.DBG_NEGOTIATE))
+ logger.debug("Failed to allocate UID for virtual circuit, " + vc);
+
+ // Failed to allocate a UID
+
+ throw new SMBSrvException(SMBStatus.NTLogonFailure, SMBStatus.DOSAccessDenied, SMBStatus.ErrDos);
+ }
+ else if ( logger.isDebugEnabled() && sess.hasDebug( SMBSrvSession.DBG_NEGOTIATE)) {
+
+ // DEBUG
+
+ logger.debug("Allocated UID=" + uid + " for VC=" + vc);
+ }
+ }
+
+ // Common session setup response
+
+ respPkt.setCommand( reqPkt.getCommand());
+ respPkt.setByteCount(0);
+
+ respPkt.setTreeId( 0);
+ respPkt.setUserId( uid);
+
+ // Set the various flags
+
+ int flags = respPkt.getFlags();
+ flags &= ~SMBSrvPacket.FLG_CASELESS;
+ respPkt.setFlags(flags);
+
+ int flags2 = SMBSrvPacket.FLG2_LONGFILENAMES + SMBSrvPacket.FLG2_EXTENDEDSECURITY + SMBSrvPacket.FLG2_LONGERRORCODE;
+ if ( isUni)
+ flags2 += SMBSrvPacket.FLG2_UNICODE;
+ respPkt.setFlags2( flags2);
+
+ // Pack the security blob
+
+ int pos = respPkt.getByteOffset();
+ buf = respPkt.getBuffer();
+
+ if ( respBlob != null)
+ {
+ System.arraycopy( respBlob, 0, buf, pos, respBlob.length);
+ pos += respBlob.length;
+ }
+
+ // Pack the OS, dialect and domain name strings
+
+ if ( isUni)
+ pos = DataPacker.wordAlign(pos);
+
+ pos = DataPacker.putString("Java", buf, pos, true, isUni);
+ pos = DataPacker.putString("Alfresco CIFS Server " + sess.getServer().isVersion(), buf, pos, true, isUni);
+ pos = DataPacker.putString(sess.getServer().getConfiguration().getDomainName(), buf, pos, true, isUni);
+
+ respPkt.setByteCount(pos - respPkt.getByteOffset());
+ }
+
+ /**
+ * Process an NTLMSSP security blob
+ *
+ * @param sess SMBSrvSession
+ * @param client ClientInfo
+ * @param secbuf byte[]
+ * @param secpos int
+ * @param seclen int
+ * @param unicode boolean
+ * @exception SMBSrvException
+ */
+ private final byte[] doNtlmsspSessionSetup( SMBSrvSession sess, ClientInfo client,
+ byte[] secbuf, int secpos, int seclen, boolean unicode) throws SMBSrvException
+ {
+ // Determine the NTLmSSP message type
+
+ int msgType = NTLMMessage.isNTLMType( secbuf, secpos);
+ byte[] respBlob = null;
+
+ if ( msgType == -1)
+ {
+ // DEBUG
+
+ if ( logger.isDebugEnabled())
+ {
+ logger.debug("Invalid NTLMSSP token received");
+ logger.debug(" Token=" + HexDump.hexString( secbuf, secpos, seclen, " "));
+ }
+
+ // Return a logon failure status
+
+ throw new SMBSrvException( SMBStatus.NTLogonFailure, SMBStatus.DOSAccessDenied, SMBStatus.ErrDos);
+ }
+
+ // Check for a type 1 NTLMSSP message
+
+ else if ( msgType == NTLM.Type1)
+ {
+ // Create the type 1 NTLM message from the token
+
+ Type1NTLMMessage type1Msg = new Type1NTLMMessage( secbuf, secpos, seclen);
+
+ // Build the type 2 NTLM response message
+ //
+ // Get the flags from the client request and mask out unsupported features
+
+ int ntlmFlags = type1Msg.getFlags() & NTLM_FLAGS;
+
+ // Generate a challenge for the response
+
+ NTLanManAuthContext ntlmCtx = (NTLanManAuthContext) getAuthContext( sess);
+
+ // Build a type2 message to send back to the client, containing the challenge
+
+ String domain = sess.getSMBServer().getServerName();
+
+ List tList = new ArrayList();
+
+ tList.add(new TargetInfo(NTLM.TargetDomain, domain));
+ tList.add(new TargetInfo(NTLM.TargetServer, sess.getServerName()));
+ tList.add(new TargetInfo(NTLM.TargetDNSDomain, domain));
+ tList.add(new TargetInfo(NTLM.TargetFullDNS, domain));
+
+ ntlmFlags = NTLM.FlagChallengeAccept + NTLM.FlagRequestTarget +
+ NTLM.FlagNegotiateNTLM + NTLM.FlagNegotiateUnicode +
+ NTLM.FlagKeyExchange + NTLM.FlagTargetInfo + NTLM.Flag56Bit;
+
+ // NTLM.FlagAlwaysSign + NTLM.FlagNegotiateSign +
+
+ Type2NTLMMessage type2Msg = new Type2NTLMMessage();
+
+ type2Msg.buildType2(ntlmFlags, domain, ntlmCtx.getChallenge(), null, tList);
+
+ // Store the type 2 message in the session until the session setup is complete
+
+ sess.setSetupObject( client.getProcessId(), type2Msg);
+
+ // Set the response blob using the type 2 message
+
+ respBlob = type2Msg.getBytes();
+ }
+ else if ( msgType == NTLM.Type3)
+ {
+ // Create the type 3 NTLM message from the token
+
+ Type3NTLMMessage type3Msg = new Type3NTLMMessage( secbuf, secpos, seclen, unicode);
+
+ // Make sure a type 2 message was stored in the first stage of the session setup
+
+ if ( sess.hasSetupObject( client.getProcessId()) == false || sess.getSetupObject( client.getProcessId()) instanceof Type2NTLMMessage == false)
+ {
+ // Clear the setup object
+
+ sess.removeSetupObject( client.getProcessId());
+
+ // Return a logon failure
+
+ throw new SMBSrvException( SMBStatus.NTLogonFailure, SMBStatus.DOSAccessDenied, SMBStatus.ErrDos);
+ }
+
+ // Determine if the client sent us NTLMv1 or NTLMv2
+
+ if ( type3Msg.hasFlag( NTLM.Flag128Bit) && type3Msg.hasFlag( NTLM.FlagNTLM2Key))
+ {
+ // Debug
+
+ if ( logger.isDebugEnabled())
+ logger.debug("Received NTLMSSP/NTLMv2, not supported");
+
+ // Return a logon failure
+
+ throw new SMBSrvException( SMBStatus.NTLogonFailure, SMBStatus.DOSAccessDenied, SMBStatus.ErrDos);
+ }
+ else
+ {
+ // Looks like an NTLMv1 blob
+
+ doNTLMv1Logon( sess, client, type3Msg);
+
+ // Debug
+
+ if ( logger.isDebugEnabled())
+ logger.debug("Logged on using NTLMSSP/NTLMv1");
+ }
+ }
+
+ // Return the response blob
+
+ return respBlob;
+ }
+
+ /**
+ * Perform an NTLMv1 logon using the NTLMSSP type3 message
+ *
+ * @param sess SMBSrvSession
+ * @param client ClientInfo
+ * @param type3Msg Type3NTLMMessage
+ * @exception SMBSrvException
+ */
+ private final void doNTLMv1Logon(SMBSrvSession sess, ClientInfo client, Type3NTLMMessage type3Msg)
+ throws SMBSrvException
+ {
+ // Get the type 2 message that contains the challenge sent to the client
+
+ Type2NTLMMessage type2Msg = (Type2NTLMMessage) sess.getSetupObject( client.getProcessId());
+ sess.removeSetupObject( client.getProcessId());
+
+ // Get the NTLM logon details
+
+ String userName = type3Msg.getUserName();
+
+ // Check for a null logon
+
+ if ( userName.length() == 0)
+ {
+ // DEBUG
+
+ if ( logger.isDebugEnabled())
+ logger.debug("Null logon");
+
+ // Indicate a null logon in the client information
+
+ client.setLogonType( ClientInfo.LogonNull);
+ return;
+ }
+
+ // Find the active authentication session details for the server session
+
+ PassthruDetails passDetails = m_sessions.get(sess.getUniqueId());
+
+ if (passDetails != null)
+ {
+ try
+ {
+ // Authenticate the user by passing the hashed password to the authentication server
+ // using the session that has already been setup.
+
+ AuthenticateSession authSess = passDetails.getAuthenticateSession();
+ authSess.doSessionSetup( type3Msg.getDomain(), userName, null, type3Msg.getLMHash(), type3Msg.getNTLMHash(), 0);
+
+ // Check if the user has been logged on as a guest
+
+ if (authSess.isGuest())
+ {
+ // Check if the local server allows guest access
+
+ if (allowGuest() == true)
+ {
+ // Get a guest authentication token
+
+ doGuestLogon( client, sess);
+
+ // Debug
+
+ if (logger.isDebugEnabled())
+ logger.debug("Passthru authenticate user=" + userName + ", GUEST");
+ }
+ }
+ else
+ {
+ // Wrap the service calls in a transaction
+
+ UserTransaction tx = m_transactionService.getUserTransaction( false);
+
+ try
+ {
+ // Start the transaction
+
+ tx.begin();
+
+ // Map the passthru username to an Alfresco person
+
+ NodeRef userNode = m_personService.getPerson(userName);
+ if ( userNode != null)
+ {
+ // Get the person name and use that as the current user to line up with permission checks
+
+ String personName = (String) m_nodeService.getProperty(userNode, ContentModel.PROP_USERNAME);
+ m_authComponent.setCurrentUser(personName);
+
+ // DEBUG
+
+ if ( logger.isDebugEnabled())
+ logger.debug("Setting current user using person " + personName + " (username " + userName + ")");
+ }
+ else
+ {
+ // Set using the user name
+
+ m_authComponent.setCurrentUser( userName);
+
+ // DEBUG
+
+ if ( logger.isDebugEnabled())
+ logger.debug("Setting current user using username " + userName);
+ }
+
+ // Get the authentication token and store
+
+ client.setAuthenticationToken( m_authComponent.getCurrentAuthentication());
+
+ // Indicate that the client is logged on
+
+ client.setLogonType( ClientInfo.LogonNormal);
+
+ // Debug
+
+ if (logger.isDebugEnabled())
+ logger.debug("Passthru authenticate user=" + userName + ", FULL");
+ }
+ finally
+ {
+ // Commit the transaction
+
+ if ( tx != null)
+ {
+ try {
+ tx.commit();
+ }
+ catch (Exception ex)
+ {
+ // Sink it
+ }
+ }
+ }
+ }
+
+ // Update the client details
+
+ client.setDomain( type3Msg.getDomain());
+ client.setUserName( userName);
+ }
+ catch (Exception ex)
+ {
+
+ // Debug
+
+ logger.error(ex.getMessage());
+
+ // Indicate logon failure
+
+ throw new SMBSrvException( SMBStatus.NTErr, SMBStatus.NTLogonFailure);
+ }
+ finally
+ {
+ // Remove the passthru session from the active list
+
+ m_sessions.remove(sess.getUniqueId());
+
+ // Close the passthru authentication session
+
+ try
+ {
+
+ // Close the authentication session
+
+ AuthenticateSession authSess = passDetails.getAuthenticateSession();
+ authSess.CloseSession();
+
+ // DEBUG
+
+ if (logger.isDebugEnabled())
+ logger.debug("Closed auth session, sessId=" + authSess.getSessionId());
+ }
+ catch (Exception ex)
+ {
+
+ // Debug
+
+ logger.error("Passthru error closing session (auth user)", ex);
+ }
+ }
+ }
+ else
+ {
+
+ // DEBUG
+
+ if (logger.isDebugEnabled())
+ logger.debug(" No PassthruDetails for " + sess.getUniqueId());
+
+ // Indicate logon failure
+
+ throw new SMBSrvException( SMBStatus.NTErr, SMBStatus.NTLogonFailure);
+ }
+ }
+
/**
* Initialzie the authenticator
*
@@ -510,6 +1210,18 @@ public class PassthruAuthenticator extends CifsAuthenticator implements SessionL
smbServer.addSessionListener(this);
}
+ /**
+ * Return the server capability flags
+ *
+ * @return int
+ */
+ public int getServerCapabilities()
+ {
+ return Capability.Unicode + Capability.RemoteAPIs + Capability.NTSMBs + Capability.NTFind +
+ Capability.NTStatus + Capability.LargeFiles + Capability.LargeRead + Capability.LargeWrite +
+ Capability.ExtendedSecurity;
+ }
+
/**
* Close the authenticator, perform cleanup
*/
@@ -520,7 +1232,7 @@ public class PassthruAuthenticator extends CifsAuthenticator implements SessionL
if ( m_passthruServers != null)
m_passthruServers.shutdown();
}
-
+
/**
* SMB server session closed notification
*
@@ -582,48 +1294,37 @@ public class PassthruAuthenticator extends CifsAuthenticator implements SessionL
*/
public void sessionLoggedOn(SrvSession sess)
{
+ // Check if there is an active session to the authentication server for this local
+ // session
- // Check if the client information has an empty user name, if so then do not close the
- // authentication session
+ PassthruDetails passDetails = m_sessions.get(sess.getUniqueId());
- if (sess.hasClientInformation() && sess.getClientInformation().getUserName() != null
- && sess.getClientInformation().getUserName().length() > 0)
+ if (passDetails != null && passDetails.hasKeepAlive() == false)
{
+ // Remove the passthru session from the active list
- // Check if there is an active session to the authentication server for this local
- // session
+ m_sessions.remove(sess.getUniqueId());
- PassthruDetails passDetails = m_sessions.get(sess.getUniqueId());
+ // Close the passthru authentication session
- if (passDetails != null)
+ try
+ {
+ // Close the authentication session
+
+ AuthenticateSession authSess = passDetails.getAuthenticateSession();
+ authSess.CloseSession();
+
+ // DEBUG
+
+ if (logger.isDebugEnabled())
+ logger.debug("Closed auth session, sessId=" + authSess.getSessionId());
+ }
+ catch (Exception ex)
{
- // Remove the passthru session from the active list
+ // Debug
- m_sessions.remove(sess.getUniqueId());
-
- // Close the passthru authentication session
-
- try
- {
-
- // Close the authentication session
-
- AuthenticateSession authSess = passDetails.getAuthenticateSession();
- authSess.CloseSession();
-
- // DEBUG
-
- if (logger.isDebugEnabled())
- logger.debug("Closed auth session, sessId=" + authSess.getSessionId());
- }
- catch (Exception ex)
- {
-
- // Debug
-
- logger.error("Passthru error closing session (logon)", ex);
- }
+ logger.error("Passthru error closing session (logon)", ex);
}
}
}
diff --git a/source/java/org/alfresco/filesys/server/auth/passthru/PassthruDetails.java b/source/java/org/alfresco/filesys/server/auth/passthru/PassthruDetails.java
index 9d2d174cd0..1fc9b5a6a2 100644
--- a/source/java/org/alfresco/filesys/server/auth/passthru/PassthruDetails.java
+++ b/source/java/org/alfresco/filesys/server/auth/passthru/PassthruDetails.java
@@ -34,7 +34,6 @@ import org.alfresco.filesys.server.SrvSession;
*/
class PassthruDetails
{
-
// Server session
private SrvSession m_sess;
@@ -43,6 +42,10 @@ class PassthruDetails
private AuthenticateSession m_authSess;
+ // Flag to indicate if session should be kept alive
+
+ private boolean m_keepAlive;
+
/**
* Class constructor
*
@@ -55,6 +58,21 @@ class PassthruDetails
m_authSess = authSess;
}
+ /**
+ * Class constructor
+ *
+ * @param sess SrvSession
+ * @param authSess AuthenticateSession
+ * @param keepAlive boolean
+ */
+ public PassthruDetails(SrvSession sess, AuthenticateSession authSess, boolean keepAlive)
+ {
+ m_sess = sess;
+ m_authSess = authSess;
+
+ m_keepAlive = keepAlive;
+ }
+
/**
* Return the session details
*
@@ -74,4 +92,14 @@ class PassthruDetails
{
return m_authSess;
}
+
+ /**
+ * Check if the authentication session should be kept alive
+ *
+ * @return boolean
+ */
+ public final boolean hasKeepAlive()
+ {
+ return m_keepAlive;
+ }
}
diff --git a/source/java/org/alfresco/filesys/server/auth/passthru/PassthruServers.java b/source/java/org/alfresco/filesys/server/auth/passthru/PassthruServers.java
index 4b52a157d7..423d9be333 100644
--- a/source/java/org/alfresco/filesys/server/auth/passthru/PassthruServers.java
+++ b/source/java/org/alfresco/filesys/server/auth/passthru/PassthruServers.java
@@ -306,16 +306,16 @@ public class PassthruServers
*/
public final AuthenticateSession openSession()
{
- return openSession( 0);
+ return openSession( false);
}
/**
* Open a new session to an authentication server
*
- * @param extFlags int
+ * @param useExtSec boolean
* @return AuthenticateSession
*/
- public final AuthenticateSession openSession(int extFlags)
+ public final AuthenticateSession openSession(boolean useExtSec)
{
// Get the details of an authentication server to connect to
@@ -331,7 +331,8 @@ public class PassthruServers
// Open a new authentication session to the server
PCShare authShare = new PCShare(passthruServer.getAddress().getHostAddress(), "IPC$", "", "");
- authShare.setExtendedSecurityFlags( extFlags);
+ if ( useExtSec == true)
+ authShare.setExtendedSecurityFlags( SMBPacket.FLG2_EXTENDEDSECURITY);
AuthenticateSession authSess = null;
diff --git a/source/java/org/alfresco/filesys/server/auth/passthru/SMBPacket.java b/source/java/org/alfresco/filesys/server/auth/passthru/SMBPacket.java
index 491be0949e..df20e6f664 100644
--- a/source/java/org/alfresco/filesys/server/auth/passthru/SMBPacket.java
+++ b/source/java/org/alfresco/filesys/server/auth/passthru/SMBPacket.java
@@ -88,6 +88,7 @@ public class SMBPacket
public static final int FLG2_LONGFILENAMES = 0x0001;
public static final int FLG2_EXTENDEDATTRIB = 0x0002;
+ public static final int FLG2_SECURITYSIG = 0x0004;
public static final int FLG2_EXTENDEDSECURITY = 0x0800;
public static final int FLG2_READIFEXE = 0x2000;
public static final int FLG2_LONGERRORCODE = 0x4000;
@@ -589,6 +590,16 @@ public class SMBPacket
}
/**
+ * Get the SMB signing value, as a long value
+ *
+ * @return long
+ */
+ public final long getSignature()
+ {
+ return DataPacker.getIntelLong( m_smbbuf, SIGNATURE);
+ }
+
+ /**
* Get the tree identifier (TID)
*
* @return Tree identifier (TID)
@@ -1131,6 +1142,16 @@ public class SMBPacket
}
/**
+ * Set a long error code (NT status code)
+ *
+ * @param sts int
+ */
+ public final void setLongErrorCode(int lsts)
+ {
+ DataPacker.putIntelInt(lsts, m_smbbuf, ERRORCODE);
+ }
+
+ /**
* Set the SMB flags value.
*
* @param flg SMB flags value.
@@ -1225,6 +1246,38 @@ public class SMBPacket
DataPacker.putIntelShort(sid, m_smbbuf, SID);
}
+ /**
+ * Set the SMB signing signature
+ *
+ * @param ival int
+ */
+ public final void setSignature( int ival)
+ {
+ DataPacker.putIntelInt( ival, m_smbbuf, SIGNATURE);
+ DataPacker.putZeros( m_smbbuf, SIGNATURE + 4, 4);
+ }
+
+ /**
+ * Set the SMB signing signature
+ *
+ * @param lval long
+ */
+ public final void setSignature( long lval)
+ {
+ DataPacker.putIntelLong( lval, m_smbbuf, SIGNATURE);
+ }
+
+ /**
+ * Set the SMB signing signature
+ *
+ * @param byts byte[]
+ * @param offset int
+ */
+ public final void setSignature( byte[] byts, int offset)
+ {
+ System.arraycopy( byts, offset, m_smbbuf, SIGNATURE, 8);
+ }
+
/**
* Set the tree identifier (TID)
*
diff --git a/source/java/org/alfresco/filesys/server/config/ServerConfiguration.java b/source/java/org/alfresco/filesys/server/config/ServerConfiguration.java
index 4221730ee1..b905c1b867 100644
--- a/source/java/org/alfresco/filesys/server/config/ServerConfiguration.java
+++ b/source/java/org/alfresco/filesys/server/config/ServerConfiguration.java
@@ -1254,20 +1254,39 @@ public class ServerConfiguration extends AbstractLifecycleBean
String lanaStr = elem.getAttribute("lana");
if (lanaStr != null && lanaStr.length() > 0)
{
-
- // Validate the LANA number
-
+ // Check if the LANA has been specified as an IP address or adapter name
+
int lana = -1;
-
- try
+
+ if ( IPAddress.isNumericAddress( lanaStr))
{
- lana = Integer.parseInt(lanaStr);
- }
- catch (NumberFormatException ex)
- {
- throw new AlfrescoRuntimeException("Invalid win32 NetBIOS LANA specified");
+
+ // 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
+ {
+ lana = Integer.parseInt(lanaStr);
+ }
+ catch (NumberFormatException ex)
+ {
+ throw new AlfrescoRuntimeException("Invalid win32 NetBIOS LANA specified");
+ }
+ }
+
// LANA should be in the range 0-255
if (lana < 0 || lana > 255)
@@ -2265,8 +2284,8 @@ public class ServerConfiguration extends AbstractLifecycleBean
{
// Check if the appropriate authentication component type is configured
- if ( ntlmMode != NTLMMode.NONE)
- throw new AlfrescoRuntimeException("Wrong authentication setup for passthru authenticator (can only be used with LDAP/JAAS auth component)");
+ if ( ntlmMode == NTLMMode.MD4_PROVIDER)
+ throw new AlfrescoRuntimeException("Wrong authentication setup for passthru authenticator (cannot be used with Alfresco users)");
// Load the passthru authenticator dynamically
diff --git a/source/java/org/alfresco/filesys/smb/server/NTProtocolHandler.java b/source/java/org/alfresco/filesys/smb/server/NTProtocolHandler.java
index a8b5d942ac..ae319b9c0b 100644
--- a/source/java/org/alfresco/filesys/smb/server/NTProtocolHandler.java
+++ b/source/java/org/alfresco/filesys/smb/server/NTProtocolHandler.java
@@ -3153,6 +3153,17 @@ public class NTProtocolHandler extends CoreProtocolHandler
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
SearchContext ctx = null;
diff --git a/source/java/org/alfresco/filesys/smb/server/SMBSrvSession.java b/source/java/org/alfresco/filesys/smb/server/SMBSrvSession.java
index 240edc84cf..60428451aa 100644
--- a/source/java/org/alfresco/filesys/smb/server/SMBSrvSession.java
+++ b/source/java/org/alfresco/filesys/smb/server/SMBSrvSession.java
@@ -313,6 +313,16 @@ public class SMBSrvSession extends SrvSession implements Runnable
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
* change notification requests.
diff --git a/source/java/org/alfresco/repo/jscript/Node.java b/source/java/org/alfresco/repo/jscript/Node.java
index ad5e08e2ec..13deb28c83 100644
--- a/source/java/org/alfresco/repo/jscript/Node.java
+++ b/source/java/org/alfresco/repo/jscript/Node.java
@@ -46,7 +46,9 @@ import org.alfresco.service.ServiceRegistry;
import org.alfresco.service.cmr.dictionary.DataTypeDefinition;
import org.alfresco.service.cmr.dictionary.DictionaryService;
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.FileNotFoundException;
import org.alfresco.service.cmr.repository.AssociationRef;
import org.alfresco.service.cmr.repository.ChildAssociationRef;
import org.alfresco.service.cmr.repository.ContentData;
@@ -298,6 +300,24 @@ public class Node implements Serializable, Scopeable
{
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());
}
}
diff --git a/source/java/org/alfresco/repo/node/db/DbNodeServiceImplTest.java b/source/java/org/alfresco/repo/node/db/DbNodeServiceImplTest.java
index 89661151ee..bccee2bac1 100644
--- a/source/java/org/alfresco/repo/node/db/DbNodeServiceImplTest.java
+++ b/source/java/org/alfresco/repo/node/db/DbNodeServiceImplTest.java
@@ -35,6 +35,8 @@ import javax.transaction.UserTransaction;
import org.alfresco.model.ContentModel;
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.node.BaseNodeServiceTest;
import org.alfresco.repo.transaction.AlfrescoTransactionSupport;
@@ -353,4 +355,29 @@ public class DbNodeServiceImplTest extends BaseNodeServiceTest
mlTextProperty,
propertiesDirect.get(BaseNodeServiceTest.PROP_QNAME_ML_TEXT_VALUE));
}
+
+ public void testDuplicatePrimaryParentHandling() throws Exception
+ {
+ Map 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);
+ }
}
diff --git a/source/java/org/alfresco/repo/node/db/hibernate/HibernateNodeDaoServiceImpl.java b/source/java/org/alfresco/repo/node/db/hibernate/HibernateNodeDaoServiceImpl.java
index cd0f89cfa7..65a2347c54 100644
--- a/source/java/org/alfresco/repo/node/db/hibernate/HibernateNodeDaoServiceImpl.java
+++ b/source/java/org/alfresco/repo/node/db/hibernate/HibernateNodeDaoServiceImpl.java
@@ -900,6 +900,15 @@ public class HibernateNodeDaoServiceImpl extends HibernateDaoSupport implements
getSession().flush();
}
+ private Set warnedDuplicateParents = new HashSet(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)
{
// get the assocs pointing to the node
@@ -914,12 +923,20 @@ public class HibernateNodeDaoServiceImpl extends HibernateDaoSupport implements
}
else if (primaryAssoc != null)
{
- // we have more than one somehow
- throw new DataIntegrityViolationException(
- "Multiple primary associations: \n" +
- " child: " + node + "\n" +
- " first primary assoc: " + primaryAssoc + "\n" +
- " second primary assoc: " + assoc);
+ // We have found one already.
+ synchronized(warnedDuplicateParents)
+ {
+ NodeRef childNodeRef = node.getNodeRef();
+ boolean added = warnedDuplicateParents.add(childNodeRef);
+ if (added)
+ {
+ logger.warn(
+ "Multiple primary associations: \n" +
+ " first primary assoc: " + primaryAssoc + "\n" +
+ " second primary assoc: " + assoc + "\n" +
+ "When running in a cluster, check that the caches are properly shared.");
+ }
+ }
}
primaryAssoc = assoc;
// we keep looping to hunt out data integrity issues
@@ -938,9 +955,21 @@ public class HibernateNodeDaoServiceImpl extends HibernateDaoSupport implements
}
if (!rootNode.equals(node))
{
- // it wasn't the root node
- throw new DataIntegrityViolationException("Non-root node has no primary parent: \n" +
- " child: " + node);
+ // Reload the node to ensure that it is properly initialized
+ 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);
+ }
+ else
+ {
+ // Repeat this method with confidence
+ primaryAssoc = getPrimaryParentAssoc(node);
+ }
}
}
// done
diff --git a/source/java/org/alfresco/repo/node/index/IndexRecoveryBootstrapBean.java b/source/java/org/alfresco/repo/node/index/IndexRecoveryBootstrapBean.java
new file mode 100644
index 0000000000..2b4dc16904
--- /dev/null
+++ b/source/java/org/alfresco/repo/node/index/IndexRecoveryBootstrapBean.java
@@ -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;
+ }
+
+}