From 4c7aa8cf3c7e7919622aa7c20760f121d95bbde9 Mon Sep 17 00:00:00 2001 From: Tobias Stoeckmann Date: Sun, 12 Jan 2025 19:19:39 +0100 Subject: [PATCH] src/: Make line number overflows less likely Huge files could trigger signed integer overflows if enough lines are within the file. Use intmax_t which is at least 64 bit to move this event far into the future. Reviewed-by: Alejandro Colomar Signed-off-by: Tobias Stoeckmann --- src/chgpasswd.c | 13 +++++++------ src/chpasswd.c | 15 ++++++++------- src/login_nopam.c | 9 +++++---- src/newusers.c | 33 +++++++++++++++++---------------- src/suauth.c | 17 +++++++++-------- 5 files changed, 46 insertions(+), 41 deletions(-) diff --git a/src/chgpasswd.c b/src/chgpasswd.c index 2d50337e6..807ef15d3 100644 --- a/src/chgpasswd.c +++ b/src/chgpasswd.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include @@ -426,7 +427,7 @@ int main (int argc, char **argv) const struct group *gr; struct group newgr; int errors = 0; - int line = 0; + intmax_t line = 0; log_set_progname(Prog); log_set_logfd(stderr); @@ -463,7 +464,7 @@ int main (int argc, char **argv) while (fgets (buf, (int) sizeof buf, stdin) != NULL) { line++; if (stpsep(buf, "\n") == NULL) { - fprintf (stderr, _("%s: line %d: line too long\n"), + fprintf (stderr, _("%s: line %jd: line too long\n"), Prog, line); errors++; continue; @@ -482,7 +483,7 @@ int main (int argc, char **argv) cp = stpsep(name, ":"); if (cp == NULL) { fprintf (stderr, - _("%s: line %d: missing new password\n"), + _("%s: line %jd: missing new password\n"), Prog, line); errors++; continue; @@ -533,7 +534,7 @@ int main (int argc, char **argv) gr = gr_locate (name); if (NULL == gr) { fprintf (stderr, - _("%s: line %d: group '%s' does not exist\n"), Prog, + _("%s: line %jd: group '%s' does not exist\n"), Prog, line, name); errors++; continue; @@ -593,7 +594,7 @@ int main (int argc, char **argv) if (NULL != sg) { if (sgr_update (&newsg) == 0) { fprintf (stderr, - _("%s: line %d: failed to prepare the new %s entry '%s'\n"), + _("%s: line %jd: failed to prepare the new %s entry '%s'\n"), Prog, line, sgr_dbname (), newsg.sg_name); errors++; continue; @@ -605,7 +606,7 @@ int main (int argc, char **argv) { if (gr_update (&newgr) == 0) { fprintf (stderr, - _("%s: line %d: failed to prepare the new %s entry '%s'\n"), + _("%s: line %jd: failed to prepare the new %s entry '%s'\n"), Prog, line, gr_dbname (), newgr.gr_name); errors++; continue; diff --git a/src/chpasswd.c b/src/chpasswd.c index dfe507409..0ac7d38b3 100644 --- a/src/chpasswd.c +++ b/src/chpasswd.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include @@ -453,7 +454,7 @@ int main (int argc, char **argv) #endif /* USE_PAM */ int errors = 0; - int line = 0; + intmax_t line = 0; log_set_progname(Prog); log_set_logfd(stderr); @@ -514,7 +515,7 @@ int main (int argc, char **argv) } fprintf (stderr, - _("%s: line %d: line too long\n"), + _("%s: line %jd: line too long\n"), Prog, line); errors++; continue; @@ -534,7 +535,7 @@ int main (int argc, char **argv) cp = stpsep(name, ":"); if (cp == NULL) { fprintf (stderr, - _("%s: line %d: missing new password\n"), + _("%s: line %jd: missing new password\n"), Prog, line); errors++; continue; @@ -545,7 +546,7 @@ int main (int argc, char **argv) if (use_pam) { if (do_pam_passwd_non_interactive (Prog, name, newpwd) != 0) { fprintf (stderr, - _("%s: (line %d, user %s) password not changed\n"), + _("%s: (line %jd, user %s) password not changed\n"), Prog, line, name); errors++; } @@ -574,7 +575,7 @@ int main (int argc, char **argv) pw = pw_locate (name); if (NULL == pw) { fprintf (stderr, - _("%s: line %d: user '%s' does not exist\n"), Prog, + _("%s: line %jd: user '%s' does not exist\n"), Prog, line, name); errors++; continue; @@ -640,7 +641,7 @@ int main (int argc, char **argv) if (NULL != sp) { if (spw_update (&newsp) == 0) { fprintf (stderr, - _("%s: line %d: failed to prepare the new %s entry '%s'\n"), + _("%s: line %jd: failed to prepare the new %s entry '%s'\n"), Prog, line, spw_dbname (), newsp.sp_namp); errors++; continue; @@ -650,7 +651,7 @@ int main (int argc, char **argv) || !streq(pw->pw_passwd, SHADOW_PASSWD_STRING)) { if (pw_update (&newpw) == 0) { fprintf (stderr, - _("%s: line %d: failed to prepare the new %s entry '%s'\n"), + _("%s: line %jd: failed to prepare the new %s entry '%s'\n"), Prog, line, pw_dbname (), newpw.pw_name); errors++; continue; diff --git a/src/login_nopam.c b/src/login_nopam.c index de9513554..a9be91d3b 100644 --- a/src/login_nopam.c +++ b/src/login_nopam.c @@ -47,6 +47,7 @@ #include #endif #include +#include #include #include #include @@ -94,7 +95,7 @@ login_access(const char *user, const char *from) */ fp = fopen (TABLE, "r"); if (NULL != fp) { - int lineno = 0; /* for diagnostics */ + intmax_t lineno = 0; /* for diagnostics */ while ( !match && (fgets (line, sizeof (line), fp) == line)) { @@ -103,7 +104,7 @@ login_access(const char *user, const char *from) lineno++; if (stpsep(line, "\n") == NULL) { SYSLOG ((LOG_ERR, - "%s: line %d: missing newline or line too long", + "%s: line %jd: missing newline or line too long", TABLE, lineno)); continue; } @@ -120,13 +121,13 @@ login_access(const char *user, const char *from) froms = strsep(&p, ":"); if (froms == NULL || p != NULL) { SYSLOG ((LOG_ERR, - "%s: line %d: bad field count", + "%s: line %jd: bad field count", TABLE, lineno)); continue; } if (perm[0] != '+' && perm[0] != '-') { SYSLOG ((LOG_ERR, - "%s: line %d: bad first field", + "%s: line %jd: bad first field", TABLE, lineno)); continue; } diff --git a/src/newusers.c b/src/newusers.c index 5e78dd976..2d99ccfe0 100644 --- a/src/newusers.c +++ b/src/newusers.c @@ -28,6 +28,7 @@ #include #include #include +#include #include #include "alloc/reallocf.h" @@ -1062,11 +1063,11 @@ int main (int argc, char **argv) char *cp; const struct passwd *pw; struct passwd newpw; - int line = 0; + intmax_t line = 0; uid_t uid; gid_t gid; #ifdef USE_PAM - int *lines = NULL; + intmax_t *lines = NULL; char **usernames = NULL; char **passwords = NULL; unsigned int nusers = 0; @@ -1112,7 +1113,7 @@ int main (int argc, char **argv) while (fgets (buf, sizeof buf, stdin) != NULL) { line++; if (stpsep(buf, "\n") == NULL && feof(stdin) == 0) { - fprintf (stderr, _("%s: line %d: line too long\n"), + fprintf (stderr, _("%s: line %jd: line too long\n"), Prog, line); fail_exit (EXIT_FAILURE); } @@ -1128,7 +1129,7 @@ int main (int argc, char **argv) break; } if (nfields != 6) { - fprintf (stderr, _("%s: line %d: invalid line\n"), + fprintf (stderr, _("%s: line %jd: invalid line\n"), Prog, line); fail_exit (EXIT_FAILURE); } @@ -1147,7 +1148,7 @@ int main (int argc, char **argv) if (NULL == pw && get_user_id(fields[2], &uid) != 0) { fprintf (stderr, - _("%s: line %d: can't create user\n"), + _("%s: line %jd: can't create user\n"), Prog, line); fail_exit (EXIT_FAILURE); } @@ -1167,7 +1168,7 @@ int main (int argc, char **argv) if ( (NULL == pw) && (add_group (fields[0], fields[3], &gid, uid) != 0)) { fprintf (stderr, - _("%s: line %d: can't create group\n"), + _("%s: line %jd: can't create group\n"), Prog, line); fail_exit (EXIT_FAILURE); } @@ -1182,7 +1183,7 @@ int main (int argc, char **argv) if ( (NULL == pw) && (add_user (fields[0], uid, gid) != 0)) { fprintf (stderr, - _("%s: line %d: can't create user\n"), + _("%s: line %jd: can't create user\n"), Prog, line); fail_exit (EXIT_FAILURE); } @@ -1194,7 +1195,7 @@ int main (int argc, char **argv) pw = pw_locate (fields[0]); if (NULL == pw) { fprintf (stderr, - _("%s: line %d: user '%s' does not exist in %s\n"), + _("%s: line %jd: user '%s' does not exist in %s\n"), Prog, line, fields[0], pw_dbname ()); fail_exit (EXIT_FAILURE); } @@ -1203,12 +1204,12 @@ int main (int argc, char **argv) #ifdef USE_PAM /* keep the list of user/password for later update by PAM */ nusers++; - lines = REALLOCF(lines, nusers, int); + lines = REALLOCF(lines, nusers, intmax_t); usernames = REALLOCF(usernames, nusers, char *); passwords = REALLOCF(passwords, nusers, char *); if (lines == NULL || usernames == NULL || passwords == NULL) { fprintf (stderr, - _("%s: line %d: %s\n"), + _("%s: line %jd: %s\n"), Prog, line, strerror(errno)); fail_exit (EXIT_FAILURE); } @@ -1218,7 +1219,7 @@ int main (int argc, char **argv) #endif /* USE_PAM */ if (add_passwd (&newpw, fields[1]) != 0) { fprintf (stderr, - _("%s: line %d: can't update password\n"), + _("%s: line %jd: can't update password\n"), Prog, line); fail_exit (EXIT_FAILURE); } @@ -1241,13 +1242,13 @@ int main (int argc, char **argv) 0777 & ~getdef_num ("UMASK", GETDEF_DEFAULT_UMASK)); if (newpw.pw_dir[0] != '/') { fprintf(stderr, - _("%s: line %d: homedir must be an absolute path\n"), + _("%s: line %jd: homedir must be an absolute path\n"), Prog, line); fail_exit (EXIT_FAILURE); } if (mkdir (newpw.pw_dir, mode) != 0) { fprintf (stderr, - _("%s: line %d: mkdir %s failed: %s\n"), + _("%s: line %jd: mkdir %s failed: %s\n"), Prog, line, newpw.pw_dir, strerror (errno)); if (errno != EEXIST) { @@ -1257,7 +1258,7 @@ int main (int argc, char **argv) if (chown(newpw.pw_dir, newpw.pw_uid, newpw.pw_gid) != 0) { fprintf (stderr, - _("%s: line %d: chown %s failed: %s\n"), + _("%s: line %jd: chown %s failed: %s\n"), Prog, line, newpw.pw_dir, strerror (errno)); fail_exit (EXIT_FAILURE); @@ -1269,7 +1270,7 @@ int main (int argc, char **argv) */ if (pw_update (&newpw) == 0) { fprintf (stderr, - _("%s: line %d: can't update entry\n"), + _("%s: line %jd: can't update entry\n"), Prog, line); fail_exit (EXIT_FAILURE); } @@ -1338,7 +1339,7 @@ int main (int argc, char **argv) for (i = 0; i < nusers; i++) { if (do_pam_passwd_non_interactive ("newusers", usernames[i], passwords[i]) != 0) { fprintf (stderr, - _("%s: (line %d, user %s) password not changed\n"), + _("%s: (line %jd, user %s) password not changed\n"), Prog, lines[i], usernames[i]); exit (EXIT_FAILURE); } diff --git a/src/suauth.c b/src/suauth.c index 8d961fd5b..aab7e9867 100644 --- a/src/suauth.c +++ b/src/suauth.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -42,7 +43,7 @@ static int applies (const char *, char *); static int isgrp (const char *, const char *); -static int lines = 0; +static intmax_t lines = 0; int @@ -78,7 +79,7 @@ check_su_auth(const char *actual_id, const char *wanted_id, bool su_to_root) if (stpsep(temp, "\n") == NULL) { SYSLOG ((LOG_ERR, - "%s, line %d: line too long or missing newline", + "%s, line %jd: line too long or missing newline", SUAUTHFILE, lines)); continue; } @@ -94,7 +95,7 @@ check_su_auth(const char *actual_id, const char *wanted_id, bool su_to_root) action = strsep(&p, ":"); if (action == NULL || p != NULL) { SYSLOG ((LOG_ERR, - "%s, line %d. Bad number of fields.\n", + "%s, line %jd. Bad number of fields.\n", SUAUTHFILE, lines)); continue; } @@ -128,7 +129,7 @@ check_su_auth(const char *actual_id, const char *wanted_id, bool su_to_root) return OWNPWORD; } else { SYSLOG ((LOG_ERR, - "%s, line %d: unrecognized action!\n", + "%s, line %jd: unrecognized action!\n", SUAUTHFILE, lines)); } } @@ -148,7 +149,7 @@ applies(const char *single, char *list) if (streq(tok, "ALL")) { if (state != 0) { SYSLOG ((LOG_ERR, - "%s, line %d: ALL in bad place\n", + "%s, line %jd: ALL in bad place\n", SUAUTHFILE, lines)); return 0; } @@ -156,7 +157,7 @@ applies(const char *single, char *list) } else if (streq(tok, "EXCEPT")) { if (state != 1) { SYSLOG ((LOG_ERR, - "%s, line %d: EXCEPT in bas place\n", + "%s, line %jd: EXCEPT in bas place\n", SUAUTHFILE, lines)); return 0; } @@ -164,7 +165,7 @@ applies(const char *single, char *list) } else if (streq(tok, "GROUP")) { if ((state != 0) && (state != 2)) { SYSLOG ((LOG_ERR, - "%s, line %d: GROUP in bad place\n", + "%s, line %jd: GROUP in bad place\n", SUAUTHFILE, lines)); return 0; } @@ -177,7 +178,7 @@ applies(const char *single, char *list) break; case 1: /* An all */ SYSLOG ((LOG_ERR, - "%s, line %d: expect another token after ALL\n", + "%s, line %jd: expect another token after ALL\n", SUAUTHFILE, lines)); return 0; case 2: /* All except */ -- 2.47.2