CifsOnlyXMLServerConfiguration.java 73 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617
  1. /*
  2. * Copyright (C) 2006-2010 Alfresco Software Limited.
  3. *
  4. * This file is part of Alfresco
  5. *
  6. * Alfresco is free software: you can redistribute it and/or modify
  7. * it under the terms of the GNU Lesser General Public License as published by
  8. * the Free Software Foundation, either version 3 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * Alfresco is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU Lesser General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU Lesser General Public License
  17. * along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
  18. */
  19. package org.alfresco.jlan.app;
  20. import java.io.FileInputStream;
  21. import java.io.IOException;
  22. import java.io.InputStream;
  23. import java.io.InputStreamReader;
  24. import java.io.Reader;
  25. import java.net.InetAddress;
  26. import java.net.NetworkInterface;
  27. import java.net.SocketException;
  28. import java.net.UnknownHostException;
  29. import java.text.ParseException;
  30. import java.text.SimpleDateFormat;
  31. import java.util.ArrayList;
  32. import java.util.Date;
  33. import java.util.Enumeration;
  34. import java.util.List;
  35. import java.util.Locale;
  36. import java.util.StringTokenizer;
  37. import javax.xml.parsers.DocumentBuilder;
  38. import javax.xml.parsers.DocumentBuilderFactory;
  39. import org.alfresco.jlan.debug.Debug;
  40. import org.alfresco.jlan.debug.DebugConfigSection;
  41. import org.alfresco.jlan.netbios.win32.Win32NetBIOS;
  42. import org.alfresco.jlan.server.auth.CifsAuthenticator;
  43. import org.alfresco.jlan.server.auth.UserAccount;
  44. import org.alfresco.jlan.server.auth.UserAccountList;
  45. import org.alfresco.jlan.server.auth.acl.ACLParseException;
  46. import org.alfresco.jlan.server.auth.acl.AccessControl;
  47. import org.alfresco.jlan.server.auth.acl.AccessControlList;
  48. import org.alfresco.jlan.server.auth.acl.AccessControlParser;
  49. import org.alfresco.jlan.server.auth.acl.InvalidACLTypeException;
  50. import org.alfresco.jlan.server.config.CoreServerConfigSection;
  51. import org.alfresco.jlan.server.config.GlobalConfigSection;
  52. import org.alfresco.jlan.server.config.InvalidConfigurationException;
  53. import org.alfresco.jlan.server.config.SecurityConfigSection;
  54. import org.alfresco.jlan.server.config.ServerConfiguration;
  55. import org.alfresco.jlan.server.core.DeviceContextException;
  56. import org.alfresco.jlan.server.core.ShareType;
  57. import org.alfresco.jlan.server.core.SharedDeviceList;
  58. import org.alfresco.jlan.server.filesys.DiskDeviceContext;
  59. import org.alfresco.jlan.server.filesys.DiskInterface;
  60. import org.alfresco.jlan.server.filesys.DiskSharedDevice;
  61. import org.alfresco.jlan.server.filesys.FilesystemsConfigSection;
  62. import org.alfresco.jlan.server.filesys.SrvDiskInfo;
  63. import org.alfresco.jlan.server.filesys.VolumeInfo;
  64. import org.alfresco.jlan.server.filesys.cache.FileStateCache;
  65. import org.alfresco.jlan.server.filesys.cache.StandaloneFileStateCache;
  66. import org.alfresco.jlan.server.thread.ThreadRequestPool;
  67. import org.alfresco.jlan.smb.Dialect;
  68. import org.alfresco.jlan.smb.DialectSelector;
  69. import org.alfresco.jlan.smb.server.CIFSConfigSection;
  70. import org.alfresco.jlan.smb.server.SMBSrvSession;
  71. import org.alfresco.jlan.smb.server.VirtualCircuitList;
  72. import org.alfresco.jlan.smb.util.DriveMapping;
  73. import org.alfresco.jlan.smb.util.DriveMappingList;
  74. import org.alfresco.jlan.util.IPAddress;
  75. import org.alfresco.jlan.util.MemorySize;
  76. import org.alfresco.jlan.util.Platform;
  77. import org.alfresco.jlan.util.StringList;
  78. import org.alfresco.jlan.util.X64;
  79. import org.springframework.extensions.config.ConfigElement;
  80. import org.springframework.extensions.config.element.GenericConfigElement;
  81. import org.w3c.dom.Document;
  82. import org.w3c.dom.Element;
  83. import org.w3c.dom.NamedNodeMap;
  84. import org.w3c.dom.Node;
  85. import org.w3c.dom.NodeList;
  86. import org.xml.sax.InputSource;
  87. /**
  88. * Cifs Only XML File Server Configuration Class
  89. *
  90. * <p>
  91. * XML implementation of the SMB server configuration.
  92. *
  93. * @author gkspencer
  94. */
  95. public class CifsOnlyXMLServerConfiguration extends ServerConfiguration {
  96. // Constants
  97. //
  98. // Node type for an Element
  99. private static final int ELEMENT_TYPE = 1;
  100. // CIFS session debug type strings
  101. //
  102. // Must match the bit mask order.
  103. private static final String m_sessDbgStr[] = { "NETBIOS", "STATE", "RXDATA", "TXDATA", "DUMPDATA", "NEGOTIATE", "TREE",
  104. "SEARCH", "INFO", "FILE", "FILEIO", "TRANSACT", "ECHO", "ERROR", "IPC", "LOCK", "PKTTYPE", "DCERPC", "STATECACHE",
  105. "TIMING", "NOTIFY", "STREAMS", "SOCKET", "PKTPOOL", "PKTSTATS", "THREADPOOL", "BENCHMARK", "OPLOCK", "PKTALLOC" };
  106. // Default session debug flags, if enabled
  107. private static final int DEFAULT_SESSDEBUG = SMBSrvSession.DBG_ERROR + SMBSrvSession.DBG_INFO + SMBSrvSession.DBG_SEARCH
  108. + SMBSrvSession.DBG_TREE + SMBSrvSession.DBG_TRAN + SMBSrvSession.DBG_STATE;
  109. // Valid drive letter names for mapped drives
  110. private static final String _driveLetters = "CDEFGHIJKLMNOPQRSTUVWXYZ";
  111. // Default thread pool size
  112. private static final int DefaultThreadPoolInit = 25;
  113. private static final int DefaultThreadPoolMax = 50;
  114. // Default memory pool settings
  115. private static final int[] DefaultMemoryPoolBufSizes = { 256, 4096, 16384, 66000 };
  116. private static final int[] DefaultMemoryPoolInitAlloc = { 20, 20, 5, 5 };
  117. private static final int[] DefaultMemoryPoolMaxAlloc = { 100, 50, 50, 50 };
  118. // Memory pool packet size limits
  119. private static final int MemoryPoolMinimumPacketSize = 256;
  120. private static final int MemoryPoolMaximumPacketSize = 128 * (int) MemorySize.KILOBYTE;
  121. // Memory pool allocation limits
  122. private static final int MemoryPoolMinimumAllocation = 5;
  123. private static final int MemoryPoolMaximumAllocation = 500;
  124. // Maximum session timeout
  125. private static final int MaxSessionTimeout = 60 * 60; // 1 hour
  126. // Date formatter
  127. private SimpleDateFormat m_dateFmt = new SimpleDateFormat("dd-MMM-yyyy hh:mm:ss");
  128. /**
  129. * Default constructor
  130. */
  131. public CifsOnlyXMLServerConfiguration() {
  132. super("");
  133. }
  134. /**
  135. * Load the configuration from the specified file.
  136. *
  137. * @param fname java.lang.String
  138. * @exception IOException
  139. * @exception InvalidConfigurationException
  140. */
  141. public final void loadConfiguration(String fname)
  142. throws IOException, InvalidConfigurationException {
  143. // Open the configuration file
  144. InputStream inFile = new FileInputStream(fname);
  145. Reader inRead = new InputStreamReader(inFile);
  146. // Call the main parsing method
  147. loadConfiguration(inRead);
  148. }
  149. /**
  150. * Load the configuration from the specified input stream
  151. *
  152. * @param in Reader
  153. * @exception IOException
  154. * @exception InvalidConfigurationException
  155. */
  156. public final void loadConfiguration(Reader in)
  157. throws IOException, InvalidConfigurationException {
  158. // Reset the current configuration to the default settings
  159. removeAllConfigSections();
  160. // Load and parse the XML configuration document
  161. try {
  162. // Load the configuration from the XML file
  163. DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
  164. DocumentBuilder builder = factory.newDocumentBuilder();
  165. InputSource xmlSource = new InputSource(in);
  166. Document doc = builder.parse(xmlSource);
  167. // Parse the document
  168. loadConfiguration(doc);
  169. }
  170. catch (Exception ex) {
  171. // Rethrow the exception as a configuration exeception
  172. throw new InvalidConfigurationException("XML error", ex);
  173. }
  174. finally {
  175. // Close the input file
  176. in.close();
  177. }
  178. }
  179. /**
  180. * Load the configuration from the specified document
  181. *
  182. * @param doc Document
  183. * @exception IOException
  184. * @exception InvalidConfigurationException
  185. */
  186. public void loadConfiguration(Document doc)
  187. throws IOException, InvalidConfigurationException {
  188. // Reset the current configuration to the default settings
  189. removeAllConfigSections();
  190. // Parse the XML configuration document
  191. try {
  192. // Access the root of the XML document, get a list of the child nodes
  193. Element root = doc.getDocumentElement();
  194. NodeList childNodes = root.getChildNodes();
  195. // Process the debug settings element
  196. procDebugElement(findChildNode("debug", childNodes));
  197. // Process the core server configuration settings
  198. procServerCoreElement(findChildNode("server-core", childNodes));
  199. // Process the global configuration settings
  200. procGlobalElement(findChildNode("global", childNodes));
  201. // Process the security element
  202. procSecurityElement(findChildNode("security", childNodes));
  203. // Process the shares element
  204. procSharesElement(findChildNode("shares", childNodes));
  205. // Process the SMB server specific settings
  206. procSMBServerElement(findChildNode("SMB", childNodes));
  207. // Process the drive mappings settings
  208. procDriveMappingsElement(findChildNode("DriveMappings", childNodes));
  209. }
  210. catch (Exception ex) {
  211. // Rethrow the exception as a configuration exeception
  212. throw new InvalidConfigurationException("XML error", ex);
  213. }
  214. }
  215. /**
  216. * Process the server core settings XML element
  217. *
  218. * @param srvCore Element
  219. * @exception InvalidConfigurationException
  220. */
  221. protected final void procServerCoreElement(Element srvCore)
  222. throws InvalidConfigurationException {
  223. // Create the core server configuration section
  224. CoreServerConfigSection coreConfig = new CoreServerConfigSection(this);
  225. // Check if the server core element has been specified
  226. if ( srvCore == null) {
  227. // Configure a default memory pool
  228. coreConfig.setMemoryPool( DefaultMemoryPoolBufSizes, DefaultMemoryPoolInitAlloc, DefaultMemoryPoolMaxAlloc);
  229. // Configure a default thread pool size
  230. coreConfig.setThreadPool( DefaultThreadPoolInit, DefaultThreadPoolMax);
  231. return;
  232. }
  233. // Check if the thread pool size has been specified
  234. Element elem = findChildNode("threadPool", srvCore.getChildNodes());
  235. if ( elem != null) {
  236. // Get the initial thread pool size
  237. String initSizeStr = elem.getAttribute("init");
  238. if ( initSizeStr == null || initSizeStr.length() == 0)
  239. throw new InvalidConfigurationException("Thread pool initial size not specified");
  240. // Validate the initial thread pool size
  241. int initSize = 0;
  242. try {
  243. initSize = Integer.parseInt( initSizeStr);
  244. }
  245. catch (NumberFormatException ex) {
  246. throw new InvalidConfigurationException("Invalid thread pool size value, " + initSizeStr);
  247. }
  248. // Range check the thread pool size
  249. if ( initSize < ThreadRequestPool.MinimumWorkerThreads)
  250. throw new InvalidConfigurationException("Thread pool size below minimum allowed size");
  251. if ( initSize > ThreadRequestPool.MaximumWorkerThreads)
  252. throw new InvalidConfigurationException("Thread pool size above maximum allowed size");
  253. // Get the maximum thread pool size
  254. String maxSizeStr = elem.getAttribute("max");
  255. int maxSize = initSize;
  256. if ( maxSizeStr.length() > 0) {
  257. // Validate the maximum thread pool size
  258. try {
  259. maxSize = Integer.parseInt( maxSizeStr);
  260. }
  261. catch (NumberFormatException ex) {
  262. throw new InvalidConfigurationException(" Invalid thread pool maximum size value, " + maxSizeStr);
  263. }
  264. // Range check the maximum thread pool size
  265. if ( maxSize < ThreadRequestPool.MinimumWorkerThreads)
  266. throw new InvalidConfigurationException("Thread pool maximum size below minimum allowed size");
  267. if ( maxSize > ThreadRequestPool.MaximumWorkerThreads)
  268. throw new InvalidConfigurationException("Thread pool maximum size above maximum allowed size");
  269. if ( maxSize < initSize)
  270. throw new InvalidConfigurationException("Initial size is larger than maxmimum size");
  271. }
  272. else if ( maxSizeStr != null)
  273. throw new InvalidConfigurationException("Thread pool maximum size not specified");
  274. // Configure the thread pool
  275. coreConfig.setThreadPool( initSize, maxSize);
  276. }
  277. else {
  278. // Configure a default thread pool size
  279. coreConfig.setThreadPool( DefaultThreadPoolInit, DefaultThreadPoolMax);
  280. }
  281. // Check if thread pool debug output is enabled
  282. if ( findChildNode("threadPoolDebug", srvCore.getChildNodes()) != null)
  283. coreConfig.getThreadPool().setDebug( true);
  284. // Check if the memory pool configuration has been specified
  285. elem = findChildNode("memoryPool", srvCore.getChildNodes());
  286. if ( elem != null) {
  287. // Check if the packet sizes/allocations have been specified
  288. Element pktElem = findChildNode("packetSizes", elem.getChildNodes());
  289. if ( pktElem != null) {
  290. // Calculate the array size for the packet size/allocation arrays
  291. NodeList nodeList = pktElem.getChildNodes();
  292. int elemCnt = 0;
  293. for ( int i = 0; i < nodeList.getLength(); i++) {
  294. if ( nodeList.item( i).getNodeType() == ELEMENT_TYPE)
  295. elemCnt++;
  296. }
  297. // Create the packet size, initial allocation and maximum allocation arrays
  298. int[] pktSizes = new int[elemCnt];
  299. int[] initSizes = new int[elemCnt];
  300. int[] maxSizes = new int[elemCnt];
  301. int elemIdx = 0;
  302. // Process the packet size elements
  303. for ( int i = 0; i < nodeList.getLength(); i++) {
  304. // Get the current element node
  305. Node curNode = nodeList.item( i);
  306. if ( curNode.getNodeType() == ELEMENT_TYPE) {
  307. // Get the element and check if it is a packet size element
  308. Element curElem = (Element) curNode;
  309. if ( curElem.getNodeName().equals("packet")) {
  310. // Get the packet size
  311. int pktSize = -1;
  312. int initAlloc = -1;
  313. int maxAlloc = -1;
  314. String pktSizeStr = curElem.getAttribute("size");
  315. if ( pktSizeStr == null || pktSizeStr.length() == 0)
  316. throw new InvalidConfigurationException("Memory pool packet size not specified");
  317. // Parse the packet size
  318. try {
  319. pktSize = MemorySize.getByteValueInt( pktSizeStr);
  320. }
  321. catch ( NumberFormatException ex) {
  322. throw new InvalidConfigurationException("Memory pool packet size, invalid size value, " + pktSizeStr);
  323. }
  324. // Make sure the packet sizes have been specified in ascending order
  325. if ( elemIdx > 0 && pktSizes[elemIdx - 1] >= pktSize)
  326. throw new InvalidConfigurationException("Invalid packet size specified, less than/equal to previous packet size");
  327. // Get the initial allocation for the current packet size
  328. String initSizeStr = curElem.getAttribute("init");
  329. if ( initSizeStr == null || initSizeStr.length() == 0)
  330. throw new InvalidConfigurationException("Memory pool initial allocation not specified");
  331. // Parse the initial allocation
  332. try {
  333. initAlloc = Integer.parseInt( initSizeStr);
  334. }
  335. catch (NumberFormatException ex) {
  336. throw new InvalidConfigurationException("Invalid initial allocation, " + initSizeStr);
  337. }
  338. // Range check the initial allocation
  339. if ( initAlloc < MemoryPoolMinimumAllocation)
  340. throw new InvalidConfigurationException("Initial memory pool allocation below minimum of " + MemoryPoolMinimumAllocation);
  341. if ( initAlloc > MemoryPoolMaximumAllocation)
  342. throw new InvalidConfigurationException("Initial memory pool allocation above maximum of " + MemoryPoolMaximumAllocation);
  343. // Get the maximum allocation for the current packet size
  344. String maxSizeStr = curElem.getAttribute("max");
  345. if ( maxSizeStr == null || maxSizeStr.length() == 0)
  346. throw new InvalidConfigurationException("Memory pool maximum allocation not specified");
  347. // Parse the maximum allocation
  348. try {
  349. maxAlloc = Integer.parseInt( maxSizeStr);
  350. }
  351. catch (NumberFormatException ex) {
  352. throw new InvalidConfigurationException("Invalid maximum allocation, " + maxSizeStr);
  353. }
  354. // Range check the maximum allocation
  355. if ( maxAlloc < MemoryPoolMinimumAllocation)
  356. throw new InvalidConfigurationException("Maximum memory pool allocation below minimum of " + MemoryPoolMinimumAllocation);
  357. if ( initAlloc > MemoryPoolMaximumAllocation)
  358. throw new InvalidConfigurationException("Maximum memory pool allocation above maximum of " + MemoryPoolMaximumAllocation);
  359. // Set the current packet size elements
  360. pktSizes[elemIdx] = pktSize;
  361. initSizes[elemIdx] = initAlloc;
  362. maxSizes[elemIdx] = maxAlloc;
  363. elemIdx++;
  364. }
  365. }
  366. }
  367. // Check if all elements were used in the packet size/allocation arrays
  368. if ( elemIdx < pktSizes.length) {
  369. // Re-allocate the packet size/allocation arrays
  370. int[] newPktSizes = new int[elemIdx];
  371. int[] newInitSizes = new int[elemIdx];
  372. int[] newMaxSizes = new int[elemIdx];
  373. // Copy the values to the shorter arrays
  374. System.arraycopy(pktSizes, 0, newPktSizes, 0, elemIdx);
  375. System.arraycopy(initSizes, 0, newInitSizes, 0, elemIdx);
  376. System.arraycopy(maxSizes, 0, newMaxSizes, 0, elemIdx);
  377. // Move the new arrays into place
  378. pktSizes = newPktSizes;
  379. initSizes = newInitSizes;
  380. maxSizes = newMaxSizes;
  381. }
  382. // Configure the memory pool
  383. coreConfig.setMemoryPool( pktSizes, initSizes, maxSizes);
  384. }
  385. }
  386. else {
  387. // Configure a default memory pool
  388. coreConfig.setMemoryPool( DefaultMemoryPoolBufSizes, DefaultMemoryPoolInitAlloc, DefaultMemoryPoolMaxAlloc);
  389. }
  390. }
  391. /**
  392. * Process the global settings XML element
  393. *
  394. * @param global Element
  395. * @exception InvalidConfigurationException
  396. */
  397. protected final void procGlobalElement(Element global)
  398. throws InvalidConfigurationException {
  399. // Create the global configuration section
  400. GlobalConfigSection globalConfig = new GlobalConfigSection(this);
  401. // Check if the global element has been specified
  402. if ( global == null)
  403. return;
  404. // Check if the timezone has been specified
  405. Element elem = findChildNode("timezone", global.getChildNodes());
  406. if ( elem != null) {
  407. // Check for the timezone name
  408. String tzName = elem.getAttribute("name");
  409. if ( tzName != null && tzName.length() > 0)
  410. globalConfig.setTimeZone(tzName);
  411. // Check for the timezone offset value
  412. String tzOffset = elem.getAttribute("offset");
  413. if ( tzOffset != null && tzOffset.length() > 0 && tzName != null && tzName.length() > 0)
  414. throw new InvalidConfigurationException("Specify name or offset for timezone");
  415. // Validate the timezone offset
  416. if ( tzOffset != null && tzOffset.length() > 0) {
  417. int offset = 0;
  418. try {
  419. offset = Integer.parseInt(tzOffset);
  420. }
  421. catch (NumberFormatException ex) {
  422. throw new InvalidConfigurationException("Invalid timezone offset value, " + tzOffset);
  423. }
  424. // Range check the timezone offset value
  425. if ( offset < -1440 || offset > 1440)
  426. throw new InvalidConfigurationException("Invalid timezone offset, value out of valid range, " + tzOffset);
  427. // Set the timezone offset in minutes from UTC
  428. globalConfig.setTimeZoneOffset(offset);
  429. }
  430. }
  431. }
  432. /**
  433. * Process the SMB server XML element
  434. *
  435. * @param smb Element
  436. * @exception InvalidConfigurationException
  437. */
  438. protected final void procSMBServerElement(Element smb)
  439. throws InvalidConfigurationException {
  440. // Check if the SMB element is valid
  441. if ( smb == null)
  442. throw new InvalidConfigurationException("SMB section must be specified");
  443. // Create the CIFS server configuration section
  444. CIFSConfigSection cifsConfig = new CIFSConfigSection(this);
  445. // Process the main SMB server settings
  446. procHostElement(findChildNode("host", smb.getChildNodes()), cifsConfig);
  447. // Debug settings are now specified within the SMB server configuration block
  448. // Check if NetBIOS debug is enabled
  449. Element elem = findChildNode("netbiosDebug", smb.getChildNodes());
  450. if ( elem != null)
  451. cifsConfig.setNetBIOSDebug(true);
  452. // Check if host announcement debug is enabled
  453. elem = findChildNode("announceDebug", smb.getChildNodes());
  454. if ( elem != null)
  455. cifsConfig.setHostAnnounceDebug(true);
  456. // Check if session debug is enabled
  457. elem = findChildNode("sessionDebug", smb.getChildNodes());
  458. if ( elem != null) {
  459. // Check for session debug flags
  460. String flags = elem.getAttribute("flags");
  461. int sessDbg = DEFAULT_SESSDEBUG;
  462. if ( flags != null) {
  463. // Clear the default debug flags
  464. sessDbg = 0;
  465. // Parse the flags
  466. flags = flags.toUpperCase();
  467. StringTokenizer token = new StringTokenizer(flags, ",");
  468. while (token.hasMoreTokens()) {
  469. // Get the current debug flag token
  470. String dbg = token.nextToken().trim();
  471. // Find the debug flag name
  472. int idx = 0;
  473. while (idx < m_sessDbgStr.length && m_sessDbgStr[idx].equalsIgnoreCase(dbg) == false)
  474. idx++;
  475. if ( idx >= m_sessDbgStr.length)
  476. throw new InvalidConfigurationException("Invalid session debug flag, " + dbg);
  477. // Set the debug flag
  478. sessDbg += 1 << idx;
  479. }
  480. }
  481. // Set the session debug flags
  482. cifsConfig.setSessionDebugFlags(sessDbg);
  483. }
  484. // Check if NIO based code should be disabled
  485. if ( findChildNode( "disableNIO", smb.getChildNodes()) != null)
  486. cifsConfig.setDisableNIOCode( true);
  487. // Check if a maximum virtual circuits per session limit has been specified
  488. elem = findChildNode("virtualCircuits", smb.getChildNodes());
  489. if ( elem != null) {
  490. // Parse and validate the maximum virtual circuits value
  491. String maxVCVal = elem.getAttribute( "maxPerSession");
  492. if ( maxVCVal != null && maxVCVal.length() > 0) {
  493. try {
  494. // Parse the value, and range check
  495. int maxVC = Integer.parseInt( maxVCVal);
  496. if ( maxVC < VirtualCircuitList.MinCircuits || maxVC > VirtualCircuitList.MaxCircuits)
  497. throw new InvalidConfigurationException("Maximum virtual circuits value out of range, valid range " + VirtualCircuitList.MinCircuits + " - " +
  498. VirtualCircuitList.MaxCircuits);
  499. // Set the maximum virtual circuits per session
  500. cifsConfig.setMaximumVirtualCircuits( maxVC);
  501. }
  502. catch (NumberFormatException ex) {
  503. throw new InvalidConfigurationException("Invalid maximum virtual circuits value, " + maxVCVal);
  504. }
  505. }
  506. }
  507. // Check if an authenticator has been specified
  508. Element authElem = findChildNode("authenticator", smb.getChildNodes());
  509. if ( authElem != null) {
  510. // Get the authenticator class and security mode
  511. Element classElem = findChildNode("class", authElem.getChildNodes());
  512. String authClass = null;
  513. if ( classElem == null) {
  514. // Check if the authenticator type has been specified
  515. String authType = authElem.getAttribute("type");
  516. if ( authType == null)
  517. throw new InvalidConfigurationException("Authenticator class not specified");
  518. // Check the authenticator type and set the appropriate authenticator class
  519. if ( authType.equalsIgnoreCase("local"))
  520. authClass = "org.alfresco.jlan.server.auth.LocalAuthenticator";
  521. else if ( authType.equalsIgnoreCase("passthru"))
  522. authClass = "org.alfresco.jlan.server.auth.passthru.PassthruAuthenticator";
  523. }
  524. else {
  525. // Set the authenticator class
  526. authClass = getText(classElem);
  527. }
  528. Element modeElem = findChildNode("mode", authElem.getChildNodes());
  529. int accessMode = CifsAuthenticator.USER_MODE;
  530. if ( modeElem != null) {
  531. // Validate the authenticator mode
  532. String mode = getText(modeElem);
  533. if ( mode.equalsIgnoreCase("user"))
  534. accessMode = CifsAuthenticator.USER_MODE;
  535. else if ( mode.equalsIgnoreCase("share"))
  536. accessMode = CifsAuthenticator.SHARE_MODE;
  537. else
  538. throw new InvalidConfigurationException("Invalid authentication mode, must be USER or SHARE");
  539. }
  540. // Get the allow guest setting
  541. Element allowGuest = findChildNode("allowGuest", authElem.getChildNodes());
  542. // Get the parameters for the authenticator class
  543. ConfigElement params = buildConfigElement(authElem);
  544. cifsConfig.setAuthenticator(authClass, params, accessMode, allowGuest != null ? true : false);
  545. }
  546. }
  547. /**
  548. * Process the host XML element
  549. *
  550. * @param host Element 2param cifsConfig CIFSConfigSection
  551. * @exception InvalidConfigurationException
  552. */
  553. protected final void procHostElement(Element host, CIFSConfigSection cifsConfig)
  554. throws InvalidConfigurationException {
  555. // Check if the host element is valid
  556. if ( host == null)
  557. throw new InvalidConfigurationException("Host section must be specified");
  558. // Get the host name attribute
  559. String attr = host.getAttribute("name");
  560. if ( attr == null || attr.length() == 0)
  561. throw new InvalidConfigurationException("Host name not specified or invalid");
  562. cifsConfig.setServerName(attr.toUpperCase());
  563. // If the global server name has not been set then use the CIFS server name
  564. if ( getServerName() == null)
  565. setServerName(cifsConfig.getServerName());
  566. // Get the domain name
  567. attr = host.getAttribute("domain");
  568. if ( attr != null && attr.length() > 0)
  569. cifsConfig.setDomainName(attr.toUpperCase());
  570. // Get the enabled SMB dialects
  571. Element elem = findChildNode("smbdialects", host.getChildNodes());
  572. if ( elem != null) {
  573. // Clear all configured SMB dialects
  574. DialectSelector diaSel = cifsConfig.getEnabledDialects();
  575. diaSel.ClearAll();
  576. // Parse the SMB dilaects list
  577. StringTokenizer token = new StringTokenizer(getText(elem), ",");
  578. while (token.hasMoreTokens()) {
  579. // Get the current SMB dialect token
  580. String dia = token.nextToken().trim();
  581. // Determine the dialect to be enabled
  582. if ( dia.equalsIgnoreCase("CORE")) {
  583. // Enable core dialects
  584. diaSel.AddDialect(Dialect.Core);
  585. diaSel.AddDialect(Dialect.CorePlus);
  586. }
  587. else if ( dia.equalsIgnoreCase("LANMAN")) {
  588. // Enable the LanMAn dialects
  589. diaSel.AddDialect(Dialect.DOSLanMan1);
  590. diaSel.AddDialect(Dialect.DOSLanMan2);
  591. diaSel.AddDialect(Dialect.LanMan1);
  592. diaSel.AddDialect(Dialect.LanMan2);
  593. diaSel.AddDialect(Dialect.LanMan2_1);
  594. }
  595. else if ( dia.equalsIgnoreCase("NT")) {
  596. // Enable the NT dialect
  597. diaSel.AddDialect(Dialect.NT);
  598. }
  599. else
  600. throw new InvalidConfigurationException("Invalid SMB dialect, " + dia);
  601. }
  602. // Set the enabled server SMB dialects
  603. cifsConfig.setEnabledDialects(diaSel);
  604. }
  605. // Check for a server comment
  606. elem = findChildNode("comment", host.getChildNodes());
  607. if ( elem != null)
  608. cifsConfig.setComment(getText(elem));
  609. // Check for a bind address
  610. elem = findChildNode("bindto", host.getChildNodes());
  611. if ( elem != null) {
  612. // Check if the network adapter name has been specified
  613. if ( elem.hasAttribute("adapter")) {
  614. // Get the IP address for the adapter
  615. InetAddress bindAddr = parseAdapterName(elem.getAttribute("adapter"));
  616. // Set the bind address for the server
  617. cifsConfig.setSMBBindAddress(bindAddr);
  618. }
  619. else {
  620. // Validate the bind address
  621. String bindText = getText(elem);
  622. try {
  623. // Check the bind address
  624. InetAddress bindAddr = InetAddress.getByName(bindText);
  625. // Set the bind address for the server
  626. cifsConfig.setSMBBindAddress(bindAddr);
  627. }
  628. catch (UnknownHostException ex) {
  629. throw new InvalidConfigurationException(ex.toString());
  630. }
  631. }
  632. }
  633. // Check if the host announcer should be enabled
  634. elem = findChildNode("hostAnnounce", host.getChildNodes());
  635. if ( elem != null) {
  636. // Check for an announcement interval
  637. attr = elem.getAttribute("interval");
  638. if ( attr != null && attr.length() > 0) {
  639. try {
  640. cifsConfig.setHostAnnounceInterval(Integer.parseInt(attr));
  641. }
  642. catch (NumberFormatException ex) {
  643. throw new InvalidConfigurationException("Invalid host announcement interval");
  644. }
  645. }
  646. // Check if the domain name has been set, this is required if the host announcer is
  647. // enabled
  648. if ( cifsConfig.getDomainName() == null)
  649. throw new InvalidConfigurationException("Domain name must be specified if host announcement is enabled");
  650. // Enable host announcement
  651. cifsConfig.setHostAnnouncer(true);
  652. }
  653. // Check for a host announcer port
  654. elem = findChildNode("HostAnnouncerPort", host.getChildNodes());
  655. if ( elem != null) {
  656. try {
  657. cifsConfig.setHostAnnouncerPort(Integer.parseInt(getText(elem)));
  658. if ( cifsConfig.getHostAnnouncerPort() <= 0 || cifsConfig.getHostAnnouncerPort() >= 65535)
  659. throw new InvalidConfigurationException("Host announcer port out of valid range");
  660. }
  661. catch (NumberFormatException ex) {
  662. throw new InvalidConfigurationException("Invalid host announcer port");
  663. }
  664. }
  665. // Check if NetBIOS SMB is enabled
  666. elem = findChildNode("netBIOSSMB", host.getChildNodes());
  667. if ( elem != null) {
  668. // Check if NetBIOS over TCP/IP is enabled for the current platform
  669. boolean platformOK = false;
  670. if ( elem.hasAttribute("platforms")) {
  671. // Get the list of platforms
  672. String platformsStr = elem.getAttribute("platforms");
  673. // Parse the list of platforms that NetBIOS over TCP/IP is to be enabled for and
  674. // check if the current platform is included
  675. List<Platform.Type> enabledPlatforms = parsePlatformString(platformsStr);
  676. if ( enabledPlatforms.contains(getPlatformType()))
  677. platformOK = true;
  678. }
  679. else {
  680. // No restriction on platforms
  681. platformOK = true;
  682. }
  683. // Enable the NetBIOS SMB support
  684. cifsConfig.setNetBIOSSMB(platformOK);
  685. // Only parse the other settings if NetBIOS based SMB is enabled for the current
  686. // platform
  687. if ( platformOK) {
  688. // Check for the session port
  689. attr = elem.getAttribute("sessionPort");
  690. if ( attr != null && attr.length() > 0) {
  691. try {
  692. cifsConfig.setSessionPort(Integer.parseInt(attr));
  693. if ( cifsConfig.getSessionPort() <= 0 || cifsConfig.getSessionPort() >= 65535)
  694. throw new InvalidConfigurationException("NetBIOS SMB session port out of valid range");
  695. }
  696. catch (NumberFormatException ex) {
  697. throw new InvalidConfigurationException("Invalid NetBIOS SMB session port");
  698. }
  699. }
  700. // Check for the datagram port
  701. attr = elem.getAttribute("datagramPort");
  702. if ( attr != null && attr.length() > 0) {
  703. try {
  704. cifsConfig.setDatagramPort(Integer.parseInt(attr));
  705. if ( cifsConfig.getDatagramPort() <= 0 || cifsConfig.getDatagramPort() >= 65535)
  706. throw new InvalidConfigurationException("NetBIOS SMB datagram port out of valid range");
  707. }
  708. catch (NumberFormatException ex) {
  709. throw new InvalidConfigurationException("Invalid NetBIOS SMB datagram port");
  710. }
  711. }
  712. // Check for the name server port
  713. attr = elem.getAttribute("namingPort");
  714. if ( attr != null && attr.length() > 0) {
  715. try {
  716. cifsConfig.setNameServerPort(Integer.parseInt(attr));
  717. if ( cifsConfig.getNameServerPort() <= 0 || cifsConfig.getNameServerPort() >= 65535)
  718. throw new InvalidConfigurationException("NetBIOS SMB naming port out of valid range");
  719. }
  720. catch (NumberFormatException ex) {
  721. throw new InvalidConfigurationException("Invalid NetBIOS SMB naming port");
  722. }
  723. }
  724. // Check for a bind address
  725. attr = elem.getAttribute("bindto");
  726. if ( attr != null && attr.length() > 0) {
  727. // Validate the bind address
  728. try {
  729. // Check the bind address
  730. InetAddress bindAddr = InetAddress.getByName(attr);
  731. // Set the bind address for the NetBIOS name server
  732. cifsConfig.setNetBIOSBindAddress(bindAddr);
  733. }
  734. catch (UnknownHostException ex) {
  735. throw new InvalidConfigurationException(ex.toString());
  736. }
  737. }
  738. // Check for a bind address using the adapter name
  739. else if ( elem.hasAttribute("adapter")) {
  740. // Get the bind address via the network adapter name
  741. InetAddress bindAddr = parseAdapterName(elem.getAttribute("adapter"));
  742. cifsConfig.setNetBIOSBindAddress(bindAddr);
  743. }
  744. else if ( cifsConfig.hasSMBBindAddress()) {
  745. // Use the SMB bind address for the NetBIOS name server
  746. cifsConfig.setNetBIOSBindAddress(cifsConfig.getSMBBindAddress());
  747. }
  748. }
  749. }
  750. else {
  751. // Disable NetBIOS SMB support
  752. cifsConfig.setNetBIOSSMB(false);
  753. }
  754. // Check if TCP/IP SMB is enabled
  755. elem = findChildNode("tcpipSMB", host.getChildNodes());
  756. if ( elem != null) {
  757. // Check if native SMB is enabled for the current platform
  758. boolean platformOK = false;
  759. if ( elem.hasAttribute("platforms")) {
  760. // Get the list of platforms
  761. String platformsStr = elem.getAttribute("platforms");
  762. // Parse the list of platforms that NetBIOS over TCP/IP is to be enabled for and
  763. // check if the current platform is included
  764. List<Platform.Type> enabledPlatforms = parsePlatformString(platformsStr);
  765. if ( enabledPlatforms.contains(getPlatformType()))
  766. platformOK = true;
  767. }
  768. else {
  769. // No restriction on platforms
  770. platformOK = true;
  771. }
  772. // Enable the TCP/IP SMB support
  773. cifsConfig.setTcpipSMB(platformOK);
  774. // Check if the port has been specified
  775. attr = elem.getAttribute("port");
  776. if ( attr != null && attr.length() > 0) {
  777. try {
  778. cifsConfig.setTcpipSMBPort(Integer.parseInt(attr));
  779. if ( cifsConfig.getTcpipSMBPort() <= 0 || cifsConfig.getTcpipSMBPort() >= 65535)
  780. throw new InvalidConfigurationException("TCP/IP SMB port out of valid range");
  781. }
  782. catch (NumberFormatException ex) {
  783. throw new InvalidConfigurationException("Invalid TCP/IP SMB port");
  784. }
  785. }
  786. }
  787. else {
  788. // Disable TCP/IP SMB support
  789. cifsConfig.setTcpipSMB(false);
  790. }
  791. // Check that the broadcast mask has been set if TCP/IP NetBIOS and/or the host announcer is
  792. // enabled
  793. if ( cifsConfig.hasNetBIOSSMB() || cifsConfig.hasEnableAnnouncer()) {
  794. // Parse the broadcast mask
  795. elem = findChildNode("broadcast", host.getChildNodes());
  796. if ( elem != null) {
  797. // Check if the broadcast mask is a valid numeric IP address
  798. if ( IPAddress.isNumericAddress(getText(elem)) == false)
  799. throw new InvalidConfigurationException("Invalid broadcast mask, must be n.n.n.n format");
  800. // Set the network broadcast mask
  801. cifsConfig.setBroadcastMask(getText(elem));
  802. }
  803. else {
  804. // Broadcast mask not configured
  805. throw new InvalidConfigurationException("Network broadcast mask not specified");
  806. }
  807. }
  808. // Check if Win32 NetBIOS is enabled
  809. elem = findChildNode("Win32NetBIOS", host.getChildNodes());
  810. if ( elem != null) {
  811. // Check if the Win32 NetBIOS server name has been specified
  812. attr = elem.getAttribute("name");
  813. if ( attr != null && attr.length() > 0) {
  814. // Validate the name
  815. if ( attr.length() > 16)
  816. throw new InvalidConfigurationException("Invalid Win32 NetBIOS name, " + attr);
  817. // Set the Win32 NetBIOS file server name
  818. cifsConfig.setWin32NetBIOSName(attr);
  819. }
  820. // Check if the Win32 NetBIOS client accept name has been specified
  821. attr = elem.getAttribute("accept");
  822. if ( attr != null && attr.length() > 0) {
  823. // Validate the client accept name
  824. if ( attr.length() > 15)
  825. throw new InvalidConfigurationException("Invalid Win32 NetBIOS accept name, " + attr);
  826. // Set the client accept string
  827. cifsConfig.setWin32NetBIOSClientAccept(attr);
  828. }
  829. // Check if the Win32 NetBIOS LANA has been specified
  830. attr = elem.getAttribute("lana");
  831. if ( attr != null && attr.length() > 0) {
  832. // Check if the LANA has been specified as an IP address or adapter name
  833. int lana = -1;
  834. if ( IPAddress.isNumericAddress(attr)) {
  835. // Convert the IP address to a LANA id
  836. lana = Win32NetBIOS.getLANAForIPAddress(attr);
  837. if ( lana == -1)
  838. throw new InvalidConfigurationException("Failed to convert IP address " + attr + " to a LANA");
  839. }
  840. else if ( attr.length() > 1 && Character.isLetter(attr.charAt(0))) {
  841. // Convert the network adapter to a LANA id
  842. lana = Win32NetBIOS.getLANAForAdapterName(attr);
  843. if ( lana == -1)
  844. throw new InvalidConfigurationException("Failed to convert network adapter " + attr + " to a LANA");
  845. }
  846. else {
  847. // Validate the LANA number
  848. try {
  849. lana = Integer.parseInt(attr);
  850. }
  851. catch (NumberFormatException ex) {
  852. throw new InvalidConfigurationException("Invalid Win32 NetBIOS LANA specified");
  853. }
  854. // LANA should be in the range 0-255
  855. if ( lana < 0 || lana > 255)
  856. throw new InvalidConfigurationException("Invalid Win32 NetBIOS LANA number, " + lana);
  857. }
  858. // Set the LANA number
  859. cifsConfig.setWin32LANA(lana);
  860. }
  861. // Check if the native NetBIOS interface has been specified, either 'winsock' or
  862. // 'netbios'
  863. attr = elem.getAttribute("api");
  864. if ( attr != null && attr.length() > 0) {
  865. // Validate the API type
  866. boolean useWinsock = true;
  867. if ( attr.equalsIgnoreCase("netbios"))
  868. useWinsock = false;
  869. else if ( attr.equalsIgnoreCase("winsock") == false)
  870. throw new InvalidConfigurationException("Invalid NetBIOS API type, spefify 'winsock' or 'netbios'");
  871. // Set the NetBIOS API to use
  872. cifsConfig.setWin32WinsockNetBIOS(useWinsock);
  873. }
  874. // Force the older NetBIOS API code to be used on 64Bit Windows as Winsock NetBIOS is
  875. // not available
  876. if ( cifsConfig.useWinsockNetBIOS() == true && X64.isWindows64()) {
  877. // Log a warning
  878. Debug.println("Using older Netbios() API code, Winsock NetBIOS not available on x64");
  879. // Use the older NetBIOS API code
  880. cifsConfig.setWin32WinsockNetBIOS(false);
  881. }
  882. // Check if the current operating system is supported by the Win32 NetBIOS handler
  883. String osName = System.getProperty("os.name");
  884. if ( osName.startsWith("Windows")
  885. && (osName.endsWith("95") == false && osName.endsWith("98") == false && osName.endsWith("ME") == false)) {
  886. // Enable Win32 NetBIOS
  887. cifsConfig.setWin32NetBIOS(true);
  888. }
  889. else {
  890. // Win32 NetBIOS not supported on the current operating system
  891. cifsConfig.setWin32NetBIOS(false);
  892. }
  893. }
  894. else {
  895. // Disable Win32 NetBIOS
  896. cifsConfig.setWin32NetBIOS(false);
  897. }
  898. // Check if the host announcer should be enabled
  899. elem = findChildNode("Win32Announce", host.getChildNodes());
  900. if ( elem != null) {
  901. // Check for an announcement interval
  902. attr = elem.getAttribute("interval");
  903. if ( attr != null && attr.length() > 0) {
  904. try {
  905. cifsConfig.setWin32HostAnnounceInterval(Integer.parseInt(attr));
  906. }
  907. catch (NumberFormatException ex) {
  908. throw new InvalidConfigurationException("Invalid host announcement interval");
  909. }
  910. }
  911. // Check if the domain name has been set, this is required if the host announcer is
  912. // enabled
  913. if ( cifsConfig.getDomainName() == null)
  914. throw new InvalidConfigurationException("Domain name must be specified if host announcement is enabled");
  915. // Enable Win32 NetBIOS host announcement
  916. cifsConfig.setWin32HostAnnouncer(true);
  917. }
  918. // Check if NetBIOS and/or TCP/IP SMB have been enabled
  919. if ( cifsConfig.hasNetBIOSSMB() == false && cifsConfig.hasTcpipSMB() == false && cifsConfig.hasWin32NetBIOS() == false)
  920. throw new InvalidConfigurationException("NetBIOS SMB, TCP/IP SMB or Win32 NetBIOS must be enabled");
  921. // Check if server alias name(s) have been specified
  922. elem = findChildNode("alias", host.getChildNodes());
  923. if ( elem != null) {
  924. // Get the alias name list
  925. attr = elem.getAttribute("names");
  926. if ( attr == null || attr.length() == 0)
  927. throw new InvalidConfigurationException("Alias name(s) not specified");
  928. // Split the alias name list
  929. StringList names = new StringList();
  930. StringTokenizer nameTokens = new StringTokenizer(attr, ",");
  931. while (nameTokens.hasMoreTokens()) {
  932. // Get the current alias name
  933. String alias = nameTokens.nextToken().trim().toUpperCase();
  934. // Check if the name already exists in the alias list, or matches the main server
  935. // name
  936. if ( alias.equalsIgnoreCase(getServerName()))
  937. throw new InvalidConfigurationException("Alias is the same as the main server name");
  938. else if ( names.containsString(alias))
  939. throw new InvalidConfigurationException("Same alias specified twice, " + alias);
  940. else
  941. names.addString(alias);
  942. }
  943. // Set the server alias names
  944. cifsConfig.addAliasNames(names);
  945. }
  946. // Check if Macintosh extension SMBs should be enabled
  947. elem = findChildNode("macExtensions", host.getChildNodes());
  948. if ( elem != null) {
  949. // Enable Macintosh extension SMBs
  950. cifsConfig.setMacintoshExtensions(true);
  951. }
  952. // Check if WINS servers are configured
  953. elem = findChildNode("WINS", host.getChildNodes());
  954. if ( elem != null) {
  955. // Get the primary WINS server
  956. Element winsSrv = findChildNode("primary", elem.getChildNodes());
  957. if ( winsSrv == null)
  958. throw new InvalidConfigurationException("No primary WINS server configured");
  959. // Validate the WINS server address
  960. InetAddress primaryWINS = null;
  961. try {
  962. primaryWINS = InetAddress.getByName(getText(winsSrv));
  963. }
  964. catch (UnknownHostException ex) {
  965. throw new InvalidConfigurationException("Invalid primary WINS server address, " + winsSrv.getNodeValue());
  966. }
  967. // Check if a secondary WINS server has been specified
  968. winsSrv = findChildNode("secondary", elem.getChildNodes());
  969. InetAddress secondaryWINS = null;
  970. if ( winsSrv != null) {
  971. // Validate the secondary WINS server address
  972. try {
  973. secondaryWINS = InetAddress.getByName(getText(winsSrv));
  974. }
  975. catch (UnknownHostException ex) {
  976. throw new InvalidConfigurationException("Invalid secondary WINS server address, " + winsSrv.getNodeValue());
  977. }
  978. }
  979. // Set the WINS server address(es)
  980. cifsConfig.setPrimaryWINSServer(primaryWINS);
  981. if ( secondaryWINS != null)
  982. cifsConfig.setSecondaryWINSServer(secondaryWINS);
  983. }
  984. // Check if a session timeout is configured
  985. elem = findChildNode("sessionTimeout", host.getChildNodes());
  986. if ( elem != null) {
  987. // Validate the session timeout value
  988. String sessTmo = getText( elem);
  989. if ( sessTmo != null && sessTmo.length() > 0) {
  990. try {
  991. // Convert the timeout value to milliseconds
  992. int tmo = Integer.parseInt(sessTmo);
  993. if ( tmo < 0 || tmo > MaxSessionTimeout)
  994. throw new InvalidConfigurationException("Session timeout out of range (0 - " + MaxSessionTimeout + ")");
  995. // Convert the session timeout to milliseconds
  996. cifsConfig.setSocketTimeout( tmo * 1000);
  997. }
  998. catch (NumberFormatException ex) {
  999. throw new InvalidConfigurationException("Invalid session timeout value, " + sessTmo);
  1000. }
  1001. }
  1002. else
  1003. throw new InvalidConfigurationException("Session timeout value not specified");
  1004. }
  1005. }
  1006. /**
  1007. * Process the debug XML element
  1008. *
  1009. * @param debug Element
  1010. * @exception InvalidConfigurationException
  1011. */
  1012. protected final void procDebugElement(Element debug)
  1013. throws InvalidConfigurationException {
  1014. // Check if the debug section has been specified
  1015. if ( debug == null)
  1016. return;
  1017. // Create the debug configuration section
  1018. DebugConfigSection debugConfig = new DebugConfigSection(this);
  1019. // Get the debug output class and parameters
  1020. Element elem = findChildNode("output", debug.getChildNodes());
  1021. if ( elem == null)
  1022. throw new InvalidConfigurationException("Output class must be specified to enable debug output");
  1023. // Get the debug output class
  1024. Element debugClass = findChildNode("class", elem.getChildNodes());
  1025. if ( debugClass == null)
  1026. throw new InvalidConfigurationException("Class must be specified for debug output");
  1027. // Get the parameters for the debug class
  1028. ConfigElement params = buildConfigElement(elem);
  1029. debugConfig.setDebug(getText(debugClass), params);
  1030. }
  1031. /**
  1032. * Process the shares XML element
  1033. *
  1034. * @param shares Element
  1035. * @exception InvalidConfigurationException
  1036. */
  1037. protected final void procSharesElement(Element shares)
  1038. throws InvalidConfigurationException {
  1039. // Check if the shares element is valid
  1040. if ( shares == null)
  1041. return;
  1042. // Create the filesystems configuration section
  1043. FilesystemsConfigSection filesysConfig = new FilesystemsConfigSection(this);
  1044. // Iterate the child elements
  1045. NodeList children = shares.getChildNodes();
  1046. if ( children != null) {
  1047. // Iterate the child elements and process the disk/print share elements
  1048. for (int i = 0; i < children.getLength(); i++) {
  1049. // Get the current child node
  1050. Node node = children.item(i);
  1051. if ( node.getNodeType() == ELEMENT_TYPE) {
  1052. // Get the next element from the list
  1053. Element child = (Element) node;
  1054. // Check if this is a disk or print share element
  1055. if ( child.getNodeName().equalsIgnoreCase("diskshare"))
  1056. addDiskShare(child, filesysConfig);
  1057. }
  1058. }
  1059. }
  1060. }
  1061. /**
  1062. * Process the security XML element
  1063. *
  1064. * @param security Element
  1065. * @exception InvalidConfigurationException
  1066. */
  1067. protected final void procSecurityElement(Element security)
  1068. throws InvalidConfigurationException {
  1069. // Check if the security element is valid
  1070. if ( security == null)
  1071. return;
  1072. // Create the security configuration section
  1073. SecurityConfigSection secConfig = new SecurityConfigSection(this);
  1074. // Check if an access control manager has been specified
  1075. Element aclElem = findChildNode("accessControlManager", security.getChildNodes());
  1076. if ( aclElem != null) {
  1077. // Get the access control manager class and security mode
  1078. Element classElem = findChildNode("class", aclElem.getChildNodes());
  1079. if ( classElem == null)
  1080. throw new InvalidConfigurationException("Access control manager class not specified");
  1081. // Get the parameters for the access control manager class
  1082. ConfigElement params = buildConfigElement(aclElem);
  1083. secConfig.setAccessControlManager(getText(classElem), params);
  1084. }
  1085. else {
  1086. // Use the default access control manager
  1087. secConfig.setAccessControlManager("org.alfresco.jlan.server.auth.acl.DefaultAccessControlManager",
  1088. new GenericConfigElement("aclManager"));
  1089. }
  1090. // Check if global access controls have been specified
  1091. Element globalACLs = findChildNode("globalAccessControl", security.getChildNodes());
  1092. if ( globalACLs != null) {
  1093. // Parse the access control list
  1094. AccessControlList acls = procAccessControlElement(globalACLs, secConfig);
  1095. if ( acls != null)
  1096. secConfig.setGlobalAccessControls(acls);
  1097. }
  1098. // Check if a JCE provider class has been specified
  1099. Element jceElem = findChildNode("JCEProvider", security.getChildNodes());
  1100. if ( jceElem != null) {
  1101. // Set the JCE provider
  1102. secConfig.setJCEProvider(getText(jceElem));
  1103. }
  1104. // Add the users
  1105. Element usersElem = findChildNode("users", security.getChildNodes());
  1106. if ( usersElem != null) {
  1107. // Get the list of user elements
  1108. NodeList userList = usersElem.getChildNodes();
  1109. for (int i = 0; i < userList.getLength(); i++) {
  1110. // Get the current user node
  1111. Node node = userList.item(i);
  1112. if ( node.getNodeType() == ELEMENT_TYPE) {
  1113. Element userElem = (Element) node;
  1114. addUser(userElem, secConfig);
  1115. }
  1116. }
  1117. }
  1118. // Check if a share mapper has been specified
  1119. Element mapper = findChildNode("shareMapper", security.getChildNodes());
  1120. if ( mapper != null) {
  1121. // Get the share mapper class
  1122. Element classElem = findChildNode("class", mapper.getChildNodes());
  1123. if ( classElem == null)
  1124. throw new InvalidConfigurationException("Share mapper class not specified");
  1125. // Get the parameters for the share mapper class
  1126. ConfigElement params = buildConfigElement(mapper);
  1127. secConfig.setShareMapper(getText(classElem), params);
  1128. }
  1129. // Check if the users interface has been specified
  1130. Element usersIface = findChildNode("usersInterface", security.getChildNodes());
  1131. if ( usersIface != null) {
  1132. // Get the users interface class
  1133. Element classElem = findChildNode("class", usersIface.getChildNodes());
  1134. if ( classElem == null)
  1135. throw new InvalidConfigurationException("Users interface class not specified");
  1136. // Get the parameters for the users interface class
  1137. ConfigElement params = buildConfigElement(usersIface);
  1138. secConfig.setUsersInterface(getText(classElem), params);
  1139. }
  1140. }
  1141. /**
  1142. * Process the drive mappings XML element
  1143. *
  1144. * @param mappings Element
  1145. * @exception InvalidConfigurationException
  1146. */
  1147. protected final void procDriveMappingsElement(Element mappings)
  1148. throws InvalidConfigurationException {
  1149. // Check if the drive mappings element is valid
  1150. if ( mappings == null)
  1151. return;
  1152. // Create the drive mappings configuration section
  1153. DriveMappingsConfigSection mapConfig = new DriveMappingsConfigSection(this);
  1154. // Parse each drive mapping element
  1155. NodeList mapElems = mappings.getChildNodes();
  1156. DriveMappingList mapList = null;
  1157. if ( mapElems != null && mapElems.getLength() > 0) {
  1158. // Create the mapped drive list
  1159. mapList = new DriveMappingList();
  1160. // Access the CIFS server configuration
  1161. CIFSConfigSection cifsConfig = (CIFSConfigSection) getConfigSection(CIFSConfigSection.SectionName);
  1162. // Get a list of the available shares
  1163. SecurityConfigSection secConfig = (SecurityConfigSection) getConfigSection(SecurityConfigSection.SectionName);
  1164. SharedDeviceList shareList = secConfig.getShareMapper().getShareList(getServerName(), null, false);
  1165. // Process each drive mapping element
  1166. for (int i = 0; i < mapElems.getLength(); i++) {
  1167. // Get the current mapped drive details
  1168. Node node = mapElems.item(i);
  1169. if ( node.getNodeType() == ELEMENT_TYPE) {
  1170. // Access the mapped drive element
  1171. Element elem = (Element) node;
  1172. if ( elem.getNodeName().equals("mapDrive")) {
  1173. // Get the mapped drive local drive and remote path details
  1174. String localPath = elem.getAttribute("drive").toUpperCase();
  1175. String shareName = elem.getAttribute("share");
  1176. // Check the local path string
  1177. if ( localPath.length() != 2)
  1178. throw new InvalidConfigurationException("Invalid local drive specified, " + localPath);
  1179. if ( localPath.charAt(1) != ':' || _driveLetters.indexOf(localPath.charAt(0)) == -1)
  1180. throw new InvalidConfigurationException("Invalid local drive specified, " + localPath);
  1181. // Check if the share name is a valid local disk share
  1182. if ( shareName.length() == 0)
  1183. throw new InvalidConfigurationException("Empty share name for mapped drive, " + localPath);
  1184. if ( shareList.findShare(shareName, ShareType.DISK, true) == null)
  1185. throw new InvalidConfigurationException("Mapped drive share " + shareName + " does not exist");
  1186. // Get the username/password to be used to connect the mapped drive
  1187. String userName = null;
  1188. String password = null;
  1189. if ( elem.hasAttribute("username"))
  1190. userName = elem.getAttribute("username");
  1191. if ( elem.hasAttribute("password"))
  1192. password = elem.getAttribute("password");
  1193. // Get the options flags
  1194. boolean interact = false;
  1195. boolean prompt = false;
  1196. if ( elem.hasAttribute("interactive")) {
  1197. if ( elem.getAttribute("interactive").equalsIgnoreCase("YES"))
  1198. interact = true;
  1199. }
  1200. if ( elem.hasAttribute("prompt")) {
  1201. if ( elem.getAttribute("prompt").equalsIgnoreCase("YES"))
  1202. prompt = true;
  1203. }
  1204. // Build the remote path
  1205. StringBuffer remPath = new StringBuffer();
  1206. remPath.append("\\\\");
  1207. if ( cifsConfig.hasWin32NetBIOS() && cifsConfig.getWin32ServerName() != null)
  1208. remPath.append(cifsConfig.getWin32ServerName());
  1209. else
  1210. remPath.append(getServerName());
  1211. remPath.append("\\");
  1212. remPath.append(shareName.toUpperCase());
  1213. // Add a drive mapping
  1214. mapList.addMapping(new DriveMapping(localPath, remPath.toString(), userName, password, interact, prompt));
  1215. }
  1216. }
  1217. }
  1218. // Set the mapped drive list
  1219. mapConfig.setMappedDrives(mapList);
  1220. }
  1221. }
  1222. /**
  1223. * Process an access control sub-section and return the access control list
  1224. *
  1225. * @param acl Element
  1226. * @param secConfig SecutiryConfigSection
  1227. * @throws InvalidConfigurationException
  1228. */
  1229. protected final AccessControlList procAccessControlElement(Element acl, SecurityConfigSection secConfig)
  1230. throws InvalidConfigurationException {
  1231. // Check if there is an access control manager configured
  1232. if ( secConfig.getAccessControlManager() == null)
  1233. throw new InvalidConfigurationException("No access control manager configured");
  1234. // Create the access control list
  1235. AccessControlList acls = new AccessControlList();
  1236. // Check if there is a default access level for the ACL group
  1237. String attrib = acl.getAttribute("default");
  1238. if ( attrib != null && attrib.length() > 0) {
  1239. // Get the access level and validate
  1240. try {
  1241. // Parse the access level name
  1242. int access = AccessControlParser.parseAccessTypeString(attrib);
  1243. // Set the default access level for the access control list
  1244. acls.setDefaultAccessLevel(access);
  1245. }
  1246. catch (InvalidACLTypeException ex) {
  1247. throw new InvalidConfigurationException("Default access level error, " + ex.toString());
  1248. }
  1249. catch (ACLParseException ex) {
  1250. throw new InvalidConfigurationException("Default access level error, " + ex.toString());
  1251. }
  1252. }
  1253. // Parse each access control element and create the required access control
  1254. NodeList aclElems = acl.getChildNodes();
  1255. if ( aclElems != null && aclElems.getLength() > 0) {
  1256. // Create the access controls
  1257. GenericConfigElement params = null;
  1258. String type = null;
  1259. for (int i = 0; i < aclElems.getLength(); i++) {
  1260. // Get the current ACL details
  1261. Node node = aclElems.item(i);
  1262. if ( node.getNodeType() == ELEMENT_TYPE) {
  1263. // Access the ACL element
  1264. Element elem = (Element) node;
  1265. type = elem.getNodeName();
  1266. // Create a new config element
  1267. params = new GenericConfigElement("acl");
  1268. // Convert the element attributes into a list of name value pairs
  1269. NamedNodeMap attrs = elem.getAttributes();
  1270. if ( attrs == null || attrs.getLength() == 0)
  1271. throw new InvalidConfigurationException("Missing attribute(s) for access control " + type);
  1272. for (int j = 0; j < attrs.getLength(); j++) {
  1273. // Create a name/value pair from the current attribute and add to the
  1274. // parameter list
  1275. Node attr = attrs.item(j);
  1276. params.addAttribute( attr.getNodeName(), attr.getNodeValue());
  1277. }
  1278. try {
  1279. // Create the access control and add to the list
  1280. acls.addControl(secConfig.getAccessControlManager().createAccessControl(type, params));
  1281. }
  1282. catch (InvalidACLTypeException ex) {
  1283. throw new InvalidConfigurationException("Invalid access control type - " + type);
  1284. }
  1285. catch (ACLParseException ex) {
  1286. throw new InvalidConfigurationException("Access control parse error (" + type + "), " + ex.toString());
  1287. }
  1288. }
  1289. }
  1290. }
  1291. // Check if there are no access control rules but the default access level is set to 'None',
  1292. // this is not allowed
  1293. // as the share would not be accessible or visible.
  1294. if ( acls.getDefaultAccessLevel() == AccessControl.NoAccess && acls.numberOfControls() == 0)
  1295. throw new InvalidConfigurationException("Empty access control list and default access 'None' not allowed");
  1296. // Return the access control list
  1297. return acls;
  1298. }
  1299. /**
  1300. * Add a user
  1301. *
  1302. * @param user Element
  1303. * @param secConfig SecurityConfigSection
  1304. * @exception InvalidConfigurationException
  1305. */
  1306. protected final void addUser(Element user, SecurityConfigSection secConfig)
  1307. throws InvalidConfigurationException {
  1308. // Get the username
  1309. String attr = user.getAttribute("name");
  1310. if ( attr == null || attr.length() == 0)
  1311. throw new InvalidConfigurationException("User name not specified, or zero length");
  1312. // Check if the user already exists
  1313. String userName = attr;
  1314. if ( secConfig.hasUserAccounts() && secConfig.getUserAccounts().findUser(userName) != null)
  1315. throw new InvalidConfigurationException("User " + userName + " already defined");
  1316. // Get the MD4 hashed password
  1317. byte[] md4 = null;
  1318. String password = null;
  1319. Element elem = findChildNode("md4", user.getChildNodes());
  1320. if ( elem != null) {
  1321. // Get the MD4 hashed password string
  1322. String md4Str = getText(elem);
  1323. if ( md4Str == null || md4Str.length() != 32)
  1324. throw new InvalidConfigurationException("Invalid MD4 hashed password for user " + userName);
  1325. // Decode the MD4 string
  1326. md4 = new byte[16];
  1327. for (int i = 0; i < 16; i++) {
  1328. // Get a hex pair and convert
  1329. String hexPair = md4Str.substring(i * 2, (i * 2) + 2);
  1330. md4[i] = (byte) Integer.parseInt(hexPair, 16);
  1331. }
  1332. }
  1333. else {
  1334. // Get the password for the account
  1335. elem = findChildNode("password", user.getChildNodes());
  1336. if ( elem == null)
  1337. throw new InvalidConfigurationException("No password specified for user " + userName);
  1338. // Get the plaintext password
  1339. password = getText(elem);
  1340. }
  1341. // Create the user account
  1342. UserAccount userAcc = new UserAccount(userName, password);
  1343. userAcc.setMD4Password(md4);
  1344. // Check if the user in an administrator
  1345. elem = findChildNode("administrator", user.getChildNodes());
  1346. if ( elem != null)
  1347. userAcc.setAdministrator(true);
  1348. // Get the real user name and comment
  1349. elem = findChildNode("realname", user.getChildNodes());
  1350. if ( elem != null)
  1351. userAcc.setRealName(getText(elem));
  1352. elem = findChildNode("comment", user.getChildNodes());
  1353. if ( elem != null)
  1354. userAcc.setComment(getText(elem));
  1355. // Get the home directory
  1356. elem = findChildNode("home", user.getChildNodes());
  1357. if ( elem != null)
  1358. userAcc.setHomeDirectory(getText(elem));
  1359. // Add the user account
  1360. UserAccountList accList = secConfig.getUserAccounts();
  1361. if ( accList == null)
  1362. secConfig.setUserAccounts(new UserAccountList());
  1363. secConfig.getUserAccounts().addUser(userAcc);
  1364. }
  1365. /**
  1366. * Add a disk share
  1367. *
  1368. * @param disk Element 2param filesysConfig FilesystemConfigSection
  1369. * @exception InvalidConfigurationException
  1370. */
  1371. protected final void addDiskShare(Element disk, FilesystemsConfigSection filesysConfig)
  1372. throws InvalidConfigurationException {
  1373. // Get the share name and comment attributes
  1374. String attr = disk.getAttribute("name");
  1375. if ( attr == null || attr.length() == 0)
  1376. throw new InvalidConfigurationException("Disk share name must be specified");
  1377. String name = attr;
  1378. String comment = null;
  1379. attr = disk.getAttribute("comment");
  1380. if ( attr != null && attr.length() > 0)
  1381. comment = attr;
  1382. // Get the disk driver details
  1383. Element driverElem = findChildNode("driver", disk.getChildNodes());
  1384. if ( driverElem == null)
  1385. throw new InvalidConfigurationException("No driver specified for disk share " + name);
  1386. Element classElem = findChildNode("class", driverElem.getChildNodes());
  1387. if ( classElem == null || getText(classElem).length() == 0)
  1388. throw new InvalidConfigurationException("No driver class specified for disk share " + name);
  1389. // Get the security configuration section
  1390. SecurityConfigSection secConfig = (SecurityConfigSection) getConfigSection(SecurityConfigSection.SectionName);
  1391. // Check if an access control list has been specified
  1392. AccessControlList acls = null;
  1393. Element aclElem = findChildNode("accessControl", disk.getChildNodes());
  1394. if ( aclElem != null) {
  1395. // Parse the access control list
  1396. acls = procAccessControlElement(aclElem, secConfig);
  1397. }
  1398. else {
  1399. // Use the global access control list for this disk share
  1400. acls = secConfig.getGlobalAccessControls();
  1401. }
  1402. // Get the parameters for the driver
  1403. ConfigElement params = buildConfigElement(driverElem);
  1404. // Check if change notification should be disabled for this device
  1405. boolean changeNotify = findChildNode("disableChangeNotification", disk.getChildNodes()) != null ? false : true;
  1406. // Check if the volume information has been specified
  1407. Element volElem = findChildNode("volume", disk.getChildNodes());
  1408. VolumeInfo volInfo = null;
  1409. if ( volElem != null) {
  1410. // Create the volume information
  1411. volInfo = new VolumeInfo("");
  1412. // Get the volume label
  1413. attr = volElem.getAttribute("label");
  1414. if ( attr != null && attr.length() > 0)
  1415. volInfo.setVolumeLabel(attr);
  1416. // Get the serial number
  1417. attr = volElem.getAttribute("serial");
  1418. if ( attr != null && attr.length() > 0) {
  1419. try {
  1420. volInfo.setSerialNumber(Integer.parseInt(attr));
  1421. }
  1422. catch (NumberFormatException ex) {
  1423. throw new InvalidConfigurationException("Volume serial number invalid, " + attr);
  1424. }
  1425. }
  1426. // Get the creation date/time
  1427. attr = volElem.getAttribute("created");
  1428. if ( attr != null && attr.length() > 0) {
  1429. try {
  1430. volInfo.setCreationDateTime(m_dateFmt.parse(attr));
  1431. }
  1432. catch (ParseException ex) {
  1433. throw new InvalidConfigurationException("Volume creation date/time invalid, " + attr);
  1434. }
  1435. }
  1436. }
  1437. else {
  1438. // Create volume information using the share name
  1439. volInfo = new VolumeInfo(name, (int) System.currentTimeMillis(), new Date(System.currentTimeMillis()));
  1440. }
  1441. // Check if the disk sizing information has been specified
  1442. SrvDiskInfo diskInfo = null;
  1443. Element sizeElem = findChildNode("size", disk.getChildNodes());
  1444. if ( sizeElem != null) {
  1445. // Get the total disk size in bytes
  1446. long totSize = -1L;
  1447. long freeSize = 0;
  1448. attr = sizeElem.getAttribute("totalSize");
  1449. if ( attr != null && attr.length() > 0)
  1450. totSize = MemorySize.getByteValue(attr);
  1451. if ( totSize == -1L)
  1452. throw new InvalidConfigurationException("Total disk size invalid or not specified");
  1453. // Get the free size in bytes
  1454. attr = sizeElem.getAttribute("freeSize");
  1455. if ( attr != null && attr.length() > 0)
  1456. freeSize = MemorySize.getByteValue(attr);
  1457. else
  1458. freeSize = (totSize / 10L) * 9L;
  1459. if ( freeSize == -1L)
  1460. throw new InvalidConfigurationException("Free disk size invalid or not specified");
  1461. // Get the block size and blocks per unit values, if specified
  1462. long blockSize = 512L;
  1463. long blocksPerUnit = 64L; // 32Kb units
  1464. attr = sizeElem.getAttribute("blockSize");
  1465. if ( attr != null && attr.length() > 0) {
  1466. try {
  1467. blockSize = Long.parseLong(attr);
  1468. // Check for a multiple of 512 bytes
  1469. if ( blockSize <= 0 || blockSize % 512 != 0)
  1470. throw new InvalidConfigurationException("Block size must be a multiple of 512");
  1471. }
  1472. catch (NumberFormatException ex) {
  1473. throw new InvalidConfigurationException("Invalid block size specified, " + attr);
  1474. }
  1475. }
  1476. attr = sizeElem.getAttribute("blocksPerUnit");
  1477. if ( attr != null && attr.length() > 0) {
  1478. try {
  1479. blocksPerUnit = Long.parseLong(attr);
  1480. // Check for a valid blocks per unit value
  1481. if ( blocksPerUnit <= 0)
  1482. throw new InvalidConfigurationException("Invalid blocks per unit, must be greater than zero");
  1483. }
  1484. catch (NumberFormatException ex) {
  1485. throw new InvalidConfigurationException("Invalid blocks per unit value");
  1486. }
  1487. }
  1488. // Calculate the sizes and set the disk sizing information
  1489. long unitSize = blockSize * blocksPerUnit;
  1490. long totUnits = totSize / unitSize;
  1491. long freeUnits = freeSize / unitSize;
  1492. diskInfo = new SrvDiskInfo(totUnits, blocksPerUnit, blockSize, freeUnits);
  1493. }
  1494. else {
  1495. // Default to a 80Gb sized disk with 90% free space
  1496. diskInfo = new SrvDiskInfo(2560000, 64, 512, 2304000);
  1497. }
  1498. // Check if a state cache is configured
  1499. Element cacheElem = findChildNode("stateCache", disk.getChildNodes());
  1500. FileStateCache stateCache = null;
  1501. if ( cacheElem != null) {
  1502. // Convert the state cache configuration
  1503. ConfigElement cacheConfig = buildConfigElement( cacheElem);
  1504. // Get the cache type
  1505. attr = cacheElem.getAttribute( "type");
  1506. if ( attr.equalsIgnoreCase( "standalone")) {
  1507. // Create a standalone file state cache
  1508. stateCache = new StandaloneFileStateCache();
  1509. }
  1510. else if ( attr.equalsIgnoreCase( "cluster")) {
  1511. // Create a clustered file state cache, need to load the class to avoid a reference to it
  1512. try {
  1513. stateCache = (FileStateCache) Class.forName( "org.alfresco.jlan.server.filesys.cache.hazelcast.HazelCastClusterFileStateCache").newInstance();
  1514. }
  1515. catch ( ClassNotFoundException ex) {
  1516. throw new InvalidConfigurationException( "Clustered file state cache not available, check build/Jar");
  1517. }
  1518. catch ( Exception ex) {
  1519. throw new InvalidConfigurationException( "Failed to load clustered file state cache class, " + ex);
  1520. }
  1521. }
  1522. else if ( attr.equalsIgnoreCase( "custom")) {
  1523. // Get the custom state cache class name
  1524. Element cacheClass = findChildNode( "class", cacheElem.getChildNodes());
  1525. if ( cacheClass == null || getText( cacheClass).length() == 0)
  1526. throw new InvalidConfigurationException( "Custom state cache class not specified");
  1527. // Create a custom file state cache
  1528. try {
  1529. Object cacheObj = Class.forName( getText( cacheClass)).newInstance();
  1530. if ( cacheObj instanceof FileStateCache == false)
  1531. throw new InvalidConfigurationException( "State cache class is not a FileStateCache based class");
  1532. stateCache = (FileStateCache) cacheObj;
  1533. }
  1534. catch ( ClassNotFoundException ex) {
  1535. throw new InvalidConfigurationException( "Clustered file state cache not available, check build/Jar");
  1536. }
  1537. catch ( Exception ex) {
  1538. throw new InvalidConfigurationException( "Failed to load clustered file state cache class, " + ex);
  1539. }
  1540. }
  1541. // Initialize the cache
  1542. if ( stateCache != null)
  1543. stateCache.initializeCache( cacheConfig, this);
  1544. else
  1545. throw new InvalidConfigurationException( "Failed to initialize state cache for filesystem " + name);
  1546. }
  1547. // Check if a share with this name already exists
  1548. if ( filesysConfig.getShares().findShare(name) != null)
  1549. throw new InvalidConfigurationException("Share " + name + " already exists");
  1550. // Validate the driver class, create a device context and add the new disk share
  1551. try {
  1552. // Load the driver class
  1553. Object drvObj = Class.forName(getText(classElem)).newInstance();
  1554. if ( drvObj instanceof DiskInterface) {
  1555. // Create the driver
  1556. DiskInterface diskDrv = (DiskInterface) drvObj;
  1557. // Create a context for this share instance, save the configuration parameters as
  1558. // part of the context
  1559. DiskDeviceContext devCtx = (DiskDeviceContext) diskDrv.createContext(name, params);
  1560. devCtx.setConfigurationParameters(params);
  1561. // Enable/disable change notification for this device
  1562. devCtx.enableChangeHandler(changeNotify);
  1563. // Set the volume information, may be null
  1564. devCtx.setVolumeInformation(volInfo);
  1565. // Set the disk sizing information, may be null
  1566. devCtx.setDiskInformation(diskInfo);
  1567. // Set the share name in the context
  1568. devCtx.setShareName(name);
  1569. // Create the default file state cache type if the filesystem requires it, for backwards compatability
  1570. if ( devCtx.requiresStateCache() && stateCache == null) {
  1571. stateCache = new StandaloneFileStateCache();
  1572. stateCache.initializeCache( new GenericConfigElement( "stateCache"), this);
  1573. }
  1574. if ( devCtx.requiresStateCache() == false && stateCache != null)
  1575. throw new InvalidConfigurationException( "Filesystem does not use state caching");
  1576. devCtx.setStateCache( stateCache);
  1577. // Create the disk shared device and add to the server's list of shares
  1578. DiskSharedDevice diskDev = new DiskSharedDevice(name, diskDrv, devCtx);
  1579. diskDev.setComment(comment);
  1580. diskDev.setConfiguration( this);
  1581. // Add any access controls to the share
  1582. diskDev.setAccessControlList(acls);
  1583. // Check if the filesystem uses the file state cache, if so then add to the file state reaper
  1584. if ( devCtx.hasStateCache()) {
  1585. // Register the state cache with the reaper thread
  1586. filesysConfig.addFileStateCache( name, devCtx.getStateCache());
  1587. }
  1588. // Start the filesystem
  1589. devCtx.startFilesystem(diskDev);
  1590. // Pass the driver/context details to the state cache
  1591. if ( devCtx.hasStateCache())
  1592. devCtx.getStateCache().setDriverDetails(diskDev);
  1593. // Add the new share to the list of available shares
  1594. filesysConfig.addShare(diskDev);
  1595. }
  1596. }
  1597. catch (ClassNotFoundException ex) {
  1598. throw new InvalidConfigurationException("Disk driver class " + getText(classElem) + " not found");
  1599. }
  1600. catch (DeviceContextException ex) {
  1601. throw new InvalidConfigurationException("Driver context error", ex);
  1602. }
  1603. catch (Exception ex) {
  1604. throw new InvalidConfigurationException("Disk share setup error", ex);
  1605. }
  1606. }
  1607. /**
  1608. * Find the specified child node in the node list
  1609. *
  1610. * @param name String
  1611. * @param list NodeList
  1612. * @return Element
  1613. */
  1614. protected final Element findChildNode(String name, NodeList list) {
  1615. // Check if the list is valid
  1616. if ( list == null)
  1617. return null;
  1618. // Search for the required element
  1619. for (int i = 0; i < list.getLength(); i++) {
  1620. // Get the current child node
  1621. Node child = list.item(i);
  1622. if ( child.getNodeName().equals(name) && child.getNodeType() == ELEMENT_TYPE)
  1623. return (Element) child;
  1624. }
  1625. // Element not found
  1626. return null;
  1627. }
  1628. /**
  1629. * Get the value text for the specified element
  1630. *
  1631. * @param elem Element
  1632. * @return String
  1633. */
  1634. protected final String getText(Element elem) {
  1635. // Check if the element has children
  1636. NodeList children = elem.getChildNodes();
  1637. String text = "";
  1638. if ( children != null && children.getLength() > 0 && children.item(0).getNodeType() != ELEMENT_TYPE)
  1639. text = children.item(0).getNodeValue();
  1640. // Return the element text value
  1641. return text;
  1642. }
  1643. /**
  1644. * Build a configuration element list from an elements child nodes
  1645. *
  1646. * @param root Element
  1647. * @return GenericConfigElement
  1648. */
  1649. protected final GenericConfigElement buildConfigElement(Element root) {
  1650. return buildConfigElement(root, null);
  1651. }
  1652. /**
  1653. * Build a configuration element list from an elements child nodes
  1654. *
  1655. * @param root Element
  1656. * @param cfgElem GenericConfigElement
  1657. * @return GenericConfigElement
  1658. */
  1659. protected final GenericConfigElement buildConfigElement(Element root, GenericConfigElement cfgElem) {
  1660. // Create the top level element, if not specified
  1661. GenericConfigElement rootElem = cfgElem;
  1662. if ( rootElem == null) {
  1663. // Create the root element
  1664. rootElem = new GenericConfigElement(root.getNodeName());
  1665. // Add any attributes
  1666. NamedNodeMap attribs = root.getAttributes();
  1667. if ( attribs != null) {
  1668. for (int i = 0; i < attribs.getLength(); i++) {
  1669. Node attribNode = attribs.item(i);
  1670. rootElem.addAttribute(attribNode.getNodeName(), attribNode.getNodeValue());
  1671. }
  1672. }
  1673. }
  1674. // Get the child node list
  1675. NodeList nodes = root.getChildNodes();
  1676. if ( nodes == null)
  1677. return rootElem;
  1678. // Process the child node list
  1679. GenericConfigElement childElem = null;
  1680. for (int i = 0; i < nodes.getLength(); i++) {
  1681. // Get the current node
  1682. Node node = nodes.item(i);
  1683. if ( node.getNodeType() == ELEMENT_TYPE) {
  1684. // Access the Element
  1685. Element elem = (Element) node;
  1686. // Check if the element has any child nodes
  1687. NodeList children = elem.getChildNodes();
  1688. if ( children != null && children.getLength() > 1) {
  1689. // Add the child nodes as child configuration elements
  1690. childElem = buildConfigElement(elem, null);
  1691. }
  1692. else {
  1693. // Create a normal name/value
  1694. if ( children.getLength() > 0) {
  1695. childElem = new GenericConfigElement(elem.getNodeName());
  1696. childElem.setValue(children.item(0).getNodeValue());
  1697. }
  1698. else
  1699. childElem = new GenericConfigElement(elem.getNodeName());
  1700. // Add any attributes
  1701. NamedNodeMap attribs = elem.getAttributes();
  1702. if ( attribs != null) {
  1703. for (int j = 0; j < attribs.getLength(); j++) {
  1704. Node attribNode = attribs.item(j);
  1705. childElem.addAttribute(attribNode.getNodeName(), attribNode.getNodeValue());
  1706. }
  1707. }
  1708. }
  1709. // Add the child configuration element
  1710. rootElem.addChild(childElem);
  1711. }
  1712. }
  1713. // Return the configuration element
  1714. return rootElem;
  1715. }
  1716. /**
  1717. * Add a configuration element
  1718. */
  1719. /**
  1720. * Parse a platform type string into a list of platform ids
  1721. *
  1722. * @param platforms String
  1723. * @return List<Integer>
  1724. * @exception InvalidConfigurationException
  1725. */
  1726. protected final List<Platform.Type> parsePlatformString(String platforms)
  1727. throws InvalidConfigurationException {
  1728. // Create the list to hold the platform ids
  1729. List<Platform.Type> platformIds = new ArrayList<Platform.Type>();
  1730. if ( platforms == null)
  1731. return platformIds;
  1732. // Split the platform list
  1733. StringTokenizer tokens = new StringTokenizer(platforms.toUpperCase(Locale.ENGLISH), ",");
  1734. while (tokens.hasMoreTokens()) {
  1735. // Get the current platform token and validate
  1736. String platform = tokens.nextToken().trim();
  1737. // Validate the platform id
  1738. Platform.Type id = Platform.Type.Unknown;
  1739. if ( platform.equalsIgnoreCase("WINDOWS"))
  1740. id = Platform.Type.WINDOWS;
  1741. else if ( platform.equalsIgnoreCase("LINUX"))
  1742. id = Platform.Type.LINUX;
  1743. else if ( platform.equalsIgnoreCase("MACOSX"))
  1744. id = Platform.Type.MACOSX;
  1745. else if ( platform.equalsIgnoreCase("SOLARIS"))
  1746. id = Platform.Type.SOLARIS;
  1747. if ( id == Platform.Type.Unknown)
  1748. throw new InvalidConfigurationException("Invalid platform type '" + platform + "'");
  1749. // Add the platform id to the list
  1750. platformIds.add(id);
  1751. }
  1752. // Return the platform id list
  1753. return platformIds;
  1754. }
  1755. /**
  1756. * Parse an adapter name string and return the matching address
  1757. *
  1758. * @param adapter String
  1759. * @return InetAddress
  1760. * @exception InvalidConfigurationException
  1761. */
  1762. protected final InetAddress parseAdapterName(String adapter)
  1763. throws InvalidConfigurationException {
  1764. NetworkInterface ni = null;
  1765. try {
  1766. ni = NetworkInterface.getByName(adapter);
  1767. }
  1768. catch (SocketException ex) {
  1769. throw new InvalidConfigurationException("Invalid adapter name, " + adapter);
  1770. }
  1771. if ( ni == null)
  1772. throw new InvalidConfigurationException("Invalid network adapter name, " + adapter);
  1773. // Get the IP address for the adapter
  1774. InetAddress adapAddr = null;
  1775. Enumeration<InetAddress> addrEnum = ni.getInetAddresses();
  1776. while (addrEnum.hasMoreElements() && adapAddr == null) {
  1777. // Get the current address
  1778. InetAddress addr = addrEnum.nextElement();
  1779. if ( IPAddress.isNumericAddress(addr.getHostAddress()))
  1780. adapAddr = addr;
  1781. }
  1782. // Check if we found the IP address to bind to
  1783. if ( adapAddr == null)
  1784. throw new InvalidConfigurationException("Adapter " + adapter + " does not have a valid IP address");
  1785. // Return the adapter address
  1786. return adapAddr;
  1787. }
  1788. }