|
|
1.1 root 1: /*
2: * Copyright (c) 1987 Regents of the University of California.
3: * All rights reserved.
4: *
5: * Redistribution and use in source and binary forms are permitted
6: * provided that: (1) source distributions retain this entire copyright
7: * notice and comment, and (2) distributions including binaries display
8: * the following acknowledgement: ``This product includes software
9: * developed by the University of California, Berkeley and its contributors''
10: * in the documentation or other materials provided with the distribution
11: * and in all advertising materials mentioning features or use of this
12: * software. Neither the name of the University nor the names of its
13: * contributors may be used to endorse or promote products derived
14: * from this software without specific prior written permission.
15: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
16: * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
17: * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
18: */
19:
20: #ifndef lint
21: char copyright[] =
22: "@(#) Copyright (c) 1987 Regents of the University of California.\n\
23: All rights reserved.\n";
24: #endif /* not lint */
25:
26: #ifndef lint
27: static char sccsid[] = "@(#)vipw.c 5.14 (Berkeley) 6/1/90";
28: #endif /* not lint */
29:
30: #include <sys/param.h>
31: #include <sys/stat.h>
32: #include <sys/signal.h>
33: #include <sys/file.h>
34: #include <sys/time.h>
35: #include <sys/resource.h>
36: #include <errno.h>
37: #include <pwd.h>
38: #include <stdio.h>
39: #include <string.h>
40:
41: char *passwd, *temp;
42:
43: main()
44: {
45: extern int errno;
46: register int n, fd_passwd, fd;
47: struct rlimit rlim;
48: struct stat s1, s2;
49: FILE *tfp;
50: char *fend, *tend;
51: char buf[8*1024], from[MAXPATHLEN], to[MAXPATHLEN];
52:
53: (void)signal(SIGHUP, SIG_IGN);
54: (void)signal(SIGINT, SIG_IGN);
55: (void)signal(SIGQUIT, SIG_IGN);
56: (void)signal(SIGTSTP, SIG_IGN);
57:
58: rlim.rlim_cur = rlim.rlim_max = RLIM_INFINITY;
59: (void)setrlimit(RLIMIT_CPU, &rlim);
60: (void)setrlimit(RLIMIT_FSIZE, &rlim);
61:
62: (void)umask(0);
63:
64: temp = _PATH_PTMP;
65: if ((fd = open(temp, O_RDWR|O_CREAT|O_EXCL, 0600)) < 0) {
66: if (errno == EEXIST)
67: (void)fprintf(stderr, "vipw: password file busy.\n");
68: else
69: (void)fprintf(stderr,
70: "vipw: %s: %s\n", temp, strerror(errno));
71: exit(1);
72: }
73: passwd = _PATH_MASTERPASSWD;
74: if ((fd_passwd = open(passwd, O_RDONLY, 0)) < 0) {
75: (void)fprintf(stderr, "vipw: %s: %s\n", passwd,
76: strerror(errno));
77: exit(1);
78: }
79: while ((n = read(fd_passwd, buf, sizeof(buf))) > 0)
80: if (write(fd, buf, n) != n)
81: goto syserr;
82:
83: if (n == -1 || close(fd_passwd)) {
84: syserr: (void)fprintf(stderr, "vipw: %s: %s; ",
85: passwd, strerror(errno));
86: stop(1);
87: }
88:
89: (void)fstat(fd, &s1);
90: (void)close(fd);
91: for (;;) {
92: if (edit()) {
93: (void)fprintf(stderr, "vipw: edit failed; ");
94: stop(1);
95: }
96: /*
97: * close and re-open the file each time we edit it; some
98: * editors create a new physical file on each edit session.
99: */
100: if (!(tfp = fopen(temp, "r"))) {
101: (void)fprintf(stderr, "vipw: %s: %s; ",
102: temp, strerror(errno));
103: stop(1);
104: }
105: (void)fstat(fileno(tfp), &s2);
106: if (s1.st_mtime == s2.st_mtime) {
107: (void)fprintf(stderr, "vipw: no changes made; ");
108: stop(0);
109: }
110: if (!check(tfp))
111: break;
112: if (prompt())
113: stop(0);
114: (void)fstat(fileno(tfp), &s1);
115: (void)fclose(tfp);
116: }
117:
118: switch(fork()) {
119: case 0:
120: break;
121: case -1:
122: (void)fprintf(stderr, "vipw: can't fork; ");
123: stop(1);
124: /* NOTREACHED */
125: default:
126: exit(0);
127: /* NOTREACHED */
128: }
129:
130: if (makedb(temp)) {
131: (void)fprintf(stderr, "vipw: mkpasswd failed; ");
132: stop(1);
133: }
134:
135: /*
136: * possible race; have to rename four files, and someone could slip
137: * in between them. LOCK_EX and rename the ``passwd.dir'' file first
138: * so that getpwent(3) can't slip in; the lock should never fail and
139: * it's unclear what to do if it does. Rename ``ptmp'' last so that
140: * passwd/vipw/chpass can't slip in.
141: */
142: (void)setpriority(PRIO_PROCESS, 0, -20);
143: fend = strcpy(from, temp) + strlen(temp);
144: tend = strcpy(to, _PATH_PASSWD) + strlen(_PATH_PASSWD);
145: bcopy(".dir", fend, 5);
146: bcopy(".dir", tend, 5);
147: if ((fd = open(from, O_RDONLY, 0)) >= 0)
148: (void)flock(fd, LOCK_EX);
149: /* here we go... */
150: (void)rename(from, to);
151: bcopy(".pag", fend, 5);
152: bcopy(".pag", tend, 5);
153: (void)rename(from, to);
154: bcopy(".orig", fend, 6);
155: (void)rename(from, _PATH_PASSWD);
156: (void)rename(temp, passwd);
157: /* done! */
158: exit(0);
159: }
160:
161: check(tfp)
162: FILE *tfp;
163: {
164: register long id;
165: register int lcnt, root;
166: register char *p, *sh;
167: long atol();
168: char buf[1024], *bp, *getusershell();
169:
170: for (lcnt = 1; fgets(buf, sizeof(buf), tfp); ++lcnt) {
171: /* skip lines that are too big */
172: if (!(p = index(buf, '\n'))) {
173: (void)fprintf(stderr, "vipw: line too long");
174: goto bad;
175: }
176: *p = '\0';
177: bp = buf;
178: if (!(p = strsep(&bp, ":"))) /* login */
179: goto general;
180: root = !strcmp(p, "root");
181: (void)strsep(&bp, ":"); /* passwd */
182: if (!(p = strsep(&bp, ":"))) /* uid */
183: goto general;
184: id = atol(p);
185: if (root && id) {
186: (void)fprintf(stderr, "vipw: root uid should be 0");
187: goto bad;
188: }
189: if (id > USHRT_MAX) {
190: (void)fprintf(stderr, "vipw: %s > max uid value (%d)",
191: p, USHRT_MAX);
192: goto bad;
193: }
194: if (!(p = strsep(&bp, ":"))) /* gid */
195: goto general;
196: id = atol(p);
197: if (id > USHRT_MAX) {
198: (void)fprintf(stderr, "vipw: %s > max gid value (%d)",
199: p, USHRT_MAX);
200: goto bad;
201: }
202: (void)strsep(&bp, ":"); /* class */
203: (void)strsep(&bp, ":"); /* change */
204: (void)strsep(&bp, ":"); /* expire */
205: (void)strsep(&bp, ":"); /* gecos */
206: (void)strsep(&bp, ":"); /* directory */
207: if (!(p = strsep(&bp, ":"))) /* shell */
208: goto general;
209: if (root && *p) /* empty == /bin/sh */
210: for (setusershell();;)
211: if (!(sh = getusershell())) {
212: (void)fprintf(stderr,
213: "vipw: warning, unknown root shell.\n");
214: break;
215: }
216: else if (!strcmp(p, sh))
217: break;
218: if (p = strsep(&bp, ":")) { /* too many */
219: (void)fprintf(stderr, "got {%s}\n", p);
220: general: (void)fprintf(stderr, "vipw: corrupted entry");
221: bad: (void)fprintf(stderr, "; line #%d.\n", lcnt);
222: (void)fflush(stderr);
223: return(1);
224: }
225: }
226: return(0);
227: }
228:
229: makedb(file)
230: char *file;
231: {
232: int status, pid, w;
233:
234: if (!(pid = vfork())) {
235: execl(_PATH_MKPASSWD, "mkpasswd", "-p", file, NULL);
236: _exit(127);
237: }
238: while ((w = wait(&status)) != pid && w != -1);
239: return(w == -1 || status);
240: }
241:
242: edit()
243: {
244: extern int errno;
245: int status, pid, w;
246: char *p, *editor, *getenv(), *strerror();
247:
248: if (editor = getenv("EDITOR")) {
249: if (p = rindex(editor, '/'))
250: ++p;
251: else
252: p = editor;
253: }
254: else
255: p = editor = "vi";
256: if (!(pid = vfork())) {
257: execlp(editor, p, temp, NULL);
258: (void)fprintf(stderr, "vipw: %s: %s\n", editor,
259: strerror(errno));
260: _exit(127);
261: }
262: while ((w = wait(&status)) != pid && w != -1);
263: return(w == -1 || status);
264: }
265:
266: prompt()
267: {
268: register int c;
269:
270: for (;;) {
271: (void)printf("re-edit the password file? [y]: ");
272: (void)fflush(stdout);
273: c = getchar();
274: if (c != EOF && c != (int)'\n')
275: while (getchar() != (int)'\n');
276: return(c == (int)'n');
277: }
278: /* NOTREACHED */
279: }
280:
281: stop(val)
282: int val;
283: {
284: (void)fprintf(stderr, "%s unchanged.\n", passwd);
285: (void)unlink(temp);
286: exit(val);
287: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.