dist -> vaxdist
[unix-history] / usr / src / usr.sbin / vipw / vipw.c
CommitLineData
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
14char 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
20static 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 34static char *passwd = "/etc/passwd", buf[BUFSIZ];
e50bab02
KB
35
36main()
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 135bad: (void)unlink(temp);
6b52f313 136 exit(1);
4c6b79b5 137}
ae41743d 138
f79ee00c 139#define CHN ((char *)NULL)
e50bab02 140static
f79ee00c 141check()
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 */
191bad: fprintf(stderr, "vipw: corrupted entry; %s unchanged.\n", passwd);
192 return(0);
193 }
e50bab02 194 }
f79ee00c 195 return(1);
e50bab02
KB
196}
197
198static
ae41743d 199makedb(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
214static char *
215token(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}