blob: 54bf41fa408eb921e35160ec63e4c16f0333fb62 [file] [log] [blame]
/* -*-mode:java; c-basic-offset:2; -*- */
/*******************************************************************************
* Copyright (c) 2003, Atsuhiko Yamanaka, JCraft,Inc. and others. All rights
* reserved. This program and the accompanying materials are made available
* under the terms of the Common Public License v1.0 which accompanies this
* distribution, and is available at http://www.eclipse.org/legal/cpl-v10.html
*
* Contributors: Atsuhiko Yamanaka, JCraft,Inc. - initial API and
* implementation.
******************************************************************************/
package org.eclipse.team.internal.ccvs.ssh2;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.Enumeration;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.Platform;
import org.eclipse.jface.preference.IPreferenceStore;
import org.eclipse.team.internal.ccvs.core.CVSException;
import org.eclipse.team.internal.ccvs.core.CVSProviderPlugin;
import org.eclipse.team.internal.ccvs.core.ICVSRepositoryLocation;
import org.eclipse.team.internal.ccvs.core.IUserAuthenticator;
import org.eclipse.team.internal.ccvs.core.IUserInfo;
import org.eclipse.team.internal.ccvs.core.connection.CVSRepositoryLocation;
import org.eclipse.team.internal.ccvs.core.util.Util;
import com.jcraft.jsch.JSch;
import com.jcraft.jsch.JSchException;
import com.jcraft.jsch.Proxy;
import com.jcraft.jsch.ProxyHTTP;
import com.jcraft.jsch.ProxySOCKS5;
import com.jcraft.jsch.Session;
import com.jcraft.jsch.SocketFactory;
import com.jcraft.jsch.UIKeyboardInteractive;
import com.jcraft.jsch.UserInfo;
class JSchSession {
private static final int SSH_DEFAULT_PORT = 22;
private static JSch jsch=new JSch();
private static java.util.Hashtable pool = new java.util.Hashtable();
static String default_ssh_home = null;
static {
String ssh_dir_name = ".ssh"; //$NON-NLS-1$
// Windows doesn't like files or directories starting with a dot.
if (Platform.getOS().equals(Platform.OS_WIN32)) {
ssh_dir_name = "ssh"; //$NON-NLS-1$
}
default_ssh_home = System.getProperty("user.home"); //$NON-NLS-1$
if (default_ssh_home != null) {
default_ssh_home = default_ssh_home + java.io.File.separator + ssh_dir_name;
} else {
}
}
private static String current_ssh_home = null;
public static class SimpleSocketFactory implements SocketFactory {
InputStream in = null;
OutputStream out = null;
public Socket createSocket(String host, int port) throws IOException, UnknownHostException {
Socket socket = null;
socket = new Socket(host, port);
return socket;
}
public InputStream getInputStream(Socket socket) throws IOException {
if (in == null)
in = socket.getInputStream();
return in;
}
public OutputStream getOutputStream(Socket socket) throws IOException {
if (out == null)
out = socket.getOutputStream();
return out;
}
}
public static class ResponsiveSocketFacory extends SimpleSocketFactory {
private IProgressMonitor monitor;
public ResponsiveSocketFacory(IProgressMonitor monitor) {
this.monitor = monitor;
}
public Socket createSocket(String host, int port) throws IOException, UnknownHostException {
Socket socket = null;
socket = Util.createSocket(host, port, monitor);
// Null out the monitor so we don't hold onto anything
// (i.e. the SSH2 session will keep a handle to the socket factory around
monitor = new NullProgressMonitor();
// Set the socket timeout
socket.setSoTimeout(CVSProviderPlugin.getPlugin().getTimeout() * 1000);
return socket;
}
}
/**
* User information delegates to the IUserAuthenticator. This allows
* headless access to the connection method.
*/
private static class MyUserInfo implements UserInfo, UIKeyboardInteractive {
private String username;
private String password;
private String passphrase;
private ICVSRepositoryLocation location;
private IUserAuthenticator authenticator;
MyUserInfo(String username, ICVSRepositoryLocation location) {
this.location = location;
this.username = username;
ICVSRepositoryLocation _location=location;
if(_location==null){
String dummy=":extssh:dummy@dummy:/"; //$NON-NLS-1$
try{
_location=CVSRepositoryLocation.fromString(dummy);
}
catch(CVSException e){
}
}
authenticator = _location.getUserAuthenticator();
}
public String getPassword() {
return password;
}
public String getPassphrase() {
return passphrase;
}
public boolean promptYesNo(String str) {
int prompt = authenticator.prompt(
location,
IUserAuthenticator.QUESTION,
Policy.bind("JSchSession.5"), //$NON-NLS-1$
str,
new int[] {IUserAuthenticator.YES_ID, IUserAuthenticator.NO_ID},
0 //yes the default
);
return prompt == 0;
}
private String promptSecret(String message, boolean includeLocation) throws CVSException{
final String[] _password = new String[1];
IUserInfo info = new IUserInfo() {
public String getUsername() {
return username;
}
public boolean isUsernameMutable() {
return false;
}
public void setPassword(String password) {
_password[0] = password;
}
public void setUsername(String username) {
}
};
authenticator.promptForUserInfo(includeLocation ? location : null, info, message);
return _password[0];
}
public boolean promptPassphrase(String message) {
try{
String _passphrase=promptSecret(message, false);
if(_passphrase!=null){
passphrase=_passphrase;
}
return _passphrase!=null;
}
catch(CVSException e){
return false;
}
}
public boolean promptPassword(String message) {
try{
String _password=promptSecret(message, true);
if(_password!=null){
password=_password;
// Cache the password with the repository location on the memory.
if(location!=null)
((CVSRepositoryLocation)location).setPassword(password);
}
return _password!=null;
}
catch(CVSException e){
return false;
}
}
public void showMessage(String message) {
authenticator.prompt(
location,
IUserAuthenticator.INFORMATION,
Policy.bind("JSchSession.5"), //$NON-NLS-1$
message,
new int[] {IUserAuthenticator.OK_ID},
IUserAuthenticator.OK_ID
);
}
public String[] promptKeyboardInteractive(String destination,
String name,
String instruction,
String[] prompt,
boolean[] echo){
try{
String[] result=
authenticator.promptForKeyboradInteractive(location,
destination,
name,
instruction,
prompt,
echo);
return result;
}
catch(CVSException e){
return null;
}
}
}
static Session getSession(ICVSRepositoryLocation location, String username, String password, String hostname, int port, SocketFactory socketFactory) throws JSchException {
if (port == 0)
port = SSH_DEFAULT_PORT;
IPreferenceStore store = CVSSSH2Plugin.getDefault().getPreferenceStore();
String ssh_home = store.getString(CVSSSH2PreferencePage.KEY_SSH2HOME);
if (current_ssh_home == null || !current_ssh_home.equals(ssh_home)) {
current_ssh_home = ssh_home;
if (ssh_home.length() == 0)
ssh_home = default_ssh_home;
try {
java.io.File file;
file=new java.io.File(ssh_home, "known_hosts"); //$NON-NLS-1$
jsch.setKnownHosts(file.getPath());
String pkeys=store.getString(CVSSSH2PreferencePage.KEY_PRIVATEKEY);
String[] pkey=pkeys.split(","); //$NON-NLS-1$
for(int i=0; i<pkey.length;i++){
file = new java.io.File(ssh_home, pkey[i]);
if (file.exists())
jsch.addIdentity(file.getPath());
}
} catch (Exception e) {
}
}
String key = username + "@" + hostname + ":" + port; //$NON-NLS-1$ //$NON-NLS-2$
try {
Session session = (Session) pool.get(key);
if (session != null && !session.isConnected()) {
pool.remove(key);
session = null;
}
if (session == null) {
session = jsch.getSession(username, hostname, port);
boolean useProxy = store.getString(CVSSSH2PreferencePage.KEY_PROXY).equals("true"); //$NON-NLS-1$
if (useProxy) {
String _type = store.getString(CVSSSH2PreferencePage.KEY_PROXY_TYPE);
String _host = store.getString(CVSSSH2PreferencePage.KEY_PROXY_HOST);
String _port = store.getString(CVSSSH2PreferencePage.KEY_PROXY_PORT);
boolean useAuth = store.getString(CVSSSH2PreferencePage.KEY_PROXY_AUTH).equals("true"); //$NON-NLS-1$
String _user = store.getString(CVSSSH2PreferencePage.KEY_PROXY_USER);
String _pass = store.getString(CVSSSH2PreferencePage.KEY_PROXY_PASS);
Proxy proxy = null;
String proxyhost = _host + ":" + _port; //$NON-NLS-1$
if (_type.equals(CVSSSH2PreferencePage.HTTP)) {
proxy = new ProxyHTTP(proxyhost);
if (useAuth) {
((ProxyHTTP) proxy).setUserPasswd(_user, _pass);
}
} else if (_type.equals(CVSSSH2PreferencePage.SOCKS5)) {
proxy = new ProxySOCKS5(proxyhost);
if (useAuth) {
((ProxySOCKS5) proxy).setUserPasswd(_user, _pass);
}
} else {
proxy = null;
}
if (proxy != null) {
session.setProxy(proxy);
}
}
session.setPassword(password);
UserInfo ui = new MyUserInfo(username, location);
session.setUserInfo(ui);
session.setSocketFactory(socketFactory);
session.connect();
pool.put(key, session);
}
return session;
} catch (JSchException e) {
pool.remove(key);
throw e;
}
}
static void shutdown() {
if (jsch != null && pool.size() > 0) {
for (Enumeration e = pool.elements(); e.hasMoreElements(); ) {
Session session = (Session) (e.nextElement());
try {
session.disconnect();
} catch (Exception ee) {
}
}
pool.clear();
}
}
static JSch getJSch(){
return jsch;
}
}