- if (use_kerberos) {
- exit(do_krb_passwd());
- /* NOTREACHED */
- }
-#endif
-
- if (!(pw = getpwnam(uname))) {
- fprintf(stderr, "passwd: unknown user %s.\n", uname);
- exit(1);
- }
- if (uid && uid != pw->pw_uid) {
- fprintf(stderr, "passwd: %s\n", strerror(EACCES));
- exit(1);
- }
-
- (void)signal(SIGHUP, SIG_IGN);
- (void)signal(SIGINT, SIG_IGN);
- (void)signal(SIGQUIT, SIG_IGN);
- (void)signal(SIGTSTP, SIG_IGN);
-
- rlim.rlim_cur = rlim.rlim_max = RLIM_INFINITY;
- (void)setrlimit(RLIMIT_CPU, &rlim);
- (void)setrlimit(RLIMIT_FSIZE, &rlim);
-
- (void)umask(0);
-
- temp = _PATH_PTMP;
- if ((fd = open(temp, O_WRONLY|O_CREAT|O_EXCL, 0600)) < 0) {
- if (errno == EEXIST) {
- fprintf(stderr,
- "passwd: password file busy -- try again later.\n");
- exit(0);
- }
- fprintf(stderr, "passwd: %s: %s", temp, strerror(errno));
- goto bad;
- }
- if (!(temp_fp = fdopen(fd, "w"))) {
- fprintf(stderr, "passwd: can't write %s", temp);
- goto bad;
- }
- passwd = _PATH_MASTERPASSWD;
- if (!freopen(passwd, "r", stdin)) {
- fprintf(stderr, "passwd: can't read %s", passwd);
- goto bad;
- }
-
- printf("Changing local password for %s.\n", pw->pw_name);
- np = getnewpasswd(pw, temp);
-
- if (!copy(pw->pw_name, np, temp_fp, pw))
- goto bad;
-
- (void)fclose(temp_fp);
- (void)fclose(stdin);
-
- switch(fork()) {
- case 0:
- break;
- case -1:
- fprintf(stderr, "passwd: can't fork");
- goto bad;
- /* NOTREACHED */
- default:
- exit(0);
- /* NOTREACHED */
- }
-
- if (makedb(temp)) {
- fprintf(stderr, "passwd: mkpasswd failed");
-bad: fprintf(stderr, "; password unchanged.\n");
- (void)unlink(temp);
- exit(1);
- }
-
- /*
- * possible race; have to rename four files, and someone could slip
- * in between them. LOCK_EX and rename the ``passwd.dir'' file first
- * so that getpwent(3) can't slip in; the lock should never fail and
- * it's unclear what to do if it does. Rename ``ptmp'' last so that
- * passwd/vipw/chpass can't slip in.
- */
- (void)setpriority(PRIO_PROCESS, 0, -20);
- fend = strcpy(from, temp) + strlen(temp);
- tend = strcpy(to, _PATH_PASSWD) + strlen(_PATH_PASSWD);
- bcopy(".dir", fend, 5);
- bcopy(".dir", tend, 5);
- if ((fd = open(from, O_RDONLY, 0)) >= 0)
- (void)flock(fd, LOCK_EX);
- /* here we go... */
- (void)rename(from, to);
- bcopy(".pag", fend, 5);
- bcopy(".pag", tend, 5);
- (void)rename(from, to);
- bcopy(".orig", fend, 6);
- (void)rename(from, _PATH_PASSWD);
- (void)rename(temp, passwd);
- /* done! */
- exit(0);
-}
-
-copy(name, np, fp, pw)
- char *name, *np;
- FILE *fp;
- struct passwd *pw;
-{
- register int done;
- register char *p;
- char buf[1024];
-
- for (done = 0; fgets(buf, sizeof(buf), stdin);) {
- /* skip lines that are too big */
- if (!index(buf, '\n')) {
- fprintf(stderr, "passwd: line too long.\n");
- return(0);
- }
- if (done) {
- fprintf(fp, "%s", buf);
- continue;
- }
- if (!(p = index(buf, ':'))) {
- fprintf(stderr, "passwd: corrupted entry.\n");
- return(0);
- }
- *p = '\0';
- if (strcmp(buf, name)) {
- *p = ':';
- fprintf(fp, "%s", buf);
- continue;
- }
- if (!(p = index(++p, ':'))) {
- fprintf(stderr, "passwd: corrupted entry.\n");
- return(0);
- }
- /*
- * reset change time to zero; when classes are implemented,
- * go and get the "offset" value for this class and reset
- * the timer.
- */
- fprintf(fp, "%s:%s:%d:%d:%s:%ld:%ld:%s:%s:%s\n",
- pw->pw_name, np, pw->pw_uid, pw->pw_gid,
- pw->pw_class, 0L, pw->pw_expire, pw->pw_gecos,
- pw->pw_dir, pw->pw_shell);
- done = 1;
- }
- return(1);
-}
-
-char *
-getnewpasswd(pw, temp)
- register struct passwd *pw;
- char *temp;
-{
- register char *p, *t;
- char buf[_PASSWORD_LEN+1], salt[2], *crypt(), *getpass();
- int tries = 0;
- time_t time();
-
- if (uid && pw->pw_passwd &&
- strcmp(crypt(getpass("Old password:"), pw->pw_passwd),
- pw->pw_passwd)) {
- (void)printf("passwd: %s.\n", strerror(EACCES));
- (void)unlink(temp);
- exit(1);
- }
-
- for (buf[0] = '\0';;) {
- p = getpass("New password:");
- if (!*p) {
- (void)printf("Password unchanged.\n");
- (void)unlink(temp);
- exit(0);
- }
- if (strlen(p) <= 5 && (uid != 0 || tries++ < 2)) {
- printf("Please enter a longer password.\n");
- continue;
- }
- for (t = p; *t && islower(*t); ++t);
- if (!*t && (uid != 0 || tries++ < 2)) {
- printf("Please don't use an all-lower case password.\nUnusual capitalization, control characters or digits are suggested.\n");
- continue;
- }
- (void)strcpy(buf, p);
- if (!strcmp(buf, getpass("Retype new password:")))
- break;
- printf("Mismatch; try again, EOF to quit.\n");
- }
- /* grab a random printable character that isn't a colon */
- (void)srandom((int)time((time_t *)NULL));
-#ifdef NEWSALT
- salt[0] = '_';
- to64(&salt[1], (long)(29*25), 4);
- to64(&salt[5], (long)random(), 4);
-#else
- to64(&salt[0], (long)random(), 2);