int getspnam_r(const char *name, struct spwd *sp, char *buf, size_t size, struct spwd **res) { char path[20+NAME_MAX]; FILE *f = 0; int rv = 0; int fd; size_t k, l = strlen(name); int skip = 0; int cs; *res = 0; /* Disallow potentially-malicious user names */ if (*name=='.' || strchr(name, '/') || !l) return EINVAL; /* Buffer size must at least be able to hold name, plus some.. */ if (size < l+100) return ERANGE; /* Protect against truncation */ if (snprintf(path, sizeof path, "/etc/tcb/%s/shadow", name) >= sizeof path) return EINVAL; 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", "rbe"); if (!f) return errno; } pthread_cleanup_push(cleanup, f); while (fgets(buf, size, f) && (k=strlen(buf))>0) { if (skip || strncmp(name, buf, l)) { skip = buf[k-1] != '\n'; continue; } if (buf[k-1] != '\n') { rv = ERANGE; break; } if (__parsespent(buf, sp) < 0) continue; *res = sp; break; } pthread_cleanup_pop(1); return rv; }
struct spwd* fgetspent(FILE* f) { static char* line; static struct spwd sp; size_t size = 0; struct spwd* res = 0; int cs; pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cs); if (getline(&line, &size, f) >= 0 && __parsespent(line, &sp) >= 0) res = &sp; pthread_setcancelstate(cs, 0); return res; }