diff lib/sshv2.c @ 122:76e2b58a9440

2003-4-5 Brian Masney <masneyb@gftp.org> * lib/config_file.c lib/options.h lib/gftp.h lib/rfc959.c lib/rfc2068.c lib/ssh.c - added new internal configuration interface. Rather than having a global variable for each option, I have a global hash table (gftp_global_options_htable) that I can look up option names by name using gftp_lookup_global_option(). I also an options hash associated with a request structure, so I will be able to call gftp_lookup_request_option(). I will be able to override options with bookmarks or while transfers are in progress very easily now. Also, all options no longer have to appear in config_file.c, the per protocol options can appear inside their own file * lib/gftp.h lib/bookmarks.c lib/local.c lib/rfc959.c lib/rfc2068.c - remove set_data_type and protocol name from struct gftp_request * lib/rfc959.c - renamed all firewall_* variables to ftp_proxy_* in the config file * lib/gftp.h lib/protocols.c lib/rfc959.c - renamed all GFTP_TYPE_* vars to GFTP_DIRTYPE_* * lib/gftp.h - removed ascii field and renamed the node pointer to user_data in struct gftp_file. In gftp_request, removed any setting that is now stored in the global/local hash tables. Added register_module() pointer that will be called whenever the protocol is first loaded into gftp * lib/rfc959.c src/text/gftp-text.c - moved the ascii/binary translation to rfc959.c. Also, moved any instance of automatically setting the data type to rfc959.c as well. * lib/misc.c lib/sshv2.c - moved all ssh functions from misc.c to sshv2.c. I had these origionally in misc.c because I used to have 2 different SSH protocols * lib/protocols.c src/text/gftp-text.c - added gftp_calc_kbs() to protocols.c. This no longer needs to be in the different ports * src/text/gftp-text.c - read/write options based on new configuration interface * Use new configuration interface in all source files * Updated copyright dates on all source files * Note: GTK+ port is completely broken at the moment. I'll upload those changes whenever I get them done
author masneyb
date Sat, 05 Apr 2003 16:30:45 +0000
parents 8c37d73d3f1f
children 65048c959029
line wrap: on
line diff
--- a/lib/sshv2.c	Sat Apr 05 02:25:42 2003 +0000
+++ b/lib/sshv2.c	Sat Apr 05 16:30:45 2003 +0000
@@ -1,6 +1,6 @@
 /*****************************************************************************/
 /*  sshv2.c - functions that will use the sshv2 protocol                     */
-/*  Copyright (C) 1998-2002 Brian Masney <masneyb@gftp.org>                  */
+/*  Copyright (C) 1998-2003 Brian Masney <masneyb@gftp.org>                  */
 /*                                                                           */
 /*  This program is free software; you can redistribute it and/or modify     */
 /*  it under the terms of the GNU General Public License as published by     */
@@ -23,6 +23,36 @@
 #define SSH_MAX_HANDLE_SIZE		256
 #define SSH_MAX_STRING_SIZE		34000
 
+static gftp_config_vars config_vars[] =
+{
+  {"", N_("SSH"), gftp_option_type_notebook, NULL, NULL, 0, NULL, 
+   GFTP_PORT_GTK, NULL},
+
+  {"ssh_prog_name", N_("SSH Prog Name:"), 
+   gftp_option_type_text, "ssh", NULL, 0,
+   N_("The path to the SSH executable"), GFTP_PORT_ALL, NULL},
+  {"ssh_extra_params", N_("SSH Extra Params:"), 
+   gftp_option_type_textarray, NULL, NULL, 0,  
+   N_("Extra parameters to pass to the SSH program"), GFTP_PORT_ALL, NULL},
+  {"ssh2_sftp_path", N_("SSH2 sftp-server path:"), 
+   gftp_option_type_text, NULL, NULL, 0,
+   N_("Default remote SSH2 sftp-server path"), GFTP_PORT_ALL, NULL},
+
+  {"ssh_need_userpass", N_("Need SSH User/Pass"), 
+   gftp_option_type_checkbox, GINT_TO_POINTER(1), NULL, 0,
+   N_("Require a username/password for SSH connections"), GFTP_PORT_ALL, NULL},
+  {"ssh_use_askpass", N_("Use ssh-askpass utility"),
+   gftp_option_type_checkbox, GINT_TO_POINTER(0), NULL, 0,
+   N_("Use the ssh-askpass utility to supply the remote password"), GFTP_PORT_GTK,
+   NULL},
+  {"sshv2_use_sftp_subsys", N_("Use SSH2 SFTP subsys"), 
+   gftp_option_type_checkbox, GINT_TO_POINTER(0), NULL, 0,
+   N_("Call ssh with the -s sftp flag. This is helpful because you won't have to know the remote path to the remote sftp-server"), 
+   GFTP_PORT_GTK, NULL},
+  {NULL, NULL, 0, NULL, NULL, 0, NULL, 0, NULL}
+};
+
+
 typedef struct sshv2_attribs_tag
 {
   gint32 flags;
@@ -112,6 +142,254 @@
 #define SSH_FX_CONNECTION_LOST               7
 #define SSH_FX_OP_UNSUPPORTED                8
 
+#define SSH_LOGIN_BUFSIZE	200
+#define SSH_ERROR_BADPASS	-1
+#define SSH_ERROR_QUESTION	-2
+#define SSH_WARNING 		-3
+
+/* We have the caller send us a pointer to a string so we can write the port
+   into it. It makes it easier so we don't have to worry about freeing it 
+   later on, the caller can just send us an auto variable, The string
+   should be at least 6 chars. I know this is messy... */
+
+static char **
+sshv2_gen_exec_args (gftp_request * request, char *execname, 
+                    int use_sftp_subsys, char *portstring)
+{
+  char **args, *oldstr, *tempstr, *ssh_prog_name, **ssh_extra_params_list;
+  int i, j, num_ssh_extra_params;
+  struct servent serv_struct;
+
+  ssh_extra_params_list = NULL;
+  gftp_lookup_request_option (request, "ssh_extra_params", 
+                              &ssh_extra_params_list);
+
+  num_ssh_extra_params = 0;
+  if (ssh_extra_params_list != NULL)
+    {
+      for (j=0; ssh_extra_params_list[j] != NULL; j++)
+        {
+          num_ssh_extra_params++;
+        }
+     }
+
+  args = g_malloc (sizeof (char *) * (num_ssh_extra_params + 15));
+
+  ssh_prog_name = "ssh";
+  gftp_lookup_request_option (request, "ssh_prog_name", &ssh_prog_name);
+  args[0] = ssh_prog_name;
+
+  i = 1;
+  tempstr = g_strdup (args[0]);
+
+
+  if (ssh_extra_params_list != NULL)
+    {
+      for (j=0; ssh_extra_params_list[j] != NULL; j++)
+        {
+          oldstr = tempstr;
+          args[i++] = ssh_extra_params_list[j];
+          tempstr = g_strconcat (oldstr, " ", ssh_extra_params_list[j], NULL);
+          g_free (oldstr);
+        }
+    }
+
+  oldstr = tempstr;
+  tempstr = g_strconcat (oldstr, " -e none", NULL);
+  g_free (oldstr);
+  args[i++] = "-e";
+  args[i++] = "none";
+
+  if (request->username && *request->username != '\0')
+    {
+      oldstr = tempstr;
+      tempstr = g_strconcat (oldstr, " -l ", request->username, NULL);
+      g_free (oldstr);
+      args[i++] = "-l";
+      args[i++] = request->username;
+    }
+
+  if (request->port != 0)
+    {
+      g_snprintf (portstring, 6, "%d", request->port);
+      oldstr = tempstr;
+      tempstr = g_strconcat (oldstr, " -p ", portstring, NULL);
+      g_free (oldstr);
+      args[i++] = "-p";
+      args[i++] = portstring;
+    }
+  else
+    {
+      if (!r_getservbyname ("ssh", "tcp", &serv_struct, NULL))
+        request->port = 22;
+      else
+        request->port = ntohs (serv_struct.s_port);
+    }
+
+  if (use_sftp_subsys)
+    {
+      oldstr = tempstr;
+      tempstr = g_strconcat (oldstr, " ", request->hostname, " -s sftp", NULL);
+      g_free (oldstr);
+      args[i++] = request->hostname;
+      args[i++] = "-s";
+      args[i++] = "sftp";
+      args[i] = NULL;
+    }
+  else
+    {
+      oldstr = tempstr;
+      tempstr = g_strconcat (oldstr, " ", request->hostname, " \"", execname, 
+                             "\"", NULL);
+      g_free (oldstr);
+      args[i++] = request->hostname;
+      args[i++] = execname;
+      args[i] = NULL;
+    }
+
+  request->logging_function (gftp_logging_misc, request->user_data, 
+                             _("Running program %s\n"), tempstr);
+  g_free (tempstr);
+  return (args);
+}
+
+
+static char *
+sshv2_start_login_sequence (gftp_request * request, int fd)
+{
+  char *tempstr, *pwstr, *tmppos;
+  size_t rem, len, diff, lastdiff, key_pos;
+  int wrotepw, ok;
+  ssize_t rd;
+
+  rem = len = SSH_LOGIN_BUFSIZE;
+  tempstr = g_malloc0 (len + 1);
+  key_pos = diff = lastdiff = 0;
+  wrotepw = 0;
+  ok = 1;
+
+  if (gftp_set_sockblocking (request, fd, 1) == -1)
+    return (NULL);
+
+  pwstr = g_strconcat (request->password, "\n", NULL);
+
+  errno = 0;
+  while (1)
+    {
+      if ((rd = gftp_read (request, tempstr + diff, rem - 1, fd)) <= 0)
+        {
+          ok = 0;
+          break;
+        }
+      rem -= rd;
+      diff += rd;
+      tempstr[diff] = '\0'; 
+
+      if (diff > 11 && strcmp (tempstr + diff - 10, "password: ") == 0)
+        {
+          if (wrotepw)
+            {
+              ok = SSH_ERROR_BADPASS;
+              break;
+            }
+
+          if (strstr (tempstr, "WARNING") != NULL ||
+              strstr (tempstr, _("WARNING")) != NULL)
+            {
+              ok = SSH_WARNING;
+              break;
+            }
+              
+          wrotepw = 1;
+          if (gftp_write (request, pwstr, strlen (pwstr), fd) < 0)
+            {
+              ok = 0;
+              break;
+            }
+        }
+      else if (diff > 2 && strcmp (tempstr + diff - 2, ": ") == 0 &&
+               ((tmppos = strstr (tempstr + key_pos, "Enter passphrase for RSA key")) != NULL ||
+                ((tmppos = strstr (tempstr + key_pos, "Enter passphrase for key '")) != NULL)))
+        {
+          key_pos = diff;
+          if (wrotepw)
+            {
+              ok = SSH_ERROR_BADPASS;
+              break;
+            }
+
+          if (strstr (tempstr, "WARNING") != NULL ||
+              strstr (tempstr, _("WARNING")) != NULL)
+            {
+              ok = SSH_WARNING;
+              break;
+            }
+
+          wrotepw = 1;
+          if (gftp_write (request, pwstr, strlen (pwstr), fd) < 0)
+            {
+              ok = 0;
+              break;
+            }
+        }
+      else if (diff > 10 && strcmp (tempstr + diff - 10, "(yes/no)? ") == 0)
+        {
+          ok = SSH_ERROR_QUESTION;
+          break;
+        }
+      else if (diff >= 5 && strcmp (tempstr + diff - 5, "xsftp") == 0)
+        break;
+      else if (rem <= 1)
+        {
+          request->logging_function (gftp_logging_recv, request->user_data,
+                                     "%s", tempstr + lastdiff);
+          len += SSH_LOGIN_BUFSIZE;
+          rem += SSH_LOGIN_BUFSIZE;
+          lastdiff = diff;
+          tempstr = g_realloc (tempstr, len);
+          continue;
+        }
+    }
+
+  g_free (pwstr);
+
+  if (*(tempstr + lastdiff) != '\0')
+    request->logging_function (gftp_logging_recv, request->user_data,
+                               "%s\n", tempstr + lastdiff);
+
+  if (ok <= 0)
+    {
+      if (ok == SSH_ERROR_BADPASS)
+        request->logging_function (gftp_logging_error, request->user_data,
+                               _("Error: An incorrect password was entered\n"));
+      else if (ok == SSH_ERROR_QUESTION)
+        request->logging_function (gftp_logging_error, request->user_data,
+                               _("Please connect to this host with the command line SSH utility and answer this question appropriately.\n"));
+      else if (ok == SSH_WARNING)
+        request->logging_function (gftp_logging_error, request->user_data,
+                                   _("Please correct the above warning to connect to this host.\n"));
+
+      g_free (tempstr);
+      return (NULL);
+    }
+ 
+  return (tempstr);
+}
+
+
+#ifdef G_HAVE_GINT64
+
+static gint64
+hton64 (gint64 val)
+{
+  if (G_BYTE_ORDER != G_BIG_ENDIAN)
+    return (GINT64_TO_BE (val));
+  else
+    return (val);
+}
+
+#endif
+
 
 static void
 sshv2_log_command (gftp_request * request, gftp_logging_level level,
@@ -523,8 +801,9 @@
 static int
 sshv2_connect (gftp_request * request)
 {
-  char **args, *tempstr, pts_name[20], *p1, p2, *exepath, port[6];
-  int version, fdm, fds, s[2], ret;
+  int version, fdm, fds, s[2], ret, ssh_use_askpass, sshv2_use_sftp_subsys;
+  char **args, *tempstr, pts_name[20], *p1, p2, *exepath, port[6],
+       *ssh2_sftp_path;
   sshv2_message message;
   pid_t child;
 
@@ -544,21 +823,25 @@
      any initial text from the server, and we'll block. So I just send a 
      xsftp server banner over. I hope this works on most Unices */
 
-  if (request->sftpserv_path == NULL ||
-      *request->sftpserv_path == '\0')
+  gftp_lookup_request_option (request, "ssh2_sftp_path", &ssh2_sftp_path);
+  gftp_lookup_request_option (request, "ssh_use_askpass", &ssh_use_askpass);
+  gftp_lookup_request_option (request, "sshv2_use_sftp_subsys", 
+                              &sshv2_use_sftp_subsys);
+
+  if (ssh2_sftp_path == NULL || *ssh2_sftp_path == '\0')
     {
       p1 = "";
       p2 = ' ';
     }
   else
     {
-      p1 = request->sftpserv_path;
+      p1 = ssh2_sftp_path;
       p2 = '/';
     }
 
   *port = '\0';
   exepath = g_strdup_printf ("echo -n xsftp ; %s%csftp-server", p1, p2);
-  args = make_ssh_exec_args (request, exepath, sshv2_use_sftp_subsys, port);
+  args = sshv2_gen_exec_args (request, exepath, sshv2_use_sftp_subsys, port);
 
   if (ssh_use_askpass || sshv2_use_sftp_subsys)
     {
@@ -608,8 +891,7 @@
       dup2 (fds, 2);
       if (!ssh_use_askpass && fds > 2)
         close (fds);
-      execvp (ssh_prog_name != NULL && *ssh_prog_name != '\0' ?
-              ssh_prog_name : "ssh", args);
+      execvp (args[0], args);
 
       printf (_("Error: Cannot execute ssh: %s\n"), g_strerror (errno));
       exit (1);
@@ -624,7 +906,7 @@
       tty_raw (fdm);
       if (!sshv2_use_sftp_subsys)
         {
-          tempstr = ssh_start_login_sequence (request, fdm);
+          tempstr = sshv2_start_login_sequence (request, fdm);
           if (!tempstr ||
               !(strlen (tempstr) > 4 && strcmp (tempstr + strlen (tempstr) - 5,
                                                 "xsftp") == 0))
@@ -1941,19 +2223,9 @@
 static void
 sshv2_set_config_options (gftp_request * request)
 {
-  if (request->sftpserv_path != NULL)
-    {
-      if (ssh2_sftp_path != NULL && 
-          strcmp (ssh2_sftp_path, request->sftpserv_path) == 0)
-        return;
+  int ssh_need_userpass;
 
-      g_free (request->sftpserv_path);
-      request->sftpserv_path = NULL;
-    }
-
-  if (ssh2_sftp_path != NULL)
-    request->sftpserv_path = g_strdup (ssh2_sftp_path);
-
+  gftp_lookup_request_option (request, "ssh_need_userpass", &ssh_need_userpass);
   request->need_userpass = ssh_need_userpass;
 }
 
@@ -1969,6 +2241,13 @@
 }
 
 
+void 
+sshv2_register_module (void)
+{
+  gftp_register_config_vars (config_vars);
+}
+
+
 void
 sshv2_init (gftp_request * request)
 {
@@ -1990,7 +2269,6 @@
   request->abort_transfer = sshv2_end_transfer; /* NOTE: uses sshv2_end_transfer */
   request->list_files = sshv2_list_files;
   request->get_next_file = sshv2_get_next_file;
-  request->set_data_type = NULL;
   request->get_file_size = sshv2_get_file_size;
   request->chdir = sshv2_chdir;
   request->rmdir = sshv2_rmdir;
@@ -2004,14 +2282,13 @@
   request->set_config_options = sshv2_set_config_options;
   request->swap_socks = sshv2_swap_socks;
   request->url_prefix = "ssh2";
-  request->protocol_name = "SSH2";
   request->need_hostport = 1;
-  request->need_userpass = ssh_need_userpass;
+  request->need_userpass = 1;
   request->use_cache = 1;
   request->use_threads = 1;
   request->always_connected = 0;
   request->protocol_data = g_malloc0 (sizeof (sshv2_params));
-  request->server_type = GFTP_TYPE_UNIX;
+  request->server_type = GFTP_DIRTYPE_UNIX;
   gftp_set_config_options (request);
 
   params = request->protocol_data;