]> git.ipfire.org Git - thirdparty/shadow.git/commitdiff
src/useradd.c: chroot or prefix SELinux file context
authorIker Pedrosa <ipedrosa@redhat.com>
Fri, 25 Apr 2025 14:32:42 +0000 (16:32 +0200)
committerIker Pedrosa <ipedrosa@redhat.com>
Tue, 7 Oct 2025 09:04:39 +0000 (11:04 +0200)
Do not process SELinux file context during file closure when chroot or
prefix options are selected.

Closes: https://github.com/shadow-maint/shadow/issues/940
Signed-off-by: Iker Pedrosa <ipedrosa@redhat.com>
src/useradd.c

index d631a8fae5f2466c3739120ddb0238143c588f54..2b1764ab856c8f215f596c8537b570aecdbda0ff 100644 (file)
 #define NEW_USER_FILE "/etc/default/nuaddXXXXXX"
 #endif
 
+/*
+ * Structures
+ */
+struct option_flags {
+       bool chroot;
+       bool prefix;
+};
 
 /*
  * Global variables
@@ -218,10 +225,10 @@ static bool home_added = false;
 
 /* local function prototypes */
 NORETURN static void fail_exit (int);
-static void get_defaults (void);
+static void get_defaults (struct option_flags *);
 static void show_defaults (void);
 static int set_defaults (void);
-static int get_groups (char *);
+static int get_groups (char *, struct option_flags *);
 static struct group * get_local_group (char * grp_name);
 NORETURN static void usage (int status);
 static void new_pwent (struct passwd *);
@@ -229,10 +236,10 @@ static void new_pwent (struct passwd *);
 static void new_spent (struct spwd *);
 static void grp_update (void);
 
-static void process_flags (int argc, char **argv);
-static void close_files (void);
-static void close_group_files (void);
-static void unlock_group_files (void);
+static void process_flags (int argc, char **argv, struct option_flags *flags);
+static void close_files (struct option_flags *flags);
+static void close_group_files (bool process_selinux);
+static void unlock_group_files (bool process_selinux);
 static void open_files (void);
 static void open_group_files (void);
 static void open_shadow (void);
@@ -320,7 +327,7 @@ static void fail_exit (int code)
  *     file does not exist.
  */
 static void
-get_defaults(void)
+get_defaults(struct option_flags *flags)
 {
        FILE        *fp;
        char        *default_file = USER_DEFAULTS_FILE;
@@ -375,7 +382,7 @@ get_defaults(void)
                ccp = cp;
 
                if (streq(buf, DGROUPS)) {
-                       if (get_groups (cp) != 0) {
+                       if (get_groups (cp, flags) != 0) {
                                fprintf (stderr,
                                         _("%s: the '%s=' configuration in %s has an invalid group, ignoring the bad group\n"),
                                         Prog, DGROUPS, default_file);
@@ -734,11 +741,14 @@ err_free_new:
  *     converts it to a NULL-terminated array. Any unknown group
  *     names are reported as errors.
  */
-static int get_groups (char *list)
+static int get_groups (char *list, struct option_flags *flags)
 {
        struct group *grp;
        bool errors = false;
        int ngroups = 0;
+       bool process_selinux;
+
+       process_selinux = !flags->chroot && !flags->prefix;
 
        /*
         * Free previous group list before creating a new one.
@@ -813,8 +823,8 @@ static int get_groups (char *list)
                gr_free (grp);
        }
 
-       close_group_files ();
-       unlock_group_files ();
+       close_group_files (process_selinux);
+       unlock_group_files (process_selinux);
 
        user_groups[ngroups] = NULL;
 
@@ -1119,7 +1129,7 @@ static void grp_update (void)
  *     the values that the user will be created with accordingly. The
  *     values are checked for sanity.
  */
-static void process_flags (int argc, char **argv)
+static void process_flags (int argc, char **argv, struct option_flags *flags)
 {
        const struct group *grp;
        bool anyflag = false;
@@ -1294,7 +1304,7 @@ static void process_flags (int argc, char **argv)
                                gflg = true;
                                break;
                        case 'G':
-                               if (get_groups (optarg) != 0) {
+                               if (get_groups (optarg, flags) != 0) {
                                        exit (E_NOTFOUND);
                                }
                                if (NULL != user_groups[0]) {
@@ -1354,8 +1364,10 @@ static void process_flags (int argc, char **argv)
                                rflg = true;
                                break;
                        case 'R': /* no-op, handled in process_root_flag () */
+                               flags->chroot = true;
                                break;
                        case 'P': /* no-op, handled in process_prefix_flag () */
+                               flags->prefix = true;
                                break;
                        case 's':
                                if (   ( !VALID (optarg) )
@@ -1560,30 +1572,34 @@ static void process_flags (int argc, char **argv)
  *     close_files() closes all of the files that were opened for this
  *     new user. This causes any modified entries to be written out.
  */
-static void close_files (void)
+static void close_files (struct option_flags *flags)
 {
-       if (pw_close (true) == 0) {
+       bool process_selinux;
+
+       process_selinux = !flags->chroot && !flags->prefix;
+
+       if (pw_close (process_selinux) == 0) {
                fprintf (stderr, _("%s: failure while writing changes to %s\n"), Prog, pw_dbname ());
                SYSLOG ((LOG_ERR, "failure while writing changes to %s", pw_dbname ()));
                fail_exit (E_PW_UPDATE);
        }
-       if (is_shadow_pwd && (spw_close (true) == 0)) {
+       if (is_shadow_pwd && (spw_close (process_selinux) == 0)) {
                fprintf (stderr,
                         _("%s: failure while writing changes to %s\n"), Prog, spw_dbname ());
                SYSLOG ((LOG_ERR, "failure while writing changes to %s", spw_dbname ()));
                fail_exit (E_PW_UPDATE);
        }
 
-       close_group_files ();
+       close_group_files (process_selinux);
 
 #ifdef ENABLE_SUBIDS
-       if (is_sub_uid  && (sub_uid_close (true) == 0)) {
+       if (is_sub_uid  && (sub_uid_close (process_selinux) == 0)) {
                fprintf (stderr,
                         _("%s: failure while writing changes to %s\n"), Prog, sub_uid_dbname ());
                SYSLOG ((LOG_ERR, "failure while writing changes to %s", sub_uid_dbname ()));
                fail_exit (E_SUB_UID_UPDATE);
        }
-       if (is_sub_gid  && (sub_gid_close (true) == 0)) {
+       if (is_sub_gid  && (sub_gid_close (process_selinux) == 0)) {
                fprintf (stderr,
                         _("%s: failure while writing changes to %s\n"), Prog, sub_gid_dbname ());
                SYSLOG ((LOG_ERR, "failure while writing changes to %s", sub_gid_dbname ()));
@@ -1591,7 +1607,7 @@ static void close_files (void)
        }
 #endif                         /* ENABLE_SUBIDS */
        if (is_shadow_pwd) {
-               if (spw_unlock (true) == 0) {
+               if (spw_unlock (process_selinux) == 0) {
                        fprintf (stderr, _("%s: failed to unlock %s\n"), Prog, spw_dbname ());
                        SYSLOG ((LOG_ERR, "failed to unlock %s", spw_dbname ()));
 #ifdef WITH_AUDIT
@@ -1604,7 +1620,7 @@ static void close_files (void)
                }
                spw_locked = false;
        }
-       if (pw_unlock (true) == 0) {
+       if (pw_unlock (process_selinux) == 0) {
                fprintf (stderr, _("%s: failed to unlock %s\n"), Prog, pw_dbname ());
                SYSLOG ((LOG_ERR, "failed to unlock %s", pw_dbname ()));
 #ifdef WITH_AUDIT
@@ -1617,11 +1633,11 @@ static void close_files (void)
        }
        pw_locked = false;
 
-       unlock_group_files ();
+       unlock_group_files (process_selinux);
 
 #ifdef ENABLE_SUBIDS
        if (is_sub_uid) {
-               if (sub_uid_unlock (true) == 0) {
+               if (sub_uid_unlock (process_selinux) == 0) {
                        fprintf (stderr, _("%s: failed to unlock %s\n"), Prog, sub_uid_dbname ());
                        SYSLOG ((LOG_ERR, "failed to unlock %s", sub_uid_dbname ()));
 #ifdef WITH_AUDIT
@@ -1635,7 +1651,7 @@ static void close_files (void)
                sub_uid_locked = false;
        }
        if (is_sub_gid) {
-               if (sub_gid_unlock (true) == 0) {
+               if (sub_gid_unlock (process_selinux) == 0) {
                        fprintf (stderr, _("%s: failed to unlock %s\n"), Prog, sub_gid_dbname ());
                        SYSLOG ((LOG_ERR, "failed to unlock %s", sub_gid_dbname ()));
 #ifdef WITH_AUDIT
@@ -1657,12 +1673,12 @@ static void close_files (void)
  *     close_group_files() closes all of the files that were opened related
  *  with groups. This causes any modified entries to be written out.
  */
-static void close_group_files (void)
+static void close_group_files (bool process_selinux)
 {
        if (!do_grp_update)
                return;
 
-       if (gr_close(true) == 0) {
+       if (gr_close(process_selinux) == 0) {
                fprintf(stderr,
                        _("%s: failure while writing changes to %s\n"),
                        Prog, gr_dbname());
@@ -1670,7 +1686,7 @@ static void close_group_files (void)
                fail_exit(E_GRP_UPDATE);
        }
 #ifdef SHADOWGRP
-       if (is_shadow_grp && sgr_close(true) == 0) {
+       if (is_shadow_grp && sgr_close(process_selinux) == 0) {
                fprintf(stderr,
                        _("%s: failure while writing changes to %s\n"),
                        Prog, sgr_dbname());
@@ -1686,9 +1702,9 @@ static void close_group_files (void)
  *     unlock_group_files() unlocks all of the files that were locked related
  *  with groups. This causes any modified entries to be written out.
  */
-static void unlock_group_files (void)
+static void unlock_group_files (bool process_selinux)
 {
-       if (gr_unlock (true) == 0) {
+       if (gr_unlock (process_selinux) == 0) {
                fprintf (stderr, _("%s: failed to unlock %s\n"), Prog, gr_dbname ());
                SYSLOG ((LOG_ERR, "failed to unlock %s", gr_dbname ()));
 #ifdef WITH_AUDIT
@@ -1702,7 +1718,7 @@ static void unlock_group_files (void)
        gr_locked = false;
 #ifdef SHADOWGRP
        if (is_shadow_grp) {
-               if (sgr_unlock (true) == 0) {
+               if (sgr_unlock (process_selinux) == 0) {
                        fprintf (stderr, _("%s: failed to unlock %s\n"), Prog, sgr_dbname ());
                        SYSLOG ((LOG_ERR, "failed to unlock %s", sgr_dbname ()));
 #ifdef WITH_AUDIT
@@ -2407,6 +2423,7 @@ int main (int argc, char **argv)
 #endif
        unsigned long subuid_count = 0;
        unsigned long subgid_count = 0;
+       struct option_flags  flags;
 
        log_set_progname(Prog);
        log_set_logfd(stderr);
@@ -2437,9 +2454,9 @@ int main (int argc, char **argv)
        is_shadow_grp = sgr_file_present ();
 #endif
 
-       get_defaults ();
+       get_defaults (&flags);
 
-       process_flags (argc, argv);
+       process_flags (argc, argv, &flags);
 
 #ifdef ENABLE_SUBIDS
        uid_min = getdef_ulong ("UID_MIN", 1000UL);
@@ -2611,7 +2628,7 @@ int main (int argc, char **argv)
 
        usr_update (subuid_count, subgid_count);
 
-       close_files ();
+       close_files (&flags);
 
        nscd_flush_cache ("passwd");
        nscd_flush_cache ("group");