|
|
1.1 root 1: /*
2: * Copyright (c) 1987 Regents of the University of California.
3: * All rights reserved.
4: *
5: * Redistribution and use in source and binary forms are permitted
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.
16: */
17:
18: #ifndef lint
19: char copyright[] =
20: "@(#) Copyright (c) 1987 Regents of the University of California.\n\
21: All rights reserved.\n";
22: #endif /* not lint */
23:
24: #ifndef lint
25: static char sccsid[] = "@(#)vipw.c 5.5 (Berkeley) 6/18/88";
26: #endif /* not lint */
27:
28: #include <machine/machparam.h>
29: #include <sys/types.h>
30: #include <sys/stat.h>
31: #include <sys/signal.h>
32: #include <sys/file.h>
33: #include <stdio.h>
34: #include <errno.h>
35:
36: /*
37: * Password file editor with locking.
38: */
39: static char *passwd = "/etc/passwd", buf[BUFSIZ];
40:
41: main()
42: {
43: register int n, fd_passwd, fd_temp;
44: static char *temp = "/etc/ptmp";
45: struct stat s1, s2;
46: char *editor, *getenv();
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);
53: (void)umask(0);
54:
55: if ((fd_passwd = open(passwd, O_RDONLY, 0)) < 0) {
56: fputs("vipw: ", stderr);
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:
63: if (errno == EEXIST) {
64: fputs("vipw: password file busy.\n", stderr);
65: exit(1);
66: }
67: fputs("vipw: ", stderr);
68: perror(temp);
69: exit(1);
70: }
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");
83: goto bad;
84: }
85: if (fstat(fd_temp, &s1)) {
86: perror("vipw: fstat");
87: goto bad;
88: }
89: (void)close(fd_temp);
90:
91: if (!(editor = getenv("EDITOR")))
92: editor = "vi";
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)) {
100: fprintf(stderr, "vipw: can't reopen temp file; %s unchanged.\n", passwd);
101: goto bad;
102: }
103: if (fstat(fileno(stdin), &s2)) {
104: fprintf(stderr, "vipw: can't stat temp file; %s unchanged.\n", passwd);
105: goto bad;
106: }
107: if (s1.st_mtime == s2.st_mtime) {
108: fprintf(stderr, "vipw: %s unchanged.\n", passwd);
109: goto bad;
110: }
111: if (!s2.st_size) {
112: fprintf(stderr, "vipw: bad temp file; %s unchanged.\n", passwd);
113: goto bad;
114: }
115: if (check()) {
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);
126: }
127: else if (rename(temp_dir, passwd_dir) < 0) {
128: fprintf(stderr, "vipw: ");
129: perror(temp_dir);
130: }
131: else if (rename(temp, passwd) < 0) {
132: fprintf(stderr, "vipw: ");
133: perror("rename");
134: }
135: else
136: exit(0);
137: (void)unlink(temp_pag);
138: (void)unlink(temp_dir);
139: }
140: bad: (void)unlink(temp);
141: exit(1);
142: }
143:
144: #define CHN ((char *)NULL)
145: static
146: check()
147: {
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);
157: continue;
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 (%d); %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 (%d); %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: }
199: }
200: return(1);
201: }
202:
203: static
204: makedb(file)
205: char *file;
206: {
207: int status, pid, w;
208:
209: if (!(pid = vfork())) {
210: execl("/etc/mkpasswd", "mkpasswd", file, 0);
211: _exit(127);
212: }
213: while ((w = wait(&status)) != pid && w != -1);
214: if (w == -1 || status)
215: return(-1);
216: return(0);
217: }
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: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.