/* * Copyright (C) 2005-2007 Alfresco Software Limited. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * As a special exception to the terms and conditions of version 2.0 of * the GPL, you may redistribute this Program in connection with Free/Libre * and Open Source Software ("FLOSS") applications as described in Alfresco's * FLOSS exception. You should have recieved a copy of the text describing * the FLOSS exception, and it is also available here: * http://www.alfresco.com/legal/licensing" */ package org.alfresco.filesys; import java.io.IOException; import java.net.InetAddress; import java.net.InetSocketAddress; import java.net.NetworkInterface; import java.net.Socket; import java.net.SocketException; import java.net.UnknownHostException; import java.nio.charset.Charset; import java.nio.charset.IllegalCharsetNameException; import java.nio.charset.UnsupportedCharsetException; import java.util.ArrayList; import java.util.EnumSet; import java.util.Enumeration; import java.util.List; import java.util.Locale; import java.util.StringTokenizer; import org.alfresco.jlan.debug.DebugConfigSection; import org.alfresco.jlan.ftp.FTPConfigSection; import org.alfresco.jlan.ftp.FTPPath; import org.alfresco.jlan.ftp.InvalidPathException; import org.alfresco.jlan.netbios.NetBIOSName; import org.alfresco.jlan.netbios.NetBIOSNameList; import org.alfresco.jlan.netbios.NetBIOSSession; import org.alfresco.jlan.netbios.RFCNetBIOSProtocol; import org.alfresco.jlan.netbios.win32.Win32NetBIOS; import org.alfresco.jlan.oncrpc.nfs.NFSConfigSection; import org.alfresco.jlan.server.auth.CifsAuthenticator; import org.alfresco.jlan.server.auth.ClientInfo; import org.alfresco.jlan.server.auth.acl.ACLParseException; import org.alfresco.jlan.server.auth.acl.AccessControl; import org.alfresco.jlan.server.auth.acl.AccessControlList; import org.alfresco.jlan.server.auth.acl.AccessControlParser; import org.alfresco.jlan.server.auth.acl.InvalidACLTypeException; import org.alfresco.jlan.server.auth.passthru.DomainMapping; import org.alfresco.jlan.server.auth.passthru.RangeDomainMapping; import org.alfresco.jlan.server.auth.passthru.SubnetDomainMapping; import org.alfresco.jlan.server.config.CoreServerConfigSection; import org.alfresco.jlan.server.config.GlobalConfigSection; import org.alfresco.jlan.server.config.InvalidConfigurationException; import org.alfresco.jlan.server.config.SecurityConfigSection; import org.alfresco.jlan.server.config.ServerConfiguration; import org.alfresco.jlan.server.core.DeviceContextException; import org.alfresco.jlan.server.core.ShareType; import org.alfresco.jlan.server.filesys.DiskInterface; import org.alfresco.jlan.server.filesys.DiskSharedDevice; import org.alfresco.jlan.server.filesys.FilesystemsConfigSection; import org.alfresco.jlan.server.thread.ThreadRequestPool; import org.alfresco.jlan.smb.server.CIFSConfigSection; import org.alfresco.jlan.util.IPAddress; import org.alfresco.jlan.util.MemorySize; import org.alfresco.jlan.util.Platform; import org.alfresco.jlan.util.StringList; import org.alfresco.jlan.util.X64; import org.alfresco.config.Config; import org.alfresco.config.ConfigElement; import org.alfresco.config.ConfigLookupContext; import org.alfresco.config.ConfigService; import org.alfresco.config.element.GenericConfigElement; import org.alfresco.error.AlfrescoRuntimeException; import org.alfresco.filesys.alfresco.AlfrescoClientInfoFactory; import org.alfresco.filesys.alfresco.DesktopAction; import org.alfresco.filesys.alfresco.DesktopActionException; import org.alfresco.filesys.alfresco.DesktopActionTable; import org.alfresco.filesys.avm.AVMContext; import org.alfresco.filesys.avm.AVMDiskDriver; import org.alfresco.filesys.repo.ContentContext; import org.alfresco.repo.security.authentication.AuthenticationComponent; import org.alfresco.repo.security.authentication.NTLMMode; import org.alfresco.repo.tenant.TenantService; import org.alfresco.service.cmr.repository.NodeService; import org.alfresco.service.cmr.search.SearchService; import org.alfresco.service.cmr.security.AuthenticationService; import org.alfresco.service.cmr.security.PersonService; import org.alfresco.service.namespace.NamespaceService; import org.alfresco.service.transaction.TransactionService; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.beans.BeansException; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; import org.springframework.context.ApplicationEvent; import org.springframework.context.ApplicationListener; import org.springframework.context.event.ContextRefreshedEvent; import org.w3c.dom.Element; import org.w3c.dom.Node; import org.w3c.dom.NodeList; import net.sf.acegisecurity.AuthenticationManager; /** * Alfresco File Server Configuration Bean Class * * @author gkspencer */ public class ServerConfigurationBean extends ServerConfiguration implements ApplicationListener, ApplicationContextAware { // Debug logging private static final Log logger = LogFactory.getLog("org.alfresco.smb.protocol"); // Filesystem configuration constants private static final String ConfigArea = "file-servers"; private static final String ConfigCIFS = "CIFS Server"; private static final String ConfigFTP = "FTP Server"; private static final String ConfigNFS = "NFS Server"; private static final String ConfigFilesystems = "Filesystems"; private static final String ConfigSecurity = "Filesystem Security"; private static final String ConfigCoreServer = "Server Core"; // Server configuration bean name public static final String SERVER_CONFIGURATION = "fileServerConfiguration"; // SMB/CIFS session debug type strings // // Must match the bit mask order private static final String m_sessDbgStr[] = { "NETBIOS", "STATE", "RXDATA", "TXDATA", "DUMPDATA", "NEGOTIATE", "TREE", "SEARCH", "INFO", "FILE", "FILEIO", "TRANSACT", "ECHO", "ERROR", "IPC", "LOCK", "PKTTYPE", "DCERPC", "STATECACHE", "TIMING", "NOTIFY", "STREAMS", "SOCKET", "PKTPOOL", "PKTSTATS", "THREADPOOL", "BENCHMARK" }; // FTP server debug type strings private static final String m_ftpDebugStr[] = { "STATE", "SEARCH", "INFO", "FILE", "FILEIO", "ERROR", "PKTTYPE", "TIMING", "DATAPORT", "DIRECTORY" }; // Default FTP server port private static final int DefaultFTPServerPort = 21; // Default FTP anonymous account name private static final String DefaultFTPAnonymousAccount = "anonymous"; // NFS server debug type strings private static final String m_nfsDebugStr[] = { "RXDATA", "TXDATA", "DUMPDATA", "SEARCH", "INFO", "FILE", "FILEIO", "ERROR", "TIMING", "DIRECTORY", "SESSION" }; // Token name to substitute current server name into the CIFS server name private static final String TokenLocalName = "${localname}"; // Default thread pool size private static final int DefaultThreadPoolInit = 25; private static final int DefaultThreadPoolMax = 50; // Default memory pool settings private static final int[] DefaultMemoryPoolBufSizes = { 256, 4096, 16384, 66000 }; private static final int[] DefaultMemoryPoolInitAlloc = { 20, 20, 5, 5 }; private static final int[] DefaultMemoryPoolMaxAlloc = { 100, 50, 50, 50 }; // Memory pool packet size limits private static final int MemoryPoolMinimumPacketSize = 256; private static final int MemoryPoolMaximumPacketSize = 128 * (int) MemorySize.KILOBYTE; // Memory pool allocation limits private static final int MemoryPoolMinimumAllocation = 5; private static final int MemoryPoolMaximumAllocation = 500; // Authentication manager private AuthenticationManager m_authenticationManager; // Configuration service private ConfigService m_configService; // Disk interface to use for shared filesystems private DiskInterface m_repoDiskInterface; // AVM filesystem interface private DiskInterface m_avmDiskInterface; // Runtime platform type private Platform.Type m_platform = Platform.Type.Unchecked; // flag to indicate successful initialization private boolean m_initialised; // Main authentication service, public API private AuthenticationService m_authenticationService; // Authentication component, for internal functions private AuthenticationComponent m_authenticationComponent; // Various services private NodeService m_nodeService; private PersonService m_personService; private TransactionService m_transactionService; private TenantService m_tenantService; private SearchService m_searchService; private NamespaceService m_namespaceService; // Local server name and domain/workgroup name private String m_localName; private String m_localDomain; /** * Default constructor */ public ServerConfigurationBean() { super ( ""); } /** * Class constructor * * @param srvName String */ public ServerConfigurationBean( String srvName) { super( srvName); } /** * Set the authentication manager * * @param authenticationManager AuthenticationManager */ public void setAuthenticationManager(AuthenticationManager authenticationManager) { m_authenticationManager = authenticationManager; } /** * Set the authentication service * * @param authenticationService AuthenticationService */ public void setAuthenticationService(AuthenticationService authenticationService) { m_authenticationService = authenticationService; } /** * Set the configuration service * * @param configService ConfigService */ public void setConfigService(ConfigService configService) { m_configService = configService; } /** * Set the filesystem driver for the node service based filesystem * * @param diskInterface DiskInterface */ public void setDiskInterface(DiskInterface diskInterface) { m_repoDiskInterface = diskInterface; } /** * Set the filesystem driver for the AVM based filesystem * */ public void setAvmDiskInterface(DiskInterface diskInterface) { m_avmDiskInterface = diskInterface; } /** * Set the authentication component * * @param component AuthenticationComponent */ public void setAuthenticationComponent(AuthenticationComponent component) { m_authenticationComponent = component; } /** * Set the node service * * @param service NodeService */ public void setNodeService(NodeService service) { m_nodeService = service; } /** * Set the person service * * @param service PersonService */ public void setPersonService(PersonService service) { m_personService = service; } /** * Set the transaction service * * @param service TransactionService */ public void setTransactionService(TransactionService service) { m_transactionService = service; } /** * Set the tenant service * * @param tenantService TenantService */ public void setTenantService(TenantService tenantService) { m_tenantService = tenantService; } /** * Set the search service * * @param searchService SearchService */ public void setSearchService(SearchService searchService) { m_searchService = searchService; } /** * Set the namespace service * * @param namespaceService NamespaceService */ public void setNamespaceService(NamespaceService namespaceService) { m_namespaceService = namespaceService; } /** * Check if the configuration has been initialized * * @return Returns true if the configuration was fully initialised */ public boolean isInitialised() { return m_initialised; } /** * Check if the SMB server is enabled * * @return boolean */ public final boolean isSMBServerEnabled() { return hasConfigSection( CIFSConfigSection.SectionName); } /** * Check if the FTP server is enabled * * @return boolean */ public final boolean isFTPServerEnabled() { return hasConfigSection( FTPConfigSection.SectionName); } /** * Check if the NFS server is enabled * * @return boolean */ public final boolean isNFSServerEnabled() { return hasConfigSection( NFSConfigSection.SectionName); } /** * Return the repository disk interface to be used to create shares * * @return DiskInterface */ public final DiskInterface getRepoDiskInterface() { return m_repoDiskInterface; } /** * Return the disk interface to be used to create AVM filesystem shares * * @return DiskInterface */ public final DiskInterface getAvmDiskInterface() { return m_avmDiskInterface; } /** * Initialize the configuration using the configuration service */ public void init() { // Check that all required properties have been set if (m_authenticationManager == null) { throw new AlfrescoRuntimeException("Property 'authenticationManager' not set"); } else if (m_authenticationComponent == null) { throw new AlfrescoRuntimeException("Property 'authenticationComponent' not set"); } else if (m_authenticationService == null) { throw new AlfrescoRuntimeException("Property 'authenticationService' not set"); } else if (m_nodeService == null) { throw new AlfrescoRuntimeException("Property 'nodeService' not set"); } else if (m_personService == null) { throw new AlfrescoRuntimeException("Property 'personService' not set"); } else if (m_transactionService == null) { throw new AlfrescoRuntimeException("Property 'transactionService' not set"); } else if (m_repoDiskInterface == null) { throw new AlfrescoRuntimeException("Property 'diskInterface' not set"); } else if (m_configService == null) { throw new AlfrescoRuntimeException("Property 'configService' not set"); } // Create the configuration context ConfigLookupContext configCtx = new ConfigLookupContext(ConfigArea); // Set the platform type determinePlatformType(); // Create the debug output configuration using a logger for all file server debug output DebugConfigSection debugConfig = new DebugConfigSection( this); try { debugConfig.setDebug("org.alfresco.filesys.debug.FileServerDebugInterface", null); } catch ( InvalidConfigurationException ex) { } // Create the global configuration and Alfresco configuration sections new GlobalConfigSection( this); new AlfrescoConfigSection( this); // Install the Alfresco client information factory ClientInfo.setFactory( new AlfrescoClientInfoFactory()); // Initialize the filesystems boolean filesysInitOK = false; Config config = null; try { // Process the core server configuration config = m_configService.getConfig(ConfigCoreServer, configCtx); processCoreServerConfig( config); // Process the security configuration config = m_configService.getConfig(ConfigSecurity, configCtx); processSecurityConfig( config); // Process the filesystems configuration config = m_configService.getConfig(ConfigFilesystems, configCtx); processFilesystemsConfig( config); // Indicate that the filesystems were initialized filesysInitOK = true; } catch (Exception ex) { // Configuration error logger.error("File server configuration error, " + ex.getMessage(), ex); } // Initialize the CIFS and FTP servers, if the filesystem(s) initialized successfully if ( filesysInitOK == true) { // Initialize the CIFS server try { // Process the CIFS server configuration config = m_configService.getConfig(ConfigCIFS, configCtx); processCIFSServerConfig(config); // Log the successful startup logger.info("CIFS server " + (isSMBServerEnabled() ? "" : "NOT ") + "started"); } catch (UnsatisfiedLinkError ex) { // Error accessing the Win32NetBIOS DLL code logger.error("Error accessing Win32 NetBIOS, check DLL is on the path"); // Disable the CIFS server removeConfigSection( CIFSConfigSection.SectionName); } catch (Throwable ex) { // Configuration error logger.error("CIFS server configuration error, " + ex.getMessage(), ex); // Disable the CIFS server removeConfigSection( CIFSConfigSection.SectionName); } // Initialize the FTP server try { // Process the FTP server configuration config = m_configService.getConfig(ConfigFTP, configCtx); processFTPServerConfig(config); // Log the successful startup logger.info("FTP server " + (isFTPServerEnabled() ? "" : "NOT ") + "started"); } catch (Exception ex) { // Configuration error logger.error("FTP server configuration error, " + ex.getMessage(), ex); } // Initialize the NFS server try { // Process the NFS server configuration config = m_configService.getConfig(ConfigNFS, configCtx); processNFSServerConfig(config); // Log the successful startup logger.info("NFS server " + (isNFSServerEnabled() ? "" : "NOT ") + "started"); } catch (Exception ex) { // Configuration error logger.error("NFS server configuration error, " + ex.getMessage(), ex); } } else { // Log the error logger.error("CIFS and FTP servers not started due to filesystem initialization error"); } } /** * Close the configuration bean */ public final void closeConfiguration() { super.closeConfiguration(); } /** * Determine the platform type */ private final void determinePlatformType() { if ( m_platform == Platform.Type.Unchecked) m_platform = Platform.isPlatformType(); } /** * Process the CIFS server configuration * * @param config Config */ private final void processCIFSServerConfig(Config config) { // If the configuration section is not valid then CIFS is disabled if ( config == null) { removeConfigSection( CIFSConfigSection.SectionName); return; } // Check if the server has been disabled ConfigElement elem = config.getConfigElement( "serverEnable"); if ( elem != null) { // Check for the enabled attribute String srvEnable = elem.getAttribute( "enabled"); if ( srvEnable != null && srvEnable.equalsIgnoreCase( "false")) { removeConfigSection( CIFSConfigSection.SectionName); return; } } // Create the CIFS server configuration section CIFSConfigSection cifsConfig = new CIFSConfigSection( this); try { // Get the network broadcast address // // Note: We need to set this first as the call to getLocalDomainName() may use a NetBIOS // name lookup, so the broadcast mask must be set before then. elem = config.getConfigElement("broadcast"); if (elem != null) { // Check if the broadcast mask is a valid numeric IP address if (IPAddress.isNumericAddress(elem.getValue()) == false) throw new AlfrescoRuntimeException("Invalid broadcast mask, must be n.n.n.n format"); // Set the network broadcast mask cifsConfig.setBroadcastMask(elem.getValue()); } // Get the host configuration elem = config.getConfigElement("host"); if (elem == null) throw new AlfrescoRuntimeException("CIFS server host settings not specified"); String hostName = elem.getAttribute("name"); if (hostName == null || hostName.length() == 0) throw new AlfrescoRuntimeException("Host name not specified or invalid"); // Check if the host name contains the local name token int pos = hostName.indexOf(TokenLocalName); if (pos != -1) { // Get the local server name String srvName = getLocalServerName(true); // Rebuild the host name substituting the token with the local server name StringBuilder hostStr = new StringBuilder(); hostStr.append(hostName.substring(0, pos)); hostStr.append(srvName); pos += TokenLocalName.length(); if (pos < hostName.length()) hostStr.append(hostName.substring(pos)); hostName = hostStr.toString(); // Make sure the CIFS server name does not match the local server name if (hostName.equals(srvName) && getPlatformType() == Platform.Type.WINDOWS) throw new AlfrescoRuntimeException("CIFS server name must be unique"); } // Check if the host name is longer than 15 characters. NetBIOS only allows a maximum of 16 characters in the // server name with the last character reserved for the service type. if ( hostName.length() > 15) { // Truncate the CIFS server name hostName = hostName.substring(0, 15); // Output a warning logger.warn("CIFS server name is longer than 15 characters, truncated to " + hostName); } // Set the CIFS server name cifsConfig.setServerName(hostName.toUpperCase()); setServerName(hostName.toUpperCase()); // Get the domain/workgroup name String domain = elem.getAttribute("domain"); if (domain != null && domain.length() > 0) { // Set the domain/workgroup name cifsConfig.setDomainName(domain.toUpperCase()); } else { // Get the local domain/workgroup name String localDomain = getLocalDomainName(); if ( localDomain == null && getPlatformType() != Platform.Type.WINDOWS) { // Use a default domain/workgroup name localDomain = "WORKGROUP"; // Output a warning logger.error("Failed to get local domain/workgroup name, using default of " + localDomain); logger.error("(This may be due to firewall settings or incorrect setting)"); } // Set the local domain/workgroup that the CIFS server belongs to cifsConfig.setDomainName( localDomain); } // Check for a server comment elem = config.getConfigElement("comment"); if (elem != null) cifsConfig.setComment(elem.getValue()); // Check for a bind address elem = config.getConfigElement("bindto"); if (elem != null) { // Check if the network adapter name has been specified if ( elem.hasAttribute("adapter")) { // Get the IP address for the adapter InetAddress bindAddr = parseAdapterName( elem.getAttribute("adapter")); // Set the bind address for the server cifsConfig.setSMBBindAddress(bindAddr); } else { // Validate the bind address String bindText = elem.getValue(); try { // Check the bind address InetAddress bindAddr = InetAddress.getByName(bindText); // Set the bind address for the server cifsConfig.setSMBBindAddress(bindAddr); } catch (UnknownHostException ex) { throw new AlfrescoRuntimeException("Invalid CIFS server bind address"); } } } // Check if an authenticator has been specified ConfigElement authElem = config.getConfigElement("authenticator"); if (authElem != null) { // Get the authenticator type String authType = authElem.getAttribute("type"); if (authType == null) authType = "alfresco"; // Get the authentication component type NTLMMode ntlmMode = m_authenticationComponent.getNTLMMode(); // Set the authenticator class to use String authClass = "org.alfresco.filesys.auth.cifs.AlfrescoCifsAuthenticator"; if (authType.equalsIgnoreCase("passthru")) { // Check if the appropriate authentication component type is configured if ( ntlmMode == NTLMMode.MD4_PROVIDER) throw new AlfrescoRuntimeException("Wrong authentication setup for passthru authenticator (cannot be used with Alfresco users)"); // Use the passthru authenticator class authClass = "org.alfresco.filesys.auth.cifs.PassthruCifsAuthenticator"; } else if (authType.equalsIgnoreCase("alfresco")) { // Standard authenticator requires MD4 or passthru based authentication if ( ntlmMode == NTLMMode.NONE) throw new AlfrescoRuntimeException("Wrong authentication setup for alfresco authenticator"); } else if( authType.equalsIgnoreCase("enterprise")) { // Load the Enterprise authenticator dynamically authClass = "org.alfresco.filesys.auth.cifs.EnterpriseCifsAuthenticator"; } else throw new AlfrescoRuntimeException("Invalid authenticator type, " + authType); // Get the allow guest and map unknown user to guest settings boolean allowGuest = authElem.getChild("allowGuest") != null ? true : false; // Initialize and set the authenticator class cifsConfig.setAuthenticator(authClass, authElem, CifsAuthenticator.USER_MODE, allowGuest); } else throw new AlfrescoRuntimeException("CIFS authenticator not specified"); // Check if the host announcer should be enabled elem = config.getConfigElement("hostAnnounce"); if (elem != null) { // Check for an announcement interval String interval = elem.getAttribute("interval"); if (interval != null && interval.length() > 0) { try { cifsConfig.setHostAnnounceInterval(Integer.parseInt(interval)); } catch (NumberFormatException ex) { throw new AlfrescoRuntimeException("Invalid host announcement interval"); } } // Check if the domain name has been set, this is required if the // host announcer is enabled if (cifsConfig.getDomainName() == null) throw new AlfrescoRuntimeException("Domain name must be specified if host announcement is enabled"); // Enable host announcement cifsConfig.setHostAnnouncer(true); } // Check if NetBIOS SMB is enabled elem = config.getConfigElement("netBIOSSMB"); if (elem != null) { // Check if NetBIOS over TCP/IP is enabled for the current platform String platformsStr = elem.getAttribute("platforms"); boolean platformOK = false; if (platformsStr != null) { // Parse the list of platforms that NetBIOS over TCP/IP is to be enabled for and // check if the current platform is included EnumSet enabledPlatforms = parsePlatformString(platformsStr); if (enabledPlatforms.contains(getPlatformType())) platformOK = true; } else { // No restriction on platforms platformOK = true; } // Enable the NetBIOS SMB support, if enabled for this platform cifsConfig.setNetBIOSSMB(platformOK); // Parse/check NetBIOS settings, if enabled if ( cifsConfig.hasNetBIOSSMB()) { // Check if the broadcast mask has been specified if (cifsConfig.getBroadcastMask() == null) throw new AlfrescoRuntimeException("Network broadcast mask not specified"); // Check for a bind address String bindto = elem.getAttribute("bindto"); if (bindto != null && bindto.length() > 0) { // Validate the bind address try { // Check the bind address InetAddress bindAddr = InetAddress.getByName(bindto); // Set the bind address for the NetBIOS name server cifsConfig.setNetBIOSBindAddress(bindAddr); } catch (UnknownHostException ex) { throw new AlfrescoRuntimeException("Invalid NetBIOS bind address"); } } else if (cifsConfig.hasSMBBindAddress()) { // Use the SMB bind address for the NetBIOS name server cifsConfig.setNetBIOSBindAddress(cifsConfig.getSMBBindAddress()); } else { // Get a list of all the local addresses InetAddress[] addrs = null; try { // Get the local server IP address list addrs = InetAddress.getAllByName(InetAddress.getLocalHost().getHostName()); } catch (UnknownHostException ex) { logger.error("Failed to get local address list", ex); } // Check the address list for one or more valid local addresses filtering out the loopback address int addrCnt = 0; if ( addrs != null) { for (int i = 0; i < addrs.length; i++) { // Check for a valid address, filter out '127.0.0.1' and '0.0.0.0' addresses if (addrs[i].getHostAddress().equals("127.0.0.1") == false && addrs[i].getHostAddress().equals("0.0.0.0") == false) addrCnt++; } } // Check if any addresses were found if ( addrCnt == 0) { // Enumerate the network adapter list Enumeration niEnum = null; try { niEnum = NetworkInterface.getNetworkInterfaces(); } catch (SocketException ex) { } if ( niEnum != null) { while ( niEnum.hasMoreElements()) { // Get the current network interface NetworkInterface ni = niEnum.nextElement(); // Enumerate the addresses for the network adapter Enumeration niAddrs = ni.getInetAddresses(); if ( niAddrs != null) { // Check for any valid addresses while ( niAddrs.hasMoreElements()) { InetAddress curAddr = niAddrs.nextElement(); if ( curAddr.getHostAddress().equals("127.0.0.1") == false && curAddr.getHostAddress().equals("0.0.0.0") == false) addrCnt++; } } } // DEBUG if ( addrCnt > 0 && logger.isDebugEnabled()) logger.debug("Found valid IP address from interface list"); } // Check if we found any valid network addresses if ( addrCnt == 0) { // Log the available IP addresses if ( logger.isDebugEnabled()) { logger.debug("Local address list dump :-"); if ( addrs != null) { for ( int i = 0; i < addrs.length; i++) logger.debug( " Address: " + addrs[i]); } else logger.debug(" No addresses"); } // Throw an exception to stop the CIFS/NetBIOS name server from starting throw new AlfrescoRuntimeException( "Failed to get IP address(es) for the local server, check hosts file and/or DNS setup"); } } } // Check if the session port has been specified String portNum = elem.getAttribute("sessionPort"); if ( portNum != null && portNum.length() > 0) { try { cifsConfig.setSessionPort(Integer.parseInt(portNum)); if ( cifsConfig.getSessionPort() <= 0 || cifsConfig.getSessionPort() >= 65535) throw new AlfrescoRuntimeException("NetBIOS session port out of valid range"); } catch (NumberFormatException ex) { throw new AlfrescoRuntimeException("Invalid NetBIOS session port"); } } // Check if the name port has been specified portNum = elem.getAttribute("namePort"); if ( portNum != null && portNum.length() > 0) { try { cifsConfig.setNameServerPort(Integer.parseInt(portNum)); if ( cifsConfig.getNameServerPort() <= 0 || cifsConfig.getNameServerPort() >= 65535) throw new AlfrescoRuntimeException("NetBIOS name port out of valid range"); } catch (NumberFormatException ex) { throw new AlfrescoRuntimeException("Invalid NetBIOS name port"); } } // Check if the datagram port has been specified portNum = elem.getAttribute("datagramPort"); if ( portNum != null && portNum.length() > 0) { try { cifsConfig.setDatagramPort(Integer.parseInt(portNum)); if ( cifsConfig.getDatagramPort() <= 0 || cifsConfig.getDatagramPort() >= 65535) throw new AlfrescoRuntimeException("NetBIOS datagram port out of valid range"); } catch (NumberFormatException ex) { throw new AlfrescoRuntimeException("Invalid NetBIOS datagram port"); } } // Check for a bind address String attr = elem.getAttribute("bindto"); if ( attr != null && attr.length() > 0) { // Validate the bind address try { // Check the bind address InetAddress bindAddr = InetAddress.getByName(attr); // Set the bind address for the NetBIOS name server cifsConfig.setNetBIOSBindAddress(bindAddr); } catch (UnknownHostException ex) { throw new InvalidConfigurationException(ex.toString()); } } // Check for a bind address using the adapter name else if ( elem.hasAttribute("adapter")) { // Get the bind address via the network adapter name InetAddress bindAddr = parseAdapterName( elem.getAttribute("adapter")); cifsConfig.setNetBIOSBindAddress( bindAddr); } else if ( cifsConfig.hasSMBBindAddress()) { // Use the SMB bind address for the NetBIOS name server cifsConfig.setNetBIOSBindAddress(cifsConfig.getSMBBindAddress()); } } } else { // Disable NetBIOS SMB support cifsConfig.setNetBIOSSMB(false); } // Check if TCP/IP SMB is enabled elem = config.getConfigElement("tcpipSMB"); if (elem != null) { // Check if native SMB is enabled for the current platform String platformsStr = elem.getAttribute("platforms"); boolean platformOK = false; if (platformsStr != null) { // Parse the list of platforms that native SMB is to be enabled for and // check if the current platform is included EnumSet enabledPlatforms = parsePlatformString(platformsStr); if (enabledPlatforms.contains(getPlatformType())) platformOK = true; } else { // No restriction on platforms platformOK = true; } // Enable the TCP/IP SMB support, if enabled for this platform cifsConfig.setTcpipSMB(platformOK); // Check if the port has been specified String portNum = elem.getAttribute("port"); if ( portNum != null && portNum.length() > 0) { try { cifsConfig.setTcpipSMBPort(Integer.parseInt(portNum)); if ( cifsConfig.getTcpipSMBPort() <= 0 || cifsConfig.getTcpipSMBPort() >= 65535) throw new AlfrescoRuntimeException("TCP/IP SMB port out of valid range"); } catch (NumberFormatException ex) { throw new AlfrescoRuntimeException("Invalid TCP/IP SMB port"); } } } else { // Disable TCP/IP SMB support cifsConfig.setTcpipSMB(false); } // Check if Win32 NetBIOS is enabled elem = config.getConfigElement("Win32NetBIOS"); if (elem != null) { // Check if the Win32 NetBIOS server name has been specified String win32Name = elem.getAttribute("name"); if (win32Name != null && win32Name.length() > 0) { // Validate the name if (win32Name.length() > 16) throw new AlfrescoRuntimeException("Invalid Win32 NetBIOS name, " + win32Name); // Set the Win32 NetBIOS file server name cifsConfig.setWin32NetBIOSName(win32Name); } // Check if the Win32 NetBIOS LANA has been specified String lanaStr = elem.getAttribute("lana"); if (lanaStr != null && lanaStr.length() > 0) { // Check if the LANA has been specified as an IP address or adapter name 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 { 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) throw new AlfrescoRuntimeException("Invalid Win32 NetBIOS LANA number, " + lana); // Set the LANA number cifsConfig.setWin32LANA(lana); } // Check if the native NetBIOS interface has been specified, either 'winsock' or 'netbios' String nativeAPI = elem.getAttribute("api"); if ( nativeAPI != null && nativeAPI.length() > 0) { // Validate the API type boolean useWinsock = true; if ( nativeAPI.equalsIgnoreCase("netbios")) useWinsock = false; else if ( nativeAPI.equalsIgnoreCase("winsock") == false) throw new AlfrescoRuntimeException("Invalid NetBIOS API type, spefify 'winsock' or 'netbios'"); // Set the NetBIOS API to use cifsConfig.setWin32WinsockNetBIOS( useWinsock); } // Force the older NetBIOS API code to be used on 64Bit Windows if ( cifsConfig.useWinsockNetBIOS() == true && X64.isWindows64()) { // Log a warning logger.warn("Using older Netbios() API code"); // Use the older NetBIOS API code cifsConfig.setWin32WinsockNetBIOS( false); } // Check if the current operating system is supported by the Win32 // NetBIOS handler String osName = System.getProperty("os.name"); if (osName.startsWith("Windows") && (osName.endsWith("95") == false && osName.endsWith("98") == false && osName.endsWith("ME") == false)) { // Call the Win32NetBIOS native code to make sure it is initialized if ( Win32NetBIOS.LanaEnumerate() != null) { // Enable Win32 NetBIOS cifsConfig.setWin32NetBIOS(true); } else { logger.warn("No NetBIOS LANAs available"); } } else { // Win32 NetBIOS not supported on the current operating system cifsConfig.setWin32NetBIOS(false); } } else { // Disable Win32 NetBIOS cifsConfig.setWin32NetBIOS(false); } // Check if the host announcer should be enabled elem = config.getConfigElement("Win32Announce"); if (elem != null) { // Check for an announcement interval String interval = elem.getAttribute("interval"); if (interval != null && interval.length() > 0) { try { cifsConfig.setWin32HostAnnounceInterval(Integer.parseInt(interval)); } catch (NumberFormatException ex) { throw new AlfrescoRuntimeException("Invalid host announcement interval"); } } // Check if the domain name has been set, this is required if the // host announcer is enabled if (cifsConfig.getDomainName() == null) throw new AlfrescoRuntimeException("Domain name must be specified if host announcement is enabled"); // Enable Win32 NetBIOS host announcement cifsConfig.setWin32HostAnnouncer(true); } // Check if NetBIOS and/or TCP/IP SMB have been enabled if (cifsConfig.hasNetBIOSSMB() == false && cifsConfig.hasTcpipSMB() == false && cifsConfig.hasWin32NetBIOS() == false) throw new AlfrescoRuntimeException("NetBIOS SMB, TCP/IP SMB or Win32 NetBIOS must be enabled"); // Check if WINS servers are configured elem = config.getConfigElement("WINS"); if (elem != null) { // Get the primary WINS server ConfigElement priWinsElem = elem.getChild("primary"); if (priWinsElem == null || priWinsElem.getValue().length() == 0) throw new AlfrescoRuntimeException("No primary WINS server configured"); // Validate the WINS server address InetAddress primaryWINS = null; try { primaryWINS = InetAddress.getByName(priWinsElem.getValue()); } catch (UnknownHostException ex) { throw new AlfrescoRuntimeException("Invalid primary WINS server address, " + priWinsElem.getValue()); } // Check if a secondary WINS server has been specified ConfigElement secWinsElem = elem.getChild("secondary"); InetAddress secondaryWINS = null; if (secWinsElem != null) { // Validate the secondary WINS server address try { secondaryWINS = InetAddress.getByName(secWinsElem.getValue()); } catch (UnknownHostException ex) { throw new AlfrescoRuntimeException("Invalid secondary WINS server address, " + secWinsElem.getValue()); } } // Set the WINS server address(es) cifsConfig.setPrimaryWINSServer(primaryWINS); if (secondaryWINS != null) cifsConfig.setSecondaryWINSServer(secondaryWINS); // Pass the setting to the NetBIOS session class NetBIOSSession.setDefaultWINSServer(primaryWINS); } // Check if WINS is configured, if we are running on Windows and socket based NetBIOS is enabled else if (cifsConfig.hasNetBIOSSMB() && getPlatformType() == Platform.Type.WINDOWS) { // Get the WINS server list String winsServers = Win32NetBIOS.getWINSServerList(); if (winsServers != null) { // Use the first WINS server address for now StringTokenizer tokens = new StringTokenizer(winsServers, ","); String addr = tokens.nextToken(); try { // Convert to a network address and check if the WINS server is accessible InetAddress winsAddr = InetAddress.getByName(addr); Socket winsSocket = new Socket(); InetSocketAddress sockAddr = new InetSocketAddress( winsAddr, RFCNetBIOSProtocol.NAME_PORT); winsSocket.connect(sockAddr, 3000); winsSocket.close(); // Set the primary WINS server address cifsConfig.setPrimaryWINSServer(winsAddr); // Debug if (logger.isDebugEnabled()) logger.debug("Configuring to use WINS server " + addr); } catch (UnknownHostException ex) { throw new AlfrescoRuntimeException("Invalid auto WINS server address, " + addr); } catch (IOException ex) { if ( logger.isDebugEnabled()) logger.debug("Failed to connect to auto WINS server " + addr); } } } // Check if session debug is enabled elem = config.getConfigElement("sessionDebug"); if (elem != null) { // Check for session debug flags String flags = elem.getAttribute("flags"); int sessDbg = 0; if (flags != null) { // Parse the flags flags = flags.toUpperCase(); StringTokenizer token = new StringTokenizer(flags, ","); while (token.hasMoreTokens()) { // Get the current debug flag token String dbg = token.nextToken().trim(); // Find the debug flag name int idx = 0; while (idx < m_sessDbgStr.length && m_sessDbgStr[idx].equalsIgnoreCase(dbg) == false) idx++; if (idx > m_sessDbgStr.length) throw new AlfrescoRuntimeException("Invalid session debug flag, " + dbg); // Set the debug flag sessDbg += 1 << idx; } } // Set the session debug flags cifsConfig.setSessionDebugFlags(sessDbg); } // Check if NIO based socket code should be disabled if ( config.getConfigElement( "disableNIO") != null) { // Disable NIO based code cifsConfig.setDisableNIOCode( true); // DEBUG if ( logger.isDebugEnabled()) logger.debug("NIO based code disabled for CIFS server"); } } catch ( InvalidConfigurationException ex) { throw new AlfrescoRuntimeException( ex.getMessage()); } } /** * Process the FTP server configuration * * @param config Config */ private final void processFTPServerConfig(Config config) { // If the configuration section is not valid then FTP is disabled if ( config == null) { removeConfigSection( FTPConfigSection.SectionName); return; } // Check if the server has been disabled ConfigElement elem = config.getConfigElement( "serverEnable"); if ( elem != null) { // Check for the enabled attribute String srvEnable = elem.getAttribute( "enabled"); if ( srvEnable != null && srvEnable.equalsIgnoreCase( "false")) { removeConfigSection( FTPConfigSection.SectionName); return; } } // Create the FTP configuration section FTPConfigSection ftpConfig = new FTPConfigSection( this); try { // Check for a bind address elem = config.getConfigElement("bindto"); if ( elem != null) { // Validate the bind address String bindText = elem.getValue(); try { // Check the bind address InetAddress bindAddr = InetAddress.getByName(bindText); // Set the bind address for the FTP server ftpConfig.setFTPBindAddress(bindAddr); } catch (UnknownHostException ex) { throw new AlfrescoRuntimeException("Invalid FTP bindto address, " + elem.getValue()); } } // Check for an FTP server port elem = config.getConfigElement("port"); if ( elem != null) { try { ftpConfig.setFTPPort(Integer.parseInt(elem.getValue())); if ( ftpConfig.getFTPPort() <= 0 || ftpConfig.getFTPPort() >= 65535) throw new AlfrescoRuntimeException("FTP server port out of valid range"); } catch (NumberFormatException ex) { throw new AlfrescoRuntimeException("Invalid FTP server port"); } } else { // Use the default FTP port ftpConfig.setFTPPort(DefaultFTPServerPort); } // Check if anonymous login is allowed elem = config.getConfigElement("allowAnonymous"); if ( elem != null) { // Enable anonymous login to the FTP server ftpConfig.setAllowAnonymousFTP(true); // Check if an anonymous account has been specified String anonAcc = elem.getAttribute("user"); if ( anonAcc != null && anonAcc.length() > 0) { // Set the anonymous account name ftpConfig.setAnonymousFTPAccount(anonAcc); // Check if the anonymous account name is valid if ( ftpConfig.getAnonymousFTPAccount() == null || ftpConfig.getAnonymousFTPAccount().length() == 0) throw new AlfrescoRuntimeException("Anonymous FTP account invalid"); } else { // Use the default anonymous account name ftpConfig.setAnonymousFTPAccount(DefaultFTPAnonymousAccount); } } else { // Disable anonymous logins ftpConfig.setAllowAnonymousFTP(false); } // Check if a root path has been specified elem = config.getConfigElement("rootDirectory"); if ( elem != null) { // Get the root path String rootPath = elem.getValue(); // Validate the root path try { // Parse the path new FTPPath(rootPath); // Set the root path ftpConfig.setFTPRootPath(rootPath); } catch (InvalidPathException ex) { throw new AlfrescoRuntimeException("Invalid FTP root directory, " + rootPath); } } // Check if FTP debug is enabled elem = config.getConfigElement("debug"); if (elem != null) { // Check for FTP debug flags String flags = elem.getAttribute("flags"); int ftpDbg = 0; if ( flags != null) { // Parse the flags flags = flags.toUpperCase(); StringTokenizer token = new StringTokenizer(flags,","); while ( token.hasMoreTokens()) { // Get the current debug flag token String dbg = token.nextToken().trim(); // Find the debug flag name int idx = 0; while ( idx < m_ftpDebugStr.length && m_ftpDebugStr[idx].equalsIgnoreCase(dbg) == false) idx++; if ( idx >= m_ftpDebugStr.length) throw new AlfrescoRuntimeException("Invalid FTP debug flag, " + dbg); // Set the debug flag ftpDbg += 1 << idx; } } // Set the FTP debug flags ftpConfig.setFTPDebug(ftpDbg); } // Check if a character set has been specified elem = config.getConfigElement( "charSet"); if ( elem != null) { try { // Validate the character set name Charset.forName( elem.getValue()); // Set the FTP character set ftpConfig.setFTPCharacterSet( elem.getValue()); } catch ( IllegalCharsetNameException ex) { throw new AlfrescoRuntimeException("Illegal character set name, " + elem.getValue()); } catch ( UnsupportedCharsetException ex) { throw new AlfrescoRuntimeException("Unsupported character set name, " + elem.getValue()); } } // Check if an authenticator has been specified ConfigElement authElem = config.getConfigElement("authenticator"); if (authElem != null) { // Get the authenticator type String authType = authElem.getAttribute("type"); if (authType == null) authType = "alfresco"; // Get the authentication component type NTLMMode ntlmMode = m_authenticationComponent.getNTLMMode(); // Set the authenticator class to use String authClass = "org.alfresco.filesys.auth.ftp.AlfrescoFtpAuthenticator"; if (authType.equalsIgnoreCase("passthru")) { // Check if the appropriate authentication component type is configured if ( ntlmMode == NTLMMode.MD4_PROVIDER) throw new AlfrescoRuntimeException("Wrong authentication setup for passthru authenticator (cannot be used with Alfresco users)"); // Use the passthru authenticator class authClass = "org.alfresco.filesys.auth.ftp.PassthruFtpAuthenticator"; } else if (authType.equalsIgnoreCase("alfresco")) { // Standard authenticator requires MD4 or passthru based authentication if ( ntlmMode == NTLMMode.NONE) throw new AlfrescoRuntimeException("Wrong authentication setup for alfresco authenticator"); } else throw new AlfrescoRuntimeException("Invalid authenticator type, " + authType); // Initialize and set the authenticator class ftpConfig.setAuthenticator(authClass, authElem); } else throw new AlfrescoRuntimeException("FTP authenticator not specified"); } catch (InvalidConfigurationException ex) { throw new AlfrescoRuntimeException( ex.getMessage()); } } /** * Process the NFS server configuration * * @param config Config */ private final void processNFSServerConfig(Config config) { // If the configuration section is not valid then NFS is disabled if ( config == null) { removeConfigSection( NFSConfigSection.SectionName); return; } // Check if the server has been disabled ConfigElement elem = config.getConfigElement( "serverEnable"); if ( elem != null) { // Check for the enabled attribute String srvEnable = elem.getAttribute( "enabled"); if ( srvEnable != null && srvEnable.equalsIgnoreCase( "false")) { removeConfigSection( NFSConfigSection.SectionName); return; } } // Create the NFS configuration section NFSConfigSection nfsConfig = new NFSConfigSection( this); try { // Check if the port mapper is enabled if ( config.getConfigElement("enablePortMapper") != null) nfsConfig.setNFSPortMapper( true); // Check for the thread pool size elem = config.getConfigElement("ThreadPool"); if ( elem != null) { try { // Convert the pool size value int poolSize = Integer.parseInt(elem.getValue()); // Range check the pool size value if ( poolSize < 4) throw new AlfrescoRuntimeException("NFS thread pool size is below minimum of 4"); // Set the thread pool size nfsConfig.setNFSThreadPoolSize(poolSize); } catch (NumberFormatException ex) { throw new AlfrescoRuntimeException("Invalid NFS thread pool size setting, " + elem.getValue()); } } // NFS packet pool size elem = config.getConfigElement("PacketPool"); if ( elem != null) { try { // Convert the packet pool size value int pktPoolSize = Integer.parseInt(elem.getValue()); // Range check the pool size value if ( pktPoolSize < 10) throw new AlfrescoRuntimeException("NFS packet pool size is below minimum of 10"); if ( pktPoolSize < nfsConfig.getNFSThreadPoolSize() + 1) throw new AlfrescoRuntimeException("NFS packet pool must be at least thread pool size plus one"); // Set the packet pool size nfsConfig.setNFSPacketPoolSize( pktPoolSize); } catch (NumberFormatException ex) { throw new AlfrescoRuntimeException("Invalid NFS packet pool size setting, " + elem.getValue()); } } // Check for a port mapper server port elem = config.getConfigElement("PortMapperPort"); if ( elem != null) { try { nfsConfig.setPortMapperPort( Integer.parseInt(elem.getValue())); if ( nfsConfig.getPortMapperPort() <= 0 || nfsConfig.getPortMapperPort() >= 65535) throw new AlfrescoRuntimeException("Port mapper server port out of valid range"); } catch (NumberFormatException ex) { throw new AlfrescoRuntimeException("Invalid port mapper server port"); } } // Check for a mount server port elem = config.getConfigElement("MountServerPort"); if ( elem != null) { try { nfsConfig.setMountServerPort( Integer.parseInt(elem.getValue())); if ( nfsConfig.getMountServerPort() <= 0 || nfsConfig.getMountServerPort() >= 65535) throw new AlfrescoRuntimeException("Mount server port out of valid range"); } catch (NumberFormatException ex) { throw new AlfrescoRuntimeException("Invalid mount server port"); } } // Check for an NFS server port elem = config.getConfigElement("NFSServerPort"); if ( elem != null) { try { nfsConfig.setNFSServerPort( Integer.parseInt(elem.getValue())); if ( nfsConfig.getNFSServerPort() <= 0 || nfsConfig.getNFSServerPort() >= 65535) throw new AlfrescoRuntimeException("NFS server port out of valid range"); } catch (NumberFormatException ex) { throw new AlfrescoRuntimeException("Invalid NFS server port"); } } // Check if NFS debug is enabled elem = config.getConfigElement("debug"); if (elem != null) { // Check for NFS debug flags String flags = elem.getAttribute("flags"); int nfsDbg = 0; if ( flags != null) { // Parse the flags flags = flags.toUpperCase(); StringTokenizer token = new StringTokenizer(flags,","); while ( token.hasMoreTokens()) { // Get the current debug flag token String dbg = token.nextToken().trim(); // Find the debug flag name int idx = 0; while ( idx < m_nfsDebugStr.length && m_nfsDebugStr[idx].equalsIgnoreCase(dbg) == false) idx++; if ( idx >= m_nfsDebugStr.length) throw new AlfrescoRuntimeException("Invalid NFS debug flag, " + dbg); // Set the debug flag nfsDbg += 1 << idx; } } // Set the NFS debug flags nfsConfig.setNFSDebug( nfsDbg); } // Check if mount server debug output is enabled elem = config.getConfigElement("mountServerDebug"); if ( elem != null) nfsConfig.setMountServerDebug( true); // Check if portmapper debug output is enabled elem = config.getConfigElement("portMapperDebug"); if ( elem != null) nfsConfig.setPortMapperDebug(true); // Create the RPC authenticator elem = config.getConfigElement("rpcAuthenticator"); if ( elem != null) { try { // Create the RPC authenticator nfsConfig.setRpcAuthenticator( "org.alfresco.filesys.auth.nfs.AlfrescoRpcAuthenticator", elem); } catch ( InvalidConfigurationException ex) { throw new AlfrescoRuntimeException( ex.getMessage()); } } else throw new AlfrescoRuntimeException("RPC authenticator configuration missing, require user mappings"); } catch ( InvalidConfigurationException ex) { throw new AlfrescoRuntimeException( ex.getMessage()); } } /** * Process the filesystems configuration * * @param config Config */ private final void processFilesystemsConfig(Config config) { // Get the top level filesystems configuration element ConfigElement filesystems = config.getConfigElement("filesystems"); // Get the filesystem configuration elements List filesysElems = null; if ( filesystems != null) { // Get the list of filesystems filesysElems = filesystems.getChildren(); } else { // Check for the old style configuration ConfigElement filesysElem = config.getConfigElement( "filesystem"); if (filesysElem != null) { // create a list with the single filesys element in filesysElems = new ArrayList(1); filesysElems.add(filesysElem); } // Warn that the configuration is using the old format logger.warn("Old style file-servers.xml configuration being used"); } // Create the filesystems configuration section FilesystemsConfigSection fsysConfig = new FilesystemsConfigSection( this); // Access the security configuration section SecurityConfigSection secConfig = (SecurityConfigSection) getConfigSection( SecurityConfigSection.SectionName); // Process the filesystems list if (filesysElems != null) { // Add the filesystems for (int i = 0; i < filesysElems.size(); i++) { // Get the current filesystem configuration ConfigElement elem = filesysElems.get(i); String filesysType = elem.getName(); String filesysName = elem.getAttribute("name"); try { // Check the filesystem type and use the appropriate driver DiskSharedDevice filesys = null; if ( filesysType.equalsIgnoreCase("avmfilesystem")) { // Create a new filesystem driver instance and create a context for // the new filesystem DiskInterface filesysDriver = getAvmDiskInterface(); AVMContext filesysContext = (AVMContext) filesysDriver.createContext( filesysName, elem); // Create the shared filesystem filesys = new DiskSharedDevice(filesysName, filesysDriver, filesysContext); // Start the filesystem filesysContext.startFilesystem(filesys); } else { // Create a new filesystem driver instance and create a context for // the new filesystem DiskInterface filesysDriver = getRepoDiskInterface(); ContentContext filesysContext = (ContentContext) filesysDriver.createContext( filesysName, elem); // Check if an access control list has been specified AccessControlList acls = null; ConfigElement aclElem = elem.getChild("accessControl"); if (aclElem != null) { // Parse the access control list acls = processAccessControlList(secConfig, aclElem); } else if (secConfig.hasGlobalAccessControls()) { // Use the global access control list for this disk share acls = secConfig.getGlobalAccessControls(); } // Check if change notifications are disabled boolean changeNotify = elem.getChild("disableChangeNotification") == null ? true : false; // Create the shared filesystem filesys = new DiskSharedDevice(filesysName, filesysDriver, filesysContext); // Attach desktop actions to the filesystem ConfigElement deskActionsElem = elem.getChild("desktopActions"); if ( deskActionsElem != null) { // Get the desktop actions list DesktopActionTable desktopActions = processDesktopActions(deskActionsElem, filesys); if ( desktopActions != null) filesysContext.setDesktopActions( desktopActions, filesysDriver); } // Add any access controls to the share filesys.setAccessControlList(acls); // Enable/disable change notification for this device filesysContext.enableChangeHandler(changeNotify); // Start the filesystem filesysContext.startFilesystem(filesys); } // Add the new filesystem fsysConfig.addShare( filesys); } catch (DeviceContextException ex) { throw new AlfrescoRuntimeException("Error creating filesystem " + filesysName, ex); } } } else { // No filesystems defined logger.warn("No filesystems defined"); } // Check if shares should be added for all AVM stores ConfigElement avmAllStoresElem = config.getConfigElement( "avmAllStores"); if ( avmAllStoresElem != null && getAvmDiskInterface() != null) { // Get the list of store names AVMDiskDriver avmDriver = (AVMDiskDriver) getAvmDiskInterface(); StringList storeNames = avmDriver.getAVMStoreNames(); // Add shares for each of the store names, if the share name does not already exist if ( storeNames != null && storeNames.numberOfStrings() > 0) { // Add a share for each store for ( int i = 0; i < storeNames.numberOfStrings(); i++) { String storeName = storeNames.getStringAt( i); // Check if a share of the same name already exists if ( fsysConfig.getShares().findShare( storeName, ShareType.DISK, true) == null) { // Create the new share for the store AVMContext avmContext = new AVMContext( storeName, storeName + ":/", AVMContext.VERSION_HEAD); avmContext.enableStateTable( true, avmDriver.getStateReaper()); // Create the shared filesystem fsysConfig.addShare( new DiskSharedDevice( storeName, avmDriver, avmContext)); // DEBUG if ( logger.isDebugEnabled()) logger.debug( "Added AVM share " + storeName); } } } } } /** * Process the security configuration * * @param config Config */ private final void processSecurityConfig(Config config) { // Create the security configuration section SecurityConfigSection secConfig = new SecurityConfigSection( this); try { // Check if global access controls have been specified ConfigElement globalACLs = config.getConfigElement("globalAccessControl"); if (globalACLs != null) { // Parse the access control list AccessControlList acls = processAccessControlList(secConfig, globalACLs); if (acls != null) secConfig.setGlobalAccessControls(acls); } // Check if a JCE provider class has been specified ConfigElement jceElem = config.getConfigElement("JCEProvider"); if (jceElem != null) { // Set the JCE provider secConfig.setJCEProvider(jceElem.getValue()); } else { // Use the default Bouncy Castle JCE provider secConfig.setJCEProvider("org.bouncycastle.jce.provider.BouncyCastleProvider"); } // Check if a share mapper has been specified ConfigElement mapperElem = config.getConfigElement("shareMapper"); if ( mapperElem != null) { // Check if the shre mapper type has been specified String mapperType = mapperElem.getAttribute( "type"); String mapperClass = null; if ( mapperType.equalsIgnoreCase( "multi-tenant")) mapperClass = "org.alfresco.filesys.alfresco.MultiTenantShareMapper"; else { // Get the share mapper class ConfigElement classElem = mapperElem.getChild( "class"); if ( classElem == null) throw new InvalidConfigurationException("Share mapper class not specified"); } // Initialize the share mapper secConfig.setShareMapper(mapperClass, mapperElem); } else { // Check if the tenant service is enabled if ( m_tenantService != null && m_tenantService.isEnabled()) { // Initialize the multi-tenancy share mapper secConfig.setShareMapper("org.alfresco.filesys.alfresco.MultiTenantShareMapper", new GenericConfigElement("shareMapper")); } } // Check if any domain mappings have been specified ConfigElement domainMappings = config.getConfigElement( "DomainMappings"); if ( domainMappings != null) { // Get the domain mapping elements List mappings = domainMappings.getChildren(); if ( mappings != null) { DomainMapping mapping = null; for ( ConfigElement domainMap : mappings) { if ( domainMap.getName().equals( "Domain")) { // Get the domain name String name = domainMap.getAttribute( "name"); // Check if the domain is specified by subnet or range if ( domainMap.hasAttribute( "subnet")) { String subnetStr = domainMap.getAttribute( "subnet"); String maskStr = domainMap.getAttribute( "mask"); // Parse the subnet and mask, to validate and convert to int values int subnet = IPAddress.parseNumericAddress( subnetStr); int mask = IPAddress.parseNumericAddress( maskStr); if ( subnet == 0 || mask == 0) throw new AlfrescoRuntimeException( "Invalid subnet/mask for domain mapping " + name); // Create the subnet domain mapping mapping = new SubnetDomainMapping( name, subnet, mask); } else if ( domainMap.hasAttribute( "rangeFrom")) { String rangeFromStr = domainMap.getAttribute( "rangeFrom"); String rangeToStr = domainMap.getAttribute( "rangeTo"); // Parse the range from/to values and convert to int values int rangeFrom = IPAddress.parseNumericAddress( rangeFromStr); int rangeTo = IPAddress.parseNumericAddress( rangeToStr); if ( rangeFrom == 0 || rangeTo == 0) throw new AlfrescoRuntimeException( "Invalid address range domain mapping " + name); // Create the subnet domain mapping mapping = new RangeDomainMapping( name, rangeFrom, rangeTo); } else throw new AlfrescoRuntimeException( "Invalid domain mapping specified"); // Add the domain mapping secConfig.addDomainMapping(mapping); } } } } } catch ( InvalidConfigurationException ex) { throw new AlfrescoRuntimeException( ex.getMessage()); } } /** * Process the core server configuration * * @param config Config * @exception InvalidConfigurationException */ private final void processCoreServerConfig(Config config) throws InvalidConfigurationException { // Create the core server configuration section CoreServerConfigSection coreConfig = new CoreServerConfigSection(this); // Check if the server core element has been specified if ( config == null) { // Configure a default memory pool coreConfig.setMemoryPool( DefaultMemoryPoolBufSizes, DefaultMemoryPoolInitAlloc, DefaultMemoryPoolMaxAlloc); // Configure a default thread pool size coreConfig.setThreadPool( DefaultThreadPoolInit, DefaultThreadPoolMax); return; } // Check if the thread pool size has been specified ConfigElement elem = config.getConfigElement("threadPool"); if ( elem != null) { // Get the initial thread pool size String initSizeStr = elem.getAttribute("init"); if ( initSizeStr == null || initSizeStr.length() == 0) throw new InvalidConfigurationException("Thread pool initial size not specified"); // Validate the initial thread pool size int initSize = 0; try { initSize = Integer.parseInt( initSizeStr); } catch (NumberFormatException ex) { throw new InvalidConfigurationException("Invalid thread pool size value, " + initSizeStr); } // Range check the thread pool size if ( initSize < ThreadRequestPool.MinimumWorkerThreads) throw new InvalidConfigurationException("Thread pool size below minimum allowed size"); if ( initSize > ThreadRequestPool.MaximumWorkerThreads) throw new InvalidConfigurationException("Thread pool size above maximum allowed size"); // Get the maximum thread pool size String maxSizeStr = elem.getAttribute("max"); int maxSize = initSize; if ( maxSizeStr.length() > 0) { // Validate the maximum thread pool size try { maxSize = Integer.parseInt( maxSizeStr); } catch (NumberFormatException ex) { throw new InvalidConfigurationException(" Invalid thread pool maximum size value, " + maxSizeStr); } // Range check the maximum thread pool size if ( maxSize < ThreadRequestPool.MinimumWorkerThreads) throw new InvalidConfigurationException("Thread pool maximum size below minimum allowed size"); if ( maxSize > ThreadRequestPool.MaximumWorkerThreads) throw new InvalidConfigurationException("Thread pool maximum size above maximum allowed size"); if ( maxSize < initSize) throw new InvalidConfigurationException("Initial size is larger than maxmimum size"); } else if ( maxSizeStr != null) throw new InvalidConfigurationException("Thread pool maximum size not specified"); // Configure the thread pool coreConfig.setThreadPool( initSize, maxSize); } else { // Configure a default thread pool size coreConfig.setThreadPool( DefaultThreadPoolInit, DefaultThreadPoolMax); } // Check if thread pool debug output is enabled if ( config.getConfigElement( "threadPoolDebug") != null) coreConfig.getThreadPool().setDebug( true); // Check if the memory pool configuration has been specified elem = config.getConfigElement( "memoryPool"); if ( elem != null) { // Check if the packet sizes/allocations have been specified ConfigElement pktElem = elem.getChild( "packetSizes"); if ( pktElem != null) { // Calculate the array size for the packet size/allocation arrays int elemCnt = pktElem.getChildCount(); // Create the packet size, initial allocation and maximum allocation arrays int[] pktSizes = new int[elemCnt]; int[] initSizes = new int[elemCnt]; int[] maxSizes = new int[elemCnt]; int elemIdx = 0; // Process the packet size elements List pktSizeList = pktElem.getChildren(); for ( int i = 0; i < pktSizeList.size(); i++) { // Get the current element ConfigElement curChild = pktSizeList.get( i); if ( curChild.getName().equals( "packet")) { // Get the packet size int pktSize = -1; int initAlloc = -1; int maxAlloc = -1; String pktSizeStr = curChild.getAttribute("size"); if ( pktSizeStr == null || pktSizeStr.length() == 0) throw new InvalidConfigurationException("Memory pool packet size not specified"); // Parse the packet size try { pktSize = MemorySize.getByteValueInt( pktSizeStr); } catch ( NumberFormatException ex) { throw new InvalidConfigurationException("Memory pool packet size, invalid size value, " + pktSizeStr); } // Make sure the packet sizes have been specified in ascending order if ( elemIdx > 0 && pktSizes[elemIdx - 1] >= pktSize) throw new InvalidConfigurationException("Invalid packet size specified, less than/equal to previous packet size"); // Get the initial allocation for the current packet size String initSizeStr = curChild.getAttribute("init"); if ( initSizeStr == null || initSizeStr.length() == 0) throw new InvalidConfigurationException("Memory pool initial allocation not specified"); // Parse the initial allocation try { initAlloc = Integer.parseInt( initSizeStr); } catch (NumberFormatException ex) { throw new InvalidConfigurationException("Invalid initial allocation, " + initSizeStr); } // Range check the initial allocation if ( initAlloc < MemoryPoolMinimumAllocation) throw new InvalidConfigurationException("Initial memory pool allocation below minimum of " + MemoryPoolMinimumAllocation); if ( initAlloc > MemoryPoolMaximumAllocation) throw new InvalidConfigurationException("Initial memory pool allocation above maximum of " + MemoryPoolMaximumAllocation); // Get the maximum allocation for the current packet size String maxSizeStr = curChild.getAttribute("max"); if ( maxSizeStr == null || maxSizeStr.length() == 0) throw new InvalidConfigurationException("Memory pool maximum allocation not specified"); // Parse the maximum allocation try { maxAlloc = Integer.parseInt( maxSizeStr); } catch (NumberFormatException ex) { throw new InvalidConfigurationException("Invalid maximum allocation, " + maxSizeStr); } // Range check the maximum allocation if ( maxAlloc < MemoryPoolMinimumAllocation) throw new InvalidConfigurationException("Maximum memory pool allocation below minimum of " + MemoryPoolMinimumAllocation); if ( initAlloc > MemoryPoolMaximumAllocation) throw new InvalidConfigurationException("Maximum memory pool allocation above maximum of " + MemoryPoolMaximumAllocation); // Set the current packet size elements pktSizes[elemIdx] = pktSize; initSizes[elemIdx] = initAlloc; maxSizes[elemIdx] = maxAlloc; elemIdx++; } } // Check if all elements were used in the packet size/allocation arrays if ( elemIdx < pktSizes.length) { // Re-allocate the packet size/allocation arrays int[] newPktSizes = new int[elemIdx]; int[] newInitSizes = new int[elemIdx]; int[] newMaxSizes = new int[elemIdx]; // Copy the values to the shorter arrays System.arraycopy(pktSizes, 0, newPktSizes, 0, elemIdx); System.arraycopy(initSizes, 0, newInitSizes, 0, elemIdx); System.arraycopy(maxSizes, 0, newMaxSizes, 0, elemIdx); // Move the new arrays into place pktSizes = newPktSizes; initSizes = newInitSizes; maxSizes = newMaxSizes; } // Configure the memory pool coreConfig.setMemoryPool( pktSizes, initSizes, maxSizes); } } else { // Configure a default memory pool coreConfig.setMemoryPool( DefaultMemoryPoolBufSizes, DefaultMemoryPoolInitAlloc, DefaultMemoryPoolMaxAlloc); } } /** * Process an access control sub-section and return the access control list * * @param secConfig SecurityConfigSection * @param aclsElem ConfigElement */ private final AccessControlList processAccessControlList(SecurityConfigSection secConfig, ConfigElement aclsElem) { // Check if there is an access control manager configured if (secConfig.getAccessControlManager() == null) throw new AlfrescoRuntimeException("No access control manager configured"); // Create the access control list AccessControlList acls = new AccessControlList(); // Check if there is a default access level for the ACL group String attrib = aclsElem.getAttribute("default"); if (attrib != null && attrib.length() > 0) { // Get the access level and validate try { // Parse the access level name int access = AccessControlParser.parseAccessTypeString(attrib); // Set the default access level for the access control list acls.setDefaultAccessLevel(access); } catch (InvalidACLTypeException ex) { throw new AlfrescoRuntimeException("Default access level error", ex); } catch (ACLParseException ex) { throw new AlfrescoRuntimeException("Default access level error", ex); } } // Parse each access control element List aclElemList = aclsElem.getChildren(); if (aclElemList != null && aclElemList.size() > 0) { // Create the access controls for (int i = 0; i < aclsElem.getChildCount(); i++) { // Get the current ACL element ConfigElement curAclElem = aclElemList.get(i); try { // Create the access control and add to the list acls.addControl(secConfig.getAccessControlManager().createAccessControl(curAclElem.getName(), curAclElem)); } catch (InvalidACLTypeException ex) { throw new AlfrescoRuntimeException("Invalid access control type - " + curAclElem.getName()); } catch (ACLParseException ex) { throw new AlfrescoRuntimeException("Access control parse error (" + curAclElem.getName() + ")", ex); } } } // Check if there are no access control rules but the default access level is set to 'None', // this is not allowed as the share would not be accessible or visible. if (acls.getDefaultAccessLevel() == AccessControl.NoAccess && acls.numberOfControls() == 0) throw new AlfrescoRuntimeException("Empty access control list and default access 'None' not allowed"); // Return the access control list return acls; } /** * Process a desktop actions sub-section and return the desktop action table * * @param deskActionElem ConfigElement * @param fileSys DiskSharedDevice */ private final DesktopActionTable processDesktopActions(ConfigElement deskActionElem, DiskSharedDevice fileSys) { // Get the desktop action configuration elements DesktopActionTable desktopActions = null; List actionElems = deskActionElem.getChildren(); if ( actionElems != null) { // Check for the global configuration section ConfigElement globalConfig = deskActionElem.getChild("global"); // Allocate the actions table desktopActions = new DesktopActionTable(); // Process the desktop actions list for ( ConfigElement actionElem : actionElems) { if ( actionElem.getName().equals("action")) { // Get the desktop action class name or bean id ConfigElement className = actionElem.getChild("class"); if ( className != null) { // Load the desktop action class, create a new instance Object actionObj = null; try { // Create a new desktop action instance actionObj = Class.forName(className.getValue()).newInstance(); // Make sure the object is a desktop action if ( actionObj instanceof DesktopAction) { // Initialize the desktop action DesktopAction deskAction = (DesktopAction) actionObj; deskAction.initializeAction(globalConfig, actionElem, fileSys); // Add the action to the list of desktop actions desktopActions.addAction(deskAction); // DEBUG if ( logger.isDebugEnabled()) logger.debug("Added desktop action " + deskAction.getName()); } else throw new AlfrescoRuntimeException("Desktop action does not extend DesktopAction class, " + className.getValue()); } catch ( ClassNotFoundException ex) { throw new AlfrescoRuntimeException("Desktop action class not found, " + className.getValue()); } catch (IllegalAccessException ex) { throw new AlfrescoRuntimeException("Failed to create desktop action instance, " + className.getValue(), ex); } catch ( InstantiationException ex) { throw new AlfrescoRuntimeException("Failed to create desktop action instance, " + className.getValue(), ex); } catch (DesktopActionException ex) { throw new AlfrescoRuntimeException("Failed to initialize desktop action", ex); } } } else if ( actionElem.getName().equals("global") == false) throw new AlfrescoRuntimeException("Invalid configuration element in desktopActions section, " + actionElem.getName()); } } // Return the desktop actions list return desktopActions; } /** * Parse the platforms attribute returning the set of platform ids * * @param platformStr String * @return EnumSet */ private final EnumSet parsePlatformString(String platformStr) { // Split the platform string and build up a set of platform types EnumSet platformTypes = EnumSet.noneOf(Platform.Type.class); if (platformStr == null || platformStr.length() == 0) return platformTypes; StringTokenizer token = new StringTokenizer(platformStr.toUpperCase(Locale.ENGLISH), ","); String typ = null; try { while (token.hasMoreTokens()) { // Get the current platform type string and validate typ = token.nextToken().trim(); Platform.Type platform = Platform.Type.valueOf(typ); if (platform != Platform.Type.Unknown) platformTypes.add(platform); else throw new AlfrescoRuntimeException("Invalid platform type, " + typ); } } catch (IllegalArgumentException ex) { throw new AlfrescoRuntimeException("Invalid platform type, " + typ); } // Return the platform types return platformTypes; } /** * Get the local server name and optionally trim the domain name * * @param trimDomain boolean * @return String */ public final String getLocalServerName(boolean trimDomain) { // Check if the name has already been set if (m_localName != null) return m_localName; // Find the local server name String srvName = null; if (getPlatformType() == Platform.Type.WINDOWS) { // Get the local name via JNI srvName = Win32NetBIOS.GetLocalNetBIOSName(); } else { // Get the DNS name of the local system try { srvName = InetAddress.getLocalHost().getHostName(); } catch (UnknownHostException ex) { } } // Strip the domain name if (trimDomain && srvName != null) { int pos = srvName.indexOf("."); if (pos != -1) srvName = srvName.substring(0, pos); } // Save the local server name m_localName = srvName; // Return the local server name return srvName; } /** * Get the local domain/workgroup name * * @return String */ public final String getLocalDomainName() { // Check if the local domain has been set if (m_localDomain != null) return m_localDomain; // Find the local domain name String domainName = null; if (getPlatformType() == Platform.Type.WINDOWS) { // Get the local domain/workgroup name via JNI domainName = Win32NetBIOS.GetLocalDomainName(); // Debug if (logger.isDebugEnabled()) logger.debug("Local domain name is " + domainName + " (via JNI)"); } else { NetBIOSName nbName = null; try { // Try and find the browse master on the local network nbName = NetBIOSSession.FindName(NetBIOSName.BrowseMasterName, NetBIOSName.BrowseMasterGroup, 5000); // Log the browse master details if (logger.isDebugEnabled()) logger.debug("Found browse master at " + nbName.getIPAddressString(0)); // Get the NetBIOS name list from the browse master NetBIOSNameList nbNameList = NetBIOSSession.FindNamesForAddress(nbName.getIPAddressString(0)); if (nbNameList != null) { nbName = nbNameList.findName(NetBIOSName.MasterBrowser, false); // Set the domain/workgroup name if (nbName != null) domainName = nbName.getName(); } } catch (IOException ex) { } } // Save the local domain name m_localDomain = domainName; // Return the local domain/workgroup name return domainName; } /** * Parse an adapter name string and return the matching address * * @param adapter String * @return InetAddress * @exception InvalidConfigurationException */ protected final InetAddress parseAdapterName(String adapter) throws InvalidConfigurationException { NetworkInterface ni = null; try { ni = NetworkInterface.getByName( adapter); } catch (SocketException ex) { throw new InvalidConfigurationException( "Invalid adapter name, " + adapter); } if ( ni == null) throw new InvalidConfigurationException( "Invalid network adapter name, " + adapter); // Get the IP address for the adapter InetAddress adapAddr = null; Enumeration addrEnum = ni.getInetAddresses(); while ( addrEnum.hasMoreElements() && adapAddr == null) { // Get the current address InetAddress addr = addrEnum.nextElement(); if ( IPAddress.isNumericAddress( addr.getHostAddress())) adapAddr = addr; } // Check if we found the IP address to bind to if ( adapAddr == null) throw new InvalidConfigurationException( "Adapter " + adapter + " does not have a valid IP address"); // Return the adapter address return adapAddr; } private ApplicationContext applicationContext = null; /* (non-Javadoc) * @see org.springframework.context.ApplicationListener#onApplicationEvent(org.springframework.context.ApplicationEvent) */ public void onApplicationEvent(ApplicationEvent event) { if (event instanceof ContextRefreshedEvent) { ContextRefreshedEvent refreshEvent = (ContextRefreshedEvent)event; ApplicationContext refreshContext = refreshEvent.getApplicationContext(); if (refreshContext != null && refreshContext.equals(applicationContext)) { // Initialize the bean init(); } } } /* (non-Javadoc) * @see org.springframework.context.ApplicationContextAware#setApplicationContext(org.springframework.context.ApplicationContext) */ public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { this.applicationContext = applicationContext; } /** * Return the authentication service * * @return AuthenticationService */ protected final AuthenticationService getAuthenticationService() { return m_authenticationService; } /** * Return the authentication component * * @return AuthenticationComponent */ protected final AuthenticationComponent getAuthenticationComponent() { return m_authenticationComponent; } /** * Return the node service * * @return NodeService */ protected final NodeService getNodeService() { return m_nodeService; } /** * Return the person service * * @return PersonService */ protected final PersonService getPersonService() { return m_personService; } /** * Return the transaction service * * @return TransactionService */ protected final TransactionService getTransactionService() { return m_transactionService; } /** * Return the tenant service * * @return TenantService */ protected final TenantService getTenantService() { return m_tenantService; } /** * Return the search service * * @return SearchService */ protected final SearchService getSearchService() { return m_searchService; } /** * Return the namespace service * * @return NamespaceService */ protected final NamespaceService getNamespaceService() { return m_namespaceService; } }