Read client certificates in mount_davfs.c

This commit is contained in:
wbaumann 2012-02-05 12:19:13 +00:00
parent 563100c460
commit c6c3fca29a
4 changed files with 119 additions and 76 deletions

View File

@ -1,6 +1,10 @@
ChangeLog for davfs2 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) 2012-02-01 Werner Baumann (werner.baumann@onlinehome.de)
* mount_davfs.c, mount_davfs.h, webdav.c: * mount_davfs.c, mount_davfs.h, webdav.c:
Add option trust_server_cert. Add option trust_server_cert.

View File

@ -216,7 +216,7 @@ static void
read_no_proxy_list(dav_args *args); read_no_proxy_list(dav_args *args);


static void static void
read_secrets(dav_args *args, const char *filename); read_secrets(dav_args *args, const char *filename, int system);


static int static int
split_uri(char **scheme, char **host, int *port,char **path, const char *uri); 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); 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); fname = xasprintf("%s/%s", DAV_SYS_CONF_DIR, DAV_SECRETS);
if (stat(fname, &st) == 0) { if (stat(fname, &st) == 0) {
if (st.st_uid != 0) if (st.st_uid != 0)
@ -556,6 +574,22 @@ check_dirs(dav_args *args)
} }
free(path); 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 (stat(args->secrets, &st) == 0) {
if (st.st_uid != args->uid) if (st.st_uid != args->uid)
error(EXIT_FAILURE, 0, _("file %s has wrong owner"), error(EXIT_FAILURE, 0, _("file %s has wrong owner"),
@ -1039,7 +1073,7 @@ parse_config(dav_args *args)
} }
} }
if (!args->ca_cert) 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); args->trust_ca_cert);
} }


@ -1076,38 +1110,31 @@ parse_config(dav_args *args)
args->secrets = xasprintf("%s/.%s/%s", args->home, PACKAGE, args->secrets = xasprintf("%s/.%s/%s", args->home, PACKAGE,
DAV_SECRETS); DAV_SECRETS);


if (args->clicert) if (args->clicert) {
expand_home(&args->clicert, args); expand_home(&args->clicert, args);
if (args->clicert && *args->clicert != '/' && !args->privileged) { if (*args->clicert != '/') {
char *f = xasprintf("%s/.%s/%s/%s/%s", args->home, PACKAGE, char *f = xasprintf("%s/.%s/%s/%s/%s", args->home, PACKAGE,
DAV_CERTS_DIR, DAV_CLICERTS_DIR, args->clicert); DAV_CERTS_DIR, DAV_CLICERTS_DIR, args->clicert);
if (access(f, F_OK) == 0) {
free(args->clicert); free(args->clicert);
args->clicert = f; args->clicert = f;
} }
} args->client_cert = ne_ssl_clicert_read(args->clicert);
if (args->clicert && *args->clicert != '/' && args->privileged) { if (!args->client_cert)
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)
error(EXIT_FAILURE, 0, _("can't read client certificate %s"), error(EXIT_FAILURE, 0, _("can't read client certificate %s"),
args->clicert); 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); release_privileges(args);
if (st.st_uid != args->uid && st.st_uid != 0) if (!args->client_cert)
error(EXIT_FAILURE, 0, error(EXIT_FAILURE, 0, _("can't read client certificate %s"),
_("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); args->clicert);
} }


@ -1183,11 +1210,11 @@ static void
parse_secrets(dav_args *args) parse_secrets(dav_args *args)
{ {
gain_privileges(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); release_privileges(args);


if (args->secrets) { if (args->secrets) {
read_secrets(args, args->secrets); read_secrets(args, args->secrets, 0);
} }


if (args->cl_username) { 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) { if (args->debug & DAV_DBG_SECRETS) {
syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG), "Secrets:"); syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG), "Secrets:");
syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG), syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG),
@ -1456,11 +1496,11 @@ delete_args(dav_args *args)
if (args->trust_ca_cert) if (args->trust_ca_cert)
free(args->trust_ca_cert); free(args->trust_ca_cert);
if (args->ca_cert) if (args->ca_cert)
free(args->ca_cert); ne_ssl_cert_free(args->ca_cert);
if (args->trust_server_cert) if (args->trust_server_cert)
free(args->trust_server_cert); free(args->trust_server_cert);
if (args->server_cert) if (args->server_cert)
free(args->server_cert); ne_ssl_cert_free(args->server_cert);
if (args->secrets) if (args->secrets)
free(args->secrets); free(args->secrets);
if (args->username) { if (args->username) {
@ -1475,6 +1515,10 @@ delete_args(dav_args *args)
} }
if (args->clicert) if (args->clicert)
free(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) { if (args->clicert_pw) {
memset(args->clicert_pw, '\0', strlen(args->clicert_pw)); memset(args->clicert_pw, '\0', strlen(args->clicert_pw));
free(args->clicert_pw); free(args->clicert_pw);
@ -1846,10 +1890,14 @@ log_dbg_config(dav_args *args)
" path: %s", args->path); " path: %s", args->path);
syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG), syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG),
" trust_ca_cert: %s", args->trust_ca_cert); " 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), syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG),
" secrets: %s", args->secrets); " secrets: %s", args->secrets);
syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG), syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG),
" clicert: %s", args->clicert); " clicert: %s", args->clicert);
syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG),
" sys_clicert: %s", args->sys_clicert);
syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG), syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG),
" p_host: %s", args->p_host); " p_host: %s", args->p_host);
syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG), syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG),
@ -2155,10 +2203,14 @@ read_config(dav_args *args, const char * filename, int system)
if (args->secrets) if (args->secrets)
free(args->secrets); free(args->secrets);
args->secrets = xstrdup(parmv[1]); args->secrets = xstrdup(parmv[1]);
} else if (strcmp(parmv[0], "clientcert") == 0) { } else if (!system && strcmp(parmv[0], "clientcert") == 0) {
if (args->clicert) if (args->clicert)
free(args->clicert); free(args->clicert);
args->clicert = xstrdup(parmv[1]); 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) { } else if (system && strcmp(parmv[0], "proxy") == 0) {
if (split_uri(NULL, &args->p_host, &args->p_port, NULL, if (split_uri(NULL, &args->p_host, &args->p_port, NULL,
parmv[1]) != 0) parmv[1]) != 0)
@ -2322,7 +2374,7 @@ read_no_proxy_list(dav_args *args)
Requires: scheme, host, port, path, clicert, p_host, p_port Requires: scheme, host, port, path, clicert, p_host, p_port
Provides: username, password, p_user, p_passwd, clicert_pw. */ Provides: username, password, p_user, p_passwd, clicert_pw. */
static void 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"); FILE *file = fopen(filename, "r");
if (!file) { if (!file) {
@ -2331,6 +2383,17 @@ read_secrets(dav_args *args, const char *filename)
return; 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; size_t n = 0;
char *line = NULL; char *line = NULL;
int length = getline(&line, &n, file); 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 *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) if ((mp && strcmp(mp, mpoint) == 0)
|| (scheme && args->scheme || (scheme && args->scheme
&& strcmp(scheme, args->scheme) == 0 && strcmp(scheme, args->scheme) == 0
@ -2404,7 +2458,7 @@ read_secrets(dav_args *args, const char *filename)
if (count == 3) if (count == 3)
args->p_passwd = xstrdup(parmv[2]); args->p_passwd = xstrdup(parmv[2]);


} else if (args->clicert } else if (!system && args->clicert
&& (strcmp(parmv[0], args->clicert) == 0 && (strcmp(parmv[0], args->clicert) == 0
|| strcmp(parmv[0], ccert) == 0)) { || strcmp(parmv[0], ccert) == 0)) {


@ -2416,6 +2470,19 @@ read_secrets(dav_args *args, const char *filename)
free(args->clicert_pw); free(args->clicert_pw);
} }
args->clicert_pw = xstrdup(parmv[1]); 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); if (scheme) free(scheme);

View File

@ -73,7 +73,9 @@ typedef struct {
char *username; /* User secrets file, system secrets file */ char *username; /* User secrets file, system secrets file */
char *cl_username; /* Command line */ char *cl_username; /* Command line */
char *password; /* User secrets file, system secrets file */ 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 *clicert_pw; /* User secrets file, system secrets file */
char *p_host; /* User config file, sys conf f., environment */ char *p_host; /* User config file, sys conf f., environment */
int p_port; /* User config file, sys conf f., environment */ int p_port; /* User config file, sys conf f., environment */

View File

@ -422,38 +422,8 @@ dav_init_webdav(dav_args *args)
ne_ssl_trust_cert(session, args->ca_cert); ne_ssl_trust_cert(session, args->ca_cert);
} }


if (args->clicert) { if (args->client_cert)
uid_t orig = geteuid(); ne_ssl_set_clicert(session, args->client_cert);
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);
}
} }


have_terminal = args->askauth; have_terminal = args->askauth;