X-Git-Url: http://nsz.repo.hu/git/?a=blobdiff_plain;f=src%2Fpasswd%2Fgetspnam_r.c;h=541e85314d56cc36d7b752ec9693563390ca07b2;hb=0ea78a6421322cab24d448670006ee2f99af3ac9;hp=9e29aa9cf78d782d4c17a93d7e2f9042fba44ab9;hpb=18bca575107d80ca81241d1429ded62918c5bd2e;p=musl diff --git a/src/passwd/getspnam_r.c b/src/passwd/getspnam_r.c index 9e29aa9c..541e8531 100644 --- a/src/passwd/getspnam_r.c +++ b/src/passwd/getspnam_r.c @@ -2,6 +2,7 @@ #include #include #include +#include #include "pwf.h" /* This implementation support Openwall-style TCB passwords in place of @@ -11,9 +12,50 @@ * file. It also avoids any allocation to prevent memory-exhaustion * attacks via huge TCB shadow files. */ -static long xatol(const char *s) +static long xatol(char **s) { - return isdigit(*s) ? atol(s) : -1; + long x; + if (**s == ':' || **s == '\n') return -1; + for (x=0; **s-'0'<10U; ++*s) x=10*x+(**s-'0'); + return x; +} + +int __parsespent(char *s, struct spwd *sp) +{ + sp->sp_namp = s; + if (!(s = strchr(s, ':'))) return -1; + *s = 0; + + sp->sp_pwdp = ++s; + if (!(s = strchr(s, ':'))) return -1; + *s = 0; + + s++; sp->sp_lstchg = xatol(&s); + if (*s != ':') return -1; + + s++; sp->sp_min = xatol(&s); + if (*s != ':') return -1; + + s++; sp->sp_max = xatol(&s); + if (*s != ':') return -1; + + s++; sp->sp_warn = xatol(&s); + if (*s != ':') return -1; + + s++; sp->sp_inact = xatol(&s); + if (*s != ':') return -1; + + s++; sp->sp_expire = xatol(&s); + if (*s != ':') return -1; + + s++; sp->sp_flag = xatol(&s); + if (*s != '\n') return -1; + return 0; +} + +static void cleanup(void *p) +{ + fclose(p); } int getspnam_r(const char *name, struct spwd *sp, char *buf, size_t size, struct spwd **res) @@ -23,37 +65,48 @@ int getspnam_r(const char *name, struct spwd *sp, char *buf, size_t size, struct int rv = 0; int fd; size_t k, l = strlen(name); - char *s; int skip = 0; + int cs; + int orig_errno = errno; *res = 0; /* Disallow potentially-malicious user names */ if (*name=='.' || strchr(name, '/') || !l) - return EINVAL; + return errno = EINVAL; /* Buffer size must at least be able to hold name, plus some.. */ - if (size < l+100) return ERANGE; + if (size < l+100) + return errno = ERANGE; /* Protect against truncation */ if (snprintf(path, sizeof path, "/etc/tcb/%s/shadow", name) >= sizeof path) - return EINVAL; + return errno = EINVAL; - fd = open(path, O_RDONLY|O_NOFOLLOW|O_NONBLOCK); + fd = open(path, O_RDONLY|O_NOFOLLOW|O_NONBLOCK|O_CLOEXEC); if (fd >= 0) { struct stat st = { 0 }; errno = EINVAL; if (fstat(fd, &st) || !S_ISREG(st.st_mode) || !(f = fdopen(fd, "rb"))) { + pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cs); close(fd); + pthread_setcancelstate(cs, 0); return errno; } } else { - f = fopen("/etc/shadow", "rb"); - if (!f) return errno; + if (errno != ENOENT && errno != ENOTDIR) + return errno; + f = fopen("/etc/shadow", "rbe"); + if (!f) { + if (errno != ENOENT && errno != ENOTDIR) + return errno; + return 0; + } } + pthread_cleanup_push(cleanup, f); while (fgets(buf, size, f) && (k=strlen(buf))>0) { - if (skip || strncmp(name, buf, l)) { + if (skip || strncmp(name, buf, l) || buf[l]!=':') { skip = buf[k-1] != '\n'; continue; } @@ -61,37 +114,12 @@ int getspnam_r(const char *name, struct spwd *sp, char *buf, size_t size, struct rv = ERANGE; break; } - buf[k-1] = 0; - - s = buf; - sp->sp_namp = s; - if (!(s = strchr(s, ':'))) continue; - - *s++ = 0; sp->sp_pwdp = s; - if (!(s = strchr(s, ':'))) continue; - - *s++ = 0; sp->sp_lstchg = xatol(s); - if (!(s = strchr(s, ':'))) continue; - - *s++ = 0; sp->sp_min = xatol(s); - if (!(s = strchr(s, ':'))) continue; - - *s++ = 0; sp->sp_max = xatol(s); - if (!(s = strchr(s, ':'))) continue; - - *s++ = 0; sp->sp_warn = xatol(s); - if (!(s = strchr(s, ':'))) continue; - - *s++ = 0; sp->sp_inact = xatol(s); - if (!(s = strchr(s, ':'))) continue; - - *s++ = 0; sp->sp_expire = xatol(s); - if (!(s = strchr(s, ':'))) continue; - *s++ = 0; sp->sp_flag = xatol(s); + if (__parsespent(buf, sp) < 0) continue; *res = sp; break; } - fclose(f); + pthread_cleanup_pop(1); + errno = rv ? rv : orig_errno; return rv; }