/* * Copyright 1989 - 1994, Julianne Frances Haugh * 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 Julianne F. Haugh 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 JULIE HAUGH 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 JULIE HAUGH 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. */ #ifdef _WIN32 #include /* For WNetGetUser */ #else #include #endif #ifndef OS2 #ifndef _WIN32 #include "prototypes.h" #include "defines.h" #endif #endif #include #include #include #include #ifdef OS2 #ifndef _WIN32 #include #endif #endif #include #include #ifndef _WIN32 #ifndef OS2 #include #include "pwauth.h" #include "pwio.h" #include "getdef.h" #else /* OS2 */ #define bzero(x,y) memset(x,0,y) #define tpw_lock() 1 #define tpw_unlock() 1 #define SYSLOG(x) struct passwd { char *pw_name; char *pw_passwd; int pw_uid; int pw_gid; char *pw_age; char *pw_comment; char *pw_gecos; char *pw_dir; char *pw_shell; }; #endif /* OS2 */ #else /* _WIN32 */ #define bzero(x,y) memset(x,0,y) #define tpw_lock() 1 #define tpw_unlock() 1 #define SYSLOG(x) struct passwd { char *pw_name; char *pw_passwd; int pw_uid; int pw_gid; char *pw_age; char *pw_comment; char *pw_gecos; char *pw_dir; char *pw_shell; }; #endif /* _WIN32 */ /* EPS STUFF */ #include "t_pwd.h" static int do_update_eps = 0; struct t_pw eps_passwd; /* * Global variables */ static char *name; /* The name of user whose password is being changed */ static char myname[64]; /* The current user's name */ static char *Prog; /* Program name */ static int amroot; /* The real UID was 0 */ static int aflg = 0, /* -a - add user */ dflg = 0, /* -d - delete password */ qflg = 0; /* -q - quiet mode */ /* * set to 1 if there are any flags which require root privileges, * and require username to be specified */ static int anyflag = 0; #ifdef AGING static long age_min = 0; /* Minimum days before change */ static long age_max = 0; /* Maximum days until change */ #endif static int do_update_age = 0; static char crypt_passwd[128]; /* The "old-style" password, if present */ /* * External identifiers */ extern char *crypt_make_salt(); #if !defined(__GLIBC__) extern char *l64a(); #endif extern int optind; /* Index into argv[] for current option */ extern char *optarg; /* Pointer to current option value */ #ifdef NDBM extern int sp_dbm_mode; extern int pw_dbm_mode; #endif /* * #defines for messages. This facilities foreign language conversion * since all messages are defined right here. */ #define USAGE \ "usage: %s [ -a | -d | -q ] name\n" #define ADMUSAGE \ " %s [ -x max ] [ -n min ] [ -w warn ] [ -i inact ] name\n" #define ADMUSAGE2 \ " %s { -l | -u | -d | -S | -e } name\n" #define OLDPASS "Old password:" #define ROOTPASS "Enter 'root' password:" #define NEWPASSMSG \ "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" #define CHANGING "Changing password for %s\n" #define ADDING "Adding user %s\n" #define NEWPASS "New password:" #define NEWPASS2 "Re-enter new password:" #define WRONGPWD "Incorrect password for %s.\n" #define WRONGPWD2 "incorrect password for `%s'" #define NOMATCH "They don't match; try again.\n" #define CANTCHANGE "The password for %s cannot be changed.\n" #define CANTCHANGE2 "password locked for `%s'" #define BADPASS "Bad password: %s. " #define EPSFAIL "Unable to update EPS password.\n" #define NOEPSCONF "Warning: configuration file missing; please run 'tconf'\n" #define TOOSOON "Sorry, the password for %s cannot be changed yet.\n" #define TOOSOON2 "now < minimum age for `%s'" #define EXECFAILED "%s: Cannot execute %s" #define EXECFAILED2 "cannot execute %s" #define WHOAREYOU "%s: Cannot determine your user name.\n" #define UNKUSER "%s: Unknown user %s\n" #define NOPERM "You may not change the password for %s.\n" #define NOPERM2 "can't change pwd for `%s'" #define UNCHANGED "The password for %s is unchanged.\n" #define PWDBUSY "Cannot lock the password file; try again later.\n" #define OPNERROR "Cannot open the password file.\n" #define UPDERROR "Error updating the password entry.\n" #define CLSERROR "Cannot commit password file changes.\n" #define DBMERROR "Error updating the DBM password entry.\n" #define PWDBUSY2 "can't lock password file" #define OPNERROR2 "can't open password file" #define UPDERROR2 "error updating password entry" #define CLSERROR2 "can't rewrite password file" #define DBMERROR2 "error updaring dbm password entry" #define NOTROOT "Cannot change ID to root.\n" #define NOTROOT2 "can't setuid(0)" #define TRYAGAIN "Try again.\n" #define PASSWARN \ "\nWarning: weak password (enter it again to use it anyway).\n" #define CHANGED "Password changed.\n" #define CHGPASSWD "password for `%s' changed by user `%s'" #define NOCHGPASSWD "did not change password for `%s'" #define DELETING "Deleting password for '%s'.\n" #define DELETED "Password for '%s' deleted.\n" #define ADDED "Password set for user '%s'\n" #define NOTADDED "Unable to add user '%s'\n" /* * usage - print command usage and exit */ static void usage(status) int status; { fprintf(stderr, USAGE, Prog); if (amroot) { fprintf(stderr, ADMUSAGE, Prog); fprintf(stderr, ADMUSAGE2, Prog); } exit(status); } /* * new_password - validate old password and replace with new * (both old and new in global "char crypt_passwd[128]") */ /*ARGSUSED*/ static int new_password() { char clear[128]; /* Pointer to clear text */ char *cipher; /* Pointer to cipher text */ char *cp; /* Pointer to getpass() response */ char orig[128]; /* Original password */ char pass[128]; /* New password */ int i; /* Counter for retries */ int warned; int pass_max_len=127; int rc = 0; /* * Authenticate the user. The user will be prompted for their * own password. */ bzero(clear, 128); bzero(orig, 128); bzero(pass, 128); if (!amroot) { /* EPS STUFF */ int retval; cipher = NULL; t_getpass (clear, 128, OLDPASS); if ((retval = t_verifypw (name, clear)) > -1) { endtpent(); retval = (retval == 0) ? 1 : 0; } else { if (strlen (clear) > pass_max_len) { memset(clear+pass_max_len, 0, strlen (clear+pass_max_len)); clear[pass_max_len] = '\0'; } } if (retval != 0) { SYSLOG((LOG_WARN, WRONGPWD2, name)); fprintf(stderr, WRONGPWD, name); return -1; } else { strcpy(orig, clear); bzero(clear, strlen (clear)); if (cipher) bzero(cipher, strlen (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. */ if (!qflg) printf(NEWPASSMSG, 5, 127); warned = 0; for (i = 5; i > 0; i--) { t_getpass (clear, 128, NEWPASS); cp = clear; if (!cp) { bzero (orig, sizeof orig); return -1; } strcpy(pass, cp); bzero(cp, strlen(cp)); t_getpass (clear, 128, NEWPASS2); cp = clear; if (!cp) { bzero (orig, sizeof orig); bzero (clear, sizeof clear); bzero (pass, sizeof pass); return -1; } if (strcmp (cp, pass)) { bzero (clear, sizeof clear); bzero (pass, sizeof pass); fprintf (stderr, NOMATCH); } else break; } bzero (orig, sizeof orig); if (i == 0) { bzero (clear, sizeof clear); bzero (pass, sizeof pass); return -1; } /* * Encrypt the password, then wipe the cleartext password. */ /* EPS STUFF */ { struct t_conf *tc; struct t_confent *tcent; if ((tc = t_openconf(NULL)) == NULL || (tcent = t_getconflast(tc)) == NULL) { fprintf(stderr, NOEPSCONF); do_update_eps = 0; rc = -1; } else { do_update_eps = 1; if (t_makepwent (&eps_passwd, name, pass, NULL, tcent) == NULL) rc = -1; } if (tc) t_closeconf (tc); pass[pass_max_len] = '\0'; } return rc; } /* * 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. */ /*ARGSUSED*/ static char * date_to_str(time_t t) { static char buf[80]; struct tm *tm; tm = gmtime(&t); sprintf(buf, "%02d/%02d/%02d", tm->tm_mon + 1, tm->tm_mday, tm->tm_year % 100); return buf; } static const char * pw_status(pass) 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(pw) const struct passwd *pw; { printf("%s %s\n", pw->pw_name, pw_status(pw->pw_passwd)); } static void fail_exit(status) int status; { tpw_unlock(); exit(status); } static void oom() { fprintf(stderr, "%s: out of memory\n", Prog); fail_exit(3); } static long getnumber(str) const char *str; { long val; char *cp; val = strtol(str, &cp, 10); if (*cp) usage(6); return val; } /* * 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 * * -l lock the named account (*) * -u unlock the named account (*) * -d delete the password for the named account (*) * -e expire the password for the named account (*) * -x # set sp_max to # days (*) * -n # set sp_min to # days (*) * -w # set sp_warn to # days (*) * -i # set sp_inact to # days (*) * -S show password status of named account * -g execute gpasswd command to interpret flags * -f execute chfn command to interpret flags * -s execute chsh command to interpret flags * -k change password only if expired * * (*) 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. * * Exit status: * 0 - success * 1 - permission denied * 2 - invalid combination of options * 3 - unexpected failure, password file unchanged * 5 - password file busy, try again later * 6 - invalid argument to option */ int main(argc, argv) int argc; char **argv; { char *cp; /* Miscellaneous character pointing */ int flag; /* Current option to process */ unsigned long mynamelen; struct t_pwent pwent; struct t_pw * pw; /* * The program behaves differently when executed by root * than when executed by a normal user. */ #ifdef WIN32 amroot = 0; #else #ifdef OS2 amroot = 0; #else amroot = (getuid () == 0); #endif #endif /* * Get the program name. The program name is used as a * prefix to most error messages. */ Prog = argv[0]; /* * 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. */ #define FLAGS "adq" while ((flag = getopt(argc, argv, FLAGS)) != EOF) { #undef FLAGS switch (flag) { case 'q': qflg++; /* ok for users */ break; case 'd': dflg++; anyflag = 1; break; case 'a': aflg++; anyflag = 1; break; default: usage(6); } } if ( !ck_crypto_loaddll() ) { fprintf(stderr, "%s: unable to load crypto dll\n",Prog); exit(1); } ck_OPENSSL_add_all_algorithms_noconf(); /* * 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. */ mynamelen = sizeof(myname); #ifdef WIN32 WNetGetUser( NULL, myname, &mynamelen); #endif /* WIN32 */ #ifdef OS2 { char * env = getenv("USER"); if (env) { strncpy(myname,env,64); myname[63] = '\0'; } } #endif /* OS2 */ if (optind < argc) name = argv[optind]; else name = myname; if (anyflag && optind >= argc) usage(2); #ifdef OS2 #define AMROOT #else #ifdef WIN32 #define AMROOT #endif #endif #ifdef AMROOT pw= t_openpwbyname((char *)t_defaultpwd()); if ( !pw ) { amroot = 1; if ( !aflg || strcmp("root",name) ) { fprintf(stderr,"Password file does not exist!!!!\n"); fprintf(stderr,"The first entry in a password file must be 'root'\n"); fprintf(stderr,"Execute '%s -a root'\n",Prog); exit(1); } } else if (anyflag) { char clear[128]; int rc; t_closepw(pw); t_getpass (clear, 128, ROOTPASS); rc = t_verifypw ("root", clear); if (rc > -1) endtpent(); if ( rc == 1 ) amroot = 1; } else t_closepw(pw); #endif if (anyflag && !amroot) { fprintf(stderr, "%s: Permission denied\n", Prog); exit(1); } if ( dflg ) { if ( !qflg ) printf(DELETING, name); pwent.name = name; pwent.password.len = 0; pwent.password.data = NULL; /* delete the password */ if (t_deletepw (NULL, name) < 0) { fprintf (stderr, EPSFAIL); exit(1); } if ( !qflg ) printf(DELETED, name); return(0); } if ( aflg ) { pw= t_openpwbyname((char *)t_defaultpwd()); if ( !qflg ) printf(ADDING, name); if (pw && t_getpwbyname(pw,name)) { t_closepw(pw); fprintf(stderr,"user '%s' already exists in password file\n",name); exit(1); } if ( pw ) t_closepw(pw); pwent.name = name; pwent.password.len = 0; pwent.password.data = NULL; if (new_password()) { fprintf(stderr, NOTADDED, name); exit(1); } if ( !qflg ) printf(ADDED, name); } /* * If there are no other flags, just change the password. */ if (!anyflag) { crypt_passwd[0] = '\0'; /* * See if the user is permitted to change the password. * Otherwise, go ahead and set a new password. */ /* * Let the user know whose password is being changed. */ if (!qflg) printf(CHANGING, name); #ifdef OS2 amroot = 0; #else #ifdef NT amroot = 0; #endif #endif if (new_password()) { fprintf(stderr, UNCHANGED, name); exit(1); } } /* EPS STUFF */ if (do_update_eps) { /* try and see if the file is there, else create it */ if ((pw = t_openpwbyname((char *)t_defaultpwd())) == NULL) { int fh = creat ((char *)t_defaultpwd(), 0600); if (fh == -1) { fprintf(stderr,"Unable to open password file\n"); fail_exit(5); } close(fh); } else t_closepw(pw); /* change the password */ if (t_changepw ((char *)t_defaultpwd(), &(eps_passwd.pebuf)) < 0) { fprintf (stderr, EPSFAIL); exit(1); } } else { fprintf (stderr, EPSFAIL); exit(1); } if (!qflg) printf(CHANGED); return(0); } .