static void edit_file(int is_shadow) { struct stat begin, end; pw_init(); pw_lock(); if (stat(tmp_file, &begin)) pw_error(tmp_file, 1, 1); pw_edit(0); if (stat(tmp_file, &end)) pw_error(tmp_file, 1, 1); if (begin.st_mtime == end.st_mtime) { (void)fprintf(stderr, _("%s: no changes made\n"), progname); pw_error((char *)NULL, 0, 0); } if (!is_shadow) chmod(tmp_file, 0644); #if 0 /* if shadow file, then mode is 0600 now */ else chmod(tmp_file, 0400); #endif pw_unlock(); }
main() { register int pfd, tfd; struct stat begin, end; pw_init(); pfd = pw_lock(); tfd = pw_tmp(); copyfile(pfd, tfd); (void)close(tfd); for (;;) { if (stat(tempname, &begin)) pw_error(tempname, 1, 1); pw_edit(0); if (stat(tempname, &end)) pw_error(tempname, 1, 1); if (begin.st_mtime == end.st_mtime) { (void)fprintf(stderr, "vipw: no changes made\n"); pw_error((char *)NULL, 0, 0); } if (pw_mkdb()) break; pw_prompt(); } exit(0); }
/* * lock_files - lock the accounts databases * * lock_files() locks the group, gshadow, and passwd databases. */ static void lock_files (void) { if (gr_lock () == 0) { fprintf (stderr, _("%s: cannot lock %s; try again later.\n"), Prog, gr_dbname ()); exit (E_GRP_UPDATE); } add_cleanup (cleanup_unlock_group, NULL); #ifdef SHADOWGRP if ( is_shadow_grp && (pflg || nflg)) { if (sgr_lock () == 0) { fprintf (stderr, _("%s: cannot lock %s; try again later.\n"), Prog, sgr_dbname ()); exit (E_GRP_UPDATE); } add_cleanup (cleanup_unlock_gshadow, NULL); } #endif if (gflg) { if (pw_lock () == 0) { fprintf (stderr, _("%s: cannot lock %s; try again later.\n"), Prog, pw_dbname ()); exit (E_GRP_UPDATE); } add_cleanup (cleanup_unlock_passwd, NULL); } }
/* * open_files - open the shadow database * * In read-only mode, the databases are not locked and are opened * only for reading. */ static void open_files (void) { bool use_tcb = false; #ifdef WITH_TCB use_tcb = getdef_bool ("USE_TCB"); #endif /* WITH_TCB */ /* * Lock the files if we aren't in "read-only" mode */ if (!read_only) { if (pw_lock () == 0) { fprintf (stderr, _("%s: cannot lock %s; try again later.\n"), Prog, pw_dbname ()); fail_exit (E_CANTLOCK); } pw_locked = true; if (is_shadow && !use_tcb) { if (spw_lock () == 0) { fprintf (stderr, _("%s: cannot lock %s; try again later.\n"), Prog, spw_dbname ()); fail_exit (E_CANTLOCK); } spw_locked = true; } } /* * Open the files. Use O_RDONLY if we are in read_only mode, O_RDWR * otherwise. */ if (pw_open (read_only ? O_RDONLY : O_RDWR) == 0) { fprintf (stderr, _("%s: cannot open %s\n"), Prog, pw_dbname ()); if (use_system_pw_file) { SYSLOG ((LOG_WARN, "cannot open %s", pw_dbname ())); } fail_exit (E_CANTOPEN); } pw_opened = true; if (is_shadow && !use_tcb) { if (spw_open (read_only ? O_RDONLY : O_RDWR) == 0) { fprintf (stderr, _("%s: cannot open %s\n"), Prog, spw_dbname ()); if (use_system_spw_file) { SYSLOG ((LOG_WARN, "cannot open %s", spw_dbname ())); } fail_exit (E_CANTOPEN); } spw_opened = true; } }
static void open_files(void) { if (!pw_lock()) { fprintf(stderr, _("%s: unable to lock password file\n"), Prog); exit(E_PW_UPDATE); } if (! pw_open (O_RDWR)) { fprintf(stderr, _("%s: unable to open password file\n"), Prog); fail_exit(E_PW_UPDATE); } #ifdef SHADOWPWD if (is_shadow_pwd && ! spw_lock ()) { fprintf(stderr, _("%s: cannot lock shadow password file\n"), Prog); fail_exit(E_PW_UPDATE); } if (is_shadow_pwd && ! spw_open (O_RDWR)) { fprintf(stderr, _("%s: cannot open shadow password file\n"), Prog); fail_exit(E_PW_UPDATE); } #endif #ifdef HAVE_TCFS if (!tcfs_lock()) { fprintf(stderr, _("%s: cannot lock TCFS key file\n"), Prog); fail_exit(E_PW_UPDATE); } if (!tcfs_open(O_RDWR)) { fprintf(stderr, _("%s: cannot open TCFS key file\n"), Prog); fail_exit(E_PW_UPDATE); } #endif if (! gr_lock ()) { fprintf(stderr, _("%s: unable to lock group file\n"), Prog); fail_exit(E_GRP_UPDATE); } if (! gr_open (O_RDWR)) { fprintf(stderr, _("%s: cannot open group file\n"), Prog); fail_exit(E_GRP_UPDATE); } #ifdef SHADOWGRP if (is_shadow_grp && ! sgr_lock ()) { fprintf(stderr, _("%s: unable to lock shadow group file\n"), Prog); fail_exit(E_GRP_UPDATE); } if (is_shadow_grp && ! sgr_open (O_RDWR)) { fprintf(stderr, _("%s: cannot open shadow group file\n"), Prog); fail_exit(E_GRP_UPDATE); } #endif }
static void update_noshadow (void) { const struct passwd *pw; struct passwd *npw; if (pw_lock () == 0) { fprintf (stderr, _("%s: cannot lock %s; try again later.\n"), Prog, pw_dbname ()); exit (E_PWDBUSY); } pw_locked = true; if (pw_open (O_RDWR) == 0) { fprintf (stderr, _("%s: cannot open %s\n"), Prog, pw_dbname ()); SYSLOG ((LOG_WARN, "cannot open %s", pw_dbname ())); fail_exit (E_MISSING); } pw = pw_locate (name); if (NULL == pw) { fprintf (stderr, _("%s: user '%s' does not exist in %s\n"), Prog, name, pw_dbname ()); fail_exit (E_NOPERM); } npw = __pw_dup (pw); if (NULL == npw) { oom (); } npw->pw_passwd = update_crypt_pw (npw->pw_passwd); if (pw_update (npw) == 0) { fprintf (stderr, _("%s: failed to prepare the new %s entry '%s'\n"), Prog, pw_dbname (), npw->pw_name); fail_exit (E_FAILURE); } if (pw_close () == 0) { fprintf (stderr, _("%s: failure while writing changes to %s\n"), Prog, pw_dbname ()); SYSLOG ((LOG_ERR, "failure while writing changes to %s", pw_dbname ())); fail_exit (E_FAILURE); } if (pw_unlock () == 0) { fprintf (stderr, _("%s: failed to unlock %s\n"), Prog, pw_dbname ()); SYSLOG ((LOG_ERR, "failed to unlock %s", pw_dbname ())); /* continue */ } pw_locked = false; }
static int pw_update(struct passwd * pwd, char const * user) { struct passwd *pw = NULL; struct passwd *old_pw = NULL; int rc, pfd, tfd; if ((rc = pwdb_check()) != 0) return (rc); if (pwd != NULL) pw = pw_dup(pwd); if (user != NULL) old_pw = GETPWNAM(user); if (pw_init(conf.etcpath, NULL)) err(1, "pw_init()"); if ((pfd = pw_lock()) == -1) { pw_fini(); err(1, "pw_lock()"); } if ((tfd = pw_tmp(-1)) == -1) { pw_fini(); err(1, "pw_tmp()"); } if (pw_copy(pfd, tfd, pw, old_pw) == -1) { pw_fini(); close(tfd); err(1, "pw_copy()"); } fsync(tfd); close(tfd); /* * in case of deletion of a user, the whole database * needs to be regenerated */ if (pw_mkdb(pw != NULL ? pw->pw_name : NULL) == -1) { pw_fini(); err(1, "pw_mkdb()"); } free(pw); pw_fini(); return (0); }
/* * open_files - open the shadow database * * In read-only mode, the databases are not locked and are opened * only for reading. */ static void open_files (void) { /* * Lock the files if we aren't in "read-only" mode */ if (!read_only) { if (pw_lock () == 0) { fprintf (stderr, _("%s: cannot lock %s; try again later.\n"), Prog, pwd_file); fail_exit (E_CANTLOCK); } pw_locked = true; if (is_shadow) { if (spw_lock () == 0) { fprintf (stderr, _("%s: cannot lock %s; try again later.\n"), Prog, spw_file); fail_exit (E_CANTLOCK); } spw_locked = true; } } /* * Open the files. Use O_RDONLY if we are in read_only mode, O_RDWR * otherwise. */ if (pw_open (read_only ? O_RDONLY : O_RDWR) == 0) { fprintf (stderr, _("%s: cannot open %s\n"), Prog, pwd_file); if (use_system_pw_file) { SYSLOG ((LOG_WARN, "cannot open %s", pwd_file)); } fail_exit (E_CANTOPEN); } if (is_shadow && (spw_open (read_only ? O_RDONLY : O_RDWR) == 0)) { fprintf (stderr, _("%s: cannot open %s\n"), Prog, spw_file); if (use_system_spw_file) { SYSLOG ((LOG_WARN, "cannot open %s", spw_file)); } fail_exit (E_CANTOPEN); } }
/* * open_files - open the shadow database * * In read-only mode, the databases are not locked and are opened * only for reading. */ static void open_files (bool readonly) { /* * Lock and open the password file. This loads all of the password * file entries into memory. Then we get a pointer to the password * file entry for the requested user. */ if (!readonly) { if (pw_lock () == 0) { fprintf (stderr, _("%s: cannot lock %s; try again later.\n"), Prog, pw_dbname ()); fail_exit (E_NOPERM); } pw_locked = true; } if (pw_open (readonly ? O_RDONLY: O_RDWR) == 0) { fprintf (stderr, _("%s: cannot open %s\n"), Prog, pw_dbname ()); SYSLOG ((LOG_WARN, "cannot open %s", pw_dbname ())); fail_exit (E_NOPERM); } /* * For shadow password files we have to lock the file and read in * the entries as was done for the password file. The user entries * does not have to exist in this case; a new entry will be created * for this user if one does not exist already. */ if (!readonly) { if (spw_lock () == 0) { fprintf (stderr, _("%s: cannot lock %s; try again later.\n"), Prog, spw_dbname ()); fail_exit (E_NOPERM); } spw_locked = true; } if (spw_open (readonly ? O_RDONLY: O_RDWR) == 0) { fprintf (stderr, _("%s: cannot open %s\n"), Prog, spw_dbname ()); SYSLOG ((LOG_WARN, "cannot open %s", spw_dbname ())); fail_exit (E_NOPERM); } }
static int pw_update(struct passwd * pwd, char const * user) { int rc = 0; rc = pwdb("-C", (char *)NULL); /* Check only */ if (rc == 0) { int pfd, tfd; struct passwd *pw = NULL; struct passwd *old_pw = NULL; if (pwd != NULL) pw = pw_dup(pwd); if (user != NULL) old_pw = GETPWNAM(user); if (pw_init(pwpath, NULL)) err(1, "pw_init()"); if ((pfd = pw_lock()) == -1) { pw_fini(); err(1, "pw_lock()"); } if ((tfd = pw_tmp(-1)) == -1) { pw_fini(); err(1, "pw_tmp()"); } if (pw_copy(pfd, tfd, pw, old_pw) == -1) { pw_fini(); err(1, "pw_copy()"); } /* * in case of deletion of a user, the whole database * needs to be regenerated */ if (pw_mkdb(pw != NULL ? pw->pw_name : NULL) == -1) { pw_fini(); err(1, "pw_mkdb()"); } free(pw); pw_fini(); } return 0; }
static int pw_nisupdate(const char * path, struct passwd * pwd, char const * user) { int pfd, tfd; struct passwd *pw = NULL; struct passwd *old_pw = NULL; printf("===> %s\n", path); if (pwd != NULL) pw = pw_dup(pwd); if (user != NULL) old_pw = GETPWNAM(user); if (pw_init(NULL, path)) err(1,"pw_init()"); if ((pfd = pw_lock()) == -1) { pw_fini(); err(1, "pw_lock()"); } if ((tfd = pw_tmp(-1)) == -1) { pw_fini(); err(1, "pw_tmp()"); } if (pw_copy(pfd, tfd, pw, old_pw) == -1) { pw_fini(); close(tfd); err(1, "pw_copy()"); } close(tfd); if (chmod(pw_tempname(), 0644) == -1) err(1, "chmod()"); if (rename(pw_tempname(), path) == -1) err(1, "rename()"); free(pw); pw_fini(); return (0); }
/* * open_files - lock and open the password databases */ static void open_files (void) { /* * Lock the password file and open it for reading and writing. This * will bring all of the entries into memory where they may be updated. */ if (pw_lock () == 0) { fprintf (stderr, _("%s: cannot lock %s; try again later.\n"), Prog, pw_dbname ()); fail_exit (1); } pw_locked = true; if (pw_open (O_RDWR) == 0) { fprintf (stderr, _("%s: cannot open %s\n"), Prog, pw_dbname ()); fail_exit (1); } /* Do the same for the shadowed database, if it exist */ if (is_shadow_pwd) { if (spw_lock () == 0) { fprintf (stderr, _("%s: cannot lock %s; try again later.\n"), Prog, spw_dbname ()); fail_exit (1); } spw_locked = true; if (spw_open (O_RDWR) == 0) { fprintf (stderr, _("%s: cannot open %s\n"), Prog, spw_dbname ()); fail_exit (1); } } }
/* * chfn - change a user's password file information * * This command controls the GECOS field information in the password * file entry. * * The valid options are * * -f full name * -r room number * -w work phone number * -h home phone number * -o other information (*) * * (*) requires root permission to execute. */ int main (int argc, char **argv) { char *cp; /* temporary character pointer */ const struct passwd *pw; /* password file entry */ struct passwd pwent; /* modified password file entry */ char old_gecos[BUFSIZ]; /* buffer for old GECOS fields */ char new_gecos[BUFSIZ]; /* buffer for new GECOS fields */ int flag; /* flag currently being processed */ int fflg = 0; /* -f - set full name */ int rflg = 0; /* -r - set room number */ int wflg = 0; /* -w - set work phone number */ int hflg = 0; /* -h - set home phone number */ int oflg = 0; /* -o - set other information */ char *user; #ifdef USE_PAM pam_handle_t *pamh = NULL; struct passwd *pampw; int retval; #endif sanitize_env (); setlocale (LC_ALL, ""); bindtextdomain (PACKAGE, LOCALEDIR); textdomain (PACKAGE); /* * This command behaves different for root and non-root * users. */ amroot = (getuid () == 0); /* * Get the program name. The program name is used as a * prefix to most error messages. */ Prog = Basename (argv[0]); OPENLOG ("chfn"); /* * The remaining arguments will be processed one by one and executed * by this command. The name is the last argument if it does not * begin with a "-", otherwise the name is determined from the * environment and must agree with the real UID. Also, the UID will * be checked for any commands which are restricted to root only. */ while ((flag = getopt (argc, argv, "f:r:w:h:o:")) != EOF) { switch (flag) { case 'f': if (!may_change_field ('f')) { fprintf (stderr, _("%s: Permission denied.\n"), Prog); exit (E_NOPERM); } fflg++; STRFCPY (fullnm, optarg); break; case 'h': if (!may_change_field ('h')) { fprintf (stderr, _("%s: Permission denied.\n"), Prog); exit (E_NOPERM); } hflg++; STRFCPY (homeph, optarg); break; case 'r': if (!may_change_field ('r')) { fprintf (stderr, _("%s: Permission denied.\n"), Prog); exit (E_NOPERM); } rflg++; STRFCPY (roomno, optarg); break; case 'o': if (!amroot) { fprintf (stderr, _("%s: Permission denied.\n"), Prog); exit (E_NOPERM); } oflg++; STRFCPY (slop, optarg); break; case 'w': if (!may_change_field ('w')) { fprintf (stderr, _("%s: Permission denied.\n"), Prog); exit (E_NOPERM); } wflg++; STRFCPY (workph, optarg); break; default: usage (); } } /* * Get the name of the user to check. It is either the command line * name, or the name getlogin() returns. */ if (optind < argc) { user = argv[optind]; pw = getpwnam (user); if (!pw) { fprintf (stderr, _("%s: unknown user %s\n"), Prog, user); exit (E_NOPERM); } } else { pw = get_my_pwent (); if (!pw) { fprintf (stderr, _ ("%s: Cannot determine your user name.\n"), Prog); exit (E_NOPERM); } user = xstrdup (pw->pw_name); } #ifdef USE_NIS /* * Now we make sure this is a LOCAL password entry for this user ... */ if (__ispwNIS ()) { char *nis_domain; char *nis_master; fprintf (stderr, _("%s: cannot change user `%s' on NIS client.\n"), Prog, user); if (!yp_get_default_domain (&nis_domain) && !yp_master (nis_domain, "passwd.byname", &nis_master)) { fprintf (stderr, _ ("%s: `%s' is the NIS master for this client.\n"), Prog, nis_master); } exit (E_NOPERM); } #endif /* * Non-privileged users are only allowed to change the gecos field * if the UID of the user matches the current real UID. */ if (!amroot && pw->pw_uid != getuid ()) { fprintf (stderr, _("%s: Permission denied.\n"), Prog); closelog (); exit (E_NOPERM); } #ifdef WITH_SELINUX /* * If the UID of the user does not match the current real UID, * check if the change is allowed by SELinux policy. */ if ((pw->pw_uid != getuid ()) && (selinux_check_passwd_access (PASSWD__CHFN) != 0)) { fprintf (stderr, _("%s: Permission denied.\n"), Prog); closelog (); exit (E_NOPERM); } #endif #ifndef USE_PAM /* * Non-privileged users are optionally authenticated (must enter the * password of the user whose information is being changed) before * any changes can be made. Idea from util-linux chfn/chsh. * --marekm */ if (!amroot && getdef_bool ("CHFN_AUTH")) passwd_check (pw->pw_name, pw->pw_passwd, "chfn"); #else /* !USE_PAM */ retval = PAM_SUCCESS; pampw = getpwuid (getuid ()); if (pampw == NULL) { retval = PAM_USER_UNKNOWN; } if (retval == PAM_SUCCESS) { retval = pam_start ("chfn", pampw->pw_name, &conv, &pamh); } if (retval == PAM_SUCCESS) { retval = pam_authenticate (pamh, 0); if (retval != PAM_SUCCESS) { pam_end (pamh, retval); } } if (retval == PAM_SUCCESS) { retval = pam_acct_mgmt (pamh, 0); if (retval != PAM_SUCCESS) { pam_end (pamh, retval); } } if (retval != PAM_SUCCESS) { fprintf (stderr, _("%s: PAM authentication failed\n"), Prog); exit (E_NOPERM); } #endif /* USE_PAM */ /* * Now get the full name. It is the first comma separated field in * the GECOS field. */ STRFCPY (old_gecos, pw->pw_gecos); cp = copy_field (old_gecos, fflg ? (char *) 0 : fullnm, slop); /* * Now get the room number. It is the next comma separated field, * if there is indeed one. */ if (cp) cp = copy_field (cp, rflg ? (char *) 0 : roomno, slop); /* * Now get the work phone number. It is the third field. */ if (cp) cp = copy_field (cp, wflg ? (char *) 0 : workph, slop); /* * Now get the home phone number. It is the fourth field. */ if (cp) cp = copy_field (cp, hflg ? (char *) 0 : homeph, slop); /* * Anything left over is "slop". */ if (cp && !oflg) { if (slop[0]) strcat (slop, ","); strcat (slop, cp); } /* * If none of the fields were changed from the command line, let the * user interactively change them. */ if (!fflg && !rflg && !wflg && !hflg && !oflg) { printf (_("Changing the user information for %s\n"), user); new_fields (); } /* * Check all of the fields for valid information */ if (valid_field (fullnm, ":,=")) { fprintf (stderr, _("%s: invalid name: \"%s\"\n"), Prog, fullnm); closelog (); exit (E_NOPERM); } if (valid_field (roomno, ":,=")) { fprintf (stderr, _("%s: invalid room number: \"%s\"\n"), Prog, roomno); closelog (); exit (E_NOPERM); } if (valid_field (workph, ":,=")) { fprintf (stderr, _("%s: invalid work phone: \"%s\"\n"), Prog, workph); closelog (); exit (E_NOPERM); } if (valid_field (homeph, ":,=")) { fprintf (stderr, _("%s: invalid home phone: \"%s\"\n"), Prog, homeph); closelog (); exit (E_NOPERM); } if (valid_field (slop, ":")) { fprintf (stderr, _("%s: \"%s\" contains illegal characters\n"), Prog, slop); closelog (); exit (E_NOPERM); } /* * Build the new GECOS field by plastering all the pieces together, * if they will fit ... */ if (strlen (fullnm) + strlen (roomno) + strlen (workph) + strlen (homeph) + strlen (slop) > (unsigned int) 80) { fprintf (stderr, _("%s: fields too long\n"), Prog); closelog (); exit (E_NOPERM); } snprintf (new_gecos, sizeof new_gecos, "%s,%s,%s,%s%s%s", fullnm, roomno, workph, homeph, slop[0] ? "," : "", slop); /* * Before going any further, raise the ulimit to prevent colliding * into a lowered ulimit, and set the real UID to root to protect * against unexpected signals. Any keyboard signals are set to be * ignored. */ if (setuid (0)) { fprintf (stderr, _("Cannot change ID to root.\n")); SYSLOG ((LOG_ERR, "can't setuid(0)")); closelog (); exit (E_NOPERM); } pwd_init (); /* * The passwd entry is now ready to be committed back to the * password file. Get a lock on the file and open it. */ if (!pw_lock ()) { fprintf (stderr, _ ("Cannot lock the password file; try again later.\n")); SYSLOG ((LOG_WARN, "can't lock /etc/passwd")); closelog (); exit (E_NOPERM); } if (!pw_open (O_RDWR)) { fprintf (stderr, _("Cannot open the password file.\n")); pw_unlock (); SYSLOG ((LOG_ERR, "can't open /etc/passwd")); closelog (); exit (E_NOPERM); } /* * Get the entry to update using pw_locate() - we want the real one * from /etc/passwd, not the one from getpwnam() which could contain * the shadow password if (despite the warnings) someone enables * AUTOSHADOW (or SHADOW_COMPAT in libc). --marekm */ pw = pw_locate (user); if (!pw) { pw_unlock (); fprintf (stderr, _("%s: %s not found in /etc/passwd\n"), Prog, user); exit (E_NOPERM); } /* * Make a copy of the entry, then change the gecos field. The other * fields remain unchanged. */ pwent = *pw; pwent.pw_gecos = new_gecos; /* * Update the passwd file entry. If there is a DBM file, update that * entry as well. */ if (!pw_update (&pwent)) { fprintf (stderr, _("Error updating the password entry.\n")); pw_unlock (); SYSLOG ((LOG_ERR, "error updating passwd entry")); closelog (); exit (E_NOPERM); } /* * Changes have all been made, so commit them and unlock the file. */ if (!pw_close ()) { fprintf (stderr, _("Cannot commit password file changes.\n")); pw_unlock (); SYSLOG ((LOG_ERR, "can't rewrite /etc/passwd")); closelog (); exit (E_NOPERM); } if (!pw_unlock ()) { fprintf (stderr, _("Cannot unlock the password file.\n")); SYSLOG ((LOG_ERR, "can't unlock /etc/passwd")); closelog (); exit (E_NOPERM); } SYSLOG ((LOG_INFO, "changed user `%s' information", user)); nscd_flush_cache ("passwd"); #ifdef USE_PAM if (retval == PAM_SUCCESS) pam_end (pamh, PAM_SUCCESS); #endif /* USE_PAM */ closelog (); exit (E_SUCCESS); }
/* * open_files - lock and open the password, group and shadow databases */ static void open_files (void) { /* * Lock the password files and open them for update. This will bring * all of the entries into memory where they may be searched for an * modified, or new entries added. The password file is the key - if * it gets locked, assume the others can be locked right away. */ if (pw_lock () == 0) { fprintf (stderr, _("%s: cannot lock %s; try again later.\n"), Prog, pw_dbname ()); fail_exit (EXIT_FAILURE); } pw_locked = true; if (is_shadow) { if (spw_lock () == 0) { fprintf (stderr, _("%s: cannot lock %s; try again later.\n"), Prog, spw_dbname ()); fail_exit (EXIT_FAILURE); } spw_locked = true; } if (gr_lock () == 0) { fprintf (stderr, _("%s: cannot lock %s; try again later.\n"), Prog, gr_dbname ()); fail_exit (EXIT_FAILURE); } gr_locked = true; #ifdef SHADOWGRP if (is_shadow_grp) { if (sgr_lock () == 0) { fprintf (stderr, _("%s: cannot lock %s; try again later.\n"), Prog, sgr_dbname ()); fail_exit (EXIT_FAILURE); } sgr_locked = true; } #endif #ifdef ENABLE_SUBIDS if (is_sub_uid) { if (sub_uid_lock () == 0) { fprintf (stderr, _("%s: cannot lock %s; try again later.\n"), Prog, sub_uid_dbname ()); fail_exit (EXIT_FAILURE); } sub_uid_locked = true; } if (is_sub_gid) { if (sub_gid_lock () == 0) { fprintf (stderr, _("%s: cannot lock %s; try again later.\n"), Prog, sub_gid_dbname ()); fail_exit (EXIT_FAILURE); } sub_gid_locked = true; } #endif /* ENABLE_SUBIDS */ if (pw_open (O_CREAT | O_RDWR) == 0) { fprintf (stderr, _("%s: cannot open %s\n"), Prog, pw_dbname ()); fail_exit (EXIT_FAILURE); } if (is_shadow && (spw_open (O_CREAT | O_RDWR) == 0)) { fprintf (stderr, _("%s: cannot open %s\n"), Prog, spw_dbname ()); fail_exit (EXIT_FAILURE); } if (gr_open (O_CREAT | O_RDWR) == 0) { fprintf (stderr, _("%s: cannot open %s\n"), Prog, gr_dbname ()); fail_exit (EXIT_FAILURE); } #ifdef SHADOWGRP if (is_shadow_grp && (sgr_open (O_CREAT | O_RDWR) == 0)) { fprintf (stderr, _("%s: cannot open %s\n"), Prog, sgr_dbname ()); fail_exit (EXIT_FAILURE); } #endif #ifdef ENABLE_SUBIDS if (is_sub_uid) { if (sub_uid_open (O_CREAT | O_RDWR) == 0) { fprintf (stderr, _("%s: cannot open %s\n"), Prog, sub_uid_dbname ()); fail_exit (EXIT_FAILURE); } } if (is_sub_gid) { if (sub_gid_open (O_CREAT | O_RDWR) == 0) { fprintf (stderr, _("%s: cannot open %s\n"), Prog, sub_gid_dbname ()); fail_exit (EXIT_FAILURE); } } #endif /* ENABLE_SUBIDS */ }
int main (int argc, char **argv) { const struct passwd *pw; struct passwd pwent; const struct spwd *spwd; #ifdef ATT_AGE char newage[5]; #endif char *Prog = argv[0]; setlocale (LC_ALL, ""); bindtextdomain (PACKAGE, LOCALEDIR); textdomain (PACKAGE); if (!spw_file_present ()) /* shadow not installed, do nothing */ exit (0); if (!pw_lock ()) { fprintf (stderr, _("%s: can't lock passwd file\n"), Prog); fail_exit (5); } passwd_locked++; if (!pw_open (O_RDWR)) { fprintf (stderr, _("%s: can't open passwd file\n"), Prog); fail_exit (1); } if (!spw_lock ()) { fprintf (stderr, _("%s: can't open shadow file\n"), Prog); fail_exit (5); } shadow_locked++; if (!spw_open (O_RDWR)) { fprintf (stderr, _("%s: can't open shadow file\n"), Prog); fail_exit (1); } pw_rewind (); while ((pw = pw_next ())) { if (!(spwd = spw_locate (pw->pw_name))) continue; pwent = *pw; /* * Update password if non-shadow is "x". */ if (strcmp (pw->pw_passwd, SHADOW_PASSWD_STRING) == 0) pwent.pw_passwd = spwd->sp_pwdp; /* * Password aging works differently in the two different * systems. With shadow password files you apparently must * have some aging information. The maxweeks or minweeks * may not map exactly. In pwconv we set max == 10000, * which is about 30 years. Here we have to undo that * kludge. So, if maxdays == 10000, no aging information is * put into the new file. Otherwise, the days are converted * to weeks and so on. */ #ifdef ATT_AGE if (spwd->sp_max > (63 * WEEK / SCALE) && spwd->sp_max < 10000) spwd->sp_max = (63 * WEEK / SCALE); /* 10000 is infinity */ if (spwd->sp_min >= 0 && spwd->sp_min <= 63 * 7 && spwd->sp_max >= 0 && spwd->sp_max <= 63 * 7) { if (spwd->sp_lstchg == -1) spwd->sp_lstchg = 0; spwd->sp_max /= WEEK / SCALE; /* turn it into weeks */ spwd->sp_min /= WEEK / SCALE; spwd->sp_lstchg /= WEEK / SCALE; strncpy (newage, l64a (spwd->sp_lstchg * (64L * 64L) + spwd->sp_min * (64L) + spwd->sp_max), 5); pwent.pw_age = newage; } else pwent.pw_age = ""; #endif /* ATT_AGE */ if (!pw_update (&pwent)) { fprintf (stderr, _("%s: can't update entry for user %s\n"), Prog, pwent.pw_name); fail_exit (3); } } if (!spw_close ()) { fprintf (stderr, _("%s: can't update shadow password file\n"), Prog); fail_exit (3); } if (!pw_close ()) { fprintf (stderr, _("%s: can't update password file\n"), Prog); fail_exit (3); } if (unlink (SHADOW) != 0) { fprintf (stderr, _("%s: can't delete shadow password file\n"), Prog); fail_exit (3); } spw_unlock (); pw_unlock (); return 0; }
int main(int argc, char *argv[]) { const char *passwd_dir = NULL; int ch, pfd, tfd; char *line; size_t len; while ((ch = getopt(argc, argv, "d:")) != -1) switch (ch) { case 'd': passwd_dir = optarg; break; case '?': default: usage(); } argc -= optind; argv += optind; if (argc != 0) usage(); if (pw_init(passwd_dir, NULL) == -1) err(1, "pw_init()"); if ((pfd = pw_lock()) == -1) { pw_fini(); err(1, "pw_lock()"); } if ((tfd = pw_tmp(pfd)) == -1) { pw_fini(); err(1, "pw_tmp()"); } close(tfd); /* Force umask for partial writes made in the edit phase */ umask(077); for (;;) { switch (pw_edit(0)) { case -1: pw_fini(); err(1, "pw_edit()"); case 0: pw_fini(); errx(0, "no changes made"); default: break; } if (pw_mkdb(NULL) == 0) { pw_fini(); errx(0, "password list updated"); } printf("re-edit the password file? "); fflush(stdout); if ((line = fgetln(stdin, &len)) == NULL) { pw_fini(); err(1, "fgetln()"); } if (len > 0 && (*line == 'N' || *line == 'n')) break; } pw_fini(); exit(0); }
/* * update_gecos - update the gecos fields in the password database * * Commit the user's entry after changing her gecos field. */ static void update_gecos (const char *user, char *gecos) { const struct passwd *pw; /* The user's password file entry */ struct passwd pwent; /* modified password file entry */ /* * Before going any further, raise the ulimit to prevent colliding * into a lowered ulimit, and set the real UID to root to protect * against unexpected signals. Any keyboard signals are set to be * ignored. */ if (setuid (0) != 0) { fputs (_("Cannot change ID to root.\n"), stderr); SYSLOG ((LOG_ERR, "can't setuid(0)")); fail_exit (E_NOPERM); } pwd_init (); /* * The passwd entry is now ready to be committed back to the * password file. Get a lock on the file and open it. */ if (pw_lock () == 0) { fprintf (stderr, _("%s: cannot lock %s; try again later.\n"), Prog, pw_dbname ()); fail_exit (E_NOPERM); } pw_locked = true; if (pw_open (O_RDWR) == 0) { fprintf (stderr, _("%s: cannot open %s\n"), Prog, pw_dbname ()); fail_exit (E_NOPERM); } /* * Get the entry to update using pw_locate() - we want the real one * from /etc/passwd, not the one from getpwnam() which could contain * the shadow password if (despite the warnings) someone enables * AUTOSHADOW (or SHADOW_COMPAT in libc). --marekm */ pw = pw_locate (user); if (NULL == pw) { fprintf (stderr, _("%s: user '%s' does not exist in %s\n"), Prog, user, pw_dbname ()); fail_exit (E_NOPERM); } /* * Make a copy of the entry, then change the gecos field. The other * fields remain unchanged. */ pwent = *pw; pwent.pw_gecos = gecos; /* * Update the passwd file entry. If there is a DBM file, update that * entry as well. */ if (pw_update (&pwent) == 0) { fprintf (stderr, _("%s: failed to prepare the new %s entry '%s'\n"), Prog, pw_dbname (), pwent.pw_name); fail_exit (E_NOPERM); } /* * Changes have all been made, so commit them and unlock the file. */ if (pw_close () == 0) { fprintf (stderr, _("%s: failure while writing changes to %s\n"), Prog, pw_dbname ()); SYSLOG ((LOG_ERR, "failure while writing changes to %s", pw_dbname ())); fail_exit (E_NOPERM); } if (pw_unlock () == 0) { fprintf (stderr, _("%s: failed to unlock %s\n"), Prog, pw_dbname ()); SYSLOG ((LOG_ERR, "failed to unlock %s", pw_dbname ())); /* continue */ } pw_locked = false; }
static void open_files (void) { if (pw_lock () == 0) { fprintf (stderr, _("%s: cannot lock %s; try again later.\n"), Prog, pw_dbname ()); #ifdef WITH_AUDIT audit_logger (AUDIT_DEL_USER, Prog, "locking password file", user_name, (unsigned int) user_id, SHADOW_AUDIT_FAILURE); #endif /* WITH_AUDIT */ fail_exit (E_PW_UPDATE); } pw_locked = true; if (pw_open (O_CREAT | O_RDWR) == 0) { fprintf (stderr, _("%s: cannot open %s\n"), Prog, pw_dbname ()); #ifdef WITH_AUDIT audit_logger (AUDIT_DEL_USER, Prog, "opening password file", user_name, (unsigned int) user_id, SHADOW_AUDIT_FAILURE); #endif /* WITH_AUDIT */ fail_exit (E_PW_UPDATE); } if (is_shadow_pwd) { if (spw_lock () == 0) { fprintf (stderr, _("%s: cannot lock %s; try again later.\n"), Prog, spw_dbname ()); #ifdef WITH_AUDIT audit_logger (AUDIT_DEL_USER, Prog, "locking shadow password file", user_name, (unsigned int) user_id, SHADOW_AUDIT_FAILURE); #endif /* WITH_AUDIT */ fail_exit (E_PW_UPDATE); } spw_locked = true; if (spw_open (O_CREAT | O_RDWR) == 0) { fprintf (stderr, _("%s: cannot open %s\n"), Prog, spw_dbname ()); #ifdef WITH_AUDIT audit_logger (AUDIT_DEL_USER, Prog, "opening shadow password file", user_name, (unsigned int) user_id, SHADOW_AUDIT_FAILURE); #endif /* WITH_AUDIT */ fail_exit (E_PW_UPDATE); } } if (gr_lock () == 0) { fprintf (stderr, _("%s: cannot lock %s; try again later.\n"), Prog, gr_dbname ()); #ifdef WITH_AUDIT audit_logger (AUDIT_DEL_USER, Prog, "locking group file", user_name, (unsigned int) user_id, SHADOW_AUDIT_FAILURE); #endif /* WITH_AUDIT */ fail_exit (E_GRP_UPDATE); } gr_locked = true; if (gr_open (O_CREAT | O_RDWR) == 0) { fprintf (stderr, _("%s: cannot open %s\n"), Prog, gr_dbname ()); #ifdef WITH_AUDIT audit_logger (AUDIT_DEL_USER, Prog, "opening group file", user_name, (unsigned int) user_id, SHADOW_AUDIT_FAILURE); #endif /* WITH_AUDIT */ fail_exit (E_GRP_UPDATE); } #ifdef SHADOWGRP if (is_shadow_grp) { if (sgr_lock () == 0) { fprintf (stderr, _("%s: cannot lock %s; try again later.\n"), Prog, sgr_dbname ()); #ifdef WITH_AUDIT audit_logger (AUDIT_DEL_USER, Prog, "locking shadow group file", user_name, (unsigned int) user_id, SHADOW_AUDIT_FAILURE); #endif /* WITH_AUDIT */ fail_exit (E_GRP_UPDATE); } sgr_locked= true; if (sgr_open (O_CREAT | O_RDWR) == 0) { fprintf (stderr, _("%s: cannot open %s\n"), Prog, sgr_dbname ()); #ifdef WITH_AUDIT audit_logger (AUDIT_DEL_USER, Prog, "opening shadow group file", user_name, (unsigned int) user_id, SHADOW_AUDIT_FAILURE); #endif /* WITH_AUDIT */ fail_exit (E_GRP_UPDATE); } } #endif /* SHADOWGRP */ #ifdef ENABLE_SUBIDS if (is_sub_uid) { if (sub_uid_lock () == 0) { fprintf (stderr, _("%s: cannot lock %s; try again later.\n"), Prog, sub_uid_dbname ()); #ifdef WITH_AUDIT audit_logger (AUDIT_DEL_USER, Prog, "locking subordinate user file", user_name, (unsigned int) user_id, SHADOW_AUDIT_FAILURE); #endif /* WITH_AUDIT */ fail_exit (E_SUB_UID_UPDATE); } sub_uid_locked = true; if (sub_uid_open (O_CREAT | O_RDWR) == 0) { fprintf (stderr, _("%s: cannot open %s\n"), Prog, sub_uid_dbname ()); #ifdef WITH_AUDIT audit_logger (AUDIT_DEL_USER, Prog, "opening subordinate user file", user_name, (unsigned int) user_id, SHADOW_AUDIT_FAILURE); #endif /* WITH_AUDIT */ fail_exit (E_SUB_UID_UPDATE); } } if (is_sub_gid) { if (sub_gid_lock () == 0) { fprintf (stderr, _("%s: cannot lock %s; try again later.\n"), Prog, sub_gid_dbname ()); #ifdef WITH_AUDIT audit_logger (AUDIT_DEL_USER, Prog, "locking subordinate group file", user_name, (unsigned int) user_id, SHADOW_AUDIT_FAILURE); #endif /* WITH_AUDIT */ fail_exit (E_SUB_GID_UPDATE); } sub_gid_locked = true; if (sub_gid_open (O_CREAT | O_RDWR) == 0) { fprintf (stderr, _("%s: cannot open %s\n"), Prog, sub_gid_dbname ()); #ifdef WITH_AUDIT audit_logger (AUDIT_DEL_USER, Prog, "opening subordinate group file", user_name, (unsigned int) user_id, SHADOW_AUDIT_FAILURE); #endif /* WITH_AUDIT */ fail_exit (E_SUB_GID_UPDATE); } } #endif /* ENABLE_SUBIDS */ }
int main (int argc, char **argv) { const struct passwd *pw; struct passwd pwent; const struct spwd *sp; struct spwd spent; Prog = Basename (argv[0]); (void) setlocale (LC_ALL, ""); (void) bindtextdomain (PACKAGE, LOCALEDIR); (void) textdomain (PACKAGE); process_root_flag ("-R", argc, argv); OPENLOG ("pwconv"); process_flags (argc, argv); #ifdef WITH_TCB if (getdef_bool("USE_TCB")) { fprintf (stderr, _("%s: can't work with tcb enabled\n"), Prog); exit (E_FAILURE); } #endif /* WITH_TCB */ if (pw_lock () == 0) { fprintf (stderr, _("%s: cannot lock %s; try again later.\n"), Prog, pw_dbname ()); fail_exit (E_PWDBUSY); } pw_locked = true; if (pw_open (O_RDWR) == 0) { fprintf (stderr, _("%s: cannot open %s\n"), Prog, pw_dbname ()); fail_exit (E_MISSING); } if (spw_lock () == 0) { fprintf (stderr, _("%s: cannot lock %s; try again later.\n"), Prog, spw_dbname ()); fail_exit (E_PWDBUSY); } spw_locked = true; if (spw_open (O_CREAT | O_RDWR) == 0) { fprintf (stderr, _("%s: cannot open %s\n"), Prog, spw_dbname ()); fail_exit (E_FAILURE); } /* * Remove /etc/shadow entries for users not in /etc/passwd. */ (void) spw_rewind (); while ((sp = spw_next ()) != NULL) { if (pw_locate (sp->sp_namp) != NULL) { continue; } if (spw_remove (sp->sp_namp) == 0) { /* * This shouldn't happen (the entry exists) but... */ fprintf (stderr, _("%s: cannot remove entry '%s' from %s\n"), Prog, sp->sp_namp, spw_dbname ()); fail_exit (E_FAILURE); } } /* * Update shadow entries which don't have "x" as pw_passwd. Add any * missing shadow entries. */ (void) pw_rewind (); while ((pw = pw_next ()) != NULL) { sp = spw_locate (pw->pw_name); if (NULL != sp) { /* do we need to update this entry? */ if (strcmp (pw->pw_passwd, SHADOW_PASSWD_STRING) == 0) { continue; } /* update existing shadow entry */ spent = *sp; } else { /* add new shadow entry */ memset (&spent, 0, sizeof spent); spent.sp_namp = pw->pw_name; spent.sp_min = getdef_num ("PASS_MIN_DAYS", -1); spent.sp_max = getdef_num ("PASS_MAX_DAYS", -1); spent.sp_warn = getdef_num ("PASS_WARN_AGE", -1); spent.sp_inact = -1; spent.sp_expire = -1; spent.sp_flag = SHADOW_SP_FLAG_UNSET; } spent.sp_pwdp = pw->pw_passwd; spent.sp_lstchg = (long) time ((time_t *) 0) / SCALE; if (0 == spent.sp_lstchg) { /* Better disable aging than requiring a password * change */ spent.sp_lstchg = -1; } if (spw_update (&spent) == 0) { fprintf (stderr, _("%s: failed to prepare the new %s entry '%s'\n"), Prog, spw_dbname (), spent.sp_namp); fail_exit (E_FAILURE); } /* remove password from /etc/passwd */ pwent = *pw; pwent.pw_passwd = SHADOW_PASSWD_STRING; /* XXX warning: const */ if (pw_update (&pwent) == 0) { fprintf (stderr, _("%s: failed to prepare the new %s entry '%s'\n"), Prog, pw_dbname (), pwent.pw_name); fail_exit (E_FAILURE); } } if (spw_close () == 0) { fprintf (stderr, _("%s: failure while writing changes to %s\n"), Prog, spw_dbname ()); SYSLOG ((LOG_ERR, "failure while writing changes to %s", spw_dbname ())); fail_exit (E_FAILURE); } if (pw_close () == 0) { fprintf (stderr, _("%s: failure while writing changes to %s\n"), Prog, pw_dbname ()); SYSLOG ((LOG_ERR, "failure while writing changes to %s", pw_dbname ())); fail_exit (E_FAILURE); } /* /etc/passwd- (backup file) */ if (chmod (PASSWD_FILE "-", 0600) != 0) { fprintf (stderr, _("%s: failed to change the mode of %s to 0600\n"), Prog, PASSWD_FILE "-"); SYSLOG ((LOG_ERR, "failed to change the mode of %s to 0600", PASSWD_FILE "-")); /* continue */ } if (pw_unlock () == 0) { fprintf (stderr, _("%s: failed to unlock %s\n"), Prog, pw_dbname ()); SYSLOG ((LOG_ERR, "failed to unlock %s", pw_dbname ())); /* continue */ } if (spw_unlock () == 0) { fprintf (stderr, _("%s: failed to unlock %s\n"), Prog, spw_dbname ()); SYSLOG ((LOG_ERR, "failed to unlock %s", spw_dbname ())); /* continue */ } nscd_flush_cache ("passwd"); return E_SUCCESS; }
int main(int argc, char *argv[]) { struct passwd *pw = NULL, *opw = NULL, lpw; int i, ch, pfd, tfd, dfd; char *tz, *arg = NULL; sigset_t fullset; #ifdef YP use_yp = _yp_check(NULL); #endif /* We need to use the system timezone for date conversions. */ if ((tz = getenv("TZ")) != NULL) { unsetenv("TZ"); tzset(); setenv("TZ", tz, 1); } op = EDITENTRY; while ((ch = getopt(argc, argv, "a:s:ly")) != -1) switch(ch) { case 'a': op = LOADENTRY; arg = optarg; break; case 's': op = NEWSH; arg = optarg; break; #ifdef YP case 'l': use_yp = 0; break; case 'y': if (!use_yp) { warnx("YP not in use."); usage(); } force_yp = 1; break; #endif case '?': default: usage(); } argc -= optind; argv += optind; #ifdef YP if (op == LOADENTRY && use_yp) errx(1, "cannot load using YP, use -l to load local."); #endif uid = getuid(); if (op == EDITENTRY || op == NEWSH) switch(argc) { case 0: pw = getpwuid(uid); #ifdef YP if (pw && !force_yp) use_yp = 0; else if (use_yp) pw = ypgetpwuid(uid); #endif /* YP */ if (!pw) errx(1, "unknown user: uid %u", uid); break; case 1: pw = getpwnam(*argv); #ifdef YP if (pw && !force_yp) use_yp = 0; else if (use_yp) pw = ypgetpwnam(*argv); #endif /* YP */ if (!pw) errx(1, "unknown user: %s", *argv); if (uid && uid != pw->pw_uid) baduser(); break; default: usage(); } if (op == LOADENTRY) { if (argc != 0) errx(1, "option -a does not accept user argument"); if (uid) baduser(); pw = &lpw; if (!pw_scan(arg, pw, NULL)) exit(1); opw = getpwnam(pw->pw_name); } if (opw == NULL && (opw = pw_dup(pw)) == NULL) err(1, NULL); /* Edit the user passwd information if requested. */ if (op == EDITENTRY) { char tempname[] = _PATH_VARTMP "pw.XXXXXXXXXX"; int edit_status; if ((pw = pw_dup(pw)) == NULL) pw_error(NULL, 1, 1); dfd = mkstemp(tempname); if (dfd == -1 || fcntl(dfd, F_SETFD, 1) == -1) pw_error(tempname, 1, 1); display(tempname, dfd, pw); edit_status = edit(tempname, pw); close(dfd); unlink(tempname); switch (edit_status) { case EDIT_OK: break; case EDIT_NOCHANGE: pw_error(NULL, 0, 0); break; case EDIT_ERROR: default: pw_error(tempname, 1, 1); break; } } if (op == NEWSH) { /* protect p_shell -- it thinks NULL is /bin/sh */ if (!arg[0]) usage(); if (p_shell(arg, pw, NULL)) pw_error(NULL, 0, 1); } /* Drop user's real uid and block all signals to avoid a DoS. */ setuid(0); sigfillset(&fullset); sigdelset(&fullset, SIGINT); sigprocmask(SIG_BLOCK, &fullset, NULL); /* Get the passwd lock file and open the passwd file for reading. */ pw_init(); for (i = 1; (tfd = pw_lock(0)) == -1; i++) { if (i == 4) (void)fputs("Attempting to lock password file, " "please wait or press ^C to abort", stderr); (void)signal(SIGINT, kbintr); if (i % 16 == 0) fputc('.', stderr); usleep(250000); (void)signal(SIGINT, SIG_IGN); } if (i >= 4) fputc('\n', stderr); pfd = open(_PATH_MASTERPASSWD, O_RDONLY, 0); if (pfd == -1 || fcntl(pfd, F_SETFD, 1) == -1) pw_error(_PATH_MASTERPASSWD, 1, 1); #ifdef YP if (use_yp) { if (pw_yp(pw, uid)) pw_error(NULL, 0, 1); else { pw_abort(); exit(0); } } else #endif /* YP */ { /* Copy the passwd file to the lock file, updating pw. */ pw_copy(pfd, tfd, pw, opw); /* If username changed we need to rebuild the entire db. */ arg = !strcmp(opw->pw_name, pw->pw_name) ? pw->pw_name : NULL; /* Now finish the passwd file update. */ if (pw_mkdb(arg, 0) == -1) pw_error(NULL, 0, 1); } exit(0); }
int main(int argc, char *argv[]) { enum { NEWSH, LOADENTRY, EDITENTRY, NEWPW, NEWEXP } op; struct passwd lpw, *old_pw, *pw; int ch, pfd, tfd; const char *password; char *arg = NULL; uid_t uid; #ifdef YP struct ypclnt *ypclnt; const char *yp_domain = NULL, *yp_host = NULL; #endif pw = old_pw = NULL; op = EDITENTRY; #ifdef YP while ((ch = getopt(argc, argv, "a:p:s:e:d:h:loy")) != -1) #else while ((ch = getopt(argc, argv, "a:p:s:e:")) != -1) #endif switch (ch) { case 'a': op = LOADENTRY; arg = optarg; break; case 's': op = NEWSH; arg = optarg; break; case 'p': op = NEWPW; arg = optarg; break; case 'e': op = NEWEXP; arg = optarg; break; #ifdef YP case 'd': yp_domain = optarg; break; case 'h': yp_host = optarg; break; case 'l': case 'o': case 'y': /* compatibility */ break; #endif case '?': default: usage(); } argc -= optind; argv += optind; if (argc > 1) usage(); uid = getuid(); if (op == EDITENTRY || op == NEWSH || op == NEWPW || op == NEWEXP) { if (argc == 0) { if ((pw = getpwuid(uid)) == NULL) errx(1, "unknown user: uid %lu", (unsigned long)uid); } else { if ((pw = getpwnam(*argv)) == NULL) errx(1, "unknown user: %s", *argv); if (uid != 0 && uid != pw->pw_uid) baduser(); } /* Make a copy for later verification */ if ((pw = pw_dup(pw)) == NULL || (old_pw = pw_dup(pw)) == NULL) err(1, "pw_dup"); } #ifdef YP if (pw != NULL && (pw->pw_fields & _PWF_SOURCE) == _PWF_NIS) { ypclnt = ypclnt_new(yp_domain, "passwd.byname", yp_host); master_mode = (ypclnt != NULL && ypclnt_connect(ypclnt) != -1 && ypclnt_havepasswdd(ypclnt) == 1); ypclnt_free(ypclnt); } else #endif master_mode = (uid == 0); if (op == NEWSH) { /* protect p_shell -- it thinks NULL is /bin/sh */ if (!arg[0]) usage(); if (p_shell(arg, pw, (ENTRY *)NULL) == -1) exit(1); } if (op == NEWEXP) { if (uid) /* only root can change expire */ baduser(); if (p_expire(arg, pw, (ENTRY *)NULL) == -1) exit(1); } if (op == LOADENTRY) { if (uid) baduser(); pw = &lpw; old_pw = NULL; if (!__pw_scan(arg, pw, _PWSCAN_WARN|_PWSCAN_MASTER)) exit(1); } if (op == NEWPW) { if (uid) baduser(); if (strchr(arg, ':')) errx(1, "invalid format for password"); pw->pw_passwd = arg; } if (op == EDITENTRY) { /* * We don't really need pw_*() here, but pw_edit() (used * by edit()) is just too useful... */ if (pw_init(NULL, NULL)) err(1, "pw_init()"); if ((tfd = pw_tmp(-1)) == -1) { pw_fini(); err(1, "pw_tmp()"); } free(pw); pw = edit(pw_tempname(), old_pw); pw_fini(); if (pw == NULL) err(1, "edit()"); /* * pw_equal does not check for crypted passwords, so we * should do it explicitly */ if (pw_equal(old_pw, pw) && strcmp(old_pw->pw_passwd, pw->pw_passwd) == 0) errx(0, "user information unchanged"); } if (old_pw && !master_mode) { password = getpass("Password: "******""; } if (old_pw != NULL) pw->pw_fields |= (old_pw->pw_fields & _PWF_SOURCE); switch (pw->pw_fields & _PWF_SOURCE) { #ifdef YP case _PWF_NIS: ypclnt = ypclnt_new(yp_domain, "passwd.byname", yp_host); if (ypclnt == NULL) { warnx("ypclnt_new failed"); exit(1); } if (ypclnt_connect(ypclnt) == -1 || ypclnt_passwd(ypclnt, pw, password) == -1) { warnx("%s", ypclnt->error); ypclnt_free(ypclnt); exit(1); } ypclnt_free(ypclnt); errx(0, "NIS user information updated"); #endif /* YP */ case 0: case _PWF_FILES: if (pw_init(NULL, NULL)) err(1, "pw_init()"); if ((pfd = pw_lock()) == -1) { pw_fini(); err(1, "pw_lock()"); } if ((tfd = pw_tmp(-1)) == -1) { pw_fini(); err(1, "pw_tmp()"); } if (pw_copy(pfd, tfd, pw, old_pw) == -1) { pw_fini(); err(1, "pw_copy"); } if (pw_mkdb(pw->pw_name) == -1) { pw_fini(); err(1, "pw_mkdb()"); } pw_fini(); errx(0, "user information updated"); break; default: errx(1, "unsupported passwd source"); } }
int main(int argc, char **argv) { char *cp; /* temporary character pointer */ const struct passwd *pw; /* password file entry */ struct passwd pwent; /* modified password file entry */ char old_gecos[BUFSIZ]; /* buffer for old GECOS fields */ char new_gecos[BUFSIZ]; /* buffer for new GECOS fields */ int flag; /* flag currently being processed */ int fflg = 0; /* -f - set full name */ int rflg = 0; /* -r - set room number */ int wflg = 0; /* -w - set work phone number */ int hflg = 0; /* -h - set home phone number */ int oflg = 0; /* -o - set other information */ char *user; sanitize_env(); setlocale(LC_ALL, ""); bindtextdomain(PACKAGE, LOCALEDIR); textdomain(PACKAGE); /* * This command behaves different for root and non-root * users. */ amroot = (getuid () == 0); #ifdef NDBM pw_dbm_mode = O_RDWR; #endif /* * Get the program name. The program name is used as a * prefix to most error messages. It is also used as input * to the openlog() function for error logging. */ Prog = Basename(argv[0]); openlog("chfn", LOG_PID, LOG_AUTH); /* * The remaining arguments will be processed one by one and * executed by this command. The name is the last argument * if it does not begin with a "-", otherwise the name is * determined from the environment and must agree with the * real UID. Also, the UID will be checked for any commands * which are restricted to root only. */ while ((flag = getopt (argc, argv, "f:r:w:h:o:")) != EOF) { switch (flag) { case 'f': if (!may_change_field('f')) { fprintf(stderr, _("%s: Permission denied.\n"), Prog); exit(1); } fflg++; STRFCPY(fullnm, optarg); break; case 'r': if (!may_change_field('r')) { fprintf(stderr, _("%s: Permission denied.\n"), Prog); exit(1); } rflg++; STRFCPY(roomno, optarg); break; case 'w': if (!may_change_field('w')) { fprintf(stderr, _("%s: Permission denied.\n"), Prog); exit(1); } wflg++; STRFCPY(workph, optarg); break; case 'h': if (!may_change_field('h')) { fprintf(stderr, _("%s: Permission denied.\n"), Prog); exit(1); } hflg++; STRFCPY(homeph, optarg); break; case 'o': if (!amroot) { fprintf(stderr, _("%s: Permission denied.\n"), Prog); exit(1); } oflg++; STRFCPY(slop, optarg); break; default: usage(); } } /* * Get the name of the user to check. It is either * the command line name, or the name getlogin() * returns. */ if (optind < argc) { user = argv[optind]; pw = getpwnam(user); if (!pw) { fprintf(stderr, _("%s: Unknown user %s\n"), Prog, user); exit(1); } } else { pw = get_my_pwent(); if (!pw) { fprintf(stderr, _("%s: Cannot determine your user name.\n"), Prog); exit(1); } user = xstrdup(pw->pw_name); } #ifdef USE_NIS /* * Now we make sure this is a LOCAL password entry for * this user ... */ if (__ispwNIS ()) { char *nis_domain; char *nis_master; fprintf (stderr, _("%s: cannot change user `%s' on NIS client.\n"), Prog, user); if (! yp_get_default_domain (&nis_domain) && ! yp_master (nis_domain, "passwd.byname", &nis_master)) { fprintf (stderr, _("%s: `%s' is the NIS master for this client.\n"), Prog, nis_master); } exit (1); } #endif /* * Non-privileged users are only allowed to change the * gecos field if the UID of the user matches the current * real UID. */ if (!amroot && pw->pw_uid != getuid()) { fprintf (stderr, _("%s: Permission denied.\n"), Prog); closelog(); exit(1); } /* * Non-privileged users are optionally authenticated * (must enter the password of the user whose information * is being changed) before any changes can be made. * Idea from util-linux chfn/chsh. --marekm */ if (!amroot && getdef_bool("CHFN_AUTH")) passwd_check(pw->pw_name, pw->pw_passwd, "chfn"); /* * Now get the full name. It is the first comma separated field * in the GECOS field. */ STRFCPY(old_gecos, pw->pw_gecos); cp = copy_field (old_gecos, fflg ? (char *) 0:fullnm, slop); /* * Now get the room number. It is the next comma separated field, * if there is indeed one. */ if (cp) cp = copy_field (cp, rflg ? (char *) 0:roomno, slop); /* * Now get the work phone number. It is the third field. */ if (cp) cp = copy_field (cp, wflg ? (char *) 0:workph, slop); /* * Now get the home phone number. It is the fourth field. */ if (cp) cp = copy_field (cp, hflg ? (char *) 0:homeph, slop); /* * Anything left over is "slop". */ if (cp && !oflg) { if (slop[0]) strcat (slop, ","); strcat (slop, cp); } /* * If none of the fields were changed from the command line, * let the user interactively change them. */ if (!fflg && !rflg && !wflg && !hflg && !oflg) { printf(_("Changing the user information for %s\n"), user); new_fields(); } /* * Check all of the fields for valid information */ if (valid_field(fullnm, ":,=")) { fprintf(stderr, _("%s: invalid name: \"%s\"\n"), Prog, fullnm); closelog(); exit(1); } if (valid_field(roomno, ":,=")) { fprintf(stderr, _("%s: invalid room number: \"%s\"\n"), Prog, roomno); closelog(); exit(1); } if (valid_field(workph, ":,=")) { fprintf(stderr, _("%s: invalid work phone: \"%s\"\n"), Prog, workph); closelog(); exit(1); } if (valid_field (homeph, ":,=")) { fprintf(stderr, _("%s: invalid home phone: \"%s\"\n"), Prog, homeph); closelog(); exit(1); } if (valid_field(slop, ":")) { fprintf(stderr, _("%s: \"%s\" contains illegal characters\n"), Prog, slop); closelog(); exit(1); } /* * Build the new GECOS field by plastering all the pieces together, * if they will fit ... */ if (strlen(fullnm) + strlen(roomno) + strlen(workph) + strlen(homeph) + strlen(slop) > (unsigned int) 80) { fprintf(stderr, _("%s: fields too long\n"), Prog); closelog(); exit(1); } snprintf(new_gecos, sizeof new_gecos, "%s,%s,%s,%s%s%s", fullnm, roomno, workph, homeph, slop[0] ? "," : "", slop); /* * Before going any further, raise the ulimit to prevent * colliding into a lowered ulimit, and set the real UID * to root to protect against unexpected signals. Any * keyboard signals are set to be ignored. */ if (setuid(0)) { fprintf(stderr, _("Cannot change ID to root.\n")); SYSLOG((LOG_ERR, NOTROOT2)); closelog(); exit(1); } pwd_init(); /* * The passwd entry is now ready to be committed back to * the password file. Get a lock on the file and open it. */ if (!pw_lock()) { fprintf(stderr, _("Cannot lock the password file; try again later.\n")); SYSLOG((LOG_WARN, PWDBUSY2)); closelog(); exit(1); } if (!pw_open(O_RDWR)) { fprintf(stderr, _("Cannot open the password file.\n")); pw_unlock(); SYSLOG((LOG_ERR, OPNERROR2)); closelog(); exit(1); } /* * Get the entry to update using pw_locate() - we want the real * one from /etc/passwd, not the one from getpwnam() which could * contain the shadow password if (despite the warnings) someone * enables AUTOSHADOW (or SHADOW_COMPAT in libc). --marekm */ pw = pw_locate(user); if (!pw) { pw_unlock(); fprintf(stderr, _("%s: %s not found in /etc/passwd\n"), Prog, user); exit(1); } /* * Make a copy of the entry, then change the gecos field. The other * fields remain unchanged. */ pwent = *pw; pwent.pw_gecos = new_gecos; /* * Update the passwd file entry. If there is a DBM file, * update that entry as well. */ if (!pw_update(&pwent)) { fprintf(stderr, _("Error updating the password entry.\n")); pw_unlock(); SYSLOG((LOG_ERR, UPDERROR2)); closelog(); exit(1); } #ifdef NDBM if (pw_dbm_present() && !pw_dbm_update(&pwent)) { fprintf(stderr, _("Error updating the DBM password entry.\n")); pw_unlock (); SYSLOG((LOG_ERR, DBMERROR2)); closelog(); exit(1); } endpwent(); #endif /* * Changes have all been made, so commit them and unlock the * file. */ if (!pw_close()) { fprintf(stderr, _("Cannot commit password file changes.\n")); pw_unlock(); SYSLOG((LOG_ERR, CLSERROR2)); closelog(); exit(1); } if (!pw_unlock()) { fprintf(stderr, _("Cannot unlock the password file.\n")); SYSLOG((LOG_ERR, UNLKERROR2)); closelog(); exit(1); } SYSLOG((LOG_INFO, CHGGECOS, user)); closelog(); exit (0); }
static int pw_update(struct passwd * pwd, char const * user) { int rc = 0; /* * First, let's check the see if the database is alright * Note: -C is only available in FreeBSD 2.2 and above */ #ifdef HAVE_PWDB_C rc = pwdb("-C", (char *)NULL); /* Check only */ if (rc == 0) { #else { /* No -C */ #endif int pfd, tfd; struct passwd *pw = NULL; struct passwd *old_pw = NULL; if (pwd != NULL) pw = pw_dup(pwd); if (user != NULL) old_pw = GETPWNAM(user); if (pw_init(pwpath, NULL)) err(1, "pw_init()"); if ((pfd = pw_lock()) == -1) { pw_fini(); err(1, "pw_lock()"); } if ((tfd = pw_tmp(-1)) == -1) { pw_fini(); err(1, "pw_tmp()"); } if (pw_copy(pfd, tfd, pw, old_pw) == -1) { pw_fini(); err(1, "pw_copy()"); } if (pw_mkdb(user) == -1) { pw_fini(); err(1, "pw_mkdb()"); } free(pw); pw_fini(); } return 0; } int addpwent(struct passwd * pwd) { return pw_update(pwd, NULL); } int chgpwent(char const * login, struct passwd * pwd) { return pw_update(pwd, login); } int delpwent(struct passwd * pwd) { char login[MAXLOGNAME]; strlcpy(login, pwd->pw_name, MAXLOGNAME); return pw_update(NULL, login); }
/* * process_flags - perform command line argument setting * * process_flags() interprets the command line arguments and sets the * values that the user will be created with accordingly. The values * are checked for sanity. */ static void process_flags (int argc, char **argv) { const struct group *grp; const struct passwd *pwd; const struct spwd *spwd = NULL; int anyflag = 0; int arg; if (argc == 1 || argv[argc - 1][0] == '-') usage (); if (!(pwd = getpwnam (argv[argc - 1]))) { fprintf (stderr, _("%s: user %s does not exist\n"), Prog, argv[argc - 1]); exit (E_NOTFOUND); } user_name = argv[argc - 1]; user_id = pwd->pw_uid; user_gid = pwd->pw_gid; user_comment = xstrdup (pwd->pw_gecos); user_home = xstrdup (pwd->pw_dir); user_shell = xstrdup (pwd->pw_shell); #ifdef WITH_AUDIT user_newname = user_name; user_newid = user_id; user_newgid = user_gid; user_newcomment = user_comment; user_newhome = user_home; user_newshell = user_shell; #endif #ifdef USE_NIS /* * Now make sure it isn't an NIS user. */ if (__ispwNIS ()) { char *nis_domain; char *nis_master; fprintf (stderr, _("%s: user %s is a NIS user\n"), Prog, user_name); if (!yp_get_default_domain (&nis_domain) && !yp_master (nis_domain, "passwd.byname", &nis_master)) { fprintf (stderr, _("%s: %s is the NIS master\n"), Prog, nis_master); } exit (E_NOTFOUND); } #endif if (is_shadow_pwd && (spwd = getspnam (user_name))) { user_expire = spwd->sp_expire; user_inactive = spwd->sp_inact; #ifdef WITH_AUDIT user_newexpire = user_expire; user_newinactive = user_inactive; #endif } { /* * Parse the command line options. */ int c; static struct option long_options[] = { {"append", required_argument, NULL, 'a'}, {"comment", required_argument, NULL, 'c'}, {"home", required_argument, NULL, 'd'}, {"expiredate", required_argument, NULL, 'e'}, {"inactive", required_argument, NULL, 'f'}, {"gid", required_argument, NULL, 'g'}, {"groups", required_argument, NULL, 'G'}, {"help", no_argument, NULL, 'h'}, {"login", required_argument, NULL, 'l'}, {"lock", no_argument, NULL, 'L'}, {"move-home", no_argument, NULL, 'm'}, {"non-unique", no_argument, NULL, 'o'}, {"password", required_argument, NULL, 'p'}, {"shell", required_argument, NULL, 's'}, {"uid", required_argument, NULL, 'u'}, {"unlock", no_argument, NULL, 'U'}, {NULL, 0, NULL, '\0'} }; while ((c = getopt_long (argc, argv, "ac:d:e:f:g:G:l:Lmop:s:u:U", long_options, NULL)) != -1) { switch (c) { case 'a': aflg++; break; case 'c': if (!VALID (optarg)) { fprintf (stderr, _("%s: invalid field `%s'\n"), Prog, optarg); exit (E_BAD_ARG); } #ifdef WITH_AUDIT user_newcomment = optarg; #else user_comment = optarg; #endif cflg++; break; case 'd': if (!VALID (optarg)) { fprintf (stderr, _("%s: invalid field `%s'\n"), Prog, optarg); exit (E_BAD_ARG); } dflg++; user_newhome = optarg; break; case 'e': if (*optarg) { #ifdef WITH_AUDIT user_newexpire = strtoday (optarg); if (user_newexpire == -1) { #else user_expire = strtoday (optarg); if (user_expire == -1) { #endif fprintf (stderr, _ ("%s: invalid date `%s'\n"), Prog, optarg); exit (E_BAD_ARG); } #ifdef WITH_AUDIT user_newexpire *= DAY / SCALE; #else user_expire *= DAY / SCALE; #endif } else #ifdef WITH_AUDIT user_newexpire = -1; #else user_expire = -1; #endif eflg++; break; case 'f': #ifdef WITH_AUDIT user_newinactive = get_number (optarg); #else user_inactive = get_number (optarg); #endif fflg++; break; case 'g': grp = getgr_nam_gid (optarg); if (!grp) { fprintf (stderr, _("%s: unknown group %s\n"), Prog, optarg); exit (E_NOTFOUND); } user_newgid = grp->gr_gid; gflg++; break; case 'G': if (get_groups (optarg)) exit (E_NOTFOUND); Gflg++; break; case 'l': if (!check_user_name (optarg)) { fprintf (stderr, _("%s: invalid field `%s'\n"), Prog, optarg); exit (E_BAD_ARG); } /* * If the name does not really change, we mustn't * set the flag as this will cause rather serious * problems later! */ if (strcmp (user_name, optarg)) lflg++; user_newname = optarg; break; case 'L': if (Uflg || pflg) usage (); Lflg++; break; case 'm': if (!dflg) usage (); mflg++; break; case 'o': if (!uflg) usage (); oflg++; break; case 'p': if (Lflg || Uflg) usage (); user_pass = optarg; pflg++; break; case 's': if (!VALID (optarg)) { fprintf (stderr, _("%s: invalid field `%s'\n"), Prog, optarg); exit (E_BAD_ARG); } #ifdef WITH_AUDIT user_newshell = optarg; #else user_shell = optarg; #endif sflg++; break; case 'u': user_newid = get_id (optarg); uflg++; break; case 'U': if (Lflg && pflg) usage (); Uflg++; break; default: usage (); } anyflag++; } } if (anyflag == 0) { fprintf (stderr, _("%s: no flags given\n"), Prog); exit (E_USAGE); } if (!is_shadow_pwd && (eflg || fflg)) { fprintf (stderr, _ ("%s: shadow passwords required for -e and -f\n"), Prog); exit (E_USAGE); } if (optind != argc - 1) usage (); if (aflg && (!Gflg)) { fprintf (stderr, _("%s: -a flag is ONLY allowed with the -G flag\n"), Prog); usage (); exit (E_USAGE); } if (dflg && strcmp (user_home, user_newhome) == 0) dflg = mflg = 0; if (uflg && user_id == user_newid) uflg = oflg = 0; if (lflg && getpwnam (user_newname)) { fprintf (stderr, _("%s: user %s exists\n"), Prog, user_newname); exit (E_NAME_IN_USE); } if (uflg && !oflg && getpwuid (user_newid)) { fprintf (stderr, _("%s: uid %lu is not unique\n"), Prog, (unsigned long) user_newid); exit (E_UID_IN_USE); } } /* * close_files - close all of the files that were opened * * close_files() closes all of the files that were opened for this new * user. This causes any modified entries to be written out. */ static void close_files (void) { if (!pw_close ()) { fprintf (stderr, _("%s: cannot rewrite password file\n"), Prog); fail_exit (E_PW_UPDATE); } if (is_shadow_pwd && !spw_close ()) { fprintf (stderr, _("%s: cannot rewrite shadow password file\n"), Prog); fail_exit (E_PW_UPDATE); } if (is_shadow_pwd) spw_unlock (); (void) pw_unlock (); /* * Close the DBM and/or flat files */ endpwent (); endspent (); endgrent (); #ifdef SHADOWGRP endsgent (); #endif } /* * open_files - lock and open the password files * * open_files() opens the two password files. */ static void open_files (void) { if (!pw_lock ()) { fprintf (stderr, _("%s: unable to lock password file\n"), Prog); exit (E_PW_UPDATE); } if (!pw_open (O_RDWR)) { fprintf (stderr, _("%s: unable to open password file\n"), Prog); fail_exit (E_PW_UPDATE); } if (is_shadow_pwd && !spw_lock ()) { fprintf (stderr, _("%s: cannot lock shadow password file\n"), Prog); fail_exit (E_PW_UPDATE); } if (is_shadow_pwd && !spw_open (O_RDWR)) { fprintf (stderr, _("%s: cannot open shadow password file\n"), Prog); fail_exit (E_PW_UPDATE); } } /* * usr_update - create the user entries * * usr_update() creates the password file entries for this user and * will update the group entries if required. */ static void usr_update (void) { struct passwd pwent; const struct passwd *pwd; struct spwd spent; const struct spwd *spwd = NULL; /* * Locate the entry in /etc/passwd, which MUST exist. */ pwd = pw_locate (user_name); if (!pwd) { fprintf (stderr, _("%s: %s not found in /etc/passwd\n"), Prog, user_name); fail_exit (E_NOTFOUND); } pwent = *pwd; new_pwent (&pwent); /* * Locate the entry in /etc/shadow. It doesn't have to exist, and * won't be created if it doesn't. */ if (is_shadow_pwd && (spwd = spw_locate (user_name))) { spent = *spwd; new_spent (&spent); } if (lflg || uflg || gflg || cflg || dflg || sflg || pflg || Lflg || Uflg) { if (!pw_update (&pwent)) { fprintf (stderr, _("%s: error changing password entry\n"), Prog); fail_exit (E_PW_UPDATE); } if (lflg && !pw_remove (user_name)) { fprintf (stderr, _("%s: error removing password entry\n"), Prog); fail_exit (E_PW_UPDATE); } } if (spwd && (lflg || eflg || fflg || pflg || Lflg || Uflg)) { if (!spw_update (&spent)) { fprintf (stderr, _ ("%s: error adding new shadow password entry\n"), Prog); fail_exit (E_PW_UPDATE); } if (lflg && !spw_remove (user_name)) { fprintf (stderr, _ ("%s: error removing shadow password entry\n"), Prog); fail_exit (E_PW_UPDATE); } } } /* * move_home - move the user's home directory * * move_home() moves the user's home directory to a new location. The * files will be copied if the directory cannot simply be renamed. */ static void move_home (void) { struct stat sb; if (mflg && stat (user_home, &sb) == 0) { /* * Don't try to move it if it is not a directory * (but /dev/null for example). --marekm */ if (!S_ISDIR (sb.st_mode)) return; if (access (user_newhome, F_OK) == 0) { fprintf (stderr, _("%s: directory %s exists\n"), Prog, user_newhome); fail_exit (E_HOMEDIR); } else if (rename (user_home, user_newhome)) { if (errno == EXDEV) { if (mkdir (user_newhome, sb.st_mode & 0777)) { fprintf (stderr, _ ("%s: can't create %s\n"), Prog, user_newhome); } if (chown (user_newhome, sb.st_uid, sb.st_gid)) { fprintf (stderr, _("%s: can't chown %s\n"), Prog, user_newhome); rmdir (user_newhome); fail_exit (E_HOMEDIR); } if (copy_tree (user_home, user_newhome, uflg ? user_newid : -1, gflg ? user_newgid : -1) == 0) { if (remove_tree (user_home) != 0 || rmdir (user_home) != 0) fprintf (stderr, _ ("%s: warning: failed to completely remove old home directory %s"), Prog, user_home); #ifdef WITH_AUDIT audit_logger (AUDIT_USER_CHAUTHTOK, Prog, "moving home directory", user_newname, user_newid, 1); #endif return; } (void) remove_tree (user_newhome); (void) rmdir (user_newhome); } fprintf (stderr, _ ("%s: cannot rename directory %s to %s\n"), Prog, user_home, user_newhome); fail_exit (E_HOMEDIR); } #ifdef WITH_AUDIT audit_logger (AUDIT_USER_CHAUTHTOK, Prog, "moving home directory", user_newname, user_newid, 1); #endif } if (uflg || gflg) { #ifdef WITH_AUDIT audit_logger (AUDIT_USER_CHAUTHTOK, Prog, "changing home directory owner", user_newname, user_newid, 1); #endif chown (dflg ? user_newhome : user_home, uflg ? user_newid : user_id, gflg ? user_newgid : user_gid); } } /* * update_files - update the lastlog and faillog files */ static void update_files (void) { struct lastlog ll; struct faillog fl; int fd; /* * Relocate the "lastlog" entries for the user. The old entry is * left alone in case the UID was shared. It doesn't hurt anything * to just leave it be. */ if ((fd = open (LASTLOG_FILE, O_RDWR)) != -1) { lseek (fd, (off_t) user_id * sizeof ll, SEEK_SET); if (read (fd, (char *) &ll, sizeof ll) == sizeof ll) { lseek (fd, (off_t) user_newid * sizeof ll, SEEK_SET); write (fd, (char *) &ll, sizeof ll); } close (fd); } /* * Relocate the "faillog" entries in the same manner. */ if ((fd = open (FAILLOG_FILE, O_RDWR)) != -1) { lseek (fd, (off_t) user_id * sizeof fl, SEEK_SET); if (read (fd, (char *) &fl, sizeof fl) == sizeof fl) { lseek (fd, (off_t) user_newid * sizeof fl, SEEK_SET); write (fd, (char *) &fl, sizeof fl); } close (fd); } } #ifndef NO_MOVE_MAILBOX /* * This is the new and improved code to carefully chown/rename the user's * mailbox. Maybe I am too paranoid but the mail spool dir sometimes * happens to be mode 1777 (this makes mail user agents work without * being setgid mail, but is NOT recommended; they all should be fixed * to use movemail). --marekm */ static void move_mailbox (void) { const char *maildir; char mailfile[1024], newmailfile[1024]; int fd; struct stat st; maildir = getdef_str ("MAIL_DIR"); #ifdef MAIL_SPOOL_DIR if (!maildir && !getdef_str ("MAIL_FILE")) maildir = MAIL_SPOOL_DIR; #endif if (!maildir) return; /* * O_NONBLOCK is to make sure open won't hang on mandatory locks. * We do fstat/fchown to make sure there are no races (someone * replacing /var/spool/mail/luser with a hard link to /etc/passwd * between stat and chown). --marekm */ snprintf (mailfile, sizeof mailfile, "%s/%s", maildir, user_name); fd = open (mailfile, O_RDONLY | O_NONBLOCK, 0); if (fd < 0) { /* no need for warnings if the mailbox doesn't exist */ if (errno != ENOENT) perror (mailfile); return; } if (fstat (fd, &st) < 0) { perror ("fstat"); close (fd); return; } if (st.st_uid != user_id) { /* better leave it alone */ fprintf (stderr, _("%s: warning: %s not owned by %s\n"), Prog, mailfile, user_name); close (fd); return; } if (uflg) { if (fchown (fd, user_newid, (gid_t) - 1) < 0) { perror (_("failed to change mailbox owner")); } #ifdef WITH_AUDIT else { audit_logger (AUDIT_USER_CHAUTHTOK, Prog, "changing mail file owner", user_newname, user_newid, 1); } #endif } close (fd); if (lflg) { snprintf (newmailfile, sizeof newmailfile, "%s/%s", maildir, user_newname); if (link (mailfile, newmailfile) || unlink (mailfile)) { perror (_("failed to rename mailbox")); } #ifdef WITH_AUDIT else { audit_logger (AUDIT_USER_CHAUTHTOK, Prog, "changing mail file name", user_newname, user_newid, 1); } #endif } } #endif /* * main - usermod command */ int main (int argc, char **argv) { int grp_err = 0; #ifdef USE_PAM pam_handle_t *pamh = NULL; struct passwd *pampw; int retval; #endif #ifdef WITH_AUDIT audit_help_open (); #endif /* * Get my name so that I can use it to report errors. */ Prog = Basename (argv[0]); setlocale (LC_ALL, ""); bindtextdomain (PACKAGE, LOCALEDIR); textdomain (PACKAGE); sys_ngroups = sysconf (_SC_NGROUPS_MAX); user_groups = malloc ((1 + sys_ngroups) * sizeof (char *)); user_groups[0] = (char *) 0; OPENLOG ("usermod"); is_shadow_pwd = spw_file_present (); #ifdef SHADOWGRP is_shadow_grp = sgr_file_present (); #endif process_flags (argc, argv); #ifdef USE_PAM retval = PAM_SUCCESS; pampw = getpwuid (getuid ()); if (pampw == NULL) { retval = PAM_USER_UNKNOWN; } if (retval == PAM_SUCCESS) { retval = pam_start ("usermod", pampw->pw_name, &conv, &pamh); } if (retval == PAM_SUCCESS) { retval = pam_authenticate (pamh, 0); if (retval != PAM_SUCCESS) { pam_end (pamh, retval); } } if (retval == PAM_SUCCESS) { retval = pam_acct_mgmt (pamh, 0); if (retval != PAM_SUCCESS) { pam_end (pamh, retval); } } if (retval != PAM_SUCCESS) { fprintf (stderr, _("%s: PAM authentication failed\n"), Prog); exit (1); } #endif /* USE_PAM */ /* * Do the hard stuff - open the files, change the user entries, * change the home directory, then close and update the files. */ open_files (); usr_update (); nscd_flush_cache ("passwd"); nscd_flush_cache ("group"); close_files (); if (Gflg || lflg) grp_err = grp_update (); if (mflg) move_home (); #ifndef NO_MOVE_MAILBOX if (lflg || uflg) move_mailbox (); #endif if (uflg) { update_files (); /* * Change the UID on all of the files owned by `user_id' to * `user_newid' in the user's home directory. */ chown_tree (dflg ? user_newhome : user_home, user_id, user_newid, user_gid, gflg ? user_newgid : user_gid); } if (grp_err) exit (E_GRP_UPDATE); #ifdef USE_PAM if (retval == PAM_SUCCESS) pam_end (pamh, PAM_SUCCESS); #endif /* USE_PAM */ exit (E_SUCCESS); /* NOT REACHED */ }
int main(int argc, char **argv) { enum { NEWSH, LOADENTRY, EDITENTRY } op; struct passwd *pw, lpw, old_pw; int ch, dfd, pfd, tfd; #ifdef YP int yflag = 0; #endif char *arg, *username = NULL; #ifdef __GNUC__ pw = NULL; /* XXX gcc -Wuninitialized */ arg = NULL; #endif #ifdef YP use_yp = _yp_check(NULL); #endif op = EDITENTRY; while ((ch = getopt(argc, argv, "a:s:ly")) != -1) switch (ch) { case 'a': op = LOADENTRY; arg = optarg; break; case 's': op = NEWSH; arg = optarg; break; case 'l': use_yp = 0; break; case 'y': #ifdef YP if (!use_yp) errx(1, "YP not in use."); yflag = 1; #else errx(1, "YP support not compiled in."); #endif break; default: usage(); } argc -= optind; argv += optind; uid = getuid(); switch (argc) { case 0: /* nothing */ break; case 1: username = argv[0]; break; default: usage(); } #ifdef YP /* * We need to determine if we _really_ want to use YP. * If we defaulted to YP (i.e. were not given the -y flag), * and the master is not running rpc.yppasswdd, we check * to see if the user exists in the local passwd database. * If so, we use it, otherwise we error out. */ if (use_yp && yflag == 0) { if (check_yppasswdd()) { /* * We weren't able to contact rpc.yppasswdd. * Check to see if we're in the local * password database. If we are, use it. */ if (username != NULL) pw = getpwnam(username); else pw = getpwuid(uid); if (pw != NULL) use_yp = 0; else { warnx("master YP server not running yppasswd" " daemon."); errx(1, "Can't change password."); } } } #endif #ifdef YP if (use_yp) Pw_error = yppw_error; else #endif Pw_error = pw_error; #ifdef YP if (op == LOADENTRY && use_yp) errx(1, "cannot load entry using YP.\n" "\tUse the -l flag to load local."); #endif if (op == EDITENTRY || op == NEWSH) { if (username != NULL) { pw = getpwnam(username); if (pw == NULL) errx(1, "unknown user: %s", username); if (uid && uid != pw->pw_uid) baduser(); } else { pw = getpwuid(uid); if (pw == NULL) errx(1, "unknown user: uid %u", uid); } /* Make a copy for later verification */ old_pw = *pw; old_pw.pw_gecos = strdup(old_pw.pw_gecos); if (!old_pw.pw_gecos) { err(1, "strdup"); /*NOTREACHED*/ } } if (op == NEWSH) { /* protect p_shell -- it thinks NULL is /bin/sh */ if (!arg[0]) usage(); if (p_shell(arg, pw, NULL)) (*Pw_error)(NULL, 0, 1); } if (op == LOADENTRY) { if (uid) baduser(); pw = &lpw; if (!pw_scan(arg, pw, NULL)) exit(1); } /* Edit the user passwd information if requested. */ if (op == EDITENTRY) { struct stat sb; dfd = mkstemp(tempname); if (dfd < 0 || fcntl(dfd, F_SETFD, 1) < 0) (*Pw_error)(tempname, 1, 1); if (atexit(cleanup)) { cleanup(); errx(1, "couldn't register cleanup"); } if (stat(dirname(tempname), &sb) == -1) err(1, "couldn't stat `%s'", dirname(tempname)); if (!(sb.st_mode & S_ISTXT)) errx(1, "temporary directory `%s' is not sticky", dirname(tempname)); display(tempname, dfd, pw); edit(tempname, pw); } #ifdef YP if (use_yp) { if (pw_yp(pw, uid)) yppw_error(NULL, 0, 1); else exit(0); /* Will not exit from this if. */ } #endif /* YP */ /* * Get the passwd lock file and open the passwd file for * reading. */ pw_init(); tfd = pw_lock(0); if (tfd < 0) { if (errno != EEXIST) err(1, "%s", _PATH_MASTERPASSWD_LOCK); warnx("The passwd file is busy, waiting..."); tfd = pw_lock(10); if (tfd < 0) { if (errno != EEXIST) err(1, "%s", _PATH_MASTERPASSWD_LOCK); errx(1, "The passwd file is still busy, " "try again later."); } } if (fcntl(tfd, F_SETFD, 1) < 0) pw_error(_PATH_MASTERPASSWD_LOCK, 1, 1); pfd = open(_PATH_MASTERPASSWD, O_RDONLY, 0); if (pfd < 0 || fcntl(pfd, F_SETFD, 1) < 0) pw_error(_PATH_MASTERPASSWD, 1, 1); /* Copy the passwd file to the lock file, updating pw. */ pw_copy(pfd, tfd, pw, (op == LOADENTRY) ? NULL : &old_pw); close(pfd); close(tfd); /* Now finish the passwd file update. */ if (pw_mkdb(username, 0) < 0) pw_error(NULL, 0, 1); exit(0); }
int main (int argc, char **argv) { const struct passwd *pw; struct passwd pwent; const struct spwd *spwd; if (1 != argc) { (void) fputs (_("Usage: pwunconv\n"), stderr); } Prog = Basename (argv[0]); (void) setlocale (LC_ALL, ""); (void) bindtextdomain (PACKAGE, LOCALEDIR); (void) textdomain (PACKAGE); OPENLOG ("pwunconv"); #ifdef WITH_TCB if (getdef_bool("USE_TCB")) { fprintf(stderr, _("%s: can't work with tcb enabled\n"), Prog); exit(1); } #endif /* WITH_TCB */ if (!spw_file_present ()) { /* shadow not installed, do nothing */ exit (0); } if (pw_lock () == 0) { fprintf (stderr, _("%s: cannot lock %s; try again later.\n"), Prog, pw_dbname ()); fail_exit (5); } pw_locked = true; if (pw_open (O_RDWR) == 0) { fprintf (stderr, _("%s: cannot open %s\n"), Prog, pw_dbname ()); fail_exit (1); } if (spw_lock () == 0) { fprintf (stderr, _("%s: cannot lock %s; try again later.\n"), Prog, spw_dbname ()); fail_exit (5); } spw_locked = true; if (spw_open (O_RDWR) == 0) { fprintf (stderr, _("%s: cannot open %s\n"), Prog, spw_dbname ()); fail_exit (1); } pw_rewind (); while ((pw = pw_next ()) != NULL) { spwd = spw_locate (pw->pw_name); if (NULL == spwd) { continue; } pwent = *pw; /* * Update password if non-shadow is "x". */ if (strcmp (pw->pw_passwd, SHADOW_PASSWD_STRING) == 0) { pwent.pw_passwd = spwd->sp_pwdp; } /* * Password aging works differently in the two different * systems. With shadow password files you apparently must * have some aging information. The maxweeks or minweeks * may not map exactly. In pwconv we set max == 10000, * which is about 30 years. Here we have to undo that * kludge. So, if maxdays == 10000, no aging information is * put into the new file. Otherwise, the days are converted * to weeks and so on. */ if (pw_update (&pwent) == 0) { fprintf (stderr, _("%s: failed to prepare the new %s entry '%s'\n"), Prog, pw_dbname (), pwent.pw_name); fail_exit (3); } } if (spw_close () == 0) { fprintf (stderr, _("%s: failure while writing changes to %s\n"), Prog, spw_dbname ()); SYSLOG ((LOG_ERR, "failure while writing changes to %s", spw_dbname ())); fail_exit (3); } if (pw_close () == 0) { fprintf (stderr, _("%s: failure while writing changes to %s\n"), Prog, pw_dbname ()); SYSLOG ((LOG_ERR, "failure while writing changes to %s", pw_dbname ())); fail_exit (3); } if (unlink (SHADOW) != 0) { fprintf (stderr, _("%s: cannot delete %s\n"), Prog, SHADOW); SYSLOG ((LOG_ERR, "cannot delete %s", SHADOW)); fail_exit (3); } if (spw_unlock () == 0) { fprintf (stderr, _("%s: failed to unlock %s\n"), Prog, spw_dbname ()); SYSLOG ((LOG_ERR, "failed to unlock %s", spw_dbname ())); /* continue */ } if (pw_unlock () == 0) { fprintf (stderr, _("%s: failed to unlock %s\n"), Prog, pw_dbname ()); SYSLOG ((LOG_ERR, "failed to unlock %s", pw_dbname ())); /* continue */ } nscd_flush_cache ("passwd"); return 0; }
void pwlocal_process(const char *username, int argc, char **argv) { struct passwd *pw; struct passwd old_pw; time_t old_change; int pfd, tfd; int min_pw_len = 0; int pw_expiry = 0; int ch; #ifdef LOGIN_CAP login_cap_t *lc; #endif while ((ch = getopt(argc, argv, "l")) != -1) { switch (ch) { case 'l': /* * Aborb the -l that may have gotten us here. */ break; default: usage(); /* NOTREACHED */ } } argc -= optind; argv += optind; switch (argc) { case 0: /* username already provided */ break; case 1: username = argv[0]; break; default: usage(); /* NOTREACHED */ } if (!(pw = getpwnam(username))) errx(1, "unknown user %s", username); uid = getuid(); if (uid && uid != pw->pw_uid) errx(1, "%s", strerror(EACCES)); /* Save the old pw information for comparing on pw_copy(). */ old_pw = *pw; /* * Get class restrictions for this user, then get the new password. */ #ifdef LOGIN_CAP if((lc = login_getclass(pw->pw_class)) != NULL) { min_pw_len = (int) login_getcapnum(lc, "minpasswordlen", 0, 0); pw_expiry = (int) login_getcaptime(lc, "passwordtime", 0, 0); login_close(lc); } #endif #if 0 printf("AAA: pw_expiry = %x\n", pw_expiry); #endif pw->pw_passwd = getnewpasswd(pw, min_pw_len); old_change = pw->pw_change; pw->pw_change = pw_expiry ? pw_expiry + time(NULL) : 0; /* * Now that the user has given us a new password, let us * change the database. */ pw_init(); tfd = pw_lock(0); if (tfd < 0) { warnx ("The passwd file is busy, waiting..."); tfd = pw_lock(10); if (tfd < 0) errx(1, "The passwd file is still busy, " "try again later."); } pfd = open(_PATH_MASTERPASSWD, O_RDONLY, 0); if (pfd < 0) pw_error(_PATH_MASTERPASSWD, 1, 1); pw_copy(pfd, tfd, pw, &old_pw); if (pw_mkdb(username, old_change == pw->pw_change) < 0) pw_error((char *)NULL, 0, 1); syslog(LOG_AUTH | LOG_INFO, "user %s (UID %lu) successfully changed " "the local password of user %s", uid ? username : "******", (unsigned long)uid, username); }