diff --git a/source/java/org/alfresco/filesys/ServerConfigurationBean.java b/source/java/org/alfresco/filesys/ServerConfigurationBean.java index b2b6919cfc..5a453ca5a5 100644 --- a/source/java/org/alfresco/filesys/ServerConfigurationBean.java +++ b/source/java/org/alfresco/filesys/ServerConfigurationBean.java @@ -88,6 +88,7 @@ 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.alfresco.HomeShareMapper; import org.alfresco.filesys.avm.AVMContext; import org.alfresco.filesys.avm.AVMDiskDriver; import org.alfresco.filesys.repo.ContentContext; @@ -2422,6 +2423,29 @@ public class ServerConfigurationBean extends ServerConfiguration implements Appl } } } + + // Check for the home folder filesystem + + ConfigElement homeElem = config.getConfigElement("homeFolder"); + + if ( homeElem != null) + { + try + { + // Initialize the home folder share mapper + + secConfig.setShareMapper( "org.alfresco.filesys.alfresco.HomeShareMapper", homeElem); + + // Debug + + if ( logger.isDebugEnabled()) + logger.debug("Using home folder share mapper"); + } + catch (InvalidConfigurationException ex) + { + throw new AlfrescoRuntimeException("Failed to initialize home folder share mapper", ex); + } + } } /** @@ -2473,13 +2497,15 @@ public class ServerConfigurationBean extends ServerConfiguration implements Appl if ( mapperElem != null) { - // Check if the shre mapper type has been specified + // Check if the share 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 if ( mapperType.equalsIgnoreCase( "home-folder")) + mapperClass = "org.alfresco.filesys.alfresco.HomeShareMapper"; else { // Get the share mapper class diff --git a/source/java/org/alfresco/filesys/alfresco/HomeShareMapper.java b/source/java/org/alfresco/filesys/alfresco/HomeShareMapper.java new file mode 100644 index 0000000000..2078eaabf1 --- /dev/null +++ b/source/java/org/alfresco/filesys/alfresco/HomeShareMapper.java @@ -0,0 +1,346 @@ +/* + * Copyright (C) 2006-2009 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.alfresco; + +import java.util.Enumeration; + +import org.alfresco.config.ConfigElement; +import org.alfresco.filesys.AlfrescoConfigSection; +import org.alfresco.filesys.repo.ContentContext; +import org.alfresco.filesys.repo.ContentDiskDriver; +import org.alfresco.jlan.server.SrvSession; +import org.alfresco.jlan.server.auth.InvalidUserException; +import org.alfresco.jlan.server.config.InvalidConfigurationException; +import org.alfresco.jlan.server.config.ServerConfiguration; +import org.alfresco.jlan.server.core.ShareMapper; +import org.alfresco.jlan.server.core.ShareType; +import org.alfresco.jlan.server.core.SharedDevice; +import org.alfresco.jlan.server.core.SharedDeviceList; +import org.alfresco.jlan.server.filesys.DiskSharedDevice; +import org.alfresco.jlan.server.filesys.FilesystemsConfigSection; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +/** + * Home Share Mapper Class + * + *

Maps disk share lookup requests to the list of shares defined in the server + * configuration and provides a dynamic home share mapped to the users home node. + * + * @author GKSpencer + */ +public class HomeShareMapper implements ShareMapper +{ + // Logging + + private static final Log logger = LogFactory.getLog("org.alfresco.smb.protocol"); + + // Home folder share name + + public static final String HOME_FOLDER_SHARE = "HOME"; + + // Server configuration + + private ServerConfiguration m_config; + + private AlfrescoConfigSection m_alfConfig; + private FilesystemsConfigSection m_fsysConfig; + + // Home folder share name + + private String m_homeShareName = HOME_FOLDER_SHARE; + + // Debug enable flag + + private boolean m_debug; + + /** + * Default constructor + */ + public HomeShareMapper() + { + } + + /** + * Initialize the share mapper + * + * @param config ServerConfiguration + * @param params ConfigElement + * @exception InvalidConfigurationException + */ + public void initializeMapper(ServerConfiguration config, ConfigElement params) throws InvalidConfigurationException + { + // Save the server configuration + + m_config = config; + + m_alfConfig = (AlfrescoConfigSection) m_config.getConfigSection( AlfrescoConfigSection.SectionName); + m_fsysConfig = (FilesystemsConfigSection) m_config.getConfigSection( FilesystemsConfigSection.SectionName); + + // Check if the home share name has been specified + + String homeName = params.getAttribute("name"); + if ( homeName != null && homeName.length() > 0) + m_homeShareName = homeName; + + // Check if debug is enabled + + if (params != null && params.getChild("debug") != null) + m_debug = true; + } + + /** + * Check if debug output is enabled + * + * @return boolean + */ + public final boolean hasDebug() + { + return m_debug; + } + + /** + * Return the home folder share name + * + * @return String + */ + public final String getHomeFolderName() + { + return m_homeShareName; + } + + /** + * Return the list of available shares. + * + * @param host String + * @param sess SrvSession + * @param allShares boolean + * @return SharedDeviceList + */ + public SharedDeviceList getShareList(String host, SrvSession sess, boolean allShares) + { + // Check if the user has a home folder, and the session does not currently have any + // dynamic shares defined + + if ( sess != null && sess.hasClientInformation() && sess.hasDynamicShares() == false && + sess.getClientInformation() instanceof AlfrescoClientInfo) + { + AlfrescoClientInfo client = (AlfrescoClientInfo) sess.getClientInformation(); + if ( client.hasHomeFolder()) + { + // Create the home folder share + + DiskSharedDevice homeShare = createHomeDiskShare(client); + sess.addDynamicShare(homeShare); + + // Debug + + if ( logger.isDebugEnabled()) + logger.debug("Added " + getHomeFolderName() + " share to list of shares for " + client.getUserName()); + } + } + + // Make a copy of the global share list and add the per session dynamic shares + + SharedDeviceList shrList = new SharedDeviceList(m_fsysConfig.getShares()); + + if ( sess != null && sess.hasDynamicShares()) { + + // Add the per session dynamic shares + + shrList.addShares(sess.getDynamicShareList()); + } + + // Remove unavailable shares from the list and return the list + + if ( allShares == false) + shrList.removeUnavailableShares(); + return shrList; + } + + /** + * Find a share using the name and type for the specified client. + * + * @param host String + * @param name String + * @param typ int + * @param sess SrvSession + * @param create boolean + * @return SharedDevice + * @exception InvalidUserException + */ + public SharedDevice findShare(String tohost, String name, int typ, SrvSession sess, boolean create) + throws Exception + { + + // Check for the special HOME disk share + + SharedDevice share = null; + + if (( typ == ShareType.DISK || typ == ShareType.UNKNOWN) && name.equalsIgnoreCase(getHomeFolderName()) && + sess.getClientInformation() != null && sess.getClientInformation() instanceof AlfrescoClientInfo) { + + // Get the client details + + AlfrescoClientInfo client = (AlfrescoClientInfo) sess.getClientInformation(); + + // DEBUG + + if ( logger.isDebugEnabled()) + logger.debug("Map share " + name + ", type=" + ShareType.TypeAsString(typ) + ", client=" + client); + + // Check if the user has a home folder node + + if ( client != null && client.hasHomeFolder()) { + + // Check if the share has already been created for the session + + if ( sess.hasDynamicShares()) { + + // Check if the required share exists in the sessions dynamic share list + + share = sess.getDynamicShareList().findShare(name, typ, false); + + // DEBUG + + if ( logger.isDebugEnabled()) + logger.debug(" Reusing existing dynamic share for " + name); + } + + // Check if we found a share, if not then create a new dynamic share for the home directory + + if ( share == null && create == true) { + + // Create the home share mapped to the users home folder + + DiskSharedDevice diskShare = createHomeDiskShare(client); + + // Add the new share to the sessions dynamic share list + + sess.addDynamicShare(diskShare); + share = diskShare; + + // DEBUG + + if (logger.isDebugEnabled()) + logger.debug(" Mapped share " + name + " to " + client.getHomeFolder()); + } + } + else + throw new InvalidUserException("No home directory"); + } + else { + + // Find the required share by name/type. Use a case sensitive search first, if that fails use a case + // insensitive search. + + share = m_fsysConfig.getShares().findShare(name, typ, false); + + if ( share == null) { + + // Try a case insensitive search for the required share + + share = m_fsysConfig.getShares().findShare(name, typ, true); + } + } + + // Check if the share is available + + if ( share != null && share.getContext() != null && share.getContext().isAvailable() == false) + share = null; + + // Return the shared device, or null if no matching device was found + + return share; + } + + /** + * Delete temporary shares for the specified session + * + * @param sess SrvSession + */ + public void deleteShares(SrvSession sess) + { + + // Check if the session has any dynamic shares + + if ( sess.hasDynamicShares() == false) + return; + + // Delete the dynamic shares + + SharedDeviceList shares = sess.getDynamicShareList(); + Enumeration enm = shares.enumerateShares(); + + while ( enm.hasMoreElements()) { + + // Get the current share from the list + + SharedDevice shr = (SharedDevice) enm.nextElement(); + + // Close the shared device + + shr.getContext().CloseContext(); + + // DEBUG + + if (logger.isDebugEnabled()) + logger.debug("Deleted dynamic share " + shr); + } + + // Clear the dynamic share list + + shares.removeAllShares(); + } + + /** + * Close the share mapper, release any resources. + */ + public void closeMapper() + { + // Nothing to do + } + + /** + * Create a disk share for the home folder + * + * @param client AlfrescoClientInfo + * @return DiskSharedDevice + */ + private final DiskSharedDevice createHomeDiskShare(AlfrescoClientInfo client) + { + // Create the disk driver and context + + ContentDiskDriver diskDrv = ( ContentDiskDriver) m_alfConfig.getRepoDiskInterface(); + ContentContext diskCtx = new ContentContext( getHomeFolderName(), "", "", client.getHomeFolder()); + + diskCtx.enableStateTable( true, diskDrv.getStateReaper()); + + // Create a temporary shared device for the users home directory + + return new DiskSharedDevice(getHomeFolderName(), diskDrv, diskCtx, SharedDevice.Temporary); + } +} diff --git a/source/java/org/alfresco/filesys/auth/cifs/CifsAuthenticatorBase.java b/source/java/org/alfresco/filesys/auth/cifs/CifsAuthenticatorBase.java index 7175c7aa7e..a26a3b99d7 100644 --- a/source/java/org/alfresco/filesys/auth/cifs/CifsAuthenticatorBase.java +++ b/source/java/org/alfresco/filesys/auth/cifs/CifsAuthenticatorBase.java @@ -169,9 +169,10 @@ public abstract class CifsAuthenticatorBase extends CifsAuthenticator */ protected final void getHomeFolderForUser(ClientInfo client) { - // Check if the client is an Alfresco client + // Check if the client is an Alfresco client, and not a null logon - if ( client instanceof AlfrescoClientInfo == false) + if ( client instanceof AlfrescoClientInfo == false || + client.isNullSession() == true) return; AlfrescoClientInfo alfClient = (AlfrescoClientInfo) client; diff --git a/source/java/org/alfresco/filesys/auth/cifs/EnterpriseCifsAuthenticator.java b/source/java/org/alfresco/filesys/auth/cifs/EnterpriseCifsAuthenticator.java index 33a2eca33f..c34de229c1 100644 --- a/source/java/org/alfresco/filesys/auth/cifs/EnterpriseCifsAuthenticator.java +++ b/source/java/org/alfresco/filesys/auth/cifs/EnterpriseCifsAuthenticator.java @@ -905,6 +905,10 @@ public class EnterpriseCifsAuthenticator extends CifsAuthenticatorBase implement checkForAdminUserName( client); + // Get the users home folder node, if available + + getHomeFolderForUser( client); + // Create a virtual circuit for the new logon VirtualCircuit vc = new VirtualCircuit( vcNum, client); diff --git a/source/java/org/alfresco/filesys/auth/cifs/PassthruCifsAuthenticator.java b/source/java/org/alfresco/filesys/auth/cifs/PassthruCifsAuthenticator.java index 4d5da86e66..a3189f5316 100644 --- a/source/java/org/alfresco/filesys/auth/cifs/PassthruCifsAuthenticator.java +++ b/source/java/org/alfresco/filesys/auth/cifs/PassthruCifsAuthenticator.java @@ -751,6 +751,10 @@ public class PassthruCifsAuthenticator extends CifsAuthenticatorBase implements checkForAdminUserName( client); + // Get the users home folder node, if available + + getHomeFolderForUser( client); + // Create a virtual circuit for the new logon VirtualCircuit vc = new VirtualCircuit( vcNum, client);