From: Howard Chu Date: Mon, 26 Jul 2021 15:04:24 +0000 (+0100) Subject: ITS#9615 move CheckModule from policy to overlay config X-Git-Tag: OPENLDAP_REL_ENG_2_6_0~130 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=e700dc03eee0d96441aee4edc9d1133db495f94b;p=thirdparty%2Fopenldap.git ITS#9615 move CheckModule from policy to overlay config And fix errmsg FIXME --- diff --git a/contrib/slapd-modules/ppm/ppm.c b/contrib/slapd-modules/ppm/ppm.c index 7c4a54c227..7c6a406817 100644 --- a/contrib/slapd-modules/ppm/ppm.c +++ b/contrib/slapd-modules/ppm/ppm.c @@ -7,10 +7,10 @@ /* password policy module is called with: - int check_password (char *pPasswd, char **ppErrStr, Entry *e, void *pArg) + int check_password (char *pPasswd, struct berval *ppErrmsg, Entry *e, void *pArg) *pPasswd: new password - **ppErrStr: pointer to the string containing the error message + *ppErrmsg: pointer to a struct berval containing space for an error message of length bv_len *e: pointer to the current user entry *pArg: pointer to a struct berval holding the value of pwdCheckModuleArg attr */ @@ -360,13 +360,14 @@ typeParam(char* param) #endif static int -realloc_error_message(char **target, int curlen, int nextlen) +realloc_error_message(const char *orig, char **target, int curlen, int nextlen) { if (curlen < nextlen + MEMORY_MARGIN) { ppm_log(LOG_WARNING, "ppm: Reallocating szErrStr from %d to %d", curlen, nextlen + MEMORY_MARGIN); - ber_memfree(*target); + if (*target != orig) + ber_memfree(*target); curlen = nextlen + MEMORY_MARGIN; *target = (char *) ber_memalloc(curlen); } @@ -428,7 +429,7 @@ containsRDN(char* passwd, char* DN) int -check_password(char *pPasswd, char **ppErrStr, Entry *e, void *pArg) +check_password(char *pPasswd, struct berval *ppErrmsg, Entry *e, void *pArg) { Entry *pEntry = e; @@ -445,8 +446,9 @@ check_password(char *pPasswd, char **ppErrStr, Entry *e, void *pArg) (*(struct berval*)pwdCheckModuleArg).bv_val); #endif - char *szErrStr = (char *) ber_memalloc(MEM_INIT_SZ); - int mem_len = MEM_INIT_SZ; + char *origmsg = ppErrmsg->bv_val; + char *szErrStr = origmsg; + int mem_len = ppErrmsg->bv_len; int numParam = 0; // Number of params in current configuration int useCracklib; @@ -566,7 +568,7 @@ check_password(char *pPasswd, char **ppErrStr, Entry *e, void *pArg) } if (nQuality < minQuality) { - mem_len = realloc_error_message(&szErrStr, mem_len, + mem_len = realloc_error_message(origmsg, &szErrStr, mem_len, strlen(PASSWORD_QUALITY_SZ) + strlen(pEntry->e_nname.bv_val) + 4); sprintf(szErrStr, PASSWORD_QUALITY_SZ, pEntry->e_nname.bv_val, @@ -579,7 +581,7 @@ check_password(char *pPasswd, char **ppErrStr, Entry *e, void *pArg) if ((nbInClass[i] < fileConf[i].min) && strlen(fileConf[i].value.sVal) != 0) { // constraint is not satisfied... goto fail - mem_len = realloc_error_message(&szErrStr, mem_len, + mem_len = realloc_error_message(origmsg, &szErrStr, mem_len, strlen(PASSWORD_CRITERIA) + strlen(pEntry->e_nname.bv_val) + 2 + PARAM_MAX_LEN); @@ -592,7 +594,7 @@ check_password(char *pPasswd, char **ppErrStr, Entry *e, void *pArg) // Password checking done, now loocking for forbiddenChars criteria if (nForbiddenChars > 0) { // at least 1 forbidden char... goto fail - mem_len = realloc_error_message(&szErrStr, mem_len, + mem_len = realloc_error_message(origmsg, &szErrStr, mem_len, strlen(PASSWORD_FORBIDDENCHARS) + strlen(pEntry->e_nname.bv_val) + 2 + VALUE_MAX_LEN); @@ -610,7 +612,7 @@ check_password(char *pPasswd, char **ppErrStr, Entry *e, void *pArg) // Too much consecutive characters of the same class ppm_log(LOG_NOTICE, "ppm: Too much consecutive chars for class %s", fileConf[i].param); - mem_len = realloc_error_message(&szErrStr, mem_len, + mem_len = realloc_error_message(origmsg, &szErrStr, mem_len, strlen(PASSWORD_MAXCONSECUTIVEPERCLASS) + strlen(pEntry->e_nname.bv_val) + 2 + PARAM_MAX_LEN); @@ -630,7 +632,7 @@ check_password(char *pPasswd, char **ppErrStr, Entry *e, void *pArg) if (( fd = fopen ( cracklibDictFiles[j], "r")) == NULL ) { ppm_log(LOG_NOTICE, "ppm: Error while reading %s file", cracklibDictFiles[j]); - mem_len = realloc_error_message(&szErrStr, mem_len, + mem_len = realloc_error_message(origmsg, &szErrStr, mem_len, strlen(GENERIC_ERROR)); sprintf(szErrStr, GENERIC_ERROR); goto fail; @@ -644,7 +646,7 @@ check_password(char *pPasswd, char **ppErrStr, Entry *e, void *pArg) if ( res != NULL ) { ppm_log(LOG_NOTICE, "ppm: cracklib does not validate password for entry %s", pEntry->e_nname.bv_val); - mem_len = realloc_error_message(&szErrStr, mem_len, + mem_len = realloc_error_message(origmsg, &szErrStr, mem_len, strlen(PASSWORD_CRACKLIB) + strlen(pEntry->e_nname.bv_val)); sprintf(szErrStr, PASSWORD_CRACKLIB, pEntry->e_nname.bv_val); @@ -659,7 +661,7 @@ check_password(char *pPasswd, char **ppErrStr, Entry *e, void *pArg) if (checkRDN == 1 && containsRDN(pPasswd, pEntry->e_nname.bv_val)) // RDN check enabled and a token from RDN is found in password: goto fail { - mem_len = realloc_error_message(&szErrStr, mem_len, + mem_len = realloc_error_message(origmsg, &szErrStr, mem_len, strlen(RDN_TOKEN_FOUND) + strlen(pEntry->e_nname.bv_val)); sprintf(szErrStr, RDN_TOKEN_FOUND, pEntry->e_nname.bv_val); @@ -667,13 +669,12 @@ check_password(char *pPasswd, char **ppErrStr, Entry *e, void *pArg) goto fail; } - *ppErrStr = strdup(""); - ber_memfree(szErrStr); + szErrStr[0] = '\0'; return (LDAP_SUCCESS); fail: - *ppErrStr = strdup(szErrStr); - ber_memfree(szErrStr); + ppErrmsg->bv_val = szErrStr; + ppErrmsg->bv_len = mem_len; return (EXIT_FAILURE); } diff --git a/contrib/slapd-modules/ppm/ppm.h b/contrib/slapd-modules/ppm/ppm.h index 25b360d974..049623483f 100644 --- a/contrib/slapd-modules/ppm/ppm.h +++ b/contrib/slapd-modules/ppm/ppm.h @@ -31,7 +31,6 @@ #define DEFAULT_QUALITY 3 #define MEMORY_MARGIN 50 -#define MEM_INIT_SZ 64 #define DN_MAX_LEN 512 #define CONF_MAX_SIZE 50 @@ -111,7 +110,7 @@ int min(char *str1, char *str2); #ifdef PPM_READ_FILE static void read_config_file(conf * fileConf, int *numParam, char *ppm_config_file); #endif -int check_password(char *pPasswd, char **ppErrStr, Entry *e, void *pArg); +int check_password(char *pPasswd, struct berval *ppErrmsg, Entry *e, void *pArg); int maxConsPerClass(char *password, char *charClass); void storeEntry(char *param, char *value, valueType valType, char *min, char *minForPoint, conf * fileConf, int *numParam); diff --git a/contrib/slapd-modules/ppm/ppm_test.c b/contrib/slapd-modules/ppm/ppm_test.c index 520aa0aff5..3754149680 100644 --- a/contrib/slapd-modules/ppm/ppm_test.c +++ b/contrib/slapd-modules/ppm/ppm_test.c @@ -19,7 +19,8 @@ int main(int argc, char *argv[]) ); /* format user entry */ - char *errmsg = NULL; + char errbuf[256]; + struct berval errmsg = { sizeof(errbuf)-1, errbuf }; Entry pEntry; pEntry.e_nname.bv_val=argv[1]; pEntry.e_name.bv_val=argv[1]; @@ -51,10 +52,11 @@ int main(int argc, char *argv[]) } else { - printf("Password failed checks : %s\n", errmsg); + printf("Password failed checks : %s\n", errmsg.bv_val); } - ber_memfree(errmsg); + if (errmsg.bv_val != errbuf) + ber_memfree(errmsg.bv_val); return ret; } diff --git a/doc/man/man5/slapo-ppolicy.5 b/doc/man/man5/slapo-ppolicy.5 index da768fec25..8bd068b4f1 100644 --- a/doc/man/man5/slapo-ppolicy.5 +++ b/doc/man/man5/slapo-ppolicy.5 @@ -100,6 +100,24 @@ If set, ppolicy will send the password policy expired (2.16.840.1.113730.3.4.4) and password policy expiring (2.16.840.1.113730.3.4.5) controls when appropriate. The controls are not sent for bind requests where the Password policy control has already been requested. Default is not to send the controls. +.TP +.B ppolicy_check_module +Specify the path of a loadable module containing a +.B check_password() +function for additional password quality checks. The use of this module +is described further below in the description of the +.B pwdPolicyChecker +objectclass. + +Note: The user-defined loadable module must be in +.B slapd's +standard executable search PATH, or an absolute path must be provided. + +Note: Use of a +.B ppolicy_check_module +is a non-standard extension to the LDAP password +policy proposal. + .SH OBJECT CLASS The @@ -145,7 +163,7 @@ objectclass, used for password quality checking (see below). NAME 'pwdPolicyChecker' AUXILIARY SUP top - MAY ( pwdCheckModule $ pwdCheckModuleArg ) ) + MAY ( pwdCheckModule $ pwdCheckModuleArg $ pwdUseCheckModule ) ) .RE .P Every account that should be subject to password policy control should @@ -279,8 +297,9 @@ without checking it (if is zero (0) or one (1)) or refuse it (if .B pwdCheckQuality is two (2)). If the number of characters should be enforced with regards -to a particular encoding, the use of an appropriate pwdCheckModule is -required. +to a particular encoding, the use of an appropriate +.B ppolicy_check_module +is required. .LP .RS 4 ( 1.3.6.1.4.1.42.2.27.8.1.6 @@ -309,8 +328,9 @@ without checking it (if is zero (0) or one (1)) or refuse it (if .B pwdCheckQuality is two (2)). If the number of characters should be enforced with regards -to a particular encoding, the use of an appropriate pwdCheckModule is -required. +to a particular encoding, the use of an appropriate +.B ppolicy_check_module +is required. .LP .RS 4 ( 1.3.6.1.4.1.42.2.27.8.1.31 @@ -622,9 +642,13 @@ is set to SINGLE\-VALUE ) .RE -.BR pwdCheckModule / pwdCheckModuleArg +.BR pwdUseCheckModule / pwdCheckModuleArg .P -This attribute names a user-defined loadable module that must +The +.B pwdUseCheckModule +attribute enables use of a loadable module previously configured with +.B ppolicy_check_module +for the current policy. The module must instantiate the check_password() function. This function will be called to further check a new password if .B pwdCheckQuality @@ -635,14 +659,22 @@ function prototype: .RS 4 int .I check_password -(char *pPasswd, char **ppErrStr, Entry *pEntry, struct berval *pArg); +(char *pPasswd, struct berval *pErrmsg, Entry *pEntry, struct berval *pArg); .RE The .B pPasswd parameter contains the clear-text user password, the -.B ppErrStr -parameter contains a double pointer that allows the function +.B pErrmsg +parameter points to a +.B struct berval +containing space to return human-readable details about any error it encounters. +The +.B bv_len +field must contain the size of the space provided +by the +.B bv_val +field. The .B pEntry @@ -658,24 +690,31 @@ containing the value of in the effective password policy, if set, otherwise NULL. If -.B ppErrStr +.B pErrmsg is NULL, then .I funcName -must NOT attempt to use it/them. +must NOT attempt to use it. A return value of LDAP_SUCCESS from the called function indicates that the password is ok, any other value indicates that the password is unacceptable. If the password is unacceptable, the server will return an error to the client, and -.B ppErrStr +.B pErrmsg may be used to return a human-readable textual explanation of the -error. The error string must be dynamically allocated as it will +error. If the space passed in by the caller is too small, the function +may replace it with a dynamically allocated buffer, which will be free()'d by slapd. + +The +.B pwdCheckModule +attribute is now obsolete and is ignored. + .LP .RS 4 ( 1.3.6.1.4.1.4754.1.99.1 NAME 'pwdCheckModule' EQUALITY caseExactIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 + OBSOLETE SINGLE\-VALUE ) ( 1.3.6.1.4.1.4754.1.99.2 @@ -684,19 +723,13 @@ be free()'d by slapd. SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 DESC 'Argument to pass to check_password() function' SINGLE\-VALUE ) + +( 1.3.6.1.4.1.4754.1.99.3 + NAME 'pwdUseCheckModule' + EQUALITY booleanMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 + SINGLE\-VALUE ) .RE -.P -Note: -The user-defined loadable module named by -.B pwdCheckModule -must be in -.B slapd's -standard executable search PATH. -.P -Note: -.B pwdCheckModule -is a non-standard extension to the LDAP password -policy proposal. .SH OPERATIONAL ATTRIBUTES .P diff --git a/servers/slapd/overlays/ppolicy.c b/servers/slapd/overlays/ppolicy.c index 6f56752a59..e684ae921f 100644 --- a/servers/slapd/overlays/ppolicy.c +++ b/servers/slapd/overlays/ppolicy.c @@ -41,14 +41,18 @@ #include #include "slap-config.h" -#ifndef MODULE_NAME_SZ -#define MODULE_NAME_SZ 256 -#endif - #ifndef PPOLICY_DEFAULT_MAXRECORDED_FAILURE #define PPOLICY_DEFAULT_MAXRECORDED_FAILURE 5 #endif + /* External password quality checking function. + * The error message must have a preallocated buffer and size + * passed in. Module can still allocate a buffer for + * it if the provided one is too small. + */ +typedef int (check_func)( char *passwd, struct berval *errmsg, Entry *ent, struct berval *arg ); +#define ERRBUFSIZ 256 + /* Per-instance configuration information */ typedef struct pp_info { struct berval def_policy; /* DN of default policy subentry */ @@ -57,6 +61,10 @@ typedef struct pp_info { int forward_updates; /* use frontend for policy state updates */ int disable_write; int send_netscape_controls; /* send netscape password controls */ + char *pwdCheckModule; /* name of module to dynamically + load to check password */ + lt_dlhandle pwdCheckHandle; /* handle from lt_dlopen */ + check_func *pwdCheckFunc; ldap_pvt_thread_mutex_t pwdFailureTime_mutex; } pp_info; @@ -104,8 +112,7 @@ typedef struct pass_policy { 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 */ + int pwdUseCheckModule; /* 0 = do not use password check module, 1 = use */ struct berval pwdCheckModuleArg; /* Optional argument to the password check module */ } PassPolicy; @@ -129,7 +136,7 @@ static AttributeDescription *ad_pwdMinAge, *ad_pwdMaxAge, *ad_pwdMaxIdle, *ad_pwdMaxFailure, *ad_pwdGraceExpiry, *ad_pwdGraceAuthNLimit, *ad_pwdExpireWarning, *ad_pwdMinDelay, *ad_pwdMaxDelay, *ad_pwdLockoutDuration, *ad_pwdFailureCountInterval, - *ad_pwdCheckModule, *ad_pwdCheckModuleArg, *ad_pwdLockout, + *ad_pwdCheckModule, *ad_pwdCheckModuleArg, *ad_pwdUseCheckModule, *ad_pwdLockout, *ad_pwdMustChange, *ad_pwdAllowUserChange, *ad_pwdSafeModify, *ad_pwdAttribute, *ad_pwdMaxRecordedFailure; @@ -382,7 +389,8 @@ static struct schema_info { "NAME ( 'pwdCheckModule' ) " "EQUALITY caseExactIA5Match " "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 " - "DESC 'Loadable module that instantiates check_password() function' " + "DESC 'Obsolete, no longer used' " + "OBSOLETE " "SINGLE-VALUE )", &ad_pwdCheckModule }, { "( 1.3.6.1.4.1.4754.1.99.2 " @@ -392,6 +400,13 @@ static struct schema_info { "DESC 'Argument to pass to check_password() function' " "SINGLE-VALUE )", &ad_pwdCheckModuleArg }, + { "( 1.3.6.1.4.1.4754.1.99.3 " + "NAME ( 'pwdUseCheckModule' ) " + "EQUALITY booleanMatch " + "SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 " + "DESC 'Toggle use of the loaded pwdCheckModule' " + "SINGLE-VALUE )", + &ad_pwdUseCheckModule }, { NULL, NULL } }; @@ -401,7 +416,7 @@ static char *pwd_ocs[] = { "NAME 'pwdPolicyChecker' " "SUP top " "AUXILIARY " - "MAY ( pwdCheckModule $ pwdCheckModuleArg ) )" , + "MAY ( pwdCheckModule $ pwdCheckModuleArg $ pwdUseCheckModule ) )" , "( 1.3.6.1.4.1.42.2.27.8.2.1 " "NAME 'pwdPolicy' " "SUP top " @@ -424,9 +439,10 @@ enum { PPOLICY_HASH_CLEARTEXT, PPOLICY_USE_LOCKOUT, PPOLICY_DISABLE_WRITE, + PPOLICY_CHECK_MODULE, }; -static ConfigDriver ppolicy_cf_default; +static ConfigDriver ppolicy_cf_default, ppolicy_cf_checkmod; static ConfigTable ppolicycfg[] = { { "ppolicy_default", "policyDN", 2, 2, 0, @@ -470,6 +486,13 @@ static ConfigTable ppolicycfg[] = { "DESC 'Send Netscape policy controls' " "EQUALITY booleanMatch " "SYNTAX OMsBoolean SINGLE-VALUE )", NULL, NULL }, + { "ppolicy_check_module", "path", 2, 2, 0, + ARG_STRING|ARG_MAGIC|PPOLICY_CHECK_MODULE, ppolicy_cf_checkmod, + "( OLcfgOvAt:12.7 NAME 'olcPPolicyCheckModule' " + "DESC 'Loadable module that instantiates check_password() function' " + "EQUALITY caseExactIA5Match " + "SYNTAX OMsIA5String " + "SINGLE-VALUE )", NULL, NULL }, { NULL, NULL, 0, 0, 0, ARG_IGNORED } }; @@ -480,7 +503,8 @@ static ConfigOCs ppolicyocs[] = { "SUP olcOverlayConfig " "MAY ( olcPPolicyDefault $ olcPPolicyHashCleartext $ " "olcPPolicyUseLockout $ olcPPolicyForwardUpdates $ " - "olcPPolicyDisableWrite $ olcPPolicySendNetscapeControls ) )", + "olcPPolicyDisableWrite $ olcPPolicySendNetscapeControls $ " + "olcPPolicyCheckModule ) )", Cft_Overlay, ppolicycfg }, { NULL, 0, NULL } }; @@ -536,6 +560,61 @@ ppolicy_cf_default( ConfigArgs *c ) return rc; } +static int +ppolicy_cf_checkmod( ConfigArgs *c ) +{ + slap_overinst *on = (slap_overinst *)c->bi; + pp_info *pi = (pp_info *)on->on_bi.bi_private; + int rc = ARG_BAD_CONF; + + assert ( c->type == PPOLICY_CHECK_MODULE ); + Debug(LDAP_DEBUG_TRACE, "==> ppolicy_cf_checkmod\n" ); + + switch ( c->op ) { + case SLAP_CONFIG_EMIT: + if ( pi->pwdCheckModule ) { + c->value_string = ch_strdup( pi->pwdCheckModule ); + rc = 0; + } + break; + case LDAP_MOD_DELETE: + if ( pi->pwdCheckHandle ) { + lt_dlclose( pi->pwdCheckHandle ); + pi->pwdCheckHandle = NULL; + pi->pwdCheckFunc = NULL; + } + ch_free( pi->pwdCheckModule ); + pi->pwdCheckModule = NULL; + rc = 0; + break; + case SLAP_CONFIG_ADD: + /* fallthru to LDAP_MOD_ADD */ + case LDAP_MOD_ADD: + pi->pwdCheckHandle = lt_dlopen( c->value_string ); + if ( pi->pwdCheckHandle == NULL ) { + const char *dlerr = lt_dlerror(); + snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> lt_dlopen(%s) failed: %s", + c->argv[0], c->value_string, dlerr ); + Debug(LDAP_DEBUG_ANY, "%s: %s\n", c->log, c->cr_msg ); + } else { + if (( pi->pwdCheckFunc = lt_dlsym( pi->pwdCheckHandle, "check_password" )) == NULL) { + const char *dlerr = lt_dlerror(); + snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> lt_dlsym(%s) failed: %s", + c->argv[0], c->value_string, dlerr ); + Debug(LDAP_DEBUG_ANY, "%s: %s\n", c->log, c->cr_msg ); + } else { + pi->pwdCheckModule = c->value_string; + rc = 0; + } + } + break; + default: + abort (); + } + + return rc; +} + static time_t parse_time( char *atm ) { @@ -1024,12 +1103,16 @@ ppolicy_get( Operation *op, Entry *e, PassPolicy *pp ) } ad = ad_pwdCheckModule; - if ( (a = attr_find( pe->e_attrs, ad )) ) { - strncpy( pp->pwdCheckModule, a->a_vals[0].bv_val, - sizeof(pp->pwdCheckModule) ); - pp->pwdCheckModule[sizeof(pp->pwdCheckModule)-1] = '\0'; + if ( attr_find( pe->e_attrs, ad )) { + Debug( LDAP_DEBUG_ANY, "ppolicy_get: " + "WARNING: Ignoring OBSOLETE attribute %s in policy %s.\n", + ad->ad_cname.bv_val, pe->e_name.bv_val ); } + ad = ad_pwdUseCheckModule; + if ( (a = attr_find( pe->e_attrs, ad )) ) + pp->pwdUseCheckModule = bvmatch( &a->a_nvals[0], &slap_true_bv ); + ad = ad_pwdCheckModuleArg; if ( (a = attr_find( pe->e_attrs, ad )) ) { ber_dupbv_x( &pp->pwdCheckModuleArg, &a->a_vals[0], op->o_tmpmemctx ); @@ -1123,7 +1206,8 @@ password_scheme( struct berval *cred, struct berval *sch ) } static int -check_password_quality( struct berval *cred, PassPolicy *pp, LDAPPasswordPolicyError *err, Entry *e, char **txt ) +check_password_quality( struct berval *cred, pp_info *pi, PassPolicy *pp, LDAPPasswordPolicyError *err, + Entry *e, struct berval *errmsg ) { int rc = LDAP_SUCCESS, ok = LDAP_SUCCESS; char *ptr; @@ -1131,11 +1215,12 @@ check_password_quality( struct berval *cred, PassPolicy *pp, LDAPPasswordPolicyE assert( cred != NULL ); assert( pp != NULL ); - assert( txt != NULL ); + assert( errmsg != NULL ); - ptr = cred->bv_val; + ptr = errmsg->bv_val; + *ptr = '\0'; - *txt = NULL; + ptr = cred->bv_val; if ((cred->bv_len == 0) || (pp->pwdMinLength > cred->bv_len)) { rc = LDAP_CONSTRAINT_VIOLATION; @@ -1180,63 +1265,40 @@ check_password_quality( struct berval *cred, PassPolicy *pp, LDAPPasswordPolicyE rc = LDAP_SUCCESS; - if (pp->pwdCheckModule[0]) { + if (pp->pwdUseCheckModule) { #ifdef SLAPD_MODULES - lt_dlhandle mod; - const char *err; - - if ((mod = lt_dlopen( pp->pwdCheckModule )) == NULL) { - err = lt_dlerror(); + check_func *prog; + if ( !pi->pwdCheckFunc ) { Debug(LDAP_DEBUG_ANY, - "check_password_quality: lt_dlopen failed: (%s) %s.\n", - pp->pwdCheckModule, err ); - ok = LDAP_OTHER; /* internal error */ + "check_password_quality: no CheckModule loaded\n" ); + ok = LDAP_OTHER; } else { - /* FIXME: the error message ought to be passed thru a - * struct berval, with preallocated buffer and size - * passed in. Module can still allocate a buffer for - * it if the provided one is too small. - */ - int (*prog)( char *passwd, char **text, Entry *ent, struct berval *arg ); - - if ((prog = lt_dlsym( mod, "check_password" )) == NULL) { - err = lt_dlerror(); + struct berval *arg = NULL; + if ( !BER_BVISNULL( &pp->pwdCheckModuleArg ) ) { + arg = &pp->pwdCheckModuleArg; + } + ldap_pvt_thread_mutex_lock( &chk_syntax_mutex ); + ok = pi->pwdCheckFunc( ptr, errmsg, e, arg ); + ldap_pvt_thread_mutex_unlock( &chk_syntax_mutex ); + if (ok != LDAP_SUCCESS) { Debug(LDAP_DEBUG_ANY, - "check_password_quality: lt_dlsym failed: (%s) %s.\n", - pp->pwdCheckModule, err ); - ok = LDAP_OTHER; - } else { - struct berval *arg = NULL; - if ( !BER_BVISNULL( &pp->pwdCheckModuleArg ) ) { - arg = &pp->pwdCheckModuleArg; - } - - ldap_pvt_thread_mutex_lock( &chk_syntax_mutex ); - ok = prog( ptr, txt, e, arg ); - ldap_pvt_thread_mutex_unlock( &chk_syntax_mutex ); - if (ok != LDAP_SUCCESS) { - Debug(LDAP_DEBUG_ANY, - "check_password_quality: module error: (%s) %s.[%d]\n", - pp->pwdCheckModule, *txt ? *txt : "", ok ); - } + "check_password_quality: module error: (%s) %s.[%d]\n", + pi->pwdCheckModule, errmsg->bv_val ? errmsg->bv_val : "", ok ); } - - lt_dlclose( mod ); } #else - Debug(LDAP_DEBUG_ANY, "check_password_quality: external modules not " - "supported. pwdCheckModule ignored.\n" ); + Debug(LDAP_DEBUG_ANY, "check_password_quality: external modules not " + "supported. pwdCheckModule ignored.\n" ); #endif /* SLAPD_MODULES */ } - - + if (ok != LDAP_SUCCESS) { rc = LDAP_CONSTRAINT_VIOLATION; if (err) *err = PP_insufficientPasswordQuality; } - + return rc; } @@ -2240,14 +2302,16 @@ ppolicy_add( struct berval *bv = &(pa->a_vals[0]); int rc, send_ctrl = 0; LDAPPasswordPolicyError pErr = PP_noError; - char *txt; + char errbuf[ERRBUFSIZ]; + struct berval errmsg = BER_BVC( errbuf ); /* Did we receive a password policy request control? */ if ( op->o_ctrlflag[ppolicy_cid] ) { send_ctrl = 1; } - rc = check_password_quality( bv, &pp, &pErr, op->ora_e, &txt ); + rc = check_password_quality( bv, pi, &pp, &pErr, op->ora_e, &errmsg ); if (rc != LDAP_SUCCESS) { + char *txt = errmsg.bv_val; LDAPControl **oldctrls = NULL; op->o_bd->bd_info = (BackendInfo *)on->on_info; if ( send_ctrl ) { @@ -2255,8 +2319,8 @@ ppolicy_add( ctrl = create_passcontrol( op, -1, -1, pErr ); oldctrls = add_passcontrol( op, rs, ctrl ); } - send_ldap_error( op, rs, rc, txt ? txt : "Password fails quality checking policy" ); - if ( txt ) { + send_ldap_error( op, rs, rc, txt && txt[0] ? txt : "Password fails quality checking policy" ); + if ( txt != errbuf ) { free( txt ); } if ( send_ctrl ) { @@ -2353,6 +2417,7 @@ ppolicy_modify( Operation *op, SlapReply *rs ) *ml, *delmod, *addmod; Attribute *pa, *ha, at; const char *txt; + char errbuf[ERRBUFSIZ]; pw_hist *tl = NULL, *p; int zapReset, send_ctrl = 0, free_txt = 0; Entry *e; @@ -2767,13 +2832,16 @@ ppolicy_modify( Operation *op, SlapReply *rs ) bv = newpw.bv_val ? &newpw : &addmod->sml_values[0]; if (pp.pwdCheckQuality > 0) { + struct berval errmsg = BER_BVC( errbuf ); - rc = check_password_quality( bv, &pp, &pErr, e, (char **)&txt ); + rc = check_password_quality( bv, pi, &pp, &pErr, e, &errmsg ); if (rc != LDAP_SUCCESS) { rs->sr_err = rc; - if ( txt ) { + txt = errmsg.bv_val; + if ( txt && txt[0] ) { rs->sr_text = txt; - free_txt = 1; + if ( txt != errbuf ) + free_txt = 1; } else { rs->sr_text = "Password fails quality checking policy"; }