|
|
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: (1) source distributions retain this entire copyright ! 7: * notice and comment, and (2) distributions including binaries display ! 8: * the following acknowledgement: ``This product includes software ! 9: * developed by the University of California, Berkeley and its contributors'' ! 10: * in the documentation or other materials provided with the distribution ! 11: * and in all advertising materials mentioning features or use of this ! 12: * software. Neither the name of the University nor the names of its ! 13: * contributors may be used to endorse or promote products derived ! 14: * from this software without specific prior written permission. ! 15: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR ! 16: * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED ! 17: * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. ! 18: */ ! 19: ! 20: #ifndef lint ! 21: char copyright[] = ! 22: "@(#) Copyright (c) 1987 Regents of the University of California.\n\ ! 23: All rights reserved.\n"; ! 24: #endif /* not lint */ ! 25: ! 26: #ifndef lint ! 27: static char sccsid[] = "@(#)vipw.c 5.14 (Berkeley) 6/1/90"; ! 28: #endif /* not lint */ ! 29: ! 30: #include <sys/param.h> ! 31: #include <sys/stat.h> ! 32: #include <sys/signal.h> ! 33: #include <sys/file.h> ! 34: #include <sys/time.h> ! 35: #include <sys/resource.h> ! 36: #include <errno.h> ! 37: #include <pwd.h> ! 38: #include <stdio.h> ! 39: #include <string.h> ! 40: ! 41: char *passwd, *temp; ! 42: ! 43: main() ! 44: { ! 45: extern int errno; ! 46: register int n, fd_passwd, fd; ! 47: struct rlimit rlim; ! 48: struct stat s1, s2; ! 49: FILE *tfp; ! 50: char *fend, *tend; ! 51: char buf[8*1024], from[MAXPATHLEN], to[MAXPATHLEN]; ! 52: ! 53: (void)signal(SIGHUP, SIG_IGN); ! 54: (void)signal(SIGINT, SIG_IGN); ! 55: (void)signal(SIGQUIT, SIG_IGN); ! 56: (void)signal(SIGTSTP, SIG_IGN); ! 57: ! 58: rlim.rlim_cur = rlim.rlim_max = RLIM_INFINITY; ! 59: (void)setrlimit(RLIMIT_CPU, &rlim); ! 60: (void)setrlimit(RLIMIT_FSIZE, &rlim); ! 61: ! 62: (void)umask(0); ! 63: ! 64: temp = _PATH_PTMP; ! 65: if ((fd = open(temp, O_RDWR|O_CREAT|O_EXCL, 0600)) < 0) { ! 66: if (errno == EEXIST) ! 67: (void)fprintf(stderr, "vipw: password file busy.\n"); ! 68: else ! 69: (void)fprintf(stderr, ! 70: "vipw: %s: %s\n", temp, strerror(errno)); ! 71: exit(1); ! 72: } ! 73: passwd = _PATH_MASTERPASSWD; ! 74: if ((fd_passwd = open(passwd, O_RDONLY, 0)) < 0) { ! 75: (void)fprintf(stderr, "vipw: %s: %s\n", passwd, ! 76: strerror(errno)); ! 77: exit(1); ! 78: } ! 79: while ((n = read(fd_passwd, buf, sizeof(buf))) > 0) ! 80: if (write(fd, buf, n) != n) ! 81: goto syserr; ! 82: ! 83: if (n == -1 || close(fd_passwd)) { ! 84: syserr: (void)fprintf(stderr, "vipw: %s: %s; ", ! 85: passwd, strerror(errno)); ! 86: stop(1); ! 87: } ! 88: ! 89: (void)fstat(fd, &s1); ! 90: (void)close(fd); ! 91: for (;;) { ! 92: if (edit()) { ! 93: (void)fprintf(stderr, "vipw: edit failed; "); ! 94: stop(1); ! 95: } ! 96: /* ! 97: * close and re-open the file each time we edit it; some ! 98: * editors create a new physical file on each edit session. ! 99: */ ! 100: if (!(tfp = fopen(temp, "r"))) { ! 101: (void)fprintf(stderr, "vipw: %s: %s; ", ! 102: temp, strerror(errno)); ! 103: stop(1); ! 104: } ! 105: (void)fstat(fileno(tfp), &s2); ! 106: if (s1.st_mtime == s2.st_mtime) { ! 107: (void)fprintf(stderr, "vipw: no changes made; "); ! 108: stop(0); ! 109: } ! 110: if (!check(tfp)) ! 111: break; ! 112: if (prompt()) ! 113: stop(0); ! 114: (void)fstat(fileno(tfp), &s1); ! 115: (void)fclose(tfp); ! 116: } ! 117: ! 118: switch(fork()) { ! 119: case 0: ! 120: break; ! 121: case -1: ! 122: (void)fprintf(stderr, "vipw: can't fork; "); ! 123: stop(1); ! 124: /* NOTREACHED */ ! 125: default: ! 126: exit(0); ! 127: /* NOTREACHED */ ! 128: } ! 129: ! 130: if (makedb(temp)) { ! 131: (void)fprintf(stderr, "vipw: mkpasswd failed; "); ! 132: stop(1); ! 133: } ! 134: ! 135: /* ! 136: * possible race; have to rename four files, and someone could slip ! 137: * in between them. LOCK_EX and rename the ``passwd.dir'' file first ! 138: * so that getpwent(3) can't slip in; the lock should never fail and ! 139: * it's unclear what to do if it does. Rename ``ptmp'' last so that ! 140: * passwd/vipw/chpass can't slip in. ! 141: */ ! 142: (void)setpriority(PRIO_PROCESS, 0, -20); ! 143: fend = strcpy(from, temp) + strlen(temp); ! 144: tend = strcpy(to, _PATH_PASSWD) + strlen(_PATH_PASSWD); ! 145: bcopy(".dir", fend, 5); ! 146: bcopy(".dir", tend, 5); ! 147: if ((fd = open(from, O_RDONLY, 0)) >= 0) ! 148: (void)flock(fd, LOCK_EX); ! 149: /* here we go... */ ! 150: (void)rename(from, to); ! 151: bcopy(".pag", fend, 5); ! 152: bcopy(".pag", tend, 5); ! 153: (void)rename(from, to); ! 154: bcopy(".orig", fend, 6); ! 155: (void)rename(from, _PATH_PASSWD); ! 156: (void)rename(temp, passwd); ! 157: /* done! */ ! 158: exit(0); ! 159: } ! 160: ! 161: check(tfp) ! 162: FILE *tfp; ! 163: { ! 164: register long id; ! 165: register int lcnt, root; ! 166: register char *p, *sh; ! 167: long atol(); ! 168: char buf[1024], *bp, *getusershell(); ! 169: ! 170: for (lcnt = 1; fgets(buf, sizeof(buf), tfp); ++lcnt) { ! 171: /* skip lines that are too big */ ! 172: if (!(p = index(buf, '\n'))) { ! 173: (void)fprintf(stderr, "vipw: line too long"); ! 174: goto bad; ! 175: } ! 176: *p = '\0'; ! 177: bp = buf; ! 178: if (!(p = strsep(&bp, ":"))) /* login */ ! 179: goto general; ! 180: root = !strcmp(p, "root"); ! 181: (void)strsep(&bp, ":"); /* passwd */ ! 182: if (!(p = strsep(&bp, ":"))) /* uid */ ! 183: goto general; ! 184: id = atol(p); ! 185: if (root && id) { ! 186: (void)fprintf(stderr, "vipw: root uid should be 0"); ! 187: goto bad; ! 188: } ! 189: if (id > USHRT_MAX) { ! 190: (void)fprintf(stderr, "vipw: %s > max uid value (%d)", ! 191: p, USHRT_MAX); ! 192: goto bad; ! 193: } ! 194: if (!(p = strsep(&bp, ":"))) /* gid */ ! 195: goto general; ! 196: id = atol(p); ! 197: if (id > USHRT_MAX) { ! 198: (void)fprintf(stderr, "vipw: %s > max gid value (%d)", ! 199: p, USHRT_MAX); ! 200: goto bad; ! 201: } ! 202: (void)strsep(&bp, ":"); /* class */ ! 203: (void)strsep(&bp, ":"); /* change */ ! 204: (void)strsep(&bp, ":"); /* expire */ ! 205: (void)strsep(&bp, ":"); /* gecos */ ! 206: (void)strsep(&bp, ":"); /* directory */ ! 207: if (!(p = strsep(&bp, ":"))) /* shell */ ! 208: goto general; ! 209: if (root && *p) /* empty == /bin/sh */ ! 210: for (setusershell();;) ! 211: if (!(sh = getusershell())) { ! 212: (void)fprintf(stderr, ! 213: "vipw: warning, unknown root shell.\n"); ! 214: break; ! 215: } ! 216: else if (!strcmp(p, sh)) ! 217: break; ! 218: if (p = strsep(&bp, ":")) { /* too many */ ! 219: (void)fprintf(stderr, "got {%s}\n", p); ! 220: general: (void)fprintf(stderr, "vipw: corrupted entry"); ! 221: bad: (void)fprintf(stderr, "; line #%d.\n", lcnt); ! 222: (void)fflush(stderr); ! 223: return(1); ! 224: } ! 225: } ! 226: return(0); ! 227: } ! 228: ! 229: makedb(file) ! 230: char *file; ! 231: { ! 232: int status, pid, w; ! 233: ! 234: if (!(pid = vfork())) { ! 235: execl(_PATH_MKPASSWD, "mkpasswd", "-p", file, NULL); ! 236: _exit(127); ! 237: } ! 238: while ((w = wait(&status)) != pid && w != -1); ! 239: return(w == -1 || status); ! 240: } ! 241: ! 242: edit() ! 243: { ! 244: extern int errno; ! 245: int status, pid, w; ! 246: char *p, *editor, *getenv(), *strerror(); ! 247: ! 248: if (editor = getenv("EDITOR")) { ! 249: if (p = rindex(editor, '/')) ! 250: ++p; ! 251: else ! 252: p = editor; ! 253: } ! 254: else ! 255: p = editor = "vi"; ! 256: if (!(pid = vfork())) { ! 257: execlp(editor, p, temp, NULL); ! 258: (void)fprintf(stderr, "vipw: %s: %s\n", editor, ! 259: strerror(errno)); ! 260: _exit(127); ! 261: } ! 262: while ((w = wait(&status)) != pid && w != -1); ! 263: return(w == -1 || status); ! 264: } ! 265: ! 266: prompt() ! 267: { ! 268: register int c; ! 269: ! 270: for (;;) { ! 271: (void)printf("re-edit the password file? [y]: "); ! 272: (void)fflush(stdout); ! 273: c = getchar(); ! 274: if (c != EOF && c != (int)'\n') ! 275: while (getchar() != (int)'\n'); ! 276: return(c == (int)'n'); ! 277: } ! 278: /* NOTREACHED */ ! 279: } ! 280: ! 281: stop(val) ! 282: int val; ! 283: { ! 284: (void)fprintf(stderr, "%s unchanged.\n", passwd); ! 285: (void)unlink(temp); ! 286: exit(val); ! 287: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.