OLD | NEW |
1 #include <fcntl.h> | 1 #include <fcntl.h> |
2 #include <unistd.h> | 2 #include <unistd.h> |
3 #include <sys/stat.h> | 3 #include <sys/stat.h> |
4 #include <ctype.h> | 4 #include <ctype.h> |
5 #include <pthread.h> | 5 #include <pthread.h> |
6 #include "pwf.h" | 6 #include "pwf.h" |
7 | 7 |
8 /* This implementation support Openwall-style TCB passwords in place of | 8 /* This implementation support Openwall-style TCB passwords in place of |
9 * traditional shadow, if the appropriate directories and files exist. | 9 * traditional shadow, if the appropriate directories and files exist. |
10 * Thus, it is careful to avoid following symlinks or blocking on fifos | 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 | 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 | 12 * file. It also avoids any allocation to prevent memory-exhaustion |
13 * attacks via huge TCB shadow files. */ | 13 * attacks via huge TCB shadow files. */ |
14 | 14 |
15 static long xatol(char **s) | 15 static long xatol(char** s) { |
16 { | 16 long x; |
17 » long x; | 17 if (**s == ':' || **s == '\n') |
18 » if (**s == ':' || **s == '\n') return -1; | 18 return -1; |
19 » for (x=0; **s-'0'<10U; ++*s) x=10*x+(**s-'0'); | 19 for (x = 0; **s - '0' < 10U; ++*s) |
20 » return x; | 20 x = 10 * x + (**s - '0'); |
| 21 return x; |
21 } | 22 } |
22 | 23 |
23 int __parsespent(char *s, struct spwd *sp) | 24 int __parsespent(char* s, struct spwd* sp) { |
24 { | 25 sp->sp_namp = s; |
25 » sp->sp_namp = s; | 26 if (!(s = strchr(s, ':'))) |
26 » if (!(s = strchr(s, ':'))) return -1; | 27 return -1; |
27 » *s = 0; | 28 *s = 0; |
28 | 29 |
29 » sp->sp_pwdp = ++s; | 30 sp->sp_pwdp = ++s; |
30 » if (!(s = strchr(s, ':'))) return -1; | 31 if (!(s = strchr(s, ':'))) |
31 » *s = 0; | 32 return -1; |
| 33 *s = 0; |
32 | 34 |
33 » s++; sp->sp_lstchg = xatol(&s); | 35 s++; |
34 » if (*s != ':') return -1; | 36 sp->sp_lstchg = xatol(&s); |
| 37 if (*s != ':') |
| 38 return -1; |
35 | 39 |
36 » s++; sp->sp_min = xatol(&s); | 40 s++; |
37 » if (*s != ':') return -1; | 41 sp->sp_min = xatol(&s); |
| 42 if (*s != ':') |
| 43 return -1; |
38 | 44 |
39 » s++; sp->sp_max = xatol(&s); | 45 s++; |
40 » if (*s != ':') return -1; | 46 sp->sp_max = xatol(&s); |
| 47 if (*s != ':') |
| 48 return -1; |
41 | 49 |
42 » s++; sp->sp_warn = xatol(&s); | 50 s++; |
43 » if (*s != ':') return -1; | 51 sp->sp_warn = xatol(&s); |
| 52 if (*s != ':') |
| 53 return -1; |
44 | 54 |
45 » s++; sp->sp_inact = xatol(&s); | 55 s++; |
46 » if (*s != ':') return -1; | 56 sp->sp_inact = xatol(&s); |
| 57 if (*s != ':') |
| 58 return -1; |
47 | 59 |
48 » s++; sp->sp_expire = xatol(&s); | 60 s++; |
49 » if (*s != ':') return -1; | 61 sp->sp_expire = xatol(&s); |
| 62 if (*s != ':') |
| 63 return -1; |
50 | 64 |
51 » s++; sp->sp_flag = xatol(&s); | 65 s++; |
52 » if (*s != '\n') return -1; | 66 sp->sp_flag = xatol(&s); |
53 » return 0; | 67 if (*s != '\n') |
| 68 return -1; |
| 69 return 0; |
54 } | 70 } |
55 | 71 |
56 static void cleanup(void *p) | 72 static void cleanup(void* p) { |
57 { | 73 fclose(p); |
58 » fclose(p); | |
59 } | 74 } |
60 | 75 |
61 int getspnam_r(const char *name, struct spwd *sp, char *buf, size_t size, struct
spwd **res) | 76 int getspnam_r(const char* name, |
62 { | 77 struct spwd* sp, |
63 » char path[20+NAME_MAX]; | 78 char* buf, |
64 » FILE *f = 0; | 79 size_t size, |
65 » int rv = 0; | 80 struct spwd** res) { |
66 » int fd; | 81 char path[20 + NAME_MAX]; |
67 » size_t k, l = strlen(name); | 82 FILE* f = 0; |
68 » int skip = 0; | 83 int rv = 0; |
69 » int cs; | 84 int fd; |
| 85 size_t k, l = strlen(name); |
| 86 int skip = 0; |
| 87 int cs; |
70 | 88 |
71 » *res = 0; | 89 *res = 0; |
72 | 90 |
73 » /* Disallow potentially-malicious user names */ | 91 /* Disallow potentially-malicious user names */ |
74 » if (*name=='.' || strchr(name, '/') || !l) | 92 if (*name == '.' || strchr(name, '/') || !l) |
75 » » return EINVAL; | 93 return EINVAL; |
76 | 94 |
77 » /* Buffer size must at least be able to hold name, plus some.. */ | 95 /* Buffer size must at least be able to hold name, plus some.. */ |
78 » if (size < l+100) return ERANGE; | 96 if (size < l + 100) |
| 97 return ERANGE; |
79 | 98 |
80 » /* Protect against truncation */ | 99 /* Protect against truncation */ |
81 » if (snprintf(path, sizeof path, "/etc/tcb/%s/shadow", name) >= sizeof pa
th) | 100 if (snprintf(path, sizeof path, "/etc/tcb/%s/shadow", name) >= sizeof path) |
82 » » return EINVAL; | 101 return EINVAL; |
83 | 102 |
84 » fd = open(path, O_RDONLY|O_NOFOLLOW|O_NONBLOCK|O_CLOEXEC); | 103 fd = open(path, O_RDONLY | O_NOFOLLOW | O_NONBLOCK | O_CLOEXEC); |
85 » if (fd >= 0) { | 104 if (fd >= 0) { |
86 » » struct stat st = { 0 }; | 105 struct stat st = {0}; |
87 » » errno = EINVAL; | 106 errno = EINVAL; |
88 » » if (fstat(fd, &st) || !S_ISREG(st.st_mode) || !(f = fdopen(fd, "
rb"))) { | 107 if (fstat(fd, &st) || !S_ISREG(st.st_mode) || !(f = fdopen(fd, "rb"))) { |
89 » » » pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cs); | 108 pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cs); |
90 » » » close(fd); | 109 close(fd); |
91 » » » pthread_setcancelstate(cs, 0); | 110 pthread_setcancelstate(cs, 0); |
92 » » » return errno; | 111 return errno; |
93 » » } | 112 } |
94 » } else { | 113 } else { |
95 » » f = fopen("/etc/shadow", "rbe"); | 114 f = fopen("/etc/shadow", "rbe"); |
96 » » if (!f) return errno; | 115 if (!f) |
97 » } | 116 return errno; |
| 117 } |
98 | 118 |
99 » pthread_cleanup_push(cleanup, f); | 119 pthread_cleanup_push(cleanup, f); |
100 » while (fgets(buf, size, f) && (k=strlen(buf))>0) { | 120 while (fgets(buf, size, f) && (k = strlen(buf)) > 0) { |
101 » » if (skip || strncmp(name, buf, l) || buf[l]!=':') { | 121 if (skip || strncmp(name, buf, l) || buf[l] != ':') { |
102 » » » skip = buf[k-1] != '\n'; | 122 skip = buf[k - 1] != '\n'; |
103 » » » continue; | 123 continue; |
104 » » } | 124 } |
105 » » if (buf[k-1] != '\n') { | 125 if (buf[k - 1] != '\n') { |
106 » » » rv = ERANGE; | 126 rv = ERANGE; |
107 » » » break; | 127 break; |
108 » » } | 128 } |
109 | 129 |
110 » » if (__parsespent(buf, sp) < 0) continue; | 130 if (__parsespent(buf, sp) < 0) |
111 » » *res = sp; | 131 continue; |
112 » » break; | 132 *res = sp; |
113 » } | 133 break; |
114 » pthread_cleanup_pop(1); | 134 } |
115 » return rv; | 135 pthread_cleanup_pop(1); |
| 136 return rv; |
116 } | 137 } |
OLD | NEW |