diff --git a/etc/login.defs b/etc/login.defs index 1b81afd82e..c05bb3ba59 100644 --- a/etc/login.defs +++ b/etc/login.defs @@ -143,7 +143,7 @@ HUSHLOGIN_FILE .hushlogin # If defined, either a TZ environment parameter spec or the # fully-rooted pathname of a file containing such a spec. # -#ENV_TZ TZ=CST6CDT +#ENV_TZ TZ=UTC #ENV_TZ /etc/tzname # diff --git a/lib/getdef.c b/lib/getdef.c index e85e0a4460..30a413e2d7 100644 --- a/lib/getdef.c +++ b/lib/getdef.c @@ -559,11 +559,12 @@ static void def_load (void) * Go through all of the lines in the file. */ while (fgets_a(buf, fp) != NULL) { + if (stpsep(buf, "\n") == NULL) { + SYSLOG(LOG_CRIT, "%s: %s", def_fname, _("Non-text file.")); + exit(EXIT_FAILURE); + } - /* - * Trim trailing whitespace. - */ - stpcpy(stprspn(buf, " \t\n"), ""); + stpcpy(stprspn(buf, " \t"), ""); /* * Break the line into two fields. diff --git a/lib/hushed.c b/lib/hushed.c index d88549a647..d021268196 100644 --- a/lib/hushed.c +++ b/lib/hushed.c @@ -76,7 +76,10 @@ bool hushed (const char *username) return false; } for (found = false; !found && (fgets_a(buf, fp) != NULL);) { - stpsep(buf, "\n"); + if (stpsep(buf, "\n") == NULL) { + fclose(fp); + return false; + } found = streq(buf, pw->pw_shell) || streq(buf, pw->pw_name); } diff --git a/lib/limits.c b/lib/limits.c index 3fabe54d3a..659829b958 100644 --- a/lib/limits.c +++ b/lib/limits.c @@ -363,9 +363,13 @@ static int setup_user_limits (const char *uname) * FIXME: a better (smarter) checking should be done */ while (fgets_a(buf, fil) != NULL) { - if (strprefix(buf, "#") || strprefix(buf, "\n")) { - continue; + if (stpsep(buf, "\n") == NULL) { + fclose(fil); + return 0; } + if (strspn(buf, "#") || streq(buf, "")) + continue; + memzero_a(tempbuf); /* a valid line should have a username, then spaces, * then limits diff --git a/lib/port.c b/lib/port.c index cde50b27e2..bb0035f449 100644 --- a/lib/port.c +++ b/lib/port.c @@ -145,11 +145,15 @@ getportent(void) errno = saveerr; return NULL; } + + if (stpsep(buf, "\n") == NULL) { + errno = EINVAL; + return NULL; + } + if (strprefix(buf, "#")) goto next; - stpsep(buf, "\n"); - if (strsep2arr_a(buf, ":", fields) == -1) goto next; diff --git a/lib/tz.c b/lib/tz.c index b2d9531e20..bbcddb4253 100644 --- a/lib/tz.c +++ b/lib/tz.c @@ -1,57 +1,55 @@ -/* - * SPDX-FileCopyrightText: 1991 - 1994, Julianne Frances Haugh - * SPDX-FileCopyrightText: 1991 - 1994, Chip Rosenthal - * SPDX-FileCopyrightText: 1996 - 1998, Marek Michałkiewicz - * SPDX-FileCopyrightText: 2003 - 2005, Tomasz Kłoczko - * SPDX-FileCopyrightText: 2007 - 2010, Nicolas François - * - * SPDX-License-Identifier: BSD-3-Clause - */ +// SPDX-FileCopyrightText: 1991-1994, Julianne Frances Haugh +// SPDX-FileCopyrightText: 1991-1994, Chip Rosenthal +// SPDX-FileCopyrightText: 1996-1998, Marek Michałkiewicz +// SPDX-FileCopyrightText: 2003-2005, Tomasz Kłoczko +// SPDX-FileCopyrightText: 2007-2010, Nicolas François +// SPDX-FileCopyrightText: 2026, Alejandro Colomar +// SPDX-License-Identifier: BSD-3-Clause + #include "config.h" #ifndef USE_PAM -#ident "$Id$" - +#include #include -#include -#include "defines.h" -#include "getdef.h" #include "io/fgets/fgets.h" #include "prototypes.h" #include "string/strtok/stpsep.h" +#define DEFAULT_TZ "TZ=UTC" + + /* * tz - return local timezone name * * tz() determines the name of the local timezone by reading the - * contents of the file named by ``fname''. + * contents of the file named by 'path'. */ -/*@observer@*/const char *tz (const char *fname) +/*@observer@*/ +const char * +tz(const char *path) { - FILE *fp = NULL; - const char *result; - static char tzbuf[BUFSIZ]; - - fp = fopen (fname, "r"); - if ( (NULL == fp) - || (fgets_a(tzbuf, fp) == NULL)) { - result = "TZ=CST6CDT"; - } else { - stpsep(tzbuf, "\n"); - result = tzbuf; - } - - if (NULL != fp) { - (void) fclose (fp); - } - - return result; + FILE *fp; + static char buf[LINE_MAX + 1]; + + fp = fopen(path, "r"); + if (fp == NULL) + return DEFAULT_TZ; + + if (fgets_a(buf, fp) == NULL) + goto def; + if (stpsep(buf, "\n") == NULL) + goto def; + + fclose(fp); + return buf; +def: + fclose(fp); + return DEFAULT_TZ; } #else /* !USE_PAM */ extern int ISO_C_forbids_an_empty_translation_unit; #endif /* !USE_PAM */ - diff --git a/lib/user_busy.c b/lib/user_busy.c index 2f21ca0993..c4bea49e6d 100644 --- a/lib/user_busy.c +++ b/lib/user_busy.c @@ -130,6 +130,9 @@ static int check_status (const char *name, uid_t uid, pid_t pid, pid_t tid) return 0; } while (fgets_a(line, sfile) != NULL) { + if (stpsep(line, "\n") == NULL) + goto nontext; + if (strprefix(line, "Uid:\t")) { unsigned long ruid, euid, suid; @@ -158,6 +161,7 @@ static int check_status (const char *name, uid_t uid, pid_t pid, pid_t tid) return 0; } } +nontext: (void) fclose (sfile); return 0; } diff --git a/man/login.defs.d/ENV_TZ.xml b/man/login.defs.d/ENV_TZ.xml index 04d208ed05..bef702f58e 100644 --- a/man/login.defs.d/ENV_TZ.xml +++ b/man/login.defs.d/ENV_TZ.xml @@ -11,14 +11,14 @@ If set, it will be used to define the TZ environment variable when a user login. The value can be the name of a timezone preceded by TZ= (for example - TZ=CST6CDT), or the full path to the file + TZ=UTC), or the full path to the file containing the timezone specification (for example /etc/tzname). If a full path is specified but the file does not exist or cannot be - read, the default is to use TZ=CST6CDT. + read, the default is to use TZ=UTC. diff --git a/src/chgpasswd.c b/src/chgpasswd.c index e77ecc6ac7..7626f637d6 100644 --- a/src/chgpasswd.c +++ b/src/chgpasswd.c @@ -348,7 +348,6 @@ int main (int argc, char **argv) const struct group *gr; struct group newgr; - bool errors = false; intmax_t line = 0; struct option_flags flags = {.chroot = false}; bool process_selinux; @@ -387,10 +386,8 @@ int main (int argc, char **argv) while (fgets_a(buf, stdin) != NULL) { line++; if (stpsep(buf, "\n") == NULL) { - fprintf (stderr, _("%s: line %jd: line too long\n"), - Prog, line); - errors = true; - continue; + fprintf(stderr, "%s: %jd: %s\n", Prog, line, _("Non-text file.")); + goto fail; } /* @@ -408,8 +405,7 @@ int main (int argc, char **argv) fprintf (stderr, _("%s: line %jd: missing new password\n"), Prog, line); - errors = true; - continue; + goto fail; } newpwd = cp; if ( (!eflg) @@ -452,8 +448,7 @@ int main (int argc, char **argv) fprintf (stderr, _("%s: line %jd: group '%s' does not exist\n"), Prog, line, name); - errors = true; - continue; + goto fail; } #ifdef SHADOWGRP if (is_shadow_grp) { @@ -512,8 +507,7 @@ int main (int argc, char **argv) fprintf (stderr, _("%s: line %jd: failed to prepare the new %s entry '%s'\n"), Prog, line, sgr_dbname (), newsg.sg_namp); - errors = true; - continue; + goto fail; } } if ( (NULL == sg) @@ -524,12 +518,18 @@ int main (int argc, char **argv) fprintf (stderr, _("%s: line %jd: failed to prepare the new %s entry '%s'\n"), Prog, line, gr_dbname (), newgr.gr_name); - errors = true; - continue; + goto fail; } } } + close_files (&flags); + + nscd_flush_cache ("group"); + sssd_flush_cache (SSSD_DB_GROUP); + + return (0); +fail: /* * Any detected errors will cause the entire set of changes to be * aborted. Unlocking the group file will cause all of the @@ -537,17 +537,7 @@ int main (int argc, char **argv) * changes to be written out all at once, and then unlocked * afterwards. */ - if (errors) { - fprintf (stderr, - _("%s: error detected, changes ignored\n"), Prog); - fail_exit (1, process_selinux); - } - - close_files (&flags); - - nscd_flush_cache ("group"); - sssd_flush_cache (SSSD_DB_GROUP); - - return (0); + fprintf(stderr, "%s: %s\n", Prog, _("error detected, changes ignored\n")); + fail_exit(1, process_selinux); } diff --git a/src/chpasswd.c b/src/chpasswd.c index 9c2c5e7901..f0897d32b9 100644 --- a/src/chpasswd.c +++ b/src/chpasswd.c @@ -374,7 +374,6 @@ int main (int argc, char **argv) bool use_pam = true; #endif /* USE_PAM */ - bool errors = false; intmax_t line = 0; struct option_flags flags = {.chroot = false, .prefix = false}; bool process_selinux; @@ -429,19 +428,8 @@ int main (int argc, char **argv) line++; if (stpsep(buf, "\n") == NULL) { - if (feof (stdin) == 0) { - // Drop all remaining characters on this line. - while (fgets_a(buf, stdin) != NULL) { - if (strchr(buf, '\n')) - break; - } - - fprintf (stderr, - _("%s: line %jd: line too long\n"), - Prog, line); - errors = true; - continue; - } + fprintf(stderr, "%s: %jd: %s\n", Prog, line, _("Non-text file.")); + goto fail; } /* @@ -459,8 +447,7 @@ int main (int argc, char **argv) fprintf (stderr, _("%s: line %jd: missing new password\n"), Prog, line); - errors = true; - continue; + goto fail; } newpwd = cp; @@ -470,11 +457,11 @@ int main (int argc, char **argv) fprintf (stderr, _("%s: (line %jd, user %s) password not changed\n"), Prog, line, name); - errors = true; + goto fail; } - } else + continue; + } #endif /* USE_PAM */ - { /* * Prevent adding a non valid hash to /etc/shadow and @@ -486,8 +473,7 @@ int main (int argc, char **argv) fprintf (stderr, _("%s: (line %jd, user %s) invalid password hash\n"), Prog, line, name); - errors = true; - continue; + goto fail; } } const struct spwd *sp; @@ -514,8 +500,7 @@ int main (int argc, char **argv) fprintf (stderr, _("%s: line %jd: user '%s' does not exist\n"), Prog, line, name); - errors = true; - continue; + goto fail; } if (is_shadow_pwd) { /* The shadow entry should be updated if the @@ -580,8 +565,7 @@ int main (int argc, char **argv) fprintf (stderr, _("%s: line %jd: failed to prepare the new %s entry '%s'\n"), Prog, line, spw_dbname (), newsp.sp_namp); - errors = true; - continue; + goto fail; } } if ( (NULL == sp) @@ -590,13 +574,24 @@ int main (int argc, char **argv) fprintf (stderr, _("%s: line %jd: failed to prepare the new %s entry '%s'\n"), Prog, line, pw_dbname (), newpw.pw_name); - errors = true; - continue; + goto fail; } } - } } +#ifdef USE_PAM + if (!use_pam) +#endif /* USE_PAM */ + { + /* Save the changes */ + close_files (&flags); + } + + nscd_flush_cache ("passwd"); + sssd_flush_cache (SSSD_DB_PASSWD); + + return (0); +fail: /* * Any detected errors will cause the entire set of changes to be * aborted. Unlocking the password file will cause all of the @@ -607,29 +602,12 @@ int main (int argc, char **argv) * With PAM, it is not possible to delay the update of the * password database. */ - if (errors) { -#ifdef USE_PAM - if (!use_pam) -#endif /* USE_PAM */ - { - fprintf (stderr, - _("%s: error detected, changes ignored\n"), - Prog); - } - fail_exit (1, process_selinux); - } - #ifdef USE_PAM if (!use_pam) -#endif /* USE_PAM */ +#endif { - /* Save the changes */ - close_files (&flags); + fprintf(stderr, _("%s: error detected, changes ignored\n"), Prog); } - - nscd_flush_cache ("passwd"); - sssd_flush_cache (SSSD_DB_PASSWD); - - return (0); + fail_exit(1, process_selinux); } diff --git a/src/newusers.c b/src/newusers.c index b316d8b5ca..7f7831fbe5 100644 --- a/src/newusers.c +++ b/src/newusers.c @@ -1025,9 +1025,8 @@ int main (int argc, char **argv) */ while (fgets_a(buf, stdin) != NULL) { line++; - if (stpsep(buf, "\n") == NULL && feof(stdin) == 0) { - fprintf (stderr, _("%s: line %jd: line too long\n"), - Prog, line); + if (stpsep(buf, "\n") == NULL) { + fprintf(stderr, "%s: %jd: %s\n", Prog, line, _("Non-text file.")); fail_exit (EXIT_FAILURE, process_selinux); } diff --git a/src/suauth.c b/src/suauth.c index 5d55484ce9..0894a1d8c6 100644 --- a/src/suauth.c +++ b/src/suauth.c @@ -79,10 +79,10 @@ check_su_auth(const char *actual_id, const char *wanted_id, bool su_to_root) lines++; if (stpsep(temp, "\n") == NULL) { - SYSLOG(LOG_ERR, - "%s, line %jd: line too long or missing newline", - SUAUTHFILE, lines); - continue; + fprintf(stderr, "%s:%jd: %s\n", SUAUTHFILE, lines, _("Non-text file.")); + SYSLOG(LOG_ERR, "%s:%jd: Non-text file.", SUAUTHFILE, lines); + fclose(authfile_fd); + return DENY; } stpcpy(stprspn(temp, " \t"), ""); diff --git a/src/useradd.c b/src/useradd.c index 81798b6af5..4e53b0c3b9 100644 --- a/src/useradd.c +++ b/src/useradd.c @@ -358,7 +358,10 @@ get_defaults(const struct option_flags *flags) * values are used, everything else can be ignored. */ while (fgets_a(buf, fp) != NULL) { - stpsep(buf, "\n"); + if (stpsep(buf, "\n") == NULL) { + fprintf(stderr, "%s: %s: %s\n", Prog, default_file, _("Non-text file.")); + goto nontext; + } cp = stpsep(buf, "="); if (NULL == cp) @@ -487,8 +490,9 @@ get_defaults(const struct option_flags *flags) def_log_init = xstrdup(ccp); } } +nontext: (void) fclose (fp); - getdef_err: +getdef_err: if (prefix[0]) { free(default_file); } @@ -605,17 +609,10 @@ set_defaults(void) char *val; if (stpsep(buf, "\n") == NULL) { - /* A line which does not end with \n is only valid - * at the end of the file. - */ - if (feof (ifp) == 0) { - fprintf (stderr, - _("%s: line too long in %s: %s..."), - Prog, default_file, buf); - fclose(ifp); - fclose(ofp); - goto err_free_def; - } + fprintf(stderr, "%s: %s: %s\n", Prog, default_file, _("Non-text file.")); + fclose(ifp); + fclose(ofp); + goto err_free_def; } val = stpsep(buf, "="); diff --git a/tests/newusers/62_create_user_no_aging/config/etc/login.defs b/tests/newusers/62_create_user_no_aging/config/etc/login.defs index 1e61b5cd41..8beb789ee3 100644 --- a/tests/newusers/62_create_user_no_aging/config/etc/login.defs +++ b/tests/newusers/62_create_user_no_aging/config/etc/login.defs @@ -143,7 +143,7 @@ HUSHLOGIN_FILE .hushlogin # If defined, either a TZ environment parameter spec or the # fully-rooted pathname of a file containing such a spec. # -#ENV_TZ TZ=CST6CDT +#ENV_TZ TZ=UTC #ENV_TZ /etc/tzname # diff --git a/tests/system/etc/login.defs b/tests/system/etc/login.defs index 7f1feffd64..2286c0b85b 100644 --- a/tests/system/etc/login.defs +++ b/tests/system/etc/login.defs @@ -143,7 +143,7 @@ HUSHLOGIN_FILE .hushlogin # If defined, either a TZ environment parameter spec or the # fully-rooted pathname of a file containing such a spec. # -#ENV_TZ TZ=CST6CDT +#ENV_TZ TZ=UTC #ENV_TZ /etc/tzname #