aboutsummaryrefslogtreecommitdiff
path: root/remote/ssh-conn.c
diff options
context:
space:
mode:
authorLeandro A. F. Pereira <leandro@hardinfo.org>2010-05-03 09:27:26 -0300
committerLeandro A. F. Pereira <leandro@hardinfo.org>2010-05-03 21:08:06 -0300
commit9273c075a2f993c5154614b70233d8f74515c851 (patch)
treeeb72a8c58e6bc8f4ca3b739d28fbecc269c0052d /remote/ssh-conn.c
parent9a50155ec3e27aa6cedf3f118196f1947c769a29 (diff)
Move files from hardinfo2 to root.
Diffstat (limited to 'remote/ssh-conn.c')
-rw-r--r--remote/ssh-conn.c338
1 files changed, 338 insertions, 0 deletions
diff --git a/remote/ssh-conn.c b/remote/ssh-conn.c
new file mode 100644
index 00000000..7f099d35
--- /dev/null
+++ b/remote/ssh-conn.c
@@ -0,0 +1,338 @@
+/*
+ Remote Client
+ HardInfo - Displays System Information
+ Copyright (C) 2003-2009 Leandro A. F. Pereira <leandro@hardinfo.org>
+
+ Based on ssh-method.c from GnomeVFS
+ Copyright (C) 1999 Free Software Foundation
+ Original author: Ian McKellar <yakk@yakk.net>
+
+ ssh-conn.c and ssh-conn.h are free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ ssh-conn.c and ssh-con.h are distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with ssh-conn.c and ssh-conn.h; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+#include "config.h"
+#ifdef HAS_LIBSOUP
+#include <glib/gstdio.h>
+#include <glib.h>
+#include <unistd.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+
+#include "ssh-conn.h"
+
+const char *ssh_conn_errors[] = {
+ "OK",
+ "No URI specified",
+ "Unknown protocol",
+ "Unknown error",
+ "Cannot spawn SSH",
+ "Bad parameters",
+ "Permission denied (invalid credentials)",
+ "Host key verification failed",
+ "Connection refused",
+ "Invalid username or password"
+};
+
+int ssh_write(SSHConn * conn,
+ gconstpointer buffer, gint num_bytes, gint * bytes_written)
+{
+ int written;
+ int count = 0;
+
+ do {
+ written = write(conn->fd_write, buffer, (size_t) num_bytes);
+ if (written == -1 && errno == EINTR) {
+ count++;
+ usleep(10);
+ }
+ } while (written == -1 && errno == EINTR && count < 5);
+
+ if (written == -1) {
+ return -1;
+ }
+
+ *bytes_written = written;
+
+ return 1;
+}
+
+int ssh_read(gint fd, gpointer buffer, gint num_bytes, gint * bytes_read)
+{
+ int retval;
+ fd_set fds;
+ struct timeval tv = { 5, 0 };
+
+ FD_ZERO(&fds);
+ FD_SET(fd, &fds);
+
+ *bytes_read = 0;
+
+ if ((retval = select(fd + 1, &fds, NULL, NULL, &tv)) < 0) {
+ return retval;
+ }
+
+ if ((retval = read(fd, buffer, (size_t) num_bytes)) > 0) {
+ *bytes_read = retval;
+ return 1;
+ }
+
+ return retval;
+}
+
+void ssh_close(SSHConn * conn)
+{
+ if (!conn) {
+ return;
+ }
+
+ close(conn->fd_read);
+ close(conn->fd_write);
+ close(conn->fd_error);
+
+ if (conn->uri) {
+ soup_uri_free(conn->uri);
+ }
+
+ kill(conn->pid, SIGINT);
+
+ if (conn->askpass_path) {
+ DEBUG("unlinking %s", conn->askpass_path);
+ g_remove(conn->askpass_path);
+ g_free(conn->askpass_path);
+ }
+
+ g_free(conn);
+}
+
+static void ssh_conn_setup(gpointer user_data)
+{
+ gchar *askpass_path = (gchar *) user_data;
+ int fd;
+
+ if ((fd = open("/dev/tty", O_RDWR)) != -1) {
+ ioctl(fd, TIOCNOTTY, NULL);
+ close(fd);
+ }
+
+ if (askpass_path) {
+ g_setenv("DISPLAY", "none:0.", TRUE);
+ g_setenv("SSH_ASKPASS", askpass_path, TRUE);
+ } else {
+ g_setenv("SSH_ASKPASS", "/bin/false", TRUE);
+ }
+}
+
+SSHConnResponse ssh_new(SoupURI * uri,
+ SSHConn ** conn_return, gchar * command)
+{
+ int argc, res, bytes_read;
+ char **argv, *askpass_path = NULL;
+ GString *cmd_line;
+ SSHConnResponse response;
+ SSHConn *connection;
+ gchar buffer[512];
+
+ if (!conn_return) {
+ return SSH_CONN_BAD_PARAMS;
+ }
+
+ if (!uri) {
+ return SSH_CONN_NO_URI;
+ }
+
+ if (!g_str_equal(uri->scheme, "ssh")) {
+ return SSH_CONN_UNKNOWN_PROTOCOL;
+ }
+
+ if (uri->password) {
+ int tmp_askpass;
+
+ askpass_path =
+ g_build_filename(g_get_home_dir(), ".hardinfo",
+ "ssh-askpass-XXXXXX", NULL);
+ tmp_askpass = g_mkstemp(askpass_path);
+ if (tmp_askpass > 0) {
+ gchar *tmp;
+
+ g_chmod(askpass_path, 0700);
+
+ tmp = g_strdup_printf("#!/bin/sh\n"
+ "echo '%s'\n"
+ "rm -f \"$0\"", uri->password);
+ write(tmp_askpass, tmp, strlen(tmp));
+ close(tmp_askpass);
+ g_free(tmp);
+
+ DEBUG("using [%s] as ssh-askpass", askpass_path);
+ }
+ }
+
+
+ cmd_line = g_string_new("ssh -x");
+
+ if (uri->query && strlen(uri->query)) {
+ GHashTable *query;
+ GList *keys, *key;
+
+ query = soup_form_decode(uri->query);
+ keys = g_hash_table_get_keys(query);
+
+ for (key = keys; key; key = key->next) {
+ gchar *param;
+
+ g_string_append_printf(cmd_line, " -%s", (gchar *) key->data);
+
+ if ((param = (gchar *) g_hash_table_lookup(query, key->data))) {
+ g_string_append_printf(cmd_line, "'%s'", param);
+ }
+ }
+
+ g_list_free(keys);
+ g_hash_table_destroy(query);
+ }
+
+ if (uri->user) {
+ g_string_append_printf(cmd_line, " -l '%s'", uri->user);
+ }
+
+ if (uri->port) {
+ g_string_append_printf(cmd_line, " -p %d", uri->port);
+ }
+
+ g_string_append_printf(cmd_line,
+ " %s \"LC_ALL=C %s\"", uri->host, command);
+
+ DEBUG("cmd_line = [%s]", cmd_line->str);
+
+ if (!g_shell_parse_argv(cmd_line->str, &argc, &argv, NULL)) {
+ response = SSH_CONN_BAD_PARAMS;
+ goto end;
+ }
+
+ connection = g_new0(SSHConn, 1);
+ connection->exit_status = -1;
+
+ DEBUG("spawning SSH");
+
+ if (!g_spawn_async_with_pipes(NULL, argv, NULL,
+ G_SPAWN_SEARCH_PATH,
+ ssh_conn_setup, askpass_path,
+ &connection->pid,
+ &connection->fd_write,
+ &connection->fd_read,
+ &connection->fd_error, NULL)) {
+ response = SSH_CONN_CANNOT_SPAWN_SSH;
+ goto end;
+ }
+
+ memset(buffer, 0, sizeof(buffer));
+ res = ssh_read(connection->fd_error, &buffer, sizeof(buffer),
+ &bytes_read);
+ DEBUG("bytes read: %d, result = %d", bytes_read, res);
+ if (bytes_read > 0 && res == 1) {
+ DEBUG("Received (error channel): [%s]", buffer);
+
+ if (strstr(buffer, "Permission denied")) {
+ response = SSH_CONN_PERMISSION_DENIED;
+ goto end;
+ } else if (strstr(buffer, "Host key verification failed")) {
+ response = SSH_CONN_HOST_KEY_CHECK_FAIL;
+ goto end;
+ } else if (strstr(buffer, "Connection refused")) {
+ response = SSH_CONN_REFUSED;
+ goto end;
+ }
+ }
+
+ DEBUG("no error detected; ssh conn established");
+
+ connection->uri = soup_uri_copy(uri);
+ response = SSH_CONN_OK;
+
+ end:
+ g_strfreev(argv);
+ g_string_free(cmd_line, TRUE);
+
+ if (askpass_path) {
+ if (connection) {
+ connection->askpass_path = askpass_path;
+ } else {
+ g_free(askpass_path);
+ }
+ }
+
+ if (response != SSH_CONN_OK) {
+ if (connection->uri) {
+ soup_uri_free(connection->uri);
+ }
+
+ g_free(connection);
+
+ *conn_return = NULL;
+ } else {
+ *conn_return = connection;
+ }
+
+ DEBUG("response = %d (%s)", response, ssh_conn_errors[response]);
+
+ return response;
+}
+
+#ifdef SSH_TEST
+int main(int argc, char **argv)
+{
+ SSHConn *c;
+ SSHConnResponse r;
+ SoupURI *u;
+ char buffer[256];
+
+ if (argc < 2) {
+ g_print("Usage: %s URI command\n", argv[0]);
+ g_print("Example: %s ssh://user:password@host 'ls -la /'\n",
+ argv[0]);
+ return 1;
+ }
+
+ u = soup_uri_new(argv[1]);
+ r = ssh_new(u, &c, argv[2]);
+ g_print("Connection result: %s\n", ssh_conn_errors[r]);
+
+ if (r == SSH_CONN_OK) {
+ int bytes_read;
+
+ while (ssh_read(c->fd_read, &buffer, sizeof(buffer),
+ &bytes_read) > 0) {
+ g_print("Bytes read: %d\n", bytes_read);
+ g_print("Contents: %s", buffer);
+ }
+
+ g_print("Finished running remote command\n");
+ }
+
+ g_print("Closing SSH [ptr = %p]", c);
+ ssh_close(c);
+
+ return 0;
+}
+#endif /* SSH_TEST */
+#endif /* HAS_LIBSOUP */