From c6c3fca29a48d74d0fcba5aaf456e7c83735a528 Mon Sep 17 00:00:00 2001 From: wbaumann Date: Sun, 5 Feb 2012 12:19:13 +0000 Subject: [PATCH] Read client certificates in mount_davfs.c --- ChangeLog | 4 ++ src/mount_davfs.c | 153 +++++++++++++++++++++++++++++++++------------- src/mount_davfs.h | 4 +- src/webdav.c | 34 +---------- 4 files changed, 119 insertions(+), 76 deletions(-) diff --git a/ChangeLog b/ChangeLog index 4d72cc2..5ab4a4e 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,6 +1,10 @@ ChangeLog for davfs2 -------------------- +2012-02-05 Werner Baumann (werner.baumann@onlinehome.de) + * mount_davfs.c, mount_davfs.h, webdav.c: + Better handling of client certificates. + 2012-02-01 Werner Baumann (werner.baumann@onlinehome.de) * mount_davfs.c, mount_davfs.h, webdav.c: Add option trust_server_cert. diff --git a/src/mount_davfs.c b/src/mount_davfs.c index 9a922f5..e773356 100644 --- a/src/mount_davfs.c +++ b/src/mount_davfs.c @@ -216,7 +216,7 @@ static void read_no_proxy_list(dav_args *args); static void -read_secrets(dav_args *args, const char *filename); +read_secrets(dav_args *args, const char *filename, int system); static int split_uri(char **scheme, char **host, int *port,char **path, const char *uri); @@ -499,6 +499,24 @@ check_dirs(dav_args *args) } release_privileges(args); + if (args->sys_clicert) { + gain_privileges(args); + if (stat(args->clicert, &st) < 0) + error(EXIT_FAILURE, 0, _("can't read client certificate %s"), + args->clicert); + release_privileges(args); + if (st.st_uid != 0) + error(EXIT_FAILURE, 0, + _("client certificate file %s has wrong owner"), + args->sys_clicert); + if ((st.st_mode & + (S_IXUSR | S_IRWXG | S_IRWXO | S_ISUID | S_ISGID | S_ISVTX)) + != 0) + error(EXIT_FAILURE, 0, + _("client certificate file %s has wrong permissions"), + args->sys_clicert); + } + fname = xasprintf("%s/%s", DAV_SYS_CONF_DIR, DAV_SECRETS); if (stat(fname, &st) == 0) { if (st.st_uid != 0) @@ -556,6 +574,22 @@ check_dirs(dav_args *args) } free(path); + if (args->clicert) { + if (stat(args->clicert, &st) < 0) + error(EXIT_FAILURE, 0, _("can't read client certificate %s"), + args->clicert); + if (st.st_uid != args->uid) + error(EXIT_FAILURE, 0, + _("client certificate file %s has wrong owner"), + args->clicert); + if ((st.st_mode & + (S_IXUSR | S_IRWXG | S_IRWXO | S_ISUID | S_ISGID | S_ISVTX)) + != 0) + error(EXIT_FAILURE, 0, + _("client certificate file %s has wrong permissions"), + args->clicert); + } + if (stat(args->secrets, &st) == 0) { if (st.st_uid != args->uid) error(EXIT_FAILURE, 0, _("file %s has wrong owner"), @@ -1039,7 +1073,7 @@ parse_config(dav_args *args) } } if (!args->ca_cert) - error(EXIT_FAILURE, 0, _("can't read server certificate %s"), + error(EXIT_FAILURE, 0, _("can't read CA certificate %s"), args->trust_ca_cert); } @@ -1076,38 +1110,31 @@ parse_config(dav_args *args) args->secrets = xasprintf("%s/.%s/%s", args->home, PACKAGE, DAV_SECRETS); - if (args->clicert) + if (args->clicert) { expand_home(&args->clicert, args); - if (args->clicert && *args->clicert != '/' && !args->privileged) { - char *f = xasprintf("%s/.%s/%s/%s/%s", args->home, PACKAGE, - DAV_CERTS_DIR, DAV_CLICERTS_DIR, args->clicert); - if (access(f, F_OK) == 0) { + if (*args->clicert != '/') { + char *f = xasprintf("%s/.%s/%s/%s/%s", args->home, PACKAGE, + DAV_CERTS_DIR, DAV_CLICERTS_DIR, args->clicert); free(args->clicert); args->clicert = f; } - } - if (args->clicert && *args->clicert != '/' && args->privileged) { - char *f = xasprintf("%s/%s/%s/%s", DAV_SYS_CONF_DIR, DAV_CERTS_DIR, - DAV_CLICERTS_DIR, args->clicert); - free(args->clicert); - args->clicert = f; - } - if (args->clicert) { - struct stat st; - gain_privileges(args); - if (stat(args->clicert, &st) < 0) + args->client_cert = ne_ssl_clicert_read(args->clicert); + if (!args->client_cert) error(EXIT_FAILURE, 0, _("can't read client certificate %s"), args->clicert); + } else if (args->sys_clicert) { + if (*args->sys_clicert != '/') { + char *f = xasprintf("%s/.%s/%s/%s/%s", args->home, PACKAGE, + DAV_CERTS_DIR, DAV_CLICERTS_DIR, + args->sys_clicert); + free(args->clicert); + args->clicert = f; + } + gain_privileges(args); + args->client_cert = ne_ssl_clicert_read(args->sys_clicert); release_privileges(args); - if (st.st_uid != args->uid && st.st_uid != 0) - error(EXIT_FAILURE, 0, - _("client certificate file %s has wrong owner"), - args->clicert); - if ((st.st_mode & - (S_IXUSR | S_IRWXG | S_IRWXO | S_ISUID | S_ISGID | S_ISVTX)) - != 0) - error(EXIT_FAILURE, 0, - _("client certificate file %s has wrong permissions"), + if (!args->client_cert) + error(EXIT_FAILURE, 0, _("can't read client certificate %s"), args->clicert); } @@ -1183,11 +1210,11 @@ static void parse_secrets(dav_args *args) { gain_privileges(args); - read_secrets(args, DAV_SYS_CONF_DIR "/" DAV_SECRETS); + read_secrets(args, DAV_SYS_CONF_DIR "/" DAV_SECRETS, 1); release_privileges(args); if (args->secrets) { - read_secrets(args, args->secrets); + read_secrets(args, args->secrets, 0); } if (args->cl_username) { @@ -1241,6 +1268,19 @@ parse_secrets(dav_args *args) } } + if (args->client_cert && ne_ssl_clicert_encrypted(args->client_cert)) { + if (!args->clicert_pw && args->askauth) { + printf(_("Please enter the password to decrypt client\n" + "certificate %s.\n"), args->clicert); + args->clicert_pw = dav_user_input_hidden(_("Password: ")); + } + if (!args->clicert_pw + || ne_ssl_clicert_decrypt(args->client_cert, + args->clicert_pw) != 0) + error(EXIT_FAILURE, 0, _("can't decrypt client certificate %s"), + args->clicert); + } + if (args->debug & DAV_DBG_SECRETS) { syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG), "Secrets:"); syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG), @@ -1456,11 +1496,11 @@ delete_args(dav_args *args) if (args->trust_ca_cert) free(args->trust_ca_cert); if (args->ca_cert) - free(args->ca_cert); + ne_ssl_cert_free(args->ca_cert); if (args->trust_server_cert) free(args->trust_server_cert); if (args->server_cert) - free(args->server_cert); + ne_ssl_cert_free(args->server_cert); if (args->secrets) free(args->secrets); if (args->username) { @@ -1475,6 +1515,10 @@ delete_args(dav_args *args) } if (args->clicert) free(args->clicert); + if (args->sys_clicert) + free(args->sys_clicert); + if (args->client_cert) + ne_ssl_clicert_free(args->client_cert); if (args->clicert_pw) { memset(args->clicert_pw, '\0', strlen(args->clicert_pw)); free(args->clicert_pw); @@ -1846,10 +1890,14 @@ log_dbg_config(dav_args *args) " path: %s", args->path); syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG), " trust_ca_cert: %s", args->trust_ca_cert); + syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG), + " trust_server_cert: %s", args->trust_server_cert); syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG), " secrets: %s", args->secrets); syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG), " clicert: %s", args->clicert); + syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG), + " sys_clicert: %s", args->sys_clicert); syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG), " p_host: %s", args->p_host); syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG), @@ -2155,10 +2203,14 @@ read_config(dav_args *args, const char * filename, int system) if (args->secrets) free(args->secrets); args->secrets = xstrdup(parmv[1]); - } else if (strcmp(parmv[0], "clientcert") == 0) { + } else if (!system && strcmp(parmv[0], "clientcert") == 0) { if (args->clicert) free(args->clicert); args->clicert = xstrdup(parmv[1]); + } else if (system && strcmp(parmv[0], "clientcert") == 0) { + if (args->sys_clicert) + free(args->sys_clicert); + args->sys_clicert = xstrdup(parmv[1]); } else if (system && strcmp(parmv[0], "proxy") == 0) { if (split_uri(NULL, &args->p_host, &args->p_port, NULL, parmv[1]) != 0) @@ -2322,7 +2374,7 @@ read_no_proxy_list(dav_args *args) Requires: scheme, host, port, path, clicert, p_host, p_port Provides: username, password, p_user, p_passwd, clicert_pw. */ static void -read_secrets(dav_args *args, const char *filename) +read_secrets(dav_args *args, const char *filename, int system) { FILE *file = fopen(filename, "r"); if (!file) { @@ -2331,6 +2383,17 @@ read_secrets(dav_args *args, const char *filename) return; } + char *ccert = NULL; + if (!system && args->clicert) { + ccert = strrchr(args->clicert, '/'); + } else if (system && args->sys_clicert) { + ccert = strrchr(args->sys_clicert, '/'); + } + if (ccert && *(ccert + 1) == '\0') + ccert = NULL; + if (ccert) + ccert++; + size_t n = 0; char *line = NULL; int length = getline(&line, &n, file); @@ -2358,15 +2421,6 @@ read_secrets(dav_args *args, const char *filename) char *mp = canonicalize_file_name(parmv[0]); - char *ccert = NULL; - if (args->clicert) { - ccert = strrchr(args->clicert, '/'); - if (ccert && *(ccert + 1) == '\0') - ccert = NULL; - if (ccert) - ccert++; - } - if ((mp && strcmp(mp, mpoint) == 0) || (scheme && args->scheme && strcmp(scheme, args->scheme) == 0 @@ -2404,7 +2458,7 @@ read_secrets(dav_args *args, const char *filename) if (count == 3) args->p_passwd = xstrdup(parmv[2]); - } else if (args->clicert + } else if (!system && args->clicert && (strcmp(parmv[0], args->clicert) == 0 || strcmp(parmv[0], ccert) == 0)) { @@ -2416,6 +2470,19 @@ read_secrets(dav_args *args, const char *filename) free(args->clicert_pw); } args->clicert_pw = xstrdup(parmv[1]); + + } else if (system && args->sys_clicert + && (strcmp(parmv[0], args->sys_clicert) == 0 + || strcmp(parmv[0], ccert) == 0)) { + + if (count != 2) + error_at_line(EXIT_FAILURE, 0, filename, lineno, + _("malformed line")); + if (args->clicert_pw) { + memset(args->clicert_pw, '\0', strlen(args->clicert_pw)); + free(args->clicert_pw); + } + args->clicert_pw = xstrdup(parmv[1]); } if (scheme) free(scheme); diff --git a/src/mount_davfs.h b/src/mount_davfs.h index 27c9278..644b787 100644 --- a/src/mount_davfs.h +++ b/src/mount_davfs.h @@ -73,7 +73,9 @@ typedef struct { char *username; /* User secrets file, system secrets file */ char *cl_username; /* Command line */ char *password; /* User secrets file, system secrets file */ - char *clicert; /* User config file, system config file */ + char *clicert; /* User config file */ + char *sys_clicert; /* System config file */ + ne_ssl_client_cert *client_cert; char *clicert_pw; /* User secrets file, system secrets file */ char *p_host; /* User config file, sys conf f., environment */ int p_port; /* User config file, sys conf f., environment */ diff --git a/src/webdav.c b/src/webdav.c index 2989345..12c61a1 100644 --- a/src/webdav.c +++ b/src/webdav.c @@ -422,38 +422,8 @@ dav_init_webdav(dav_args *args) ne_ssl_trust_cert(session, args->ca_cert); } - if (args->clicert) { - uid_t orig = geteuid(); - seteuid(0); - ne_ssl_client_cert *client_cert - = ne_ssl_clicert_read(args->clicert); - seteuid(orig); - if (!client_cert) - error(EXIT_FAILURE, 0, _("can't read client certificate %s"), - args->clicert); - if (client_cert && ne_ssl_clicert_encrypted(client_cert)) { - char *pw = NULL; - if (!args->clicert_pw && args->askauth) { - printf(_("Please enter the password to decrypt client\n" - "certificate %s.\n"), args->clicert); - pw = dav_user_input_hidden(_("Password: ")); - } else { - pw = xstrdup(args->clicert_pw); - } - int ret = 1; - if (pw) { - ret = ne_ssl_clicert_decrypt(client_cert, pw); - memset(pw, '\0', strlen(pw)); - free(pw); - } - if (ret) - error(EXIT_FAILURE, 0, - _("can't decrypt client certificate %s"), - args->clicert); - } - ne_ssl_set_clicert(session, client_cert); - ne_ssl_clicert_free(client_cert); - } + if (args->client_cert) + ne_ssl_set_clicert(session, args->client_cert); } have_terminal = args->askauth;