/* * $Id: pam_unix_acct.-c,v 1.6 1997/01/04 20:37:15 morgan Exp morgan $ * * $Log: pam_unix_acct.-c,v $ * Revision 1.6 1997/01/04 20:37:15 morgan * extra debugging * * Revision 1.5 1996/12/01 03:05:54 morgan * debugging with _pam_macros.h * * Revision 1.4 1996/11/10 21:03:57 morgan * pwdb conversion * * Revision 1.3 1996/09/05 06:45:45 morgan * tidied shadow acct management * * Revision 1.2 1996/09/01 01:13:14 morgan * Cristian Gafton's patches * * Revision 1.1 1996/08/29 13:27:51 morgan * Initial revision * * * See end of file for copyright information */ static const char rcsid_acct[] = "$Id: pam_unix_acct.-c,v 1.6 1997/01/04 20:37:15 morgan Exp morgan $\n" " - PAM_PWDB account management "; /* the shadow suite has accout managment.. */ static int _shadow_acct_mgmt_exp(pam_handle_t *pamh, unsigned int ctrl, const struct pwdb *pw, const char *uname) { const struct pwdb_entry *pwe = NULL; time_t curdays; int last_change, max_change; int retval; D(("called.")); /* Now start the checks */ curdays = time(NULL)/(60*60*24); /* today */ /* First: has account expired ? (CG) * - expire < curdays * - or (last_change + max_change + defer_change) < curdays * - in both cases, deny access */ D(("pwdb_get_entry")); retval = pwdb_get_entry(pw, "expire", &pwe); if (retval == PWDB_SUCCESS) { int expire; expire = *( (const int *) pwe->value ); (void) pwdb_entry_delete(&pwe); /* no longer needed */ if ((curdays > expire) && (expire > 0)) { _log_err(LOG_NOTICE , "acct: account %s has expired (account expired)" , uname); make_remark(pamh, ctrl, PAM_ERROR_MSG , "Your account has expired; " "please contact your system administrator"); D(("account expired")); return PAM_ACCT_EXPIRED; } } D(("pwdb_get_entry")); retval = pwdb_get_entry(pw, "last_change", &pwe); if ( retval == PWDB_SUCCESS ) { last_change = *( (const int *) pwe->value ); } else { last_change = curdays; } (void) pwdb_entry_delete(&pwe); D(("pwdb_get_entry")); retval = pwdb_get_entry(pw, "max_change", &pwe); if ( retval == PWDB_SUCCESS ) { max_change = *( (const int *) pwe->value ); } else { max_change = -1; } (void) pwdb_entry_delete(&pwe); D(("pwdb_get_entry")); retval = pwdb_get_entry(pw, "defer_change", &pwe); if (retval == PWDB_SUCCESS) { int defer_change; defer_change = *( (const int *) pwe->value ); (void) pwdb_entry_delete(&pwe); if ((curdays > (last_change + max_change + defer_change)) && (max_change != -1) && (defer_change != -1) && (last_change > 0)) { if ( on(UNIX_DEBUG, ctrl) ) { _log_err(LOG_NOTICE, "acct: account %s has expired " "(failed to change password)", uname); } make_remark(pamh, ctrl, PAM_ERROR_MSG , "Your password has expired; " "please see your system administrator"); D(("account expired2")); return PAM_ACCT_EXPIRED; } } /* Now test if the password is expired, but the user still can * change their password. (CG) * - last_change = 0 * - last_change + max_change < curdays */ D(("when was the last change")); if (last_change == 0) { if ( on(UNIX_DEBUG, ctrl) ) { _log_err(LOG_NOTICE , "acct: expired password for user %s (root enforced)" , uname); } make_remark(pamh, ctrl, PAM_ERROR_MSG , "You are required to change your password immediately" ); D(("need a new password")); return PAM_NEW_AUTHTOK_REQD; } if (((last_change + max_change) < curdays) && (max_change < 99999) && (max_change > 0)) { if ( on(UNIX_DEBUG, ctrl) ) { _log_err(LOG_DEBUG , "acct: expired password for user %s (password aged)" , uname); } make_remark(pamh, ctrl, PAM_ERROR_MSG , "Your password has expired; please change it!"); D(("need a new password 2")); return PAM_NEW_AUTHTOK_REQD; } /* * Now test if the password is about to expire (CG) * - last_change + max_change - curdays <= warn_change */ retval = pwdb_get_entry(pw, "warn_change", &pwe); if ( retval == PWDB_SUCCESS ) { int warn_days, daysleft; daysleft = last_change + max_change - curdays; warn_days = *((const int *) pwe->value); (void) pwdb_entry_delete(&pwe); if ((daysleft <= warn_days) && (warn_days > 0)) { char *s; if ( on(UNIX_DEBUG, ctrl) ) { _log_err(LOG_DEBUG , "acct: password for user %s will expire in %d days" , uname, daysleft); } #define LocalComment "Warning: your password will expire in %d day%s" if ((s = (char *) malloc(30+sizeof(LocalComment))) == NULL) { _log_err(LOG_CRIT, "malloc failure in " __FILE__); retval = PAM_BUF_ERR; } else { sprintf(s, LocalComment, daysleft, daysleft == 1 ? "":"s"); make_remark(pamh, ctrl, PAM_TEXT_INFO, s); free(s); } #undef LocalComment } } else { retval = PAM_SUCCESS; } D(("all done")); return retval; } /* * this function checks for the account details. The user may not be * permitted to log in at this time etc.. Within the context of * vanilla Unix, this function simply does nothing. The shadow suite * added password/account expiry, but PWDB takes care of this * transparently. */ static int _unix_acct_mgmt(pam_handle_t *pamh, unsigned int ctrl) { const struct pwdb *pw = NULL; char *uname=NULL; int retval; D(("called.")); /* identify user */ retval = pam_get_item(pamh,PAM_USER,(const void **)&uname); D(("user = `%s'", uname)); if (retval != PAM_SUCCESS || uname == NULL) { _log_err(LOG_ALERT , "acct; could not identify user (from uid=%d)" , getuid()); return PAM_USER_UNKNOWN; } /* get database information for user */ retval = pwdb_locate("user", PWDB_DEFAULT, uname, PWDB_ID_UNKNOWN, &pw); if (retval != PWDB_SUCCESS || pw == NULL) { _log_err(LOG_ALERT, "acct; %s (%s from uid=%d)" , pwdb_strerror(retval), uname, getuid()); if ( pw ) { (void) pwdb_delete(&pw); } return PAM_USER_UNKNOWN; } /* now check the user's times etc.. */ retval = _shadow_acct_mgmt_exp(pamh, ctrl, pw, uname); if (retval != PAM_SUCCESS) { _log_err(LOG_NOTICE, "expiry check failed for '%s'", uname); } /* Done with pw */ (void) pwdb_delete(&pw); /* all done */ D(("done.")); return retval; } /* * Copyright (c) Elliot Lee, 1996. * Copyright (c) Andrew Morgan 1996. * Copyright (c) Cristian Gafton 1996. * * 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, and the entire permission notice in its entirety, * including the disclaimer of warranties. * 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 author may not be used to endorse or promote * products derived from this software without specific prior * written permission. * * ALTERNATIVELY, this product may be distributed under the terms of * the GNU Public License, in which case the provisions of the GPL are * required INSTEAD OF the above restrictions. (This clause is * necessary due to a potential bad interaction between the GPL and * the restrictions contained in a BSD-style copyright.) * * THIS SOFTWARE IS PROVIDED ``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 AUTHOR 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. */