string.h is ANSI C include file
[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
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
19char 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 25static 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
39char *passwd, *temp;
e50bab02
KB
40
41main()
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)) {
82syserr: (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
159check(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
218general: (void)fprintf(stderr, "vipw: corrupted entry");
219bad: (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 227makedb(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 240edit()
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
264prompt()
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
279stop(val)
280 int val;
281{
282 (void)fprintf(stderr, "%s unchanged.\n", passwd);
283 (void)unlink(temp);
284 exit(val);
285}