summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNathan Kinder <nkinder@redhat.com>2006-01-25 16:51:39 +0000
committerNathan Kinder <nkinder@redhat.com>2006-01-25 16:51:39 +0000
commitaa7708769b0f977a709add4bb10780dfd562cfe1 (patch)
treee017d80a5529fa80b1a23a13d43f8c982b0ebe82
parent19a69e611cf61aae13fac5ac23f64f2a8ea0abca (diff)
downloadds-aa7708769b0f977a709add4bb10780dfd562cfe1.tar.gz
ds-aa7708769b0f977a709add4bb10780dfd562cfe1.tar.xz
ds-aa7708769b0f977a709add4bb10780dfd562cfe1.zip
178867 - Enhanced password syntax checking
-rw-r--r--ldap/servers/slapd/libglobs.c416
-rw-r--r--ldap/servers/slapd/libslapd.def19
-rw-r--r--ldap/servers/slapd/modify.c14
-rw-r--r--ldap/servers/slapd/proto-slap.h20
-rw-r--r--ldap/servers/slapd/pw.c285
-rw-r--r--ldap/servers/slapd/slap.h18
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;