[gvfs] sftp: Login to both connections when mounting
- From: Ross Lagerwall <rossl src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gvfs] sftp: Login to both connections when mounting
- Date: Sun, 7 Jun 2015 16:10:49 +0000 (UTC)
commit 542fed5a189b08416fc6255be13abb06dd248919
Author: Ross Lagerwall <rosslagerwall gmail com>
Date: Tue Mar 31 17:38:32 2015 +0100
sftp: Login to both connections when mounting
Login to the command connection and the data connection when mounting.
Any password entered during the first connection is reused for the
second connection.
Because the data connection is not essential, do not fail if the
connection attempt fails, and introduce a function to determine if a
connection is usable.
https://bugzilla.gnome.org/show_bug.cgi?id=747128
daemon/gvfsbackendsftp.c | 175 ++++++++++++++++++++++++++++++++--------------
1 files changed, 122 insertions(+), 53 deletions(-)
---
diff --git a/daemon/gvfsbackendsftp.c b/daemon/gvfsbackendsftp.c
index 1ccf8d2..112dcfb 100644
--- a/daemon/gvfsbackendsftp.c
+++ b/daemon/gvfsbackendsftp.c
@@ -286,6 +286,12 @@ destroy_connection (Connection *conn)
g_clear_object (&conn->error_stream);
}
+static gboolean
+connection_is_usable (Connection *conn)
+{
+ return conn->command_stream != NULL;
+}
+
static void
g_vfs_backend_sftp_finalize (GObject *object)
{
@@ -964,6 +970,7 @@ static gboolean
handle_login (GVfsBackend *backend,
GMountSource *mount_source,
int tty_fd, int stdout_fd, int stderr_fd,
+ gboolean initial_connection,
GError **error)
{
GVfsBackendSftp *op_backend = G_VFS_BACKEND_SFTP (backend);
@@ -981,13 +988,14 @@ handle_login (GVfsBackend *backend,
const gchar *authtype = NULL;
gchar *object = NULL;
char *prompt;
+ int attempts = 0;
#ifdef PRINT_DEBUG
static int i = 0;
i++;
#endif
- DEBUG ("handle_login #%d - user: %s, host: %s, port: %d\n",
- i, op_backend->user, op_backend->host, op_backend->port);
+ DEBUG ("handle_login #%d, initial_connection = %d - user: %s, host: %s, port: %d\n",
+ i, initial_connection, op_backend->user, op_backend->host, op_backend->port);
if (op_backend->client_vendor == SFTP_VENDOR_SSH)
prompt_fd = stderr_fd;
@@ -1038,6 +1046,10 @@ handle_login (GVfsBackend *backend,
DEBUG ("handle_login #%d - prompt: \"%s\"\n", i, buffer);
/*
+ * If logging in on a second connection (e.g. the data connection), use
+ * the user and password stored in the backend and don't retry if it
+ * fails.
+ *
* If the input URI contains a username
* if the input URI contains a password, we attempt one login and return
GNOME_VFS_ERROR_ACCESS_DENIED on failure.
* if the input URI contains no password, we query the user until he provides a correct one, or he
cancels.
@@ -1065,9 +1077,19 @@ handle_login (GVfsBackend *backend,
gboolean aborted = FALSE;
gsize bytes_written;
+ attempts++;
authtype = get_authtype_from_password_line (buffer);
object = get_object_from_password_line (buffer);
+ if (!initial_connection && attempts > 1)
+ {
+ g_set_error_literal (error,
+ G_IO_ERROR, G_IO_ERROR_PERMISSION_DENIED,
+ _("Permission denied"));
+ ret_val = FALSE;
+ break;
+ }
+
/* If password is in keyring at this point is because it failed */
if (!op_backend->tmp_password && (password_in_keyring ||
!g_vfs_keyring_lookup_password (op_backend->user,
@@ -1134,8 +1156,9 @@ handle_login (GVfsBackend *backend,
}
else if (op_backend->tmp_password)
{
- /* I already a have a password of a previous login attempt
- * that failed because the user provided a new user name
+ /* I already have a password of a previous login attempt
+ * (either because this is a second connection or because the
+ * user provided a new user name).
*/
new_password = op_backend->tmp_password;
op_backend->tmp_password = NULL;
@@ -1257,7 +1280,7 @@ handle_login (GVfsBackend *backend,
}
}
- if (ret_val)
+ if (ret_val && initial_connection)
{
DEBUG ("handle_login #%d - password_save: %d\n", i, op_backend->password_save);
@@ -1274,6 +1297,10 @@ handle_login (GVfsBackend *backend,
0,
new_password,
op_backend->password_save);
+
+ /* Keep the successful password for subsequent connections. */
+ op_backend->tmp_password = new_password;
+ new_password = NULL;
}
DEBUG ("handle_login #%d - ret_val: %d\n", i, ret_val);
@@ -1732,7 +1759,17 @@ do_mount (GVfsBackend *backend,
GVfsJobMount *job,
GMountSpec *mount_spec,
GMountSource *mount_source,
- gboolean is_automount)
+ gboolean is_automount);
+
+static gboolean
+setup_connection (GVfsBackend *backend,
+ GVfsJobMount *job,
+ GMountSpec *mount_spec,
+ GMountSource *mount_source,
+ gboolean is_automount,
+ Connection *connection,
+ gboolean initial_connection,
+ GError **error)
{
const struct {
const char *name; /* extension_name field */
@@ -1743,100 +1780,84 @@ do_mount (GVfsBackend *backend,
};
GVfsBackendSftp *op_backend = G_VFS_BACKEND_SFTP (backend);
- gchar **args; /* Enough for now, extend if you add more args */
+ gchar **args;
pid_t pid;
int tty_fd, stdout_fd, stdin_fd, stderr_fd, slave_fd;
- GError *error;
GInputStream *is;
GDataOutputStream *command;
GDataInputStream *reply;
gboolean res;
- GMountSpec *sftp_mount_spec;
char *extension_name, *extension_data;
- char *display_name;
int i;
args = setup_ssh_commandline (backend);
- error = NULL;
if (!spawn_ssh (backend,
args, &pid,
&tty_fd, &stdin_fd, &stdout_fd, &stderr_fd, &slave_fd,
- &error))
+ error))
{
- g_vfs_job_failed_from_error (G_VFS_JOB (job), error);
- g_error_free (error);
g_strfreev (args);
- return;
+ return FALSE;
}
g_strfreev (args);
- op_backend->command_connection.op_backend = op_backend;
- op_backend->command_connection.command_stream = g_unix_output_stream_new (stdin_fd, TRUE);
+ connection->op_backend = op_backend;
+ connection->command_stream = g_unix_output_stream_new (stdin_fd, TRUE);
command = new_command_stream (op_backend, SSH_FXP_INIT);
g_data_output_stream_put_int32 (command,
SSH_FILEXFER_VERSION, NULL, NULL);
- send_command_sync_and_unref_command (&op_backend->command_connection,
- command,
- NULL, NULL);
+ send_command_sync_and_unref_command (connection, command, NULL, NULL);
if (tty_fd == -1)
- res = wait_for_reply (backend, stdout_fd, &error);
+ res = wait_for_reply (backend, stdout_fd, error);
else
{
res = handle_login (backend,
mount_source,
tty_fd, stdout_fd, stderr_fd,
- &error);
+ initial_connection,
+ error);
close (slave_fd);
}
-
+
if (!res)
{
- if (error->code == G_IO_ERROR_INVALID_ARGUMENT)
+ if (error && (*error)->code == G_IO_ERROR_INVALID_ARGUMENT)
{
/* New username provided by the user,
* we need to re-spawn the ssh command
*/
- g_error_free (error);
+ g_clear_error (error);
do_mount (backend, job, mount_spec, mount_source, is_automount);
}
- else
- {
- g_vfs_job_failed_from_error (G_VFS_JOB (job), error);
- g_error_free (error);
- }
-
- return;
+
+ return FALSE;
}
- op_backend->command_connection.reply_stream = g_unix_input_stream_new (stdout_fd, TRUE);
- op_backend->command_connection.reply_stream_cancellable = g_cancellable_new ();
+ connection->reply_stream = g_unix_input_stream_new (stdout_fd, TRUE);
+ connection->reply_stream_cancellable = g_cancellable_new ();
make_fd_nonblocking (stderr_fd);
is = g_unix_input_stream_new (stderr_fd, TRUE);
- op_backend->command_connection.error_stream = g_data_input_stream_new (is);
+ connection->error_stream = g_data_input_stream_new (is);
g_object_unref (is);
-
- reply = read_reply_sync (&op_backend->command_connection, NULL, NULL);
+
+ reply = read_reply_sync (connection, NULL, NULL);
if (reply == NULL)
{
- look_for_stderr_errors (&op_backend->command_connection, &error);
- g_vfs_job_failed_from_error (G_VFS_JOB (job), error);
- g_error_free (error);
- return;
+ look_for_stderr_errors (connection, error);
+ return FALSE;
}
-
+
if (g_data_input_stream_read_byte (reply, NULL, NULL) != SSH_FXP_VERSION)
{
- g_set_error_literal (&error, G_IO_ERROR, G_IO_ERROR_FAILED, _("Protocol error"));
- g_vfs_job_failed_from_error (G_VFS_JOB (job), error);
- g_error_free (error);
- return;
+ g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED, _("Protocol error"));
+ return FALSE;
}
-
+
op_backend->protocol_version = g_data_input_stream_read_uint32 (reply, NULL, NULL);
while ((extension_name = read_string (reply, NULL)) != NULL)
@@ -1857,16 +1878,64 @@ do_mount (GVfsBackend *backend,
g_object_unref (reply);
- if (!get_uid_sync (op_backend) || !get_home_sync (op_backend))
+ if (initial_connection &&
+ (!get_uid_sync (op_backend) || !get_home_sync (op_backend)))
{
- g_set_error_literal (&error, G_IO_ERROR, G_IO_ERROR_FAILED, _("Protocol error"));
- g_vfs_job_failed_from_error (G_VFS_JOB (job), error);
- g_error_free (error);
- return;
+ g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED, _("Protocol error"));
+ return FALSE;
}
g_object_ref (op_backend);
- read_reply_async (&op_backend->command_connection);
+ read_reply_async (connection);
+
+ return TRUE;
+}
+
+static void
+do_mount (GVfsBackend *backend,
+ GVfsJobMount *job,
+ GMountSpec *mount_spec,
+ GMountSource *mount_source,
+ gboolean is_automount)
+{
+ GVfsBackendSftp *op_backend = G_VFS_BACKEND_SFTP (backend);
+ GError *error = NULL;
+ GMountSpec *sftp_mount_spec;
+ char *display_name;
+
+ if (!setup_connection (backend,
+ job,
+ mount_spec,
+ mount_source,
+ is_automount,
+ &op_backend->command_connection,
+ TRUE,
+ &error))
+ {
+ if (error)
+ {
+ g_vfs_job_failed_from_error (G_VFS_JOB (job), error);
+ g_error_free (error);
+ }
+ /* When a new user is specified, do_mount is called recursively so we
+ * need to return here without finishing the job. */
+ return;
+ }
+
+ if (!setup_connection (backend,
+ job,
+ mount_spec,
+ mount_source,
+ is_automount,
+ &op_backend->data_connection,
+ FALSE,
+ NULL))
+ {
+ g_warning ("Setting up data connection failed\n");
+ destroy_connection (&op_backend->data_connection);
+ }
+
+ g_clear_pointer (&op_backend->tmp_password, g_free);
sftp_mount_spec = g_mount_spec_new ("sftp");
if (op_backend->user_specified_in_uri)
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]