diff options
Diffstat (limited to 'java/com/jcraft/jsch/OpenSSHConfig.java')
-rw-r--r-- | java/com/jcraft/jsch/OpenSSHConfig.java | 264 |
1 files changed, 264 insertions, 0 deletions
diff --git a/java/com/jcraft/jsch/OpenSSHConfig.java b/java/com/jcraft/jsch/OpenSSHConfig.java new file mode 100644 index 00000000..9b1bff8b --- /dev/null +++ b/java/com/jcraft/jsch/OpenSSHConfig.java @@ -0,0 +1,264 @@ +/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ +/* +Copyright (c) 2013-2015 ymnk, JCraft,Inc. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the distribution. + + 3. The names of the authors may not be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT, +INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, +OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, +EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +package com.jcraft.jsch; + +import java.io.InputStream; +import java.io.Reader; +import java.io.StringReader; +import java.io.FileReader; +import java.io.BufferedReader; +import java.io.IOException; +import java.util.Hashtable; +import java.util.Vector; + +/** + * This class implements ConfigRepository interface, and parses + * OpenSSH's configuration file. The following keywords will be recognized, + * <ul> + * <li>Host</li> + * <li>User</li> + * <li>Hostname</li> + * <li>Port</li> + * <li>PreferredAuthentications</li> + * <li>IdentityFile</li> + * <li>NumberOfPasswordPrompts</li> + * <li>ConnectTimeout</li> + * <li>HostKeyAlias</li> + * <li>UserKnownHostsFile</li> + * <li>KexAlgorithms</li> + * <li>HostKeyAlgorithms</li> + * <li>Ciphers</li> + * <li>Macs</li> + * <li>Compression</li> + * <li>CompressionLevel</li> + * <li>ForwardAgent</li> + * <li>RequestTTY</li> + * <li>ServerAliveInterval</li> + * <li>LocalForward</li> + * <li>RemoteForward</li> + * <li>ClearAllForwardings</li> + * </ul> + * + * @see ConfigRepository + */ +public class OpenSSHConfig implements ConfigRepository { + + /** + * Parses the given string, and returns an instance of ConfigRepository. + * + * @param conf string, which includes OpenSSH's config + * @return an instanceof OpenSSHConfig + */ + public static OpenSSHConfig parse(String conf) throws IOException { + Reader r = new StringReader(conf); + try { + return new OpenSSHConfig(r); + } + finally { + r.close(); + } + } + + /** + * Parses the given file, and returns an instance of ConfigRepository. + * + * @param file OpenSSH's config file + * @return an instanceof OpenSSHConfig + */ + public static OpenSSHConfig parseFile(String file) throws IOException { + Reader r = new FileReader(Util.checkTilde(file)); + try { + return new OpenSSHConfig(r); + } + finally { + r.close(); + } + } + + OpenSSHConfig(Reader r) throws IOException { + _parse(r); + } + + private final Hashtable config = new Hashtable(); + private final Vector hosts = new Vector(); + + private void _parse(Reader r) throws IOException { + BufferedReader br = new BufferedReader(r); + + String host = ""; + Vector/*<String[]>*/ kv = new Vector(); + String l = null; + + while((l = br.readLine()) != null){ + l = l.trim(); + if(l.length() == 0 || l.startsWith("#")) + continue; + + String[] key_value = l.split("[= \t]", 2); + for(int i = 0; i < key_value.length; i++) + key_value[i] = key_value[i].trim(); + + if(key_value.length <= 1) + continue; + + if(key_value[0].equals("Host")){ + config.put(host, kv); + hosts.addElement(host); + host = key_value[1]; + kv = new Vector(); + } + else { + kv.addElement(key_value); + } + } + config.put(host, kv); + hosts.addElement(host); + } + + public Config getConfig(String host) { + return new MyConfig(host); + } + + private static final Hashtable keymap = new Hashtable(); + static { + keymap.put("kex", "KexAlgorithms"); + keymap.put("server_host_key", "HostKeyAlgorithms"); + keymap.put("cipher.c2s", "Ciphers"); + keymap.put("cipher.s2c", "Ciphers"); + keymap.put("mac.c2s", "Macs"); + keymap.put("mac.s2c", "Macs"); + keymap.put("compression.s2c", "Compression"); + keymap.put("compression.c2s", "Compression"); + keymap.put("compression_level", "CompressionLevel"); + keymap.put("MaxAuthTries", "NumberOfPasswordPrompts"); + } + + class MyConfig implements Config { + + private String host; + private Vector _configs = new Vector(); + + MyConfig(String host){ + this.host = host; + + _configs.addElement(config.get("")); + + byte[] _host = Util.str2byte(host); + if(hosts.size() > 1){ + for(int i = 1; i < hosts.size(); i++){ + String patterns[] = ((String)hosts.elementAt(i)).split("[ \t]"); + for(int j = 0; j < patterns.length; j++){ + boolean negate = false; + String foo = patterns[j].trim(); + if(foo.startsWith("!")){ + negate = true; + foo = foo.substring(1).trim(); + } + if(Util.glob(Util.str2byte(foo), _host)){ + if(!negate){ + _configs.addElement(config.get((String)hosts.elementAt(i))); + } + } + else if(negate){ + _configs.addElement(config.get((String)hosts.elementAt(i))); + } + } + } + } + } + + private String find(String key) { + if(keymap.get(key)!=null) { + key = (String)keymap.get(key); + } + key = key.toUpperCase(); + String value = null; + for(int i = 0; i < _configs.size(); i++) { + Vector v = (Vector)_configs.elementAt(i); + for(int j = 0; j < v.size(); j++) { + String[] kv = (String[])v.elementAt(j); + if(kv[0].toUpperCase().equals(key)) { + value = kv[1]; + break; + } + } + if(value != null) + break; + } + return value; + } + + private String[] multiFind(String key) { + key = key.toUpperCase(); + Vector value = new Vector(); + for(int i = 0; i < _configs.size(); i++) { + Vector v = (Vector)_configs.elementAt(i); + for(int j = 0; j < v.size(); j++) { + String[] kv = (String[])v.elementAt(j); + if(kv[0].toUpperCase().equals(key)) { + String foo = kv[1]; + if(foo != null) { + value.remove(foo); + value.addElement(foo); + } + } + } + } + String[] result = new String[value.size()]; + value.toArray(result); + return result; + } + + public String getHostname(){ return find("Hostname"); } + public String getUser(){ return find("User"); } + public int getPort(){ + String foo = find("Port"); + int port = -1; + try { + port = Integer.parseInt(foo); + } + catch(NumberFormatException e){ + // wrong format + } + return port; + } + public String getValue(String key){ + if(key.equals("compression.s2c") || + key.equals("compression.c2s")) { + String foo = find(key); + if(foo == null || foo.equals("no")) + return "none,zlib@openssh.com,zlib"; + return "zlib@openssh.com,zlib,none"; + } + return find(key); + } + public String[] getValues(String key){ return multiFind(key); } + } +} |