Commit e700dc03 authored by Howard Chu's avatar Howard Chu Committed by Quanah Gibson-Mount
Browse files

ITS#9615 move CheckModule from policy to overlay config

And fix errmsg FIXME
parent 8311c71f
......@@ -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);
}
......@@ -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);
......
......@@ -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;
}
......
......@@ -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 <path>
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
......
......@@ -41,14 +41,18 @@
#include <ac/ctype.h>
#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 */
}