aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-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
@@ -36,6 +36,7 @@ wydawca_SOURCES=\
sql.h\
tcpwrap.c\
triplet.c\
+ userprivs.c\
verify.c\
wydawca.c\
wydawca.h\
diff --git a/src/config.c b/src/config.c
index b1f339f..b6e2533 100644
--- a/src/config.c
+++ b/src/config.c
@@ -978,6 +978,7 @@ cb_access_method_params (enum gconf_callback_command cmd,
meth->parmv[i] = xstrdup (vp->v.string);
}
+ gl_list_iterator_free (&itr);
meth->parmv[i] = NULL;
}
return 0;
@@ -1224,6 +1225,82 @@ 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;
+}
+
+
static struct gconf_keyword wydawca_kw[] = {
{ "daemon", NULL, N_("Enable daemon mode"),
@@ -1237,6 +1314,11 @@ static struct gconf_keyword wydawca_kw[] = {
{ "pidfile", N_("file"), N_("Set pid file name"),
gconf_type_string, &pidfile },
+ { "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"),
gconf_type_bool, &enable_locking },
{ "lockdir", N_("dir"), N_("Set directory for lock files"),
diff --git a/src/directive.c b/src/directive.c
index 2915fee..416095f 100644
--- a/src/directive.c
+++ b/src/directive.c
@@ -337,9 +337,7 @@ process_directives (struct file_triplet *trp, const struct spool *spool)
break;
case filename_dir:
- wydawca_set_root_privs ();
rc = verify_detached_signature (trp, spool);
- wydawca_set_triplet_privs (trp);
if (rc == 0)
{
if (move_file (trp, spool, file_dist, relative_dir)
diff --git a/src/diskio.c b/src/diskio.c
index fbd1050..35ba71e 100644
--- a/src/diskio.c
+++ b/src/diskio.c
@@ -58,9 +58,9 @@ 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)
{
int rc;
struct stat st;
@@ -92,7 +92,7 @@ create_hierarchy (char *dir, size_t baselen, uid_t uid, gid_t gid)
*p = 0;
}
- rc = create_hierarchy (dir, baselen, uid, gid);
+ rc = create_hierarchy (dir, baselen);
if (rc == 0)
{
if (p)
@@ -103,11 +103,6 @@ create_hierarchy (char *dir, size_t baselen, uid_t uid, gid_t gid)
dir, strerror (errno));
rc = 1;
}
- if (chown (dir, uid, gid))
- {
- logmsg (LOG_NOTICE, _("cannot change ownership of %s: %s"),
- dir, strerror (errno));
- }
}
return rc;
}
@@ -116,18 +111,14 @@ create_hierarchy (char *dir, size_t baselen, uid_t uid, gid_t gid)
NAME). Use UID and GID as owner ids.
Do nothing if dry_run_mode is set. */
char *
-create_directory (const char *base, const char *name, uid_t uid, gid_t gid)
+create_directory (const char *base, const char *name)
{
size_t baselen;
char *dir = concat_dir (base, name, &baselen);
if (!dry_run_mode)
{
- 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))
{
free (dir);
dir = NULL;
@@ -137,9 +128,9 @@ 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)
{
int in_fd, out_fd;
struct stat st;
@@ -223,10 +214,9 @@ 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)
{
int rc = 0;
@@ -234,7 +224,7 @@ do_move_file (const char *file, const char *dst_file, uid_t uid, gid_t gid)
{
if (errno == EXDEV)
{
- if (copy_file (file, dst_file, uid, gid))
+ if (copy_file (file, dst_file))
{
logmsg (LOG_CRIT, _("cannot copy %s to %s: %s"),
file, dst_file, strerror (errno));
@@ -299,13 +289,12 @@ tar_append_file (const char *archive, const char *file)
DST_DIR - Directory part of DST_FILE.
FILE - File part of DST_FILE; can contain subdirs.
ARCHIVE - Archive descriptor.
- UID, GID - Ownership
RELDIR - Directory part of FILE
Do nothing if dry_run_mode is set. */
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)
{
int rc = 0;
@@ -313,9 +302,9 @@ backup_file (const char *dst_file, const char *dst_dir, const char *file,
char *file_name;
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)
return 1;
@@ -347,7 +336,7 @@ backup_file (const char *dst_file, const char *dst_dir, const char *file,
file_name, archive_file_name);
if (!dry_run_mode)
{
- rc = do_move_file (file_name, archive_file_name, uid, gid);
+ rc = do_move_file (file_name, archive_file_name);
if (rc)
{
logmsg (LOG_ERR, _("backing `%s' up as `%s' failed: %s"),
@@ -366,7 +355,7 @@ backup_file (const char *dst_file, const char *dst_dir, const char *file,
logmsg (LOG_DEBUG, _("archiving `%s' to `%s'"), dst_file, file_name);
if (!dry_run_mode)
{
- rc = do_move_file (dst_file, file_name, uid, gid);
+ rc = do_move_file (dst_file, file_name);
if (rc)
logmsg (LOG_ERR, _("archiving `%s' as `%s' failed: %s"),
dst_file, file_name, strerror (errno));
@@ -380,7 +369,7 @@ backup_file (const char *dst_file, const char *dst_dir, const char *file,
for the argument description. */
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)
{
switch (archive->type)
@@ -389,7 +378,7 @@ do_archive_file (const char *dst_file, const char *dst_dir, const char *file,
break;
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);
case archive_tar:
if (tar_append_file (archive->name, dst_file))
@@ -415,8 +404,7 @@ dir_move_file (struct file_triplet *trp, const struct spool *spool,
{
char *dst_file;
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);
if (!dst_dir)
return 1;
@@ -428,12 +416,10 @@ dir_move_file (struct file_triplet *trp, const struct spool *spool,
if (access (dst_file, F_OK) == 0)
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);
free (dst_file);
free (dst_dir);
@@ -453,8 +439,7 @@ archive_single_file (struct file_triplet *trp, const struct spool *spool,
{
char *dst_file;
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);
if (!dst_dir)
return 1;
@@ -474,7 +459,7 @@ archive_single_file (struct file_triplet *trp, const struct spool *spool,
if (debug_level)
logmsg (LOG_DEBUG, _("archiving file `%s'"), dst_file);
rc = do_archive_file (dst_file, dst_dir, file_name, &spool->archive,
- TRIPLET_UID (trp), TRIPLET_GID (trp), reldir);
+ reldir);
if (rc == 0)
UPDATE_STATS (STAT_ARCHIVES);
}
@@ -543,8 +528,7 @@ dir_symlink_file (struct file_triplet *trp, const struct spool *spool,
{
int rc = 0;
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;
if (!dst_dir)
@@ -588,8 +572,7 @@ dir_symlink_file (struct file_triplet *trp, const struct spool *spool,
char *dir;
*p = 0;
- dir = create_directory (spool->dest_dir, dst,
- TRIPLET_UID (trp), TRIPLET_GID (trp));
+ dir = create_directory (spool->dest_dir, dst);
if (!dir)
rc = 1;
else
@@ -703,8 +686,7 @@ dir_rmsymlink_file (struct file_triplet *trp, const struct spool *spool,
char *dst_file;
int rc = 0;
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);
if (!dst_dir)
return 1;
diff --git a/src/lock.c b/src/lock.c
index d94731c..3b8787d 100644
--- a/src/lock.c
+++ b/src/lock.c
@@ -233,7 +233,7 @@ wydawca_lock_init ()
{
if (!lockdir)
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
@@ -335,7 +335,7 @@ do_notify (struct file_triplet *trp, enum notification_event ev,
switch (ntf->tgt)
{
case notify_admin:
- rcpt = admin_address;
+ rcpt = mu_address_dup (admin_address);
break;
case notify_user:
diff --git a/src/triplet.c b/src/triplet.c
index 614e2b5..e060089 100644
--- a/src/triplet.c
+++ b/src/triplet.c
@@ -199,11 +199,7 @@ triplet_processor (void *data, void *proc_data)
case triplet_complete:
if (debug_level)
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;
case triplet_incomplete:
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
@@ -19,6 +19,10 @@
#include "argmatch.h"
#include "version-etc.h"
+uid_t wydawca_uid;
+gid_t wydawca_gid;
+size_t wydawca_supp_groupc;
+gid_t *wydawca_supp_groups;
char *conffile = SYSCONFDIR "/wydawca.rc" ;
int debug_level;
int dry_run_mode;
@@ -265,73 +269,6 @@ 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;
extern int reconfigure;
@@ -377,6 +314,8 @@ main (int argc, char **argv)
if (lint_mode)
exit (0);
+ if (dry_run_mode)
+ cron_option = 1;
if (cron_option)
daemon_mode = 0;
if (foreground_option >= 0)
@@ -394,6 +333,22 @@ main (int argc, char **argv)
log_printer = syslog_printer;
}
+ 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 ();
wydawca_lock_init ();
@@ -414,7 +369,6 @@ main (int argc, char **argv)
if (reconfigure)
{
int i;
- wydawca_set_uid (0);
for (i = getdtablesize (); i > 2; i--)
close (i);
remove_pidfile ();
diff --git a/src/wydawca.h b/src/wydawca.h
index f786271..81e6509 100644
--- a/src/wydawca.h
+++ b/src/wydawca.h
@@ -303,6 +303,10 @@ 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 */
extern int debug_level; /* Debugging level */
extern int dry_run_mode; /* Dry run indicator */
@@ -355,8 +359,8 @@ size_t trim_length (const char *str);
size_t trim (char *str);
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);
void log_output (int prio, const char *prog, FILE *fp);
@@ -428,9 +432,6 @@ int process_directives (struct file_triplet *trp,
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);
int parse_time_interval (const char *str, time_t *pint, const char **endp);
@@ -538,3 +539,6 @@ void wydawca_lock_init (void);
/* tcpwrap.h */
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.