From 096d8958a81ee57d3486d8260430cbfab81a0bbc Mon Sep 17 00:00:00 2001 From: Mark Reynolds Date: Mar 05 2014 20:55:31 +0000 Subject: 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 Reviewed by: nhosoi(Thanks!) --- 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 8a5df7e..9064e41 100644 --- a/ldap/servers/slapd/entry.c +++ b/ldap/servers/slapd/entry.c @@ -2607,46 +2607,70 @@ 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 * slapi_entry_attr_get_charptr( const Slapi_Entry* e, const char *type) { - char *p= NULL; - Slapi_Attr* attr; + char *p= NULL; + Slapi_Attr* attr; + slapi_entry_attr_find(e, type, &attr); 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 9db10c5..014be1c 100644 --- a/ldap/servers/slapd/modify.c +++ b/ldap/servers/slapd/modify.c @@ -1224,11 +1224,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); } @@ -1240,16 +1238,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 1d1db1e..20df245 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 7e53db0..1fb782b 100644 --- a/ldap/servers/slapd/proto-slap.h +++ b/ldap/servers/slapd/proto-slap.h @@ -348,6 +348,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 27215c4..3a1e4a1 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 2465500..2c8b2a6 100644 --- a/ldap/servers/slapd/slap.h +++ b/ldap/servers/slapd/slap.h @@ -2015,6 +2015,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" @@ -2078,6 +2079,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 521de6a..f0dd555 100644 --- a/ldap/servers/slapd/slapi-plugin.h +++ b/ldap/servers/slapd/slapi-plugin.h @@ -1622,6 +1622,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 char ** 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);