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