2 * Copyright (c) 1989 - 1994, Julianne Frances Haugh
3 * Copyright (c) 1996 - 2000, Marek Michałkiewicz
4 * Copyright (c) 2001 - 2006, Tomasz Kłoczko
5 * Copyright (c) 2007 - 2011, Nicolas François
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. The name of the copyright holders or contributors may not be used to
17 * endorse or promote products derived from this software without
18 * specific prior written permission.
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
23 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24 * HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
43 #include <sys/types.h>
45 #include <selinux/selinux.h>
46 #include <selinux/flask.h>
47 #include <selinux/av_permissions.h>
48 #include <selinux/context.h>
49 #endif /* WITH_SELINUX */
54 #include "prototypes.h"
63 #define E_SUCCESS 0 /* success */
64 #define E_NOPERM 1 /* permission denied */
65 #define E_USAGE 2 /* invalid combination of options */
66 #define E_FAILURE 3 /* unexpected failure, nothing done */
67 #define E_MISSING 4 /* unexpected failure, passwd file missing */
68 #define E_PWDBUSY 5 /* passwd file busy, try again later */
69 #define E_BAD_ARG 6 /* invalid argument to option */
73 const char *Prog; /* Program name */
75 static char *name; /* The name of user whose password is being changed */
76 static char *myname; /* The current user's name */
77 static bool amroot; /* The caller's real UID was 0 */
80 aflg = false, /* -a - show status for all users */
81 dflg = false, /* -d - delete password */
82 eflg = false, /* -e - force password change */
83 iflg = false, /* -i - set inactive days */
84 kflg = false, /* -k - change only if expired */
85 lflg = false, /* -l - lock the user's password */
86 nflg = false, /* -n - set minimum days */
87 qflg = false, /* -q - quiet mode */
88 Sflg = false, /* -S - show password status */
89 uflg = false, /* -u - unlock the user's password */
90 wflg = false, /* -w - set warning days */
91 xflg = false; /* -x - set maximum days */
94 * set to 1 if there are any flags which require root privileges,
95 * and require username to be specified
97 static bool anyflag = false;
99 static long age_min = 0; /* Minimum days before change */
100 static long age_max = 0; /* Maximum days until change */
101 static long warn = 0; /* Warning days before change */
102 static long inact = 0; /* Days without change before locked */
105 static bool do_update_age = false;
106 #endif /* ! USE_PAM */
108 static bool pw_locked = false;
109 static bool spw_locked = false;
113 * Size of the biggest passwd:
125 static char crypt_passwd[256];
126 static bool do_update_pwd = false;
127 #endif /* !USE_PAM */
130 * External identifiers
133 /* local function prototypes */
134 static /*@noreturn@*/void usage (int);
137 static bool reuse (const char *, const struct passwd *);
138 static int new_password (const struct passwd *);
140 static void check_password (const struct passwd *, const struct spwd *);
141 #endif /* !USE_PAM */
142 static /*@observer@*/const char *date_to_str (time_t);
143 static /*@observer@*/const char *pw_status (const char *);
144 static void print_status (const struct passwd *);
145 static /*@noreturn@*/void fail_exit (int);
146 static /*@noreturn@*/void oom (void);
147 static char *update_crypt_pw (char *);
148 static void update_noshadow (void);
150 static void update_shadow (void);
152 static int check_selinux_access (const char *changed_user,
154 access_vector_t requested_access);
155 #endif /* WITH_SELINUX */
158 * usage - print command usage and exit
160 static /*@noreturn@*/void usage (int status)
162 FILE *usageout = (E_SUCCESS != status) ? stderr : stdout;
163 (void) fprintf (usageout,
164 _("Usage: %s [options] [LOGIN]\n"
168 (void) fputs (_(" -a, --all report password status on all accounts\n"), usageout);
169 (void) fputs (_(" -d, --delete delete the password for the named account\n"), usageout);
170 (void) fputs (_(" -e, --expire force expire the password for the named account\n"), usageout);
171 (void) fputs (_(" -h, --help display this help message and exit\n"), usageout);
172 (void) fputs (_(" -k, --keep-tokens change password only if expired\n"), usageout);
173 (void) fputs (_(" -i, --inactive INACTIVE set password inactive after expiration\n"
174 " to INACTIVE\n"), usageout);
175 (void) fputs (_(" -l, --lock lock the password of the named account\n"), usageout);
176 (void) fputs (_(" -n, --mindays MIN_DAYS set minimum number of days before password\n"
177 " change to MIN_DAYS\n"), usageout);
178 (void) fputs (_(" -q, --quiet quiet mode\n"), usageout);
179 (void) fputs (_(" -r, --repository REPOSITORY change password in REPOSITORY repository\n"), usageout);
180 (void) fputs (_(" -R, --root CHROOT_DIR directory to chroot into\n"), usageout);
181 (void) fputs (_(" -S, --status report password status on the named account\n"), usageout);
182 (void) fputs (_(" -u, --unlock unlock the password of the named account\n"), usageout);
183 (void) fputs (_(" -w, --warndays WARN_DAYS set expiration warning days to WARN_DAYS\n"), usageout);
184 (void) fputs (_(" -x, --maxdays MAX_DAYS set maximum number of days before password\n"
185 " change to MAX_DAYS\n"), usageout);
186 (void) fputs ("\n", usageout);
191 static bool reuse (const char *pass, const struct passwd *pw)
193 #ifdef HAVE_LIBCRACK_HIST
196 #ifdef HAVE_LIBCRACK_PW
197 const char *FascistHistoryPw (const char *, const struct passwd *);
199 reason = FascistHistory (pass, pw);
200 #else /* !HAVE_LIBCRACK_PW */
201 const char *FascistHistory (const char *, int);
203 reason = FascistHistory (pass, pw->pw_uid);
204 #endif /* !HAVE_LIBCRACK_PW */
205 if (NULL != reason) {
206 (void) printf (_("Bad password: %s. "), reason);
209 #endif /* HAVE_LIBCRACK_HIST */
214 * new_password - validate old password and replace with new (both old and
215 * new in global "char crypt_passwd[128]")
217 static int new_password (const struct passwd *pw)
219 char *clear; /* Pointer to clear text */
220 char *cipher; /* Pointer to cipher text */
221 char *cp; /* Pointer to getpass() response */
222 char orig[200]; /* Original password */
223 char pass[200]; /* New password */
224 int i; /* Counter for retries */
226 int pass_max_len = -1;
229 #ifdef HAVE_LIBCRACK_HIST
230 int HistUpdate (const char *, const char *);
231 #endif /* HAVE_LIBCRACK_HIST */
234 * Authenticate the user. The user will be prompted for their own
238 if (!amroot && ('\0' != crypt_passwd[0])) {
239 clear = getpass (_("Old password: "));
244 cipher = pw_encrypt (clear, crypt_passwd);
245 if (strcmp (cipher, crypt_passwd) != 0) {
248 SYSLOG ((LOG_WARN, "incorrect password for %s",
251 (void) fprintf (stderr,
252 _("Incorrect password for %s.\n"),
256 STRFCPY (orig, clear);
264 * Get the new password. The user is prompted for the new password
265 * and has five tries to get it right. The password will be tested
266 * for strength, unless it is the root user. This provides an escape
267 * for initial login passwords.
269 method = getdef_str ("ENCRYPT_METHOD");
270 if (NULL == method) {
271 if (!getdef_bool ("MD5_CRYPT_ENAB")) {
272 pass_max_len = getdef_num ("PASS_MAX_LEN", 8);
275 if ( (strcmp (method, "MD5") == 0)
277 || (strcmp (method, "SHA256") == 0)
278 || (strcmp (method, "SHA512") == 0)
279 #endif /* USE_SHA_CRYPT */
283 pass_max_len = getdef_num ("PASS_MAX_LEN", 8);
287 if (pass_max_len == -1) {
289 "Enter the new password (minimum of %d characters)\n"
290 "Please use a combination of upper and lower case letters and numbers.\n"),
291 getdef_num ("PASS_MIN_LEN", 5));
294 "Enter the new password (minimum of %d, maximum of %d characters)\n"
295 "Please use a combination of upper and lower case letters and numbers.\n"),
296 getdef_num ("PASS_MIN_LEN", 5), pass_max_len);
301 for (i = getdef_num ("PASS_CHANGE_TRIES", 5); i > 0; i--) {
302 cp = getpass (_("New password: "));
304 memzero (orig, sizeof orig);
307 if (warned && (strcmp (pass, cp) != 0)) {
313 if (!amroot && (!obscure (orig, pass, pw) || reuse (pass, pw))) {
314 (void) puts (_("Try again."));
319 * If enabled, warn about weak passwords even if you are
320 * root (enter this password again to use it anyway).
323 if (amroot && !warned && getdef_bool ("PASS_ALWAYS_WARN")
324 && (!obscure (orig, pass, pw) || reuse (pass, pw))) {
325 (void) puts (_("\nWarning: weak password (enter it again to use it anyway)."));
329 cp = getpass (_("Re-enter new password: "));
331 memzero (orig, sizeof orig);
334 if (strcmp (cp, pass) != 0) {
335 (void) fputs (_("They don't match; try again.\n"), stderr);
341 memzero (orig, sizeof orig);
344 memzero (pass, sizeof pass);
349 * Encrypt the password, then wipe the cleartext password.
351 cp = pw_encrypt (pass, crypt_make_salt (NULL, NULL));
352 memzero (pass, sizeof pass);
354 #ifdef HAVE_LIBCRACK_HIST
355 HistUpdate (pw->pw_name, crypt_passwd);
356 #endif /* HAVE_LIBCRACK_HIST */
357 STRFCPY (crypt_passwd, cp);
362 * check_password - test a password to see if it can be changed
364 * check_password() sees if the invoker has permission to change the
365 * password for the given user.
367 static void check_password (const struct passwd *pw, const struct spwd *sp)
372 exp_status = isexpired (pw, sp);
375 * If not expired and the "change only if expired" option (idea from
376 * PAM) was specified, do nothing. --marekm
378 if (kflg && (0 == exp_status)) {
383 * Root can change any password any time.
392 * Expired accounts cannot be changed ever. Passwords which are
393 * locked may not be changed. Passwords where min > max may not be
394 * changed. Passwords which have been inactive too long cannot be
397 if ( (sp->sp_pwdp[0] == '!')
399 || ( (sp->sp_max >= 0)
400 && (sp->sp_min > sp->sp_max))) {
401 (void) fprintf (stderr,
402 _("The password for %s cannot be changed.\n"),
404 SYSLOG ((LOG_WARN, "password locked for '%s'", sp->sp_namp));
410 * Passwords may only be changed after sp_min time is up.
412 if (sp->sp_lstchg > 0) {
414 last = sp->sp_lstchg * SCALE;
415 ok = last + (sp->sp_min > 0 ? sp->sp_min * SCALE : 0);
418 (void) fprintf (stderr,
419 _("The password for %s cannot be changed yet.\n"),
421 SYSLOG ((LOG_WARN, "now < minimum age for '%s'", pw->pw_name));
427 #endif /* !USE_PAM */
429 static /*@observer@*/const char *date_to_str (time_t t)
436 (void) strftime (buf, sizeof buf, "%m/%d/%Y", tm);
437 #else /* !HAVE_STRFTIME */
438 (void) snprintf (buf, sizeof buf, "%02d/%02d/%04d",
439 tm->tm_mon + 1, tm->tm_mday, tm->tm_year + 1900);
440 #endif /* !HAVE_STRFTIME */
444 static /*@observer@*/const char *pw_status (const char *pass)
446 if (*pass == '*' || *pass == '!') {
456 * print_status - print current password status
458 static void print_status (const struct passwd *pw)
462 sp = getspnam (pw->pw_name); /* local, no need for xgetspnam */
464 (void) printf ("%s %s %s %lld %lld %lld %lld\n",
466 pw_status (sp->sp_pwdp),
467 date_to_str (sp->sp_lstchg * SCALE),
468 ((long long)sp->sp_min * SCALE) / DAY,
469 ((long long)sp->sp_max * SCALE) / DAY,
470 ((long long)sp->sp_warn * SCALE) / DAY,
471 ((long long)sp->sp_inact * SCALE) / DAY);
473 (void) printf ("%s %s\n",
474 pw->pw_name, pw_status (pw->pw_passwd));
479 static /*@noreturn@*/void fail_exit (int status)
482 if (pw_unlock () == 0) {
483 (void) fprintf (stderr, _("%s: failed to unlock %s\n"), Prog, pw_dbname ());
484 SYSLOG ((LOG_ERR, "failed to unlock %s", pw_dbname ()));
490 if (spw_unlock () == 0) {
491 (void) fprintf (stderr, _("%s: failed to unlock %s\n"), Prog, spw_dbname ());
492 SYSLOG ((LOG_ERR, "failed to unlock %s", spw_dbname ()));
500 static /*@noreturn@*/void oom (void)
502 (void) fprintf (stderr, _("%s: out of memory\n"), Prog);
503 fail_exit (E_FAILURE);
506 static char *update_crypt_pw (char *cp)
510 cp = xstrdup (crypt_passwd);
512 #endif /* !USE_PAM */
518 if (uflg && *cp == '!') {
520 (void) fprintf (stderr,
521 _("%s: unlocking the password would result in a passwordless account.\n"
522 "You should set a password with usermod -p to unlock the password of this account.\n"),
524 fail_exit (E_FAILURE);
530 if (lflg && *cp != '!') {
531 char *newpw = xmalloc (strlen (cp) + 2);
541 static void update_noshadow (void)
543 const struct passwd *pw;
546 if (pw_lock () == 0) {
547 (void) fprintf (stderr,
548 _("%s: cannot lock %s; try again later.\n"),
553 if (pw_open (O_RDWR) == 0) {
554 (void) fprintf (stderr,
555 _("%s: cannot open %s\n"),
557 SYSLOG ((LOG_WARN, "cannot open %s", pw_dbname ()));
558 fail_exit (E_MISSING);
560 pw = pw_locate (name);
562 (void) fprintf (stderr,
563 _("%s: user '%s' does not exist in %s\n"),
564 Prog, name, pw_dbname ());
565 fail_exit (E_NOPERM);
571 npw->pw_passwd = update_crypt_pw (npw->pw_passwd);
572 if (pw_update (npw) == 0) {
573 (void) fprintf (stderr,
574 _("%s: failed to prepare the new %s entry '%s'\n"),
575 Prog, pw_dbname (), npw->pw_name);
576 fail_exit (E_FAILURE);
578 if (pw_close () == 0) {
579 (void) fprintf (stderr,
580 _("%s: failure while writing changes to %s\n"),
582 SYSLOG ((LOG_ERR, "failure while writing changes to %s", pw_dbname ()));
583 fail_exit (E_FAILURE);
585 if (pw_unlock () == 0) {
586 (void) fprintf (stderr,
587 _("%s: failed to unlock %s\n"),
589 SYSLOG ((LOG_ERR, "failed to unlock %s", pw_dbname ()));
595 static void update_shadow (void)
597 const struct spwd *sp;
600 if (spw_lock () == 0) {
601 (void) fprintf (stderr,
602 _("%s: cannot lock %s; try again later.\n"),
603 Prog, spw_dbname ());
607 if (spw_open (O_RDWR) == 0) {
608 (void) fprintf (stderr,
609 _("%s: cannot open %s\n"),
610 Prog, spw_dbname ());
611 SYSLOG ((LOG_WARN, "cannot open %s", spw_dbname ()));
612 fail_exit (E_FAILURE);
614 sp = spw_locate (name);
616 /* Try to update the password in /etc/passwd instead. */
619 if (spw_unlock () == 0) {
620 (void) fprintf (stderr,
621 _("%s: failed to unlock %s\n"),
622 Prog, spw_dbname ());
623 SYSLOG ((LOG_ERR, "failed to unlock %s", spw_dbname ()));
629 nsp = __spw_dup (sp);
633 nsp->sp_pwdp = update_crypt_pw (nsp->sp_pwdp);
635 nsp->sp_max = (age_max * DAY) / SCALE;
638 nsp->sp_min = (age_min * DAY) / SCALE;
641 nsp->sp_warn = (warn * DAY) / SCALE;
644 nsp->sp_inact = (inact * DAY) / SCALE;
648 nsp->sp_lstchg = (long) time ((time_t *) 0) / SCALE;
649 if (0 == nsp->sp_lstchg) {
650 /* Better disable aging than requiring a password
655 #endif /* !USE_PAM */
658 * Force change on next login, like SunOS 4.x passwd -e or Solaris
659 * 2.x passwd -f. Solaris 2.x seems to do the same thing (set
666 if (spw_update (nsp) == 0) {
667 (void) fprintf (stderr,
668 _("%s: failed to prepare the new %s entry '%s'\n"),
669 Prog, spw_dbname (), nsp->sp_namp);
670 fail_exit (E_FAILURE);
672 if (spw_close () == 0) {
673 (void) fprintf (stderr,
674 _("%s: failure while writing changes to %s\n"),
675 Prog, spw_dbname ());
676 SYSLOG ((LOG_ERR, "failure while writing changes to %s", spw_dbname ()));
677 fail_exit (E_FAILURE);
679 if (spw_unlock () == 0) {
680 (void) fprintf (stderr,
681 _("%s: failed to unlock %s\n"),
682 Prog, spw_dbname ());
683 SYSLOG ((LOG_ERR, "failed to unlock %s", spw_dbname ()));
690 static int check_selinux_access (const char *changed_user,
692 access_vector_t requested_access)
695 security_context_t user_context;
699 /* if in permissive mode then allow the operation */
700 if (security_getenforce() == 0) {
704 /* get the context of the process which executed passwd */
705 if (getprevcon(&user_context) != 0) {
709 /* get the "user" portion of the context (the part before the first
711 c = context_new(user_context);
712 user = context_user_get(c);
714 /* if changing a password for an account with UID==0 or for an account
715 where the identity matches then return success */
716 if (changed_uid != 0 && strcmp(changed_user, user) == 0) {
719 struct av_decision avd;
721 retval = security_compute_av(user_context,
727 ((requested_access & avd.allowed) == requested_access)) {
732 freecon(user_context);
736 #endif /* WITH_SELINUX */
739 * passwd - change a user's password file information
741 * This command controls the password file and commands which are used
744 * The valid options are
746 * -d delete the password for the named account (*)
747 * -e expire the password for the named account (*)
748 * -f execute chfn command to interpret flags
749 * -g execute gpasswd command to interpret flags
750 * -i # set sp_inact to # days (*)
751 * -k change password only if expired
752 * -l lock the password of the named account (*)
753 * -n # set sp_min to # days (*)
754 * -r # change password in # repository
755 * -s execute chsh command to interpret flags
756 * -S show password status of named account
757 * -u unlock the password of the named account (*)
758 * -w # set sp_warn to # days (*)
759 * -x # set sp_max to # days (*)
761 * (*) requires root permission to execute.
763 * All of the time fields are entered in days and converted to the
764 * appropriate internal format. For finer resolute the chage
765 * command must be used.
767 int main (int argc, char **argv)
769 const struct passwd *pw; /* Password file entry for user */
772 char *cp; /* Miscellaneous character pointing */
774 const struct spwd *sp; /* Shadow file entry for user */
775 #endif /* !USE_PAM */
780 * Get the program name. The program name is used as a prefix to
781 * most error messages.
783 Prog = Basename (argv[0]);
785 (void) setlocale (LC_ALL, "");
786 (void) bindtextdomain (PACKAGE, LOCALEDIR);
787 (void) textdomain (PACKAGE);
789 process_root_flag ("-R", argc, argv);
792 * The program behaves differently when executed by root than when
793 * executed by a normal user.
795 amroot = (getuid () == 0);
801 * Parse the command line options.
804 static struct option long_options[] = {
805 {"all", no_argument, NULL, 'a'},
806 {"delete", no_argument, NULL, 'd'},
807 {"expire", no_argument, NULL, 'e'},
808 {"help", no_argument, NULL, 'h'},
809 {"inactive", required_argument, NULL, 'i'},
810 {"keep-tokens", no_argument, NULL, 'k'},
811 {"lock", no_argument, NULL, 'l'},
812 {"mindays", required_argument, NULL, 'n'},
813 {"quiet", no_argument, NULL, 'q'},
814 {"repository", required_argument, NULL, 'r'},
815 {"root", required_argument, NULL, 'R'},
816 {"status", no_argument, NULL, 'S'},
817 {"unlock", no_argument, NULL, 'u'},
818 {"warndays", required_argument, NULL, 'w'},
819 {"maxdays", required_argument, NULL, 'x'},
820 {NULL, 0, NULL, '\0'}
823 while ((c = getopt_long (argc, argv, "adehi:kln:qr:R:Suw:x:",
824 long_options, NULL)) != -1) {
838 if ( (getlong (optarg, &inact) == 0)
841 _("%s: invalid numeric argument '%s'\n"),
849 /* change only if expired, like Linux-PAM passwd -k. */
850 kflg = true; /* ok for users */
857 if ( (getlong (optarg, &age_min) == 0)
860 _("%s: invalid numeric argument '%s'\n"),
868 qflg = true; /* ok for users */
871 /* -r repository (files|nis|nisplus) */
872 /* only "files" supported for now */
873 if (strcmp (optarg, "files") != 0) {
875 _("%s: repository %s not supported\n"),
880 case 'R': /* no-op, handled in process_root_flag () */
883 Sflg = true; /* ok for users */
890 if ( (getlong (optarg, &warn) == 0)
892 (void) fprintf (stderr,
893 _("%s: invalid numeric argument '%s'\n"),
901 if ( (getlong (optarg, &age_max) == 0)
903 (void) fprintf (stderr,
904 _("%s: invalid numeric argument '%s'\n"),
913 /*@notreached@*/break;
921 * Now I have to get the user name. The name will be gotten from the
922 * command line if possible. Otherwise it is figured out from the
925 pw = get_my_pwent ();
927 (void) fprintf (stderr,
928 _("%s: Cannot determine your user name.\n"),
930 SYSLOG ((LOG_WARN, "Cannot determine the user name of the caller (UID %lu)",
931 (unsigned long) getuid ()));
934 myname = xstrdup (pw->pw_name);
942 * Make sure that at most one username was specified.
944 if (argc > (optind+1)) {
949 * The -a flag requires -S, no other flags, no username, and
950 * you must be root. --marekm
953 if (anyflag || !Sflg || (optind < argc)) {
957 (void) fprintf (stderr,
958 _("%s: Permission denied.\n"),
963 while ( (pw = getpwent ()) != NULL ) {
971 * Allow certain users (administrators) to change passwords of
972 * certain users. Not implemented yet. --marekm
974 if (may_change_passwd (myname, name))
979 * If any of the flags were given, a user name must be supplied on
980 * the command line. Only an unadorned command line doesn't require
981 * the user's name be given. Also, -x, -n, -w, -i, -e, -d,
982 * -l, -u may appear with each other. -S, -k must appear alone.
986 * -S now ok for normal users (check status of my own account), and
987 * doesn't require username. --marekm
989 if (anyflag && optind >= argc) {
994 || (anyflag && (Sflg || kflg))) {
998 if (anyflag && !amroot) {
999 (void) fprintf (stderr, _("%s: Permission denied.\n"), Prog);
1003 pw = xgetpwnam (name);
1005 (void) fprintf (stderr,
1006 _("%s: user '%s' does not exist\n"),
1011 /* only do this check when getuid()==0 because it's a pre-condition for
1012 changing a password without entering the old one */
1013 if ((is_selinux_enabled() > 0) && (getuid() == 0) &&
1014 (check_selinux_access (name, pw->pw_uid, PASSWD__PASSWD) != 0)) {
1015 security_context_t user_context = NULL;
1016 const char *user = "Unknown user context";
1017 if (getprevcon (&user_context) == 0) {
1018 user = user_context; /* FIXME: use context_user_get? */
1021 "%s is not authorized to change the password of %s",
1023 (void) fprintf(stderr,
1024 _("%s: %s is not authorized to change the password of %s\n"),
1026 if (NULL != user_context) {
1027 freecon (user_context);
1031 #endif /* WITH_SELINUX */
1034 * If the UID of the user does not match the current real UID,
1035 * check if I'm root.
1037 if (!amroot && (pw->pw_uid != getuid ())) {
1038 (void) fprintf (stderr,
1039 _("%s: You may not view or modify password information for %s.\n"),
1042 "%s: can't view or modify password information for %s",
1054 * The user name is valid, so let's get the shadow file entry.
1056 sp = getspnam (name); /* !USE_PAM, no need for xgetspnam */
1058 sp = pwd_to_spwd (pw);
1064 * If there are no other flags, just change the password.
1067 STRFCPY (crypt_passwd, cp);
1070 * See if the user is permitted to change the password.
1071 * Otherwise, go ahead and set a new password.
1073 check_password (pw, sp);
1076 * Let the user know whose password is being changed.
1079 (void) printf (_("Changing password for %s\n"), name);
1082 if (new_password (pw) != 0) {
1083 (void) fprintf (stderr,
1084 _("The password for %s is unchanged.\n"),
1089 do_update_pwd = true;
1090 do_update_age = true;
1092 #endif /* !USE_PAM */
1094 * Before going any further, raise the ulimit to prevent colliding
1095 * into a lowered ulimit, and set the real UID to root to protect
1096 * against unexpected signals. Any keyboard signals are set to be
1103 * Don't set the real UID for PAM...
1106 do_pam_passwd (name, qflg, kflg);
1109 #endif /* USE_PAM */
1110 if (setuid (0) != 0) {
1111 (void) fputs (_("Cannot change ID to root.\n"), stderr);
1112 SYSLOG ((LOG_ERR, "can't setuid(0)"));
1116 if (spw_file_present ()) {
1122 nscd_flush_cache ("passwd");
1123 nscd_flush_cache ("group");
1125 SYSLOG ((LOG_INFO, "password for '%s' changed by '%s'", name, myname));
1130 (void) printf (_("%s: password changed.\n"), Prog);
1131 #endif /* USE_PAM */
1133 (void) printf (_("%s: password expiry information changed.\n"), Prog);