8 /* This implementation support Openwall-style TCB passwords in place of
9 * traditional shadow, if the appropriate directories and files exist.
10 * Thus, it is careful to avoid following symlinks or blocking on fifos
11 * which a malicious user might create in place of his or her TCB shadow
12 * file. It also avoids any allocation to prevent memory-exhaustion
13 * attacks via huge TCB shadow files. */
15 static long xatol(const char *s)
17 return isdigit(*s) ? atol(s) : -1;
20 static void cleanup(void *p)
25 int getspnam_r(const char *name, struct spwd *sp, char *buf, size_t size, struct spwd **res)
27 char path[20+NAME_MAX];
31 size_t k, l = strlen(name);
38 /* Disallow potentially-malicious user names */
39 if (*name=='.' || strchr(name, '/') || !l)
42 /* Buffer size must at least be able to hold name, plus some.. */
43 if (size < l+100) return ERANGE;
45 /* Protect against truncation */
46 if (snprintf(path, sizeof path, "/etc/tcb/%s/shadow", name) >= sizeof path)
49 fd = open(path, O_RDONLY|O_NOFOLLOW|O_NONBLOCK);
51 struct stat st = { 0 };
53 if (fstat(fd, &st) || !S_ISREG(st.st_mode) || !(f = fdopen(fd, "rb"))) {
54 pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cs);
56 pthread_setcancelstate(cs, 0);
60 f = fopen("/etc/shadow", "rb");
64 pthread_cleanup_push(cleanup, f);
65 while (fgets(buf, size, f) && (k=strlen(buf))>0) {
66 if (skip || strncmp(name, buf, l)) {
67 skip = buf[k-1] != '\n';
70 if (buf[k-1] != '\n') {
78 if (!(s = strchr(s, ':'))) continue;
80 *s++ = 0; sp->sp_pwdp = s;
81 if (!(s = strchr(s, ':'))) continue;
83 *s++ = 0; sp->sp_lstchg = xatol(s);
84 if (!(s = strchr(s, ':'))) continue;
86 *s++ = 0; sp->sp_min = xatol(s);
87 if (!(s = strchr(s, ':'))) continue;
89 *s++ = 0; sp->sp_max = xatol(s);
90 if (!(s = strchr(s, ':'))) continue;
92 *s++ = 0; sp->sp_warn = xatol(s);
93 if (!(s = strchr(s, ':'))) continue;
95 *s++ = 0; sp->sp_inact = xatol(s);
96 if (!(s = strchr(s, ':'))) continue;
98 *s++ = 0; sp->sp_expire = xatol(s);
99 if (!(s = strchr(s, ':'))) continue;
101 *s++ = 0; sp->sp_flag = xatol(s);
105 pthread_cleanup_pop(1);