From fa6fba4d7716cb2ce4cd5446e0af790d765d71e2 Mon Sep 17 00:00:00 2001
From: Mark Reynolds <mreynolds@redhat.com>
Date: Wed, 5 Mar 2014 15:55:31 -0500
Subject: [PATCH] Ticket 417, 458, 47522 - Password Administrator Backport
Description: Backported all the fixes needed to implement the feature.
https://fedorahosted.org/389/ticket/417
https://fedorahosted.org/389/ticket/458
https://fedorahosted.org/389/ticket/47522
Bug 985270 - [RFE] Add Password adminstrators to RHDS 9 as in
http://directory.fedoraproject.org/wiki/Password_Administrator (edit)
Reviewed by: nhosoi(Thanks!)
(cherry picked from commit 096d8958a81ee57d3486d8260430cbfab81a0bbc)
---
ldap/schema/02common.ldif | 3 +-
ldap/servers/slapd/entry.c | 45 ++++++++++----
ldap/servers/slapd/libglobs.c | 24 +++++++-
ldap/servers/slapd/modify.c | 25 ++++----
ldap/servers/slapd/pblock.c | 6 ++
ldap/servers/slapd/proto-slap.h | 1 +
ldap/servers/slapd/pw.c | 123 ++++++++++++++++++++++++++++++++++++--
ldap/servers/slapd/pw.h | 1 +
ldap/servers/slapd/slap.h | 3 +
ldap/servers/slapd/slapi-plugin.h | 32 ++++++++++
10 files changed, 233 insertions(+), 30 deletions(-)
diff --git a/ldap/schema/02common.ldif b/ldap/schema/02common.ldif
index ffec7ce..92feb49 100644
--- a/ldap/schema/02common.ldif
+++ b/ldap/schema/02common.ldif
@@ -95,6 +95,7 @@ attributeTypes: ( 2.16.840.1.113730.3.1.2081 NAME ( 'passwordMaxRepeats' 'pwdMax
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.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.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.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' )
attributeTypes: ( 2.16.840.1.113730.3.1.207 NAME 'vlvBase' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 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 $ passwordAdminDN $ passwordMinAlphas $ passwordMinUppers $ passwordMinLowers $ passwordMinSpecials $ passwordMin8bit $ passwordMaxRepeats $ passwordMinCategories $ passwordMinTokenLength $ passwordTrackUpdateTime ) 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 785256f..8b7766e 100644
--- a/ldap/servers/slapd/entry.c
+++ b/ldap/servers/slapd/entry.c
@@ -2630,25 +2630,46 @@ 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)
{
- char **parray = NULL;
- Slapi_Attr* attr = NULL;
+ 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;
+ int count = 0;
+
+ if(numVals == NULL){
+ return NULL;
+ }
+
slapi_entry_attr_find(e, type, &attr);
- if(attr!=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++;
}
}
- return parray;
+ *numVals = count;
+
+ return parray;
}
char *
@@ -2660,16 +2681,18 @@ slapi_entry_attr_get_charptr( const Slapi_Entry* e, const char *type)
if(attr!=NULL)
{
Slapi_Value *v;
- const struct berval *bvp;
+ const struct berval *bvp;
+
slapi_valueset_first_value( &attr->a_present_values, &v);
- bvp = slapi_value_get_berval(v);
- p= slapi_ch_malloc(bvp->bv_len + 1);
- memcpy(p, bvp->bv_val, bvp->bv_len);
- p[bvp->bv_len]= '\0';
+ bvp = slapi_value_get_berval(v);
+ p= slapi_ch_malloc(bvp->bv_len + 1);
+ memcpy(p, bvp->bv_val, bvp->bv_len);
+ p[bvp->bv_len]= '\0';
}
- return p;
+ return p;
}
+
int
slapi_entry_attr_get_int( const Slapi_Entry* e, const char *type)
{
diff --git a/ldap/servers/slapd/libglobs.c b/ldap/servers/slapd/libglobs.c
index 8103133..b7dadcd 100644
--- a/ldap/servers/slapd/libglobs.c
+++ b/ldap/servers/slapd/libglobs.c
@@ -248,6 +248,9 @@ static struct config_get_and_set {
{CONFIG_PWPOLICY_LOCAL_ATTRIBUTE, config_set_pwpolicy_local,
NULL, 0,
(void**)&global_slapdFrontendConfig.pwpolicy_local, CONFIG_ON_OFF, NULL},
+ {CONFIG_PW_ADMIN_DN_ATTRIBUTE, config_set_pw_admin_dn,
+ NULL, 0,
+ (void**)&global_slapdFrontendConfig.pw_policy.pw_admin, CONFIG_STRING, NULL},
{CONFIG_AUDITLOG_MAXLOGDISKSPACE_ATTRIBUTE, NULL,
log_set_maxdiskspace, SLAPD_AUDIT_LOG,
(void**)&global_slapdFrontendConfig.auditlog_maxdiskspace, CONFIG_INT, NULL},
@@ -685,8 +688,7 @@ static struct config_get_and_set {
{CONFIG_DISK_THRESHOLD, config_set_disk_threshold,
NULL, 0,
(void**)&global_slapdFrontendConfig.disk_threshold,
- CONFIG_LONG_LONG, (ConfigGetFunc)config_get_disk_threshold,
- DEFAULT_DISK_THRESHOLD},
+ CONFIG_LONG_LONG, (ConfigGetFunc)config_get_disk_threshold},
{CONFIG_DISK_GRACE_PERIOD, config_set_disk_grace_period,
NULL, 0,
(void**)&global_slapdFrontendConfig.disk_grace_period,
@@ -1122,9 +1124,11 @@ FrontendConfig_init () {
cfg->disk_grace_period = 60; /* 1 hour */
cfg->disk_logging_critical = LDAP_OFF;
cfg->sasl_max_bufsize = SLAPD_DEFAULT_SASL_MAXBUFSIZE;
-
+ cfg->pw_policy.pw_admin = NULL;
+ cfg->pw_policy.pw_admin_user = NULL;
cfg->listen_backlog_size = DAEMON_LISTEN_SIZE;
cfg->ignore_time_skew = LDAP_OFF;
+
#if defined(LINUX)
cfg->malloc_mxfast = DEFAULT_MALLOC_UNSET;
cfg->malloc_trim_threshold = DEFAULT_MALLOC_UNSET;
@@ -2837,6 +2841,20 @@ config_set_dn_validate_strict( const char *attrname, char *value, char *errorbuf
}
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_ds4_compatible_schema( 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 817f17c..90c9f8c 100644
--- a/ldap/servers/slapd/modify.c
+++ b/ldap/servers/slapd/modify.c
@@ -1227,11 +1227,9 @@ 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);
}
@@ -1243,16 +1241,23 @@ static int op_shared_allow_pw_change (Slapi_PBlock *pb, LDAPMod *mod, char **old
/* 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;
}
+ /*
+ * If this mod is being performed by a password administrator/rootDN,
+ * just return success.
+ */
+ if(pw_is_pwp_admin(pb, pwpolicy)){
+ rc = 1;
+ goto done;
+ }
+
/* 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)
diff --git a/ldap/servers/slapd/pblock.c b/ldap/servers/slapd/pblock.c
index 9b59e7b..849c20e 100644
--- a/ldap/servers/slapd/pblock.c
+++ b/ldap/servers/slapd/pblock.c
@@ -1803,6 +1803,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_OPERATION_AUTHTYPE:
if (pblock->pb_op != NULL)
{
diff --git a/ldap/servers/slapd/proto-slap.h b/ldap/servers/slapd/proto-slap.h
index 954cfd2..8c9f0fb 100644
--- a/ldap/servers/slapd/proto-slap.h
+++ b/ldap/servers/slapd/proto-slap.h
@@ -347,6 +347,7 @@ int config_set_return_exact_case(const char *attrname, char *value, char *error
int config_set_result_tweak(const char *attrname, char *value, char *errorbuf, int apply );
int config_set_referral_mode(const char *attrname, char *url, char *errorbuf, int apply);
int config_set_conntablesize(const char *attrname, char *url, char *errorbuf, int apply);
+int config_set_pw_admin_dn( const char *attrname, char *value, char *errorbuf, int apply );
int config_set_maxbersize(const char *attrname, char *value, char *errorbuf, int apply );
int config_set_maxsasliosize(const char *attrname, char *value, char *errorbuf, int apply );
int config_set_versionstring(const char *attrname, char *versionstring, char *errorbuf, int apply );
diff --git a/ldap/servers/slapd/pw.c b/ldap/servers/slapd/pw.c
index 6f3d436..cf400a1 100644
--- a/ldap/servers/slapd/pw.c
+++ b/ldap/servers/slapd/pw.c
@@ -73,6 +73,8 @@ static int update_pw_history( Slapi_PBlock *pb, const Slapi_DN *sdn, char *old_p
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 void pw_get_admin_users(passwdPolicy *pwp);
+
/* static LDAPMod* pw_malloc_mod (char* name, char* value, int mod_op); */
@@ -588,7 +590,7 @@ update_pw_info ( Slapi_PBlock *pb , char *old_pw) {
char *timestr;
time_t pw_exp_date;
time_t cur_time;
- const char *dn;
+ const char *target_dn, *bind_dn;
Slapi_DN *sdn = NULL;
passwdPolicy *pwpolicy = NULL;
int internal_op = 0;
@@ -598,10 +600,11 @@ update_pw_info ( Slapi_PBlock *pb , char *old_pw) {
internal_op = slapi_operation_is_flag_set(operation, SLAPI_OP_FLAG_INTERNAL);
cur_time = current_time();
+ slapi_pblock_get( pb, SLAPI_REQUESTOR_NDN, &bind_dn);
slapi_pblock_get( pb, SLAPI_TARGET_SDN, &sdn );
- dn = slapi_sdn_get_dn(sdn);
+ target_dn = slapi_sdn_get_dn(sdn);
- pwpolicy = new_passwdPolicy(pb, dn);
+ pwpolicy = new_passwdPolicy(pb, target_dn);
/* update passwordHistory */
if ( old_pw != NULL && pwpolicy->pw_history == 1 ) {
@@ -643,7 +646,8 @@ update_pw_info ( Slapi_PBlock *pb , char *old_pw) {
* we stuff the actual user who initiated the password change in pb_conn. We check
* for this special case to ensure we reset the expiration date properly. */
if ((internal_op && pwpolicy->pw_must_change && (!pb->pb_conn || slapi_dn_isroot(pb->pb_conn->c_dn))) ||
- (!internal_op && pwpolicy->pw_must_change && (pb->pb_requestor_isroot == 1))) {
+ (!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 ) {
Slapi_Entry *pse = NULL;
@@ -836,7 +840,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 ) {
@@ -1527,6 +1531,97 @@ 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 = NULL;
+ const Slapi_DN *sdn = pwp->pw_admin;
+ char **uniquemember_vals = NULL;
+ char **member_vals = NULL;
+ const char *binddn = slapi_sdn_get_dn(sdn);
+ int uniquemember_count = 0;
+ int member_count = 0;
+ int nentries = 0;
+ int count = 0;
+ int res;
+ int i;
+
+ if(binddn == NULL){
+ return;
+ }
+ pb = slapi_pblock_new();
+ /*
+ * Check if the DN exists and has "group" objectclasses
+ */
+ slapi_search_internal_set_pb(pb, binddn, 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.
@@ -1831,6 +1926,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);
@@ -1851,6 +1953,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);
return pwdpolicy;
@@ -1861,6 +1965,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..9bb5cc7 100644
--- a/ldap/servers/slapd/pw.h
+++ b/ldap/servers/slapd/pw.h
@@ -86,6 +86,7 @@ int pw_encodevals_ext( Slapi_PBlock *pb, const Slapi_DN *sdn, Slapi_Value **vals
int checkPrefix(char *cipher, char *schemaName, char **encrypt);
struct passwordpolicyarray *new_passwdPolicy ( Slapi_PBlock *pb, const char *dn );
void delete_passwdPolicy( struct passwordpolicyarray **pwpolicy);
+int pw_is_pwp_admin(Slapi_PBlock *pb, struct passwordpolicyarray *pwp);
/* function for checking the values of fine grained password policy attributes */
int check_pw_duration_value( const char *attr_name, char *value, long minval, long maxval, char *errorbuf );
diff --git a/ldap/servers/slapd/slap.h b/ldap/servers/slapd/slap.h
index ca30d2a..33cfeb4 100644
--- a/ldap/servers/slapd/slap.h
+++ b/ldap/servers/slapd/slap.h
@@ -2018,6 +2018,7 @@ typedef struct _slapdEntryPoints {
#define CONFIG_SASL_MAXBUFSIZE "nsslapd-sasl-max-buffer-size"
#define CONFIG_LISTEN_BACKLOG_SIZE "nsslapd-listen-backlog-size"
#define CONFIG_IGNORE_TIME_SKEW "nsslapd-ignore-time-skew"
+#define CONFIG_PW_ADMIN_DN_ATTRIBUTE "passwordAdminDN"
/* getenv alternative */
#define CONFIG_MALLOC_MXFAST "nsslapd-malloc-mxfast"
@@ -2081,6 +2082,8 @@ typedef struct passwordpolicyarray {
int pw_is_legacy;
int pw_track_update_time;
struct pw_scheme *pw_storagescheme;
+ Slapi_DN *pw_admin;
+ Slapi_DN **pw_admin_user;
} passwdPolicy;
typedef struct _slapdFrontendConfig {
diff --git a/ldap/servers/slapd/slapi-plugin.h b/ldap/servers/slapd/slapi-plugin.h
index 9e85dc0..c13a1a8 100644
--- a/ldap/servers/slapd/slapi-plugin.h
+++ b/ldap/servers/slapd/slapi-plugin.h
@@ -1618,6 +1618,38 @@ int slapi_entry_attr_delete( Slapi_Entry *e, const char *type );
* 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 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);
--
1.8.1.4