./0000775000175000017500000000000012511510612011427 5ustar nielsenrnielsenr./generic_BSD0000664000175000017500000000273312511411356013470 0ustar nielsenrnielsenrCopyright (c) The Regents of the University of California. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the University nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ./generic_Artistic-1.00000664000175000017500000001126112511411356015132 0ustar nielsenrnielsenr The Artistic License Preamble The intent of this document is to state the conditions under which a Package may be copied, such that the Copyright Holder maintains some semblance of artistic control over the development of the package, while giving the users of the package the right to use and distribute the Package in a more-or-less customary fashion, plus the right to make reasonable modifications. Definitions: "Package" refers to the collection of files distributed by the Copyright Holder, and derivatives of that collection of files created through textual modification. "Standard Version" refers to such a Package if it has not been modified, or has been modified in accordance with the wishes of the Copyright Holder. "Copyright Holder" is whoever is named in the copyright or copyrights for the package. "You" is you, if you`re thinking about copying or distributing this Package. "Reasonable copying fee" is whatever you can justify on the basis of media cost, duplication charges, time of people involved, and so on. (You will not be required to justify it to the Copyright Holder, but only to the computing community at large as a market that must bear the fee.) "Freely Available" means that no fee is charged for the item itself, though there may be fees involved in handling the item. It also means that recipients of the item may redistribute it under the same conditions they received it. 1. You may make and give away verbatim copies of the source form of the Standard Version of this Package without restriction, provided that you duplicate all of the original copyright notices and associated disclaimers. 2. You may apply bug fixes, portability fixes and other modifications derived from the Public Domain or from the Copyright Holder. A Package modified in such a way shall still be considered the Standard Version. 3. You may otherwise modify your copy of this Package in any way, provided that you insert a prominent notice in each changed file stating how and when you changed that file, and provided that you do at least ONE of the following: a) place your modifications in the Public Domain or otherwise make them Freely Available, such as by posting said modifications to Usenet or an equivalent medium, or placing the modifications on a major archive site such as ftp.uu.net, or by allowing the Copyright Holder to include your modifications in the Standard Version of the Package. b) use the modified Package only within your corporation or organization. c) rename any non-standard executables so the names do not conflict with standard executables, which must also be provided, and provide a separate manual page for each non-standard executable that clearly documents how it differs from the Standard Version. d) make other distribution arrangements with the Copyright Holder. 4. You may distribute the programs of this Package in object code or executable form, provided that you do at least ONE of the following: a) distribute a Standard Version of the executables and library files, together with instructions (in the manual page or equivalent) on where to get the Standard Version. b) accompany the distribution with the machine-readable source of the Package with your modifications. c) accompany any non-standard executables with their corresponding Standard Version executables, giving the non-standard executables non-standard names, and clearly documenting the differences in manual pages (or equivalent), together with instructions on where to get the Standard Version. d) make other distribution arrangements with the Copyright Holder. 5. You may charge a reasonable copying fee for any distribution of this Package. You may charge any fee you choose for support of this Package. You may not charge a fee for this Package itself. However, you may distribute this Package in aggregate with other (possibly commercial) programs as part of a larger (possibly commercial) software distribution provided that you do not advertise this Package as a product of your own. 6. The scripts and library files supplied as input to or produced as output from the programs of this Package do not automatically fall under the copyright of this Package, but belong to whomever generated them, and may be sold commercially, and may be aggregated with this Package. 7. C or perl subroutines supplied by you and linked into this Package shall not be considered part of this Package. 8. The name of the Copyright Holder may not be used to endorse or promote products derived from this software without specific prior written permission. 9. THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. The End ./passwd.c0000664000175000017500000007671212304427047013122 0ustar nielsenrnielsenr/* * Copyright (c) 1989 - 1994, Julianne Frances Haugh * Copyright (c) 1996 - 2000, Marek Michałkiewicz * Copyright (c) 2001 - 2006, Tomasz Kłoczko * Copyright (c) 2007 - 2011, Nicolas François * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the copyright holders or contributors may not be used to * endorse or promote products derived from this software without * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #ident "$Id$" #include #include #include #include #include #include #include #ifdef WITH_SELINUX #include #include #include #include #endif /* WITH_SELINUX */ #include #include "defines.h" #include "getdef.h" #include "nscd.h" #include "prototypes.h" #include "pwauth.h" #include "pwio.h" #include "shadowio.h" /* * exit status values */ /*@-exitarg@*/ #define E_SUCCESS 0 /* success */ #define E_NOPERM 1 /* permission denied */ #define E_USAGE 2 /* invalid combination of options */ #define E_FAILURE 3 /* unexpected failure, nothing done */ #define E_MISSING 4 /* unexpected failure, passwd file missing */ #define E_PWDBUSY 5 /* passwd file busy, try again later */ #define E_BAD_ARG 6 /* invalid argument to option */ /* * Global variables */ const char *Prog; /* Program name */ static char *name; /* The name of user whose password is being changed */ static char *myname; /* The current user's name */ static bool amroot; /* The caller's real UID was 0 */ static bool aflg = false, /* -a - show status for all users */ dflg = false, /* -d - delete password */ eflg = false, /* -e - force password change */ iflg = false, /* -i - set inactive days */ kflg = false, /* -k - change only if expired */ lflg = false, /* -l - lock the user's password */ nflg = false, /* -n - set minimum days */ qflg = false, /* -q - quiet mode */ Sflg = false, /* -S - show password status */ uflg = false, /* -u - unlock the user's password */ wflg = false, /* -w - set warning days */ xflg = false; /* -x - set maximum days */ /* * set to 1 if there are any flags which require root privileges, * and require username to be specified */ static bool anyflag = false; static long age_min = 0; /* Minimum days before change */ static long age_max = 0; /* Maximum days until change */ static long warn = 0; /* Warning days before change */ static long inact = 0; /* Days without change before locked */ #ifndef USE_PAM static bool do_update_age = false; #endif /* ! USE_PAM */ static bool pw_locked = false; static bool spw_locked = false; #ifndef USE_PAM /* * Size of the biggest passwd: * $6$ 3 * rounds= 7 * 999999999 9 * $ 1 * salt 16 * $ 1 * SHA512 123 * nul 1 * * total 161 */ static char crypt_passwd[256]; static bool do_update_pwd = false; #endif /* !USE_PAM */ /* * External identifiers */ /* local function prototypes */ static /*@noreturn@*/void usage (int); #ifndef USE_PAM static bool reuse (const char *, const struct passwd *); static int new_password (const struct passwd *); static void check_password (const struct passwd *, const struct spwd *); #endif /* !USE_PAM */ static /*@observer@*/const char *date_to_str (time_t); static /*@observer@*/const char *pw_status (const char *); static void print_status (const struct passwd *); static /*@noreturn@*/void fail_exit (int); static /*@noreturn@*/void oom (void); static char *update_crypt_pw (char *); static void update_noshadow (void); static void update_shadow (void); #ifdef WITH_SELINUX static int check_selinux_access (const char *changed_user, uid_t changed_uid, access_vector_t requested_access); #endif /* WITH_SELINUX */ /* * usage - print command usage and exit */ static /*@noreturn@*/void usage (int status) { FILE *usageout = (E_SUCCESS != status) ? stderr : stdout; (void) fprintf (usageout, _("Usage: %s [options] [LOGIN]\n" "\n" "Options:\n"), Prog); (void) fputs (_(" -a, --all report password status on all accounts\n"), usageout); (void) fputs (_(" -d, --delete delete the password for the named account\n"), usageout); (void) fputs (_(" -e, --expire force expire the password for the named account\n"), usageout); (void) fputs (_(" -h, --help display this help message and exit\n"), usageout); (void) fputs (_(" -k, --keep-tokens change password only if expired\n"), usageout); (void) fputs (_(" -i, --inactive INACTIVE set password inactive after expiration\n" " to INACTIVE\n"), usageout); (void) fputs (_(" -l, --lock lock the password of the named account\n"), usageout); (void) fputs (_(" -n, --mindays MIN_DAYS set minimum number of days before password\n" " change to MIN_DAYS\n"), usageout); (void) fputs (_(" -q, --quiet quiet mode\n"), usageout); (void) fputs (_(" -r, --repository REPOSITORY change password in REPOSITORY repository\n"), usageout); (void) fputs (_(" -R, --root CHROOT_DIR directory to chroot into\n"), usageout); (void) fputs (_(" -S, --status report password status on the named account\n"), usageout); (void) fputs (_(" -u, --unlock unlock the password of the named account\n"), usageout); (void) fputs (_(" -w, --warndays WARN_DAYS set expiration warning days to WARN_DAYS\n"), usageout); (void) fputs (_(" -x, --maxdays MAX_DAYS set maximum number of days before password\n" " change to MAX_DAYS\n"), usageout); (void) fputs ("\n", usageout); exit (status); } #ifndef USE_PAM static bool reuse (const char *pass, const struct passwd *pw) { #ifdef HAVE_LIBCRACK_HIST const char *reason; #ifdef HAVE_LIBCRACK_PW const char *FascistHistoryPw (const char *, const struct passwd *); reason = FascistHistory (pass, pw); #else /* !HAVE_LIBCRACK_PW */ const char *FascistHistory (const char *, int); reason = FascistHistory (pass, pw->pw_uid); #endif /* !HAVE_LIBCRACK_PW */ if (NULL != reason) { (void) printf (_("Bad password: %s. "), reason); return true; } #endif /* HAVE_LIBCRACK_HIST */ return false; } /* * new_password - validate old password and replace with new (both old and * new in global "char crypt_passwd[128]") */ static int new_password (const struct passwd *pw) { char *clear; /* Pointer to clear text */ char *cipher; /* Pointer to cipher text */ const char *salt; /* Pointer to new salt */ char *cp; /* Pointer to getpass() response */ char orig[200]; /* Original password */ char pass[200]; /* New password */ int i; /* Counter for retries */ bool warned; int pass_max_len = -1; const char *method; #ifdef HAVE_LIBCRACK_HIST int HistUpdate (const char *, const char *); #endif /* HAVE_LIBCRACK_HIST */ /* * Authenticate the user. The user will be prompted for their own * password. */ if (!amroot && ('\0' != crypt_passwd[0])) { clear = getpass (_("Old password: ")); if (NULL == clear) { return -1; } cipher = pw_encrypt (clear, crypt_passwd); if (NULL == cipher) { strzero (clear); fprintf (stderr, _("%s: failed to crypt password with previous salt: %s\n"), Prog, strerror (errno)); SYSLOG ((LOG_INFO, "Failed to crypt password with previous salt of user '%s'", pw->pw_name)); return -1; } if (strcmp (cipher, crypt_passwd) != 0) { strzero (clear); strzero (cipher); SYSLOG ((LOG_WARN, "incorrect password for %s", pw->pw_name)); (void) sleep (1); (void) fprintf (stderr, _("Incorrect password for %s.\n"), pw->pw_name); return -1; } STRFCPY (orig, clear); strzero (clear); strzero (cipher); } else { orig[0] = '\0'; } /* * Get the new password. The user is prompted for the new password * and has five tries to get it right. The password will be tested * for strength, unless it is the root user. This provides an escape * for initial login passwords. */ method = getdef_str ("ENCRYPT_METHOD"); if (NULL == method) { if (!getdef_bool ("MD5_CRYPT_ENAB")) { pass_max_len = getdef_num ("PASS_MAX_LEN", 8); } } else { if ( (strcmp (method, "MD5") == 0) #ifdef USE_SHA_CRYPT || (strcmp (method, "SHA256") == 0) || (strcmp (method, "SHA512") == 0) #endif /* USE_SHA_CRYPT */ ) { pass_max_len = -1; } else { pass_max_len = getdef_num ("PASS_MAX_LEN", 8); } } if (!qflg) { if (pass_max_len == -1) { (void) printf (_( "Enter the new password (minimum of %d characters)\n" "Please use a combination of upper and lower case letters and numbers.\n"), getdef_num ("PASS_MIN_LEN", 5)); } else { (void) printf (_( "Enter the new password (minimum of %d, maximum of %d characters)\n" "Please use a combination of upper and lower case letters and numbers.\n"), getdef_num ("PASS_MIN_LEN", 5), pass_max_len); } } warned = false; for (i = getdef_num ("PASS_CHANGE_TRIES", 5); i > 0; i--) { cp = getpass (_("New password: ")); if (NULL == cp) { memzero (orig, sizeof orig); return -1; } if (warned && (strcmp (pass, cp) != 0)) { warned = false; } STRFCPY (pass, cp); strzero (cp); if (!amroot && (!obscure (orig, pass, pw) || reuse (pass, pw))) { (void) puts (_("Try again.")); continue; } /* * If enabled, warn about weak passwords even if you are * root (enter this password again to use it anyway). * --marekm */ if (amroot && !warned && getdef_bool ("PASS_ALWAYS_WARN") && (!obscure (orig, pass, pw) || reuse (pass, pw))) { (void) puts (_("\nWarning: weak password (enter it again to use it anyway).")); warned = true; continue; } cp = getpass (_("Re-enter new password: ")); if (NULL == cp) { memzero (orig, sizeof orig); return -1; } if (strcmp (cp, pass) != 0) { (void) fputs (_("They don't match; try again.\n"), stderr); } else { strzero (cp); break; } } memzero (orig, sizeof orig); if (i == 0) { memzero (pass, sizeof pass); return -1; } /* * Encrypt the password, then wipe the cleartext password. */ salt = crypt_make_salt (NULL, NULL); cp = pw_encrypt (pass, salt); memzero (pass, sizeof pass); if (NULL == cp) { fprintf (stderr, _("%s: failed to crypt password with salt '%s': %s\n"), Prog, salt, strerror (errno)); return -1; } #ifdef HAVE_LIBCRACK_HIST HistUpdate (pw->pw_name, crypt_passwd); #endif /* HAVE_LIBCRACK_HIST */ STRFCPY (crypt_passwd, cp); return 0; } /* * check_password - test a password to see if it can be changed * * check_password() sees if the invoker has permission to change the * password for the given user. */ static void check_password (const struct passwd *pw, const struct spwd *sp) { time_t now; int exp_status; exp_status = isexpired (pw, sp); /* * If not expired and the "change only if expired" option (idea from * PAM) was specified, do nothing. --marekm */ if (kflg && (0 == exp_status)) { exit (E_SUCCESS); } /* * Root can change any password any time. */ if (amroot) { return; } (void) time (&now); /* * Expired accounts cannot be changed ever. Passwords which are * locked may not be changed. Passwords where min > max may not be * changed. Passwords which have been inactive too long cannot be * changed. */ if ( (sp->sp_pwdp[0] == '!') || (exp_status > 1) || ( (sp->sp_max >= 0) && (sp->sp_min > sp->sp_max))) { (void) fprintf (stderr, _("The password for %s cannot be changed.\n"), sp->sp_namp); SYSLOG ((LOG_WARN, "password locked for '%s'", sp->sp_namp)); closelog (); exit (E_NOPERM); } /* * Passwords may only be changed after sp_min time is up. */ if (sp->sp_lstchg > 0) { time_t ok; ok = (time_t) sp->sp_lstchg * SCALE; if (sp->sp_min > 0) { ok += (time_t) sp->sp_min * SCALE; } if (now < ok) { (void) fprintf (stderr, _("The password for %s cannot be changed yet.\n"), pw->pw_name); SYSLOG ((LOG_WARN, "now < minimum age for '%s'", pw->pw_name)); closelog (); exit (E_NOPERM); } } } #endif /* !USE_PAM */ static /*@observer@*/const char *date_to_str (time_t t) { static char buf[80]; struct tm *tm; tm = gmtime (&t); #ifdef HAVE_STRFTIME (void) strftime (buf, sizeof buf, "%m/%d/%Y", tm); #else /* !HAVE_STRFTIME */ (void) snprintf (buf, sizeof buf, "%02d/%02d/%04d", tm->tm_mon + 1, tm->tm_mday, tm->tm_year + 1900); #endif /* !HAVE_STRFTIME */ return buf; } static /*@observer@*/const char *pw_status (const char *pass) { if (*pass == '*' || *pass == '!') { return "L"; } if (*pass == '\0') { return "NP"; } return "P"; } /* * print_status - print current password status */ static void print_status (const struct passwd *pw) { struct spwd *sp; sp = getspnam (pw->pw_name); /* local, no need for xgetspnam */ if (NULL != sp) { (void) printf ("%s %s %s %lld %lld %lld %lld\n", pw->pw_name, pw_status (sp->sp_pwdp), date_to_str (sp->sp_lstchg * SCALE), ((long long)sp->sp_min * SCALE) / DAY, ((long long)sp->sp_max * SCALE) / DAY, ((long long)sp->sp_warn * SCALE) / DAY, ((long long)sp->sp_inact * SCALE) / DAY); } else { (void) printf ("%s %s\n", pw->pw_name, pw_status (pw->pw_passwd)); } } static /*@noreturn@*/void fail_exit (int status) { if (pw_locked) { if (pw_unlock () == 0) { (void) fprintf (stderr, _("%s: failed to unlock %s\n"), Prog, pw_dbname ()); SYSLOG ((LOG_ERR, "failed to unlock %s", pw_dbname ())); /* continue */ } } if (spw_locked) { if (spw_unlock () == 0) { (void) fprintf (stderr, _("%s: failed to unlock %s\n"), Prog, spw_dbname ()); SYSLOG ((LOG_ERR, "failed to unlock %s", spw_dbname ())); /* continue */ } } exit (status); } static /*@noreturn@*/void oom (void) { (void) fprintf (stderr, _("%s: out of memory\n"), Prog); fail_exit (E_FAILURE); } static char *update_crypt_pw (char *cp) { #ifndef USE_PAM if (do_update_pwd) { cp = xstrdup (crypt_passwd); } #endif /* !USE_PAM */ if (dflg) { *cp = '\0'; } if (uflg && *cp == '!') { if (cp[1] == '\0') { (void) fprintf (stderr, _("%s: unlocking the password would result in a passwordless account.\n" "You should set a password with usermod -p to unlock the password of this account.\n"), Prog); fail_exit (E_FAILURE); } else { cp++; } } if (lflg && *cp != '!') { char *newpw = xmalloc (strlen (cp) + 2); strcpy (newpw, "!"); strcat (newpw, cp); cp = newpw; } return cp; } static void update_noshadow (void) { const struct passwd *pw; struct passwd *npw; if (pw_lock () == 0) { (void) 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) { (void) 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) { (void) 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) { (void) 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) { (void) 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) { (void) 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 update_shadow (void) { const struct spwd *sp; struct spwd *nsp; if (spw_lock () == 0) { (void) fprintf (stderr, _("%s: cannot lock %s; try again later.\n"), Prog, spw_dbname ()); exit (E_PWDBUSY); } spw_locked = true; if (spw_open (O_RDWR) == 0) { (void) fprintf (stderr, _("%s: cannot open %s\n"), Prog, spw_dbname ()); SYSLOG ((LOG_WARN, "cannot open %s", spw_dbname ())); fail_exit (E_FAILURE); } sp = spw_locate (name); if (NULL == sp) { /* Try to update the password in /etc/passwd instead. */ (void) spw_close (); update_noshadow (); if (spw_unlock () == 0) { (void) fprintf (stderr, _("%s: failed to unlock %s\n"), Prog, spw_dbname ()); SYSLOG ((LOG_ERR, "failed to unlock %s", spw_dbname ())); /* continue */ } spw_locked = false; return; } nsp = __spw_dup (sp); if (NULL == nsp) { oom (); } nsp->sp_pwdp = update_crypt_pw (nsp->sp_pwdp); if (xflg) { nsp->sp_max = (age_max * DAY) / SCALE; } if (nflg) { nsp->sp_min = (age_min * DAY) / SCALE; } if (wflg) { nsp->sp_warn = (warn * DAY) / SCALE; } if (iflg) { nsp->sp_inact = (inact * DAY) / SCALE; } #ifndef USE_PAM if (do_update_age) { nsp->sp_lstchg = (long) time ((time_t *) 0) / SCALE; if (0 == nsp->sp_lstchg) { /* Better disable aging than requiring a password * change */ nsp->sp_lstchg = -1; } } #endif /* !USE_PAM */ /* * Force change on next login, like SunOS 4.x passwd -e or Solaris * 2.x passwd -f. Solaris 2.x seems to do the same thing (set * sp_lstchg to 0). */ if (eflg) { nsp->sp_lstchg = 0; } if (spw_update (nsp) == 0) { (void) fprintf (stderr, _("%s: failed to prepare the new %s entry '%s'\n"), Prog, spw_dbname (), nsp->sp_namp); fail_exit (E_FAILURE); } if (spw_close () == 0) { (void) 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 (spw_unlock () == 0) { (void) fprintf (stderr, _("%s: failed to unlock %s\n"), Prog, spw_dbname ()); SYSLOG ((LOG_ERR, "failed to unlock %s", spw_dbname ())); /* continue */ } spw_locked = false; } #ifdef WITH_SELINUX static int check_selinux_access (const char *changed_user, uid_t changed_uid, access_vector_t requested_access) { int status = -1; security_context_t user_context; context_t c; const char *user; /* if in permissive mode then allow the operation */ if (security_getenforce() == 0) { return 0; } /* get the context of the process which executed passwd */ if (getprevcon(&user_context) != 0) { return -1; } /* get the "user" portion of the context (the part before the first colon) */ c = context_new(user_context); user = context_user_get(c); /* if changing a password for an account with UID==0 or for an account where the identity matches then return success */ if (changed_uid != 0 && strcmp(changed_user, user) == 0) { status = 0; } else { struct av_decision avd; int retval; retval = security_compute_av(user_context, user_context, SECCLASS_PASSWD, requested_access, &avd); if ((retval == 0) && ((requested_access & avd.allowed) == requested_access)) { status = 0; } } context_free(c); freecon(user_context); return status; } #endif /* WITH_SELINUX */ /* * passwd - change a user's password file information * * This command controls the password file and commands which are used * to modify it. * * The valid options are * * -d delete the password for the named account (*) * -e expire the password for the named account (*) * -f execute chfn command to interpret flags * -g execute gpasswd command to interpret flags * -i # set sp_inact to # days (*) * -k change password only if expired * -l lock the password of the named account (*) * -n # set sp_min to # days (*) * -r # change password in # repository * -s execute chsh command to interpret flags * -S show password status of named account * -u unlock the password of the named account (*) * -w # set sp_warn to # days (*) * -x # set sp_max to # days (*) * * (*) requires root permission to execute. * * All of the time fields are entered in days and converted to the * appropriate internal format. For finer resolute the chage * command must be used. */ int main (int argc, char **argv) { const struct passwd *pw; /* Password file entry for user */ #ifndef USE_PAM char *cp; /* Miscellaneous character pointing */ const struct spwd *sp; /* Shadow file entry for user */ #endif /* !USE_PAM */ sanitize_env (); /* * Get the program name. The program name is used as a prefix to * most error messages. */ Prog = Basename (argv[0]); (void) setlocale (LC_ALL, ""); (void) bindtextdomain (PACKAGE, LOCALEDIR); (void) textdomain (PACKAGE); process_root_flag ("-R", argc, argv); /* * The program behaves differently when executed by root than when * executed by a normal user. */ amroot = (getuid () == 0); OPENLOG ("passwd"); { /* * Parse the command line options. */ int c; static struct option long_options[] = { {"all", no_argument, NULL, 'a'}, {"delete", no_argument, NULL, 'd'}, {"expire", no_argument, NULL, 'e'}, {"help", no_argument, NULL, 'h'}, {"inactive", required_argument, NULL, 'i'}, {"keep-tokens", no_argument, NULL, 'k'}, {"lock", no_argument, NULL, 'l'}, {"mindays", required_argument, NULL, 'n'}, {"quiet", no_argument, NULL, 'q'}, {"repository", required_argument, NULL, 'r'}, {"root", required_argument, NULL, 'R'}, {"status", no_argument, NULL, 'S'}, {"unlock", no_argument, NULL, 'u'}, {"warndays", required_argument, NULL, 'w'}, {"maxdays", required_argument, NULL, 'x'}, {NULL, 0, NULL, '\0'} }; while ((c = getopt_long (argc, argv, "adehi:kln:qr:R:Suw:x:", long_options, NULL)) != -1) { switch (c) { case 'a': aflg = true; break; case 'd': dflg = true; anyflag = true; break; case 'e': eflg = true; anyflag = true; break; case 'h': usage (E_SUCCESS); /*@notreached@*/break; case 'i': if ( (getlong (optarg, &inact) == 0) || (inact < -1)) { fprintf (stderr, _("%s: invalid numeric argument '%s'\n"), Prog, optarg); usage (E_BAD_ARG); } iflg = true; anyflag = true; break; case 'k': /* change only if expired, like Linux-PAM passwd -k. */ kflg = true; /* ok for users */ break; case 'l': lflg = true; anyflag = true; break; case 'n': if ( (getlong (optarg, &age_min) == 0) || (age_min < -1)) { fprintf (stderr, _("%s: invalid numeric argument '%s'\n"), Prog, optarg); usage (E_BAD_ARG); } nflg = true; anyflag = true; break; case 'q': qflg = true; /* ok for users */ break; case 'r': /* -r repository (files|nis|nisplus) */ /* only "files" supported for now */ if (strcmp (optarg, "files") != 0) { fprintf (stderr, _("%s: repository %s not supported\n"), Prog, optarg); exit (E_BAD_ARG); } break; case 'R': /* no-op, handled in process_root_flag () */ break; case 'S': Sflg = true; /* ok for users */ break; case 'u': uflg = true; anyflag = true; break; case 'w': if ( (getlong (optarg, &warn) == 0) || (warn < -1)) { (void) fprintf (stderr, _("%s: invalid numeric argument '%s'\n"), Prog, optarg); usage (E_BAD_ARG); } wflg = true; anyflag = true; break; case 'x': if ( (getlong (optarg, &age_max) == 0) || (age_max < -1)) { (void) fprintf (stderr, _("%s: invalid numeric argument '%s'\n"), Prog, optarg); usage (E_BAD_ARG); } xflg = true; anyflag = true; break; default: usage (E_BAD_ARG); } } } /* * Now I have to get the user name. The name will be gotten from the * command line if possible. Otherwise it is figured out from the * environment. */ pw = get_my_pwent (); if (NULL == pw) { (void) fprintf (stderr, _("%s: Cannot determine your user name.\n"), Prog); SYSLOG ((LOG_WARN, "Cannot determine the user name of the caller (UID %lu)", (unsigned long) getuid ())); exit (E_NOPERM); } myname = xstrdup (pw->pw_name); if (optind < argc) { name = argv[optind]; } else { name = myname; } /* * Make sure that at most one username was specified. */ if (argc > (optind+1)) { usage (E_USAGE); } /* * The -a flag requires -S, no other flags, no username, and * you must be root. --marekm */ if (aflg) { if (anyflag || !Sflg || (optind < argc)) { usage (E_USAGE); } if (!amroot) { (void) fprintf (stderr, _("%s: Permission denied.\n"), Prog); exit (E_NOPERM); } setpwent (); while ( (pw = getpwent ()) != NULL ) { print_status (pw); } endpwent (); exit (E_SUCCESS); } #if 0 /* * Allow certain users (administrators) to change passwords of * certain users. Not implemented yet. --marekm */ if (may_change_passwd (myname, name)) amroot = 1; #endif /* * If any of the flags were given, a user name must be supplied on * the command line. Only an unadorned command line doesn't require * the user's name be given. Also, -x, -n, -w, -i, -e, -d, * -l, -u may appear with each other. -S, -k must appear alone. */ /* * -S now ok for normal users (check status of my own account), and * doesn't require username. --marekm */ if (anyflag && optind >= argc) { usage (E_USAGE); } if ( (Sflg && kflg) || (anyflag && (Sflg || kflg))) { usage (E_USAGE); } if (anyflag && !amroot) { (void) fprintf (stderr, _("%s: Permission denied.\n"), Prog); exit (E_NOPERM); } pw = xgetpwnam (name); if (NULL == pw) { (void) fprintf (stderr, _("%s: user '%s' does not exist\n"), Prog, name); exit (E_NOPERM); } #ifdef WITH_SELINUX /* only do this check when getuid()==0 because it's a pre-condition for changing a password without entering the old one */ if ((is_selinux_enabled() > 0) && (getuid() == 0) && (check_selinux_access (name, pw->pw_uid, PASSWD__PASSWD) != 0)) { security_context_t user_context = NULL; const char *user = "Unknown user context"; if (getprevcon (&user_context) == 0) { user = user_context; /* FIXME: use context_user_get? */ } SYSLOG ((LOG_ALERT, "%s is not authorized to change the password of %s", user, name)); (void) fprintf(stderr, _("%s: %s is not authorized to change the password of %s\n"), Prog, user, name); if (NULL != user_context) { freecon (user_context); } exit (E_NOPERM); } #endif /* WITH_SELINUX */ /* * If the UID of the user does not match the current real UID, * check if I'm root. */ if (!amroot && (pw->pw_uid != getuid ())) { (void) fprintf (stderr, _("%s: You may not view or modify password information for %s.\n"), Prog, name); SYSLOG ((LOG_WARN, "%s: can't view or modify password information for %s", Prog, name)); closelog (); exit (E_NOPERM); } if (Sflg) { print_status (pw); exit (E_SUCCESS); } #ifndef USE_PAM /* * The user name is valid, so let's get the shadow file entry. */ sp = getspnam (name); /* !USE_PAM, no need for xgetspnam */ if (NULL == sp) { if (errno == EACCES) { (void) fprintf (stderr, _("%s: Permission denied.\n"), Prog); exit (E_NOPERM); } sp = pwd_to_spwd (pw); } cp = sp->sp_pwdp; /* * If there are no other flags, just change the password. */ if (!anyflag) { STRFCPY (crypt_passwd, cp); /* * See if the user is permitted to change the password. * Otherwise, go ahead and set a new password. */ check_password (pw, sp); /* * Let the user know whose password is being changed. */ if (!qflg) { (void) printf (_("Changing password for %s\n"), name); } if (new_password (pw) != 0) { (void) fprintf (stderr, _("The password for %s is unchanged.\n"), name); closelog (); exit (E_NOPERM); } do_update_pwd = true; do_update_age = true; } #endif /* !USE_PAM */ /* * 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. */ pwd_init (); #ifdef USE_PAM /* * Don't set the real UID for PAM... */ if (!anyflag) { do_pam_passwd (name, qflg, kflg); exit (E_SUCCESS); } #endif /* USE_PAM */ if (setuid (0) != 0) { (void) fputs (_("Cannot change ID to root.\n"), stderr); SYSLOG ((LOG_ERR, "can't setuid(0)")); closelog (); exit (E_NOPERM); } if (spw_file_present ()) { update_shadow (); } else { update_noshadow (); } nscd_flush_cache ("passwd"); nscd_flush_cache ("group"); SYSLOG ((LOG_INFO, "password for '%s' changed by '%s'", name, myname)); closelog (); if (!qflg) { if (!anyflag) { #ifndef USE_PAM (void) printf (_("%s: password changed.\n"), Prog); #endif /* USE_PAM */ } else { (void) printf (_("%s: password expiry information changed.\n"), Prog); } } return E_SUCCESS; } ./COPYING0000664000175000017500000001160112304427047012472 0ustar nielsenrnielsenrNOTE: This license has been obsoleted by the change to the BSD-style copyright. You may continue to use this license if you wish, but you are under no obligation to do so. (* This document is freely plagiarised from the 'Artistic Licence', distributed as part of the Perl v4.0 kit by Larry Wall, which is available from most major archive sites. I stole it from CrackLib. $Id$ *) This documents purpose is to state the conditions under which this Package (See definition below) viz: "Shadow", the Shadow Password Suite which is held by Julianne Frances Haugh, may be copied, such that the copyright holder maintains some semblance of artistic control over the development of the package, while giving the users of the package the right to use and distribute the Package in a more-or-less customary fashion, plus the right to make reasonable modifications. So there. *************************************************************************** Definitions: A "Package" refers to the collection of files distributed by the Copyright Holder, and derivatives of that collection of files created through textual modification, or segments thereof. "Standard Version" refers to such a Package if it has not been modified, or has been modified in accordance with the wishes of the Copyright Holder. "Copyright Holder" is whoever is named in the copyright or copyrights for the package. "You" is you, if you're thinking about copying or distributing this Package. "Reasonable copying fee" is whatever you can justify on the basis of media cost, duplication charges, time of people involved, and so on. (You will not be required to justify it to the Copyright Holder, but only to the computing community at large as a market that must bear the fee.) "Freely Available" means that no fee is charged for the item itself, though there may be fees involved in handling the item. It also means that recipients of the item may redistribute it under the same conditions they received it. 1. You may make and give away verbatim copies of the source form of the Standard Version of this Package without restriction, provided that you duplicate all of the original copyright notices and associated disclaimers. 2. You may apply bug fixes, portability fixes and other modifications derived from the Public Domain or from the Copyright Holder. A Package modified in such a way shall still be considered the Standard Version. 3. You may otherwise modify your copy of this Package in any way, provided that you insert a prominent notice in each changed file stating how and when AND WHY you changed that file, and provided that you do at least ONE of the following: a) place your modifications in the Public Domain or otherwise make them Freely Available, such as by posting said modifications to Usenet or an equivalent medium, or placing the modifications on a major archive site such as uunet.uu.net, or by allowing the Copyright Holder to include your modifications in the Standard Version of the Package. b) use the modified Package only within your corporation or organization. c) rename any non-standard executables so the names do not conflict with standard executables, which must also be provided, and provide separate documentation for each non-standard executable that clearly documents how it differs from the Standard Version. d) make other distribution arrangements with the Copyright Holder. 4. You may distribute the programs of this Package in object code or executable form, provided that you do at least ONE of the following: a) distribute a Standard Version of the executables and library files, together with instructions (in the manual page or equivalent) on where to get the Standard Version. b) accompany the distribution with the machine-readable source of the Package with your modifications. c) accompany any non-standard executables with their corresponding Standard Version executables, giving the non-standard executables non-standard names, and clearly documenting the differences in manual pages (or equivalent), together with instructions on where to get the Standard Version. d) make other distribution arrangements with the Copyright Holder. 5. You may charge a reasonable copying fee for any distribution of this Package. You may charge any fee you choose for support of this Package. YOU MAY NOT CHARGE A FEE FOR THIS PACKAGE ITSELF. However, you may distribute this Package in aggregate with other (possibly commercial) programs as part of a larger (possibly commercial) software distribution provided that YOU DO NOT ADVERTISE this package as a product of your own. 6. The name of the Copyright Holder may not be used to endorse or promote products derived from this software without specific prior written permission. 7. THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. The End