diff options
author | Sergey Poznyakoff <gray@gnu.org.ua> | 2009-02-26 00:50:24 +0200 |
---|---|---|
committer | Sergey Poznyakoff <gray@gnu.org.ua> | 2009-02-26 00:50:24 +0200 |
commit | 81640ab2b9ad954d4952aed43a70d7874da1c463 (patch) | |
tree | 8160066cb7259357f17a40121f7ed7d0fff5701e /src | |
parent | 9ec721b2a3a023f6339fe3c910635e477e4a311f (diff) | |
download | wydawca-81640ab2b9ad954d4952aed43a70d7874da1c463.tar.gz wydawca-81640ab2b9ad954d4952aed43a70d7874da1c463.tar.bz2 |
Switch to non-privileged UID/GID before startup.
* src/userprivs.c: New file.
* src/Makefile.am (wydawca_SOURCES): Add userprivs.c
* src/config.c (cb_access_method_params): Add missing gl_list_iterator_free.
(cb_user, cb_supp_groups): New callbacks.
(wydawca_kw): New keywords: user and group.
* src/wydawca.c (wydawca_uid, wydawca_gid)
(wydawca_supp_groupc, wydawca_supp_groups): New variables.
(wydawca_set_uid, wydawca_set_gid, wydawca_set_privs)
(wydawca_set_triplet_privs, wydawca_set_root_privs): Remove.
(main): --dry-run implies --cron.
Switch to non-privileged UID/GID before startup.
* src/wydawca.h (wydawca_uid, wydawca_gid)
(wydawca_supp_groupc, wydawca_supp_groups): New declarations.
* src/mail.c (do_notify): Duplicate admin_address, it gets freed in do_notify.
* src/directive.c, src/diskio.c, src/lock.c, src/triplet.c: Update.
Diffstat (limited to 'src')
-rw-r--r-- | src/Makefile.am | 1 | ||||
-rw-r--r-- | src/config.c | 82 | ||||
-rw-r--r-- | src/directive.c | 2 | ||||
-rw-r--r-- | src/diskio.c | 68 | ||||
-rw-r--r-- | src/lock.c | 2 | ||||
-rw-r--r-- | src/mail.c | 2 | ||||
-rw-r--r-- | src/triplet.c | 4 | ||||
-rw-r--r-- | src/userprivs.c | 118 | ||||
-rw-r--r-- | src/wydawca.c | 90 | ||||
-rw-r--r-- | src/wydawca.h | 14 |
10 files changed, 259 insertions, 124 deletions
diff --git a/src/Makefile.am b/src/Makefile.am index c91669e..993ce0d 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -38,2 +38,3 @@ wydawca_SOURCES=\ triplet.c\ + userprivs.c\ verify.c\ diff --git a/src/config.c b/src/config.c index b1f339f..b6e2533 100644 --- a/src/config.c +++ b/src/config.c @@ -980,2 +980,3 @@ cb_access_method_params (enum gconf_callback_command cmd, } + gl_list_iterator_free (&itr); meth->parmv[i] = NULL; @@ -1226,2 +1227,78 @@ cb_spool (enum gconf_callback_command cmd, +static int +cb_user (enum gconf_callback_command cmd, + gconf_locus_t *locus, + void *varptr, + gconf_value_t *value, + void *cb_data) +{ + int rc; + struct passwd *pw; + + if (assert_string_arg (locus, cmd, value)) + return 1; + + pw = getpwnam (value->v.string); + if (!pw) + { + gconf_error (locus, 0, _("no such user: %s"), value->v.string); + return 1; + } + + wydawca_uid = pw->pw_uid; + wydawca_gid = pw->pw_gid; + return 0; +} + +static int +cb_supp_groups (enum gconf_callback_command cmd, + gconf_locus_t *locus, + void *varptr, + gconf_value_t *value, + void *cb_data) +{ + if (cmd != gconf_callback_set_value) + { + gconf_error (locus, 0, _("Unexpected block statement")); + return 1; + } + if (!value || value->type != GCONF_TYPE_LIST) + { + gconf_error (locus, 0, _("expected list value")); + return 1; + } + + wydawca_supp_groupc = gl_list_size (value->v.list); + if (wydawca_supp_groupc == 0) + wydawca_supp_groups = NULL; + else + { + int i; + gl_list_iterator_t itr; + const void *p; + + wydawca_supp_groups = xcalloc (wydawca_supp_groupc, + sizeof (wydawca_supp_groups[0])); + itr = gl_list_iterator (value->v.list); + for (i = 0; gl_list_iterator_next (&itr, &p, NULL); i++) + { + const gconf_value_t *vp = p; + struct group *grp; + + if (assert_string_arg (locus, cmd, vp)) + break; + grp = getgrnam (vp->v.string); + if (!grp) + { + gconf_error (locus, 0, _("no such group: %s"), value->v.string); + break; + } + wydawca_supp_groups[i] = grp->gr_gid; + } + gl_list_iterator_free (&itr); + } + return 0; +} + + @@ -1239,2 +1316,7 @@ static struct gconf_keyword wydawca_kw[] = { + { "user", N_("name"), N_("Run with UID and GID of this user"), + gconf_type_string, NULL, 0, cb_user }, + { "group", NULL, N_("Retain these supplementary groups"), + gconf_type_string|GCONF_LIST, NULL, 0, cb_supp_groups }, + { "locking", NULL, N_("Enable or disable locking"), diff --git a/src/directive.c b/src/directive.c index 2915fee..416095f 100644 --- a/src/directive.c +++ b/src/directive.c @@ -339,5 +339,3 @@ process_directives (struct file_triplet *trp, const struct spool *spool) case filename_dir: - wydawca_set_root_privs (); rc = verify_detached_signature (trp, spool); - wydawca_set_triplet_privs (trp); if (rc == 0) diff --git a/src/diskio.c b/src/diskio.c index fbd1050..35ba71e 100644 --- a/src/diskio.c +++ b/src/diskio.c @@ -60,5 +60,5 @@ concat_dir (const char *base, const char *name, size_t *pbaselen) /* Create the directory DIR, eventually creating all intermediate directories - starting from DIR + BASELEN, with owner UID and GID. */ + starting from DIR + BASELEN. */ int -create_hierarchy (char *dir, size_t baselen, uid_t uid, gid_t gid) +create_hierarchy (char *dir, size_t baselen) { @@ -94,3 +94,3 @@ create_hierarchy (char *dir, size_t baselen, uid_t uid, gid_t gid) - rc = create_hierarchy (dir, baselen, uid, gid); + rc = create_hierarchy (dir, baselen); if (rc == 0) @@ -105,7 +105,2 @@ create_hierarchy (char *dir, size_t baselen, uid_t uid, gid_t gid) } - if (chown (dir, uid, gid)) - { - logmsg (LOG_NOTICE, _("cannot change ownership of %s: %s"), - dir, strerror (errno)); - } } @@ -118,3 +113,3 @@ create_hierarchy (char *dir, size_t baselen, uid_t uid, gid_t gid) char * -create_directory (const char *base, const char *name, uid_t uid, gid_t gid) +create_directory (const char *base, const char *name) { @@ -125,7 +120,3 @@ create_directory (const char *base, const char *name, uid_t uid, gid_t gid) { - int rc; - wydawca_set_root_privs (); - rc = create_hierarchy (dir, baselen, uid, gid); - wydawca_set_privs (uid, gid); - if (rc) + if (create_hierarchy (dir, baselen)) { @@ -139,5 +130,5 @@ create_directory (const char *base, const char *name, uid_t uid, gid_t gid) -/* Copy FILE to DST_FILE, creating the latter with owner UID and GID. */ +/* Copy FILE to DST_FILE. */ int -copy_file (const char *file, const char *dst_file, uid_t uid, gid_t gid) +copy_file (const char *file, const char *dst_file) { @@ -225,6 +216,5 @@ copy_file (const char *file, const char *dst_file, uid_t uid, gid_t gid) /* Move FILE to DST_FILE. If they reside on different devices, use copy_file - + unlink. - UID and GID give DST_FILE ownership. */ + + unlink. */ int -do_move_file (const char *file, const char *dst_file, uid_t uid, gid_t gid) +do_move_file (const char *file, const char *dst_file) { @@ -236,3 +226,3 @@ do_move_file (const char *file, const char *dst_file, uid_t uid, gid_t gid) { - if (copy_file (file, dst_file, uid, gid)) + if (copy_file (file, dst_file)) { @@ -301,3 +291,2 @@ tar_append_file (const char *archive, const char *file) ARCHIVE - Archive descriptor. - UID, GID - Ownership RELDIR - Directory part of FILE @@ -307,3 +296,3 @@ int backup_file (const char *dst_file, const char *dst_dir, const char *file, - const struct archive_descr *archive, uid_t uid, gid_t gid, + const struct archive_descr *archive, const char *reldir) @@ -315,5 +304,5 @@ backup_file (const char *dst_file, const char *dst_dir, const char *file, if (archive->name[0] == '/') - adir = create_directory (archive->name, reldir, uid, gid); + adir = create_directory (archive->name, reldir); else - adir = create_directory (dst_dir, archive->name, uid, gid); + adir = create_directory (dst_dir, archive->name); if (!adir) @@ -349,3 +338,3 @@ backup_file (const char *dst_file, const char *dst_dir, const char *file, { - rc = do_move_file (file_name, archive_file_name, uid, gid); + rc = do_move_file (file_name, archive_file_name); if (rc) @@ -368,3 +357,3 @@ backup_file (const char *dst_file, const char *dst_dir, const char *file, { - rc = do_move_file (dst_file, file_name, uid, gid); + rc = do_move_file (dst_file, file_name); if (rc) @@ -382,3 +371,3 @@ int do_archive_file (const char *dst_file, const char *dst_dir, const char *file, - const struct archive_descr *archive, uid_t uid, gid_t gid, + const struct archive_descr *archive, const char *reldir) @@ -391,3 +380,3 @@ do_archive_file (const char *dst_file, const char *dst_dir, const char *file, case archive_directory: - return backup_file (dst_file, dst_dir, file, archive, uid, gid, reldir); + return backup_file (dst_file, dst_dir, file, archive, reldir); @@ -417,4 +406,3 @@ dir_move_file (struct file_triplet *trp, const struct spool *spool, int rc = 0; - char *dst_dir = create_directory (spool->dest_dir, reldir, - TRIPLET_UID (trp), TRIPLET_GID (trp)); + char *dst_dir = create_directory (spool->dest_dir, reldir); @@ -430,8 +418,6 @@ dir_move_file (struct file_triplet *trp, const struct spool *spool, rc = do_archive_file (dst_file, dst_dir, trp->file[file_id].name, - &spool->archive, - TRIPLET_UID (trp), TRIPLET_GID (trp), reldir); + &spool->archive, reldir); if (!dry_run_mode && rc == 0) - rc = do_move_file (trp->file[file_id].name, dst_file, - TRIPLET_UID (trp), TRIPLET_GID (trp)); + rc = do_move_file (trp->file[file_id].name, dst_file); @@ -455,4 +441,3 @@ archive_single_file (struct file_triplet *trp, const struct spool *spool, int rc = 0; - char *dst_dir = create_directory (spool->dest_dir, reldir, - TRIPLET_UID (trp), TRIPLET_GID (trp)); + char *dst_dir = create_directory (spool->dest_dir, reldir); @@ -476,3 +461,3 @@ archive_single_file (struct file_triplet *trp, const struct spool *spool, rc = do_archive_file (dst_file, dst_dir, file_name, &spool->archive, - TRIPLET_UID (trp), TRIPLET_GID (trp), reldir); + reldir); if (rc == 0) @@ -545,4 +530,3 @@ dir_symlink_file (struct file_triplet *trp, const struct spool *spool, struct saved_cwd cwd; - char *dst_dir = create_directory (spool->dest_dir, reldir, - TRIPLET_UID (trp), TRIPLET_GID (trp)); + char *dst_dir = create_directory (spool->dest_dir, reldir); char *src, *dst; @@ -590,4 +574,3 @@ dir_symlink_file (struct file_triplet *trp, const struct spool *spool, *p = 0; - dir = create_directory (spool->dest_dir, dst, - TRIPLET_UID (trp), TRIPLET_GID (trp)); + dir = create_directory (spool->dest_dir, dst); if (!dir) @@ -705,4 +688,3 @@ dir_rmsymlink_file (struct file_triplet *trp, const struct spool *spool, char *signame; - char *dst_dir = create_directory (spool->dest_dir, reldir, - TRIPLET_UID (trp), TRIPLET_GID (trp)); + char *dst_dir = create_directory (spool->dest_dir, reldir); @@ -235,3 +235,3 @@ wydawca_lock_init () lockdir = xstrdup (LOCALSTATEDIR "/lock/" PACKAGE); - if (create_hierarchy (lockdir, 0, getuid (), getgid ())) + if (create_hierarchy (lockdir, 0)) exit (EX_OSFILE); @@ -337,3 +337,3 @@ do_notify (struct file_triplet *trp, enum notification_event ev, case notify_admin: - rcpt = admin_address; + rcpt = mu_address_dup (admin_address); break; diff --git a/src/triplet.c b/src/triplet.c index 614e2b5..e060089 100644 --- a/src/triplet.c +++ b/src/triplet.c @@ -201,7 +201,3 @@ triplet_processor (void *data, void *proc_data) logmsg (LOG_DEBUG, _("processing triplet `%s'"), trp->name); - if (wydawca_set_triplet_privs (trp) == 0) - { process_directives (trp, spool); - wydawca_set_root_privs (); - } return true; diff --git a/src/userprivs.c b/src/userprivs.c new file mode 100644 index 0000000..e6a18c8 --- /dev/null +++ b/src/userprivs.c @@ -0,0 +1,118 @@ +/* wydawca - automatic release submission daemon + Copyright (C) 2007, 2009 Sergey Poznyakoff + + Wydawca is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 3 of the License, or (at your + option) any later version. + + Wydawca is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with wydawca. If not, see <http://www.gnu.org/licenses/>. */ + +#include "wydawca.h" + +int +wydawca_userprivs (uid_t uid, gid_t gid, gid_t *grplist, size_t ngrp) +{ + int rc = 0; + size_t size = 1, j = 1; + + if (uid == 0) + return 0; + + /* Reset group permissions */ + if (geteuid () == 0 && setgroups (ngrp, grplist)) + { + logmsg (LOG_CRIT, "setgroups(%lu, %lu...): %s", + ngrp, grplist[0], 0, strerror (errno)); + return rc; + } + + /* Switch to the user's gid. On some OSes the effective gid must + be reset first */ + +#if defined(HAVE_SETEGID) + if ((rc = setegid (gid)) < 0) + logmsg (LOG_CRIT, "setegid(%lu): %s", gid, strerror (errno)); +#elif defined(HAVE_SETREGID) + if ((rc = setregid (gid, gid)) < 0) + logmsg (LOG_CRIT, "setregid(%lu,%lu)d: %s", + (unsigned long) gid, (unsigned long) gid, strerror (errno)); +#elif defined(HAVE_SETRESGID) + if ((rc = setresgid (gid, gid, gid)) < 0) + logmsg (LOG_CRIT, "setresgid(%lu,%lu,%lu): %s", + (unsigned long) gid, (unsigned long) gid, + (unsigned long) gid, + strerror (errno)); +#endif + + if (rc == 0 && gid != 0) + { + if ((rc = setgid (gid)) < 0 && getegid () != gid) + logmsg (LOG_CRIT, "setgid(%lu): %s", + (unsigned long) gid, strerror (errno)); + if (rc == 0 && getegid () != gid) + { + logmsg (LOG_CRIT, _("cannot set effective gid to %lu"), + (unsigned long) gid); + rc = 1; + } + } + + /* Now reset uid */ + if (rc == 0 && uid != 0) + { + uid_t euid; + + if (setuid (uid) + || geteuid () != uid + || (getuid () != uid + && (geteuid () == 0 || getuid () == 0))) + { + +#if defined(HAVE_SETREUID) + if (geteuid () != uid) + { + if (setreuid (uid, -1) < 0) + { + logmsg (LOG_CRIT, "setreuid(%lu,-1): %s", + (unsigned long) uid, strerror (errno)); + rc = 1; + } + if (setuid (uid) < 0) + { + logmsg (LOG_CRIT, "setreuid(%lu,-1): %s", + (unsigned long) uid, strerror (errno)); + rc = 1; + } + } + else +#endif + { + logmsg (LOG_CRIT, "setuid(%lu): %s", + (unsigned long) uid, strerror (errno)); + rc = 1; + } + } + + euid = geteuid (); + if (uid != 0 && setuid (0) == 0) + { + logmsg (LOG_CRIT, _("seteuid(0) succeeded when it should not")); + rc = 1; + } + else if (uid != euid && setuid (euid) == 0) + { + logmsg (LOG_CRIT, _("cannot drop non-root setuid privileges")); + rc = 1; + } + + } + + return rc; +} diff --git a/src/wydawca.c b/src/wydawca.c index 48c27e9..f02ac99 100644 --- a/src/wydawca.c +++ b/src/wydawca.c @@ -21,2 +21,6 @@ +uid_t wydawca_uid; +gid_t wydawca_gid; +size_t wydawca_supp_groupc; +gid_t *wydawca_supp_groups; char *conffile = SYSCONFDIR "/wydawca.rc" ; @@ -267,69 +271,2 @@ collect_uids (int argc, char **argv) -static int -wydawca_set_uid (uid_t uid) -{ - int rc; - - if (getuid () != 0) - return 0; -#if defined(HAVE_SETREUID) - rc = setreuid (0, uid); -#elif defined(HAVE_SETRESUID) - rc = setresuid (-1, uid, -1); -#elif defined(HAVE_SETEUID) - rc = seteuid (uid); -#else -# error "No way to reset user privileges?" -#endif - if (rc < 0) - logmsg (LOG_ERR, _("cannot switch to UID %d: %s (r=%d, e=%d)"), - uid, strerror (errno), getuid (), geteuid ()); - return rc; -} - -static int -wydawca_set_gid (gid_t gid) -{ - int rc; - - if (getuid () != 0) - return 0; -#if defined(HAVE_SETREGID) - rc = setregid (0, gid); -#elif defined(HAVE_SETRESGID) - rc = setresgid (-1, gid, -1); -#elif defined(HAVE_SETEGID) - rc = setegid (gid); -#else -# error "No way to reset user privileges?" -#endif - if (rc < 0) - logmsg (LOG_ERR, _("cannot switch to GID %d: %s (r=%d, e=%d)"), - gid, strerror (errno), getgid (), getegid ()); - return rc; -} - -int -wydawca_set_privs (uid_t uid, gid_t gid) -{ - if (wydawca_set_gid (gid)) - return -1; - if (wydawca_set_uid (uid)) - return -1; - return 0; -} - -int -wydawca_set_triplet_privs (struct file_triplet *trp) -{ - return wydawca_set_privs (TRIPLET_UID (trp), TRIPLET_GID (trp)); -} - -int -wydawca_set_root_privs () -{ - return wydawca_set_privs (0, 0); -} - - char **x_argv; @@ -379,2 +316,4 @@ main (int argc, char **argv) + if (dry_run_mode) + cron_option = 1; if (cron_option) @@ -396,2 +335,18 @@ main (int argc, char **argv) + if (getgid () == 0) + { + if (wydawca_uid == 0) + { + if (!force_startup) + { + logmsg (LOG_CRIT, _("won't run with root privileges")); + exit (EX_UNAVAILABLE); + } + } + else if (wydawca_userprivs (wydawca_uid, wydawca_gid, + wydawca_supp_groups, + wydawca_supp_groupc)) + exit (EX_UNAVAILABLE); + } + mail_init (); @@ -416,3 +371,2 @@ main (int argc, char **argv) int i; - wydawca_set_uid (0); for (i = getdtablesize (); i > 2; i--) diff --git a/src/wydawca.h b/src/wydawca.h index f786271..81e6509 100644 --- a/src/wydawca.h +++ b/src/wydawca.h @@ -305,2 +305,6 @@ void make_default_meta (struct metadef kwexp[5], const char *user, /* Global variables */ +extern uid_t wydawca_uid; +extern gid_t wydawca_gid; +extern size_t wydawca_supp_groupc; +extern gid_t *wydawca_supp_groups; extern char *conffile; /* Configuration file name */ @@ -357,4 +361,4 @@ void logmsg (int prio, char *fmt, ...) GSC_PRINTFLIKE(2,3); int test_dir (const char *name, int *ec); -char *create_directory (const char *base, const char *name, - uid_t uid, gid_t gid); +char *create_directory (const char *base, const char *name); +int create_hierarchy (char *dir, size_t baselen); void parse_config (void); @@ -430,5 +434,2 @@ int enabled_spool_p (const struct spool *spool); -int wydawca_set_privs (uid_t uid, gid_t gid); -int wydawca_set_triplet_privs (struct file_triplet *trp); -int wydawca_set_root_privs (void); @@ -540 +541,4 @@ extern struct gconf_keyword tcpwrapper_kw[]; int tcpwrap_access(int fd); + +/* userprivs.c */ +int wydawca_userprivs (uid_t uid, gid_t gid, gid_t *grplist, size_t ngrp); |