ldap/schema/02common.ldif | 3 -
ldap/servers/slapd/entry.c | 53 ++++++++++++-----
ldap/servers/slapd/libglobs.c | 20 ++++++
ldap/servers/slapd/modify.c | 22 ++-----
ldap/servers/slapd/pblock.c | 7 ++
ldap/servers/slapd/proto-slap.h | 1
ldap/servers/slapd/pw.c | 113 ++++++++++++++++++++++++++++++++++++--
ldap/servers/slapd/pw.h | 1
ldap/servers/slapd/slap.h | 3 +
ldap/servers/slapd/slapi-plugin.h | 31 ++++++++++
10 files changed, 219 insertions(+), 35 deletions(-)
New commits:
commit 3ea04762c380a448aa8f72a62a04e5bb748829d4
Author: Mark Reynolds <mreynolds(a)redhat.com>
Date: Wed Mar 20 10:37:45 2013 -0400
Ticket 458 - RFE - Make it possible for privileges to be provided to an admin user
to import an LDIF file containing hashed passwords
Bug Description: Only rootdn can add encoded passwords, or force a user to
change
their password after a reset.
Fix Description: Extended password policy to include "passwordAdminDN".
This
attribute contains a DN of a user or a group. When we create
a new password policy object we gather the DN's that are
Password Policy Administrators. Then we allow these accounts
to add encoded passwords, and force users to reset their
passwords.
https://fedorahosted.org/389/ticket/458
Reviewed by: nhosoi & richm(Thanks!!)
diff --git a/ldap/schema/02common.ldif b/ldap/schema/02common.ldif
index c0ac751..fa604c6 100644
--- a/ldap/schema/02common.ldif
+++ b/ldap/schema/02common.ldif
@@ -94,6 +94,7 @@ attributeTypes: ( 2.16.840.1.113730.3.1.2080 NAME (
'passwordMin8bit' 'pwdMin8bi
attributeTypes: ( 2.16.840.1.113730.3.1.2081 NAME ( 'passwordMaxRepeats'
'pwdMaxRepeats' ) DESC 'Netscape defined password policy attribute type'
SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN 'Netscape Directory
Server' )
attributeTypes: ( 2.16.840.1.113730.3.1.2082 NAME ( 'passwordMinCategories'
'pwdMinCategories' ) DESC 'Netscape defined password policy attribute
type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN 'Netscape
Directory Server' )
attributeTypes: ( 2.16.840.1.113730.3.1.2083 NAME ( 'passwordMinTokenLength'
'pwdMinTokenLength' ) DESC 'Netscape defined password policy attribute
type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN 'Netscape
Directory Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.2153 NAME ( 'passwordAdminDN'
'pwdAdminDN' ) DESC 'Netscape defined password policy attribute type'
SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 SINGLE-VALUE X-ORIGIN 'Netscape Directory
Server' )
attributeTypes: ( 2.16.840.1.113730.3.1.2140 NAME ( 'passwordTrackUpdateTime' )
DESC 'Netscape defined password policy attribute type' SYNTAX
1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN 'Netscape Directory Server' )
attributeTypes: ( 2.16.840.1.113730.3.1.198 NAME 'memberURL' DESC 'Netscape
defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 X-ORIGIN 'Netscape
Directory Server' )
attributeTypes: ( 2.16.840.1.113730.3.1.199 NAME 'memberCertificateDescription'
DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.26
X-ORIGIN 'Netscape Directory Server' )
@@ -164,7 +165,7 @@ objectClasses: ( 2.16.840.1.113730.3.2.7 NAME 'nsLicenseUser'
DESC 'Netscape def
objectClasses: ( 2.16.840.1.113730.3.2.1 NAME 'changeLogEntry' DESC 'LDAP
changelog objectclass' SUP top MUST ( targetdn $ changeTime $ changenumber $
changeType ) MAY ( changes $ newrdn $ deleteoldrdn $ newsuperior ) X-ORIGIN 'Changelog
Internet Draft' )
objectClasses: ( 2.16.840.1.113730.3.2.6 NAME 'referral' DESC 'LDAP referrals
objectclass' SUP top MAY ( ref ) X-ORIGIN 'LDAPv3 referrals Internet Draft' )
objectClasses: ( 2.16.840.1.113730.3.2.12 NAME 'passwordObject' DESC
'Netscape defined password policy objectclass' SUP top MAY ( pwdpolicysubentry $
passwordExpirationTime $ passwordExpWarned $ passwordRetryCount $ retryCountResetTime $
accountUnlockTime $ passwordHistory $ passwordAllowChangeTime $ passwordGraceUserTime )
X-ORIGIN 'Netscape Directory Server' )
-objectClasses: ( 2.16.840.1.113730.3.2.13 NAME 'passwordPolicy' DESC
'Netscape defined password policy objectclass' SUP top MAY ( passwordMaxAge $
passwordExp $ passwordMinLength $ passwordKeepHistory $ passwordInHistory $ passwordChange
$ passwordWarning $ passwordLockout $ passwordMaxFailure $ passwordResetDuration $
passwordUnlock $ passwordLockoutDuration $ passwordCheckSyntax $ passwordMustChange $
passwordStorageScheme $ passwordMinAge $ passwordResetFailureCount $ passwordGraceLimit $
passwordMinDigits $ passwordMinAlphas $ passwordMinUppers $ passwordMinLowers $
passwordMinSpecials $ passwordMin8bit $ passwordMaxRepeats $ passwordMinCategories $
passwordMinTokenLength $ passwordTrackUpdateTime ) X-ORIGIN 'Netscape Directory
Server' )
+objectClasses: ( 2.16.840.1.113730.3.2.13 NAME 'passwordPolicy' DESC
'Netscape defined password policy objectclass' SUP top MAY ( passwordMaxAge $
passwordExp $ passwordMinLength $ passwordKeepHistory $ passwordInHistory $ passwordChange
$ passwordWarning $ passwordLockout $ passwordMaxFailure $ passwordResetDuration $
passwordUnlock $ passwordLockoutDuration $ passwordCheckSyntax $ passwordMustChange $
passwordStorageScheme $ passwordMinAge $ passwordResetFailureCount $ passwordGraceLimit $
passwordMinDigits $ passwordMinAlphas $ passwordMinUppers $ passwordMinLowers $
passwordMinSpecials $ passwordMin8bit $ passwordMaxRepeats $ passwordMinCategories $
passwordMinTokenLength $ passwordTrackUpdateTime $ passwordAdminDN ) X-ORIGIN
'Netscape Directory Server' )
objectClasses: ( 2.16.840.1.113730.3.2.30 NAME 'glue' DESC 'Netscape defined
objectclass' SUP top X-ORIGIN 'Netscape Directory Server' )
objectClasses: ( 2.16.840.1.113730.3.2.32 NAME 'netscapeMachineData' DESC
'Netscape defined objectclass' SUP top X-ORIGIN 'Netscape Directory
Server' )
objectClasses: ( 2.16.840.1.113730.3.2.38 NAME 'vlvSearch' DESC 'Netscape
defined objectclass' SUP top MUST ( cn $ vlvBase $ vlvScope $ vlvFilter ) MAY (
multiLineDescription ) X-ORIGIN 'Netscape Directory Server' )
diff --git a/ldap/servers/slapd/entry.c b/ldap/servers/slapd/entry.c
index 1fde838..ebd49de 100644
--- a/ldap/servers/slapd/entry.c
+++ b/ldap/servers/slapd/entry.c
@@ -2726,24 +2726,45 @@ slapi_entry_delete_string(Slapi_Entry *e, const char *type, const
char *value)
char **
slapi_entry_attr_get_charray( const Slapi_Entry* e, const char *type)
{
+ int ignore;
+ return slapi_entry_attr_get_charray_ext(e, type, &ignore);
+}
+
+/*
+ * The extension also gathers the number of values.
+ * The caller must free with slapi_ch_array_free
+ */
+char **
+slapi_entry_attr_get_charray_ext( const Slapi_Entry* e, const char *type, int *numVals)
+{
char **parray = NULL;
Slapi_Attr* attr = NULL;
- slapi_entry_attr_find(e, type, &attr);
- if(attr!=NULL)
- {
- int hint;
- Slapi_Value *v = NULL;
- for (hint = slapi_attr_first_value(attr, &v);
- hint != -1;
- hint = slapi_attr_next_value(attr, hint, &v))
- {
- const struct berval *bvp = slapi_value_get_berval(v);
- char *p = slapi_ch_malloc(bvp->bv_len + 1);
- memcpy(p, bvp->bv_val, bvp->bv_len);
- p[bvp->bv_len]= '\0';
- charray_add(&parray, p);
- }
- }
+ slapi_entry_attr_find(e, type, &attr);
+ int count = 0;
+
+ if(numVals == NULL){
+ return NULL;
+ }
+
+ if(attr!=NULL){
+ int hint;
+ Slapi_Value *v = NULL;
+
+ for (hint = slapi_attr_first_value(attr, &v);
+ hint != -1;
+ hint = slapi_attr_next_value(attr, hint, &v))
+ {
+ const struct berval *bvp = slapi_value_get_berval(v);
+ char *p = slapi_ch_malloc(bvp->bv_len + 1);
+
+ memcpy(p, bvp->bv_val, bvp->bv_len);
+ p[bvp->bv_len]= '\0';
+ charray_add(&parray, p);
+ count++;
+ }
+ }
+ *numVals = count;
+
return parray;
}
diff --git a/ldap/servers/slapd/libglobs.c b/ldap/servers/slapd/libglobs.c
index 4c977e2..13f5d8b 100644
--- a/ldap/servers/slapd/libglobs.c
+++ b/ldap/servers/slapd/libglobs.c
@@ -387,6 +387,10 @@ static struct config_get_and_set {
NULL, 0,
(void**)&global_slapdFrontendConfig.pw_policy.pw_gracelimit,
CONFIG_INT, NULL, DEFAULT_PW_GRACELIMIT},
+ {CONFIG_PW_ADMIN_DN_ATTRIBUTE, config_set_pw_admin_dn,
+ NULL, 0,
+ (void**)&global_slapdFrontendConfig.pw_policy.pw_admin,
+ CONFIG_STRING, NULL, ""},
{CONFIG_ACCESSLOG_LOGROTATIONSYNCENABLED_ATTRIBUTE, NULL,
log_set_rotationsync_enabled, SLAPD_ACCESS_LOG,
(void**)&global_slapdFrontendConfig.accesslog_rotationsync_enabled,
@@ -1391,6 +1395,8 @@ FrontendConfig_init () {
cfg->pw_policy.pw_lockduration = 3600; /* 60 minutes */
cfg->pw_policy.pw_resetfailurecount = 600; /* 10 minutes */
cfg->pw_policy.pw_gracelimit = 0;
+ cfg->pw_policy.pw_admin = NULL;
+ cfg->pw_policy.pw_admin_user = NULL;
init_pw_is_legacy = cfg->pw_policy.pw_is_legacy = LDAP_ON;
init_pw_track_update_time = cfg->pw_policy.pw_track_update_time = LDAP_OFF;
init_pw_is_global_policy = cfg->pw_is_global_policy = LDAP_OFF;
@@ -2910,6 +2916,20 @@ config_set_pw_is_legacy_policy( const char *attrname, char *value,
char *errorbu
}
int
+config_set_pw_admin_dn( const char *attrname, char *value, char *errorbuf, int apply ) {
+ int retVal = LDAP_SUCCESS;
+ slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
+
+ if ( apply ) {
+ CFG_LOCK_WRITE(slapdFrontendConfig);
+ slapi_sdn_free(&slapdFrontendConfig->pw_policy.pw_admin);
+ slapdFrontendConfig->pw_policy.pw_admin = slapi_sdn_new_dn_byval(value);
+ CFG_UNLOCK_WRITE(slapdFrontendConfig);
+ }
+ return retVal;
+}
+
+int
config_set_pw_track_last_update_time( const char *attrname, char *value, char *errorbuf,
int apply ) {
int retVal = LDAP_SUCCESS;
slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
diff --git a/ldap/servers/slapd/modify.c b/ldap/servers/slapd/modify.c
index 49f2324..d42ef2c 100644
--- a/ldap/servers/slapd/modify.c
+++ b/ldap/servers/slapd/modify.c
@@ -1264,27 +1264,21 @@ static int op_shared_allow_pw_change (Slapi_PBlock *pb, LDAPMod
*mod, char **old
slapi_pblock_set( pb, SLAPI_BACKEND, slapi_be_select( &sdn ) );
/* Check if ACIs allow password to be changed */
- if ( (res = slapi_acl_check_mods(pb, e, mods, &errtxt)) != LDAP_SUCCESS) {
- if (operation_is_flag_set(operation,OP_FLAG_ACTION_LOG_ACCESS))
- {
- if (proxydn)
- {
+ if ( !pw_is_pwp_admin(pb, pwpolicy) && (res = slapi_acl_check_mods(pb, e, mods,
&errtxt)) != LDAP_SUCCESS){
+ if (operation_is_flag_set(operation,OP_FLAG_ACTION_LOG_ACCESS)){
+ if (proxydn){
proxystr = slapi_ch_smprintf(" authzid=\"%s\"", proxydn);
}
-
slapi_log_access(LDAP_DEBUG_STATS, "conn=%" NSPRIu64 " op=%d MOD
dn=\"%s\"%s\n",
pb->pb_conn->c_connid, pb->pb_op->o_opid,
- slapi_sdn_get_dn(&sdn),
- proxystr ? proxystr : "");
+ slapi_sdn_get_dn(&sdn), proxystr ? proxystr : "");
}
/* Write access is denied to userPassword by ACIs */
if ( pwresponse_req == 1 ) {
- slapi_pwpolicy_make_response_control ( pb, -1, -1,
- LDAP_PWPOLICY_PWDMODNOTALLOWED );
- }
-
- send_ldap_result(pb, res, NULL, errtxt, 0, NULL);
+ slapi_pwpolicy_make_response_control ( pb, -1, -1, LDAP_PWPOLICY_PWDMODNOTALLOWED );
+ }
+ send_ldap_result(pb, res, NULL, errtxt, 0, NULL);
slapi_ch_free_string(&errtxt);
rc = -1;
goto done;
@@ -1292,7 +1286,7 @@ static int op_shared_allow_pw_change (Slapi_PBlock *pb, LDAPMod
*mod, char **old
/* Check if password policy allows users to change their passwords.*/
if (!pb->pb_op->o_isroot && slapi_sdn_compare(&sdn,
&pb->pb_op->o_sdn)==0 &&
- !pb->pb_conn->c_needpw && !pwpolicy->pw_change)
+ !pb->pb_conn->c_needpw && !pwpolicy->pw_change &&
!pw_is_pwp_admin(pb, pwpolicy))
{
if ( pwresponse_req == 1 ) {
slapi_pwpolicy_make_response_control ( pb, -1, -1, LDAP_PWPOLICY_PWDMODNOTALLOWED );
diff --git a/ldap/servers/slapd/pblock.c b/ldap/servers/slapd/pblock.c
index d7a726d..8d8c66f 100644
--- a/ldap/servers/slapd/pblock.c
+++ b/ldap/servers/slapd/pblock.c
@@ -1779,7 +1779,6 @@ slapi_pblock_get( Slapi_PBlock *pblock, int arg, void *value )
case SLAPI_PLUGIN_ACL_MODS_UPDATE:
(*(IFP *)value) = pblock->pb_plugin->plg_acl_mods_update;
break;
-
case SLAPI_REQUESTOR_DN:
/* NOTE: It's not a copy of the DN */
if (pblock->pb_op != NULL)
@@ -1792,6 +1791,12 @@ slapi_pblock_get( Slapi_PBlock *pblock, int arg, void *value )
}
break;
+ case SLAPI_REQUESTOR_SDN:
+ if(pblock->pb_op != NULL){
+ (*(Slapi_DN **)value) = &pblock->pb_op->o_sdn;
+ }
+ break;
+
case SLAPI_REQUESTOR_NDN:
/* NOTE: It's not a copy of the DN */
if (pblock->pb_op != NULL)
diff --git a/ldap/servers/slapd/proto-slap.h b/ldap/servers/slapd/proto-slap.h
index acea92f..0bb923f 100644
--- a/ldap/servers/slapd/proto-slap.h
+++ b/ldap/servers/slapd/proto-slap.h
@@ -347,6 +347,7 @@ int config_set_pw_is_global_policy(const char *attrname, char *value,
char *err
int config_set_pw_is_legacy_policy(const char *attrname, char *value, char *errorbuf,
int apply );
int config_set_pw_track_last_update_time(const char *attrname, char *value, char
*errorbuf, int apply );
int config_set_pw_gracelimit(const char *attrname, char *value, char *errorbuf, int
apply );
+int config_set_pw_admin_dn( const char *attrname, char *value, char *errorbuf, int apply
);
int config_set_useroc(const char *attrname, char *value, char *errorbuf, int apply );
int config_set_return_exact_case(const char *attrname, char *value, char *errorbuf, int
apply );
int config_set_result_tweak(const char *attrname, char *value, char *errorbuf, int apply
);
diff --git a/ldap/servers/slapd/pw.c b/ldap/servers/slapd/pw.c
index b95a19d..b31c2a8 100644
--- a/ldap/servers/slapd/pw.c
+++ b/ldap/servers/slapd/pw.c
@@ -77,7 +77,7 @@ 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); */
-
+static void pw_get_admin_users(passwdPolicy *pwp);
/*
* We want to be able to return errors to internal operations (which
@@ -643,7 +643,8 @@ update_pw_info ( Slapi_PBlock *pb , char *old_pw)
* for this special case to ensure we reset the expiration date properly.
*/
if ((internal_op && pwpolicy->pw_must_change && (!pb->pb_conn ||
strcasecmp(target_dn, pb->pb_conn->c_dn))) ||
- (!internal_op && pwpolicy->pw_must_change && (target_dn
&& bind_dn && strcasecmp(target_dn, bind_dn))))
+ (!internal_op && pwpolicy->pw_must_change &&
+ ((target_dn && bind_dn && strcasecmp(target_dn, bind_dn))
&& pw_is_pwp_admin(pb, pwpolicy))))
{
pw_exp_date = NO_TIME;
} else if ( pwpolicy->pw_exp == 1 ) {
@@ -828,7 +829,7 @@ check_pw_syntax_ext ( Slapi_PBlock *pb, const Slapi_DN *sdn,
Slapi_Value **vals,
* case for the password modify extended operation. */
if (slapi_is_encoded((char *)slapi_value_get_string(vals[i]))) {
if ((!is_replication && ((internal_op && pb->pb_conn &&
!slapi_dn_isroot(pb->pb_conn->c_dn)) ||
- (!internal_op && !pb->pb_requestor_isroot)))) {
+ (!internal_op && !pw_is_pwp_admin(pb, pwpolicy))))) {
PR_snprintf( errormsg, BUFSIZ,
"invalid password syntax - passwords with storage scheme are not
allowed");
if ( pwresponse_req == 1 ) {
@@ -1504,6 +1505,94 @@ pw_add_allowchange_aci(Slapi_Entry *e, int pw_prohibit_change) {
slapi_ch_free((void **) &aci_pw);
}
+int
+pw_is_pwp_admin(Slapi_PBlock *pb, passwdPolicy *pwp){
+ Slapi_DN *bind_sdn = NULL;
+ int i;
+
+ /* first check if it's root */
+ if(pb->pb_requestor_isroot){
+ return 1;
+ }
+ /* now check if it's a Password Policy Administrator */
+ slapi_pblock_get(pb, SLAPI_REQUESTOR_SDN, &bind_sdn);
+ if(bind_sdn == NULL){
+ return 0;
+ }
+ for(i = 0; pwp->pw_admin_user && pwp->pw_admin_user[i]; i++){
+ if(slapi_sdn_compare(bind_sdn, pwp->pw_admin_user[i]) == 0){
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+static void
+pw_get_admin_users(passwdPolicy *pwp)
+{
+ Slapi_PBlock *pb = slapi_pblock_new();
+ const Slapi_DN *sdn = pwp->pw_admin;
+ char **uniquemember_vals = NULL;
+ char **member_vals = NULL;
+ int uniquemember_count = 0;
+ int member_count = 0;
+ int nentries = 0;
+ int count = 0;
+ int res;
+ int i;
+
+ if(sdn == NULL){
+ return;
+ }
+ /*
+ * Check if the DN exists and has "group" objectclasses
+ */
+ slapi_search_internal_set_pb(pb, slapi_sdn_get_dn(sdn),
LDAP_SCOPE_BASE,"(|(objectclass=groupofuniquenames)(objectclass=groupofnames))",
+ NULL, 0, NULL, NULL, (void *) plugin_get_default_component_id(), 0);
+ slapi_search_internal_pb(pb);
+ slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_RESULT, &res);
+ if (res != LDAP_SUCCESS) {
+ slapi_pblock_destroy(pb);
+ LDAPDebug(LDAP_DEBUG_ANY, "pw_get_admin_users: search failed for %s: error %d -
Password Policy Administrators can not be set\n",
+ slapi_sdn_get_dn(sdn), res, 0);
+ return;
+ }
+ /*
+ * Ok, we know we have a valid DN, and nentries will tell us if its a group or a user
+ */
+ slapi_pblock_get(pb, SLAPI_NENTRIES, &nentries);
+ if ( nentries > 0 ){
+ /*
+ * It's a group DN, gather all the members
+ */
+ Slapi_Entry **entries = NULL;
+
+ slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_SEARCH_ENTRIES, &entries);
+ uniquemember_vals = slapi_entry_attr_get_charray_ext(entries[0],
"uniquemember", &uniquemember_count);
+ member_vals = slapi_entry_attr_get_charray_ext(entries[0], "member",
&member_count);
+ pwp->pw_admin_user = (Slapi_DN **)slapi_ch_calloc((uniquemember_count + member_count
+ 1), sizeof(Slapi_DN *));
+ if(uniquemember_count > 0){
+ for(i = 0; i < uniquemember_count; i++){
+ pwp->pw_admin_user[count++] = slapi_sdn_new_dn_passin(uniquemember_vals[i]);
+ }
+ }
+ if(member_count > 0){
+ for(i = 0; i < member_count; i++){
+ pwp->pw_admin_user[count++] = slapi_sdn_new_dn_passin(member_vals[i]);
+ }
+ }
+ slapi_ch_free((void**)&uniquemember_vals);
+ slapi_ch_free((void**)&member_vals);
+ } else {
+ /* It's a single user */
+ pwp->pw_admin_user = (Slapi_DN **)slapi_ch_calloc(2, sizeof(Slapi_DN *));
+ pwp->pw_admin_user[0] = slapi_sdn_dup(sdn);
+ }
+ slapi_free_search_results_internal(pb);
+ slapi_pblock_destroy(pb);
+}
+
/* This function creates a passwdPolicy structure, loads it from either
* slapdFrontendconfig or the entry pointed by pwdpolicysubentry and
* returns the structure.
@@ -1813,6 +1902,13 @@ new_passwdPolicy(Slapi_PBlock *pb, const char *dn)
pw_boolean_str2value(slapi_value_get_string(*sval));
}
}
+ else
+ if (!strcasecmp(attr_name, "passwordAdminDN")) {
+ if ((sval = attr_get_present_values(attr))) {
+ pwdpolicy->pw_admin = slapi_sdn_new_dn_byval(slapi_value_get_string(*sval));
+ pw_get_admin_users(pwdpolicy);
+ }
+ }
} /* end of for() loop */
if (pw_entry) {
slapi_entry_free(pw_entry);
@@ -1836,6 +1932,8 @@ done:
*pwdscheme = *slapdFrontendConfig->pw_storagescheme;
pwdscheme->pws_name = strdup( slapdFrontendConfig->pw_storagescheme->pws_name
);
pwdpolicy->pw_storagescheme = pwdscheme;
+ pwdpolicy->pw_admin = slapi_sdn_dup(slapdFrontendConfig->pw_policy.pw_admin);
+ pw_get_admin_users(pwdpolicy);
if(pb){
pb->pwdpolicy = pwdpolicy;
}
@@ -1849,6 +1947,15 @@ delete_passwdPolicy( passwdPolicy **pwpolicy)
{
if (pwpolicy && *pwpolicy) {
free_pw_scheme( (*(*pwpolicy)).pw_storagescheme );
+ slapi_sdn_free(&(*(*pwpolicy)).pw_admin);
+ if((*(*pwpolicy)).pw_admin_user){
+ int i = 0;
+ while((*(*pwpolicy)).pw_admin_user[i]){
+ slapi_sdn_free(&(*(*pwpolicy)).pw_admin_user[i]);
+ i++;
+ }
+ slapi_ch_free((void **)&(*(*pwpolicy)).pw_admin_user);
+ }
slapi_ch_free((void **)pwpolicy);
}
}
diff --git a/ldap/servers/slapd/pw.h b/ldap/servers/slapd/pw.h
index a470fdd..39583e1 100644
--- a/ldap/servers/slapd/pw.h
+++ b/ldap/servers/slapd/pw.h
@@ -92,6 +92,7 @@ int check_pw_duration_value( const char *attr_name, char *value, long
minval, lo
int check_pw_resetfailurecount_value( const char *attr_name, char *value, long minval,
long maxval, char *errorbuf );
int check_pw_storagescheme_value( const char *attr_name, char *value, long minval, long
maxval, char *errorbuf );
+int pw_is_pwp_admin(Slapi_PBlock *pb, struct passwordpolicyarray *pwp);
/*
* Public functions from pw_retry.c:
*/
diff --git a/ldap/servers/slapd/slap.h b/ldap/servers/slapd/slap.h
index 02cb121..f1cd80e 100644
--- a/ldap/servers/slapd/slap.h
+++ b/ldap/servers/slapd/slap.h
@@ -1562,6 +1562,8 @@ typedef struct passwordpolicyarray {
slapi_onoff_t pw_is_legacy;
slapi_onoff_t pw_track_update_time;
struct pw_scheme *pw_storagescheme;
+ Slapi_DN *pw_admin;
+ Slapi_DN **pw_admin_user;
} passwdPolicy;
typedef struct slapi_pblock {
@@ -2023,6 +2025,7 @@ typedef struct _slapdEntryPoints {
#define CONFIG_PW_GRACELIMIT_ATTRIBUTE "passwordGraceLimit"
#define CONFIG_PW_IS_LEGACY "passwordLegacyPolicy"
#define CONFIG_PW_TRACK_LAST_UPDATE_TIME "passwordTrackUpdateTime"
+#define CONFIG_PW_ADMIN_DN_ATTRIBUTE "passwordAdminDN"
#define CONFIG_ACCESSLOG_BUFFERING_ATTRIBUTE "nsslapd-accesslog-logbuffering"
#define CONFIG_CSNLOGGING_ATTRIBUTE "nsslapd-csnlogging"
#define CONFIG_RETURN_EXACT_CASE_ATTRIBUTE "nsslapd-return-exact-case"
diff --git a/ldap/servers/slapd/slapi-plugin.h b/ldap/servers/slapd/slapi-plugin.h
index 42c01bc..f2dc6af 100644
--- a/ldap/servers/slapd/slapi-plugin.h
+++ b/ldap/servers/slapd/slapi-plugin.h
@@ -1633,6 +1633,37 @@ int slapi_entry_attr_delete( Slapi_Entry *e, const char *type );
char **slapi_entry_attr_get_charray(const Slapi_Entry* e, const char *type);
/**
+ * Gets the values of a multi-valued attribute of an entry.
+ *
+ * This function is very similar to slapi_entry_attr_get_charptr(), except that it
+ * returns a <tt>char **</tt> array for multi-valued attributes. The array
and all
+ * values are copies. Even if the attribute values are not strings, they will still
+ * be \c NULL terminated so that they can be used safely in a string context. If there
+ * are no values, \c NULL will be returned. Because the array is \c NULL terminated,
+ * the usage should be similar to the sample shown below:
+ *
+ * \code
+ * char **ary = slapi_entry_attr_get_charray(e, someattr);
+ * int ii;
+ * for (ii = 0; ary && ary[ii]; ++ii) {
+ * char *strval = ary[ii];
+ * ...
+ * }
+ * slapi_ch_array_free(ary);
+ * \endcode
+ *
+ * \param e Entry from which you want to get the values.
+ * \param type Attribute type from which you want to get the values.
+ * \param numVals The number of attribute values will be stored in this variable.
+ * \return A copy of all the values of the attribute.
+ * \return \c NULL if the entry does not contain the attribute or if the attribute
+ * has no values.
+ * \warning When you are done working with the values, free them from memory by calling
+ * the slapi_ch_array_free() function.
+ * \see slapi_entry_attr_get_charptr()
+ */
+char **slapi_entry_attr_get_charray_ext( const Slapi_Entry* e, const char *type, int
*numVals);
+/**
* Gets the first value of an attribute of an entry as a string.
*
* \param e Entry from which you want to get the string value.