1: /* 2: * Copyright (c) 1988 The 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 MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 16: */ 17: 18: #ifndef lint 19: char copyright[] = 20: "@(#) Copyright (c) 1988 The Regents of the University of California.\n\ 21: All rights reserved.\n"; 22: #endif /* not lint */ 23: 24: #ifndef lint 25: static char sccsid[] = "@(#)passwd.c 4.35 (Berkeley) 3/16/89"; 26: #endif /* not lint */ 27: 28: #include <sys/param.h> 29: #include <sys/file.h> 30: #include <sys/signal.h> 31: #include <sys/time.h> 32: #include <sys/resource.h> 33: #include <errno.h> 34: #include <pwd.h> 35: #include <stdio.h> 36: #include <ctype.h> 37: #include <strings.h> 38: 39: uid_t uid; 40: 41: main(argc, argv) 42: int argc; 43: char **argv; 44: { 45: extern int errno; 46: struct passwd *pw; 47: struct rlimit rlim; 48: FILE *temp_fp; 49: int fd; 50: char *fend, *np, *passwd, *temp, *tend; 51: char from[MAXPATHLEN], to[MAXPATHLEN]; 52: char *getnewpasswd(); 53: 54: uid = getuid(); 55: switch(--argc) { 56: case 0: 57: if (!(pw = getpwuid(uid))) { 58: fprintf(stderr, "passwd: unknown user: uid %u\n", uid); 59: exit(1); 60: } 61: break; 62: case 1: 63: if (!(pw = getpwnam(argv[1]))) { 64: fprintf(stderr, "passwd: unknown user %s.\n", argv[1]); 65: exit(1); 66: } 67: if (uid && uid != pw->pw_uid) { 68: fprintf(stderr, "passwd: %s\n", strerror(EACCES)); 69: exit(1); 70: } 71: break; 72: default: 73: fprintf(stderr, "usage: passwd [user]\n"); 74: exit(1); 75: } 76: 77: (void)signal(SIGHUP, SIG_IGN); 78: (void)signal(SIGINT, SIG_IGN); 79: (void)signal(SIGQUIT, SIG_IGN); 80: (void)signal(SIGTSTP, SIG_IGN); 81: 82: rlim.rlim_cur = rlim.rlim_max = RLIM_INFINITY; 83: (void)setrlimit(RLIMIT_CPU, &rlim); 84: (void)setrlimit(RLIMIT_FSIZE, &rlim); 85: 86: (void)umask(0); 87: 88: temp = _PATH_PTMP; 89: if ((fd = open(temp, O_WRONLY|O_CREAT|O_EXCL, 0600)) < 0) { 90: if (errno == EEXIST) { 91: fprintf(stderr, 92: "passwd: password file busy -- try again later.\n"); 93: exit(0); 94: } 95: fprintf(stderr, "passwd: %s: %s", temp, strerror(errno)); 96: goto bad; 97: } 98: if (!(temp_fp = fdopen(fd, "w"))) { 99: fprintf(stderr, "passwd: can't write %s\n", temp); 100: goto bad; 101: } 102: passwd = _PATH_MASTERPASSWD; 103: if (!freopen(passwd, "r", stdin)) { 104: fprintf(stderr, "passwd: can't read %s\n", passwd); 105: goto bad; 106: } 107: 108: printf("Changing password for %s.\n", pw->pw_name); 109: np = getnewpasswd(pw, temp); 110: 111: if (!copy(pw->pw_name, np, temp_fp, pw)) 112: goto bad; 113: 114: (void)fclose(temp_fp); 115: (void)fclose(stdin); 116: 117: switch(fork()) { 118: case 0: 119: break; 120: case -1: 121: fprintf(stderr, "passwd: can't fork"); 122: goto bad; 123: /* NOTREACHED */ 124: default: 125: exit(0); 126: /* NOTREACHED */ 127: } 128: 129: if (makedb(temp)) { 130: fprintf(stderr, "passwd: mkpasswd failed"); 131: bad: fprintf(stderr, "; password unchanged.\n"); 132: (void)unlink(temp); 133: exit(1); 134: } 135: 136: /* 137: * possible race; have to rename four files, and someone could slip 138: * in between them. LOCK_EX and rename the ``passwd.dir'' file first 139: * so that getpwent(3) can't slip in; the lock should never fail and 140: * it's unclear what to do if it does. Rename ``ptmp'' last so that 141: * passwd/vipw/chpass can't slip in. 142: */ 143: (void)setpriority(PRIO_PROCESS, 0, -20); 144: fend = strcpy(from, temp) + strlen(temp); 145: tend = strcpy(to, _PATH_PASSWD) + strlen(_PATH_PASSWD); 146: bcopy(".dir", fend, 5); 147: bcopy(".dir", tend, 5); 148: if ((fd = open(from, O_RDONLY, 0)) >= 0) 149: (void)flock(fd, LOCK_EX); 150: /* here we go... */ 151: (void)rename(from, to); 152: bcopy(".pag", fend, 5); 153: bcopy(".pag", tend, 5); 154: (void)rename(from, to); 155: bcopy(".orig", fend, 6); 156: (void)rename(from, _PATH_PASSWD); 157: (void)rename(temp, passwd); 158: /* done! */ 159: exit(0); 160: } 161: 162: copy(name, np, fp, pw) 163: char *name, *np; 164: FILE *fp; 165: struct passwd *pw; 166: { 167: register int done; 168: register char *p; 169: char buf[256]; 170: 171: for (done = 0; fgets(buf, sizeof(buf), stdin);) { 172: /* skip lines that are too big */ 173: if (!index(buf, '\n')) { 174: fprintf(stderr, "passwd: line too long.\n"); 175: return(0); 176: } 177: if (done) { 178: fprintf(fp, "%s", buf); 179: continue; 180: } 181: if (!(p = index(buf, ':'))) { 182: fprintf(stderr, "passwd: corrupted entry.\n"); 183: return(0); 184: } 185: *p = '\0'; 186: if (strcmp(buf, name)) { 187: *p = ':'; 188: fprintf(fp, "%s", buf); 189: continue; 190: } 191: if (!(p = index(++p, ':'))) { 192: fprintf(stderr, "passwd: corrupted entry.\n"); 193: return(0); 194: } 195: /* 196: * reset change time to zero; when classes are implemented, 197: * go and get the "offset" value for this class and reset 198: * the timer. 199: */ 200: fprintf(fp, "%s:%s:%d:%d:%s:%ld:%ld:%s:%s:%s\n", 201: pw->pw_name, np, pw->pw_uid, pw->pw_gid, 202: pw->pw_class, 0L, pw->pw_expire, pw->pw_gecos, 203: pw->pw_dir, pw->pw_shell); 204: done = 1; 205: } 206: return(1); 207: } 208: 209: char * 210: getnewpasswd(pw, temp) 211: register struct passwd *pw; 212: char *temp; 213: { 214: register char *p, *t; 215: char buf[10], salt[2], *crypt(), *getpass(); 216: time_t time(); 217: 218: if (uid && pw->pw_passwd && 219: strcmp(crypt(getpass("Old password:"), pw->pw_passwd), 220: pw->pw_passwd)) { 221: (void)printf("passwd: %s.\n", strerror(EACCES)); 222: (void)unlink(temp); 223: exit(1); 224: } 225: 226: for (buf[0] = '\0';;) { 227: p = getpass("New password:"); 228: if (!*p) { 229: (void)printf("Password unchanged.\n"); 230: (void)unlink(temp); 231: exit(0); 232: } 233: if (strlen(p) <= 5) { 234: printf("Please enter a longer password.\n"); 235: continue; 236: } 237: for (t = p; *t && islower(*t); ++t); 238: if (!*t) { 239: printf("Please don't use an all-lower case password.\nUnusual capitalization, control characters or digits are suggested.\n"); 240: continue; 241: } 242: (void)strcpy(buf, p); 243: if (!strcmp(buf, getpass("Retype new password:"))) 244: break; 245: printf("Mismatch; try again, EOF to quit.\n"); 246: } 247: /* grab a random printable character that isn't a colon */ 248: (void)srandom((int)time((time_t *)NULL)); 249: while ((salt[0] = random() % 93 + 33) == ':'); 250: while ((salt[1] = random() % 93 + 33) == ':'); 251: return(crypt(buf, salt)); 252: } 253: 254: makedb(file) 255: char *file; 256: { 257: int status, pid, w; 258: 259: if (!(pid = vfork())) { 260: execl(_PATH_MKPASSWD, "mkpasswd", "-p", file, NULL); 261: _exit(127); 262: } 263: while ((w = wait(&status)) != pid && w != -1); 264: return(w == -1 || status); 265: }