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 |
b8c620d6 | 25 | static char sccsid[] = "@(#)vipw.c 5.5 (Berkeley) %G%"; |
3dd425ca | 26 | #endif /* not lint */ |
4c6b79b5 | 27 | |
f79ee00c | 28 | #include <machine/machparam.h> |
4c6b79b5 SL |
29 | #include <sys/types.h> |
30 | #include <sys/stat.h> | |
f79ee00c | 31 | #include <sys/signal.h> |
4c6b79b5 | 32 | #include <sys/file.h> |
4c6b79b5 SL |
33 | #include <stdio.h> |
34 | #include <errno.h> | |
4c6b79b5 SL |
35 | |
36 | /* | |
37 | * Password file editor with locking. | |
38 | */ | |
f79ee00c | 39 | static char *passwd = "/etc/passwd", buf[BUFSIZ]; |
e50bab02 KB |
40 | |
41 | main() | |
4c6b79b5 | 42 | { |
f79ee00c KB |
43 | register int n, fd_passwd, fd_temp; |
44 | static char *temp = "/etc/ptmp"; | |
45 | struct stat s1, s2; | |
3dd425ca | 46 | char *editor, *getenv(); |
e50bab02 KB |
47 | |
48 | (void)signal(SIGHUP, SIG_IGN); | |
49 | (void)signal(SIGINT, SIG_IGN); | |
50 | (void)signal(SIGQUIT, SIG_IGN); | |
51 | ||
52 | setbuf(stderr, (char *)NULL); | |
f79ee00c | 53 | (void)umask(0); |
e50bab02 KB |
54 | |
55 | if ((fd_passwd = open(passwd, O_RDONLY, 0)) < 0) { | |
f79ee00c | 56 | fputs("vipw: ", stderr); |
e50bab02 KB |
57 | perror(passwd); |
58 | exit(1); | |
59 | } | |
60 | if ((fd_temp = open(temp, O_WRONLY|O_CREAT|O_EXCL, 0644)) < 0) { | |
61 | extern int errno; | |
62 | ||
4c6b79b5 | 63 | if (errno == EEXIST) { |
f79ee00c | 64 | fputs("vipw: password file busy.\n", stderr); |
4c6b79b5 SL |
65 | exit(1); |
66 | } | |
f79ee00c | 67 | fputs("vipw: ", stderr); |
e50bab02 | 68 | perror(temp); |
4c6b79b5 SL |
69 | exit(1); |
70 | } | |
e50bab02 KB |
71 | while ((n = read(fd_passwd, buf, sizeof(buf))) > 0) |
72 | if (write(fd_temp, buf, n) != n) { | |
73 | perror("vipw: write"); | |
74 | goto bad; | |
75 | } | |
76 | if (n == -1) { | |
77 | perror("vipw: read"); | |
78 | goto bad; | |
79 | } | |
80 | (void)close(fd_passwd); | |
81 | if (fsync(fd_temp)) { | |
82 | perror("vipw: fsync"); | |
4c6b79b5 SL |
83 | goto bad; |
84 | } | |
e50bab02 KB |
85 | if (fstat(fd_temp, &s1)) { |
86 | perror("vipw: fstat"); | |
4c6b79b5 SL |
87 | goto bad; |
88 | } | |
e50bab02 KB |
89 | (void)close(fd_temp); |
90 | ||
91 | if (!(editor = getenv("EDITOR"))) | |
4c6b79b5 | 92 | editor = "vi"; |
e50bab02 KB |
93 | (void)sprintf(buf, "%s %s", editor, temp); |
94 | if (system(buf)) { | |
95 | perror("vipw: system"); | |
96 | goto bad; | |
97 | } | |
98 | ||
99 | if (!freopen(temp, "r", stdin)) { | |
f79ee00c | 100 | fprintf(stderr, "vipw: can't reopen temp file; %s unchanged.\n", passwd); |
e50bab02 KB |
101 | goto bad; |
102 | } | |
103 | if (fstat(fileno(stdin), &s2)) { | |
f79ee00c | 104 | fprintf(stderr, "vipw: can't stat temp file; %s unchanged.\n", passwd); |
e50bab02 KB |
105 | goto bad; |
106 | } | |
107 | if (s1.st_mtime == s2.st_mtime) { | |
f79ee00c | 108 | fprintf(stderr, "vipw: %s unchanged.\n", passwd); |
e50bab02 KB |
109 | goto bad; |
110 | } | |
111 | if (!s2.st_size) { | |
f79ee00c | 112 | fprintf(stderr, "vipw: bad temp file; %s unchanged.\n", passwd); |
e50bab02 KB |
113 | goto bad; |
114 | } | |
f79ee00c | 115 | if (check()) { |
e50bab02 KB |
116 | static char *temp_pag = "/etc/ptmp.pag", |
117 | *temp_dir = "/etc/ptmp.dir", | |
118 | *passwd_pag = "/etc/passwd.pag", | |
119 | *passwd_dir = "/etc/passwd.dir"; | |
120 | ||
121 | if (makedb(temp) < 0) | |
122 | fputs("vipw: mkpasswd failed.\n", stderr); | |
123 | else if (rename(temp_pag, passwd_pag) < 0) { | |
124 | fprintf(stderr, "vipw: "); | |
125 | perror(temp_pag); | |
4c6b79b5 | 126 | } |
e50bab02 KB |
127 | else if (rename(temp_dir, passwd_dir) < 0) { |
128 | fprintf(stderr, "vipw: "); | |
129 | perror(temp_dir); | |
4c6b79b5 | 130 | } |
e50bab02 KB |
131 | else if (rename(temp, passwd) < 0) { |
132 | fprintf(stderr, "vipw: "); | |
133 | perror("rename"); | |
4c6b79b5 | 134 | } |
e50bab02 KB |
135 | else |
136 | exit(0); | |
137 | (void)unlink(temp_pag); | |
138 | (void)unlink(temp_dir); | |
4c6b79b5 | 139 | } |
e50bab02 | 140 | bad: (void)unlink(temp); |
6b52f313 | 141 | exit(1); |
4c6b79b5 | 142 | } |
ae41743d | 143 | |
f79ee00c | 144 | #define CHN ((char *)NULL) |
e50bab02 | 145 | static |
f79ee00c | 146 | check() |
e50bab02 | 147 | { |
f79ee00c KB |
148 | register char *cp, *sh; |
149 | register long id; | |
150 | register int root; | |
151 | long atol(); | |
152 | char *token(), *getusershell(); | |
153 | ||
154 | for (root = 0; gets(buf); root = 0) { | |
155 | if (!*buf) { | |
156 | fputs("vipw: empty line.\n", stderr); | |
e50bab02 | 157 | continue; |
f79ee00c KB |
158 | } |
159 | if (!(cp = token(buf)) || !*cp) /* login */ | |
160 | goto bad; | |
161 | if (!strcmp(cp, "root")) | |
162 | root = 1; | |
163 | (void)token(CHN); /* passwd */ | |
164 | if (!(cp = token(CHN)) || !*cp) /* uid */ | |
165 | goto bad; | |
166 | id = atol(cp); | |
167 | if (root && id) { | |
168 | fprintf(stderr, "vipw: root uid should be 0; %s unchanged.\n", passwd); | |
169 | return(0); | |
170 | } | |
171 | if (id > USHRT_MAX) { | |
172 | fprintf(stderr, "vipw: %s > max uid value (%u); %s unchanged.\n", cp, USHRT_MAX, passwd); | |
173 | return(0); | |
174 | } | |
175 | if (!(cp = token(CHN)) || !*cp) /* gid */ | |
176 | goto bad; | |
177 | id = atol(cp); | |
178 | if (id > USHRT_MAX) { | |
179 | fprintf(stderr, "vipw: %s > max gid value (%u); %s unchanged.\n", cp, USHRT_MAX, passwd); | |
180 | return(0); | |
181 | } | |
182 | (void)token(CHN); /* gcos */ | |
183 | if (!token(CHN)) /* home directory */ | |
184 | goto bad; | |
185 | if (!(cp = token(CHN))) /* shell */ | |
186 | goto bad; | |
187 | if (root && *cp) /* empty == /bin/sh */ | |
188 | for (;;) | |
189 | if (!(sh = getusershell())) { | |
190 | fprintf(stderr, "vipw: illegal shell (%s) for root; %s unchanged.\n", cp, passwd); | |
191 | return(0); | |
192 | } | |
193 | else if (!strcmp(cp, sh)) | |
194 | break; | |
195 | if (token(CHN)) { /* too many fields */ | |
196 | bad: fprintf(stderr, "vipw: corrupted entry; %s unchanged.\n", passwd); | |
197 | return(0); | |
198 | } | |
e50bab02 | 199 | } |
f79ee00c | 200 | return(1); |
e50bab02 KB |
201 | } |
202 | ||
203 | static | |
ae41743d | 204 | makedb(file) |
f79ee00c | 205 | char *file; |
ae41743d | 206 | { |
f79ee00c | 207 | int status, pid, w; |
ae41743d | 208 | |
e50bab02 | 209 | if (!(pid = vfork())) { |
ae41743d RC |
210 | execl("/etc/mkpasswd", "mkpasswd", file, 0); |
211 | _exit(127); | |
212 | } | |
e50bab02 KB |
213 | while ((w = wait(&status)) != pid && w != -1); |
214 | if (w == -1 || status) | |
215 | return(-1); | |
216 | return(0); | |
ae41743d | 217 | } |
f79ee00c KB |
218 | |
219 | static char * | |
220 | token(bfr) | |
221 | char *bfr; | |
222 | { | |
223 | static char *cp; | |
224 | char *start; | |
225 | ||
226 | if (bfr) /* re-init string */ | |
227 | cp = bfr; | |
228 | else if (!cp) /* check if hit EOS last time */ | |
229 | return(CHN); | |
230 | else if (!bfr) /* start at next char after ':' */ | |
231 | ++cp; | |
232 | for (start = cp;; ++cp) | |
233 | if (!*cp) { /* found EOS; mark it for next time */ | |
234 | cp = CHN; | |
235 | break; | |
236 | } | |
237 | else if (*cp == ':') { /* found ':'; end token */ | |
238 | *cp = '\0'; | |
239 | break; | |
240 | } | |
241 | return(start); /* return token */ | |
242 | } |