Check for _POSIX_SAVED_IDS, add gain_privileges and release_privileges

This commit is contained in:
wbaumann 2012-01-15 17:29:11 +00:00
parent 67c5cbe9ee
commit af0e0b57c7
3 changed files with 94 additions and 59 deletions

View File

@ -8,6 +8,9 @@ ChangeLog for davfs2
parse_config, defaults.h:
Set defaults for netdev, mopts, fsuid and fsgid
in get_options.
* mount_davfs.c, kernel_interface.c:
Check for _POSIX_SAVED_IDS,
add gain_privileges and release_privileges.

2012-01-14 Werner Baumann (werner.baumann@onlinehome.de)
* src/Makefile.am:

View File

@ -99,9 +99,6 @@ dav_init_kernel_interface(int *dev, dav_run_msgloop_fn *msg_loop, void **mdata,
char **kernel_fs, size_t *buf_size, const char *url,
const char *mpoint, const dav_args *args)
{
uid_t orig = geteuid();
seteuid(0);

if (!*kernel_fs)
*kernel_fs = strdup("fuse");
if (!*kernel_fs) abort();
@ -146,9 +143,6 @@ dav_init_kernel_interface(int *dev, dav_run_msgloop_fn *msg_loop, void **mdata,

error(EXIT_FAILURE, 0, _("unknown kernel file system %s"), *kernel_fs);
}

seteuid(orig);
return mounted;
}



View File

@ -143,8 +143,11 @@ check_permissions(dav_args *args);
static void
check_persona(dav_args *args);

static void
gain_privileges(const dav_args *args);

static int
do_mount(unsigned long int mopts, void *mdata);
do_mount(dav_args *args, void *mdata);

static int
is_mounted(void);
@ -158,6 +161,9 @@ parse_config(dav_args *args);
static void
parse_secrets(dav_args *args);

static void
release_privileges(const dav_args *args);

static int
save_pid(void);

@ -238,14 +244,11 @@ main(int argc, char *argv[])

check_persona(args);

release_privileges(args);

parse_commandline(args, argc, argv);

if (geteuid() != 0)
error(EXIT_FAILURE, errno, _("program is not setuid root"));
if (seteuid(getuid()) != 0)
error(EXIT_FAILURE, errno, _("can't change effective user id"));

if (getuid() != 0)
if (!args->privileged)
check_fstab(args);

parse_config(args);
@ -272,9 +275,11 @@ main(int argc, char *argv[])
if (args->kernel_fs)
kernel_fs = ne_strdup(args->kernel_fs);
size_t buf_size = args->buf_size * 1024;
gain_privileges(args);
int mounted = dav_init_kernel_interface(&dev, &run_msgloop, &mdata,
&kernel_fs, &buf_size, url, mpoint,
args);
release_privileges(args);
if (args->debug & DAV_DBG_CONFIG)
syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG), "kernel_fs: %s", kernel_fs);

@ -290,7 +295,7 @@ main(int argc, char *argv[])
if (args->debug & DAV_DBG_CONFIG)
syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG),
"Parent: mounting filesystem");
if (do_mount(args->mopts, mdata) != 0) {
if (do_mount(args, mdata) != 0) {
kill(childpid, SIGTERM);
delete_args(args);
exit(EXIT_FAILURE);
@ -328,7 +333,7 @@ main(int argc, char *argv[])
if (args->debug & DAV_DBG_CONFIG)
syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG), "Releasing root privileges");
uid_t daemon_id = geteuid();
seteuid(0);
gain_privileges(args);
ret = setuid(daemon_id);
if (ret) {
syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_ERR),
@ -425,32 +430,23 @@ dav_user_input_hidden(const char *prompt)
/* Private functions */
/*===================*/

/* Changes the group id of the process permanently to dav_group. The
effective user id of the process will be changed too, but the real
/* Changes the group id of the process permanently to dav_group.
If the process is privileged args->uid will be changed to
args->dav_uid. This way release_privileges will set the
effective uid to dav_uid.
The process is still able to gain root privileges. The real
user id still has to be changed permanently. */
static void
change_persona(dav_args *args)
{
struct group *grp = getgrnam(args->dav_group);
if (!grp)
error(EXIT_FAILURE, errno, _("group %s does not exist"),
args->dav_group);
seteuid(0);
if (setgid(grp->gr_gid) != 0)
gain_privileges(args);
if (setgid(args->dav_gid) != 0)
error(EXIT_FAILURE, errno, _("can't change group id"));

if (getuid() == 0) {
struct passwd *pw = getpwnam(args->dav_user);
if (!pw)
error(EXIT_FAILURE, errno, _("user %s does not exist"),
args->dav_user);
if (seteuid(pw->pw_uid) != 0)
error(EXIT_FAILURE, errno, _("can't change effective user id"));
} else {
if (seteuid(getuid()) != 0)
error(EXIT_FAILURE, errno, _("can't change effective user id"));
}
if (args->privileged)
args->uid = args->dav_uid;
release_privileges(args);

if (args->debug & DAV_DBG_CONFIG)
syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG),
"changing persona: euid %i, gid %i", geteuid(), getgid());
@ -478,7 +474,7 @@ check_dirs(dav_args *args)
if (args->debug & DAV_DBG_CONFIG)
syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG), "mounts in: %s", mounts);

seteuid(0);
gain_privileges(args);
if (access(DAV_SYS_RUN, F_OK) != 0) {
if (mkdir(DAV_SYS_RUN, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH | S_ISVTX)
!= 0)
@ -503,9 +499,9 @@ check_dirs(dav_args *args)
error(EXIT_FAILURE, errno,
_("can't change group of directory %s"), DAV_SYS_RUN);
}
seteuid(getuid());
release_privileges(args);

if (getuid() != 0) {
if (!args->privileged) {

char *path = NULL;
struct passwd *pw = getpwuid(getuid());
@ -560,7 +556,7 @@ check_dirs(dav_args *args)

if (strcmp(args->cache_dir, args->sys_cache) == 0) {

seteuid(0);
gain_privileges(args);
if (access(args->sys_cache, F_OK) != 0) {
if (mkdir(args->sys_cache, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH)
!= 0)
@ -587,7 +583,7 @@ check_dirs(dav_args *args)
_("can't change group of directory %s"),
args->sys_cache);
}
seteuid(getuid());
release_privileges(args);

} else {

@ -763,7 +759,7 @@ check_mountpoint(dav_args *args)

struct passwd *pw;

if (args->relative_mpoint && getuid() != 0) {
if (args->relative_mpoint && !args->privileged) {
pw = getpwuid(getuid());
if (!pw || !pw->pw_dir)
error(EXIT_FAILURE, 0,
@ -787,7 +783,7 @@ check_mountpoint(dav_args *args)
static void
check_permissions(dav_args *args)
{
if (getuid() == 0)
if (args->privileged)
return;

if (args->fsuid != getuid())
@ -880,12 +876,11 @@ check_persona(dav_args *args)
as mount data.
return value : 0 on success, -1 if mount() fails. */
static int
do_mount(unsigned long int mopts, void *mdata)
do_mount(dav_args *args, void *mdata)
{
uid_t orig = geteuid();
seteuid(0);
int ret = mount(url, mpoint, kernel_fs, mopts, mdata);
seteuid(orig);
gain_privileges(args);
int ret = mount(url, mpoint, kernel_fs, args->mopts, mdata);
release_privileges(args);

if (ret) {
error(0, errno, _("can't mount %s on %s"), url, mpoint);
@ -899,6 +894,22 @@ do_mount(unsigned long int mopts, void *mdata)
}


/* Gains super user privileges. If an error occurs it prints an error
message and calls exit(EXIT_FAILURE). */
static void
gain_privileges(const dav_args *args)
{
int ret;
#ifdef _POSIX_SAVED_IDS
ret = seteuid(0);
#else
ret = setreuid(args->uid, 0);
#endif
if (ret)
error(EXIT_FAILURE, 0, _("can't change effective user id"));
}


/* Checks wether the file system is mounted.
It uses information from the private global variables mounts (mtab-file),
url (must be device in the mtab entry) and mpoint (mount point).
@ -1059,8 +1070,19 @@ parse_config(dav_args *args)

if (!args->dav_user)
args->dav_user = ne_strdup(DAV_USER);
struct passwd *d_pw = getpwnam(args->dav_user);
if (!d_pw)
error(EXIT_FAILURE, errno, _("user %s does not exist"),
args->dav_user);
args->dav_uid = d_pw->pw_uid;

if (!args->dav_group)
args->dav_group = ne_strdup(DAV_GROUP);
struct group *grp = getgrnam(args->dav_group);
if (!grp)
error(EXIT_FAILURE, errno, _("group %s does not exist"),
args->dav_group);
args->dav_gid = grp->gr_gid;

eval_modes(args);

@ -1072,7 +1094,7 @@ parse_config(dav_args *args)
free(args->servercert);
args->servercert = f;
}
if (args->servercert && *args->servercert != '/' && getuid() != 0) {
if (args->servercert && *args->servercert != '/' && !args->privileged) {
char *f = ne_concat(pw->pw_dir, "/.", PACKAGE, "/", DAV_CERTS_DIR, "/",
args->servercert, NULL);
if (access(f, F_OK) == 0) {
@ -1109,7 +1131,7 @@ parse_config(dav_args *args)
free(args->clicert);
args->clicert = f;
}
if (args->clicert && *args->clicert != '/' && getuid() != 0) {
if (args->clicert && *args->clicert != '/' && !args->privileged) {
char *f = ne_concat(pw->pw_dir, "/.", PACKAGE, "/", DAV_CERTS_DIR, "/",
DAV_CLICERTS_DIR, "/", args->clicert, NULL);
if (access(f, F_OK) == 0) {
@ -1117,7 +1139,7 @@ parse_config(dav_args *args)
args->clicert = f;
}
}
if (args->clicert && *args->clicert != '/' && getuid() == 0) {
if (args->clicert && *args->clicert != '/' && args->privileged) {
char *f = ne_concat(DAV_SYS_CONF_DIR, "/", DAV_CERTS_DIR, "/",
DAV_CLICERTS_DIR, "/", args->clicert, NULL);
free(args->clicert);
@ -1125,11 +1147,11 @@ parse_config(dav_args *args)
}
if (args->clicert) {
struct stat st;
seteuid(0);
gain_privileges(args);
if (stat(args->clicert, &st) < 0)
error(EXIT_FAILURE, 0, _("can't read client certificate %s"),
args->clicert);
seteuid(getuid());
release_privileges(args);
if (st.st_uid != getuid() && st.st_uid != 0)
error(EXIT_FAILURE, 0,
_("client certificate file %s has wrong owner"),
@ -1142,7 +1164,7 @@ parse_config(dav_args *args)
args->clicert);
}

if (getuid() == 0 && !args->p_host) {
if (args->privileged && !args->p_host) {
proxy_from_env(args);
read_no_proxy_list(args);
}
@ -1182,9 +1204,9 @@ parse_config(dav_args *args)
static void
parse_secrets(dav_args *args)
{
seteuid(0);
gain_privileges(args);
read_secrets(args, DAV_SYS_CONF_DIR "/" DAV_SECRETS);
seteuid(getuid());
release_privileges(args);

if (args->secrets) {
read_secrets(args, args->secrets);
@ -1259,6 +1281,23 @@ parse_secrets(dav_args *args)
}


/* Releases super user privileges and sets the effective uid to the value
of args->uid. If an error occurs it prints an error message and
calls exit(EXIT_FAILURE). */
static void
release_privileges(const dav_args *args)
{
int ret;
#ifdef _POSIX_SAVED_IDS
ret = seteuid(args->uid);
#else
ret = setreuid(0, args->uid);
#endif
if (ret)
error(EXIT_FAILURE, 0, _("can't change effective user id"));
}


/* Saves the pid of the mount.davfs daemon in the pid-file. The name of the
pid-file is taken from the private global variable pidfile. If an error
occurs during opening of the pid-file, the function returns with -1. */
@ -1312,7 +1351,7 @@ write_mtab_entry(const dav_args *args)
mntent. mnt_freq = 0;
mntent. mnt_passno = 0;

if (getuid() != 0) {
if (!args->privileged) {
struct passwd *pw = getpwuid(getuid());
if (!pw) {
error(0, errno, _("Warning: can't read user data base. Mounting "
@ -1324,8 +1363,7 @@ write_mtab_entry(const dav_args *args)
free(opts);
}

uid_t orig = geteuid();
seteuid(0);
gain_privileges(args);
int ret;
FILE *mtab = setmntent(_PATH_MOUNTED, "a");
if (mtab) {
@ -1335,7 +1373,7 @@ write_mtab_entry(const dav_args *args)
error(0, 0, _("Warning: can't write entry into mtab, but will mount "
"the file system anyway"));
}
seteuid(orig);
release_privileges(args);

free(mntent.mnt_opts);
}