150276Speter#include <fcntl.h> 2174993Srafan#include <unistd.h> 350276Speter#include <sys/stat.h> 450276Speter#include <ctype.h> 550276Speter#include <pthread.h> 650276Speter#include "pwf.h" 750276Speter 850276Speter/* This implementation support Openwall-style TCB passwords in place of 950276Speter * traditional shadow, if the appropriate directories and files exist. 1050276Speter * Thus, it is careful to avoid following symlinks or blocking on fifos 1150276Speter * which a malicious user might create in place of his or her TCB shadow 1250276Speter * file. It also avoids any allocation to prevent memory-exhaustion 1350276Speter * attacks via huge TCB shadow files. */ 1450276Speter 1550276Speterstatic long xatol(char **s) 1650276Speter{ 1750276Speter long x; 1850276Speter if (**s == ':' || **s == '\n') return -1; 1950276Speter for (x=0; **s-'0'<10U; ++*s) x=10*x+(**s-'0'); 2050276Speter return x; 2150276Speter} 2250276Speter 2350276Speterint __parsespent(char *s, struct spwd *sp) 2450276Speter{ 2550276Speter sp->sp_namp = s; 2650276Speter if (!(s = strchr(s, ':'))) return -1; 2750276Speter *s = 0; 2850276Speter 2950276Speter sp->sp_pwdp = ++s; 30174993Srafan if (!(s = strchr(s, ':'))) return -1; 3150276Speter *s = 0; 3250276Speter 3350276Speter s++; sp->sp_lstchg = xatol(&s); 3450276Speter if (*s != ':') return -1; 35166124Srafan 3650276Speter s++; sp->sp_min = xatol(&s); 3750276Speter if (*s != ':') return -1; 3850276Speter 3950276Speter s++; sp->sp_max = xatol(&s); 4050276Speter if (*s != ':') return -1; 4150276Speter 4250276Speter s++; sp->sp_warn = xatol(&s); 43174993Srafan if (*s != ':') return -1; 4450276Speter 4550276Speter s++; sp->sp_inact = xatol(&s); 4650276Speter if (*s != ':') return -1; 4750276Speter 4850276Speter s++; sp->sp_expire = xatol(&s); 4976726Speter if (*s != ':') return -1; 5062449Speter 5150276Speter s++; sp->sp_flag = xatol(&s); 5262449Speter if (*s != '\n') return -1; 53166124Srafan return 0; 5450276Speter} 55166124Srafan 5650276Speterstatic void cleanup(void *p) 57174993Srafan{ 58174993Srafan fclose(p); 59174993Srafan} 60174993Srafan 61166124Srafanint getspnam_r(const char *name, struct spwd *sp, char *buf, size_t size, struct spwd **res) 6250276Speter{ 6362449Speter char path[20+NAME_MAX]; 64174993Srafan FILE *f = 0; 65174993Srafan int rv = 0; 6650276Speter int fd; 67174993Srafan size_t k, l = strlen(name); 68174993Srafan int skip = 0; 6962449Speter int cs; 7062449Speter 7162449Speter *res = 0; 7250276Speter 7362449Speter /* Disallow potentially-malicious user names */ 7462449Speter if (*name=='.' || strchr(name, '/') || !l) 7597049Speter return EINVAL; 7697049Speter 7762449Speter /* Buffer size must at least be able to hold name, plus some.. */ 7862449Speter if (size < l+100) return ERANGE; 7962449Speter 8062449Speter /* Protect against truncation */ 8150276Speter if (snprintf(path, sizeof path, "/etc/tcb/%s/shadow", name) >= sizeof path) 8262449Speter return EINVAL; 83174993Srafan 84174993Srafan fd = open(path, O_RDONLY|O_NOFOLLOW|O_NONBLOCK|O_CLOEXEC); 8562449Speter if (fd >= 0) { 8650276Speter struct stat st = { 0 }; 8762449Speter errno = EINVAL; 88174993Srafan if (fstat(fd, &st) || !S_ISREG(st.st_mode) || !(f = fdopen(fd, "rb"))) { 89174993Srafan pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cs); 90174993Srafan close(fd); 91174993Srafan pthread_setcancelstate(cs, 0); 92174993Srafan return errno; 93174993Srafan } 9450276Speter } else { 95166124Srafan f = fopen("/etc/shadow", "rbe"); 96174993Srafan if (!f) return errno; 97166124Srafan } 98174993Srafan 99174993Srafan pthread_cleanup_push(cleanup, f); 100174993Srafan while (fgets(buf, size, f) && (k=strlen(buf))>0) { 101166124Srafan if (skip || strncmp(name, buf, l) || buf[l]!=':') { 102166124Srafan skip = buf[k-1] != '\n'; 103166124Srafan continue; 104166124Srafan } 10550276Speter if (buf[k-1] != '\n') { 10662449Speter rv = ERANGE; 10750276Speter break; 108166124Srafan } 109174993Srafan 110174993Srafan if (__parsespent(buf, sp) < 0) continue; 111174993Srafan *res = sp; 112174993Srafan break; 113174993Srafan } 114174993Srafan pthread_cleanup_pop(1); 11550276Speter return rv; 11662449Speter} 11750276Speter