summaryrefslogtreecommitdiffabout
path: root/src
authorSergey Poznyakoff <gray@gnu.org.ua>2009-02-25 22:50:24 (GMT)
committer Sergey Poznyakoff <gray@gnu.org.ua>2009-02-25 22:50:24 (GMT)
commit81640ab2b9ad954d4952aed43a70d7874da1c463 (patch) (side-by-side diff)
tree8160066cb7259357f17a40121f7ed7d0fff5701e /src
parent9ec721b2a3a023f6339fe3c910635e477e4a311f (diff)
downloadwydawca-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') (more/less context) (ignore whitespace changes)
-rw-r--r--src/Makefile.am1
-rw-r--r--src/config.c82
-rw-r--r--src/directive.c2
-rw-r--r--src/diskio.c68
-rw-r--r--src/lock.c2
-rw-r--r--src/mail.c2
-rw-r--r--src/triplet.c6
-rw-r--r--src/userprivs.c118
-rw-r--r--src/wydawca.c90
-rw-r--r--src/wydawca.h14
10 files changed, 260 insertions, 125 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);
diff --git a/src/lock.c b/src/lock.c
index d94731c..3b8787d 100644
--- a/src/lock.c
+++ b/src/lock.c
@@ -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);
diff --git a/src/mail.c b/src/mail.c
index ea74b8c..ba77f49 100644
--- a/src/mail.c
+++ b/src/mail.c
@@ -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 ();
- }
+ process_directives (trp, spool);
return true;
diff --git a/src/userprivs.c b/src/userprivs.c
new file mode 100644
index 0000000..e6a18c8
--- a/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);

Return to:

Send suggestions and report system problems to the System administrator.