0001: /* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
0002: /*
0003: Copyright (c) 2002-2008 ymnk, JCraft,Inc. All rights reserved.
0004:
0005: Redistribution and use in source and binary forms, with or without
0006: modification, are permitted provided that the following conditions are met:
0007:
0008: 1. Redistributions of source code must retain the above copyright notice,
0009: this list of conditions and the following disclaimer.
0010:
0011: 2. Redistributions in binary form must reproduce the above copyright
0012: notice, this list of conditions and the following disclaimer in
0013: the documentation and/or other materials provided with the distribution.
0014:
0015: 3. The names of the authors may not be used to endorse or promote products
0016: derived from this software without specific prior written permission.
0017:
0018: THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
0019: INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
0020: FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT,
0021: INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,
0022: INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
0023: LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
0024: OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
0025: LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
0026: NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
0027: EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
0028: */
0029:
0030: package com.jcraft.jsch;
0031:
0032: import java.io.*;
0033: import java.net.*;
0034:
0035: public class Session implements Runnable {
0036: static private final String version = "JSCH-0.1.37";
0037:
0038: // http://ietf.org/internet-drafts/draft-ietf-secsh-assignednumbers-01.txt
0039: static final int SSH_MSG_DISCONNECT = 1;
0040: static final int SSH_MSG_IGNORE = 2;
0041: static final int SSH_MSG_UNIMPLEMENTED = 3;
0042: static final int SSH_MSG_DEBUG = 4;
0043: static final int SSH_MSG_SERVICE_REQUEST = 5;
0044: static final int SSH_MSG_SERVICE_ACCEPT = 6;
0045: static final int SSH_MSG_KEXINIT = 20;
0046: static final int SSH_MSG_NEWKEYS = 21;
0047: static final int SSH_MSG_KEXDH_INIT = 30;
0048: static final int SSH_MSG_KEXDH_REPLY = 31;
0049: static final int SSH_MSG_KEX_DH_GEX_GROUP = 31;
0050: static final int SSH_MSG_KEX_DH_GEX_INIT = 32;
0051: static final int SSH_MSG_KEX_DH_GEX_REPLY = 33;
0052: static final int SSH_MSG_KEX_DH_GEX_REQUEST = 34;
0053: static final int SSH_MSG_GLOBAL_REQUEST = 80;
0054: static final int SSH_MSG_REQUEST_SUCCESS = 81;
0055: static final int SSH_MSG_REQUEST_FAILURE = 82;
0056: static final int SSH_MSG_CHANNEL_OPEN = 90;
0057: static final int SSH_MSG_CHANNEL_OPEN_CONFIRMATION = 91;
0058: static final int SSH_MSG_CHANNEL_OPEN_FAILURE = 92;
0059: static final int SSH_MSG_CHANNEL_WINDOW_ADJUST = 93;
0060: static final int SSH_MSG_CHANNEL_DATA = 94;
0061: static final int SSH_MSG_CHANNEL_EXTENDED_DATA = 95;
0062: static final int SSH_MSG_CHANNEL_EOF = 96;
0063: static final int SSH_MSG_CHANNEL_CLOSE = 97;
0064: static final int SSH_MSG_CHANNEL_REQUEST = 98;
0065: static final int SSH_MSG_CHANNEL_SUCCESS = 99;
0066: static final int SSH_MSG_CHANNEL_FAILURE = 100;
0067:
0068: private byte[] V_S; // server version
0069: private byte[] V_C = ("SSH-2.0-" + version).getBytes(); // client version
0070:
0071: private byte[] I_C; // the payload of the client's SSH_MSG_KEXINIT
0072: private byte[] I_S; // the payload of the server's SSH_MSG_KEXINIT
0073: private byte[] K_S; // the host key
0074:
0075: private byte[] session_id;
0076:
0077: private byte[] IVc2s;
0078: private byte[] IVs2c;
0079: private byte[] Ec2s;
0080: private byte[] Es2c;
0081: private byte[] MACc2s;
0082: private byte[] MACs2c;
0083:
0084: private int seqi = 0;
0085: private int seqo = 0;
0086:
0087: String[] guess = null;
0088: private Cipher s2ccipher;
0089: private Cipher c2scipher;
0090: private MAC s2cmac;
0091: private MAC c2smac;
0092: //private byte[] mac_buf;
0093: private byte[] s2cmac_result1;
0094: private byte[] s2cmac_result2;
0095:
0096: private Compression deflater;
0097: private Compression inflater;
0098:
0099: private IO io;
0100: private Socket socket;
0101: private int timeout = 0;
0102:
0103: private boolean isConnected = false;
0104:
0105: private boolean isAuthed = false;
0106:
0107: private Thread connectThread = null;
0108:
0109: boolean x11_forwarding = false;
0110: boolean agent_forwarding = false;
0111:
0112: InputStream in = null;
0113: OutputStream out = null;
0114:
0115: static Random random;
0116:
0117: Buffer buf;
0118: Packet packet;
0119:
0120: SocketFactory socket_factory = null;
0121:
0122: private java.util.Hashtable config = null;
0123:
0124: private Proxy proxy = null;
0125: private UserInfo userinfo;
0126:
0127: private String hostKeyAlias = null;
0128: private int serverAliveInterval = 0;
0129: private int serverAliveCountMax = 1;
0130:
0131: protected boolean daemon_thread = false;
0132:
0133: String host = "127.0.0.1";
0134: int port = 22;
0135:
0136: String username = null;
0137: byte[] password = null;
0138:
0139: JSch jsch;
0140:
0141: Session(JSch jsch) throws JSchException {
0142: super ();
0143: this .jsch = jsch;
0144: buf = new Buffer();
0145: packet = new Packet(buf);
0146: }
0147:
0148: public void connect() throws JSchException {
0149: connect(timeout);
0150: }
0151:
0152: public void connect(int connectTimeout) throws JSchException {
0153: if (isConnected) {
0154: throw new JSchException("session is already connected");
0155: }
0156:
0157: io = new IO();
0158: if (random == null) {
0159: try {
0160: Class c = Class.forName(getConfig("random"));
0161: random = (Random) (c.newInstance());
0162: } catch (Exception e) {
0163: throw new JSchException(e.toString(), e);
0164: }
0165: }
0166: Packet.setRandom(random);
0167:
0168: if (JSch.getLogger().isEnabled(Logger.INFO)) {
0169: JSch.getLogger().log(Logger.INFO,
0170: "Connecting to " + host + " port " + port);
0171: }
0172:
0173: try {
0174: int i, j;
0175:
0176: if (proxy == null) {
0177: InputStream in;
0178: OutputStream out;
0179: if (socket_factory == null) {
0180: socket = Util.createSocket(host, port,
0181: connectTimeout);
0182: in = socket.getInputStream();
0183: out = socket.getOutputStream();
0184: } else {
0185: socket = socket_factory.createSocket(host, port);
0186: in = socket_factory.getInputStream(socket);
0187: out = socket_factory.getOutputStream(socket);
0188: }
0189: //if(timeout>0){ socket.setSoTimeout(timeout); }
0190: socket.setTcpNoDelay(true);
0191: io.setInputStream(in);
0192: io.setOutputStream(out);
0193: } else {
0194: synchronized (proxy) {
0195: proxy.connect(socket_factory, host, port,
0196: connectTimeout);
0197: io.setInputStream(proxy.getInputStream());
0198: io.setOutputStream(proxy.getOutputStream());
0199: socket = proxy.getSocket();
0200: }
0201: }
0202:
0203: if (connectTimeout > 0 && socket != null) {
0204: socket.setSoTimeout(connectTimeout);
0205: }
0206:
0207: isConnected = true;
0208:
0209: if (JSch.getLogger().isEnabled(Logger.INFO)) {
0210: JSch.getLogger().log(Logger.INFO,
0211: "Connection established");
0212: }
0213:
0214: jsch.addSession(this );
0215:
0216: {
0217: // Some Cisco devices will miss to read '\n' if it is sent separately.
0218: byte[] foo = new byte[V_C.length + 1];
0219: System.arraycopy(V_C, 0, foo, 0, V_C.length);
0220: foo[foo.length - 1] = (byte) '\n';
0221: io.put(foo, 0, foo.length);
0222: }
0223:
0224: while (true) {
0225: i = 0;
0226: j = 0;
0227: while (i < buf.buffer.length) {
0228: j = io.getByte();
0229: if (j < 0)
0230: break;
0231: buf.buffer[i] = (byte) j;
0232: i++;
0233: if (j == 10)
0234: break;
0235: }
0236: if (j < 0) {
0237: throw new JSchException(
0238: "connection is closed by foreign host");
0239: }
0240:
0241: if (buf.buffer[i - 1] == 10) { // 0x0a
0242: i--;
0243: if (buf.buffer[i - 1] == 13) { // 0x0d
0244: i--;
0245: }
0246: }
0247:
0248: if (i > 4
0249: && (i != buf.buffer.length)
0250: && (buf.buffer[0] != 'S'
0251: || buf.buffer[1] != 'S'
0252: || buf.buffer[2] != 'H' || buf.buffer[3] != '-')) {
0253: //System.err.println(new String(buf.buffer, 0, i);
0254: continue;
0255: }
0256:
0257: if (i == buf.buffer.length || i < 7 || // SSH-1.99 or SSH-2.0
0258: (buf.buffer[4] == '1' && buf.buffer[6] != '9') // SSH-1.5
0259: ) {
0260: throw new JSchException(
0261: "invalid server's version string");
0262: }
0263: break;
0264: }
0265:
0266: V_S = new byte[i];
0267: System.arraycopy(buf.buffer, 0, V_S, 0, i);
0268: //System.err.println("V_S: ("+i+") ["+new String(V_S)+"]");
0269:
0270: if (JSch.getLogger().isEnabled(Logger.INFO)) {
0271: JSch.getLogger().log(Logger.INFO,
0272: "Remote version string: " + new String(V_S));
0273: JSch.getLogger().log(Logger.INFO,
0274: "Local version string: " + new String(V_C));
0275: }
0276:
0277: send_kexinit();
0278:
0279: buf = read(buf);
0280: if (buf.getCommand() != SSH_MSG_KEXINIT) {
0281: throw new JSchException("invalid protocol: "
0282: + buf.getCommand());
0283: }
0284:
0285: if (JSch.getLogger().isEnabled(Logger.INFO)) {
0286: JSch.getLogger().log(Logger.INFO,
0287: "SSH_MSG_KEXINIT received");
0288: }
0289:
0290: KeyExchange kex = receive_kexinit(buf);
0291:
0292: while (true) {
0293: buf = read(buf);
0294: if (kex.getState() == buf.getCommand()) {
0295: boolean result = kex.next(buf);
0296: if (!result) {
0297: //System.err.println("verify: "+result);
0298: in_kex = false;
0299: throw new JSchException("verify: " + result);
0300: }
0301: } else {
0302: in_kex = false;
0303: throw new JSchException("invalid protocol(kex): "
0304: + buf.getCommand());
0305: }
0306: if (kex.getState() == KeyExchange.STATE_END) {
0307: break;
0308: }
0309: }
0310:
0311: try {
0312: checkHost(host, port, kex);
0313: } catch (JSchException ee) {
0314: in_kex = false;
0315: throw ee;
0316: }
0317:
0318: send_newkeys();
0319:
0320: // receive SSH_MSG_NEWKEYS(21)
0321: buf = read(buf);
0322: //System.err.println("read: 21 ? "+buf.getCommand());
0323: if (buf.getCommand() == SSH_MSG_NEWKEYS) {
0324:
0325: if (JSch.getLogger().isEnabled(Logger.INFO)) {
0326: JSch.getLogger().log(Logger.INFO,
0327: "SSH_MSG_NEWKEYS received");
0328: }
0329:
0330: receive_newkeys(buf, kex);
0331: } else {
0332: in_kex = false;
0333: throw new JSchException("invalid protocol(newkyes): "
0334: + buf.getCommand());
0335: }
0336:
0337: boolean auth = false;
0338: boolean auth_cancel = false;
0339:
0340: UserAuth ua = null;
0341: try {
0342: Class c = Class.forName(getConfig("userauth.none"));
0343: ua = (UserAuth) (c.newInstance());
0344: } catch (Exception e) {
0345: throw new JSchException(e.toString(), e);
0346: }
0347:
0348: auth = ua.start(this );
0349:
0350: String cmethods = getConfig("PreferredAuthentications");
0351: String[] cmethoda = Util.split(cmethods, ",");
0352:
0353: String smethods = null;
0354: if (!auth) {
0355: smethods = ((UserAuthNone) ua).getMethods();
0356: if (smethods != null) {
0357: smethods = smethods.toLowerCase();
0358: } else {
0359: // methods: publickey,password,keyboard-interactive
0360: //smethods="publickey,password,keyboard-interactive";
0361: smethods = cmethods;
0362: }
0363: }
0364:
0365: String[] smethoda = Util.split(smethods, ",");
0366:
0367: int methodi = 0;
0368:
0369: loop: while (true) {
0370:
0371: //System.err.println("methods: "+methods);
0372:
0373: while (!auth && cmethoda != null
0374: && methodi < cmethoda.length) {
0375:
0376: String method = cmethoda[methodi++];
0377: boolean acceptable = false;
0378: for (int k = 0; k < smethoda.length; k++) {
0379: if (smethoda[k].equals(method)) {
0380: acceptable = true;
0381: break;
0382: }
0383: }
0384: if (!acceptable) {
0385: continue;
0386: }
0387:
0388: //System.err.println(" method: "+method);
0389:
0390: if (JSch.getLogger().isEnabled(Logger.INFO)) {
0391: String str = "Authentications that can continue: ";
0392: for (int k = methodi - 1; k < cmethoda.length; k++) {
0393: str += cmethoda[k];
0394: if (k + 1 < cmethoda.length)
0395: str += ",";
0396: }
0397: JSch.getLogger().log(Logger.INFO, str);
0398: JSch.getLogger()
0399: .log(
0400: Logger.INFO,
0401: "Next authentication method: "
0402: + method);
0403: }
0404:
0405: ua = null;
0406: try {
0407: Class c = null;
0408: if (getConfig("userauth." + method) != null) {
0409: c = Class.forName(getConfig("userauth."
0410: + method));
0411: ua = (UserAuth) (c.newInstance());
0412: }
0413: } catch (Exception e) {
0414: if (JSch.getLogger().isEnabled(Logger.WARN)) {
0415: JSch.getLogger().log(
0416: Logger.WARN,
0417: "failed to load " + method
0418: + " method");
0419: }
0420: }
0421:
0422: if (ua != null) {
0423: auth_cancel = false;
0424: try {
0425: auth = ua.start(this );
0426: if (auth
0427: && JSch.getLogger().isEnabled(
0428: Logger.INFO)) {
0429: JSch.getLogger().log(
0430: Logger.INFO,
0431: "Authentication succeeded ("
0432: + method + ").");
0433: }
0434: } catch (JSchAuthCancelException ee) {
0435: auth_cancel = true;
0436: } catch (JSchPartialAuthException ee) {
0437: smethods = ee.getMethods();
0438: smethoda = Util.split(smethods, ",");
0439: methodi = 0;
0440: //System.err.println("PartialAuth: "+methods);
0441: auth_cancel = false;
0442: continue loop;
0443: } catch (RuntimeException ee) {
0444: throw ee;
0445: } catch (Exception ee) {
0446: //System.err.println("ee: "+ee); // SSH_MSG_DISCONNECT: 2 Too many authentication failures
0447: break loop;
0448: }
0449: }
0450: }
0451: break;
0452: }
0453:
0454: if (!auth) {
0455: if (auth_cancel)
0456: throw new JSchException("Auth cancel");
0457: throw new JSchException("Auth fail");
0458: }
0459:
0460: if (connectTimeout > 0 || timeout > 0) {
0461: socket.setSoTimeout(timeout);
0462: }
0463:
0464: isAuthed = true;
0465: connectThread = new Thread(this );
0466: connectThread
0467: .setName("Connect thread " + host + " session");
0468: if (daemon_thread) {
0469: connectThread.setDaemon(daemon_thread);
0470: }
0471: connectThread.start();
0472: } catch (Exception e) {
0473: in_kex = false;
0474: if (isConnected) {
0475: try {
0476: packet.reset();
0477: buf.putByte((byte) SSH_MSG_DISCONNECT);
0478: buf.putInt(3);
0479: buf.putString(e.toString().getBytes());
0480: buf.putString("en".getBytes());
0481: write(packet);
0482: disconnect();
0483: } catch (Exception ee) {
0484: }
0485: }
0486: isConnected = false;
0487: //e.printStackTrace();
0488: if (e instanceof RuntimeException)
0489: throw (RuntimeException) e;
0490: if (e instanceof JSchException)
0491: throw (JSchException) e;
0492: throw new JSchException("Session.connect: " + e);
0493: } finally {
0494: Util.bzero(this .password);
0495: this .password = null;
0496: }
0497: }
0498:
0499: private KeyExchange receive_kexinit(Buffer buf) throws Exception {
0500: int j = buf.getInt();
0501: if (j != buf.getLength()) { // packet was compressed and
0502: buf.getByte(); // j is the size of deflated packet.
0503: I_S = new byte[buf.index - 5];
0504: } else {
0505: I_S = new byte[j - 1 - buf.getByte()];
0506: }
0507: System.arraycopy(buf.buffer, buf.s, I_S, 0, I_S.length);
0508:
0509: guess = KeyExchange.guess(I_S, I_C);
0510: if (guess == null) {
0511: throw new JSchException("Algorithm negotiation fail");
0512: }
0513:
0514: if (!isAuthed
0515: && (guess[KeyExchange.PROPOSAL_ENC_ALGS_CTOS]
0516: .equals("none") || (guess[KeyExchange.PROPOSAL_ENC_ALGS_STOC]
0517: .equals("none")))) {
0518: throw new JSchException(
0519: "NONE Cipher should not be chosen before authentification is successed.");
0520: }
0521:
0522: KeyExchange kex = null;
0523: try {
0524: Class c = Class
0525: .forName(getConfig(guess[KeyExchange.PROPOSAL_KEX_ALGS]));
0526: kex = (KeyExchange) (c.newInstance());
0527: } catch (Exception e) {
0528: throw new JSchException(e.toString(), e);
0529: }
0530:
0531: kex.init(this , V_S, V_C, I_S, I_C);
0532: return kex;
0533: }
0534:
0535: private boolean in_kex = false;
0536:
0537: public void rekey() throws Exception {
0538: send_kexinit();
0539: }
0540:
0541: private void send_kexinit() throws Exception {
0542: if (in_kex)
0543: return;
0544:
0545: String cipherc2s = getConfig("cipher.c2s");
0546: String ciphers2c = getConfig("cipher.s2c");
0547:
0548: String[] not_available = checkCiphers(getConfig("CheckCiphers"));
0549: if (not_available != null && not_available.length > 0) {
0550: cipherc2s = Util.diffString(cipherc2s, not_available);
0551: ciphers2c = Util.diffString(ciphers2c, not_available);
0552: if (cipherc2s == null || ciphers2c == null) {
0553: throw new JSchException(
0554: "There are not any available ciphers.");
0555: }
0556: }
0557:
0558: in_kex = true;
0559:
0560: // byte SSH_MSG_KEXINIT(20)
0561: // byte[16] cookie (random bytes)
0562: // string kex_algorithms
0563: // string server_host_key_algorithms
0564: // string encryption_algorithms_client_to_server
0565: // string encryption_algorithms_server_to_client
0566: // string mac_algorithms_client_to_server
0567: // string mac_algorithms_server_to_client
0568: // string compression_algorithms_client_to_server
0569: // string compression_algorithms_server_to_client
0570: // string languages_client_to_server
0571: // string languages_server_to_client
0572: packet.reset();
0573: buf.putByte((byte) SSH_MSG_KEXINIT);
0574: synchronized (random) {
0575: random.fill(buf.buffer, buf.index, 16);
0576: buf.skip(16);
0577: }
0578: buf.putString(getConfig("kex").getBytes());
0579: buf.putString(getConfig("server_host_key").getBytes());
0580: buf.putString(cipherc2s.getBytes());
0581: buf.putString(ciphers2c.getBytes());
0582: buf.putString(getConfig("mac.c2s").getBytes());
0583: buf.putString(getConfig("mac.s2c").getBytes());
0584: buf.putString(getConfig("compression.c2s").getBytes());
0585: buf.putString(getConfig("compression.s2c").getBytes());
0586: buf.putString(getConfig("lang.c2s").getBytes());
0587: buf.putString(getConfig("lang.s2c").getBytes());
0588: buf.putByte((byte) 0);
0589: buf.putInt(0);
0590:
0591: buf.setOffSet(5);
0592: I_C = new byte[buf.getLength()];
0593: buf.getByte(I_C);
0594:
0595: write(packet);
0596:
0597: if (JSch.getLogger().isEnabled(Logger.INFO)) {
0598: JSch.getLogger().log(Logger.INFO, "SSH_MSG_KEXINIT sent");
0599: }
0600: }
0601:
0602: private void send_newkeys() throws Exception {
0603: // send SSH_MSG_NEWKEYS(21)
0604: packet.reset();
0605: buf.putByte((byte) SSH_MSG_NEWKEYS);
0606: write(packet);
0607:
0608: if (JSch.getLogger().isEnabled(Logger.INFO)) {
0609: JSch.getLogger().log(Logger.INFO, "SSH_MSG_NEWKEYS sent");
0610: }
0611: }
0612:
0613: private void checkHost(String chost, int port, KeyExchange kex)
0614: throws JSchException {
0615: String shkc = getConfig("StrictHostKeyChecking");
0616:
0617: if (hostKeyAlias != null) {
0618: chost = hostKeyAlias;
0619: }
0620:
0621: //System.err.println("shkc: "+shkc);
0622:
0623: byte[] K_S = kex.getHostKey();
0624: String key_type = kex.getKeyType();
0625: String key_fprint = kex.getFingerPrint();
0626:
0627: if (hostKeyAlias == null && port != 22) {
0628: chost = ("[" + chost + "]:" + port);
0629: }
0630:
0631: // hostkey=new HostKey(chost, K_S);
0632:
0633: HostKeyRepository hkr = jsch.getHostKeyRepository();
0634: int i = 0;
0635: synchronized (hkr) {
0636: i = hkr.check(chost, K_S);
0637: }
0638:
0639: boolean insert = false;
0640:
0641: if ((shkc.equals("ask") || shkc.equals("yes"))
0642: && i == HostKeyRepository.CHANGED) {
0643: String file = null;
0644: synchronized (hkr) {
0645: file = hkr.getKnownHostsRepositoryID();
0646: }
0647: if (file == null) {
0648: file = "known_hosts";
0649: }
0650:
0651: boolean b = false;
0652:
0653: if (userinfo != null) {
0654: String message = "WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED!\n"
0655: + "IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY!\n"
0656: + "Someone could be eavesdropping on you right now (man-in-the-middle attack)!\n"
0657: + "It is also possible that the "
0658: + key_type
0659: + " host key has just been changed.\n"
0660: + "The fingerprint for the "
0661: + key_type
0662: + " key sent by the remote host is\n"
0663: + key_fprint
0664: + ".\n"
0665: + "Please contact your system administrator.\n"
0666: + "Add correct host key in "
0667: + file
0668: + " to get rid of this message.";
0669:
0670: if (shkc.equals("ask")) {
0671: b = userinfo
0672: .promptYesNo(message
0673: + "\nDo you want to delete the old key and insert the new key?");
0674: } else { // shkc.equals("yes")
0675: userinfo.showMessage(message);
0676: }
0677: }
0678:
0679: if (!b) {
0680: throw new JSchException("HostKey has been changed: "
0681: + chost);
0682: }
0683:
0684: synchronized (hkr) {
0685: hkr.remove(chost, (key_type.equals("DSA") ? "ssh-dss"
0686: : "ssh-rsa"), null);
0687: insert = true;
0688: }
0689: }
0690:
0691: if ((shkc.equals("ask") || shkc.equals("yes"))
0692: && (i != HostKeyRepository.OK) && !insert) {
0693: if (shkc.equals("yes")) {
0694: throw new JSchException("reject HostKey: " + host);
0695: }
0696: //System.err.println("finger-print: "+key_fprint);
0697: if (userinfo != null) {
0698: boolean foo = userinfo
0699: .promptYesNo("The authenticity of host '"
0700: + host
0701: + "' can't be established.\n"
0702: + key_type
0703: + " key fingerprint is "
0704: + key_fprint
0705: + ".\n"
0706: + "Are you sure you want to continue connecting?");
0707: if (!foo) {
0708: throw new JSchException("reject HostKey: " + host);
0709: }
0710: insert = true;
0711: } else {
0712: if (i == HostKeyRepository.NOT_INCLUDED)
0713: throw new JSchException("UnknownHostKey: " + host
0714: + ". " + key_type + " key fingerprint is "
0715: + key_fprint);
0716: else
0717: throw new JSchException(
0718: "HostKey has been changed: " + host);
0719: }
0720: }
0721:
0722: if (shkc.equals("no") && HostKeyRepository.NOT_INCLUDED == i) {
0723: insert = true;
0724: }
0725:
0726: if (i == HostKeyRepository.OK
0727: && JSch.getLogger().isEnabled(Logger.INFO)) {
0728: JSch.getLogger().log(
0729: Logger.INFO,
0730: "Host '" + host + "' is known and mathces the "
0731: + key_type + " host key");
0732: }
0733:
0734: if (insert && JSch.getLogger().isEnabled(Logger.WARN)) {
0735: JSch.getLogger().log(
0736: Logger.WARN,
0737: "Permanently added '" + host + "' (" + key_type
0738: + ") to the list of known hosts.");
0739: }
0740:
0741: String hkh = getConfig("HashKnownHosts");
0742: if (hkh.equals("yes") && (hkr instanceof KnownHosts)) {
0743: hostkey = ((KnownHosts) hkr)
0744: .createHashedHostKey(chost, K_S);
0745: } else {
0746: hostkey = new HostKey(chost, K_S);
0747: }
0748:
0749: if (insert) {
0750: synchronized (hkr) {
0751: hkr.add(hostkey, userinfo);
0752: }
0753:
0754: }
0755:
0756: }
0757:
0758: //public void start(){ (new Thread(this)).start(); }
0759:
0760: public Channel openChannel(String type) throws JSchException {
0761: if (!isConnected) {
0762: throw new JSchException("session is down");
0763: }
0764: try {
0765: Channel channel = Channel.getChannel(type);
0766: addChannel(channel);
0767: channel.init();
0768: return channel;
0769: } catch (Exception e) {
0770: //e.printStackTrace();
0771: }
0772: return null;
0773: }
0774:
0775: // encode will bin invoked in write with synchronization.
0776: public void encode(Packet packet) throws Exception {
0777: //System.err.println("encode: "+packet.buffer.getCommand());
0778: //System.err.println(" "+packet.buffer.index);
0779: //if(packet.buffer.getCommand()==96){
0780: //Thread.dumpStack();
0781: //}
0782: if (deflater != null) {
0783: packet.buffer.index = deflater.compress(
0784: packet.buffer.buffer, 5, packet.buffer.index);
0785: }
0786: if (c2scipher != null) {
0787: //packet.padding(c2scipher.getIVSize());
0788: packet.padding(c2scipher_size);
0789: int pad = packet.buffer.buffer[4];
0790: synchronized (random) {
0791: random.fill(packet.buffer.buffer, packet.buffer.index
0792: - pad, pad);
0793: }
0794: } else {
0795: packet.padding(8);
0796: }
0797:
0798: if (c2smac != null) {
0799: c2smac.update(seqo);
0800: c2smac.update(packet.buffer.buffer, 0, packet.buffer.index);
0801: c2smac.doFinal(packet.buffer.buffer, packet.buffer.index);
0802: }
0803: if (c2scipher != null) {
0804: byte[] buf = packet.buffer.buffer;
0805: c2scipher.update(buf, 0, packet.buffer.index, buf, 0);
0806: }
0807: if (c2smac != null) {
0808: packet.buffer.skip(c2smac.getBlockSize());
0809: }
0810: }
0811:
0812: int[] uncompress_len = new int[1];
0813:
0814: private int s2ccipher_size = 8;
0815: private int c2scipher_size = 8;
0816:
0817: public Buffer read(Buffer buf) throws Exception {
0818: int j = 0;
0819: while (true) {
0820: buf.reset();
0821: io.getByte(buf.buffer, buf.index, s2ccipher_size);
0822: buf.index += s2ccipher_size;
0823: if (s2ccipher != null) {
0824: s2ccipher.update(buf.buffer, 0, s2ccipher_size,
0825: buf.buffer, 0);
0826: }
0827: j = ((buf.buffer[0] << 24) & 0xff000000)
0828: | ((buf.buffer[1] << 16) & 0x00ff0000)
0829: | ((buf.buffer[2] << 8) & 0x0000ff00)
0830: | ((buf.buffer[3]) & 0x000000ff);
0831: // RFC 4253 6.1. Maximum Packet Length
0832: if (j < 5 || j > (32768 - 4)) {
0833: throw new IOException("invalid data");
0834: }
0835: j = j + 4 - s2ccipher_size;
0836: //if(j<0){
0837: // throw new IOException("invalid data");
0838: //}
0839: if ((buf.index + j) > buf.buffer.length) {
0840: byte[] foo = new byte[buf.index + j];
0841: System.arraycopy(buf.buffer, 0, foo, 0, buf.index);
0842: buf.buffer = foo;
0843: }
0844: if (j > 0) {
0845: io.getByte(buf.buffer, buf.index, j);
0846: buf.index += (j);
0847: if (s2ccipher != null) {
0848: s2ccipher.update(buf.buffer, s2ccipher_size, j,
0849: buf.buffer, s2ccipher_size);
0850: }
0851: }
0852:
0853: if (s2cmac != null) {
0854: s2cmac.update(seqi);
0855: s2cmac.update(buf.buffer, 0, buf.index);
0856:
0857: s2cmac.doFinal(s2cmac_result1, 0);
0858: io.getByte(s2cmac_result2, 0, s2cmac_result2.length);
0859: if (!java.util.Arrays.equals(s2cmac_result1,
0860: s2cmac_result2)) {
0861: throw new IOException("MAC Error");
0862: }
0863: }
0864:
0865: seqi++;
0866:
0867: if (inflater != null) {
0868: //inflater.uncompress(buf);
0869: int pad = buf.buffer[4];
0870: uncompress_len[0] = buf.index - 5 - pad;
0871: byte[] foo = inflater.uncompress(buf.buffer, 5,
0872: uncompress_len);
0873: if (foo != null) {
0874: buf.buffer = foo;
0875: buf.index = 5 + uncompress_len[0];
0876: } else {
0877: System.err.println("fail in inflater");
0878: break;
0879: }
0880: }
0881:
0882: int type = buf.getCommand() & 0xff;
0883: //System.err.println("read: "+type);
0884: if (type == SSH_MSG_DISCONNECT) {
0885: buf.rewind();
0886: buf.getInt();
0887: buf.getShort();
0888: int reason_code = buf.getInt();
0889: byte[] description = buf.getString();
0890: byte[] language_tag = buf.getString();
0891: throw new JSchException("SSH_MSG_DISCONNECT:" + " "
0892: + reason_code + " " + new String(description)
0893: + " " + new String(language_tag));
0894: //break;
0895: } else if (type == SSH_MSG_IGNORE) {
0896: } else if (type == SSH_MSG_UNIMPLEMENTED) {
0897: buf.rewind();
0898: buf.getInt();
0899: buf.getShort();
0900: int reason_id = buf.getInt();
0901: if (JSch.getLogger().isEnabled(Logger.INFO)) {
0902: JSch.getLogger().log(
0903: Logger.INFO,
0904: "Received SSH_MSG_UNIMPLEMENTED for "
0905: + reason_id);
0906: }
0907: } else if (type == SSH_MSG_DEBUG) {
0908: buf.rewind();
0909: buf.getInt();
0910: buf.getShort();
0911: /*
0912: byte always_display=(byte)buf.getByte();
0913: byte[] message=buf.getString();
0914: byte[] language_tag=buf.getString();
0915: System.err.println("SSH_MSG_DEBUG:"+
0916: " "+new String(message)+
0917: " "+new String(language_tag));
0918: */
0919: } else if (type == SSH_MSG_CHANNEL_WINDOW_ADJUST) {
0920: buf.rewind();
0921: buf.getInt();
0922: buf.getShort();
0923: Channel c = Channel.getChannel(buf.getInt(), this );
0924: if (c == null) {
0925: } else {
0926: c.addRemoteWindowSize(buf.getInt());
0927: }
0928: } else if (type == 52/*SSH_MSG_USERAUTH_SUCCESS*/) {
0929: isAuthed = true;
0930: if (inflater == null && deflater == null) {
0931: String method;
0932: method = guess[KeyExchange.PROPOSAL_COMP_ALGS_CTOS];
0933: initDeflater(method);
0934:
0935: method = guess[KeyExchange.PROPOSAL_COMP_ALGS_STOC];
0936: initInflater(method);
0937: }
0938: break;
0939: } else {
0940: break;
0941: }
0942: }
0943: buf.rewind();
0944: return buf;
0945: }
0946:
0947: byte[] getSessionId() {
0948: return session_id;
0949: }
0950:
0951: private void receive_newkeys(Buffer buf, KeyExchange kex)
0952: throws Exception {
0953: updateKeys(kex);
0954: in_kex = false;
0955: }
0956:
0957: private void updateKeys(KeyExchange kex) throws Exception {
0958: byte[] K = kex.getK();
0959: byte[] H = kex.getH();
0960: HASH hash = kex.getHash();
0961:
0962: // String[] guess=kex.guess;
0963:
0964: if (session_id == null) {
0965: session_id = new byte[H.length];
0966: System.arraycopy(H, 0, session_id, 0, H.length);
0967: }
0968:
0969: /*
0970: Initial IV client to server: HASH (K || H || "A" || session_id)
0971: Initial IV server to client: HASH (K || H || "B" || session_id)
0972: Encryption key client to server: HASH (K || H || "C" || session_id)
0973: Encryption key server to client: HASH (K || H || "D" || session_id)
0974: Integrity key client to server: HASH (K || H || "E" || session_id)
0975: Integrity key server to client: HASH (K || H || "F" || session_id)
0976: */
0977:
0978: buf.reset();
0979: buf.putMPInt(K);
0980: buf.putByte(H);
0981: buf.putByte((byte) 0x41);
0982: buf.putByte(session_id);
0983: hash.update(buf.buffer, 0, buf.index);
0984: IVc2s = hash.digest();
0985:
0986: int j = buf.index - session_id.length - 1;
0987:
0988: buf.buffer[j]++;
0989: hash.update(buf.buffer, 0, buf.index);
0990: IVs2c = hash.digest();
0991:
0992: buf.buffer[j]++;
0993: hash.update(buf.buffer, 0, buf.index);
0994: Ec2s = hash.digest();
0995:
0996: buf.buffer[j]++;
0997: hash.update(buf.buffer, 0, buf.index);
0998: Es2c = hash.digest();
0999:
1000: buf.buffer[j]++;
1001: hash.update(buf.buffer, 0, buf.index);
1002: MACc2s = hash.digest();
1003:
1004: buf.buffer[j]++;
1005: hash.update(buf.buffer, 0, buf.index);
1006: MACs2c = hash.digest();
1007:
1008: try {
1009: Class c;
1010: String method;
1011:
1012: method = guess[KeyExchange.PROPOSAL_ENC_ALGS_STOC];
1013: c = Class.forName(getConfig(method));
1014: s2ccipher = (Cipher) (c.newInstance());
1015: while (s2ccipher.getBlockSize() > Es2c.length) {
1016: buf.reset();
1017: buf.putMPInt(K);
1018: buf.putByte(H);
1019: buf.putByte(Es2c);
1020: hash.update(buf.buffer, 0, buf.index);
1021: byte[] foo = hash.digest();
1022: byte[] bar = new byte[Es2c.length + foo.length];
1023: System.arraycopy(Es2c, 0, bar, 0, Es2c.length);
1024: System.arraycopy(foo, 0, bar, Es2c.length, foo.length);
1025: Es2c = bar;
1026: }
1027: s2ccipher.init(Cipher.DECRYPT_MODE, Es2c, IVs2c);
1028: s2ccipher_size = s2ccipher.getIVSize();
1029:
1030: method = guess[KeyExchange.PROPOSAL_MAC_ALGS_STOC];
1031: c = Class.forName(getConfig(method));
1032: s2cmac = (MAC) (c.newInstance());
1033: s2cmac.init(MACs2c);
1034: //mac_buf=new byte[s2cmac.getBlockSize()];
1035: s2cmac_result1 = new byte[s2cmac.getBlockSize()];
1036: s2cmac_result2 = new byte[s2cmac.getBlockSize()];
1037:
1038: method = guess[KeyExchange.PROPOSAL_ENC_ALGS_CTOS];
1039: c = Class.forName(getConfig(method));
1040: c2scipher = (Cipher) (c.newInstance());
1041: while (c2scipher.getBlockSize() > Ec2s.length) {
1042: buf.reset();
1043: buf.putMPInt(K);
1044: buf.putByte(H);
1045: buf.putByte(Ec2s);
1046: hash.update(buf.buffer, 0, buf.index);
1047: byte[] foo = hash.digest();
1048: byte[] bar = new byte[Ec2s.length + foo.length];
1049: System.arraycopy(Ec2s, 0, bar, 0, Ec2s.length);
1050: System.arraycopy(foo, 0, bar, Ec2s.length, foo.length);
1051: Ec2s = bar;
1052: }
1053: c2scipher.init(Cipher.ENCRYPT_MODE, Ec2s, IVc2s);
1054: c2scipher_size = c2scipher.getIVSize();
1055:
1056: method = guess[KeyExchange.PROPOSAL_MAC_ALGS_CTOS];
1057: c = Class.forName(getConfig(method));
1058: c2smac = (MAC) (c.newInstance());
1059: c2smac.init(MACc2s);
1060:
1061: method = guess[KeyExchange.PROPOSAL_COMP_ALGS_CTOS];
1062: initDeflater(method);
1063:
1064: method = guess[KeyExchange.PROPOSAL_COMP_ALGS_STOC];
1065: initInflater(method);
1066: } catch (Exception e) {
1067: if (e instanceof JSchException)
1068: throw e;
1069: throw new JSchException(e.toString(), e);
1070: //System.err.println("updatekeys: "+e);
1071: }
1072: }
1073:
1074: /*public*//*synchronized*/void write(Packet packet, Channel c,
1075: int length) throws Exception {
1076: while (true) {
1077: if (in_kex) {
1078: try {
1079: Thread.sleep(10);
1080: } catch (java.lang.InterruptedException e) {
1081: }
1082: ;
1083: continue;
1084: }
1085: synchronized (c) {
1086: if (c.rwsize >= length) {
1087: c.rwsize -= length;
1088: break;
1089: }
1090: }
1091: if (c.close || !c.isConnected()) {
1092: throw new IOException("channel is broken");
1093: }
1094:
1095: boolean sendit = false;
1096: int s = 0;
1097: byte command = 0;
1098: int recipient = -1;
1099: synchronized (c) {
1100: if (c.rwsize > 0) {
1101: int len = c.rwsize;
1102: if (len > length) {
1103: len = length;
1104: }
1105: if (len != length) {
1106: s = packet.shift(len, (c2smac != null ? c2smac
1107: .getBlockSize() : 0));
1108: }
1109: command = packet.buffer.getCommand();
1110: recipient = c.getRecipient();
1111: length -= len;
1112: c.rwsize -= len;
1113: sendit = true;
1114: }
1115: }
1116: if (sendit) {
1117: _write(packet);
1118: if (length == 0) {
1119: return;
1120: }
1121: packet.unshift(command, recipient, s, length);
1122: }
1123:
1124: synchronized (c) {
1125: if (in_kex) {
1126: continue;
1127: }
1128: if (c.rwsize >= length) {
1129: c.rwsize -= length;
1130: break;
1131: }
1132: try {
1133: c.notifyme++;
1134: c.wait(100);
1135: } catch (java.lang.InterruptedException e) {
1136: } finally {
1137: c.notifyme--;
1138: }
1139: }
1140:
1141: }
1142: _write(packet);
1143: }
1144:
1145: public void write(Packet packet) throws Exception {
1146: // System.err.println("in_kex="+in_kex+" "+(packet.buffer.getCommand()));
1147: while (in_kex) {
1148: byte command = packet.buffer.getCommand();
1149: //System.err.println("command: "+command);
1150: if (command == SSH_MSG_KEXINIT
1151: || command == SSH_MSG_NEWKEYS
1152: || command == SSH_MSG_KEXDH_INIT
1153: || command == SSH_MSG_KEXDH_REPLY
1154: || command == SSH_MSG_KEX_DH_GEX_GROUP
1155: || command == SSH_MSG_KEX_DH_GEX_INIT
1156: || command == SSH_MSG_KEX_DH_GEX_REPLY
1157: || command == SSH_MSG_KEX_DH_GEX_REQUEST
1158: || command == SSH_MSG_DISCONNECT) {
1159: break;
1160: }
1161: try {
1162: Thread.sleep(10);
1163: } catch (java.lang.InterruptedException e) {
1164: }
1165: ;
1166: }
1167: _write(packet);
1168: }
1169:
1170: private synchronized void _write(Packet packet) throws Exception {
1171: encode(packet);
1172: if (io != null) {
1173: io.put(packet);
1174: seqo++;
1175: }
1176: }
1177:
1178: Runnable thread;
1179:
1180: public void run() {
1181: thread = this ;
1182:
1183: byte[] foo;
1184: Buffer buf = new Buffer();
1185: Packet packet = new Packet(buf);
1186: int i = 0;
1187: Channel channel;
1188: int[] start = new int[1];
1189: int[] length = new int[1];
1190: KeyExchange kex = null;
1191:
1192: int stimeout = 0;
1193: try {
1194: while (isConnected && thread != null) {
1195: try {
1196: buf = read(buf);
1197: stimeout = 0;
1198: } catch (InterruptedIOException/*SocketTimeoutException*/ee) {
1199: if (!in_kex && stimeout < serverAliveCountMax) {
1200: sendKeepAliveMsg();
1201: stimeout++;
1202: continue;
1203: }
1204: throw ee;
1205: }
1206:
1207: int msgType = buf.getCommand() & 0xff;
1208:
1209: if (kex != null && kex.getState() == msgType) {
1210: boolean result = kex.next(buf);
1211: if (!result) {
1212: throw new JSchException("verify: " + result);
1213: }
1214: continue;
1215: }
1216:
1217: switch (msgType) {
1218: case SSH_MSG_KEXINIT:
1219: //System.err.println("KEXINIT");
1220: kex = receive_kexinit(buf);
1221: break;
1222:
1223: case SSH_MSG_NEWKEYS:
1224: //System.err.println("NEWKEYS");
1225: send_newkeys();
1226: receive_newkeys(buf, kex);
1227: kex = null;
1228: break;
1229:
1230: case SSH_MSG_CHANNEL_DATA:
1231: buf.getInt();
1232: buf.getByte();
1233: buf.getByte();
1234: i = buf.getInt();
1235: channel = Channel.getChannel(i, this );
1236: foo = buf.getString(start, length);
1237: if (channel == null) {
1238: break;
1239: }
1240:
1241: if (length[0] == 0) {
1242: break;
1243: }
1244:
1245: try {
1246: channel.write(foo, start[0], length[0]);
1247: } catch (Exception e) {
1248: //System.err.println(e);
1249: try {
1250: channel.disconnect();
1251: } catch (Exception ee) {
1252: }
1253: break;
1254: }
1255: int len = length[0];
1256: channel.setLocalWindowSize(channel.lwsize - len);
1257: if (channel.lwsize < channel.lwsize_max / 2) {
1258: packet.reset();
1259: buf
1260: .putByte((byte) SSH_MSG_CHANNEL_WINDOW_ADJUST);
1261: buf.putInt(channel.getRecipient());
1262: buf.putInt(channel.lwsize_max - channel.lwsize);
1263: write(packet);
1264: channel.setLocalWindowSize(channel.lwsize_max);
1265: }
1266: break;
1267:
1268: case SSH_MSG_CHANNEL_EXTENDED_DATA:
1269: buf.getInt();
1270: buf.getShort();
1271: i = buf.getInt();
1272: channel = Channel.getChannel(i, this );
1273: buf.getInt(); // data_type_code == 1
1274: foo = buf.getString(start, length);
1275: //System.err.println("stderr: "+new String(foo,start[0],length[0]));
1276: if (channel == null) {
1277: break;
1278: }
1279:
1280: if (length[0] == 0) {
1281: break;
1282: }
1283:
1284: channel.write_ext(foo, start[0], length[0]);
1285:
1286: len = length[0];
1287: channel.setLocalWindowSize(channel.lwsize - len);
1288: if (channel.lwsize < channel.lwsize_max / 2) {
1289: packet.reset();
1290: buf
1291: .putByte((byte) SSH_MSG_CHANNEL_WINDOW_ADJUST);
1292: buf.putInt(channel.getRecipient());
1293: buf.putInt(channel.lwsize_max - channel.lwsize);
1294: write(packet);
1295: channel.setLocalWindowSize(channel.lwsize_max);
1296: }
1297: break;
1298:
1299: case SSH_MSG_CHANNEL_WINDOW_ADJUST:
1300: buf.getInt();
1301: buf.getShort();
1302: i = buf.getInt();
1303: channel = Channel.getChannel(i, this );
1304: if (channel == null) {
1305: break;
1306: }
1307: channel.addRemoteWindowSize(buf.getInt());
1308: break;
1309:
1310: case SSH_MSG_CHANNEL_EOF:
1311: buf.getInt();
1312: buf.getShort();
1313: i = buf.getInt();
1314: channel = Channel.getChannel(i, this );
1315: if (channel != null) {
1316: //channel.eof_remote=true;
1317: //channel.eof();
1318: channel.eof_remote();
1319: }
1320: /*
1321: packet.reset();
1322: buf.putByte((byte)SSH_MSG_CHANNEL_EOF);
1323: buf.putInt(channel.getRecipient());
1324: write(packet);
1325: */
1326: break;
1327: case SSH_MSG_CHANNEL_CLOSE:
1328: buf.getInt();
1329: buf.getShort();
1330: i = buf.getInt();
1331: channel = Channel.getChannel(i, this );
1332: if (channel != null) {
1333: // channel.close();
1334: channel.disconnect();
1335: }
1336: /*
1337: if(Channel.pool.size()==0){
1338: thread=null;
1339: }
1340: */
1341: break;
1342: case SSH_MSG_CHANNEL_OPEN_CONFIRMATION:
1343: buf.getInt();
1344: buf.getShort();
1345: i = buf.getInt();
1346: channel = Channel.getChannel(i, this );
1347: if (channel == null) {
1348: //break;
1349: }
1350: int r = buf.getInt();
1351: int rws = buf.getInt();
1352: int rps = buf.getInt();
1353:
1354: channel.setRemoteWindowSize(rws);
1355: channel.setRemotePacketSize(rps);
1356: channel.setRecipient(r);
1357: break;
1358: case SSH_MSG_CHANNEL_OPEN_FAILURE:
1359: buf.getInt();
1360: buf.getShort();
1361: i = buf.getInt();
1362: channel = Channel.getChannel(i, this );
1363: if (channel == null) {
1364: //break;
1365: }
1366: int reason_code = buf.getInt();
1367: //foo=buf.getString(); // additional textual information
1368: //foo=buf.getString(); // language tag
1369: channel.exitstatus = reason_code;
1370: channel.close = true;
1371: channel.eof_remote = true;
1372: channel.setRecipient(0);
1373: break;
1374: case SSH_MSG_CHANNEL_REQUEST:
1375: buf.getInt();
1376: buf.getShort();
1377: i = buf.getInt();
1378: foo = buf.getString();
1379: boolean reply = (buf.getByte() != 0);
1380: channel = Channel.getChannel(i, this );
1381: if (channel != null) {
1382: byte reply_type = (byte) SSH_MSG_CHANNEL_FAILURE;
1383: if ((new String(foo)).equals("exit-status")) {
1384: i = buf.getInt(); // exit-status
1385: channel.setExitStatus(i);
1386: // System.err.println("exit-stauts: "+i);
1387: // channel.close();
1388: reply_type = (byte) SSH_MSG_CHANNEL_SUCCESS;
1389: }
1390: if (reply) {
1391: packet.reset();
1392: buf.putByte(reply_type);
1393: buf.putInt(channel.getRecipient());
1394: write(packet);
1395: }
1396: } else {
1397: }
1398: break;
1399: case SSH_MSG_CHANNEL_OPEN:
1400: buf.getInt();
1401: buf.getShort();
1402: foo = buf.getString();
1403: String ctyp = new String(foo);
1404: if (!"forwarded-tcpip".equals(ctyp)
1405: && !("x11".equals(ctyp) && x11_forwarding)
1406: && !("auth-agent@openssh.com".equals(ctyp) && agent_forwarding)) {
1407: //System.err.println("Session.run: CHANNEL OPEN "+ctyp);
1408: //throw new IOException("Session.run: CHANNEL OPEN "+ctyp);
1409: packet.reset();
1410: buf
1411: .putByte((byte) SSH_MSG_CHANNEL_OPEN_FAILURE);
1412: buf.putInt(buf.getInt());
1413: buf
1414: .putInt(Channel.SSH_OPEN_ADMINISTRATIVELY_PROHIBITED);
1415: buf.putString("".getBytes());
1416: buf.putString("".getBytes());
1417: write(packet);
1418: } else {
1419: channel = Channel.getChannel(ctyp);
1420: addChannel(channel);
1421: channel.getData(buf);
1422: channel.init();
1423:
1424: Thread tmp = new Thread(channel);
1425: tmp.setName("Channel " + ctyp + " " + host);
1426: if (daemon_thread) {
1427: tmp.setDaemon(daemon_thread);
1428: }
1429: tmp.start();
1430: break;
1431: }
1432: case SSH_MSG_CHANNEL_SUCCESS:
1433: buf.getInt();
1434: buf.getShort();
1435: i = buf.getInt();
1436: channel = Channel.getChannel(i, this );
1437: if (channel == null) {
1438: break;
1439: }
1440: channel.reply = 1;
1441: break;
1442: case SSH_MSG_CHANNEL_FAILURE:
1443: buf.getInt();
1444: buf.getShort();
1445: i = buf.getInt();
1446: channel = Channel.getChannel(i, this );
1447: if (channel == null) {
1448: break;
1449: }
1450: channel.reply = 0;
1451: break;
1452: case SSH_MSG_GLOBAL_REQUEST:
1453: buf.getInt();
1454: buf.getShort();
1455: foo = buf.getString(); // request name
1456: reply = (buf.getByte() != 0);
1457: if (reply) {
1458: packet.reset();
1459: buf.putByte((byte) SSH_MSG_REQUEST_FAILURE);
1460: write(packet);
1461: }
1462: break;
1463: case SSH_MSG_REQUEST_FAILURE:
1464: case SSH_MSG_REQUEST_SUCCESS:
1465: Thread t = grr.getThread();
1466: if (t != null) {
1467: grr
1468: .setReply(msgType == SSH_MSG_REQUEST_SUCCESS ? 1
1469: : 0);
1470: t.interrupt();
1471: }
1472: break;
1473: default:
1474: //System.err.println("Session.run: unsupported type "+msgType);
1475: throw new IOException("Unknown SSH message type "
1476: + msgType);
1477: }
1478: }
1479: } catch (Exception e) {
1480: if (JSch.getLogger().isEnabled(Logger.INFO)) {
1481: JSch.getLogger().log(
1482: Logger.INFO,
1483: "Caught an exception, leaving main loop due to "
1484: + e.getMessage());
1485: }
1486: //System.err.println("# Session.run");
1487: //e.printStackTrace();
1488: }
1489: try {
1490: disconnect();
1491: } catch (NullPointerException e) {
1492: //System.err.println("@1");
1493: //e.printStackTrace();
1494: } catch (Exception e) {
1495: //System.err.println("@2");
1496: //e.printStackTrace();
1497: }
1498: isConnected = false;
1499: }
1500:
1501: public void disconnect() {
1502: if (!isConnected)
1503: return;
1504: //System.err.println(this+": disconnect");
1505: //Thread.dumpStack();
1506: if (JSch.getLogger().isEnabled(Logger.INFO)) {
1507: JSch.getLogger().log(Logger.INFO,
1508: "Disconnecting from " + host + " port " + port);
1509: }
1510: /*
1511: for(int i=0; i<Channel.pool.size(); i++){
1512: try{
1513: Channel c=((Channel)(Channel.pool.elementAt(i)));
1514: if(c.session==this) c.eof();
1515: }
1516: catch(Exception e){
1517: }
1518: }
1519: */
1520:
1521: Channel.disconnect(this );
1522:
1523: isConnected = false;
1524:
1525: PortWatcher.delPort(this );
1526: ChannelForwardedTCPIP.delPort(this );
1527:
1528: synchronized (connectThread) {
1529: Thread.yield();
1530: connectThread.interrupt();
1531: connectThread = null;
1532: }
1533: thread = null;
1534: try {
1535: if (io != null) {
1536: if (io.in != null)
1537: io.in.close();
1538: if (io.out != null)
1539: io.out.close();
1540: if (io.out_ext != null)
1541: io.out_ext.close();
1542: }
1543: if (proxy == null) {
1544: if (socket != null)
1545: socket.close();
1546: } else {
1547: synchronized (proxy) {
1548: proxy.close();
1549: }
1550: proxy = null;
1551: }
1552: } catch (Exception e) {
1553: // e.printStackTrace();
1554: }
1555: io = null;
1556: socket = null;
1557: // synchronized(jsch.pool){
1558: // jsch.pool.removeElement(this);
1559: // }
1560:
1561: jsch.removeSession(this );
1562:
1563: //System.gc();
1564: }
1565:
1566: public int setPortForwardingL(int lport, String host, int rport)
1567: throws JSchException {
1568: return setPortForwardingL("127.0.0.1", lport, host, rport);
1569: }
1570:
1571: public int setPortForwardingL(String boundaddress, int lport,
1572: String host, int rport) throws JSchException {
1573: return setPortForwardingL(boundaddress, lport, host, rport,
1574: null);
1575: }
1576:
1577: public int setPortForwardingL(String boundaddress, int lport,
1578: String host, int rport, ServerSocketFactory ssf)
1579: throws JSchException {
1580: PortWatcher pw = PortWatcher.addPort(this , boundaddress, lport,
1581: host, rport, ssf);
1582: Thread tmp = new Thread(pw);
1583: tmp.setName("PortWatcher Thread for " + host);
1584: if (daemon_thread) {
1585: tmp.setDaemon(daemon_thread);
1586: }
1587: tmp.start();
1588: return pw.lport;
1589: }
1590:
1591: public void delPortForwardingL(int lport) throws JSchException {
1592: delPortForwardingL("127.0.0.1", lport);
1593: }
1594:
1595: public void delPortForwardingL(String boundaddress, int lport)
1596: throws JSchException {
1597: PortWatcher.delPort(this , boundaddress, lport);
1598: }
1599:
1600: public String[] getPortForwardingL() throws JSchException {
1601: return PortWatcher.getPortForwarding(this );
1602: }
1603:
1604: public void setPortForwardingR(int rport, String host, int lport)
1605: throws JSchException {
1606: setPortForwardingR(null, rport, host, lport,
1607: (SocketFactory) null);
1608: }
1609:
1610: public void setPortForwardingR(String bind_address, int rport,
1611: String host, int lport) throws JSchException {
1612: setPortForwardingR(bind_address, rport, host, lport,
1613: (SocketFactory) null);
1614: }
1615:
1616: public void setPortForwardingR(int rport, String host, int lport,
1617: SocketFactory sf) throws JSchException {
1618: setPortForwardingR(null, rport, host, lport, sf);
1619: }
1620:
1621: public void setPortForwardingR(String bind_address, int rport,
1622: String host, int lport, SocketFactory sf)
1623: throws JSchException {
1624: ChannelForwardedTCPIP.addPort(this , rport, host, lport, sf);
1625: setPortForwarding(bind_address, rport);
1626: }
1627:
1628: public void setPortForwardingR(int rport, String daemon)
1629: throws JSchException {
1630: setPortForwardingR(null, rport, daemon, null);
1631: }
1632:
1633: public void setPortForwardingR(int rport, String daemon,
1634: Object[] arg) throws JSchException {
1635: setPortForwardingR(null, rport, daemon, arg);
1636: }
1637:
1638: public void setPortForwardingR(String bind_address, int rport,
1639: String daemon, Object[] arg) throws JSchException {
1640: ChannelForwardedTCPIP.addPort(this , rport, daemon, arg);
1641: setPortForwarding(bind_address, rport);
1642: }
1643:
1644: private class GlobalRequestReply {
1645: private Thread thread = null;
1646: private int reply = -1;
1647:
1648: void setThread(Thread thread) {
1649: this .thread = thread;
1650: this .reply = -1;
1651: }
1652:
1653: Thread getThread() {
1654: return thread;
1655: }
1656:
1657: void setReply(int reply) {
1658: this .reply = reply;
1659: }
1660:
1661: int getReply() {
1662: return this .reply;
1663: }
1664: }
1665:
1666: private GlobalRequestReply grr = new GlobalRequestReply();
1667:
1668: private void setPortForwarding(String bind_address, int rport)
1669: throws JSchException {
1670: synchronized (grr) {
1671: Buffer buf = new Buffer(100); // ??
1672: Packet packet = new Packet(buf);
1673:
1674: String address_to_bind = "localhost";
1675: if (bind_address == null) {
1676: //address_to_bind="localhost";
1677: } else if (bind_address.length() == 0
1678: || bind_address.equals("*")) {
1679: address_to_bind = "";
1680: } else {
1681: address_to_bind = bind_address;
1682: }
1683:
1684: try {
1685: // byte SSH_MSG_GLOBAL_REQUEST 80
1686: // string "tcpip-forward"
1687: // boolean want_reply
1688: // string address_to_bind
1689: // uint32 port number to bind
1690: packet.reset();
1691: buf.putByte((byte) SSH_MSG_GLOBAL_REQUEST);
1692: buf.putString("tcpip-forward".getBytes());
1693: // buf.putByte((byte)0);
1694: buf.putByte((byte) 1);
1695: buf.putString(address_to_bind.getBytes());
1696: //buf.putString("0.0.0.0".getBytes());
1697: buf.putInt(rport);
1698: write(packet);
1699: } catch (Exception e) {
1700: if (e instanceof Throwable)
1701: throw new JSchException(e.toString(), (Throwable) e);
1702: throw new JSchException(e.toString());
1703: }
1704:
1705: grr.setThread(Thread.currentThread());
1706: try {
1707: Thread.sleep(10000);
1708: } catch (Exception e) {
1709: }
1710: int reply = grr.getReply();
1711: grr.setThread(null);
1712: if (reply == 0) {
1713: throw new JSchException(
1714: "remote port forwarding failed for listen port "
1715: + rport);
1716: }
1717: }
1718: }
1719:
1720: public void delPortForwardingR(int rport) throws JSchException {
1721: ChannelForwardedTCPIP.delPort(this , rport);
1722: }
1723:
1724: private void initDeflater(String method) throws JSchException {
1725: if (method.equals("none")) {
1726: deflater = null;
1727: return;
1728: }
1729: String foo = getConfig(method);
1730: if (foo != null) {
1731: if (method.equals("zlib")
1732: || (isAuthed && method.equals("zlib@openssh.com"))) {
1733: try {
1734: Class c = Class.forName(foo);
1735: deflater = (Compression) (c.newInstance());
1736: int level = 6;
1737: try {
1738: level = Integer
1739: .parseInt(getConfig("compression_level"));
1740: } catch (Exception ee) {
1741: }
1742: deflater.init(Compression.DEFLATER, level);
1743: } catch (Exception ee) {
1744: throw new JSchException(ee.toString(), ee);
1745: //System.err.println(foo+" isn't accessible.");
1746: }
1747: }
1748: }
1749: }
1750:
1751: private void initInflater(String method) throws JSchException {
1752: if (method.equals("none")) {
1753: inflater = null;
1754: return;
1755: }
1756: String foo = getConfig(method);
1757: if (foo != null) {
1758: if (method.equals("zlib")
1759: || (isAuthed && method.equals("zlib@openssh.com"))) {
1760: try {
1761: Class c = Class.forName(foo);
1762: inflater = (Compression) (c.newInstance());
1763: inflater.init(Compression.INFLATER, 0);
1764: } catch (Exception ee) {
1765: throw new JSchException(ee.toString(), ee);
1766: //System.err.println(foo+" isn't accessible.");
1767: }
1768: }
1769: }
1770: }
1771:
1772: void addChannel(Channel channel) {
1773: channel.session = this ;
1774: }
1775:
1776: // public Channel getChannel(){ return channel; }
1777: public void setProxy(Proxy proxy) {
1778: this .proxy = proxy;
1779: }
1780:
1781: public void setHost(String host) {
1782: this .host = host;
1783: }
1784:
1785: public void setPort(int port) {
1786: this .port = port;
1787: }
1788:
1789: void setUserName(String username) {
1790: this .username = username;
1791: }
1792:
1793: public void setUserInfo(UserInfo userinfo) {
1794: this .userinfo = userinfo;
1795: }
1796:
1797: public UserInfo getUserInfo() {
1798: return userinfo;
1799: }
1800:
1801: public void setInputStream(InputStream in) {
1802: this .in = in;
1803: }
1804:
1805: public void setOutputStream(OutputStream out) {
1806: this .out = out;
1807: }
1808:
1809: public void setX11Host(String host) {
1810: ChannelX11.setHost(host);
1811: }
1812:
1813: public void setX11Port(int port) {
1814: ChannelX11.setPort(port);
1815: }
1816:
1817: public void setX11Cookie(String cookie) {
1818: ChannelX11.setCookie(cookie);
1819: }
1820:
1821: public void setPassword(String password) {
1822: if (password != null)
1823: this .password = Util.str2byte(password);
1824: }
1825:
1826: public void setPassword(byte[] password) {
1827: if (password != null) {
1828: this .password = new byte[password.length];
1829: System.arraycopy(password, 0, this .password, 0,
1830: password.length);
1831: }
1832: }
1833:
1834: public void setConfig(java.util.Properties newconf) {
1835: setConfig((java.util.Hashtable) newconf);
1836: }
1837:
1838: public synchronized void setConfig(java.util.Hashtable newconf) {
1839: if (config == null)
1840: config = new java.util.Hashtable();
1841: for (java.util.Enumeration e = newconf.keys(); e
1842: .hasMoreElements();) {
1843: String key = (String) (e.nextElement());
1844: config.put(key, (String) (newconf.get(key)));
1845: }
1846: }
1847:
1848: public synchronized void setConfig(String key, String value) {
1849: if (config == null) {
1850: config = new java.util.Hashtable();
1851: }
1852: config.put(key, value);
1853: }
1854:
1855: public String getConfig(String key) {
1856: Object foo = null;
1857: if (config != null) {
1858: foo = config.get(key);
1859: if (foo instanceof String)
1860: return (String) foo;
1861: }
1862: foo = jsch.getConfig(key);
1863: if (foo instanceof String)
1864: return (String) foo;
1865: return null;
1866: }
1867:
1868: public void setSocketFactory(SocketFactory sfactory) {
1869: socket_factory = sfactory;
1870: }
1871:
1872: public boolean isConnected() {
1873: return isConnected;
1874: }
1875:
1876: public int getTimeout() {
1877: return timeout;
1878: }
1879:
1880: public void setTimeout(int timeout) throws JSchException {
1881: if (socket == null) {
1882: if (timeout < 0) {
1883: throw new JSchException("invalid timeout value");
1884: }
1885: this .timeout = timeout;
1886: return;
1887: }
1888: try {
1889: socket.setSoTimeout(timeout);
1890: this .timeout = timeout;
1891: } catch (Exception e) {
1892: if (e instanceof Throwable)
1893: throw new JSchException(e.toString(), (Throwable) e);
1894: throw new JSchException(e.toString());
1895: }
1896: }
1897:
1898: public String getServerVersion() {
1899: return new String(V_S);
1900: }
1901:
1902: public String getClientVersion() {
1903: return new String(V_C);
1904: }
1905:
1906: public void setClientVersion(String cv) {
1907: V_C = cv.getBytes();
1908: }
1909:
1910: public void sendIgnore() throws Exception {
1911: Buffer buf = new Buffer();
1912: Packet packet = new Packet(buf);
1913: packet.reset();
1914: buf.putByte((byte) SSH_MSG_IGNORE);
1915: write(packet);
1916: }
1917:
1918: private static final byte[] keepalivemsg = "keepalive@jcraft.com"
1919: .getBytes();
1920:
1921: public void sendKeepAliveMsg() throws Exception {
1922: Buffer buf = new Buffer();
1923: Packet packet = new Packet(buf);
1924: packet.reset();
1925: buf.putByte((byte) SSH_MSG_GLOBAL_REQUEST);
1926: buf.putString(keepalivemsg);
1927: buf.putByte((byte) 1);
1928: write(packet);
1929: }
1930:
1931: private HostKey hostkey = null;
1932:
1933: public HostKey getHostKey() {
1934: return hostkey;
1935: }
1936:
1937: public String getHost() {
1938: return host;
1939: }
1940:
1941: public String getUserName() {
1942: return username;
1943: }
1944:
1945: public int getPort() {
1946: return port;
1947: }
1948:
1949: public void setHostKeyAlias(String hostKeyAlias) {
1950: this .hostKeyAlias = hostKeyAlias;
1951: }
1952:
1953: public String getHostKeyAlias() {
1954: return hostKeyAlias;
1955: }
1956:
1957: public void setServerAliveInterval(int interval)
1958: throws JSchException {
1959: setTimeout(interval);
1960: this .serverAliveInterval = interval;
1961: }
1962:
1963: public void setServerAliveCountMax(int count) {
1964: this .serverAliveCountMax = count;
1965: }
1966:
1967: public void setDaemonThread(boolean enable) {
1968: this .daemon_thread = enable;
1969: }
1970:
1971: private String[] checkCiphers(String ciphers) {
1972: if (ciphers == null || ciphers.length() == 0)
1973: return null;
1974:
1975: if (JSch.getLogger().isEnabled(Logger.INFO)) {
1976: JSch.getLogger().log(Logger.INFO,
1977: "CheckCiphers: " + ciphers);
1978: }
1979:
1980: java.util.Vector result = new java.util.Vector();
1981: String[] _ciphers = Util.split(ciphers, ",");
1982: for (int i = 0; i < _ciphers.length; i++) {
1983: try {
1984: Class c = Class.forName(getConfig(_ciphers[i]));
1985: Cipher _c = (Cipher) (c.newInstance());
1986: _c.init(Cipher.ENCRYPT_MODE,
1987: new byte[_c.getBlockSize()], new byte[_c
1988: .getIVSize()]);
1989: } catch (Exception e) {
1990: result.addElement(_ciphers[i]);
1991: }
1992: }
1993: if (result.size() == 0)
1994: return null;
1995: String[] foo = new String[result.size()];
1996: System.arraycopy(result.toArray(), 0, foo, 0, result.size());
1997:
1998: if (JSch.getLogger().isEnabled(Logger.INFO)) {
1999: for (int i = 0; i < foo.length; i++) {
2000: JSch.getLogger().log(Logger.INFO,
2001: foo[i] + " is not available.");
2002: }
2003: }
2004:
2005: return foo;
2006: }
2007: }
|