diff --git a/SOURCES/shadow-4.6-check-local-groups.patch b/SOURCES/shadow-4.6-check-local-groups.patch new file mode 100644 index 0000000..6e9d2bf --- /dev/null +++ b/SOURCES/shadow-4.6-check-local-groups.patch @@ -0,0 +1,642 @@ +From 140510de9de4771feb3af1d859c09604043a4c9b Mon Sep 17 00:00:00 2001 +From: ikerexxe +Date: Fri, 27 Mar 2020 14:23:02 +0100 +Subject: [PATCH 1/2] usermod: check only local groups with -G option + +Check only local groups when adding new supplementary groups to a user + +Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1727236 +--- + src/usermod.c | 220 ++++++++++++++++++++++++++++++++------------------ + 1 file changed, 143 insertions(+), 77 deletions(-) + +diff --git a/src/usermod.c b/src/usermod.c +index 05b98715..ef430296 100644 +--- a/src/usermod.c ++++ b/src/usermod.c +@@ -183,6 +183,7 @@ static bool sub_gid_locked = false; + static void date_to_str (/*@unique@*//*@out@*/char *buf, size_t maxsize, + long int date); + static int get_groups (char *); ++static struct group * get_local_group (char * grp_name); + static /*@noreturn@*/void usage (int status); + static void new_pwent (struct passwd *); + static void new_spent (struct spwd *); +@@ -196,7 +197,9 @@ static void grp_update (void); + + static void process_flags (int, char **); + static void close_files (void); ++static void close_group_files (void); + static void open_files (void); ++static void open_group_files (void); + static void usr_update (void); + static void move_home (void); + static void update_lastlog (void); +@@ -253,6 +256,11 @@ static int get_groups (char *list) + return 0; + } + ++ /* ++ * Open the group files ++ */ ++ open_group_files (); ++ + /* + * So long as there is some data to be converted, strip off each + * name and look it up. A mix of numerical and string values for +@@ -272,7 +280,7 @@ static int get_groups (char *list) + * Names starting with digits are treated as numerical GID + * values, otherwise the string is looked up as is. + */ +- grp = prefix_getgr_nam_gid (list); ++ grp = get_local_group (list); + + /* + * There must be a match, either by GID value or by +@@ -322,6 +330,8 @@ static int get_groups (char *list) + gr_free ((struct group *)grp); + } while (NULL != list); + ++ close_group_files (); ++ + user_groups[ngroups] = (char *) 0; + + /* +@@ -334,6 +344,44 @@ static int get_groups (char *list) + return 0; + } + ++/* ++ * get_local_group - checks if a given group name exists locally ++ * ++ * get_local_group() checks if a given group name exists locally. ++ * If the name exists the group information is returned, otherwise NULL is ++ * returned. ++ */ ++static struct group * get_local_group(char * grp_name) ++{ ++ const struct group *grp; ++ struct group *result_grp = NULL; ++ long long int gid; ++ char *endptr; ++ ++ gid = strtoll (grp_name, &endptr, 10); ++ if ( ('\0' != *grp_name) ++ && ('\0' == *endptr) ++ && (ERANGE != errno) ++ && (gid == (gid_t)gid)) { ++ grp = gr_locate_gid ((gid_t) gid); ++ } ++ else { ++ grp = gr_locate(grp_name); ++ } ++ ++ if (grp != NULL) { ++ result_grp = __gr_dup (grp); ++ if (NULL == result_grp) { ++ fprintf (stderr, ++ _("%s: Out of memory. Cannot find group '%s'.\n"), ++ Prog, grp_name); ++ fail_exit (E_GRP_UPDATE); ++ } ++ } ++ ++ return result_grp; ++} ++ + #ifdef ENABLE_SUBIDS + struct ulong_range + { +@@ -1447,50 +1495,7 @@ static void close_files (void) + } + + if (Gflg || lflg) { +- if (gr_close () == 0) { +- fprintf (stderr, +- _("%s: failure while writing changes to %s\n"), +- Prog, gr_dbname ()); +- SYSLOG ((LOG_ERR, +- "failure while writing changes to %s", +- gr_dbname ())); +- fail_exit (E_GRP_UPDATE); +- } +-#ifdef SHADOWGRP +- if (is_shadow_grp) { +- if (sgr_close () == 0) { +- fprintf (stderr, +- _("%s: failure while writing changes to %s\n"), +- Prog, sgr_dbname ()); +- SYSLOG ((LOG_ERR, +- "failure while writing changes to %s", +- sgr_dbname ())); +- fail_exit (E_GRP_UPDATE); +- } +- } +-#endif +-#ifdef SHADOWGRP +- if (is_shadow_grp) { +- if (sgr_unlock () == 0) { +- fprintf (stderr, +- _("%s: failed to unlock %s\n"), +- Prog, sgr_dbname ()); +- SYSLOG ((LOG_ERR, +- "failed to unlock %s", +- sgr_dbname ())); +- /* continue */ +- } +- } +-#endif +- if (gr_unlock () == 0) { +- fprintf (stderr, +- _("%s: failed to unlock %s\n"), +- Prog, gr_dbname ()); +- SYSLOG ((LOG_ERR, +- "failed to unlock %s", +- gr_dbname ())); +- /* continue */ +- } ++ close_group_files (); + } + + if (is_shadow_pwd) { +@@ -1559,6 +1564,60 @@ static void close_files (void) + #endif + } + ++/* ++ * close_group_files - close all of the files that were opened ++ * ++ * 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) ++{ ++ if (gr_close () == 0) { ++ fprintf (stderr, ++ _("%s: failure while writing changes to %s\n"), ++ Prog, gr_dbname ()); ++ SYSLOG ((LOG_ERR, ++ "failure while writing changes to %s", ++ gr_dbname ())); ++ fail_exit (E_GRP_UPDATE); ++ } ++#ifdef SHADOWGRP ++ if (is_shadow_grp) { ++ if (sgr_close () == 0) { ++ fprintf (stderr, ++ _("%s: failure while writing changes to %s\n"), ++ Prog, sgr_dbname ()); ++ SYSLOG ((LOG_ERR, ++ "failure while writing changes to %s", ++ sgr_dbname ())); ++ fail_exit (E_GRP_UPDATE); ++ } ++ } ++#endif ++#ifdef SHADOWGRP ++ if (is_shadow_grp) { ++ if (sgr_unlock () == 0) { ++ fprintf (stderr, ++ _("%s: failed to unlock %s\n"), ++ Prog, sgr_dbname ()); ++ SYSLOG ((LOG_ERR, ++ "failed to unlock %s", ++ sgr_dbname ())); ++ /* continue */ ++ } ++ } ++#endif ++ if (gr_unlock () == 0) { ++ fprintf (stderr, ++ _("%s: failed to unlock %s\n"), ++ Prog, gr_dbname ()); ++ SYSLOG ((LOG_ERR, ++ "failed to unlock %s", ++ gr_dbname ())); ++ /* continue */ ++ } ++} ++ + /* + * open_files - lock and open the password files + * +@@ -1594,38 +1653,7 @@ static void open_files (void) + } + + if (Gflg || lflg) { +- /* +- * Lock and open the group file. This will load all of the +- * group entries. +- */ +- if (gr_lock () == 0) { +- fprintf (stderr, +- _("%s: cannot lock %s; try again later.\n"), +- Prog, gr_dbname ()); +- fail_exit (E_GRP_UPDATE); +- } +- gr_locked = true; +- if (gr_open (O_CREAT | O_RDWR) == 0) { +- fprintf (stderr, +- _("%s: cannot open %s\n"), +- Prog, gr_dbname ()); +- fail_exit (E_GRP_UPDATE); +- } +-#ifdef SHADOWGRP +- if (is_shadow_grp && (sgr_lock () == 0)) { +- fprintf (stderr, +- _("%s: cannot lock %s; try again later.\n"), +- Prog, sgr_dbname ()); +- fail_exit (E_GRP_UPDATE); +- } +- sgr_locked = true; +- if (is_shadow_grp && (sgr_open (O_CREAT | O_RDWR) == 0)) { +- fprintf (stderr, +- _("%s: cannot open %s\n"), +- Prog, sgr_dbname ()); +- fail_exit (E_GRP_UPDATE); +- } +-#endif ++ open_group_files (); + } + #ifdef ENABLE_SUBIDS + if (vflg || Vflg) { +@@ -1661,6 +1689,44 @@ static void open_files (void) + #endif /* ENABLE_SUBIDS */ + } + ++/* ++ * open_group_files - lock and open the group files ++ * ++ * open_group_files() loads all of the group entries. ++ */ ++static void open_group_files (void) ++{ ++ if (gr_lock () == 0) { ++ fprintf (stderr, ++ _("%s: cannot lock %s; try again later.\n"), ++ Prog, gr_dbname ()); ++ fail_exit (E_GRP_UPDATE); ++ } ++ gr_locked = true; ++ if (gr_open (O_CREAT | O_RDWR) == 0) { ++ fprintf (stderr, ++ _("%s: cannot open %s\n"), ++ Prog, gr_dbname ()); ++ fail_exit (E_GRP_UPDATE); ++ } ++ ++#ifdef SHADOWGRP ++ if (is_shadow_grp && (sgr_lock () == 0)) { ++ fprintf (stderr, ++ _("%s: cannot lock %s; try again later.\n"), ++ Prog, sgr_dbname ()); ++ fail_exit (E_GRP_UPDATE); ++ } ++ sgr_locked = true; ++ if (is_shadow_grp && (sgr_open (O_CREAT | O_RDWR) == 0)) { ++ fprintf (stderr, ++ _("%s: cannot open %s\n"), ++ Prog, sgr_dbname ()); ++ fail_exit (E_GRP_UPDATE); ++ } ++#endif ++} ++ + /* + * usr_update - create the user entries + * +-- +2.25.4 + + +From 8762f465d487a52bf68f9c0b7c3c1eb3caea7bc9 Mon Sep 17 00:00:00 2001 +From: ikerexxe +Date: Mon, 30 Mar 2020 09:08:23 +0200 +Subject: [PATCH 2/2] useradd: check only local groups with -G option + +Check only local groups when adding new supplementary groups to a user + +Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1727236 +--- + src/useradd.c | 234 +++++++++++++++++++++++++++++++++----------------- + 1 file changed, 157 insertions(+), 77 deletions(-) + +diff --git a/src/useradd.c b/src/useradd.c +index 645d4a40..90210233 100644 +--- a/src/useradd.c ++++ b/src/useradd.c +@@ -211,6 +211,7 @@ static void get_defaults (void); + static void show_defaults (void); + static int set_defaults (void); + static int get_groups (char *); ++static struct group * get_local_group (char * grp_name); + static void usage (int status); + static void new_pwent (struct passwd *); + +@@ -220,7 +221,10 @@ 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 open_files (void); ++static void open_group_files (void); + static void open_shadow (void); + static void faillog_reset (uid_t); + static void lastlog_reset (uid_t); +@@ -731,6 +735,11 @@ static int get_groups (char *list) + return 0; + } + ++ /* ++ * Open the group files ++ */ ++ open_group_files (); ++ + /* + * So long as there is some data to be converted, strip off + * each name and look it up. A mix of numerical and string +@@ -749,7 +758,7 @@ static int get_groups (char *list) + * Names starting with digits are treated as numerical + * GID values, otherwise the string is looked up as is. + */ +- grp = prefix_getgr_nam_gid (list); ++ grp = get_local_group (list); + + /* + * There must be a match, either by GID value or by +@@ -799,6 +808,9 @@ static int get_groups (char *list) + user_groups[ngroups++] = xstrdup (grp->gr_name); + } while (NULL != list); + ++ close_group_files (); ++ unlock_group_files (); ++ + user_groups[ngroups] = (char *) 0; + + /* +@@ -811,6 +823,44 @@ static int get_groups (char *list) + return 0; + } + ++/* ++ * get_local_group - checks if a given group name exists locally ++ * ++ * get_local_group() checks if a given group name exists locally. ++ * If the name exists the group information is returned, otherwise NULL is ++ * returned. ++ */ ++static struct group * get_local_group(char * grp_name) ++{ ++ const struct group *grp; ++ struct group *result_grp = NULL; ++ long long int gid; ++ char *endptr; ++ ++ gid = strtoll (grp_name, &endptr, 10); ++ if ( ('\0' != *grp_name) ++ && ('\0' == *endptr) ++ && (ERANGE != errno) ++ && (gid == (gid_t)gid)) { ++ grp = gr_locate_gid ((gid_t) gid); ++ } ++ else { ++ grp = gr_locate(grp_name); ++ } ++ ++ if (grp != NULL) { ++ result_grp = __gr_dup (grp); ++ if (NULL == result_grp) { ++ fprintf (stderr, ++ _("%s: Out of memory. Cannot find group '%s'.\n"), ++ Prog, grp_name); ++ fail_exit (E_GRP_UPDATE); ++ } ++ } ++ ++ return result_grp; ++} ++ + /* + * usage - display usage message and exit + */ +@@ -1530,23 +1580,9 @@ static void close_files (void) + SYSLOG ((LOG_ERR, "failure while writing changes to %s", spw_dbname ())); + fail_exit (E_PW_UPDATE); + } +- if (do_grp_update) { +- if (gr_close () == 0) { +- fprintf (stderr, +- _("%s: failure while writing changes to %s\n"), Prog, gr_dbname ()); +- SYSLOG ((LOG_ERR, "failure while writing changes to %s", gr_dbname ())); +- fail_exit (E_GRP_UPDATE); +- } +-#ifdef SHADOWGRP +- if (is_shadow_grp && (sgr_close () == 0)) { +- fprintf (stderr, +- _("%s: failure while writing changes to %s\n"), +- Prog, sgr_dbname ()); +- SYSLOG ((LOG_ERR, "failure while writing changes to %s", sgr_dbname ())); +- fail_exit (E_GRP_UPDATE); +- } +-#endif +- } ++ ++ close_group_files (); ++ + #ifdef ENABLE_SUBIDS + if (is_sub_uid && (sub_uid_close () == 0)) { + fprintf (stderr, +@@ -1587,34 +1623,9 @@ static void close_files (void) + /* continue */ + } + pw_locked = false; +- if (gr_unlock () == 0) { +- fprintf (stderr, _("%s: failed to unlock %s\n"), Prog, gr_dbname ()); +- SYSLOG ((LOG_ERR, "failed to unlock %s", gr_dbname ())); +-#ifdef WITH_AUDIT +- audit_logger (AUDIT_ADD_USER, Prog, +- "unlocking-group-file", +- user_name, AUDIT_NO_ID, +- SHADOW_AUDIT_FAILURE); +-#endif +- /* continue */ +- } +- gr_locked = false; +-#ifdef SHADOWGRP +- if (is_shadow_grp) { +- if (sgr_unlock () == 0) { +- fprintf (stderr, _("%s: failed to unlock %s\n"), Prog, sgr_dbname ()); +- SYSLOG ((LOG_ERR, "failed to unlock %s", sgr_dbname ())); +-#ifdef WITH_AUDIT +- audit_logger (AUDIT_ADD_USER, Prog, +- "unlocking-gshadow-file", +- user_name, AUDIT_NO_ID, +- SHADOW_AUDIT_FAILURE); +-#endif +- /* continue */ +- } +- sgr_locked = false; +- } +-#endif ++ ++ unlock_group_files (); ++ + #ifdef ENABLE_SUBIDS + if (is_sub_uid) { + if (sub_uid_unlock () == 0) { +@@ -1647,6 +1658,71 @@ static void close_files (void) + #endif /* ENABLE_SUBIDS */ + } + ++/* ++ * close_group_files - close all of the files that were opened ++ * ++ * 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) ++{ ++ if (do_grp_update) { ++ if (gr_close () == 0) { ++ fprintf (stderr, ++ _("%s: failure while writing changes to %s\n"), Prog, gr_dbname ()); ++ SYSLOG ((LOG_ERR, "failure while writing changes to %s", gr_dbname ())); ++ fail_exit (E_GRP_UPDATE); ++ } ++#ifdef SHADOWGRP ++ if (is_shadow_grp && (sgr_close () == 0)) { ++ fprintf (stderr, ++ _("%s: failure while writing changes to %s\n"), ++ Prog, sgr_dbname ()); ++ SYSLOG ((LOG_ERR, "failure while writing changes to %s", sgr_dbname ())); ++ fail_exit (E_GRP_UPDATE); ++ } ++#endif /* SHADOWGRP */ ++ } ++} ++ ++/* ++ * unlock_group_files - unlock all of the files that were locked ++ * ++ * 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) ++{ ++ if (gr_unlock () == 0) { ++ fprintf (stderr, _("%s: failed to unlock %s\n"), Prog, gr_dbname ()); ++ SYSLOG ((LOG_ERR, "failed to unlock %s", gr_dbname ())); ++#ifdef WITH_AUDIT ++ audit_logger (AUDIT_ADD_USER, Prog, ++ "unlocking-group-file", ++ user_name, AUDIT_NO_ID, ++ SHADOW_AUDIT_FAILURE); ++#endif /* WITH_AUDIT */ ++ /* continue */ ++ } ++ gr_locked = false; ++#ifdef SHADOWGRP ++ if (is_shadow_grp) { ++ if (sgr_unlock () == 0) { ++ fprintf (stderr, _("%s: failed to unlock %s\n"), Prog, sgr_dbname ()); ++ SYSLOG ((LOG_ERR, "failed to unlock %s", sgr_dbname ())); ++#ifdef WITH_AUDIT ++ audit_logger (AUDIT_ADD_USER, Prog, ++ "unlocking-gshadow-file", ++ user_name, AUDIT_NO_ID, ++ SHADOW_AUDIT_FAILURE); ++#endif /* WITH_AUDIT */ ++ /* continue */ ++ } ++ sgr_locked = false; ++ } ++#endif /* SHADOWGRP */ ++} ++ + /* + * open_files - lock and open the password files + * +@@ -1668,37 +1744,8 @@ static void open_files (void) + + /* shadow file will be opened by open_shadow(); */ + +- /* +- * Lock and open the group file. +- */ +- if (gr_lock () == 0) { +- fprintf (stderr, +- _("%s: cannot lock %s; try again later.\n"), +- Prog, gr_dbname ()); +- fail_exit (E_GRP_UPDATE); +- } +- gr_locked = true; +- if (gr_open (O_CREAT | O_RDWR) == 0) { +- fprintf (stderr, _("%s: cannot open %s\n"), Prog, gr_dbname ()); +- fail_exit (E_GRP_UPDATE); +- } +-#ifdef SHADOWGRP +- if (is_shadow_grp) { +- if (sgr_lock () == 0) { +- fprintf (stderr, +- _("%s: cannot lock %s; try again later.\n"), +- Prog, sgr_dbname ()); +- fail_exit (E_GRP_UPDATE); +- } +- sgr_locked = true; +- if (sgr_open (O_CREAT | O_RDWR) == 0) { +- fprintf (stderr, +- _("%s: cannot open %s\n"), +- Prog, sgr_dbname ()); +- fail_exit (E_GRP_UPDATE); +- } +- } +-#endif ++ open_group_files (); ++ + #ifdef ENABLE_SUBIDS + if (is_sub_uid) { + if (sub_uid_lock () == 0) { +@@ -1733,6 +1780,39 @@ static void open_files (void) + #endif /* ENABLE_SUBIDS */ + } + ++static void open_group_files (void) ++{ ++ if (gr_lock () == 0) { ++ fprintf (stderr, ++ _("%s: cannot lock %s; try again later.\n"), ++ Prog, gr_dbname ()); ++ fail_exit (E_GRP_UPDATE); ++ } ++ gr_locked = true; ++ if (gr_open (O_CREAT | O_RDWR) == 0) { ++ fprintf (stderr, _("%s: cannot open %s\n"), Prog, gr_dbname ()); ++ fail_exit (E_GRP_UPDATE); ++ } ++ ++#ifdef SHADOWGRP ++ if (is_shadow_grp) { ++ if (sgr_lock () == 0) { ++ fprintf (stderr, ++ _("%s: cannot lock %s; try again later.\n"), ++ Prog, sgr_dbname ()); ++ fail_exit (E_GRP_UPDATE); ++ } ++ sgr_locked = true; ++ if (sgr_open (O_CREAT | O_RDWR) == 0) { ++ fprintf (stderr, ++ _("%s: cannot open %s\n"), ++ Prog, sgr_dbname ()); ++ fail_exit (E_GRP_UPDATE); ++ } ++ } ++#endif /* SHADOWGRP */ ++} ++ + static void open_shadow (void) + { + if (!is_shadow_pwd) { +-- +2.25.4 + diff --git a/SOURCES/shadow-4.6-home_mode-directive.patch b/SOURCES/shadow-4.6-home_mode-directive.patch new file mode 100644 index 0000000..f6b50eb --- /dev/null +++ b/SOURCES/shadow-4.6-home_mode-directive.patch @@ -0,0 +1,201 @@ +From a847899b521b0df0665e442845bcff23407d9ea0 Mon Sep 17 00:00:00 2001 +From: Duncan Overbruck +Date: Sat, 11 Jan 2020 22:19:37 +0100 +Subject: [PATCH] add new HOME_MODE login.defs(5) option + +This option can be used to set a separate mode for useradd(8) and +newusers(8) to create the home directories with. +If this option is not set, the current behavior of using UMASK +or the default umask is preserved. + +There are many distributions that set UMASK to 077 by default just +to create home directories not readable by others and use things like +/etc/profile, bashrc or sudo configuration files to set a less +restrictive +umask. This has always resulted in bug reports because it is hard +to follow as users tend to change files like bashrc and are not about +setting the umask to counteract the umask set in /etc/login.defs. + +A recent change in sudo has also resulted in many bug reports about +this. sudo now tries to respect the umask set by pam modules and on +systems where pam does not set a umask, the login.defs UMASK value is +used. +--- + etc/login.defs | 7 ++++++- + lib/getdef.c | 1 + + man/login.defs.5.xml | 4 ++++ + man/login.defs.d/UMASK.xml | 3 ++- + src/newusers.c | 6 +++--- + src/useradd.c | 5 +++-- + 6 files changed, 19 insertions(+), 7 deletions(-) + +diff --git a/etc/login.defs b/etc/login.defs +index cd2597dc..a2f8cd50 100644 +--- a/etc/login.defs ++++ b/etc/login.defs +@@ -195,12 +195,17 @@ KILLCHAR 025 + # Default initial "umask" value used by login(1) on non-PAM enabled systems. + # Default "umask" value for pam_umask(8) on PAM enabled systems. + # UMASK is also used by useradd(8) and newusers(8) to set the mode for new +-# home directories. ++# home directories if HOME_MODE is not set. + # 022 is the default value, but 027, or even 077, could be considered + # for increased privacy. There is no One True Answer here: each sysadmin + # must make up their mind. + UMASK 022 + ++# HOME_MODE is used by useradd(8) and newusers(8) to set the mode for new ++# home directories. ++# If HOME_MODE is not set, the value of UMASK is used to create the mode. ++HOME_MODE 0700 ++ + # + # Password aging controls: + # +diff --git a/lib/getdef.c b/lib/getdef.c +index bbb273f4..00f6abfe 100644 +--- a/lib/getdef.c ++++ b/lib/getdef.c +@@ -93,6 +93,7 @@ static struct itemdef def_table[] = { + {"FAKE_SHELL", NULL}, + {"GID_MAX", NULL}, + {"GID_MIN", NULL}, ++ {"HOME_MODE", NULL}, + {"HUSHLOGIN_FILE", NULL}, + {"KILLCHAR", NULL}, + {"LOGIN_RETRIES", NULL}, +diff --git a/man/login.defs.5.xml b/man/login.defs.5.xml +index ebf60ba3..9e95da20 100644 +--- a/man/login.defs.5.xml ++++ b/man/login.defs.5.xml +@@ -50,6 +50,7 @@ + + + ++ + + + +@@ -185,6 +186,7 @@ + &FAKE_SHELL; + &FTMP_FILE; + &GID_MAX; ++ &HOME_MODE; + &HUSHLOGIN_FILE; + &ISSUE_FILE; + &KILLCHAR; +@@ -401,6 +403,7 @@ + ENCRYPT_METHOD + GID_MAX GID_MIN + MAX_MEMBERS_PER_GROUP MD5_CRYPT_ENAB ++ HOME_MODE + PASS_MAX_DAYS PASS_MIN_DAYS PASS_WARN_AGE + SHA_CRYPT_MAX_ROUNDS + SHA_CRYPT_MIN_ROUNDS +@@ -481,6 +484,7 @@ + + CREATE_HOME + GID_MAX GID_MIN ++ HOME_MODE + MAIL_DIR MAX_MEMBERS_PER_GROUP + PASS_MAX_DAYS PASS_MIN_DAYS PASS_WARN_AGE + SUB_GID_COUNT SUB_GID_MAX SUB_GID_MIN +diff --git a/man/login.defs.d/HOME_MODE.xml b/man/login.defs.d/HOME_MODE.xml +new file mode 100644 +index 00000000..21aa55f7 +--- /dev/null ++++ b/man/login.defs.d/HOME_MODE.xml +@@ -0,0 +1,43 @@ ++ ++ ++ (number) ++ ++ ++ The mode for new home directories. If not specified, ++ the is used to create the mode. ++ ++ ++ useradd and newusers use this ++ to set the mode of the home directory they create. ++ ++ ++ +diff --git a/man/login.defs.d/UMASK.xml b/man/login.defs.d/UMASK.xml +index d7b71a5e..0f061dbb 100644 +--- a/man/login.defs.d/UMASK.xml ++++ b/man/login.defs.d/UMASK.xml +@@ -37,7 +37,8 @@ + + + useradd and newusers use this +- mask to set the mode of the home directory they create ++ mask to set the mode of the home directory they create if ++ is not set. + + + It is also used by login to define users' initial +diff --git a/src/newusers.c b/src/newusers.c +index 99c69f78..e9fe0e27 100644 +--- a/src/newusers.c ++++ b/src/newusers.c +@@ -1216,9 +1216,9 @@ int main (int argc, char **argv) + if ( ('\0' != fields[5][0]) + && (access (newpw.pw_dir, F_OK) != 0)) { + /* FIXME: should check for directory */ +- mode_t msk = 0777 & ~getdef_num ("UMASK", +- GETDEF_DEFAULT_UMASK); +- if (mkdir (newpw.pw_dir, msk) != 0) { ++ mode_t mode = getdef_num ("HOME_MODE", ++ 0777 & ~getdef_num ("UMASK", GETDEF_DEFAULT_UMASK)); ++ if (mkdir (newpw.pw_dir, mode) != 0) { + fprintf (stderr, + _("%s: line %d: mkdir %s failed: %s\n"), + Prog, line, newpw.pw_dir, +diff --git a/src/useradd.c b/src/useradd.c +index 4af0f7c6..8b453e3c 100644 +--- a/src/useradd.c ++++ b/src/useradd.c +@@ -2152,8 +2152,9 @@ static void create_home (void) + fail_exit (E_HOMEDIR); + } + (void) chown (prefix_user_home, user_id, user_gid); +- chmod (prefix_user_home, +- 0777 & ~getdef_num ("UMASK", GETDEF_DEFAULT_UMASK)); ++ mode_t mode = getdef_num ("HOME_MODE", ++ 0777 & ~getdef_num ("UMASK", GETDEF_DEFAULT_UMASK)); ++ chmod (prefix_user_home, mode); + home_added = true; + #ifdef WITH_AUDIT + audit_logger (AUDIT_USER_MGMT, Prog, +-- +2.25.2 + diff --git a/SOURCES/shadow-4.6-regular-user.patch b/SOURCES/shadow-4.6-regular-user.patch new file mode 100644 index 0000000..a1c781a --- /dev/null +++ b/SOURCES/shadow-4.6-regular-user.patch @@ -0,0 +1,108 @@ +From fd4405b763d26649339069532e79bd45013c8c38 Mon Sep 17 00:00:00 2001 +From: Tomas Mraz +Date: Mon, 20 Jan 2020 13:58:07 +0100 +Subject: [PATCH] Do not mistake a regular user process for a namespaced one + +In case there is a regular user with a process running on a system +with uid falling into a namespaced uid range of another user. +The user with the colliding namespaced uid range will not be +allowed to be deleted without forcing the action with -f. + +The user_busy() is adjusted to check whether the suspected process +is really a namespaced process in a different namespace. +--- + libmisc/user_busy.c | 44 ++++++++++++++++++++++++++++++++++++-------- + 1 file changed, 36 insertions(+), 8 deletions(-) + +diff --git a/libmisc/user_busy.c b/libmisc/user_busy.c +index b0867568..324bb946 100644 +--- a/libmisc/user_busy.c ++++ b/libmisc/user_busy.c +@@ -39,6 +39,7 @@ + #include + #include + #include ++#include + #include "defines.h" + #include "prototypes.h" + #ifdef ENABLE_SUBIDS +@@ -106,6 +107,31 @@ static int user_busy_utmp (const char *name) + #endif /* !__linux__ */ + + #ifdef __linux__ ++#ifdef ENABLE_SUBIDS ++#define in_parentuid_range(uid) ((uid) >= parentuid && (uid) < parentuid + range) ++static int different_namespace (const char *sname) ++{ ++ /* 41: /proc/xxxxxxxxxx/task/xxxxxxxxxx/ns/user + \0 */ ++ char path[41]; ++ char buf[512], buf2[512]; ++ ssize_t llen1, llen2; ++ ++ snprintf (path, 41, "/proc/%s/ns/user", sname); ++ ++ if ((llen1 = readlink (path, buf, sizeof(buf))) == -1) ++ return 0; ++ ++ if ((llen2 = readlink ("/proc/self/ns/user", buf2, sizeof(buf2))) == -1) ++ return 0; ++ ++ if (llen1 == llen2 && memcmp (buf, buf2, llen1) == 0) ++ return 0; /* same namespace */ ++ ++ return 1; ++} ++#endif /* ENABLE_SUBIDS */ ++ ++ + static int check_status (const char *name, const char *sname, uid_t uid) + { + /* 40: /proc/xxxxxxxxxx/task/xxxxxxxxxx/status + \0 */ +@@ -114,7 +140,6 @@ static int check_status (const char *name, const char *sname, uid_t uid) + FILE *sfile; + + snprintf (status, 40, "/proc/%s/status", sname); +- status[39] = '\0'; + + sfile = fopen (status, "r"); + if (NULL == sfile) { +@@ -123,26 +148,29 @@ static int check_status (const char *name, const char *sname, uid_t uid) + while (fgets (line, sizeof (line), sfile) == line) { + if (strncmp (line, "Uid:\t", 5) == 0) { + unsigned long ruid, euid, suid; ++ + assert (uid == (unsigned long) uid); ++ (void) fclose (sfile); + if (sscanf (line, + "Uid:\t%lu\t%lu\t%lu\n", + &ruid, &euid, &suid) == 3) { + if ( (ruid == (unsigned long) uid) + || (euid == (unsigned long) uid) +- || (suid == (unsigned long) uid) ++ || (suid == (unsigned long) uid) ) { ++ return 1; ++ } + #ifdef ENABLE_SUBIDS +- || have_sub_uids(name, ruid, 1) +- || have_sub_uids(name, euid, 1) +- || have_sub_uids(name, suid, 1) +-#endif /* ENABLE_SUBIDS */ ++ if ( different_namespace (sname) ++ && ( have_sub_uids(name, ruid, 1) ++ || have_sub_uids(name, euid, 1) ++ || have_sub_uids(name, suid, 1)) + ) { +- (void) fclose (sfile); + return 1; + } ++#endif /* ENABLE_SUBIDS */ + } else { + /* Ignore errors. This is just a best effort. */ + } +- (void) fclose (sfile); + return 0; + } + } +-- +2.25.2 + diff --git a/SOURCES/shadow-utils.login.defs b/SOURCES/shadow-utils.login.defs index 0adfb66..12d516c 100644 --- a/SOURCES/shadow-utils.login.defs +++ b/SOURCES/shadow-utils.login.defs @@ -15,6 +15,20 @@ MAIL_DIR /var/spool/mail #MAIL_FILE .mail +# Default initial "umask" value used by login(1) on non-PAM enabled systems. +# Default "umask" value for pam_umask(8) on PAM enabled systems. +# UMASK is also used by useradd(8) and newusers(8) to set the mode for new +# home directories if HOME_MODE is not set. +# 022 is the default value, but 027, or even 077, could be considered +# for increased privacy. There is no One True Answer here: each sysadmin +# must make up their mind. +UMASK 022 + +# HOME_MODE is used by useradd(8) and newusers(8) to set the mode for new +# home directories. +# If HOME_MODE is not set, the value of UMASK is used to create the mode. +HOME_MODE 0700 + # Password aging controls: # # PASS_MAX_DAYS Maximum number of days a password may be used. @@ -59,10 +73,6 @@ SYS_GID_MAX 999 # CREATE_HOME yes -# The permission mask is initialized to this value. If not specified, -# the permission mask will be initialized to 022. -UMASK 077 - # This enables userdel to remove user groups if no members exist. # USERGROUPS_ENAB yes diff --git a/SPECS/shadow-utils.spec b/SPECS/shadow-utils.spec index b329b11..81dfeef 100644 --- a/SPECS/shadow-utils.spec +++ b/SPECS/shadow-utils.spec @@ -1,7 +1,7 @@ Summary: Utilities for managing accounts and shadow password files Name: shadow-utils Version: 4.6 -Release: 8%{?dist} +Release: 11%{?dist} Epoch: 2 URL: http://pkg-shadow.alioth.debian.org/ Source0: https://github.com/shadow-maint/shadow/releases/download/%{version}/shadow-%{version}.tar.xz @@ -37,6 +37,12 @@ Patch38: shadow-4.6-sysugid-min-limit.patch Patch39: shadow-4.6-chgrp-guard.patch Patch40: shadow-4.6-ignore-login-prompt.patch Patch41: shadow-4.6-use-lckpwdf.patch +# Upstreamed +Patch42: shadow-4.6-regular-user.patch +# Upstreamed +Patch43: shadow-4.6-home_mode-directive.patch +# Upstreamed +Patch44: shadow-4.6-check-local-groups.patch License: BSD and GPLv2+ Group: System Environment/Base @@ -96,6 +102,9 @@ are used for managing group accounts. %patch39 -p1 -b .chgrp-guard %patch40 -p1 -b .login-prompt %patch41 -p1 -b .use-lckpwdf +%patch42 -p1 -b .regular-user +%patch43 -p1 -b .home_mode-directive +%patch44 -p1 -b .check-local-groups iconv -f ISO88591 -t utf-8 doc/HOWTO > doc/HOWTO.utf8 cp -f doc/HOWTO.utf8 doc/HOWTO @@ -250,6 +259,16 @@ done %{_mandir}/man8/vigr.8* %changelog +* Fri Aug 7 2020 Iker Pedrosa - 2:4.6-11 +- change UMASK value and add HOME_MODE in login.defs (#1777718) + +* Tue May 5 2020 Iker Pedrosa - 2:4.6-10 +- check only local groups when adding new supplementary groups to a user + +* Fri Apr 17 2020 Iker Pedrosa - 2:4.6-9 +- do not mistake a regular user process for a namespaced one (#1788696) +- add HOME_MODE support in login.defs (#1777718) + * Fri Jun 7 2019 Tomáš Mráz - 2:4.6-8 - properly audit group password change - do not add uid of a new (not yet added) user to the audit message