]> git.ipfire.org Git - thirdparty/shadow.git/commitdiff
src/chfn.c: chroot or prefix SELinux file context
authorIker Pedrosa <ipedrosa@redhat.com>
Thu, 3 Jul 2025 09:45:29 +0000 (11:45 +0200)
committerIker Pedrosa <ipedrosa@redhat.com>
Tue, 7 Oct 2025 09:05:38 +0000 (11:05 +0200)
Do not process SELinux file context during file closure when chroot or
prefix options are selected.

Signed-off-by: Iker Pedrosa <ipedrosa@redhat.com>
src/chfn.c

index b0e7c315d973421d3204006667161e0c4b248072..0d382515558cb5d9e5851a3aaefb03dd6fbbbe88 100644 (file)
@@ -40,6 +40,9 @@
 #include "string/strcpy/strtcpy.h"
 #include "string/strdup/xstrdup.h"
 
+struct option_flags {
+       bool chroot;
+};
 
 /*
  * Global variables.
@@ -68,9 +71,9 @@ NORETURN static void fail_exit (int code);
 NORETURN static void usage (int status);
 static bool may_change_field (int);
 static void new_fields (void);
-static void process_flags (int argc, char **argv);
+static void process_flags (int argc, char **argv, struct option_flags *flags);
 static void check_perms (const struct passwd *pw);
-static void update_gecos (const char *user, char *gecos);
+static void update_gecos (const char *user, char *gecos, struct option_flags *flags);
 static void get_old_fields (const char *gecos);
 
 /*
@@ -210,7 +213,7 @@ static void new_fields (void)
  *
  *     It will not return if an error is encountered.
  */
-static void process_flags (int argc, char **argv)
+static void process_flags (int argc, char **argv, struct option_flags *flags)
 {
        int c;          /* flag currently being processed    */
        static struct option long_options[] = {
@@ -276,6 +279,7 @@ static void process_flags (int argc, char **argv)
                        STRTCPY(roomno, optarg);
                        break;
                case 'R': /* no-op, handled in process_root_flag () */
+                       flags->chroot = true;
                        break;
                case 'u':
                        usage (E_SUCCESS);
@@ -383,10 +387,13 @@ static void check_perms (const struct passwd *pw)
  *
  *     Commit the user's entry after changing her gecos field.
  */
-static void update_gecos (const char *user, char *gecos)
+static void update_gecos (const char *user, char *gecos, struct option_flags *flags)
 {
        const struct passwd *pw;        /* The user's password file entry */
        struct passwd pwent;            /* modified password file entry */
+       bool process_selinux;
+
+       process_selinux = !flags->chroot;
 
        /*
         * Before going any further, raise the ulimit to prevent colliding
@@ -453,12 +460,12 @@ static void update_gecos (const char *user, char *gecos)
        /*
         * Changes have all been made, so commit them and unlock the file.
         */
-       if (pw_close (true) == 0) {
+       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_NOPERM);
        }
-       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 ()));
                /* continue */
@@ -565,6 +572,7 @@ int main (int argc, char **argv)
        char                 new_gecos[80];
        char                 *user, *p, *e;
        const struct passwd  *pw;
+       struct option_flags  flags;
 
        sanitize_env ();
        check_fds ();
@@ -587,7 +595,7 @@ int main (int argc, char **argv)
        OPENLOG (Prog);
 
        /* parse the command line options */
-       process_flags (argc, argv);
+       process_flags (argc, argv, &flags);
 
        /*
         * Get the name of the user to check. It is either the command line
@@ -656,7 +664,7 @@ int main (int argc, char **argv)
        }
 
        /* Rewrite the user's gecos in the passwd file */
-       update_gecos (user, new_gecos);
+       update_gecos (user, new_gecos, &flags);
 
        SYSLOG ((LOG_INFO, "changed user '%s' information", user));