/**************************************************************************** * 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 = System .getProperty( "org.eclipse.ecf.filetransfer.scp.util.sshHomeDirectory", "sshHomeDirectory"); //$NON-NLS-1$ public static final String SCP_PUBLICKEYFILE = System.getProperty( "org.eclipse.ecf.filetransfer.scp.util.keyFile", "keyFile"); //$NON-NLS-1$ public static final String SCP_KNOWNHOSTSFILE = System .getProperty( "org.eclipse.ecf.filetransfer.scp.util.knownHostsFile", "knownHostsFile"); //$NON-NLS-1$ public static final int DEFAULT_SCP_PORT = Integer .parseInt(System.getProperty( "org.eclipse.ecf.filetransfer.scp.util.scpPort", "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) { 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; } }