diff options
author | Tobias Stoeckmann <tobias@stoeckmann.org> | 2023-12-05 20:22:24 +0100 |
---|---|---|
committer | Dmitry V. Levin <ldv@strace.io> | 2023-12-05 19:26:24 +0000 |
commit | dd87776d3683b1fe66b55c750af9e7ab2c5461c2 (patch) | |
tree | 554909a942f77e7a78ea02065d567d44dd4749fe | |
parent | 9082c6c2754b72b2146c6e6e3011b4920a491b3f (diff) | |
download | pam-dd87776d3683b1fe66b55c750af9e7ab2c5461c2.tar.gz pam-dd87776d3683b1fe66b55c750af9e7ab2c5461c2.tar.bz2 pam-dd87776d3683b1fe66b55c750af9e7ab2c5461c2.zip |
pam_faildelay: validate parameter ranges
The function sscanf does not verify that a value parsed with %ld is
actually within the valid range of a long, allowing silent truncation.
When parsing FAIL_DELAY from login.defs, a mask of 0777 is applied
before performing range checks for strtol return value. Since this
mask does not make sense here, it is removed.
With these changes, values smaller than 0 or larger than UINT_MAX,
which is the actual limit for pam_fail_delay, are discarded and
logged.
Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
-rw-r--r-- | modules/pam_faildelay/pam_faildelay.c | 36 |
1 files changed, 25 insertions, 11 deletions
diff --git a/modules/pam_faildelay/pam_faildelay.c b/modules/pam_faildelay/pam_faildelay.c index 02c5fafd..96176eec 100644 --- a/modules/pam_faildelay/pam_faildelay.c +++ b/modules/pam_faildelay/pam_faildelay.c @@ -60,8 +60,8 @@ */ #include "config.h" +#include "pam_inline.h" -#include <errno.h> #include <ctype.h> #include <stdio.h> #include <limits.h> @@ -75,19 +75,37 @@ #include <security/pam_modutil.h> #define LOGIN_DEFS "/etc/login.defs" +#define S_TO_MICROS 1000000 /* --- authentication management functions (only) --- */ +static long parse_delay(const char *val) +{ + long delay; + char *endptr; + + delay = strtol (val, &endptr, 10); + if (delay == 0 && val == endptr) + return -1; + return delay; +} + int pam_sm_authenticate(pam_handle_t *pamh, int flags UNUSED, int argc, const char **argv) { int i, debug_flag = 0; - long int delay = -1; + long delay = -1; /* step through arguments */ for (i = 0; i < argc; i++) { - if (sscanf(argv[i], "delay=%ld", &delay) == 1) { - /* sscanf did already everything necessary */ + const char *val = pam_str_skip_prefix (argv[i], "delay="); + if (val != NULL) { + delay = parse_delay (val); + if (delay < 0 || delay > UINT_MAX) + { + pam_syslog (pamh, LOG_ERR, "%s (%s) not valid", argv[i], val); + return PAM_IGNORE; + } } else if (strcmp (argv[i], "debug") == 0) debug_flag = 1; else @@ -96,17 +114,13 @@ int pam_sm_authenticate(pam_handle_t *pamh, int flags UNUSED, if (delay == -1) { - char *endptr; char *val = pam_modutil_search_key (pamh, LOGIN_DEFS, "FAIL_DELAY"); - const char *val_orig = val; if (val == NULL) return PAM_IGNORE; - errno = 0; - delay = strtol (val, &endptr, 10) & 0777; - if (((delay == 0) && (val_orig == endptr)) || - ((delay == LONG_MIN || delay == LONG_MAX) && (errno == ERANGE))) + delay = parse_delay (val); + if (delay < 0 || delay > UINT_MAX / S_TO_MICROS) { pam_syslog (pamh, LOG_ERR, "FAIL_DELAY=%s in %s not valid", val, LOGIN_DEFS); @@ -116,7 +130,7 @@ int pam_sm_authenticate(pam_handle_t *pamh, int flags UNUSED, free (val); /* delay is in seconds, convert to microseconds. */ - delay *= 1000000; + delay *= S_TO_MICROS; } if (debug_flag) |