📄 ppolicy.c
字号:
/* $OpenLDAP: pkg/ldap/servers/slapd/overlays/ppolicy.c,v 1.31.2.29 2007/02/08 12:31:24 hyc Exp $ *//* This work is part of OpenLDAP Software <http://www.openldap.org/>. * * Copyright 2004-2007 The OpenLDAP Foundation. * Portions Copyright 2004-2005 Howard Chu, Symas Corporation. * Portions Copyright 2004 Hewlett-Packard Company. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted only as authorized by the OpenLDAP * Public License. * * A copy of this license is available in the file LICENSE in the * top-level directory of the distribution or, alternatively, at * <http://www.OpenLDAP.org/license.html>. *//* ACKNOWLEDGEMENTS: * This work was developed by Howard Chu for inclusion in * OpenLDAP Software, based on prior work by Neil Dunbar (HP). * This work was sponsored by the Hewlett-Packard Company. */#include "portable.h"/* This file implements "Password Policy for LDAP Directories", * based on draft behera-ldap-password-policy-09 */#ifdef SLAPD_OVER_PPOLICY#include <ldap.h>#include "lutil.h"#include "slap.h"#if SLAPD_MODULES#define LIBLTDL_DLL_IMPORT /* Win32: don't re-export libltdl's symbols */#include <ltdl.h>#endif#include <ac/errno.h>#include <ac/time.h>#include <ac/string.h>#include <ac/ctype.h>#include "config.h"#ifndef MODULE_NAME_SZ#define MODULE_NAME_SZ 256#endif/* Per-instance configuration information */typedef struct pp_info { struct berval def_policy; /* DN of default policy subentry */ int use_lockout; /* send AccountLocked result? */ int hash_passwords; /* transparently hash cleartext pwds */} pp_info;/* Our per-connection info - note, it is not per-instance, it is * used by all instances */typedef struct pw_conn { struct berval dn; /* DN of restricted user */} pw_conn;static pw_conn *pwcons;static int ppolicy_cid;typedef struct pass_policy { AttributeDescription *ad; /* attribute to which the policy applies */ int pwdMinAge; /* minimum time (seconds) until passwd can change */ int pwdMaxAge; /* time in seconds until pwd will expire after change */ int pwdInHistory; /* number of previous passwords kept */ int pwdCheckQuality; /* 0 = don't check quality, 1 = check if possible, 2 = check mandatory; fail if not possible */ int pwdMinLength; /* minimum number of chars in password */ int pwdExpireWarning; /* number of seconds that warning controls are sent before a password expires */ int pwdGraceAuthNLimit; /* number of times you can log in with an expired password */ int pwdLockout; /* 0 = do not lockout passwords, 1 = lock them out */ int pwdLockoutDuration; /* time in seconds a password is locked out for */ int pwdMaxFailure; /* number of failed binds allowed before lockout */ int pwdFailureCountInterval; /* number of seconds before failure counts are zeroed */ int pwdMustChange; /* 0 = users can use admin set password 1 = users must change password after admin set */ int pwdAllowUserChange; /* 0 = users cannot change their passwords 1 = users can change them */ int pwdSafeModify; /* 0 = old password doesn't need to come with password change request 1 = password change must supply existing pwd */ char pwdCheckModule[MODULE_NAME_SZ]; /* name of module to dynamically load to check password */} PassPolicy;typedef struct pw_hist { time_t t; /* timestamp of history entry */ struct berval pw; /* old password hash */ struct berval bv; /* text of entire entry */ struct pw_hist *next;} pw_hist;/* Operational attributes */static AttributeDescription *ad_pwdChangedTime, *ad_pwdAccountLockedTime, *ad_pwdFailureTime, *ad_pwdHistory, *ad_pwdGraceUseTime, *ad_pwdReset, *ad_pwdPolicySubentry;static struct schema_info { char *def; AttributeDescription **ad;} pwd_OpSchema[] = { { "( 1.3.6.1.4.1.42.2.27.8.1.16 " "NAME ( 'pwdChangedTime' ) " "DESC 'The time the password was last changed' " "EQUALITY generalizedTimeMatch " "ORDERING generalizedTimeOrderingMatch " "SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 " "SINGLE-VALUE NO-USER-MODIFICATION USAGE directoryOperation )", &ad_pwdChangedTime }, { "( 1.3.6.1.4.1.42.2.27.8.1.17 " "NAME ( 'pwdAccountLockedTime' ) " "DESC 'The time an user account was locked' " "EQUALITY generalizedTimeMatch " "ORDERING generalizedTimeOrderingMatch " "SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 " "SINGLE-VALUE "#if 0 /* Not until MANAGEDIT control is released */ "NO-USER-MODIFICATION "#endif "USAGE directoryOperation )", &ad_pwdAccountLockedTime }, { "( 1.3.6.1.4.1.42.2.27.8.1.19 " "NAME ( 'pwdFailureTime' ) " "DESC 'The timestamps of the last consecutive authentication failures' " "EQUALITY generalizedTimeMatch " "ORDERING generalizedTimeOrderingMatch " "SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 " "NO-USER-MODIFICATION USAGE directoryOperation )", &ad_pwdFailureTime }, { "( 1.3.6.1.4.1.42.2.27.8.1.20 " "NAME ( 'pwdHistory' ) " "DESC 'The history of users passwords' " "EQUALITY octetStringMatch " "SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 " "NO-USER-MODIFICATION USAGE directoryOperation )", &ad_pwdHistory }, { "( 1.3.6.1.4.1.42.2.27.8.1.21 " "NAME ( 'pwdGraceUseTime' ) " "DESC 'The timestamps of the grace login once the password has expired' " "EQUALITY generalizedTimeMatch " "SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 " "NO-USER-MODIFICATION USAGE directoryOperation )", &ad_pwdGraceUseTime }, { "( 1.3.6.1.4.1.42.2.27.8.1.22 " "NAME ( 'pwdReset' ) " "DESC 'The indication that the password has been reset' " "EQUALITY booleanMatch " "SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 " "SINGLE-VALUE USAGE directoryOperation )", &ad_pwdReset }, { "( 1.3.6.1.4.1.42.2.27.8.1.23 " "NAME ( 'pwdPolicySubentry' ) " "DESC 'The pwdPolicy subentry in effect for this object' " "EQUALITY distinguishedNameMatch " "SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 " "SINGLE-VALUE "#if 0 /* Not until MANAGEDIT control is released */ "NO-USER-MODIFICATION "#endif "USAGE directoryOperation )", &ad_pwdPolicySubentry }, { NULL, NULL }};/* User attributes */static AttributeDescription *ad_pwdMinAge, *ad_pwdMaxAge, *ad_pwdInHistory, *ad_pwdCheckQuality, *ad_pwdMinLength, *ad_pwdMaxFailure, *ad_pwdGraceAuthNLimit, *ad_pwdExpireWarning, *ad_pwdLockoutDuration, *ad_pwdFailureCountInterval, *ad_pwdCheckModule, *ad_pwdLockout, *ad_pwdMustChange, *ad_pwdAllowUserChange, *ad_pwdSafeModify, *ad_pwdAttribute;#define TAB(name) { #name, &ad_##name }static struct schema_info pwd_UsSchema[] = { TAB(pwdAttribute), TAB(pwdMinAge), TAB(pwdMaxAge), TAB(pwdInHistory), TAB(pwdCheckQuality), TAB(pwdMinLength), TAB(pwdMaxFailure), TAB(pwdGraceAuthNLimit), TAB(pwdExpireWarning), TAB(pwdLockout), TAB(pwdLockoutDuration), TAB(pwdFailureCountInterval), TAB(pwdCheckModule), TAB(pwdMustChange), TAB(pwdAllowUserChange), TAB(pwdSafeModify), { NULL, NULL }};static ldap_pvt_thread_mutex_t chk_syntax_mutex;enum { PPOLICY_DEFAULT = 1, PPOLICY_HASH_CLEARTEXT, PPOLICY_USE_LOCKOUT};static ConfigDriver ppolicy_cf_default;static ConfigTable ppolicycfg[] = { { "ppolicy_default", "policyDN", 2, 2, 0, ARG_DN|ARG_MAGIC|PPOLICY_DEFAULT, ppolicy_cf_default, "( OLcfgOvAt:12.1 NAME 'olcPPolicyDefault' " "DESC 'DN of a pwdPolicy object for uncustomized objects' " "SYNTAX OMsDN SINGLE-VALUE )", NULL, NULL }, { "ppolicy_hash_cleartext", "on|off", 1, 2, 0, ARG_ON_OFF|ARG_OFFSET|PPOLICY_HASH_CLEARTEXT, (void *)offsetof(pp_info,hash_passwords), "( OLcfgOvAt:12.2 NAME 'olcPPolicyHashCleartext' " "DESC 'Hash passwords on add or modify' " "SYNTAX OMsBoolean SINGLE-VALUE )", NULL, NULL }, { "ppolicy_use_lockout", "on|off", 1, 2, 0, ARG_ON_OFF|ARG_OFFSET|PPOLICY_USE_LOCKOUT, (void *)offsetof(pp_info,use_lockout), "( OLcfgOvAt:12.3 NAME 'olcPPolicyUseLockout' " "DESC 'Warn clients with AccountLocked' " "SYNTAX OMsBoolean SINGLE-VALUE )", NULL, NULL }, { NULL, NULL, 0, 0, 0, ARG_IGNORED }};static ConfigOCs ppolicyocs[] = { { "( OLcfgOvOc:12.1 " "NAME 'olcPPolicyConfig' " "DESC 'Password Policy configuration' " "SUP olcOverlayConfig " "MAY ( olcPPolicyDefault $ olcPPolicyHashCleartext $ " "olcPPolicyUseLockout ) )", Cft_Overlay, ppolicycfg }, { NULL, 0, NULL }};static intppolicy_cf_default( ConfigArgs *c ){ slap_overinst *on = (slap_overinst *)c->bi; pp_info *pi = (pp_info *)on->on_bi.bi_private; BackendDB *be = (BackendDB *)c->be; const char *text; int rc = ARG_BAD_CONF; assert ( c->type == PPOLICY_DEFAULT ); Debug(LDAP_DEBUG_TRACE, "==> ppolicy_cf_default\n", 0, 0, 0); switch ( c->op ) { case SLAP_CONFIG_EMIT: Debug(LDAP_DEBUG_TRACE, "==> ppolicy_cf_default emit\n", 0, 0, 0); rc = 0; if ( !BER_BVISEMPTY( &pi->def_policy )) { rc = value_add_one( &c->rvalue_vals, &pi->def_policy ); if ( rc ) return rc; rc = value_add_one( &c->rvalue_nvals, &pi->def_policy ); } break; case LDAP_MOD_DELETE: Debug(LDAP_DEBUG_TRACE, "==> ppolicy_cf_default delete\n", 0, 0, 0); if ( pi->def_policy.bv_val ) { ber_memfree ( pi->def_policy.bv_val ); pi->def_policy.bv_val = NULL; } pi->def_policy.bv_len = 0; rc = 0; break; case SLAP_CONFIG_ADD: /* fallthrough to LDAP_MOD_ADD */ case LDAP_MOD_ADD: Debug(LDAP_DEBUG_TRACE, "==> ppolicy_cf_default add\n", 0, 0, 0); if ( pi->def_policy.bv_val ) ber_memfree ( pi->def_policy.bv_val ); pi->def_policy = c->value_ndn; rc = 0; break; default: abort (); } return rc;}static time_tparse_time( char *atm ){ struct lutil_tm tm; struct lutil_timet tt; time_t ret = (time_t)-1; if ( lutil_parsetime( atm, &tm ) == 0) { lutil_tm2time( &tm, &tt ); ret = tt.tt_sec; } return ret;}static intaccount_locked( Operation *op, Entry *e, PassPolicy *pp, Modifications **mod ) { Attribute *la; assert(mod != NULL); if ( (la = attr_find( e->e_attrs, ad_pwdAccountLockedTime )) != NULL ) { BerVarray vals = la->a_nvals; /* * there is a lockout stamp - we now need to know if it's * a valid one. */ if (vals[0].bv_val != NULL) { time_t then, now; Modifications *m; if (!pp->pwdLockoutDuration) return 1; if ((then = parse_time( vals[0].bv_val )) == (time_t)0) return 1; now = slap_get_time(); if (now < then + pp->pwdLockoutDuration) return 1; m = ch_calloc( sizeof(Modifications), 1 ); m->sml_op = LDAP_MOD_DELETE; m->sml_flags = 0; m->sml_type = ad_pwdAccountLockedTime->ad_cname; m->sml_desc = ad_pwdAccountLockedTime; m->sml_next = *mod; *mod = m; } } return 0;}/* IMPLICIT TAGS, all context-specific */#define PPOLICY_WARNING 0xa0L /* constructed + 0 */#define PPOLICY_ERROR 0x81L /* primitive + 1 */ #define PPOLICY_EXPIRE 0x80L /* primitive + 0 */#define PPOLICY_GRACE 0x81L /* primitive + 1 */static LDAPControl *create_passcontrol( int exptime, int grace, LDAPPasswordPolicyError err ){ char berbuf[LBER_ELEMENT_SIZEOF], bb2[LBER_ELEMENT_SIZEOF]; BerElement *ber = (BerElement *)berbuf, *b2 = (BerElement *)bb2; LDAPControl *c; struct berval bv; c = ch_calloc( sizeof( LDAPControl ), 1 ); if ( c == NULL ) { return NULL; } c->ldctl_oid = LDAP_CONTROL_PASSWORDPOLICYRESPONSE; c->ldctl_iscritical = 0; BER_BVZERO( &c->ldctl_value ); ber_init2( ber, NULL, LBER_USE_DER ); ber_printf( ber, "{" /*}*/ ); if ( exptime >= 0 ) { ber_init2( b2, NULL, LBER_USE_DER ); ber_printf( b2, "ti", PPOLICY_EXPIRE, exptime ); ber_flatten2( b2, &bv, 1 ); (void)ber_free_buf(b2); ber_printf( ber, "tO", PPOLICY_WARNING, &bv ); ch_free( bv.bv_val ); } else if ( grace > 0 ) { ber_init2( b2, NULL, LBER_USE_DER ); ber_printf( b2, "ti", PPOLICY_GRACE, grace ); ber_flatten2( b2, &bv, 1 ); (void)ber_free_buf(b2); ber_printf( ber, "tO", PPOLICY_WARNING, &bv ); ch_free( bv.bv_val ); } if (err != PP_noError ) { ber_printf( ber, "te", PPOLICY_ERROR, err ); } ber_printf( ber, /*{*/ "N}" ); if (ber_flatten2( ber, &(c->ldctl_value), 1 ) == LBER_DEFAULT) { ch_free(c); c = NULL; } (void)ber_free_buf(ber); return c;}static LDAPControl **add_passcontrol( Operation *op, SlapReply *rs, LDAPControl *ctrl ){ LDAPControl **ctrls, **oldctrls = rs->sr_ctrls; int n; n = 0; if ( oldctrls ) { for ( ; oldctrls[n]; n++ ) ; } n += 2; ctrls = op->o_tmpcalloc( sizeof( LDAPControl * ), n, op->o_tmpmemctx ); n = 0; if ( oldctrls ) { for ( ; oldctrls[n]; n++ ) { ctrls[n] = oldctrls[n]; } } ctrls[n] = ctrl; ctrls[n+1] = NULL; rs->sr_ctrls = ctrls; return oldctrls;}static voidppolicy_get( Operation *op, Entry *e, PassPolicy *pp ){ slap_overinst *on = (slap_overinst *)op->o_bd->bd_info; pp_info *pi = on->on_bi.bi_private; Attribute *a; BerVarray vals;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -