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