summaryrefslogtreecommitdiffstats
path: root/tdesu/ssh.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'tdesu/ssh.cpp')
-rw-r--r--tdesu/ssh.cpp279
1 files changed, 279 insertions, 0 deletions
diff --git a/tdesu/ssh.cpp b/tdesu/ssh.cpp
new file mode 100644
index 000000000..f45b38e7e
--- /dev/null
+++ b/tdesu/ssh.cpp
@@ -0,0 +1,279 @@
+/* vi: ts=8 sts=4 sw=4
+*
+* $Id$
+*
+* This file is part of the KDE project, module tdesu.
+* Copyright (C) 2000 Geert Jansen <jansen@kde.org>
+*
+* This is free software; you can use this library under the GNU Library
+* General Public License, version 2. See the file "COPYING.LIB" for the
+* exact licensing terms.
+*
+* ssh.cpp: Execute a program on a remote machine using ssh.
+*/
+
+#include <config.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <errno.h>
+#include <string.h>
+#include <ctype.h>
+#include <signal.h>
+#include <time.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <tqglobal.h>
+#include <tqcstring.h>
+
+#include <kdebug.h>
+#include <klocale.h>
+#include <kstandarddirs.h>
+
+#include "ssh.h"
+#include "kcookie.h"
+
+
+SshProcess::SshProcess(const TQCString &host, const TQCString &user, const TQCString &command)
+{
+ m_Host = host;
+ m_User = user;
+ m_Command = command;
+ m_Stub = "tdesu_stub";
+ srand(time(0L));
+}
+
+
+SshProcess::~SshProcess()
+{
+}
+
+
+void SshProcess::setStub(const TQCString &stub)
+{
+ m_Stub = stub;
+}
+
+
+int SshProcess::checkInstall(const char *password)
+{
+ return exec(password, 1);
+}
+
+
+int SshProcess::checkNeedPassword()
+{
+ return exec(0L, 2);
+}
+
+
+int SshProcess::exec(const char *password, int check)
+{
+ if (check)
+ setTerminal(true);
+
+ QCStringList args;
+ args += "-l"; args += m_User;
+ args += "-o"; args += "StrictHostKeyChecking=no";
+ args += m_Host; args += m_Stub;
+
+ if (StubProcess::exec("ssh", args) < 0)
+ {
+ return check ? SshNotFound : -1;
+ }
+
+ int ret = ConverseSsh(password, check);
+ if (ret < 0)
+ {
+ if (!check)
+ kdError(900) << k_lineinfo << "Conversation with ssh failed\n";
+ return ret;
+ }
+ if (check == 2)
+ {
+ if (ret == 1)
+ {
+ kill(m_Pid, SIGTERM);
+ waitForChild();
+ }
+ return ret;
+ }
+
+ if (m_bErase && password)
+ {
+ char *ptr = const_cast<char *>(password);
+ const uint plen = strlen(password);
+ for (unsigned i=0; i < plen; i++)
+ ptr[i] = '\000';
+ }
+
+ ret = ConverseStub(check);
+ if (ret < 0)
+ {
+ if (!check)
+ kdError(900) << k_lineinfo << "Converstation with tdesu_stub failed\n";
+ return ret;
+ }
+ else if (ret == 1)
+ {
+ kill(m_Pid, SIGTERM);
+ waitForChild();
+ ret = SshIncorrectPassword;
+ }
+
+ if (check == 1)
+ {
+ waitForChild();
+ return 0;
+ }
+
+ setExitString("Waiting for forwarded connections to terminate");
+ ret = waitForChild();
+ return ret;
+}
+
+/*
+* Create a port forwarding for DCOP. For the remote port, we take a pseudo
+* random number between 10k and 50k. This is not ok, of course, but I see
+* no other way. There is, afaik, no security issue involved here. If the port
+* happens to be occupied, ssh will refuse to start.
+*
+* 14/SEP/2000: DCOP forwarding is not used anymore.
+*/
+
+TQCString SshProcess::dcopForward()
+{
+ TQCString result;
+
+ setDcopTransport("tcp");
+
+ TQCString srv = StubProcess::dcopServer();
+ if (srv.isEmpty())
+ return result;
+
+ int i = srv.find('/');
+ if (i == -1)
+ return result;
+ if (srv.left(i) != "tcp")
+ return result;
+ int j = srv.find(':', ++i);
+ if (j == -1)
+ return result;
+ TQCString host = srv.mid(i, j-i);
+ bool ok;
+ int port = srv.mid(++j).toInt(&ok);
+ if (!ok)
+ return result;
+
+ m_dcopPort = 10000 + (int) ((40000.0 * rand()) / (1.0 + RAND_MAX));
+ result.sprintf("%d:%s:%d", m_dcopPort, host.data(), port);
+ return result;
+}
+
+
+/*
+* Conversation with ssh.
+* If check is 0, this waits for either a "Password: " prompt,
+* or the header of the stub. If a prompt is received, the password is
+* written back. Used for running a command.
+* If check is 1, operation is the same as 0 except that if a stub header is
+* received, the stub is stopped with the "stop" command. This is used for
+* checking a password.
+* If check is 2, operation is the same as 1, except that no password is
+* written. The prompt is saved to m_Prompt. Used for checking the need for
+* a password.
+*/
+
+int SshProcess::ConverseSsh(const char *password, int check)
+{
+ unsigned i, j, colon;
+
+ TQCString line;
+ int state = 0;
+
+ while (state < 2)
+ {
+ line = readLine();
+ const uint len = line.length();
+ if (line.isNull())
+ return -1;
+
+ switch (state) {
+ case 0:
+ // Check for "tdesu_stub" header.
+ if (line == "tdesu_stub")
+ {
+ unreadLine(line);
+ return 0;
+ }
+
+ // Match "Password: " with the regex ^[^:]+:[\w]*$.
+ for (i=0,j=0,colon=0; i<len; i++)
+ {
+ if (line[i] == ':')
+ {
+ j = i; colon++;
+ continue;
+ }
+ if (!isspace(line[i]))
+ j++;
+ }
+ if ((colon == 1) && (line[j] == ':'))
+ {
+ if (check == 2)
+ {
+ m_Prompt = line;
+ return SshNeedsPassword;
+ }
+ WaitSlave();
+ write(m_Fd, password, strlen(password));
+ write(m_Fd, "\n", 1);
+ state++;
+ break;
+ }
+
+ // Warning/error message.
+ m_Error += line; m_Error += "\n";
+ if (m_bTerminal)
+ fprintf(stderr, "ssh: %s\n", line.data());
+ break;
+
+ case 1:
+ if (line.isEmpty())
+ {
+ state++;
+ break;
+ }
+ return -1;
+ }
+ }
+ return 0;
+}
+
+
+// Display redirection is handled by ssh natively.
+TQCString SshProcess::display()
+{
+ return "no";
+}
+
+
+TQCString SshProcess::displayAuth()
+{
+ return "no";
+}
+
+
+// Return the remote end of the forwarded connection.
+TQCString SshProcess::dcopServer()
+{
+ return TQCString().sprintf("tcp/localhost:%d", m_dcopPort);
+}
+
+void SshProcess::virtual_hook( int id, void* data )
+{ StubProcess::virtual_hook( id, data ); }