summaryrefslogtreecommitdiff
path: root/daemon/gvfsftptask.c
diff options
context:
space:
mode:
authorRoss Lagerwall <rosslagerwall@gmail.com>2015-02-26 22:30:44 +0000
committerRoss Lagerwall <rosslagerwall@gmail.com>2015-04-09 22:10:36 +0100
commitdccf4aeea3f94251062836f2c6f5f37219c64054 (patch)
treee7a0eaac29a1cb61ce248ab07cb4d502490de917 /daemon/gvfsftptask.c
parent7cf5d5ff55fcbdebe0fb7b60e52ecb0c95ca63ee (diff)
downloadgvfs-dccf4aeea3f94251062836f2c6f5f37219c64054.tar.gz
ftp: Implement TLS support
Implement TLS support (aka explicit ftps). This is done by using a different URL scheme, ftps, so that it is only used if explicitly specified. Although the protocol allows transparently upgrading a normal connection to a secure one, there are several problems with this. FEAT is needed to determine support for it but some servers do not allow this before login. Some servers are configured to allow AUTH TLS but have firewalls that block data connections because they can't inspect the traffic. Servers may disallow TLS on the data connection, making it unclear to the user how secure the connection is. Finally, there may be verification errors which need to be presented to the user, and these are unexpected because they did not choose to use ftps. Making secure ftp opt-in as a separate URL scheme side-steps most of these issues as well as ensuring there are no regressions for normal ftp. When using ftps, we assume that the server implements AUTH TLS so the connection is secured before login. It is also assumed that TLS for data connections is allowed, so both control and data connection are secure before any information is transferred. Verification errors are presented during mounting. If the identity changes on subsequent reconnections, the connection is aborted. While presenting verification errors to the user in this way is perhaps not the best way of handling security, it is fairly standard. The implementation has been successfully tested on vsftpd, ProFTPD, Pure-FTPd, IIS, and FileZilla Server. Based on a patch by Benjamin Otte. https://bugzilla.gnome.org/show_bug.cgi?id=526582
Diffstat (limited to 'daemon/gvfsftptask.c')
-rw-r--r--daemon/gvfsftptask.c75
1 files changed, 73 insertions, 2 deletions
diff --git a/daemon/gvfsftptask.c b/daemon/gvfsftptask.c
index c70262b1..2209c2b1 100644
--- a/daemon/gvfsftptask.c
+++ b/daemon/gvfsftptask.c
@@ -161,6 +161,28 @@ do_broadcast (GCancellable *cancellable, GCond *cond)
g_cond_broadcast (cond);
}
+/* Decide whether to allow verification errors for control and data connections
+ * after the initial connection. The connection is only allowed if the
+ * identity is the same as for the initial connection. */
+static gboolean
+reconnect_certificate_cb (GTlsConnection *conn,
+ GTlsCertificate *certificate,
+ GTlsCertificateFlags errors,
+ gpointer user_data)
+{
+ GVfsBackendFtp *ftp = G_VFS_BACKEND_FTP (user_data);
+
+ /* If the verification result has changed in some way, abort the
+ * connection. */
+ if (errors != ftp->certificate_errors)
+ return FALSE;
+
+ /* Only allow the connection if the certificate presented is the same as for
+ * the initial connection which the user accepted. */
+ return ftp->certificate &&
+ g_tls_certificate_is_same (certificate, ftp->certificate);
+}
+
/**
* g_vfs_ftp_task_acquire_connection:
* @task: a task without an associated connection
@@ -229,6 +251,8 @@ g_vfs_ftp_task_acquire_connection (GVfsFtpTask *task)
if (G_LIKELY (task->conn != NULL))
{
g_vfs_ftp_task_receive (task, 0, NULL);
+ if (ftp->use_tls)
+ g_vfs_ftp_task_enable_tls (task, reconnect_certificate_cb, ftp);
g_vfs_ftp_task_login (task, ftp->user, ftp->password);
g_vfs_ftp_task_setup_connection (task);
if (G_LIKELY (!g_vfs_ftp_task_is_in_error (task)))
@@ -1144,8 +1168,8 @@ g_vfs_ftp_task_setup_data_connection (GVfsFtpTask *task)
* g_vfs_ftp_task_open_data_connection:
* @task: a task
*
- * Tries to open a data connection to the ftp server. If the operation fails,
- * @task will be set into an error state.
+ * Tries to open a data connection to the ftp server and secures it if
+ * necessary. If the operation fails, @task will be set into an error state.
**/
void
g_vfs_ftp_task_open_data_connection (GVfsFtpTask *task)
@@ -1160,5 +1184,52 @@ g_vfs_ftp_task_open_data_connection (GVfsFtpTask *task)
g_vfs_ftp_connection_accept_data_connection (task->conn,
task->cancellable,
&task->error);
+
+ if (g_vfs_ftp_task_is_in_error (task))
+ return;
+
+ if (task->backend->use_tls)
+ g_vfs_ftp_connection_data_connection_enable_tls (task->conn,
+ task->backend->server_identity,
+ reconnect_certificate_cb,
+ task->backend,
+ task->cancellable,
+ &task->error);
}
+/**
+ * g_vfs_ftp_task_enable_tls:
+ * @task: a task
+ * @cb: callback called if there's a verification error
+ * @user_data: user data passed to @cb
+ *
+ * Tries to enable tls on the control connection to an ftp server.
+ * If the operation fails, @task will be set into an error state.
+ **/
+gboolean
+g_vfs_ftp_task_enable_tls (GVfsFtpTask *task,
+ CertificateCallback cb,
+ gpointer user_data)
+{
+ if (g_vfs_ftp_task_is_in_error (task))
+ return FALSE;
+
+ if (!g_vfs_ftp_task_send (task, 0, "AUTH TLS"))
+ return FALSE;
+
+ if (!g_vfs_ftp_connection_enable_tls (task->conn,
+ task->backend->server_identity,
+ cb,
+ user_data,
+ task->cancellable,
+ &task->error))
+ return FALSE;
+
+ if (!g_vfs_ftp_task_send (task, 0, "PBSZ 0"))
+ return FALSE;
+
+ if (!g_vfs_ftp_task_send (task, 0, "PROT P"))
+ return FALSE;
+
+ return TRUE;
+}