- }
- setusershell();
- for (;;)
- if (!(p = getusershell())) {
- (void)fprintf(stderr,
- "chpass: warning, unknown root shell.");
- break;
- }
- else if (!strcmp(pw->pw_shell, p))
- break;
- }
-
- passwd = _PATH_MASTERPASSWD;
- if (!freopen(passwd, "r", stdin)) {
- (void)fprintf(stderr, "chpass: can't read %s; ", passwd);
- goto bad;
- }
- if (!copy(pw, temp_fp))
- goto bad;
-
- (void)fclose(temp_fp);
- (void)fclose(stdin);
-
- switch(fork()) {
- case 0:
- break;
- case -1:
- (void)fprintf(stderr, "chpass: can't fork; ");
- goto bad;
- /* NOTREACHED */
- default:
- exit(0);
- /* NOTREACHED */
- }
-
- if (makedb(temp)) {
- (void)fprintf(stderr, "chpass: mkpasswd failed; ");
-bad: (void)fprintf(stderr, "%s unchanged.\n", _PATH_MASTERPASSWD);
- (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);
-}
-
-info(pw)
- struct passwd *pw;
-{
- struct stat begin, end;
- FILE *fp;
- int fd, rval;
- char *tfile;
-
- tfile = _PATH_TMP;
- if ((fd = mkstemp(tfile)) == -1 || !(fp = fdopen(fd, "w+"))) {
- (void)fprintf(stderr, "chpass: no temporary file");
- return(0);
- }
-
- /*
- * if print doesn't print out a shell field, make it restricted.
- * Not particularly pretty, but print is the routine that checks
- * to see if the user can change their shell.
- */
- if (!print(fp, pw))
- list[E_SHELL].restricted = 1;
- (void)fflush(fp);
-
- /*
- * give the file to the real user; setuid permissions
- * are discarded in edit()
- */
- (void)fchown(fd, getuid(), getgid());
-
- for (rval = 0;;) {
- (void)fstat(fd, &begin);
- if (edit(tfile)) {
- (void)fprintf(stderr, "chpass: edit failed; ");
- break;
- }
- (void)fstat(fd, &end);
- if (begin.st_mtime == end.st_mtime) {
- (void)fprintf(stderr, "chpass: no changes made; ");
- break;
- }
- (void)rewind(fp);
- if (check(fp, pw)) {
- rval = 1;
- break;
- }
- (void)fflush(stderr);
- if (prompt())
- break;