blob: 54620e137e03a3759577c649f3a561ae75cf86a1 [file] [log] [blame]
/****************************************************************************
* Copyright (c) 2007 Composent, Inc. and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Composent, Inc. - initial API and implementation
*****************************************************************************/
package org.eclipse.ecf.internal.provider.filetransfer.scp;
import com.jcraft.jsch.*;
import java.io.*;
import java.net.URL;
import java.util.Map;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.ecf.core.security.*;
import org.eclipse.ecf.core.util.Proxy;
import org.eclipse.osgi.util.NLS;
/**
*
*/
public class ScpUtil implements UserInfo, UIKeyboardInteractive {
public static final String SCP_SSHHOMEDIRECTORY = "sshHomeDirectory"; //$NON-NLS-1$
public static final String SCP_PUBLICKEYFILE = "keyFile"; //$NON-NLS-1$
public static final String SCP_KNOWNHOSTSFILE = "knownHostsFile"; //$NON-NLS-1$
public static final int DEFAULT_SCP_PORT = 22;
private IScpFileTransfer handler;
private String password;
private String passphrase;
private Session session;
private String sshHome = null;
private String keyFile = null;
private String knownHostsFile = null;
public ScpUtil(IScpFileTransfer handler) throws JSchException, IOException, UnsupportedCallbackException {
this.handler = handler;
final JSch jsch = new JSch();
final URL url = handler.getTargetURL();
int port = url.getPort();
if (port == -1)
port = DEFAULT_SCP_PORT;
setupOptions(jsch);
promptUsername();
String username = handler.getUsername();
if (username == null)
throw new IOException(Messages.ScpUtil_EXCEPTION_USERNAME_NOT_NULL);
session = jsch.getSession(handler.getUsername(), url.getHost(), port);
setupProxy();
session.setUserInfo(this);
}
Session getSession() {
return session;
}
void promptUsername() throws IOException, UnsupportedCallbackException {
final IConnectContext connectContext = handler.getConnectContext();
if (connectContext != null) {
final CallbackHandler callbackHandler = connectContext.getCallbackHandler();
if (handler != null) {
final Callback[] callbacks = new Callback[2];
final NameCallback nc = new NameCallback(Messages.ScpOutgoingFileTransfer_USERNAME_PROMPT);
String user = handler.getUsername();
if (user != null)
nc.setName(user);
callbacks[0] = nc;
callbacks[1] = new PasswordCallback(Messages.ScpOutgoingFileTransfer_PASSWORD_PROMPT);
callbackHandler.handle(callbacks);
handler.setUsername(nc.getName());
}
}
}
String promptCredentials(boolean usePassphrase) {
try {
final IConnectContext connectContext = handler.getConnectContext();
if (connectContext != null) {
final CallbackHandler callbackHandler = connectContext.getCallbackHandler();
if (handler != null) {
final Callback[] callbacks = new Callback[2];
final NameCallback nc = new NameCallback(Messages.ScpOutgoingFileTransfer_USERNAME_PROMPT);
String user = handler.getUsername();
if (user != null)
nc.setName(user);
callbacks[0] = nc;
if (usePassphrase) {
callbacks[1] = new PassphraseCallback(Messages.ScpOutgoingFileTransfer_PASSPHRASE_PROMPT);
} else
callbacks[1] = new PasswordCallback(Messages.ScpOutgoingFileTransfer_PASSWORD_PROMPT);
callbackHandler.handle(callbacks);
handler.setUsername(nc.getName());
if (usePassphrase) {
passphrase = ((PassphraseCallback) callbacks[1]).getPassphrase();
} else
password = ((PasswordCallback) callbacks[1]).getPassword();
}
}
return (usePassphrase) ? this.passphrase : this.password;
} catch (final Exception e) {
return null;
}
}
/* (non-Javadoc)
* @see com.jcraft.jsch.UserInfo#getPassphrase()
*/
public String getPassphrase() {
return promptCredentials(true);
}
/* (non-Javadoc)
* @see com.jcraft.jsch.UserInfo#getPassword()
*/
public String getPassword() {
return promptCredentials(false);
}
/* (non-Javadoc)
* @see com.jcraft.jsch.UserInfo#promptPassphrase(java.lang.String)
*/
public boolean promptPassphrase(String message) {
return (keyFile != null);
}
/* (non-Javadoc)
* @see com.jcraft.jsch.UserInfo#promptPassword(java.lang.String)
*/
public boolean promptPassword(String message) {
return true;
}
/* (non-Javadoc)
* @see com.jcraft.jsch.UserInfo#promptYesNo(java.lang.String)
*/
public boolean promptYesNo(String message) {
return true;
}
/* (non-Javadoc)
* @see com.jcraft.jsch.UserInfo#showMessage(java.lang.String)
*/
public void showMessage(String message) {
// do nothing
}
/* (non-Javadoc)
* @see com.jcraft.jsch.UIKeyboardInteractive#promptKeyboardInteractive(java.lang.String, java.lang.String, java.lang.String, java.lang.String[], boolean[])
*/
public String[] promptKeyboardInteractive(String destination, String name, String instruction, String[] prompt, boolean[] echo) {
promptCredentials(false);
return new String[] {password};
}
/**
*/
void setupProxy() {
com.jcraft.jsch.Proxy jProxy = null;
final Proxy proxy = handler.getProxy();
if (proxy != null) {
final String hostname = proxy.getAddress().getHostName();
final int port = proxy.getAddress().getPort();
if (proxy.getType().equals(Proxy.Type.HTTP)) {
if (port == -1)
jProxy = new ProxyHTTP(hostname);
else
jProxy = new ProxyHTTP(hostname, port);
} else if (proxy.getType().equals(Proxy.Type.SOCKS)) {
if (port == -1)
jProxy = new ProxySOCKS5(hostname);
else
jProxy = new ProxySOCKS5(hostname, port);
}
if (jProxy != null)
session.setProxy(jProxy);
}
}
private void setupOptions(JSch jsch) {
// Get sshHome
sshHome = getProperty(SCP_SSHHOMEDIRECTORY, sshHome);
if (sshHome == null) {
final String userHome = System.getProperty("user.home"); //$NON-NLS-1$
if (userHome != null) {
File dir = new File(userHome + File.separator + ".ssh"); //$NON-NLS-1$
if (dir.exists())
sshHome = dir.getAbsolutePath();
else
dir = new File(userHome + File.separator + "ssh"); //$NON-NLS-1$
if (dir.exists())
sshHome = dir.getAbsolutePath();
}
}
keyFile = getProperty(SCP_PUBLICKEYFILE);
if (keyFile != null) {
if (!(new File(keyFile).exists()))
keyFile = null;
} else {
File file = new File(sshHome + File.separator + "id_dsa"); //$NON-NLS-1$
if (file.exists())
keyFile = file.getAbsolutePath();
else {
file = new File(sshHome + File.separator + "id_rsa"); //$NON-NLS-1$
if (file.exists())
keyFile = file.getAbsolutePath();
}
}
if (keyFile != null) {
try {
jsch.addIdentity(keyFile);
} catch (final JSchException e) {
Activator.getDefault().log(new Status(IStatus.ERROR, Activator.PLUGIN_ID, IStatus.ERROR, Messages.ScpOutgoingFileTransfer_EXCEPTION_SETTING_SSH_IDENTITY, e));
}
}
knownHostsFile = getProperty(SCP_KNOWNHOSTSFILE);
if (knownHostsFile != null) {
if (!(new File(knownHostsFile).exists()))
knownHostsFile = null;
} else {
final File file = new File(sshHome + File.separator + "known_hosts"); //$NON-NLS-1$
if (!file.exists()) {
knownHostsFile = null;
} else {
knownHostsFile = file.getAbsolutePath();
}
}
if (knownHostsFile != null) {
try {
jsch.setKnownHosts(knownHostsFile);
} catch (final JSchException e) {
Activator.getDefault().log(new Status(IStatus.ERROR, Activator.PLUGIN_ID, IStatus.ERROR, Messages.ScpOutgoingFileTransfer_EXCEPTION_SETTING_KNOWN_HOSTS, e));
}
}
}
private String getProperty(String key, String def) {
final Map options = handler.getOptions();
if (options == null)
return def;
final String result = (String) options.get(key);
if (result == null)
return def;
return result;
}
private String getProperty(String key) {
return getProperty(key, null);
}
String trimTargetFile(String string) {
if (string.charAt(0) == '/')
return string.substring(1);
return string;
}
void checkAck(InputStream ins) throws IOException {
checkAck(ins.read(), ins);
}
void checkAck(int b, InputStream ins) throws IOException {
if (b == 0)
return;
if (b == -1)
throw new IOException(Messages.ScpUtil_EXCEPTION_UNKNOWN_SCP_ERROR);
if (b == 1 || b == 2) {
final StringBuffer sb = new StringBuffer();
int c;
do {
c = ins.read();
sb.append((char) c);
} while (c != '\n');
if (b == 1) { // error
throw new IOException(NLS.bind(Messages.ScpUtil_SCP_ERROR, sb.toString()));
}
if (b == 2) { // fatal error
throw new IOException(NLS.bind(Messages.ScpUtil_SCP_ERROR, sb.toString()));
}
}
}
void sendZeroToStream(OutputStream outs) throws IOException {
// send '\0'
final byte[] buf = new byte[1];
buf[0] = 0;
outs.write(buf, 0, 1);
outs.flush();
}
void dispose() {
if (session != null) {
session.disconnect();
session = null;
}
handler = null;
password = null;
passphrase = null;
sshHome = null;
keyFile = null;
knownHostsFile = null;
}
}