Sun Apr 24 01:56:44 2011 UTC ()
fix freudian slip


(christos)
diff -r1.50 -r1.51 src/lib/libutil/passwd.c

cvs diff -r1.50 -r1.51 src/lib/libutil/passwd.c (switch to unified diff)

--- src/lib/libutil/passwd.c 2010/08/18 08:32:02 1.50
+++ src/lib/libutil/passwd.c 2011/04/24 01:56:44 1.51
@@ -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
60static const char *pw_filename(const char *filename); 60static const char *pw_filename(const char *filename);
61static void pw_cont(int sig); 61static void pw_cont(int sig);
62static const char * pw_equal(char *buf, struct passwd *old_pw); 62static const char * pw_equal(char *buf, struct passwd *old_pw);
63static const char *pw_default(const char *option); 63static const char *pw_default(const char *option);
64static int read_line(FILE *fp, char *line, int max); 64static int read_line(FILE *fp, char *line, int max);
65static void trim_whitespace(char *line); 65static void trim_whitespace(char *line);
66 66
67static char pw_prefix[MAXPATHLEN]; 67static char pw_prefix[MAXPATHLEN];
68 68
69const char * 69const char *
70pw_getprefix(void) 70pw_getprefix(void)
71{ 71{
72 72
73 return(pw_prefix); 73 return(pw_prefix);
74} 74}
75 75
76int 76int
77pw_setprefix(const char *new_prefix) 77pw_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
94static const char * 94static const char *
95pw_filename(const char *filename) 95pw_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
111int 111int
112pw_lock(int retries) 112pw_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
136int 136int
137pw_mkdb(username, secureonly) 137pw_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
186int 186int
187pw_abort(void) 187pw_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
199static pid_t editpid = -1; 199static pid_t editpid = -1;
200 200
201static void 201static void
202pw_cont(int sig) 202pw_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
209void 209void
210pw_init(void) 210pw_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
236void 236void
237pw_edit(int notsetuid, const char *filename) 237pw_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
290void 290void
291pw_prompt(void) 291pw_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 */
306static const char * 306static const char *
307pw_equal(char *buf, struct passwd *pw) 307pw_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
341void 341void
342pw_copy(int ffd, int tfd, struct passwd *pw, struct passwd *old_pw) 342pw_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
354static void 354static void
355pw_print(FILE *to, const struct passwd *pw) 355pw_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
364int 364int
365pw_copyx(int ffd, int tfd, struct passwd *pw, struct passwd *old_pw, 365pw_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
484void 484void
485pw_error(const char *name, int error, int eval) 485pw_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. */
501static void 501static void
502trim_whitespace(char *line) 502trim_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 */
523static int 523static int
524read_line(FILE *fp, char *line, int max) 524read_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
549static const char * 549static const char *
550pw_default(const char *option) 550pw_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 */
571void 571void
572pw_getconf(char *data, size_t max, const char *key, const char *option) 572pw_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
642void 642void
643pw_getpwconf(char *data, size_t max, const struct passwd *pwd, 643pw_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}