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@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.
389-commits@lists.fedoraproject.org