|
|
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.