- * Modify a field in the password file (either
- * password, login shell, or gecos field).
- * This program should be suid with an owner
- * with write permission on /etc/passwd.
- */
-#include <sys/types.h>
-#include <sys/file.h>
-#include <sys/time.h>
-#include <sys/resource.h>
-
-#include <stdio.h>
-#include <signal.h>
-#include <pwd.h>
-#include <ndbm.h>
-#include <errno.h>
-#include <strings.h>
-#include <ctype.h>
-
-char temp[] = "/etc/ptmp";
-char passwd[] = "/etc/passwd";
-char *getpass();
-char *getlogin();
-char *getfingerinfo();
-char *getloginshell();
-char *getnewpasswd();
-extern int errno;
-
-main(argc, argv)
- char *argv[];
-{
- struct passwd *pwd;
- char *cp, *uname, *progname;
- int fd, i, u, dochfn, dochsh;
- FILE *tf;
- DBM *dp;
-
- if ((progname = index(argv[0], '/')) == NULL)
- progname = argv[0];
- else
- progname++;
- dochfn = 0, dochsh = 0;
- argc--, argv++;
- while (argc > 0 && argv[0][0] == '-') {
- for (cp = &argv[0][1]; *cp; cp++) switch (*cp) {
-
- case 'f':
- if (dochsh)
- goto bad;
- dochfn = 1;
- break;
-
- case 's':
- if (dochfn) {
- bad:
- fprintf(stderr,
- "passwd: Only one of -f and -s allowed.\n");
- exit(1);
- }
- dochsh = 1;
- break;
-
- default:
- fprintf(stderr, "passwd: -%c: unknown option.\n", *cp);
- exit(1);
- }
- argc--, argv++;
- }
- if (!dochfn && !dochsh) {
- if (strcmp(progname, "chfn") == 0)
- dochfn = 1;
- else if (strcmp(progname, "chsh") == 0)
- dochsh = 1;
- }
- if (argc < 1) {
- if ((uname = getlogin()) == NULL) {
- fprintf(stderr, "Usage: %s [-f] [-s] [user]\n", progname);
- exit(1);
- }
- printf("Changing %s for %s.\n",
- dochfn ? "finger information" :
- dochsh ? "login shell" : "password",
- uname);
- } else
- uname = *argv;
- pwd = getpwnam(uname);
- if (pwd == NULL) {
- fprintf(stderr, "passwd: %s: unknown user.\n", uname);
- exit(1);
- }
- u = getuid();
- if (u != 0 && u != pwd->pw_uid) {
- printf("Permission denied.\n");
- exit(1);
- }
- if (dochfn)
- cp = getfingerinfo(pwd, u);
- else if (dochsh)
- cp = getloginshell(pwd, u);
- else
- cp = getnewpasswd(pwd, u);
- signal(SIGHUP, SIG_IGN);
- signal(SIGINT, SIG_IGN);
- signal(SIGQUIT, SIG_IGN);
- signal(SIGTSTP, SIG_IGN);
- (void) umask(0);
- fd = open(temp, O_WRONLY|O_CREAT|O_EXCL, 0644);
- if (fd < 0) {
- fprintf(stderr, "passwd: ");
- if (errno == EEXIST)
- fprintf(stderr, "password file busy - try again.\n");
- else
- perror(temp);
- exit(1);
- }
- if ((tf = fdopen(fd, "w")) == NULL) {
- fprintf(stderr, "passwd: fdopen failed?\n");
- exit(1);
- }
- if ((dp = dbm_open(passwd, O_RDWR, 0644)) == NULL) {
- fprintf(stderr, "Warning: dbm_open failed: ");
- perror(passwd);
- } else if (flock(dp->dbm_dirf, LOCK_EX) < 0) {
- perror("Warning: lock failed");
- dbm_close(dp);
- dp = NULL;
- }
- unlimit(RLIMIT_CPU);
- unlimit(RLIMIT_FSIZE);
- /*
- * Copy passwd to temp, replacing matching lines
- * with new password.
- */
- while ((pwd = getpwent()) != NULL) {
- if (strcmp(pwd->pw_name, uname) == 0) {
- if (u && u != pwd->pw_uid) {
- fprintf(stderr, "passwd: permission denied.\n");
- goto out;
- }
- if (dochfn)
- pwd->pw_gecos = cp;
- else if (dochsh)
- pwd->pw_shell = cp;
- else
- pwd->pw_passwd = cp;
- if (pwd->pw_gecos[0] == '*') /* ??? */
- pwd->pw_gecos++;
- replace(dp, pwd);
- }
- fprintf(tf,"%s:%s:%d:%d:%s:%s:%s\n",
- pwd->pw_name,
- pwd->pw_passwd,
- pwd->pw_uid,
- pwd->pw_gid,
- pwd->pw_gecos,
- pwd->pw_dir,
- pwd->pw_shell);
- }
- endpwent();
- (void) fclose(tf);
- if (dp != NULL && dbm_error(dp))
- fprintf(stderr, "Warning: dbm_store failed\n");
- dbm_close(dp);
- if (rename(temp, passwd) < 0) {
- fprintf(stderr, "passwd: "), perror("rename");
- out:
- unlink(temp);
- exit(1);
- }
- exit(0);
-}
-
-unlimit(lim)
-{
- struct rlimit rlim;
-
- rlim.rlim_cur = rlim.rlim_max = RLIM_INFINITY;
- (void) setrlimit(lim, &rlim);
-}
-
-/*
- * Replace the password entry in the dbm data base with pwd.