Mercurial > gftp.yaz
diff lib/sshv2.c @ 458:656a0b3d1403
2004-4-10 Brian Masney <masneyb@gftp.org>
* lib/gftp.h lib/pty.c lib/sshv2.c - added gftp_exec() that will always
open a pseudo terminal and a separate socket pair for the stdin/stdout
file descriptors. The banner and password request will come through the
pseudo terminal while the sftp protocol specific data will always come
through the socket pair. This allows for a much cleaner SSH login
sequence that does not require echo xsftp to capture a login banner.
Removed option ssh_use_askpass since it is no longer needed.
This code is based off of a suggestion from Gertjan Halkes
* src/text/gftp-text.c - removed setting the options ssh_use_askpass
and sshv2_use_sftp_subsys
author | masneyb |
---|---|
date | Sat, 10 Apr 2004 15:14:46 +0000 |
parents | e97f1fb92539 |
children | 075f89b4395c |
line wrap: on
line diff
--- a/lib/sshv2.c Sat Apr 10 00:28:31 2004 +0000 +++ b/lib/sshv2.c Sat Apr 10 15:14:46 2004 +0000 @@ -42,11 +42,6 @@ gftp_option_type_checkbox, GINT_TO_POINTER(1), NULL, GFTP_CVARS_FLAGS_SHOW_BOOKMARK, 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, - GFTP_CVARS_FLAGS_SHOW_BOOKMARK, - 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, GFTP_CVARS_FLAGS_SHOW_BOOKMARK, @@ -253,7 +248,7 @@ " %s -s sftp", request->hostname); else sshv2_add_exec_args (&logstr, &logstr_len, &args, &args_len, &args_cur, - " %s \"%s\"", request->hostname, execname); + " %s %s", request->hostname, execname); request->logging_function (gftp_logging_misc, request, _("Running program %s\n"), logstr); @@ -262,33 +257,81 @@ } -static char * -sshv2_start_login_sequence (gftp_request * request, int fd) +static int +sshv2_start_login_sequence (gftp_request * request, int fdm, int ptymfd) { + size_t rem, len, diff, lastdiff; char *tempstr, *pwstr, *tmppos; - size_t rem, len, diff, lastdiff, key_pos; - int wrotepw, ok; + int wrotepw, ok, maxfd, ret; + fd_set rset, eset; ssize_t rd; rem = len = SSH_LOGIN_BUFSIZE; tempstr = g_malloc0 (len + 1); - key_pos = diff = lastdiff = 0; + diff = lastdiff = 0; wrotepw = 0; ok = 1; - if (gftp_fd_set_sockblocking (request, fd, 1) == -1) - return (NULL); + if (gftp_fd_set_sockblocking (request, fdm, 1) == -1) + return (GFTP_ERETRYABLE); + + if (gftp_fd_set_sockblocking (request, ptymfd, 1) == -1) + return (GFTP_ERETRYABLE); - pwstr = g_strconcat (request->password, "\n", NULL); + if (request->password == NULL) + pwstr = g_strdup ("\n"); + else + pwstr = g_strconcat (request->password, "\n", NULL); + + FD_ZERO (&rset); + FD_ZERO (&eset); + maxfd = fdm > ptymfd ? fdm : ptymfd; errno = 0; while (1) { - if ((rd = gftp_fd_read (request, tempstr + diff, rem - 1, fd)) <= 0) + FD_SET (fdm, &rset); + FD_SET (ptymfd, &rset); + + FD_SET (fdm, &eset); + FD_SET (ptymfd, &eset); + + ret = select (maxfd + 1, &rset, NULL, &eset, NULL); + if (ret < 0 && errno == EINTR) + continue; + + if (ret < 0) { - ok = 0; + request->logging_function (gftp_logging_error, request, + _("Connection to %s timed out\n"), + request->hostname); + gftp_disconnect (request); + return (GFTP_ERETRYABLE); + } + + if (FD_ISSET (fdm, &eset) || FD_ISSET (ptymfd, &eset)) + { + request->logging_function (gftp_logging_error, request, + _("Error: Could not read from socket: %s\n"), + g_strerror (errno)); + gftp_disconnect (request); + return (GFTP_ERETRYABLE); + } + + if (FD_ISSET (fdm, &rset)) + { + ok = 1; break; } + else if (!FD_ISSET (ptymfd, &rset)) + continue; + + rd = gftp_fd_read (request, tempstr + diff, rem - 1, ptymfd); + if (rd < 0) + return (rd); + else if (rd == 0) + continue; + rem -= rd; diff += rd; tempstr[diff] = '\0'; @@ -310,17 +353,16 @@ } wrotepw = 1; - if (gftp_fd_write (request, pwstr, strlen (pwstr), fd) < 0) + if (gftp_fd_write (request, pwstr, strlen (pwstr), ptymfd) < 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))) + ((tmppos = strstr (tempstr, "Enter passphrase for RSA key")) != NULL || + ((tmppos = strstr (tempstr, "Enter passphrase for key '")) != NULL))) { - key_pos = diff; if (wrotepw) { ok = SSH_ERROR_BADPASS; @@ -335,7 +377,7 @@ } wrotepw = 1; - if (gftp_fd_write (request, pwstr, strlen (pwstr), fd) < 0) + if (gftp_fd_write (request, pwstr, strlen (pwstr), ptymfd) < 0) { ok = 0; break; @@ -346,8 +388,6 @@ 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, @@ -366,6 +406,8 @@ request->logging_function (gftp_logging_recv, request, "%s\n", tempstr + lastdiff); + g_free (tempstr); + if (ok <= 0) { if (ok == SSH_ERROR_BADPASS) @@ -378,11 +420,10 @@ request->logging_function (gftp_logging_error, request, _("Please correct the above warning to connect to this host.\n")); - g_free (tempstr); - return (NULL); + return (GFTP_EFATAL); } - return (tempstr); + return (0); } @@ -585,7 +626,7 @@ buf[len + 5] = '\0'; #ifdef DEBUG - printf ("\rSending: "); + printf ("\rSending to FD %d: ", request->datafd); for (clen=0; clen<len + 5; clen++) printf ("%x ", buf[clen] & 0xff); printf ("\n"); @@ -848,9 +889,9 @@ static int sshv2_connect (gftp_request * request) { - int version, ret, fdm; - intptr_t ssh_use_askpass, sshv2_use_sftp_subsys; - char **args, *tempstr, *p1, p2, *exepath, *ssh2_sftp_path; + char **args, *p1, p2, *exepath, *ssh2_sftp_path; + intptr_t sshv2_use_sftp_subsys; + int version, ret, fdm, ptymfd; struct servent serv_struct; sshv2_params * params; sshv2_message message; @@ -869,13 +910,7 @@ _("Opening SSH connection to %s\n"), request->hostname); - /* Ugh!! We don't get a login banner from sftp-server, and if we are - using ssh-agent to cache a users password, then we won't receive - 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 */ - 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); @@ -902,35 +937,20 @@ request->port = ntohs (serv_struct.s_port); } - exepath = g_strdup_printf ("echo -n xsftp ; %s%csftp-server", p1, p2); + exepath = g_strdup_printf ("%s%csftp-server", p1, p2); args = sshv2_gen_exec_args (request, exepath, sshv2_use_sftp_subsys); - if (ssh_use_askpass || sshv2_use_sftp_subsys) - child = gftp_exec_without_new_pty (request, &fdm, args); - else - child = gftp_exec_with_new_pty (request, &fdm, args); + child = gftp_exec (request, &fdm, &ptymfd, args); if (child == 0) exit (0); - else if (child < 0) - return (GFTP_ERETRYABLE); - - if (!sshv2_use_sftp_subsys) - { - tempstr = sshv2_start_login_sequence (request, fdm); - if (!tempstr || !(strlen (tempstr) > 4 && strcmp (tempstr + strlen (tempstr) - 5, - "xsftp") == 0)) - { - sshv2_free_args (args); - g_free (exepath); - return (GFTP_EFATAL); - } - g_free (tempstr); - } sshv2_free_args (args); g_free (exepath); + if (child < 0) + return (GFTP_ERETRYABLE); + request->datafd = fdm; version = htonl (SSH_MY_VERSION); @@ -938,6 +958,10 @@ &version, 4)) < 0) return (ret); + ret = sshv2_start_login_sequence (request, fdm, ptymfd); + if (ret < 0) + return (ret); + memset (&message, 0, sizeof (message)); ret = sshv2_read_response (request, &message, -1); if (ret < 0)