/******************************************************************************* * Copyright (c) 2009, 2014 Wind River Systems, 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: * Wind River Systems - initial API and implementation *******************************************************************************/ package org.eclipse.tcf.internal.debug.ui.launch.setup; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStreamWriter; import java.io.PrintWriter; import java.io.StringWriter; import java.net.InetAddress; import java.net.URL; import org.eclipse.core.runtime.FileLocator; import org.eclipse.core.runtime.Path; import org.eclipse.core.runtime.Platform; import org.eclipse.jface.dialogs.IPageChangingListener; import org.eclipse.jface.dialogs.PageChangingEvent; import org.eclipse.jface.wizard.IWizardPage; import org.eclipse.jface.wizard.WizardDialog; import org.eclipse.jface.wizard.WizardPage; import org.eclipse.swt.SWT; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.layout.GridLayout; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.Label; import org.eclipse.swt.widgets.Shell; import org.eclipse.swt.widgets.Text; import org.eclipse.tcf.core.Base64; import org.eclipse.tcf.internal.debug.ui.Activator; import org.eclipse.tcf.ssl.TCFSecurityManager; import org.osgi.framework.Bundle; class WizardLogPage extends WizardPage implements Runnable { private final SetupWizardDialog wizard; private Thread thread; private String protocol; private String host; private String user; private String user_password; private String root_password; private Text log_text; private Display display; private Shell parent; private IRemoteShell shell; WizardLogPage(SetupWizardDialog wizard) { super("LogPage"); this.wizard = wizard; setTitle("Remote host login"); setDescription(""); } public void createControl(Composite parent) { display = parent.getDisplay(); this.parent = parent.getShell(); ((WizardDialog)getContainer()).addPageChangingListener(new IPageChangingListener() { public void handlePageChanging(PageChangingEvent event) { if (event.getCurrentPage() instanceof WizardLoginPage && event.getTargetPage() == WizardLogPage.this) { runSetupJob((WizardLoginPage)event.getCurrentPage()); } } }); Composite composite = new Composite(parent, SWT.NULL); GridLayout gl = new GridLayout(); gl.numColumns = 1; composite.setLayout(gl); new Label(composite, SWT.WRAP).setText("Agent installation log:"); log_text = new Text(composite, SWT.BORDER | SWT.MULTI | SWT.READ_ONLY | SWT.H_SCROLL | SWT.V_SCROLL); GridData gd = new GridData(GridData.FILL_BOTH); log_text.setLayoutData(gd); setControl(composite); } private void runSetupJob(WizardLoginPage login) { assert display != null; assert display.getThread() == Thread.currentThread(); if (thread != null) return; setErrorMessage(null); protocol = login.protocol.getText(); host = login.host.getText(); user = login.user.getText(); user_password = login.user_password.getText(); root_password = login.root_password.getText(); log_text.setText("Connect to " + host + "\n"); thread = new Thread(this); thread.start(); } public void run() { Throwable error = null; try { if ("Telnet".equals(protocol)) { shell = new TelnetClient(InetAddress.getByName(host), 23, user, user_password); } else if ("SSH".equals(protocol)) { shell = new SSHClient(parent, host, user, user_password); } else { throw new Exception("Invalid protocol name: " + protocol); } String s; if (!user.equals("root")) { send("su", true); expect("Password: ", true); send(root_password, false); s = waitPrompt(); if (s.length() > 0) throw new Exception(s); } exec("cd /tmp"); send("uname -o", true); String os = waitPrompt().replace('\n', ' ').trim(); send("uname -m", true); String machine = waitPrompt().replace('\n', ' ').trim(); String version = "1.3.0"; Bundle bundle = Platform.getBundle(Activator.PLUGIN_ID); URL url = FileLocator.find(bundle, new Path("agent/get-os-tag"), null); if (url == null) throw new Exception("Cannot find get-os-tag script"); send("cat >get-os-tag", true); InputStream inp = url.openStream(); byte[] buf = new byte[0x100]; for (;;) { int len = inp.read(buf); if (len < 0) break; shell.write(new String(buf, 0, len, "ASCII")); for (int i = 0; i < len; i++) { if (buf[i] == '\n') shell.expect("\n"); } } inp.close(); shell.write("\004"); s = waitPrompt(); if (s.length() > 0) throw new Exception(s); exec("chmod u+x get-os-tag"); send("./get-os-tag", true); String os_tag = waitPrompt().replace('\n', ' ').trim(); exec("rm -f get-os-tag"); url = null; String fnm = null; String machine0 = machine; for (;;) { for (int release = 16; url == null && release > 0; release--) { fnm = "tcf-agent-" + version + "-" + release + "." + os_tag + "." + machine + ".rpm"; url = FileLocator.find(bundle, new Path("agent/" + os + "/" + machine + "/" + fnm), null); } if (url != null) break; if (machine.equals("i686")) machine = "i586"; else if (machine.equals("i586")) machine = "i486"; else if (machine.equals("i486")) machine = "i386"; else { machine = machine0; if (os_tag.startsWith("fc")) { int n = Integer.parseInt(os_tag.substring(2)) - 1; if (n <= 0) break; os_tag = "fc" + n; } else if (os_tag.startsWith("rh")) { int n = Integer.parseInt(os_tag.substring(2)) - 1; if (n <= 0) break; os_tag = "rh" + n; } else break; } } if (url == null) throw new Exception("Unsupported target OS or CPU"); inp = url.openStream(); send("which base64", true); s = waitPrompt(); if (s.indexOf(':') < 0) { send("base64 -di >" + fnm, true); sendBase64(inp); shell.write("\004"); s = waitPrompt(); if (s.length() > 0) throw new Exception(s); } else { send("which uudecode", true); s = waitPrompt(); if (s.indexOf(':') < 0) { send("uudecode", true); send("begin-base64 644 " + fnm, true); sendBase64(inp); send("====", true); s = waitPrompt(); if (s.length() > 0) throw new Exception(s); } else { throw new Exception("No base64 or uudecode commands available"); } } inp.close(); send("rpm -e --quiet tcf-agent", true); waitPrompt(); exec("rm -f /etc/init.d/tcf-agent*"); exec("rpm -i --quiet " + fnm); exec("rm -f " + fnm); File certs = TCFSecurityManager.getCertificatesDirectory(); File local_cert = new File(certs, "local.cert"); File local_priv = new File(certs, "local.priv"); if (!local_cert.exists() || !local_priv.exists()) { copyRemoteSecret("local.cert", local_cert); copyRemoteSecret("local.priv", local_priv); exec("/usr/sbin/tcf-agent -c"); } copyRemoteSecret("local.cert", new File(certs, host + ".cert")); copyLocalSecret(local_cert, InetAddress.getLocalHost().getHostName() + ".cert"); if (!user.equals("root")) { send("exit", true); waitPrompt(); } } catch (Throwable x) { error = x; } if (shell != null) { try { shell.close(); shell = null; } catch (Throwable x) { if (error != null) error = x; } } done(error); } private void sendBase64(InputStream inp) throws Exception { byte[] buf = new byte[0x100 * 3]; for (;;) { int len = 0; while (len < buf.length) { int rd = inp.read(buf, len, buf.length - len); if (rd < 0) break; len += rd; } if (len == 0) break; send(new String(Base64.toBase64(buf, 0, len)), false); } } private void copyRemoteSecret(String from, File to) throws Exception { send("cat /etc/tcf/ssl/" + from, true); String s = waitPrompt(); if (s.indexOf("-----BEGIN ") != 0) throw new Exception(s); BufferedWriter wr = new BufferedWriter(new OutputStreamWriter( new FileOutputStream(to), "ASCII")); wr.write(s); wr.close(); } private void copyLocalSecret(File from, String to) throws Exception { send("cat >/etc/tcf/ssl/" + to, true); BufferedReader rd = new BufferedReader(new InputStreamReader( new FileInputStream(from), "ASCII")); for (;;) { String s = rd.readLine(); if (s == null) break; send(s, true); } rd.close(); shell.write("\004"); String s = waitPrompt(); if (s.length() > 0) throw new Exception(s); } private void send(final String s, boolean log) throws IOException { if (log) { display.asyncExec(new Runnable() { public void run() { if (log_text.isDisposed()) return; log_text.append("Send: "); log_text.append(s); if (!s.endsWith("\n")) log_text.append("\n"); } }); } shell.write(s); shell.write("\n"); if (log) shell.expect(s); shell.expect("\n"); } private void expect(final String s, boolean log) throws IOException { if (log) { display.asyncExec(new Runnable() { public void run() { if (log_text.isDisposed()) return; log_text.append("Expect: "); log_text.append(s); if (!s.endsWith("\n")) log_text.append("\n"); } }); } shell.expect(s); } private String waitPrompt() throws IOException { display.asyncExec(new Runnable() { public void run() { if (log_text.isDisposed()) return; log_text.append("Wait for shell prompt\n"); } }); final String s = shell.waitPrompt(); if (s.length() > 0) { display.asyncExec(new Runnable() { public void run() { if (log_text.isDisposed()) return; log_text.append("Got: "); log_text.append(s); if (!s.endsWith("\n")) log_text.append("\n"); } }); } return s; } private void exec(String cmd) throws Exception { send(cmd, true); String s = waitPrompt(); if (s.length() > 0) throw new Exception(s); } private void done(final Throwable error) { display.asyncExec(new Runnable() { public void run() { thread = null; protocol = null; host = null; user = null; user_password = null; root_password = null; if (log_text.isDisposed()) return; if (error != null) { StringWriter buf = new StringWriter(); PrintWriter pwr = new PrintWriter(buf); error.printStackTrace(pwr); pwr.flush(); log_text.append(buf.toString()); setErrorMessage(error.getClass().getName() + ": " + error.getLocalizedMessage()); } else { log_text.append("Done\n"); setErrorMessage(null); } getContainer().updateButtons(); } }); } @Override public IWizardPage getPreviousPage() { if (thread != null) return null; return wizard.getPage("LoginPage"); } @Override public IWizardPage getNextPage() { return null; } public boolean canFinish() { return thread == null && getErrorMessage() == null; } }