| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441 |
- /** BEGIN COPYRIGHT BLOCK
- * This Program is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License as published by the Free Software
- * Foundation; version 2 of the License.
- *
- * This Program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
- * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this Program; if not, write to the Free Software Foundation, Inc., 59 Temple
- * Place, Suite 330, Boston, MA 02111-1307 USA.
- *
- * In addition, as a special exception, Red Hat, Inc. gives You the additional
- * right to link the code of this Program with code not covered under the GNU
- * General Public License ("Non-GPL Code") and to distribute linked combinations
- * including the two, subject to the limitations in this paragraph. Non-GPL Code
- * permitted under this exception must only link to the code of this Program
- * through those well defined interfaces identified in the file named EXCEPTION
- * found in the source code files (the "Approved Interfaces"). The files of
- * Non-GPL Code may instantiate templates or use macros or inline functions from
- * the Approved Interfaces without causing the resulting work to be covered by
- * the GNU General Public License. Only Red Hat, Inc. may make changes or
- * additions to the list of Approved Interfaces. You must obey the GNU General
- * Public License in all respects for all of the Program code and other code used
- * in conjunction with the Program except the Non-GPL Code covered by this
- * exception. If you modify this file, you may extend this exception to your
- * version of the file, but you are not obligated to do so. If you do not wish to
- * provide this exception without modification, you must delete this exception
- * statement from your version and license this file solely under the GPL without
- * exception.
- *
- *
- * Copyright (C) 2001 Sun Microsystems, Inc. Used by permission.
- * Copyright (C) 2005 Red Hat, Inc.
- * All rights reserved.
- * END COPYRIGHT BLOCK **/
- #ifdef HAVE_CONFIG_H
- # include <config.h>
- #endif
- /* pw_mgmt.c
- */
- #include <time.h>
- #include <string.h>
- #include "slap.h"
- /****************************************************************************/
- /* prototypes */
- /****************************************************************************/
- /* need_new_pw() is called when non rootdn bind operation succeeds with authentication */
- int
- need_new_pw( Slapi_PBlock *pb, long *t, Slapi_Entry *e, int pwresponse_req )
- {
- time_t cur_time, pw_exp_date;
- LDAPMod *mod;
- Slapi_Mods smods;
- double diff_t = 0;
- char *cur_time_str = NULL;
- char *passwordExpirationTime;
- char *timestring;
- char *dn;
- passwdPolicy *pwpolicy = NULL;
- int pwdGraceUserTime = 0;
- char graceUserTime[8];
- slapi_mods_init (&smods, 0);
- dn = slapi_entry_get_ndn( e );
- pwpolicy = new_passwdPolicy(pb, dn);
- /* after the user binds with authentication, clear the retry count */
- if ( pwpolicy->pw_lockout == 1)
- {
- if(slapi_entry_attr_get_int( e, "passwordRetryCount") > 0)
- {
- slapi_mods_add_string(&smods, LDAP_MOD_REPLACE, "passwordRetryCount", "0");
- }
- }
- cur_time = current_time();
- /* get passwordExpirationTime attribute */
- passwordExpirationTime= slapi_entry_attr_get_charptr(e, "passwordExpirationTime");
- if (passwordExpirationTime == NULL)
- {
- /* password expiration date is not set.
- * This is ok for data that has been loaded via ldif2ldbm
- * Set expiration time if needed,
- * don't do further checking and return 0 */
- if ( pwpolicy->pw_exp == 1) {
- pw_exp_date = time_plus_sec ( cur_time,
- pwpolicy->pw_maxage );
- timestring = format_genTime (pw_exp_date);
- slapi_mods_add_string(&smods, LDAP_MOD_REPLACE, "passwordExpirationTime", timestring);
- slapi_ch_free((void **)×tring);
- slapi_mods_add_string(&smods, LDAP_MOD_REPLACE, "passwordExpWarned", "0");
-
- pw_apply_mods(dn, &smods);
- } else if (pwpolicy->pw_lockout == 1) {
- pw_apply_mods(dn, &smods);
- }
- slapi_mods_done(&smods);
- delete_passwdPolicy(&pwpolicy);
- return ( 0 );
- }
- pw_exp_date = parse_genTime(passwordExpirationTime);
- slapi_ch_free((void**)&passwordExpirationTime);
- /* Check if password has been reset */
- if ( pw_exp_date == NO_TIME ) {
- /* check if changing password is required */
- if ( pwpolicy->pw_must_change ) {
- /* set c_needpw for this connection to be true. this client
- now can only change its own password */
- pb->pb_conn->c_needpw = 1;
- *t=0;
- /* We need to include "changeafterreset" error in
- * passwordpolicy response control. So, we will not be
- * done here. We remember this scenario by (c_needpw=1)
- * and check it before sending the control from various
- * places. We will also add LDAP_CONTROL_PWEXPIRED control
- * as the return value used to be (1).
- */
- goto skip;
- }
- /* Mark that first login occured */
- pw_exp_date = NOT_FIRST_TIME;
- timestring = format_genTime(pw_exp_date);
- slapi_mods_add_string(&smods, LDAP_MOD_REPLACE, "passwordExpirationTime", timestring);
- slapi_ch_free((void **)×tring);
- }
- skip:
- /* if password never expires, don't need to go on; return 0 */
- if ( pwpolicy->pw_exp == 0 ) {
- /* check for "changeafterreset" condition */
- if (pb->pb_conn->c_needpw == 1) {
- if (pwresponse_req) {
- slapi_pwpolicy_make_response_control ( pb, -1, -1, LDAP_PWPOLICY_CHGAFTERRESET );
- }
- slapi_add_pwd_control ( pb, LDAP_CONTROL_PWEXPIRED, 0);
- }
- pw_apply_mods(dn, &smods);
- slapi_mods_done(&smods);
- delete_passwdPolicy(&pwpolicy);
- return ( 0 );
- }
- /* check if password expired. If so, abort bind. */
- cur_time_str = format_genTime ( cur_time );
- if ( pw_exp_date != NO_TIME &&
- pw_exp_date != NOT_FIRST_TIME &&
- (diff_t = difftime ( pw_exp_date,
- parse_genTime ( cur_time_str ))) <= 0 ) {
-
- slapi_ch_free_string(&cur_time_str); /* only need this above */
- /* password has expired. Check the value of
- * passwordGraceUserTime and compare it
- * against the value of passwordGraceLimit */
- pwdGraceUserTime = slapi_entry_attr_get_int( e, "passwordGraceUserTime");
- if ( pwpolicy->pw_gracelimit > pwdGraceUserTime ) {
- pwdGraceUserTime++;
- sprintf ( graceUserTime, "%d", pwdGraceUserTime );
- slapi_mods_add_string(&smods, LDAP_MOD_REPLACE,
- "passwordGraceUserTime", graceUserTime);
- pw_apply_mods(dn, &smods);
- slapi_mods_done(&smods);
- if (pwresponse_req) {
- /* check for "changeafterreset" condition */
- if (pb->pb_conn->c_needpw == 1) {
- slapi_pwpolicy_make_response_control( pb, -1,
- ((pwpolicy->pw_gracelimit) - pwdGraceUserTime),
- LDAP_PWPOLICY_CHGAFTERRESET);
- } else {
- slapi_pwpolicy_make_response_control( pb, -1,
- ((pwpolicy->pw_gracelimit) - pwdGraceUserTime),
- -1);
- }
- }
-
- if (pb->pb_conn->c_needpw == 1) {
- slapi_add_pwd_control ( pb, LDAP_CONTROL_PWEXPIRED, 0);
- }
- delete_passwdPolicy(&pwpolicy);
- return ( 0 );
- }
- /* password expired and user exceeded limit of grace attemps.
- * Send result and also the control */
- slapi_add_pwd_control ( pb, LDAP_CONTROL_PWEXPIRED, 0);
- if (pwresponse_req) {
- slapi_pwpolicy_make_response_control ( pb, -1, -1, LDAP_PWPOLICY_PWDEXPIRED );
- }
- slapi_send_ldap_result ( pb, LDAP_INVALID_CREDENTIALS, NULL,
- "password expired!", 0, NULL );
-
- /* abort bind */
- /* pass pb to do_unbind(). pb->pb_op->o_opid and
- pb->pb_op->o_tag are not right but I don't see
- do_unbind() checking for those. We might need to
- create a pb for unbind operation. Also do_unbind calls
- pre and post ops. Maybe we don't want to call them */
- if (pb->pb_conn && (LDAP_VERSION2 == pb->pb_conn->c_ldapversion)) {
- /* We close the connection only with LDAPv2 connections */
- do_unbind( pb );
- }
- /* Apply current modifications */
- pw_apply_mods(dn, &smods);
- slapi_mods_done(&smods);
- delete_passwdPolicy(&pwpolicy);
- return (-1);
- }
- slapi_ch_free((void **) &cur_time_str );
- /* check if password is going to expire within "passwordWarning" */
- /* Note that if pw_exp_date is NO_TIME or NOT_FIRST_TIME,
- * we must send warning first and this changes the expiration time.
- * This is done just below since diff_t is 0
- */
- if ( diff_t <= pwpolicy->pw_warning ) {
- int pw_exp_warned = 0;
-
- pw_exp_warned= slapi_entry_attr_get_int( e, "passwordExpWarned");
- if ( !pw_exp_warned ){
- /* first time send out a warning */
- /* reset the expiration time to current + warning time
- * and set passwordExpWarned to true
- */
- if (pb->pb_conn->c_needpw != 1) {
- pw_exp_date = time_plus_sec ( cur_time,
- pwpolicy->pw_warning );
- }
-
- timestring = format_genTime(pw_exp_date);
- /* At this time passwordExpirationTime may already be
- * in the list of mods: Remove it */
- for (mod = slapi_mods_get_first_mod(&smods); mod != NULL;
- mod = slapi_mods_get_next_mod(&smods))
- {
- if (!strcmp(mod->mod_type, "passwordExpirationTime"))
- slapi_mods_remove(&smods);
- }
- slapi_mods_add_string(&smods, LDAP_MOD_REPLACE, "passwordExpirationTime", timestring);
- slapi_ch_free((void **)×tring);
- slapi_mods_add_string(&smods, LDAP_MOD_REPLACE, "passwordExpWarned", "1");
-
- *t = pwpolicy->pw_warning;
- } else {
- *t = (long)diff_t; /* jcm: had to cast double to long */
- }
-
- pw_apply_mods(dn, &smods);
- slapi_mods_done(&smods);
- if (pwresponse_req) {
- /* check for "changeafterreset" condition */
- if (pb->pb_conn->c_needpw == 1) {
- slapi_pwpolicy_make_response_control( pb, *t, -1,
- LDAP_PWPOLICY_CHGAFTERRESET);
- } else {
- slapi_pwpolicy_make_response_control( pb, *t, -1,
- -1);
- }
- }
- if (pb->pb_conn->c_needpw == 1) {
- slapi_add_pwd_control ( pb, LDAP_CONTROL_PWEXPIRED, 0);
- }
- delete_passwdPolicy(&pwpolicy);
- return (2);
- }
- pw_apply_mods(dn, &smods);
- slapi_mods_done(&smods);
- /* Leftover from "changeafterreset" condition */
- if (pb->pb_conn->c_needpw == 1) {
- slapi_add_pwd_control ( pb, LDAP_CONTROL_PWEXPIRED, 0);
- }
- delete_passwdPolicy(&pwpolicy);
- /* passes checking, return 0 */
- return( 0 );
- }
- /* check_account_lock is called before bind opeation; this could be a pre-op. */
- int
- check_account_lock ( Slapi_PBlock *pb, Slapi_Entry * bind_target_entry, int pwresponse_req, int account_inactivation_only) {
- time_t unlock_time;
- time_t cur_time;
- char *cur_time_str = NULL;
- char *accountUnlockTime;
- passwdPolicy *pwpolicy = NULL;
- char *dn = NULL;
- /* kexcoff: account inactivation */
- int rc = 0;
- Slapi_ValueSet *values = NULL;
- int type_name_disposition = 0;
- char *actual_type_name = NULL;
- int attr_free_flags = 0;
- /* kexcoff - end */
- if ( bind_target_entry == NULL )
- return -1;
- if(!account_inactivation_only)
- {
- dn = slapi_entry_get_ndn(bind_target_entry);
- pwpolicy = new_passwdPolicy(pb, dn);
- }
- /* kexcoff: account inactivation */
- /* check if the entry is locked by nsAccountLock attribute - account inactivation feature */
- rc = slapi_vattr_values_get(bind_target_entry, "nsAccountLock",
- &values,
- &type_name_disposition, &actual_type_name,
- SLAPI_VIRTUALATTRS_REQUEST_POINTERS,
- &attr_free_flags);
- if ( rc == 0 )
- {
- Slapi_Value *v = NULL;
- const struct berval *bvp = NULL;
- if ( (slapi_valueset_first_value( values, &v ) != -1) &&
- ( bvp = slapi_value_get_berval( v )) != NULL )
- {
- if ( (bvp != NULL) && (strcasecmp(bvp->bv_val, "true") == 0) )
- {
- /* account inactivated */
- if (!account_inactivation_only && pwresponse_req) {
- slapi_pwpolicy_make_response_control ( pb, -1, -1,
- LDAP_PWPOLICY_ACCTLOCKED );
- }
- if(!account_inactivation_only)
- send_ldap_result ( pb, LDAP_UNWILLING_TO_PERFORM, NULL,
- "Account inactivated. Contact system administrator.",
- 0, NULL );
- slapi_vattr_values_free(&values, &actual_type_name, attr_free_flags);
- goto locked;
- }
- } /* else, account "activated", keep on the process */
- if ( values != NULL )
- slapi_vattr_values_free(&values, &actual_type_name, attr_free_flags);
- }
- /* kexcoff - end */
- /*
- * Check if the password policy has to be checked or not
- */
- if ( account_inactivation_only || pwpolicy->pw_lockout == 0 ) {
- goto notlocked;
- }
- /*
- * Check the attribute of the password policy
- */
- /* check if account is locked out. If so, send result and return 1 */
- {
- unsigned int maxfailure= pwpolicy->pw_maxfailure;
- /* It's locked if passwordRetryCount >= maxfailure */
- if ( slapi_entry_attr_get_uint(bind_target_entry,"passwordRetryCount") < maxfailure )
- {
- /* Not locked */
- goto notlocked;
- }
- }
- /* locked but maybe it's time to unlock it */
- accountUnlockTime= slapi_entry_attr_get_charptr(bind_target_entry, "accountUnlockTime");
- if (accountUnlockTime != NULL)
- {
- unlock_time = parse_genTime(accountUnlockTime);
- slapi_ch_free((void **) &accountUnlockTime );
- if ( pwpolicy->pw_unlock == 0 &&
- unlock_time == NO_TIME ) {
- /* account is locked forever. contact admin to reset */
- if (pwresponse_req) {
- slapi_pwpolicy_make_response_control ( pb, -1, -1,
- LDAP_PWPOLICY_ACCTLOCKED );
- }
- send_ldap_result ( pb, LDAP_CONSTRAINT_VIOLATION, NULL,
- "Exceed password retry limit. Contact system administrator to reset."
- , 0, NULL );
- goto locked;
- }
- cur_time = current_time();
- cur_time_str = format_genTime( cur_time);
- if ( difftime ( parse_genTime( cur_time_str ), unlock_time ) < 0 ) {
- /* account is locked, cannot do anything */
- if (pwresponse_req) {
- slapi_pwpolicy_make_response_control ( pb, -1, -1,
- LDAP_PWPOLICY_ACCTLOCKED );
- }
- send_ldap_result ( pb, LDAP_CONSTRAINT_VIOLATION, NULL,
- "Exceed password retry limit. Please try later." , 0, NULL );
- slapi_ch_free((void **) &cur_time_str );
- goto locked;
- }
- slapi_ch_free((void **) &cur_time_str );
- }
- notlocked:
- /* account is not locked. */
- if(!account_inactivation_only)
- delete_passwdPolicy(&pwpolicy);
- return ( 0 );
- locked:
- if(!account_inactivation_only)
- delete_passwdPolicy(&pwpolicy);
- return (1);
- }
- void
- pw_init ( void ) {
- slapdFrontendConfig_t *slapdFrontendConfig;
- pw_set_componentID(generate_componentid(NULL, COMPONENT_PWPOLICY));
-
- slapdFrontendConfig = getFrontendConfig();
- pw_mod_allowchange_aci (!slapdFrontendConfig->pw_policy.pw_change &&
- !slapdFrontendConfig->pw_policy.pw_must_change);
- }
|