summaryrefslogtreecommitdiffstats
path: root/ldap/servers/slapd/pw_mgmt.c
diff options
context:
space:
mode:
authorcvsadm <cvsadm>2005-01-21 00:44:34 +0000
committercvsadm <cvsadm>2005-01-21 00:44:34 +0000
commitb2093e3016027d6b5cf06b3f91f30769bfc099e2 (patch)
treecf58939393a9032182c4fbc4441164a9456e82f8 /ldap/servers/slapd/pw_mgmt.c
downloadds-b2093e3016027d6b5cf06b3f91f30769bfc099e2.tar.gz
ds-b2093e3016027d6b5cf06b3f91f30769bfc099e2.tar.xz
ds-b2093e3016027d6b5cf06b3f91f30769bfc099e2.zip
Moving NSCP Directory Server from DirectoryBranch to TRUNK, initial drop. (foxworth)ldapserver7x
Diffstat (limited to 'ldap/servers/slapd/pw_mgmt.c')
-rw-r--r--ldap/servers/slapd/pw_mgmt.c398
1 files changed, 398 insertions, 0 deletions
diff --git a/ldap/servers/slapd/pw_mgmt.c b/ldap/servers/slapd/pw_mgmt.c
new file mode 100644
index 00000000..b400efab
--- /dev/null
+++ b/ldap/servers/slapd/pw_mgmt.c
@@ -0,0 +1,398 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/* 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 **)&timestring);
+ slapi_mods_add_string(&smods, LDAP_MOD_REPLACE, "passwordExpWarned", "0");
+
+ 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 **)&timestring);
+ }
+
+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) {
+ pwpolicy_make_response_control ( pb, -1, -1, LDAP_PWPOLICY_CHGAFTERRESET );
+ }
+ 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 ) {
+
+ /* 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) {
+ pwpolicy_make_response_control( pb, -1,
+ ((pwpolicy->pw_gracelimit) - pwdGraceUserTime),
+ LDAP_PWPOLICY_CHGAFTERRESET);
+ } else {
+ pwpolicy_make_response_control( pb, -1,
+ ((pwpolicy->pw_gracelimit) - pwdGraceUserTime),
+ -1);
+ }
+ }
+
+ if (pb->pb_conn->c_needpw == 1) {
+ 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 */
+ add_pwd_control ( pb, LDAP_CONTROL_PWEXPIRED, 0);
+ if (pwresponse_req) {
+ 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);
+ slapi_ch_free((void **) &cur_time_str );
+ 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 **)&timestring);
+
+ 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) {
+ pwpolicy_make_response_control( pb, *t, -1,
+ LDAP_PWPOLICY_CHGAFTERRESET);
+ } else {
+ pwpolicy_make_response_control( pb, *t, -1,
+ -1);
+ }
+ }
+
+ if (pb->pb_conn->c_needpw == 1) {
+ 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) {
+ 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) {
+
+ time_t unlock_time;
+ time_t cur_time;
+ double diff_t;
+ 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;
+
+ 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 (pwresponse_req) {
+ pwpolicy_make_response_control ( pb, -1, -1,
+ LDAP_PWPOLICY_ACCTLOCKED );
+ }
+ 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 ( 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) {
+ 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 ( ( diff_t = difftime ( parse_genTime( cur_time_str ),
+ unlock_time ) ) < 0 ) {
+
+ /* account is locked, cannot do anything */
+ if (pwresponse_req) {
+ 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. */
+ delete_passwdPolicy(&pwpolicy);
+ return ( 0 );
+locked:
+ 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);
+}
+
+