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
--------------------

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.

View File

@ -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);

View File

@ -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 */

View File

@ -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;