001: /*
002: * SSHTools - Java SSH2 API
003: *
004: * Copyright (C) 2002-2003 Lee David Painter and Contributors.
005: *
006: * Contributions made by:
007: *
008: * Brett Smith
009: * Richard Pernavas
010: * Erwin Bolwidt
011: *
012: * This program is free software; you can redistribute it and/or
013: * modify it under the terms of the GNU General Public License
014: * as published by the Free Software Foundation; either version 2
015: * of the License, or (at your option) any later version.
016: *
017: * This program is distributed in the hope that it will be useful,
018: * but WITHOUT ANY WARRANTY; without even the implied warranty of
019: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
020: * GNU General Public License for more details.
021: *
022: * You should have received a copy of the GNU General Public License
023: * along with this program; if not, write to the Free Software
024: * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
025: */
026: package com.sshtools.daemon.configuration;
027:
028: import com.sshtools.daemon.session.*;
029:
030: import com.sshtools.j2ssh.configuration.*;
031: import com.sshtools.j2ssh.transport.publickey.*;
032:
033: import org.apache.commons.logging.*;
034:
035: import org.xml.sax.*;
036: import org.xml.sax.helpers.*;
037:
038: import java.io.*;
039:
040: import java.util.*;
041:
042: import javax.xml.parsers.*;
043:
044: /**
045: *
046: *
047: * @author $author$
048: * @version $Revision: 1.12 $
049: */
050: public class ServerConfiguration extends DefaultHandler {
051: private static Log log = LogFactory
052: .getLog(ServerConfiguration.class);
053: private Map allowedSubsystems = new HashMap();
054: private Map serverHostKeys = new HashMap();
055: private List allowedAuthentications = new ArrayList();
056: private List requiredAuthentications = new ArrayList();
057: private int commandPort = 12222;
058: private int port = 22;
059: private String listenAddress = "0.0.0.0";
060: private int maxConnections = 10;
061: private int maxAuthentications = 5;
062: private String terminalProvider = "";
063: private String authorizationFile = "authorization.xml";
064: private String userConfigDirectory = "%D/.ssh2";
065: private String authenticationBanner = "";
066: private boolean allowTcpForwarding = true;
067: private String currentElement = null;
068: private Class sessionChannelImpl = SessionChannelServer.class;
069:
070: /**
071: * Creates a new ServerConfiguration object.
072: *
073: * @param in
074: *
075: * @throws SAXException
076: * @throws ParserConfigurationException
077: * @throws IOException
078: */
079: public ServerConfiguration(InputStream in) throws SAXException,
080: ParserConfigurationException, IOException {
081: reload(in);
082: }
083:
084: /**
085: *
086: *
087: * @param in
088: *
089: * @throws SAXException
090: * @throws ParserConfigurationException
091: * @throws IOException
092: */
093: public void reload(InputStream in) throws SAXException,
094: ParserConfigurationException, IOException {
095: allowedSubsystems.clear();
096: serverHostKeys.clear();
097: allowedAuthentications.clear();
098: requiredAuthentications.clear();
099: commandPort = 12222;
100: port = 22;
101: listenAddress = "0.0.0.0";
102: maxConnections = 10;
103: maxAuthentications = 5;
104: terminalProvider = "";
105: authorizationFile = "authorization.xml";
106: userConfigDirectory = "%D/.ssh2";
107: authenticationBanner = "";
108: allowTcpForwarding = true;
109: currentElement = null;
110:
111: SAXParserFactory saxFactory = SAXParserFactory.newInstance();
112: SAXParser saxParser = saxFactory.newSAXParser();
113: saxParser.parse(in, this );
114: }
115:
116: /**
117: *
118: *
119: * @param uri
120: * @param localName
121: * @param qname
122: * @param attrs
123: *
124: * @throws SAXException
125: */
126: public void startElement(String uri, String localName,
127: String qname, Attributes attrs) throws SAXException {
128: if (currentElement == null) {
129: if (!qname.equals("ServerConfiguration")) {
130: throw new SAXException("Unexpected root element "
131: + qname);
132: }
133: } else {
134: if (currentElement.equals("ServerConfiguration")) {
135: if (qname.equals("ServerHostKey")) {
136: //String algorithm = attrs.getValue("AlgorithmName");
137: String privateKey = attrs
138: .getValue("PrivateKeyFile");
139:
140: if (privateKey == null) {
141: throw new SAXException(
142: "Required attributes missing from <ServerHostKey> element");
143: }
144:
145: log.debug("ServerHostKey PrivateKeyFile="
146: + privateKey);
147:
148: File f = new File(privateKey);
149:
150: if (!f.exists()) {
151: privateKey = ConfigurationLoader
152: .getConfigurationDirectory()
153: + privateKey;
154: f = new File(privateKey);
155: }
156:
157: try {
158: if (f.exists()) {
159: SshPrivateKeyFile pkf = SshPrivateKeyFile
160: .parse(f);
161: SshPrivateKey key = pkf.toPrivateKey(null);
162: serverHostKeys.put(key.getAlgorithmName(),
163: key);
164: } else {
165: log.warn("Private key file '" + privateKey
166: + "' could not be found");
167: }
168: } catch (InvalidSshKeyException ex) {
169: log.warn("Failed to load private key '"
170: + privateKey, ex);
171: } catch (IOException ioe) {
172: log.warn("Failed to load private key '"
173: + privateKey, ioe);
174: }
175: } else if (qname.equals("Subsystem")) {
176: String type = attrs.getValue("Type");
177: String name = attrs.getValue("Name");
178: String provider = attrs.getValue("Provider");
179:
180: if ((type == null) || (name == null)
181: || (provider == null)) {
182: throw new SAXException(
183: "Required attributes missing from <Subsystem> element");
184: }
185:
186: log.debug("Subsystem Type=" + type + " Name="
187: + name + " Provider=" + provider);
188: allowedSubsystems.put(name, new AllowedSubsystem(
189: type, name, provider));
190: } else if (!qname.equals("AuthenticationBanner")
191: && !qname.equals("MaxConnections")
192: && !qname.equals("MaxAuthentications")
193: && !qname.equals("ListenAddress")
194: && !qname.equals("Port")
195: && !qname.equals("CommandPort")
196: && !qname.equals("TerminalProvider")
197: && !qname.equals("AllowedAuthentication")
198: && !qname.equals("RequiredAuthentication")
199: && !qname.equals("AuthorizationFile")
200: && !qname.equals("UserConfigDirectory")
201: && !qname.equals("AllowTcpForwarding")) {
202: throw new SAXException("Unexpected <" + qname
203: + "> element after SshAPIConfiguration");
204: }
205: }
206: }
207:
208: currentElement = qname;
209: }
210:
211: /**
212: *
213: *
214: * @param ch
215: * @param start
216: * @param length
217: *
218: * @throws SAXException
219: */
220: public void characters(char[] ch, int start, int length)
221: throws SAXException {
222: String value = new String(ch, start, length);
223:
224: if (currentElement != null) {
225: if (currentElement.equals("AuthenticationBanner")) {
226: authenticationBanner = value;
227: log.debug("AuthenticationBanner="
228: + authenticationBanner);
229: } else if (currentElement.equals("MaxConnections")) {
230: maxConnections = Integer.parseInt(value);
231: log.debug("MaxConnections=" + value);
232: } else if (currentElement.equals("ListenAddress")) {
233: listenAddress = value;
234: log.debug("ListenAddress=" + listenAddress);
235: } else if (currentElement.equals("Port")) {
236: port = Integer.parseInt(value);
237: log.debug("Port=" + value);
238: } else if (currentElement.equals("CommandPort")) {
239: commandPort = Integer.parseInt(value);
240: log.debug("CommandPort=" + value);
241: } else if (currentElement.equals("TerminalProvider")) {
242: terminalProvider = value;
243: log.debug("TerminalProvider=" + terminalProvider);
244: } else if (currentElement.equals("AllowedAuthentication")) {
245: if (!allowedAuthentications.contains(value)) {
246: allowedAuthentications.add(value);
247: log.debug("AllowedAuthentication=" + value);
248: }
249: } else if (currentElement.equals("RequiredAuthentication")) {
250: if (!requiredAuthentications.contains(value)) {
251: requiredAuthentications.add(value);
252: log.debug("RequiredAuthentication=" + value);
253: }
254: } else if (currentElement.equals("AuthorizationFile")) {
255: authorizationFile = value;
256: log.debug("AuthorizationFile=" + authorizationFile);
257: } else if (currentElement.equals("UserConfigDirectory")) {
258: userConfigDirectory = value;
259: log.debug("UserConfigDirectory=" + userConfigDirectory);
260: } else if (currentElement.equals("SessionChannelImpl")) {
261: try {
262: sessionChannelImpl = ConfigurationLoader
263: .getExtensionClass(value);
264: } catch (Exception e) {
265: log.error("Failed to load SessionChannelImpl "
266: + value, e);
267: }
268: } else if (currentElement.equals("MaxAuthentications")) {
269: maxAuthentications = Integer.parseInt(value);
270: log.debug("MaxAuthentications=" + value);
271: } else if (currentElement.equals("AllowTcpForwarding")) {
272: allowTcpForwarding = Boolean.valueOf(value)
273: .booleanValue();
274: }
275: }
276: }
277:
278: /**
279: *
280: *
281: * @param uri
282: * @param localName
283: * @param qname
284: *
285: * @throws SAXException
286: */
287: public void endElement(String uri, String localName, String qname)
288: throws SAXException {
289: if (currentElement != null) {
290: if (!currentElement.equals(qname)) {
291: throw new SAXException("Unexpected end element found <"
292: + qname + ">");
293: } else if (currentElement.equals("ServerConfiguration")) {
294: currentElement = null;
295: } else if (currentElement.equals("AuthenticationBanner")
296: || currentElement.equals("ServerHostKey")
297: || currentElement.equals("Subsystem")
298: || currentElement.equals("MaxConnections")
299: || currentElement.equals("MaxAuthentications")
300: || currentElement.equals("ListenAddress")
301: || currentElement.equals("Port")
302: || currentElement.equals("CommandPort")
303: || currentElement.equals("TerminalProvider")
304: || currentElement.equals("AllowedAuthentication")
305: || currentElement.equals("RequiredAuthentication")
306: || currentElement.equals("AuthorizationFile")
307: || currentElement.equals("UserConfigDirectory")
308: || currentElement.equals("AllowTcpForwarding")) {
309: currentElement = "ServerConfiguration";
310: }
311: } else {
312: throw new SAXException("Unexpected end element <" + qname
313: + "> found");
314: }
315: }
316:
317: /**
318: *
319: *
320: * @return
321: */
322: public List getRequiredAuthentications() {
323: return requiredAuthentications;
324: }
325:
326: /**
327: *
328: *
329: * @return
330: */
331: public List getAllowedAuthentications() {
332: return allowedAuthentications;
333: }
334:
335: /**
336: *
337: *
338: * @return
339: */
340: public boolean getAllowTcpForwarding() {
341: return allowTcpForwarding;
342: }
343:
344: /**
345: *
346: *
347: * @return
348: */
349: public String getAuthenticationBanner() {
350: return authenticationBanner;
351: }
352:
353: /**
354: *
355: *
356: * @return
357: */
358: public int getCommandPort() {
359: return commandPort;
360: }
361:
362: /**
363: *
364: *
365: * @return
366: */
367: public String getUserConfigDirectory() {
368: return userConfigDirectory;
369: }
370:
371: /**
372: *
373: *
374: * @return
375: */
376: public String getAuthorizationFile() {
377: return authorizationFile;
378: }
379:
380: /**
381: *
382: *
383: * @return
384: */
385: public String getListenAddress() {
386: return listenAddress;
387: }
388:
389: /**
390: *
391: *
392: * @return
393: */
394: public int getMaxConnections() {
395: return maxConnections;
396: }
397:
398: /**
399: *
400: *
401: * @return
402: */
403: public int getMaxAuthentications() {
404: return maxAuthentications;
405: }
406:
407: /**
408: *
409: *
410: * @return
411: */
412: public int getPort() {
413: return port;
414: }
415:
416: /*public Class getSessionChannelImpl() {
417: return sessionChannelImpl;
418: }*/
419: public Map getServerHostKeys() {
420: return serverHostKeys;
421: }
422:
423: /**
424: *
425: *
426: * @return
427: */
428: public Map getSubsystems() {
429: return allowedSubsystems;
430: }
431:
432: /**
433: *
434: *
435: * @return
436: */
437: public String getTerminalProvider() {
438: return terminalProvider;
439: }
440:
441: /**
442: *
443: *
444: * @return
445: */
446: public String toString() {
447: String xml = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
448: xml += "<!-- Server configuration file - If filenames are not absolute they are assummed to be in the same directory as this configuration file. -->\n";
449: xml += "<ServerConfiguration>\n";
450: xml += " <!-- The available host keys for server authentication -->\n";
451:
452: Map.Entry entry;
453: Iterator it = serverHostKeys.entrySet().iterator();
454:
455: while (it.hasNext()) {
456: entry = (Map.Entry) it.next();
457: xml += (" <ServerHostKey PrivateKeyFile=\""
458: + entry.getValue() + "\"/>\n");
459: }
460:
461: xml += " <!-- Add any number of subsystem elements here -->\n";
462:
463: AllowedSubsystem subsystem;
464: it = allowedSubsystems.entrySet().iterator();
465:
466: while (it.hasNext()) {
467: subsystem = (AllowedSubsystem) ((Map.Entry) it.next())
468: .getValue();
469: xml += (" <Subsystem Name=\"" + subsystem.getName()
470: + "\" Type=\"" + subsystem.getType()
471: + "\" Provider=\"" + subsystem.getProvider() + "\"/>\n");
472: }
473:
474: xml += " <!-- Display the following authentication banner before authentication -->\n";
475: xml += (" <AuthenticationBanner>" + authenticationBanner + "</AuthenticationBanner>\n");
476: xml += " <!-- The maximum number of connected sessions available -->\n";
477: xml += (" <MaxConnections>" + String.valueOf(maxConnections) + "</MaxConnections>\n");
478: xml += " <!-- The maximum number of authentication attemtps for each connection -->\n";
479: xml += (" <MaxAuthentications>"
480: + String.valueOf(maxAuthentications) + "</MaxAuthentications>\n");
481: xml += " <!-- Bind to the following address to listen for connections -->\n";
482: xml += (" <ListenAddress>" + listenAddress + "</ListenAddress>\n");
483: xml += " <!-- The port to listen to -->\n";
484: xml += (" <Port>" + String.valueOf(port) + "</Port>\n");
485: xml += " <!-- Listen on the following port (on localhost) for server commands such as stop -->\n";
486: xml += (" <CommandPort>" + String.valueOf(commandPort) + "</CommandPort>\n");
487: xml += " <!-- Specify the executable that provides the default shell -->\n";
488: xml += (" <TerminalProvider>" + terminalProvider + "</TerminalProvider>\n");
489: xml += " <!-- Specify any number of allowed authentications -->\n";
490: it = allowedAuthentications.iterator();
491:
492: while (it.hasNext()) {
493: xml += (" <AllowedAuthentication>" + it.next().toString() + "</AllowedAuthentication>\n");
494: }
495:
496: xml += " <!-- Specify any number of required authentications -->\n";
497: it = requiredAuthentications.iterator();
498:
499: while (it.hasNext()) {
500: xml += (" <RequiredAuthentication>"
501: + it.next().toString() + "</RequiredAuthentication>\n");
502: }
503:
504: xml += " <!-- The users authorizations file -->\n";
505: xml += (" <AuthorizationFile>" + authorizationFile + "</AuthorizationFile>\n");
506: xml += " <!-- The users configuration directory where files such as AuthorizationFile are found. For users home directory specify %D For users name specify %U -->\n";
507: xml += (" <UserConfigDirectory>" + userConfigDirectory + "</UserConfigDirectory>\n");
508: xml += ("<AllowTcpForwarding>"
509: + String.valueOf(allowTcpForwarding) + "</AllowTcpForwarding>\n");
510: xml += "</ServerConfiguration>\n";
511:
512: return xml;
513: }
514: }
|