| @@ -1,663 +1,663 @@ | | | @@ -1,663 +1,663 @@ |
1 | /* $NetBSD: passwd.c,v 1.50 2010/08/18 08:32:02 christos Exp $ */ | | 1 | /* $NetBSD: passwd.c,v 1.51 2011/04/24 01:56:44 christos Exp $ */ |
2 | | | 2 | |
3 | /* | | 3 | /* |
4 | * Copyright (c) 1987, 1993, 1994, 1995 | | 4 | * Copyright (c) 1987, 1993, 1994, 1995 |
5 | * The Regents of the University of California. All rights reserved. | | 5 | * The Regents of the University of California. All rights reserved. |
6 | * | | 6 | * |
7 | * Redistribution and use in source and binary forms, with or without | | 7 | * Redistribution and use in source and binary forms, with or without |
8 | * modification, are permitted provided that the following conditions | | 8 | * modification, are permitted provided that the following conditions |
9 | * are met: | | 9 | * are met: |
10 | * 1. Redistributions of source code must retain the above copyright | | 10 | * 1. Redistributions of source code must retain the above copyright |
11 | * notice, this list of conditions and the following disclaimer. | | 11 | * notice, this list of conditions and the following disclaimer. |
12 | * 2. Redistributions in binary form must reproduce the above copyright | | 12 | * 2. Redistributions in binary form must reproduce the above copyright |
13 | * notice, this list of conditions and the following disclaimer in the | | 13 | * notice, this list of conditions and the following disclaimer in the |
14 | * documentation and/or other materials provided with the distribution. | | 14 | * documentation and/or other materials provided with the distribution. |
15 | * 3. Neither the name of the University nor the names of its contributors | | 15 | * 3. Neither the name of the University nor the names of its contributors |
16 | * may be used to endorse or promote products derived from this software | | 16 | * may be used to endorse or promote products derived from this software |
17 | * without specific prior written permission. | | 17 | * without specific prior written permission. |
18 | * | | 18 | * |
19 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | | 19 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND |
20 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | | 20 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
21 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | | 21 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
22 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | | 22 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE |
23 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | | 23 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
24 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | | 24 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
25 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | | 25 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
26 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | | 26 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
27 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | | 27 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
28 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | | 28 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
29 | * SUCH DAMAGE. | | 29 | * SUCH DAMAGE. |
30 | */ | | 30 | */ |
31 | | | 31 | |
32 | #include <sys/cdefs.h> | | 32 | #include <sys/cdefs.h> |
33 | #if defined(LIBC_SCCS) && !defined(lint) | | 33 | #if defined(LIBC_SCCS) && !defined(lint) |
34 | __RCSID("$NetBSD: passwd.c,v 1.50 2010/08/18 08:32:02 christos Exp $"); | | 34 | __RCSID("$NetBSD: passwd.c,v 1.51 2011/04/24 01:56:44 christos Exp $"); |
35 | #endif /* LIBC_SCCS and not lint */ | | 35 | #endif /* LIBC_SCCS and not lint */ |
36 | | | 36 | |
37 | #include <sys/types.h> | | 37 | #include <sys/types.h> |
38 | #include <sys/param.h> | | 38 | #include <sys/param.h> |
39 | #include <sys/stat.h> | | 39 | #include <sys/stat.h> |
40 | #include <sys/time.h> | | 40 | #include <sys/time.h> |
41 | #include <sys/resource.h> | | 41 | #include <sys/resource.h> |
42 | #include <sys/wait.h> | | 42 | #include <sys/wait.h> |
43 | | | 43 | |
44 | #include <assert.h> | | 44 | #include <assert.h> |
45 | #include <ctype.h> | | 45 | #include <ctype.h> |
46 | #include <err.h> | | 46 | #include <err.h> |
47 | #include <errno.h> | | 47 | #include <errno.h> |
48 | #include <fcntl.h> | | 48 | #include <fcntl.h> |
49 | #include <limits.h> | | 49 | #include <limits.h> |
50 | #include <paths.h> | | 50 | #include <paths.h> |
51 | #include <pwd.h> | | 51 | #include <pwd.h> |
52 | #include <grp.h> | | 52 | #include <grp.h> |
53 | #include <signal.h> | | 53 | #include <signal.h> |
54 | #include <stdio.h> | | 54 | #include <stdio.h> |
55 | #include <stdlib.h> | | 55 | #include <stdlib.h> |
56 | #include <string.h> | | 56 | #include <string.h> |
57 | #include <unistd.h> | | 57 | #include <unistd.h> |
58 | #include <util.h> | | 58 | #include <util.h> |
59 | | | 59 | |
60 | static const char *pw_filename(const char *filename); | | 60 | static const char *pw_filename(const char *filename); |
61 | static void pw_cont(int sig); | | 61 | static void pw_cont(int sig); |
62 | static const char * pw_equal(char *buf, struct passwd *old_pw); | | 62 | static const char * pw_equal(char *buf, struct passwd *old_pw); |
63 | static const char *pw_default(const char *option); | | 63 | static const char *pw_default(const char *option); |
64 | static int read_line(FILE *fp, char *line, int max); | | 64 | static int read_line(FILE *fp, char *line, int max); |
65 | static void trim_whitespace(char *line); | | 65 | static void trim_whitespace(char *line); |
66 | | | 66 | |
67 | static char pw_prefix[MAXPATHLEN]; | | 67 | static char pw_prefix[MAXPATHLEN]; |
68 | | | 68 | |
69 | const char * | | 69 | const char * |
70 | pw_getprefix(void) | | 70 | pw_getprefix(void) |
71 | { | | 71 | { |
72 | | | 72 | |
73 | return(pw_prefix); | | 73 | return(pw_prefix); |
74 | } | | 74 | } |
75 | | | 75 | |
76 | int | | 76 | int |
77 | pw_setprefix(const char *new_prefix) | | 77 | pw_setprefix(const char *new_prefix) |
78 | { | | 78 | { |
79 | size_t length; | | 79 | size_t length; |
80 | | | 80 | |
81 | _DIAGASSERT(new_prefix != NULL); | | 81 | _DIAGASSERT(new_prefix != NULL); |
82 | | | 82 | |
83 | length = strlen(new_prefix); | | 83 | length = strlen(new_prefix); |
84 | if (length < sizeof(pw_prefix)) { | | 84 | if (length < sizeof(pw_prefix)) { |
85 | (void)strcpy(pw_prefix, new_prefix); | | 85 | (void)strcpy(pw_prefix, new_prefix); |
86 | while (length > 0 && pw_prefix[length - 1] == '/') | | 86 | while (length > 0 && pw_prefix[length - 1] == '/') |
87 | pw_prefix[--length] = '\0'; | | 87 | pw_prefix[--length] = '\0'; |
88 | return(0); | | 88 | return(0); |
89 | } | | 89 | } |
90 | errno = ENAMETOOLONG; | | 90 | errno = ENAMETOOLONG; |
91 | return(-1); | | 91 | return(-1); |
92 | } | | 92 | } |
93 | | | 93 | |
94 | static const char * | | 94 | static const char * |
95 | pw_filename(const char *filename) | | 95 | pw_filename(const char *filename) |
96 | { | | 96 | { |
97 | static char newfilename[MAXPATHLEN]; | | 97 | static char newfilename[MAXPATHLEN]; |
98 | | | 98 | |
99 | _DIAGASSERT(filename != NULL); | | 99 | _DIAGASSERT(filename != NULL); |
100 | | | 100 | |
101 | if (pw_prefix[0] == '\0') | | 101 | if (pw_prefix[0] == '\0') |
102 | return filename; | | 102 | return filename; |
103 | | | 103 | |
104 | if (strlen(pw_prefix) + strlen(filename) < sizeof(newfilename)) | | 104 | if (strlen(pw_prefix) + strlen(filename) < sizeof(newfilename)) |
105 | return strcat(strcpy(newfilename, pw_prefix), filename); | | 105 | return strcat(strcpy(newfilename, pw_prefix), filename); |
106 | | | 106 | |
107 | errno = ENAMETOOLONG; | | 107 | errno = ENAMETOOLONG; |
108 | return(NULL); | | 108 | return(NULL); |
109 | } | | 109 | } |
110 | | | 110 | |
111 | int | | 111 | int |
112 | pw_lock(int retries) | | 112 | pw_lock(int retries) |
113 | { | | 113 | { |
114 | const char *filename; | | 114 | const char *filename; |
115 | int i, fd; | | 115 | int i, fd; |
116 | mode_t old_mode; | | 116 | mode_t old_mode; |
117 | int oerrno; | | 117 | int oerrno; |
118 | | | 118 | |
119 | /* Acquire the lock file. */ | | 119 | /* Acquire the lock file. */ |
120 | filename = pw_filename(_PATH_MASTERPASSWD_LOCK); | | 120 | filename = pw_filename(_PATH_MASTERPASSWD_LOCK); |
121 | if (filename == NULL) | | 121 | if (filename == NULL) |
122 | return(-1); | | 122 | return(-1); |
123 | old_mode = umask(0); | | 123 | old_mode = umask(0); |
124 | fd = open(filename, O_WRONLY|O_CREAT|O_EXCL, 0600); | | 124 | fd = open(filename, O_WRONLY|O_CREAT|O_EXCL, 0600); |
125 | for (i = 0; i < retries && fd < 0 && errno == EEXIST; i++) { | | 125 | for (i = 0; i < retries && fd < 0 && errno == EEXIST; i++) { |
126 | sleep(1); | | 126 | sleep(1); |
127 | fd = open(filename, O_WRONLY|O_CREAT|O_EXCL, | | 127 | fd = open(filename, O_WRONLY|O_CREAT|O_EXCL, |
128 | 0600); | | 128 | 0600); |
129 | } | | 129 | } |
130 | oerrno = errno; | | 130 | oerrno = errno; |
131 | (void)umask(old_mode); | | 131 | (void)umask(old_mode); |
132 | errno = oerrno; | | 132 | errno = oerrno; |
133 | return(fd); | | 133 | return(fd); |
134 | } | | 134 | } |
135 | | | 135 | |
136 | int | | 136 | int |
137 | pw_mkdb(username, secureonly) | | 137 | pw_mkdb(username, secureonly) |
138 | const char *username; | | 138 | const char *username; |
139 | int secureonly; | | 139 | int secureonly; |
140 | { | | 140 | { |
141 | const char *args[9]; | | 141 | const char *args[9]; |
142 | int pstat, i; | | 142 | int pstat, i; |
143 | pid_t pid; | | 143 | pid_t pid; |
144 | | | 144 | |
145 | pid = vfork(); | | 145 | pid = vfork(); |
146 | if (pid == -1) | | 146 | if (pid == -1) |
147 | return -1; | | 147 | return -1; |
148 | | | 148 | |
149 | if (pid == 0) { | | 149 | if (pid == 0) { |
150 | args[0] = "pwd_mkdb"; | | 150 | args[0] = "pwd_mkdb"; |
151 | args[1] = "-d"; | | 151 | args[1] = "-d"; |
152 | args[2] = pw_prefix; | | 152 | args[2] = pw_prefix; |
153 | args[3] = "-pl"; | | 153 | args[3] = "-pl"; |
154 | i = 4; | | 154 | i = 4; |
155 | | | 155 | |
156 | if (secureonly) | | 156 | if (secureonly) |
157 | args[i++] = "-s"; | | 157 | args[i++] = "-s"; |
158 | if (username != NULL) { | | 158 | if (username != NULL) { |
159 | args[i++] = "-u"; | | 159 | args[i++] = "-u"; |
160 | args[i++] = username; | | 160 | args[i++] = username; |
161 | } | | 161 | } |
162 | | | 162 | |
163 | args[i++] = pw_filename(_PATH_MASTERPASSWD_LOCK); | | 163 | args[i++] = pw_filename(_PATH_MASTERPASSWD_LOCK); |
164 | args[i] = NULL; | | 164 | args[i] = NULL; |
165 | execv(_PATH_PWD_MKDB, (char * const *)__UNCONST(args)); | | 165 | execv(_PATH_PWD_MKDB, (char * const *)__UNCONST(args)); |
166 | _exit(1); | | 166 | _exit(1); |
167 | } | | 167 | } |
168 | pid = waitpid(pid, &pstat, 0); | | 168 | pid = waitpid(pid, &pstat, 0); |
169 | if (pid == -1) { | | 169 | if (pid == -1) { |
170 | warn("error waiting for pid %lu", (unsigned long)pid); | | 170 | warn("error waiting for pid %lu", (unsigned long)pid); |
171 | return -1; | | 171 | return -1; |
172 | } | | 172 | } |
173 | if (WIFEXITED(pstat)) { | | 173 | if (WIFEXITED(pstat)) { |
174 | if (WEXITSTATUS(pstat) != 0) { | | 174 | if (WEXITSTATUS(pstat) != 0) { |
175 | warnx("pwd_mkdb exited with static %d", | | 175 | warnx("pwd_mkdb exited with status %d", |
176 | WEXITSTATUS(pstat)); | | 176 | WEXITSTATUS(pstat)); |
177 | return -1; | | 177 | return -1; |
178 | } | | 178 | } |
179 | } else if (WIFSIGNALED(pstat)) { | | 179 | } else if (WIFSIGNALED(pstat)) { |
180 | warnx("pwd_mkdb exited with signal %d", WTERMSIG(pstat)); | | 180 | warnx("pwd_mkdb exited with signal %d", WTERMSIG(pstat)); |
181 | return -1; | | 181 | return -1; |
182 | } | | 182 | } |
183 | return 0; | | 183 | return 0; |
184 | } | | 184 | } |
185 | | | 185 | |
186 | int | | 186 | int |
187 | pw_abort(void) | | 187 | pw_abort(void) |
188 | { | | 188 | { |
189 | const char *filename; | | 189 | const char *filename; |
190 | | | 190 | |
191 | filename = pw_filename(_PATH_MASTERPASSWD_LOCK); | | 191 | filename = pw_filename(_PATH_MASTERPASSWD_LOCK); |
192 | return((filename == NULL) ? -1 : unlink(filename)); | | 192 | return((filename == NULL) ? -1 : unlink(filename)); |
193 | } | | 193 | } |
194 | | | 194 | |
195 | /* Everything below this point is intended for the convenience of programs | | 195 | /* Everything below this point is intended for the convenience of programs |
196 | * which allow a user to interactively edit the passwd file. Errors in the | | 196 | * which allow a user to interactively edit the passwd file. Errors in the |
197 | * routines below will cause the process to abort. */ | | 197 | * routines below will cause the process to abort. */ |
198 | | | 198 | |
199 | static pid_t editpid = -1; | | 199 | static pid_t editpid = -1; |
200 | | | 200 | |
201 | static void | | 201 | static void |
202 | pw_cont(int sig) | | 202 | pw_cont(int sig) |
203 | { | | 203 | { |
204 | | | 204 | |
205 | if (editpid != -1) | | 205 | if (editpid != -1) |
206 | kill(editpid, sig); | | 206 | kill(editpid, sig); |
207 | } | | 207 | } |
208 | | | 208 | |
209 | void | | 209 | void |
210 | pw_init(void) | | 210 | pw_init(void) |
211 | { | | 211 | { |
212 | struct rlimit rlim; | | 212 | struct rlimit rlim; |
213 | | | 213 | |
214 | /* Unlimited resource limits. */ | | 214 | /* Unlimited resource limits. */ |
215 | rlim.rlim_cur = rlim.rlim_max = RLIM_INFINITY; | | 215 | rlim.rlim_cur = rlim.rlim_max = RLIM_INFINITY; |
216 | (void)setrlimit(RLIMIT_CPU, &rlim); | | 216 | (void)setrlimit(RLIMIT_CPU, &rlim); |
217 | (void)setrlimit(RLIMIT_FSIZE, &rlim); | | 217 | (void)setrlimit(RLIMIT_FSIZE, &rlim); |
218 | (void)setrlimit(RLIMIT_STACK, &rlim); | | 218 | (void)setrlimit(RLIMIT_STACK, &rlim); |
219 | (void)setrlimit(RLIMIT_DATA, &rlim); | | 219 | (void)setrlimit(RLIMIT_DATA, &rlim); |
220 | (void)setrlimit(RLIMIT_RSS, &rlim); | | 220 | (void)setrlimit(RLIMIT_RSS, &rlim); |
221 | | | 221 | |
222 | /* Don't drop core (not really necessary, but GP's). */ | | 222 | /* Don't drop core (not really necessary, but GP's). */ |
223 | rlim.rlim_cur = rlim.rlim_max = 0; | | 223 | rlim.rlim_cur = rlim.rlim_max = 0; |
224 | (void)setrlimit(RLIMIT_CORE, &rlim); | | 224 | (void)setrlimit(RLIMIT_CORE, &rlim); |
225 | | | 225 | |
226 | /* Turn off signals. */ | | 226 | /* Turn off signals. */ |
227 | (void)signal(SIGALRM, SIG_IGN); | | 227 | (void)signal(SIGALRM, SIG_IGN); |
228 | (void)signal(SIGHUP, SIG_IGN); | | 228 | (void)signal(SIGHUP, SIG_IGN); |
229 | (void)signal(SIGINT, SIG_IGN); | | 229 | (void)signal(SIGINT, SIG_IGN); |
230 | (void)signal(SIGPIPE, SIG_IGN); | | 230 | (void)signal(SIGPIPE, SIG_IGN); |
231 | (void)signal(SIGQUIT, SIG_IGN); | | 231 | (void)signal(SIGQUIT, SIG_IGN); |
232 | (void)signal(SIGTERM, SIG_IGN); | | 232 | (void)signal(SIGTERM, SIG_IGN); |
233 | (void)signal(SIGCONT, pw_cont); | | 233 | (void)signal(SIGCONT, pw_cont); |
234 | } | | 234 | } |
235 | | | 235 | |
236 | void | | 236 | void |
237 | pw_edit(int notsetuid, const char *filename) | | 237 | pw_edit(int notsetuid, const char *filename) |
238 | { | | 238 | { |
239 | int pstat; | | 239 | int pstat; |
240 | char *p; | | 240 | char *p; |
241 | const char * volatile editor; | | 241 | const char * volatile editor; |
242 | const char *argp[] = { "sh", "-c", NULL, NULL }; | | 242 | const char *argp[] = { "sh", "-c", NULL, NULL }; |
243 | | | 243 | |
244 | if (filename == NULL) | | 244 | if (filename == NULL) |
245 | filename = _PATH_MASTERPASSWD_LOCK; | | 245 | filename = _PATH_MASTERPASSWD_LOCK; |
246 | | | 246 | |
247 | filename = pw_filename(filename); | | 247 | filename = pw_filename(filename); |
248 | if (filename == NULL) | | 248 | if (filename == NULL) |
249 | return; | | 249 | return; |
250 | | | 250 | |
251 | if ((editor = getenv("EDITOR")) == NULL) | | 251 | if ((editor = getenv("EDITOR")) == NULL) |
252 | editor = _PATH_VI; | | 252 | editor = _PATH_VI; |
253 | | | 253 | |
254 | p = malloc(strlen(editor) + 1 + strlen(filename) + 1); | | 254 | p = malloc(strlen(editor) + 1 + strlen(filename) + 1); |
255 | if (p == NULL) | | 255 | if (p == NULL) |
256 | return; | | 256 | return; |
257 | | | 257 | |
258 | sprintf(p, "%s %s", editor, filename); | | 258 | sprintf(p, "%s %s", editor, filename); |
259 | argp[2] = p; | | 259 | argp[2] = p; |
260 | | | 260 | |
261 | switch(editpid = vfork()) { | | 261 | switch(editpid = vfork()) { |
262 | case -1: | | 262 | case -1: |
263 | free(p); | | 263 | free(p); |
264 | return; | | 264 | return; |
265 | case 0: | | 265 | case 0: |
266 | if (notsetuid) { | | 266 | if (notsetuid) { |
267 | setgid(getgid()); | | 267 | setgid(getgid()); |
268 | setuid(getuid()); | | 268 | setuid(getuid()); |
269 | } | | 269 | } |
270 | execvp(_PATH_BSHELL, (char *const *)__UNCONST(argp)); | | 270 | execvp(_PATH_BSHELL, (char *const *)__UNCONST(argp)); |
271 | _exit(1); | | 271 | _exit(1); |
272 | } | | 272 | } |
273 | | | 273 | |
274 | free(p); | | 274 | free(p); |
275 | | | 275 | |
276 | for (;;) { | | 276 | for (;;) { |
277 | editpid = waitpid(editpid, (int *)&pstat, WUNTRACED); | | 277 | editpid = waitpid(editpid, (int *)&pstat, WUNTRACED); |
278 | if (editpid == -1) | | 278 | if (editpid == -1) |
279 | pw_error(editor, 1, 1); | | 279 | pw_error(editor, 1, 1); |
280 | else if (WIFSTOPPED(pstat)) | | 280 | else if (WIFSTOPPED(pstat)) |
281 | raise(WSTOPSIG(pstat)); | | 281 | raise(WSTOPSIG(pstat)); |
282 | else if (WIFEXITED(pstat) && WEXITSTATUS(pstat) == 0) | | 282 | else if (WIFEXITED(pstat) && WEXITSTATUS(pstat) == 0) |
283 | break; | | 283 | break; |
284 | else | | 284 | else |
285 | pw_error(editor, 1, 1); | | 285 | pw_error(editor, 1, 1); |
286 | } | | 286 | } |
287 | editpid = -1; | | 287 | editpid = -1; |
288 | } | | 288 | } |
289 | | | 289 | |
290 | void | | 290 | void |
291 | pw_prompt(void) | | 291 | pw_prompt(void) |
292 | { | | 292 | { |
293 | int c; | | 293 | int c; |
294 | | | 294 | |
295 | (void)printf("re-edit the password file? [y]: "); | | 295 | (void)printf("re-edit the password file? [y]: "); |
296 | (void)fflush(stdout); | | 296 | (void)fflush(stdout); |
297 | c = getchar(); | | 297 | c = getchar(); |
298 | if (c != EOF && c != '\n') | | 298 | if (c != EOF && c != '\n') |
299 | while (getchar() != '\n'); | | 299 | while (getchar() != '\n'); |
300 | if (c == 'n') | | 300 | if (c == 'n') |
301 | pw_error(NULL, 0, 0); | | 301 | pw_error(NULL, 0, 0); |
302 | } | | 302 | } |
303 | | | 303 | |
304 | /* for use in pw_copy(). Compare a pw entry to a pw struct. */ | | 304 | /* for use in pw_copy(). Compare a pw entry to a pw struct. */ |
305 | /* returns a character string labelling the miscompared field or 0 */ | | 305 | /* returns a character string labelling the miscompared field or 0 */ |
306 | static const char * | | 306 | static const char * |
307 | pw_equal(char *buf, struct passwd *pw) | | 307 | pw_equal(char *buf, struct passwd *pw) |
308 | { | | 308 | { |
309 | struct passwd buf_pw; | | 309 | struct passwd buf_pw; |
310 | size_t len; | | 310 | size_t len; |
311 | | | 311 | |
312 | _DIAGASSERT(buf != NULL); | | 312 | _DIAGASSERT(buf != NULL); |
313 | _DIAGASSERT(pw != NULL); | | 313 | _DIAGASSERT(pw != NULL); |
314 | | | 314 | |
315 | len = strlen (buf); | | 315 | len = strlen (buf); |
316 | if (buf[len-1] == '\n') | | 316 | if (buf[len-1] == '\n') |
317 | buf[len-1] = '\0'; | | 317 | buf[len-1] = '\0'; |
318 | if (!pw_scan(buf, &buf_pw, NULL)) | | 318 | if (!pw_scan(buf, &buf_pw, NULL)) |
319 | return "corrupt line"; | | 319 | return "corrupt line"; |
320 | if (strcmp(pw->pw_name, buf_pw.pw_name) != 0) | | 320 | if (strcmp(pw->pw_name, buf_pw.pw_name) != 0) |
321 | return "name"; | | 321 | return "name"; |
322 | if (pw->pw_uid != buf_pw.pw_uid) | | 322 | if (pw->pw_uid != buf_pw.pw_uid) |
323 | return "uid"; | | 323 | return "uid"; |
324 | if (pw->pw_gid != buf_pw.pw_gid) | | 324 | if (pw->pw_gid != buf_pw.pw_gid) |
325 | return "gid"; | | 325 | return "gid"; |
326 | if (strcmp( pw->pw_class, buf_pw.pw_class) != 0) | | 326 | if (strcmp( pw->pw_class, buf_pw.pw_class) != 0) |
327 | return "class"; | | 327 | return "class"; |
328 | if (pw->pw_change != buf_pw.pw_change) | | 328 | if (pw->pw_change != buf_pw.pw_change) |
329 | return "change"; | | 329 | return "change"; |
330 | if (pw->pw_expire != buf_pw.pw_expire) | | 330 | if (pw->pw_expire != buf_pw.pw_expire) |
331 | return "expire"; | | 331 | return "expire"; |
332 | if (strcmp( pw->pw_gecos, buf_pw.pw_gecos) != 0) | | 332 | if (strcmp( pw->pw_gecos, buf_pw.pw_gecos) != 0) |
333 | return "gecos"; | | 333 | return "gecos"; |
334 | if (strcmp( pw->pw_dir, buf_pw.pw_dir) != 0) | | 334 | if (strcmp( pw->pw_dir, buf_pw.pw_dir) != 0) |
335 | return "dir"; | | 335 | return "dir"; |
336 | if (strcmp( pw->pw_shell, buf_pw.pw_shell) != 0) | | 336 | if (strcmp( pw->pw_shell, buf_pw.pw_shell) != 0) |
337 | return "shell"; | | 337 | return "shell"; |
338 | return (char *)0; | | 338 | return (char *)0; |
339 | } | | 339 | } |
340 | | | 340 | |
341 | void | | 341 | void |
342 | pw_copy(int ffd, int tfd, struct passwd *pw, struct passwd *old_pw) | | 342 | pw_copy(int ffd, int tfd, struct passwd *pw, struct passwd *old_pw) |
343 | { | | 343 | { |
344 | char errbuf[200]; | | 344 | char errbuf[200]; |
345 | int rv; | | 345 | int rv; |
346 | | | 346 | |
347 | rv = pw_copyx(ffd, tfd, pw, old_pw, errbuf, sizeof(errbuf)); | | 347 | rv = pw_copyx(ffd, tfd, pw, old_pw, errbuf, sizeof(errbuf)); |
348 | if (rv == 0) { | | 348 | if (rv == 0) { |
349 | warnx("%s", errbuf); | | 349 | warnx("%s", errbuf); |
350 | pw_error(NULL, 0, 1); | | 350 | pw_error(NULL, 0, 1); |
351 | } | | 351 | } |
352 | } | | 352 | } |
353 | | | 353 | |
354 | static void | | 354 | static void |
355 | pw_print(FILE *to, const struct passwd *pw) | | 355 | pw_print(FILE *to, const struct passwd *pw) |
356 | { | | 356 | { |
357 | (void)fprintf(to, "%s:%s:%d:%d:%s:%lld:%lld:%s:%s:%s\n", | | 357 | (void)fprintf(to, "%s:%s:%d:%d:%s:%lld:%lld:%s:%s:%s\n", |
358 | pw->pw_name, pw->pw_passwd, pw->pw_uid, pw->pw_gid, | | 358 | pw->pw_name, pw->pw_passwd, pw->pw_uid, pw->pw_gid, |
359 | pw->pw_class, (long long)pw->pw_change, | | 359 | pw->pw_class, (long long)pw->pw_change, |
360 | (long long)pw->pw_expire, | | 360 | (long long)pw->pw_expire, |
361 | pw->pw_gecos, pw->pw_dir, pw->pw_shell); | | 361 | pw->pw_gecos, pw->pw_dir, pw->pw_shell); |
362 | } | | 362 | } |
363 | | | 363 | |
364 | int | | 364 | int |
365 | pw_copyx(int ffd, int tfd, struct passwd *pw, struct passwd *old_pw, | | 365 | pw_copyx(int ffd, int tfd, struct passwd *pw, struct passwd *old_pw, |
366 | char *errbuf, size_t errbufsz) | | 366 | char *errbuf, size_t errbufsz) |
367 | { | | 367 | { |
368 | const char *filename; | | 368 | const char *filename; |
369 | char mpwd[MAXPATHLEN], mpwdl[MAXPATHLEN], *p, buf[8192]; | | 369 | char mpwd[MAXPATHLEN], mpwdl[MAXPATHLEN], *p, buf[8192]; |
370 | FILE *from, *to; | | 370 | FILE *from, *to; |
371 | int done; | | 371 | int done; |
372 | | | 372 | |
373 | _DIAGASSERT(pw != NULL); | | 373 | _DIAGASSERT(pw != NULL); |
374 | _DIAGASSERT(errbuf != NULL); | | 374 | _DIAGASSERT(errbuf != NULL); |
375 | /* old_pw may be NULL */ | | 375 | /* old_pw may be NULL */ |
376 | | | 376 | |
377 | if ((filename = pw_filename(_PATH_MASTERPASSWD)) == NULL) { | | 377 | if ((filename = pw_filename(_PATH_MASTERPASSWD)) == NULL) { |
378 | snprintf(errbuf, errbufsz, "%s: %s", pw_prefix, | | 378 | snprintf(errbuf, errbufsz, "%s: %s", pw_prefix, |
379 | strerror(errno)); | | 379 | strerror(errno)); |
380 | return (0); | | 380 | return (0); |
381 | } | | 381 | } |
382 | (void)strcpy(mpwd, filename); | | 382 | (void)strcpy(mpwd, filename); |
383 | if ((filename = pw_filename(_PATH_MASTERPASSWD_LOCK)) == NULL) { | | 383 | if ((filename = pw_filename(_PATH_MASTERPASSWD_LOCK)) == NULL) { |
384 | snprintf(errbuf, errbufsz, "%s: %s", pw_prefix, | | 384 | snprintf(errbuf, errbufsz, "%s: %s", pw_prefix, |
385 | strerror(errno)); | | 385 | strerror(errno)); |
386 | return (0); | | 386 | return (0); |
387 | } | | 387 | } |
388 | (void)strcpy(mpwdl, filename); | | 388 | (void)strcpy(mpwdl, filename); |
389 | | | 389 | |
390 | if (!(from = fdopen(ffd, "r"))) { | | 390 | if (!(from = fdopen(ffd, "r"))) { |
391 | snprintf(errbuf, errbufsz, "%s: %s", mpwd, strerror(errno)); | | 391 | snprintf(errbuf, errbufsz, "%s: %s", mpwd, strerror(errno)); |
392 | return (0); | | 392 | return (0); |
393 | } | | 393 | } |
394 | if (!(to = fdopen(tfd, "w"))) { | | 394 | if (!(to = fdopen(tfd, "w"))) { |
395 | snprintf(errbuf, errbufsz, "%s: %s", mpwdl, strerror(errno)); | | 395 | snprintf(errbuf, errbufsz, "%s: %s", mpwdl, strerror(errno)); |
396 | (void)fclose(from); | | 396 | (void)fclose(from); |
397 | return (0); | | 397 | return (0); |
398 | } | | 398 | } |
399 | | | 399 | |
400 | for (done = 0; fgets(buf, (int)sizeof(buf), from);) { | | 400 | for (done = 0; fgets(buf, (int)sizeof(buf), from);) { |
401 | const char *neq; | | 401 | const char *neq; |
402 | if (!strchr(buf, '\n')) { | | 402 | if (!strchr(buf, '\n')) { |
403 | snprintf(errbuf, errbufsz, "%s: line too long", mpwd); | | 403 | snprintf(errbuf, errbufsz, "%s: line too long", mpwd); |
404 | (void)fclose(from); | | 404 | (void)fclose(from); |
405 | (void)fclose(to); | | 405 | (void)fclose(to); |
406 | return (0); | | 406 | return (0); |
407 | } | | 407 | } |
408 | if (done) { | | 408 | if (done) { |
409 | (void)fprintf(to, "%s", buf); | | 409 | (void)fprintf(to, "%s", buf); |
410 | if (ferror(to)) { | | 410 | if (ferror(to)) { |
411 | snprintf(errbuf, errbufsz, "%s", | | 411 | snprintf(errbuf, errbufsz, "%s", |
412 | strerror(errno)); | | 412 | strerror(errno)); |
413 | (void)fclose(from); | | 413 | (void)fclose(from); |
414 | (void)fclose(to); | | 414 | (void)fclose(to); |
415 | return (0); | | 415 | return (0); |
416 | } | | 416 | } |
417 | continue; | | 417 | continue; |
418 | } | | 418 | } |
419 | if (!(p = strchr(buf, ':'))) { | | 419 | if (!(p = strchr(buf, ':'))) { |
420 | snprintf(errbuf, errbufsz, "%s: corrupted entry", mpwd); | | 420 | snprintf(errbuf, errbufsz, "%s: corrupted entry", mpwd); |
421 | (void)fclose(from); | | 421 | (void)fclose(from); |
422 | (void)fclose(to); | | 422 | (void)fclose(to); |
423 | return (0); | | 423 | return (0); |
424 | } | | 424 | } |
425 | *p = '\0'; | | 425 | *p = '\0'; |
426 | if (strcmp(buf, pw->pw_name)) { | | 426 | if (strcmp(buf, pw->pw_name)) { |
427 | *p = ':'; | | 427 | *p = ':'; |
428 | (void)fprintf(to, "%s", buf); | | 428 | (void)fprintf(to, "%s", buf); |
429 | if (ferror(to)) { | | 429 | if (ferror(to)) { |
430 | snprintf(errbuf, errbufsz, "%s", | | 430 | snprintf(errbuf, errbufsz, "%s", |
431 | strerror(errno)); | | 431 | strerror(errno)); |
432 | (void)fclose(from); | | 432 | (void)fclose(from); |
433 | (void)fclose(to); | | 433 | (void)fclose(to); |
434 | return (0); | | 434 | return (0); |
435 | } | | 435 | } |
436 | continue; | | 436 | continue; |
437 | } | | 437 | } |
438 | *p = ':'; | | 438 | *p = ':'; |
439 | if (old_pw && (neq = pw_equal(buf, old_pw)) != NULL) { | | 439 | if (old_pw && (neq = pw_equal(buf, old_pw)) != NULL) { |
440 | if (strcmp(neq, "corrupt line") == 0) | | 440 | if (strcmp(neq, "corrupt line") == 0) |
441 | (void)snprintf(errbuf, errbufsz, | | 441 | (void)snprintf(errbuf, errbufsz, |
442 | "%s: entry %s corrupted", mpwd, | | 442 | "%s: entry %s corrupted", mpwd, |
443 | pw->pw_name); | | 443 | pw->pw_name); |
444 | else | | 444 | else |
445 | (void)snprintf(errbuf, errbufsz, | | 445 | (void)snprintf(errbuf, errbufsz, |
446 | "%s: entry %s inconsistent %s", | | 446 | "%s: entry %s inconsistent %s", |
447 | mpwd, pw->pw_name, neq); | | 447 | mpwd, pw->pw_name, neq); |
448 | (void)fclose(from); | | 448 | (void)fclose(from); |
449 | (void)fclose(to); | | 449 | (void)fclose(to); |
450 | return (0); | | 450 | return (0); |
451 | } | | 451 | } |
452 | pw_print(to, pw); | | 452 | pw_print(to, pw); |
453 | done = 1; | | 453 | done = 1; |
454 | if (ferror(to)) { | | 454 | if (ferror(to)) { |
455 | snprintf(errbuf, errbufsz, "%s", strerror(errno)); | | 455 | snprintf(errbuf, errbufsz, "%s", strerror(errno)); |
456 | (void)fclose(from); | | 456 | (void)fclose(from); |
457 | (void)fclose(to); | | 457 | (void)fclose(to); |
458 | return (0); | | 458 | return (0); |
459 | } | | 459 | } |
460 | } | | 460 | } |
461 | /* Only append a new entry if real uid is root! */ | | 461 | /* Only append a new entry if real uid is root! */ |
462 | if (!done) { | | 462 | if (!done) { |
463 | if (getuid() == 0) { | | 463 | if (getuid() == 0) { |
464 | pw_print(to, pw); | | 464 | pw_print(to, pw); |
465 | done = 1; | | 465 | done = 1; |
466 | } else { | | 466 | } else { |
467 | snprintf(errbuf, errbufsz, | | 467 | snprintf(errbuf, errbufsz, |
468 | "%s: changes not made, no such entry", mpwd); | | 468 | "%s: changes not made, no such entry", mpwd); |
469 | } | | 469 | } |
470 | } | | 470 | } |
471 | | | 471 | |
472 | if (ferror(to)) { | | 472 | if (ferror(to)) { |
473 | snprintf(errbuf, errbufsz, "%s", strerror(errno)); | | 473 | snprintf(errbuf, errbufsz, "%s", strerror(errno)); |
474 | (void)fclose(from); | | 474 | (void)fclose(from); |
475 | (void)fclose(to); | | 475 | (void)fclose(to); |
476 | return (0); | | 476 | return (0); |
477 | } | | 477 | } |
478 | (void)fclose(from); | | 478 | (void)fclose(from); |
479 | (void)fclose(to); | | 479 | (void)fclose(to); |
480 | | | 480 | |
481 | return (done); | | 481 | return (done); |
482 | } | | 482 | } |
483 | | | 483 | |
484 | void | | 484 | void |
485 | pw_error(const char *name, int error, int eval) | | 485 | pw_error(const char *name, int error, int eval) |
486 | { | | 486 | { |
487 | | | 487 | |
488 | if (error) { | | 488 | if (error) { |
489 | if (name) | | 489 | if (name) |
490 | warn("%s", name); | | 490 | warn("%s", name); |
491 | else | | 491 | else |
492 | warn(NULL); | | 492 | warn(NULL); |
493 | } | | 493 | } |
494 | | | 494 | |
495 | warnx("%s%s: unchanged", pw_prefix, _PATH_MASTERPASSWD); | | 495 | warnx("%s%s: unchanged", pw_prefix, _PATH_MASTERPASSWD); |
496 | pw_abort(); | | 496 | pw_abort(); |
497 | exit(eval); | | 497 | exit(eval); |
498 | } | | 498 | } |
499 | | | 499 | |
500 | /* Removes head and/or tail spaces. */ | | 500 | /* Removes head and/or tail spaces. */ |
501 | static void | | 501 | static void |
502 | trim_whitespace(char *line) | | 502 | trim_whitespace(char *line) |
503 | { | | 503 | { |
504 | char *p; | | 504 | char *p; |
505 | | | 505 | |
506 | _DIAGASSERT(line != NULL); | | 506 | _DIAGASSERT(line != NULL); |
507 | | | 507 | |
508 | /* Remove leading spaces */ | | 508 | /* Remove leading spaces */ |
509 | p = line; | | 509 | p = line; |
510 | while (isspace((unsigned char) *p)) | | 510 | while (isspace((unsigned char) *p)) |
511 | p++; | | 511 | p++; |
512 | memmove(line, p, strlen(p) + 1); | | 512 | memmove(line, p, strlen(p) + 1); |
513 | | | 513 | |
514 | /* Remove trailing spaces */ | | 514 | /* Remove trailing spaces */ |
515 | p = line + strlen(line) - 1; | | 515 | p = line + strlen(line) - 1; |
516 | while (isspace((unsigned char) *p)) | | 516 | while (isspace((unsigned char) *p)) |
517 | p--; | | 517 | p--; |
518 | *(p + 1) = '\0'; | | 518 | *(p + 1) = '\0'; |
519 | } | | 519 | } |
520 | | | 520 | |
521 | | | 521 | |
522 | /* Get one line, remove spaces from front and tail */ | | 522 | /* Get one line, remove spaces from front and tail */ |
523 | static int | | 523 | static int |
524 | read_line(FILE *fp, char *line, int max) | | 524 | read_line(FILE *fp, char *line, int max) |
525 | { | | 525 | { |
526 | char *p; | | 526 | char *p; |
527 | | | 527 | |
528 | _DIAGASSERT(fp != NULL); | | 528 | _DIAGASSERT(fp != NULL); |
529 | _DIAGASSERT(line != NULL); | | 529 | _DIAGASSERT(line != NULL); |
530 | | | 530 | |
531 | /* Read one line of config */ | | 531 | /* Read one line of config */ |
532 | if (fgets(line, max, fp) == NULL) | | 532 | if (fgets(line, max, fp) == NULL) |
533 | return (0); | | 533 | return (0); |
534 | | | 534 | |
535 | if ((p = strchr(line, '\n')) == NULL) { | | 535 | if ((p = strchr(line, '\n')) == NULL) { |
536 | warnx("line too long"); | | 536 | warnx("line too long"); |
537 | return (0); | | 537 | return (0); |
538 | } | | 538 | } |
539 | *p = '\0'; | | 539 | *p = '\0'; |
540 | | | 540 | |
541 | /* Remove comments */ | | 541 | /* Remove comments */ |
542 | if ((p = strchr(line, '#')) != NULL) | | 542 | if ((p = strchr(line, '#')) != NULL) |
543 | *p = '\0'; | | 543 | *p = '\0'; |
544 | | | 544 | |
545 | trim_whitespace(line); | | 545 | trim_whitespace(line); |
546 | return (1); | | 546 | return (1); |
547 | } | | 547 | } |
548 | | | 548 | |
549 | static const char * | | 549 | static const char * |
550 | pw_default(const char *option) | | 550 | pw_default(const char *option) |
551 | { | | 551 | { |
552 | static const char *options[][2] = { | | 552 | static const char *options[][2] = { |
553 | { "localcipher", "old" }, | | 553 | { "localcipher", "old" }, |
554 | { "ypcipher", "old" }, | | 554 | { "ypcipher", "old" }, |
555 | }; | | 555 | }; |
556 | size_t i; | | 556 | size_t i; |
557 | | | 557 | |
558 | _DIAGASSERT(option != NULL); | | 558 | _DIAGASSERT(option != NULL); |
559 | for (i = 0; i < sizeof(options) / sizeof(options[0]); i++) | | 559 | for (i = 0; i < sizeof(options) / sizeof(options[0]); i++) |
560 | if (strcmp(options[i][0], option) == 0) | | 560 | if (strcmp(options[i][0], option) == 0) |
561 | return (options[i][1]); | | 561 | return (options[i][1]); |
562 | | | 562 | |
563 | return (NULL); | | 563 | return (NULL); |
564 | } | | 564 | } |
565 | | | 565 | |
566 | /* | | 566 | /* |
567 | * Retrieve password information from the /etc/passwd.conf file, at the | | 567 | * Retrieve password information from the /etc/passwd.conf file, at the |
568 | * moment this is only for choosing the cipher to use. It could easily be | | 568 | * moment this is only for choosing the cipher to use. It could easily be |
569 | * used for other authentication methods as well. | | 569 | * used for other authentication methods as well. |
570 | */ | | 570 | */ |
571 | void | | 571 | void |
572 | pw_getconf(char *data, size_t max, const char *key, const char *option) | | 572 | pw_getconf(char *data, size_t max, const char *key, const char *option) |
573 | { | | 573 | { |
574 | FILE *fp; | | 574 | FILE *fp; |
575 | char line[LINE_MAX], *p, *p2; | | 575 | char line[LINE_MAX], *p, *p2; |
576 | static char result[LINE_MAX]; | | 576 | static char result[LINE_MAX]; |
577 | int got, found; | | 577 | int got, found; |
578 | const char *cp; | | 578 | const char *cp; |
579 | | | 579 | |
580 | _DIAGASSERT(data != NULL); | | 580 | _DIAGASSERT(data != NULL); |
581 | _DIAGASSERT(key != NULL); | | 581 | _DIAGASSERT(key != NULL); |
582 | _DIAGASSERT(option != NULL); | | 582 | _DIAGASSERT(option != NULL); |
583 | | | 583 | |
584 | got = 0; | | 584 | got = 0; |
585 | found = 0; | | 585 | found = 0; |
586 | result[0] = '\0'; | | 586 | result[0] = '\0'; |
587 | | | 587 | |
588 | if ((fp = fopen(_PATH_PASSWD_CONF, "r")) == NULL) { | | 588 | if ((fp = fopen(_PATH_PASSWD_CONF, "r")) == NULL) { |
589 | if ((cp = pw_default(option)) != NULL) | | 589 | if ((cp = pw_default(option)) != NULL) |
590 | strlcpy(data, cp, max); | | 590 | strlcpy(data, cp, max); |
591 | else | | 591 | else |
592 | data[0] = '\0'; | | 592 | data[0] = '\0'; |
593 | return; | | 593 | return; |
594 | } | | 594 | } |
595 | | | 595 | |
596 | while (!found && (got || read_line(fp, line, LINE_MAX))) { | | 596 | while (!found && (got || read_line(fp, line, LINE_MAX))) { |
597 | got = 0; | | 597 | got = 0; |
598 | | | 598 | |
599 | if (strncmp(key, line, strlen(key)) != 0 || | | 599 | if (strncmp(key, line, strlen(key)) != 0 || |
600 | line[strlen(key)] != ':') | | 600 | line[strlen(key)] != ':') |
601 | continue; | | 601 | continue; |
602 | | | 602 | |
603 | /* Now we found our specified key */ | | 603 | /* Now we found our specified key */ |
604 | while (read_line(fp, line, LINE_MAX)) { | | 604 | while (read_line(fp, line, LINE_MAX)) { |
605 | /* Leaving key field */ | | 605 | /* Leaving key field */ |
606 | if (line[0] != '\0' && strchr(line + 1, ':') != NULL) { | | 606 | if (line[0] != '\0' && strchr(line + 1, ':') != NULL) { |
607 | got = 1; | | 607 | got = 1; |
608 | break; | | 608 | break; |
609 | } | | 609 | } |
610 | p2 = line; | | 610 | p2 = line; |
611 | if ((p = strsep(&p2, "=")) == NULL || p2 == NULL) | | 611 | if ((p = strsep(&p2, "=")) == NULL || p2 == NULL) |
612 | continue; | | 612 | continue; |
613 | trim_whitespace(p); | | 613 | trim_whitespace(p); |
614 | | | 614 | |
615 | if (!strncmp(p, option, strlen(option))) { | | 615 | if (!strncmp(p, option, strlen(option))) { |
616 | trim_whitespace(p2); | | 616 | trim_whitespace(p2); |
617 | strcpy(result, p2); | | 617 | strcpy(result, p2); |
618 | found = 1; | | 618 | found = 1; |
619 | break; | | 619 | break; |
620 | } | | 620 | } |
621 | } | | 621 | } |
622 | } | | 622 | } |
623 | fclose(fp); | | 623 | fclose(fp); |
624 | | | 624 | |
625 | if (!found) | | 625 | if (!found) |
626 | errno = ENOENT; | | 626 | errno = ENOENT; |
627 | if (!got) | | 627 | if (!got) |
628 | errno = ENOTDIR; | | 628 | errno = ENOTDIR; |
629 | | | 629 | |
630 | /* | | 630 | /* |
631 | * If we got no result and were looking for a default | | 631 | * If we got no result and were looking for a default |
632 | * value, try hard coded defaults. | | 632 | * value, try hard coded defaults. |
633 | */ | | 633 | */ |
634 | | | 634 | |
635 | if (strlen(result) == 0 && strcmp(key, "default") == 0 && | | 635 | if (strlen(result) == 0 && strcmp(key, "default") == 0 && |
636 | (cp = pw_default(option)) != NULL) | | 636 | (cp = pw_default(option)) != NULL) |
637 | strlcpy(data, cp, max); | | 637 | strlcpy(data, cp, max); |
638 | else | | 638 | else |
639 | strlcpy(data, result, max); | | 639 | strlcpy(data, result, max); |
640 | } | | 640 | } |
641 | | | 641 | |
642 | void | | 642 | void |
643 | pw_getpwconf(char *data, size_t max, const struct passwd *pwd, | | 643 | pw_getpwconf(char *data, size_t max, const struct passwd *pwd, |
644 | const char *option) | | 644 | const char *option) |
645 | { | | 645 | { |
646 | char grpkey[LINE_MAX]; | | 646 | char grpkey[LINE_MAX]; |
647 | struct group grs, *grp; | | 647 | struct group grs, *grp; |
648 | char grbuf[1024]; | | 648 | char grbuf[1024]; |
649 | | | 649 | |
650 | pw_getconf(data, max, pwd->pw_name, option); | | 650 | pw_getconf(data, max, pwd->pw_name, option); |
651 | | | 651 | |
652 | /* Try to find an entry for the group */ | | 652 | /* Try to find an entry for the group */ |
653 | if (*data == '\0') { | | 653 | if (*data == '\0') { |
654 | (void)getgrgid_r(pwd->pw_gid, &grs, grbuf, sizeof(grbuf), &grp); | | 654 | (void)getgrgid_r(pwd->pw_gid, &grs, grbuf, sizeof(grbuf), &grp); |
655 | if (grp != NULL) { | | 655 | if (grp != NULL) { |
656 | (void)snprintf(grpkey, sizeof(grpkey), ":%s", | | 656 | (void)snprintf(grpkey, sizeof(grpkey), ":%s", |
657 | grp->gr_name); | | 657 | grp->gr_name); |
658 | pw_getconf(data, max, grpkey, option); | | 658 | pw_getconf(data, max, grpkey, option); |
659 | } | | 659 | } |
660 | if (*data == '\0') | | 660 | if (*data == '\0') |
661 | pw_getconf(data, max, "default", option); | | 661 | pw_getconf(data, max, "default", option); |
662 | } | | 662 | } |
663 | } | | 663 | } |