diff options
author | Nathan Kinder <nkinder@redhat.com> | 2006-01-25 16:51:39 +0000 |
---|---|---|
committer | Nathan Kinder <nkinder@redhat.com> | 2006-01-25 16:51:39 +0000 |
commit | aa7708769b0f977a709add4bb10780dfd562cfe1 (patch) | |
tree | e017d80a5529fa80b1a23a13d43f8c982b0ebe82 | |
parent | 19a69e611cf61aae13fac5ac23f64f2a8ea0abca (diff) | |
download | ds-aa7708769b0f977a709add4bb10780dfd562cfe1.tar.gz ds-aa7708769b0f977a709add4bb10780dfd562cfe1.tar.xz ds-aa7708769b0f977a709add4bb10780dfd562cfe1.zip |
178867 - Enhanced password syntax checking
-rw-r--r-- | ldap/servers/slapd/libglobs.c | 416 | ||||
-rw-r--r-- | ldap/servers/slapd/libslapd.def | 19 | ||||
-rw-r--r-- | ldap/servers/slapd/modify.c | 14 | ||||
-rw-r--r-- | ldap/servers/slapd/proto-slap.h | 20 | ||||
-rw-r--r-- | ldap/servers/slapd/pw.c | 285 | ||||
-rw-r--r-- | ldap/servers/slapd/slap.h | 18 |
6 files changed, 734 insertions, 38 deletions
diff --git a/ldap/servers/slapd/libglobs.c b/ldap/servers/slapd/libglobs.c index b28d3b80..d6b49f96 100644 --- a/ldap/servers/slapd/libglobs.c +++ b/ldap/servers/slapd/libglobs.c @@ -277,6 +277,33 @@ static struct config_get_and_set { {CONFIG_PW_MINLENGTH_ATTRIBUTE, config_set_pw_minlength, NULL, 0, (void**)&global_slapdFrontendConfig.pw_policy.pw_minlength, CONFIG_INT, NULL}, + {CONFIG_PW_MINDIGITS_ATTRIBUTE, config_set_pw_mindigits, + NULL, 0, + (void**)&global_slapdFrontendConfig.pw_policy.pw_mindigits, CONFIG_INT, NULL}, + {CONFIG_PW_MINALPHAS_ATTRIBUTE, config_set_pw_minalphas, + NULL, 0, + (void**)&global_slapdFrontendConfig.pw_policy.pw_minalphas, CONFIG_INT, NULL}, + {CONFIG_PW_MINUPPERS_ATTRIBUTE, config_set_pw_minuppers, + NULL, 0, + (void**)&global_slapdFrontendConfig.pw_policy.pw_minuppers, CONFIG_INT, NULL}, + {CONFIG_PW_MINLOWERS_ATTRIBUTE, config_set_pw_minlowers, + NULL, 0, + (void**)&global_slapdFrontendConfig.pw_policy.pw_minlowers, CONFIG_INT, NULL}, + {CONFIG_PW_MINSPECIALS_ATTRIBUTE, config_set_pw_minspecials, + NULL, 0, + (void**)&global_slapdFrontendConfig.pw_policy.pw_minspecials, CONFIG_INT, NULL}, + {CONFIG_PW_MIN8BIT_ATTRIBUTE, config_set_pw_min8bit, + NULL, 0, + (void**)&global_slapdFrontendConfig.pw_policy.pw_min8bit, CONFIG_INT, NULL}, + {CONFIG_PW_MAXREPEATS_ATTRIBUTE, config_set_pw_maxrepeats, + NULL, 0, + (void**)&global_slapdFrontendConfig.pw_policy.pw_maxrepeats, CONFIG_INT, NULL}, + {CONFIG_PW_MINCATEGORIES_ATTRIBUTE, config_set_pw_mincategories, + NULL, 0, + (void**)&global_slapdFrontendConfig.pw_policy.pw_mincategories, CONFIG_INT, NULL}, + {CONFIG_PW_MINTOKENLENGTH_ATTRIBUTE, config_set_pw_mintokenlength, + NULL, 0, + (void**)&global_slapdFrontendConfig.pw_policy.pw_mintokenlength, CONFIG_INT, NULL}, {CONFIG_ERRORLOG_ATTRIBUTE, config_set_errorlog, NULL, 0, (void**)&global_slapdFrontendConfig.errorlog, CONFIG_STRING_OR_EMPTY, NULL}, @@ -751,7 +778,16 @@ FrontendConfig_init () { cfg->pw_policy.pw_must_change = LDAP_OFF; cfg->pw_policy.pw_syntax = LDAP_OFF; cfg->pw_policy.pw_exp = LDAP_OFF; - cfg->pw_policy.pw_minlength = 6; + cfg->pw_policy.pw_minlength = 8; + cfg->pw_policy.pw_mindigits = 0; + cfg->pw_policy.pw_minalphas = 0; + cfg->pw_policy.pw_minuppers = 0; + cfg->pw_policy.pw_minlowers = 0; + cfg->pw_policy.pw_minspecials = 0; + cfg->pw_policy.pw_min8bit = 0; + cfg->pw_policy.pw_maxrepeats = 0; + cfg->pw_policy.pw_mincategories = 3; + cfg->pw_policy.pw_mintokenlength = 3; cfg->pw_policy.pw_maxage = 8640000; /* 100 days */ cfg->pw_policy.pw_minage = 0; cfg->pw_policy.pw_warning = 86400; /* 1 day */ @@ -1340,6 +1376,276 @@ config_set_pw_minlength( const char *attrname, char *value, char *errorbuf, int } int +config_set_pw_mindigits( const char *attrname, char *value, char *errorbuf, int apply ) { + int retVal = LDAP_SUCCESS, minDigits = 0; + slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig(); + + if ( config_value_is_null( attrname, value, errorbuf, 0 )) { + return LDAP_OPERATIONS_ERROR; + } + + minDigits = atoi(value); + if ( minDigits < 0 || minDigits > 64 ) { + PR_snprintf ( errorbuf, SLAPI_DSE_RETURNTEXT_SIZE, + "password minimum number of digits \"%s\" is invalid. " + "The minimum number of digits must range from 0 to 64.", + value ); + retVal = LDAP_OPERATIONS_ERROR; + return retVal; + } + + if ( apply ) { + CFG_LOCK_WRITE(slapdFrontendConfig); + + slapdFrontendConfig->pw_policy.pw_mindigits = minDigits; + + CFG_UNLOCK_WRITE(slapdFrontendConfig); + } + + return retVal; +} + +int +config_set_pw_minalphas( const char *attrname, char *value, char *errorbuf, int apply ) { + int retVal = LDAP_SUCCESS, minAlphas = 0; + slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig(); + + if ( config_value_is_null( attrname, value, errorbuf, 0 )) { + return LDAP_OPERATIONS_ERROR; + } + + minAlphas = atoi(value); + if ( minAlphas < 0 || minAlphas > 64 ) { + PR_snprintf ( errorbuf, SLAPI_DSE_RETURNTEXT_SIZE, + "password minimum number of alphas \"%s\" is invalid. " + "The minimum number of alphas must range from 0 to 64.", + value ); + retVal = LDAP_OPERATIONS_ERROR; + return retVal; + } + + if ( apply ) { + CFG_LOCK_WRITE(slapdFrontendConfig); + + slapdFrontendConfig->pw_policy.pw_minalphas = minAlphas; + + CFG_UNLOCK_WRITE(slapdFrontendConfig); + } + + return retVal; +} + +int +config_set_pw_minuppers( const char *attrname, char *value, char *errorbuf, int apply ) { + int retVal = LDAP_SUCCESS, minUppers = 0; + slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig(); + + if ( config_value_is_null( attrname, value, errorbuf, 0 )) { + return LDAP_OPERATIONS_ERROR; + } + + minUppers = atoi(value); + if ( minUppers < 0 || minUppers > 64 ) { + PR_snprintf ( errorbuf, SLAPI_DSE_RETURNTEXT_SIZE, + "password minimum number of uppercase characters \"%s\" is invalid. " + "The minimum number of uppercase characters must range from 0 to 64.", + value ); + retVal = LDAP_OPERATIONS_ERROR; + return retVal; + } + + if ( apply ) { + CFG_LOCK_WRITE(slapdFrontendConfig); + + slapdFrontendConfig->pw_policy.pw_minuppers = minUppers; + + CFG_UNLOCK_WRITE(slapdFrontendConfig); + } + + return retVal; +} + +int +config_set_pw_minlowers( const char *attrname, char *value, char *errorbuf, int apply ) { + int retVal = LDAP_SUCCESS, minLowers = 0; + slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig(); + + if ( config_value_is_null( attrname, value, errorbuf, 0 )) { + return LDAP_OPERATIONS_ERROR; + } + + minLowers = atoi(value); + if ( minLowers < 0 || minLowers > 64 ) { + PR_snprintf ( errorbuf, SLAPI_DSE_RETURNTEXT_SIZE, + "password minimum number of lowercase characters \"%s\" is invalid. " + "The minimum number of lowercase characters must range from 0 to 64.", + value ); + retVal = LDAP_OPERATIONS_ERROR; + return retVal; + } + + if ( apply ) { + CFG_LOCK_WRITE(slapdFrontendConfig); + + slapdFrontendConfig->pw_policy.pw_minlowers = minLowers; + + CFG_UNLOCK_WRITE(slapdFrontendConfig); + } + + return retVal; +} + +int +config_set_pw_minspecials( const char *attrname, char *value, char *errorbuf, int apply ) { + int retVal = LDAP_SUCCESS, minSpecials = 0; + slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig(); + + if ( config_value_is_null( attrname, value, errorbuf, 0 )) { + return LDAP_OPERATIONS_ERROR; + } + + minSpecials = atoi(value); + if ( minSpecials < 0 || minSpecials > 64 ) { + PR_snprintf ( errorbuf, SLAPI_DSE_RETURNTEXT_SIZE, + "password minimum number of special characters \"%s\" is invalid. " + "The minimum number of special characters must range from 0 to 64.", + value ); + retVal = LDAP_OPERATIONS_ERROR; + return retVal; + } + + if ( apply ) { + CFG_LOCK_WRITE(slapdFrontendConfig); + + slapdFrontendConfig->pw_policy.pw_minspecials = minSpecials; + + CFG_UNLOCK_WRITE(slapdFrontendConfig); + } + + return retVal; +} + +int +config_set_pw_min8bit( const char *attrname, char *value, char *errorbuf, int apply ) { + int retVal = LDAP_SUCCESS, min8bit = 0; + slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig(); + + if ( config_value_is_null( attrname, value, errorbuf, 0 )) { + return LDAP_OPERATIONS_ERROR; + } + + min8bit = atoi(value); + if ( min8bit < 0 || min8bit > 64 ) { + PR_snprintf ( errorbuf, SLAPI_DSE_RETURNTEXT_SIZE, + "password minimum number of 8-bit characters \"%s\" is invalid. " + "The minimum number of 8-bit characters must range from 0 to 64.", + value ); + retVal = LDAP_OPERATIONS_ERROR; + return retVal; + } + + if ( apply ) { + CFG_LOCK_WRITE(slapdFrontendConfig); + + slapdFrontendConfig->pw_policy.pw_min8bit = min8bit; + + CFG_UNLOCK_WRITE(slapdFrontendConfig); + } + + return retVal; +} + +int +config_set_pw_maxrepeats( const char *attrname, char *value, char *errorbuf, int apply ) { + int retVal = LDAP_SUCCESS, maxRepeats = 0; + slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig(); + + if ( config_value_is_null( attrname, value, errorbuf, 0 )) { + return LDAP_OPERATIONS_ERROR; + } + + maxRepeats = atoi(value); + if ( maxRepeats < 0 || maxRepeats > 64 ) { + PR_snprintf ( errorbuf, SLAPI_DSE_RETURNTEXT_SIZE, + "password maximum number of repeated characters \"%s\" is invalid. " + "The maximum number of repeated characters must range from 0 to 64.", + value ); + retVal = LDAP_OPERATIONS_ERROR; + return retVal; + } + + if ( apply ) { + CFG_LOCK_WRITE(slapdFrontendConfig); + + slapdFrontendConfig->pw_policy.pw_maxrepeats = maxRepeats; + + CFG_UNLOCK_WRITE(slapdFrontendConfig); + } + + return retVal; +} + +int +config_set_pw_mincategories( const char *attrname, char *value, char *errorbuf, int apply ) { + int retVal = LDAP_SUCCESS, minCategories = 0; + slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig(); + + if ( config_value_is_null( attrname, value, errorbuf, 0 )) { + return LDAP_OPERATIONS_ERROR; + } + + minCategories = atoi(value); + if ( minCategories < 1 || minCategories > 5 ) { + PR_snprintf ( errorbuf, SLAPI_DSE_RETURNTEXT_SIZE, + "password minimum number of categories \"%s\" is invalid. " + "The minimum number of categories must range from 1 to 5.", + value ); + retVal = LDAP_OPERATIONS_ERROR; + return retVal; + } + + if ( apply ) { + CFG_LOCK_WRITE(slapdFrontendConfig); + + slapdFrontendConfig->pw_policy.pw_mincategories = minCategories; + + CFG_UNLOCK_WRITE(slapdFrontendConfig); + } + + return retVal; +} + +int +config_set_pw_mintokenlength( const char *attrname, char *value, char *errorbuf, int apply ) { + int retVal = LDAP_SUCCESS, minTokenLength = 0; + slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig(); + + if ( config_value_is_null( attrname, value, errorbuf, 0 )) { + return LDAP_OPERATIONS_ERROR; + } + + minTokenLength = atoi(value); + if ( minTokenLength < 1 || minTokenLength > 64 ) { + PR_snprintf ( errorbuf, SLAPI_DSE_RETURNTEXT_SIZE, + "password minimum token length \"%s\" is invalid. " + "The minimum token length must range from 1 to 64.", + value ); + retVal = LDAP_OPERATIONS_ERROR; + return retVal; + } + + if ( apply ) { + CFG_LOCK_WRITE(slapdFrontendConfig); + + slapdFrontendConfig->pw_policy.pw_mintokenlength = minTokenLength; + + CFG_UNLOCK_WRITE(slapdFrontendConfig); + } + + return retVal; +} + +int config_set_pw_maxfailure( const char *attrname, char *value, char *errorbuf, int apply ) { int retVal = LDAP_SUCCESS, maxFailure = 0; slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig(); @@ -2793,6 +3099,114 @@ config_get_pw_minlength() { return retVal; } +int +config_get_pw_mindigits() { + slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig(); + int retVal; + + CFG_LOCK_READ(slapdFrontendConfig); + retVal = slapdFrontendConfig->pw_policy.pw_mindigits; + CFG_UNLOCK_READ(slapdFrontendConfig); + + return retVal; +} + +int +config_get_pw_minalphas() { + slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig(); + int retVal; + + CFG_LOCK_READ(slapdFrontendConfig); + retVal = slapdFrontendConfig->pw_policy.pw_minalphas; + CFG_UNLOCK_READ(slapdFrontendConfig); + + return retVal; +} + +int +config_get_pw_minuppers() { + slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig(); + int retVal; + + CFG_LOCK_READ(slapdFrontendConfig); + retVal = slapdFrontendConfig->pw_policy.pw_minuppers; + CFG_UNLOCK_READ(slapdFrontendConfig); + + return retVal; +} + +int +config_get_pw_minlowers() { + slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig(); + int retVal; + + CFG_LOCK_READ(slapdFrontendConfig); + retVal = slapdFrontendConfig->pw_policy.pw_minlowers; + CFG_UNLOCK_READ(slapdFrontendConfig); + + return retVal; +} + +int +config_get_pw_minspecials() { + slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig(); + int retVal; + + CFG_LOCK_READ(slapdFrontendConfig); + retVal = slapdFrontendConfig->pw_policy.pw_minspecials; + CFG_UNLOCK_READ(slapdFrontendConfig); + + return retVal; +} + +int +config_get_pw_min8bit() { + slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig(); + int retVal; + + CFG_LOCK_READ(slapdFrontendConfig); + retVal = slapdFrontendConfig->pw_policy.pw_min8bit; + CFG_UNLOCK_READ(slapdFrontendConfig); + + return retVal; +} + +int +config_get_pw_maxrepeats() { + slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig(); + int retVal; + + CFG_LOCK_READ(slapdFrontendConfig); + retVal = slapdFrontendConfig->pw_policy.pw_maxrepeats; + CFG_UNLOCK_READ(slapdFrontendConfig); + + return retVal; +} + +int +config_get_pw_mincategories() { + slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig(); + int retVal; + + CFG_LOCK_READ(slapdFrontendConfig); + retVal = slapdFrontendConfig->pw_policy.pw_mincategories; + CFG_UNLOCK_READ(slapdFrontendConfig); + + return retVal; +} + +int +config_get_pw_mintokenlength() { + slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig(); + int retVal; + + CFG_LOCK_READ(slapdFrontendConfig); + retVal = slapdFrontendConfig->pw_policy.pw_mintokenlength; + CFG_UNLOCK_READ(slapdFrontendConfig); + + return retVal; +} + int config_get_pw_maxfailure() { slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig(); diff --git a/ldap/servers/slapd/libslapd.def b/ldap/servers/slapd/libslapd.def index bc3fecad..f6a0866b 100644 --- a/ldap/servers/slapd/libslapd.def +++ b/ldap/servers/slapd/libslapd.def @@ -1179,3 +1179,22 @@ EXPORTS sasl_map_done @1179 slapd_SECITEM_FreeItem @1180 slapi_op_type_to_string @1181 +; password syntax functions + config_set_pw_mindigits @1190 + config_set_pw_minalphas @1191 + config_set_pw_minuppers @1192 + config_set_pw_minlowers @1193 + config_set_pw_minspecials @1194 + config_set_pw_min8bit @1195 + config_set_pw_maxrepeats @1196 + config_set_pw_mincategories @1197 + config_set_pw_mintokenlength @1198 + config_get_pw_mindigits @1199 + config_get_pw_minalphas @1200 + config_get_pw_minuppers @1201 + config_get_pw_minlowers @1202 + config_get_pw_minspecials @1203 + config_get_pw_min8bit @1204 + config_get_pw_maxrepeats @1205 + config_get_pw_mincategories @1206 + config_get_pw_mintokenlength @1207 diff --git a/ldap/servers/slapd/modify.c b/ldap/servers/slapd/modify.c index 42a1e154..6d4d5ac9 100644 --- a/ldap/servers/slapd/modify.c +++ b/ldap/servers/slapd/modify.c @@ -65,7 +65,7 @@ static int modify_internal_pb (Slapi_PBlock *pb); static void op_shared_modify (Slapi_PBlock *pb, int pw_change, char *old_pw); static void remove_mod (Slapi_Mods *smods, const char *type, Slapi_Mods *smod_unhashed); -static int op_shared_allow_pw_change (Slapi_PBlock *pb, LDAPMod *mod, char **old_pw); +static int op_shared_allow_pw_change (Slapi_PBlock *pb, LDAPMod *mod, char **old_pw, Slapi_Mods *smods); #ifdef LDAP_DEBUG static const char* @@ -279,7 +279,7 @@ do_modify( Slapi_PBlock *pb ) strcasecmp( mod->mod_type, SLAPI_USERPWD_ATTR ) == 0 ) { /* assumes controls have already been decoded and placed in the pblock */ - pw_change = op_shared_allow_pw_change (pb, mod, &old_pw); + pw_change = op_shared_allow_pw_change (pb, mod, &old_pw, &smods); if (pw_change == -1) { goto free_and_return; } @@ -432,7 +432,8 @@ static int modify_internal_pb (Slapi_PBlock *pb) int opresult = 0; LDAPMod **normalized_mods = NULL; LDAPMod **mods; - LDAPMod **mod; + LDAPMod **mod; + Slapi_Mods smods; int pw_change = 0; char *old_pw = NULL; @@ -469,7 +470,8 @@ static int modify_internal_pb (Slapi_PBlock *pb) { if ((*mod)->mod_bvalues != NULL && strcasecmp((*mod)->mod_type, SLAPI_USERPWD_ATTR) == 0) { - pw_change = op_shared_allow_pw_change (pb, *mod, &old_pw); + slapi_mods_init_passin(&smods, mods); + pw_change = op_shared_allow_pw_change (pb, *mod, &old_pw, &smods); if (pw_change == -1) { /* The internal result code will already have been set by op_shared_allow_pw_change() */ @@ -865,7 +867,7 @@ static void remove_mod (Slapi_Mods *smods, const char *type, Slapi_Mods *smod_un } } -static int op_shared_allow_pw_change (Slapi_PBlock *pb, LDAPMod *mod, char **old_pw) +static int op_shared_allow_pw_change (Slapi_PBlock *pb, LDAPMod *mod, char **old_pw, Slapi_Mods *smods) { int isroot, internal_op, repl_op, pwresponse_req = 0; char *dn; @@ -953,7 +955,7 @@ static int op_shared_allow_pw_change (Slapi_PBlock *pb, LDAPMod *mod, char **old /* check password syntax; remember the old password; error sent directly from check_pw_syntax function */ valuearray_init_bervalarray(mod->mod_bvalues, &values); - switch (check_pw_syntax (pb, &sdn, values, old_pw, NULL, 1)) + switch (check_pw_syntax_ext (pb, &sdn, values, old_pw, NULL, 1, smods)) { case 0: /* success */ rc = 1; diff --git a/ldap/servers/slapd/proto-slap.h b/ldap/servers/slapd/proto-slap.h index 5064fa7b..c159964d 100644 --- a/ldap/servers/slapd/proto-slap.h +++ b/ldap/servers/slapd/proto-slap.h @@ -268,6 +268,15 @@ int config_set_pw_must_change(const char *attrname, char *value, char *errorbuf int config_set_pwpolicy_local(const char *attrname, char *value, char *errorbuf, int apply ); int config_set_pw_syntax(const char *attrname, char *value, char *errorbuf, int apply ); int config_set_pw_minlength(const char *attrname, char *value, char *errorbuf, int apply ); +int config_set_pw_mindigits(const char *attrname, char *value, char *errorbuf, int apply ); +int config_set_pw_minalphas(const char *attrname, char *value, char *errorbuf, int apply ); +int config_set_pw_minuppers(const char *attrname, char *value, char *errorbuf, int apply ); +int config_set_pw_minlowers(const char *attrname, char *value, char *errorbuf, int apply ); +int config_set_pw_minspecials(const char *attrname, char *value, char *errorbuf, int apply ); +int config_set_pw_min8bit(const char *attrname, char *value, char *errorbuf, int apply ); +int config_set_pw_maxrepeats(const char *attrname, char *value, char *errorbuf, int apply ); +int config_set_pw_mincategories(const char *attrname, char *value, char *errorbuf, int apply ); +int config_set_pw_mintokenlength(const char *attrname, char *value, char *errorbuf, int apply ); int config_set_pw_exp(const char *attrname, char *value, char *errorbuf, int apply ); int config_set_pw_maxage(const char *attrname, char *value, char *errorbuf, int apply ); int config_set_pw_minage(const char *attrname, char *value, char *errorbuf, int apply ); @@ -322,6 +331,15 @@ int config_get_pw_history(); int config_get_pw_must_change(); int config_get_pw_syntax(); int config_get_pw_minlength(); +int config_get_pw_mindigits(); +int config_get_pw_minalphas(); +int config_get_pw_minuppers(); +int config_get_pw_minlowers(); +int config_get_pw_minspecials(); +int config_get_pw_min8bit(); +int config_get_pw_maxrepeats(); +int config_get_pw_mincategories(); +int config_get_pw_mintokenlength(); int config_get_pw_maxfailure(); int config_get_pw_inhistory(); long config_get_pw_lockduration(); @@ -694,6 +712,8 @@ int need_new_pw( Slapi_PBlock *pb, long *t, Slapi_Entry *e, int pwresponse_req int update_pw_info( Slapi_PBlock *pb , char *old_pw ); int check_pw_syntax( Slapi_PBlock *pb, const Slapi_DN *sdn, Slapi_Value **vals, char **old_pw, Slapi_Entry *e, int mod_op ); +int check_pw_syntax_ext( Slapi_PBlock *pb, const Slapi_DN *sdn, Slapi_Value **vals, + char **old_pw, Slapi_Entry *e, int mod_op, Slapi_Mods *smods ); int check_account_lock( Slapi_PBlock *pb, Slapi_Entry * bind_target_entry, int pwresponse_req); int check_pw_minage( Slapi_PBlock *pb, const Slapi_DN *sdn, struct berval **vals) ; void add_password_attrs( Slapi_PBlock *pb, Operation *op, Slapi_Entry *e ); diff --git a/ldap/servers/slapd/pw.c b/ldap/servers/slapd/pw.c index a377a334..c7d6896d 100644 --- a/ldap/servers/slapd/pw.c +++ b/ldap/servers/slapd/pw.c @@ -62,7 +62,8 @@ static int pw_in_history(Slapi_Value **history_vals, const Slapi_Value *pw_val); static int update_pw_history( Slapi_PBlock *pb, char *dn, char *old_pw ); -static int check_trivial_words (Slapi_PBlock *, Slapi_Entry *, Slapi_Value **, char *attrtype ); +static int check_trivial_words (Slapi_PBlock *, Slapi_Entry *, Slapi_Value **, + char *attrtype, int toklen, Slapi_Mods *smods ); static int pw_boolean_str2value (const char *str); /* static LDAPMod* pw_malloc_mod (char* name, char* value, int mod_op); */ @@ -715,19 +716,39 @@ int check_pw_syntax ( Slapi_PBlock *pb, const Slapi_DN *sdn, Slapi_Value **vals, char **old_pw, Slapi_Entry *e, int mod_op) { + return ( check_pw_syntax_ext(pb, sdn, vals, old_pw, e, mod_op, NULL) ); +} + +int +check_pw_syntax_ext ( Slapi_PBlock *pb, const Slapi_DN *sdn, Slapi_Value **vals, + char **old_pw, Slapi_Entry *e, int mod_op, Slapi_Mods *smods) +{ Slapi_Attr* attr; - int i, pwresponse_req = 0; + int i, pwresponse_req = 0; char *dn= (char*)slapi_sdn_get_ndn(sdn); /* jcm - Had to cast away const */ + char *pwd = NULL; + char *p = NULL; passwdPolicy *pwpolicy = NULL; pwpolicy = new_passwdPolicy(pb, dn); slapi_pblock_get ( pb, SLAPI_PWPOLICY, &pwresponse_req ); if ( pwpolicy->pw_syntax == 1 ) { - /* check for the minimum password lenght */ for ( i = 0; vals[ i ] != NULL; ++i ) { - if ( pwpolicy->pw_minlength - > (int)slapi_value_get_length(vals[ i ]) ) { /* jcm: had to cast unsigned int to signed int */ + int num_digits = 0; + int num_alphas = 0; + int num_uppers = 0; + int num_lowers = 0; + int num_specials = 0; + int num_8bit = 0; + int num_repeated = 0; + int max_repeated = 0; + int num_categories = 0; + + /* check for the minimum password length */ + if ( pwpolicy->pw_minlength > + ldap_utf8characters((char *)slapi_value_get_string( vals[i] )) ) + { if ( pwresponse_req == 1 ) { slapi_pwpolicy_make_response_control ( pb, -1, -1, LDAP_PWPOLICY_PWDTOOSHORT ); @@ -738,10 +759,95 @@ check_pw_syntax ( Slapi_PBlock *pb, const Slapi_DN *sdn, Slapi_Value **vals, delete_passwdPolicy(&pwpolicy); return ( 1 ); } + + /* check character types */ + pwd = (char *)slapi_value_get_string( vals[i] ); + p = pwd; + /* + pwdlen = slapi_value_get_length( vals[i] ); + for ( j = 0; j < pwdlen; j++ ) { + */ + while ( p && *p ) + { + if ( ldap_utf8isdigit( p ) ) { + num_digits++; + } else if ( ldap_utf8isalpha( p ) ) { + num_alphas++; + if ( slapi_utf8isLower( p ) ) { + num_lowers++; + } else { + num_uppers++; + } + } else { + /* check if this is an 8-bit char */ + if ( *p & 128 ) { + num_8bit++; + } else { + num_specials++; + } + } + + /* check for repeating characters. If this is the + first char of the password, no need to check */ + if ( pwd != p ) { + int len = ldap_utf8len( p ); + char *prev_p = ldap_utf8prev( p ); + + if ( len == ldap_utf8len( prev_p ) ) + { + if ( memcmp( p, prev_p, len ) == 0 ) + { + num_repeated++; + if ( max_repeated < num_repeated ) { + max_repeated = num_repeated; + } + } else { + num_repeated = 0; + } + } else { + num_repeated = 0; + } + } + + p = ldap_utf8next( p ); + } + + /* tally up the number of character categories */ + if ( num_digits > 0 ) + ++num_categories; + if ( num_uppers > 0 ) + ++num_categories; + if ( num_lowers > 0 ) + ++num_categories; + if ( num_specials > 0 ) + ++num_categories; + if ( num_8bit > 0 ) + ++num_categories; + + /* check for character based syntax limits */ + if ( ( pwpolicy->pw_mindigits > num_digits ) || + ( pwpolicy->pw_minalphas > num_alphas ) || + ( pwpolicy->pw_minuppers > num_uppers ) || + ( pwpolicy->pw_minlowers > num_lowers ) || + ( pwpolicy->pw_minspecials > num_specials ) || + ( pwpolicy->pw_min8bit > num_8bit ) || + ( (pwpolicy->pw_maxrepeats != 0) && (pwpolicy->pw_maxrepeats < (max_repeated + 1)) ) || + ( pwpolicy->pw_mincategories > num_categories ) ) + { + if ( pwresponse_req == 1 ) { + slapi_pwpolicy_make_response_control ( pb, -1, -1, + LDAP_PWPOLICY_INVALIDPWDSYNTAX ); + } + pw_send_ldap_result ( pb, + LDAP_CONSTRAINT_VIOLATION, NULL, + "invalid password syntax", 0, NULL ); + delete_passwdPolicy(&pwpolicy); + return ( 1 ); + } } } - /* get the entry and check for the password history and syntax if this is called by a modify operation */ + /* get the entry and check for the password history if this is called by a modify operation */ if ( mod_op ) { /* retrieve the entry */ e = get_entry ( pb, dn ); @@ -808,19 +914,24 @@ check_pw_syntax ( Slapi_PBlock *pb, const Slapi_DN *sdn, Slapi_Value **vals, *old_pw = NULL; } } + } - if ( pwpolicy->pw_syntax == 1 ) { - /* check for trivial words */ - if ( check_trivial_words ( pb, e, vals, "uid" ) == 1 || - check_trivial_words ( pb, e, vals, "cn" ) == 1 || - check_trivial_words ( pb, e, vals, "sn" ) == 1 || - check_trivial_words ( pb, e, vals, "givenname" ) == 1 || - check_trivial_words ( pb, e, vals, "ou" ) == 1 || - check_trivial_words ( pb, e, vals, "mail" ) == 1) { - slapi_entry_free( e ); - delete_passwdPolicy(&pwpolicy); - return 1; + /* check for trivial words if syntax checking is enabled */ + if ( pwpolicy->pw_syntax == 1 ) { + /* e is null if this is an add operation*/ + if ( check_trivial_words ( pb, e, vals, "uid", pwpolicy->pw_mintokenlength, smods ) == 1 || + check_trivial_words ( pb, e, vals, "cn", pwpolicy->pw_mintokenlength, smods ) == 1 || + check_trivial_words ( pb, e, vals, "sn", pwpolicy->pw_mintokenlength, smods ) == 1 || + check_trivial_words ( pb, e, vals, "givenname", pwpolicy->pw_mintokenlength, smods ) == 1 || + check_trivial_words ( pb, e, vals, "ou", pwpolicy->pw_mintokenlength, smods ) == 1 || + check_trivial_words ( pb, e, vals, "mail", pwpolicy->pw_mintokenlength, smods ) == 1) + { + if ( mod_op ) { + slapi_entry_free( e ); } + + delete_passwdPolicy(&pwpolicy); + return 1; } } @@ -1122,33 +1233,91 @@ add_password_attrs( Slapi_PBlock *pb, Operation *op, Slapi_Entry *e ) } static int -check_trivial_words (Slapi_PBlock *pb, Slapi_Entry *e, Slapi_Value **vals, char *attrtype ) +check_trivial_words (Slapi_PBlock *pb, Slapi_Entry *e, Slapi_Value **vals, char *attrtype, + int toklen, Slapi_Mods *smods ) { - Slapi_Attr *attr; - int i, pwresponse_req = 0; + Slapi_Attr *attr = NULL; + Slapi_Mod *smodp = NULL, *smod = NULL; + Slapi_ValueSet *vs = NULL; + Slapi_Value *valp = NULL; + struct berval *bvp = NULL; + int i, pwresponse_req = 0; + + vs = slapi_valueset_new(); slapi_pblock_get ( pb, SLAPI_PWPOLICY, &pwresponse_req ); - attr = attrlist_find(e->e_attrs, attrtype); - if (attr && !valueset_isempty(&attr->a_present_values)) + + /* Get a list of present values for attrtype in the existing entry, if there is one */ + if (e != NULL ) { - Slapi_Value **va= attr_get_present_values(attr); - for ( i = 0; va[i] != NULL; i++ ) + if ( (attr = attrlist_find(e->e_attrs, attrtype)) && + (!valueset_isempty(&attr->a_present_values)) ) { - if( strcasecmp( slapi_value_get_string(va[i]), slapi_value_get_string(vals[0])) == 0) /* JCM Innards */ + /* Add present values to valueset */ + slapi_attr_get_valueset( attr, &vs ); + } + } + + /* Get a list of new values for attrtype from the operation */ + if ( (smod = slapi_mod_new()) && smods ) + { + for (smodp = slapi_mods_get_first_smod(smods, smod); + smodp != NULL; smodp = slapi_mods_get_next_smod(smods, smod) ) + { + /* Operation has new values for attrtype */ + if ( PL_strcasecmp(attrtype, slapi_mod_get_type(smodp)) == 0 ) { - if ( pwresponse_req == 1 ) { + /* iterate through smodp values and add them if they don't exist */ + for ( bvp = slapi_mod_get_first_value( smodp ); bvp != NULL; + bvp = slapi_mod_get_next_value( smodp ) ) + { + /* Add new value to valueset */ + valp = slapi_value_new_berval( bvp ); + slapi_valueset_add_value_ext( vs, valp, SLAPI_VALUE_FLAG_PASSIN ); + valp = NULL; + } + } + } + /* Free smod */ + slapi_mod_free(&smod); + smod = NULL; + smodp = NULL; + } + + /* If valueset isn't empty, we need to check if the password contains the values */ + if ( slapi_valueset_count(vs) != 0 ) + { + for ( i = slapi_valueset_first_value( vs, &valp); + (i != -1) && (valp != NULL); + i = slapi_valueset_next_value( vs, i, &valp) ) + { + /* If the value is smaller than the max token length, + * we don't need to check the password */ + if ( ldap_utf8characters(slapi_value_get_string( valp )) < toklen ) + continue; + + /* See if the password contains the value */ + if ( PL_strcasestr( slapi_value_get_string( vals[0] ), + slapi_value_get_string( valp ) ) ) + { + if ( pwresponse_req == 1 ) + { slapi_pwpolicy_make_response_control ( pb, -1, -1, LDAP_PWPOLICY_INVALIDPWDSYNTAX ); } pw_send_ldap_result ( pb, LDAP_CONSTRAINT_VIOLATION, NULL, - "Password failed triviality check." - " Please choose a different password.", - 0, NULL ); - return ( 1 ); + "invalid password syntax", 0, NULL ); + + /* Free valueset */ + slapi_valueset_free( vs ); + return ( 1 ); } - } + } } + + /* Free valueset */ + slapi_valueset_free( vs ); return ( 0 ); } @@ -1361,6 +1530,60 @@ new_passwdPolicy(Slapi_PBlock *pb, char *dn) } } else + if (!strcasecmp(attr_name, "passwordmindigits")) { + if ((sval = attr_get_present_values(attr))) { + pwdpolicy->pw_mindigits = slapi_value_get_int(*sval); + } + } + else + if (!strcasecmp(attr_name, "passwordminalphas")) { + if ((sval = attr_get_present_values(attr))) { + pwdpolicy->pw_minalphas = slapi_value_get_int(*sval); + } + } + else + if (!strcasecmp(attr_name, "passwordminuppers")) { + if ((sval = attr_get_present_values(attr))) { + pwdpolicy->pw_minuppers = slapi_value_get_int(*sval); + } + } + else + if (!strcasecmp(attr_name, "passwordminlowers")) { + if ((sval = attr_get_present_values(attr))) { + pwdpolicy->pw_minlowers = slapi_value_get_int(*sval); + } + } + else + if (!strcasecmp(attr_name, "passwordminspecials")) { + if ((sval = attr_get_present_values(attr))) { + pwdpolicy->pw_minspecials = slapi_value_get_int(*sval); + } + } + else + if (!strcasecmp(attr_name, "passwordmin8bit")) { + if ((sval = attr_get_present_values(attr))) { + pwdpolicy->pw_min8bit = slapi_value_get_int(*sval); + } + } + else + if (!strcasecmp(attr_name, "passwordmaxrepeats")) { + if ((sval = attr_get_present_values(attr))) { + pwdpolicy->pw_maxrepeats = slapi_value_get_int(*sval); + } + } + else + if (!strcasecmp(attr_name, "passwordmincategories")) { + if ((sval = attr_get_present_values(attr))) { + pwdpolicy->pw_mincategories = slapi_value_get_int(*sval); + } + } + else + if (!strcasecmp(attr_name, "passwordmintokenlength")) { + if ((sval = attr_get_present_values(attr))) { + pwdpolicy->pw_mintokenlength = slapi_value_get_int(*sval); + } + } + else if (!strcasecmp(attr_name, "passwordexp")) { if ((sval = attr_get_present_values(attr))) { pwdpolicy->pw_exp = diff --git a/ldap/servers/slapd/slap.h b/ldap/servers/slapd/slap.h index 380d773e..ca3f68e4 100644 --- a/ldap/servers/slapd/slap.h +++ b/ldap/servers/slapd/slap.h @@ -1661,6 +1661,15 @@ typedef struct _slapdEntryPoints { #define CONFIG_PW_MUSTCHANGE_ATTRIBUTE "passwordMustChange" #define CONFIG_PW_SYNTAX_ATTRIBUTE "passwordCheckSyntax" #define CONFIG_PW_MINLENGTH_ATTRIBUTE "passwordMinLength" +#define CONFIG_PW_MINDIGITS_ATTRIBUTE "passwordMinDigits" +#define CONFIG_PW_MINALPHAS_ATTRIBUTE "passwordMinAlphas" +#define CONFIG_PW_MINUPPERS_ATTRIBUTE "passwordMinUppers" +#define CONFIG_PW_MINLOWERS_ATTRIBUTE "passwordMinLowers" +#define CONFIG_PW_MINSPECIALS_ATTRIBUTE "passwordMinSpecials" +#define CONFIG_PW_MIN8BIT_ATTRIBUTE "passwordMin8Bit" +#define CONFIG_PW_MAXREPEATS_ATTRIBUTE "passwordMaxRepeats" +#define CONFIG_PW_MINCATEGORIES_ATTRIBUTE "passwordMinCategories" +#define CONFIG_PW_MINTOKENLENGTH_ATTRIBUTE "passwordMinTokenLength" #define CONFIG_PW_EXP_ATTRIBUTE "passwordExp" #define CONFIG_PW_MAXAGE_ATTRIBUTE "passwordMaxAge" #define CONFIG_PW_MINAGE_ATTRIBUTE "passwordMinAge" @@ -1715,6 +1724,15 @@ typedef struct passwordpolicyarray { int pw_must_change; /* 1 - indicates that users must change pwd upon reset */ int pw_syntax; int pw_minlength; + int pw_mindigits; + int pw_minalphas; + int pw_minuppers; + int pw_minlowers; + int pw_minspecials; + int pw_min8bit; + int pw_maxrepeats; + int pw_mincategories; + int pw_mintokenlength; int pw_exp; long pw_maxage; long pw_minage; |