>From 062ba89c51585db2b1758ea595e7c9c9dc8956f4 Mon Sep 17 00:00:00 2001 From: Nathan Kinder Date: Mon, 27 Jun 2011 10:39:51 -0700 Subject: [PATCH] Split automember regex rules into separate entries This splits the automember regex rule out into entries that are separate from the automember definition config entries. This makes the config more readible. The internals of the plug-in still work the same. --- ldap/schema/10automember-plugin.ldif | 21 ++- ldap/servers/plugins/automember/automember.c | 385 ++++++++++++++------------ ldap/servers/plugins/automember/automember.h | 8 +- 3 files changed, 230 insertions(+), 184 deletions(-) diff --git a/ldap/schema/10automember-plugin.ldif b/ldap/schema/10automember-plugin.ldif index 3428f07..d70b2dd 100644 --- a/ldap/schema/10automember-plugin.ldif +++ b/ldap/schema/10automember-plugin.ldif @@ -96,11 +96,28 @@ attributeTypes: ( 2.16.840.1.113730.3.1.2103 NAME 'autoMemberDisabled' # ################################################################################ # +attributeTypes: ( 2.16.840.1.113730.3.1.2105 NAME 'autoMemberTargetGroup' + DESC 'Auto Membership target group' + SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 + SINGLE-VALUE + X-ORIGIN '389 Directory Server' ) +# +################################################################################ +# objectClasses: ( 2.16.840.1.113730.3.2.322 NAME 'autoMemberDefinition' DESC 'Auto Membership Config Definition Entry' SUP top STRUCTURAL MUST ( cn $ autoMemberScope $ autoMemberFilter $ autoMemberGroupingAttr ) - MAY ( autoMemberExclusiveRegex $ autoMemberInclusiveRegex $ autoMemberDefaultGroup - $ autoMemberDisabled ) + MAY ( autoMemberDefaultGroup $ autoMemberDisabled ) + X-ORIGIN '389 Directory Server' ) +# +################################################################################ +# +objectClasses: ( 2.16.840.1.113730.3.2.323 NAME 'autoMemberRegexRule' + DESC 'Auto Membership Regex Rule Entry' + SUP top + STRUCTURAL + MUST ( cn $ autoMemberTargetGroup ) + MAY ( autoMemberExclusiveRegex $ autoMemberInclusiveRegex $ description ) X-ORIGIN '389 Directory Server' ) diff --git a/ldap/servers/plugins/automember/automember.c b/ldap/servers/plugins/automember/automember.c index 5edb696..af5dfba 100644 --- a/ldap/servers/plugins/automember/automember.c +++ b/ldap/servers/plugins/automember/automember.c @@ -98,6 +98,7 @@ static void automember_set_config_area(Slapi_DN *sdn); static int automember_dn_is_config(char *dn); static int automember_oktodo(Slapi_PBlock *pb); static int automember_isrepl(Slapi_PBlock *pb); +static void automember_parse_regex_entry(struct configEntry *config, Slapi_Entry *e); static struct automemberRegexRule *automember_parse_regex_rule(char *rule_string); static void automember_free_regex_rule(struct automemberRegexRule *rule); static int automember_parse_grouping_attr(char *value, char **grouping_attr, @@ -418,7 +419,7 @@ automember_load_config() "beneath \"%s\".\n", slapi_sdn_get_ndn(automember_get_config_area())); slapi_search_internal_set_pb(search_pb, slapi_sdn_get_ndn(automember_get_config_area()), - LDAP_SCOPE_SUBTREE, "objectclass=*", + LDAP_SCOPE_SUBTREE, AUTOMEMBER_DEFINITION_FILTER, NULL, 0, NULL, NULL, automember_get_plugin_id(), 0); } else { /* Find the config entries beneath our plugin entry. */ @@ -427,7 +428,7 @@ automember_load_config() "beneath \"%s\".\n", slapi_sdn_get_ndn(automember_get_plugin_sdn())); slapi_search_internal_set_pb(search_pb, slapi_sdn_get_ndn(automember_get_plugin_sdn()), - LDAP_SCOPE_SUBTREE, "objectclass=*", + LDAP_SCOPE_SUBTREE, AUTOMEMBER_DEFINITION_FILTER, NULL, 0, NULL, NULL, automember_get_plugin_id(), 0); } @@ -488,6 +489,11 @@ automember_parse_config_entry(Slapi_Entry * e, int apply) struct configEntry *entry = NULL; struct configEntry *config_entry; PRCList *list; + Slapi_PBlock *search_pb = NULL; + Slapi_Entry **rule_entries = NULL; + char *filter_str = NULL; + Slapi_Filter *filter = NULL; + int result; int entry_added = 0; int i = 0; int ret = 0; @@ -503,6 +509,13 @@ automember_parse_config_entry(Slapi_Entry * e, int apply) goto bail; } + /* If this entry is not an automember config definition entry, just bail. */ + filter_str = slapi_ch_strdup(AUTOMEMBER_DEFINITION_FILTER); + filter = slapi_str2filter(filter_str); + if (slapi_filter_test_simple(e, filter) != 0) { + goto bail; + } + /* If marked as disabled, just bail. */ value = slapi_entry_attr_get_charptr(e, AUTOMEMBER_DISABLED_TYPE); if (value) { @@ -569,105 +582,6 @@ automember_parse_config_entry(Slapi_Entry * e, int apply) goto bail; } - /* Load exclusive regex rules */ - values = slapi_entry_attr_get_charray(e, AUTOMEMBER_EXC_REGEX_TYPE); - if (values) { - struct automemberRegexRule *rule = NULL; - - /* Create a list to hold our regex rules */ - entry->exclusive_rules = (struct automemberRegexRule *)slapi_ch_calloc(1, sizeof(struct automemberRegexRule)); - PR_INIT_CLIST((PRCList *)entry->exclusive_rules); - - /* Parse each regex rule and add to the list */ - for (i = 0; values && values[i]; ++i) { - rule = automember_parse_regex_rule(values[i]); - if (rule) { - if (!PR_CLIST_IS_EMPTY((PRCList *)entry->exclusive_rules)) { - list = PR_LIST_HEAD((PRCList *)entry->exclusive_rules); - while (list != (PRCList *)entry->exclusive_rules) { - struct automemberRegexRule *curr_rule = (struct automemberRegexRule *)list; - /* Order rules by target group DN */ - if (slapi_sdn_compare(rule->target_group_dn, curr_rule->target_group_dn) < 0) { - PR_INSERT_BEFORE(&(rule->list), list); - break; - } - - list = PR_NEXT_LINK(list); - - /* If we hit the end of the list, add to the tail. */ - if ((PRCList *)entry->exclusive_rules == list) { - PR_INSERT_BEFORE(&(rule->list), list); - break; - } - } - } else { - /* Add to head of list */ - PR_INSERT_LINK(&(rule->list), (PRCList *)entry->exclusive_rules); - } - } else { - slapi_log_error(SLAPI_LOG_FATAL, AUTOMEMBER_PLUGIN_SUBSYSTEM, - "automember_parse_config_entry: Invalid exclusive " - "regex rule in config entry \"%s\" (rule = \"%s\").\n", - entry->dn, values[i]); - ret = -1; - } - } - slapi_ch_array_free(values); - values = NULL; - - /* Bail if we had a bad regex rule */ - if (ret == -1) { - goto bail; - } - } - - /* Load inclusive regex rules */ - values = slapi_entry_attr_get_charray(e, AUTOMEMBER_INC_REGEX_TYPE); - if (values) { - struct automemberRegexRule *rule = NULL; - - /* Create a list to hold our regex rules */ - entry->inclusive_rules = (struct automemberRegexRule *)slapi_ch_calloc(1, sizeof(struct automemberRegexRule)); - PR_INIT_CLIST((PRCList *)entry->inclusive_rules); - - /* Parse each regex rule and add to the list */ - for (i = 0; values && values[i]; ++i) { - rule = automember_parse_regex_rule(values[i]); - if (rule) { - if (!PR_CLIST_IS_EMPTY((PRCList *)entry->inclusive_rules)) { - list = PR_LIST_HEAD((PRCList *)entry->inclusive_rules); - while (list != (PRCList *)entry->inclusive_rules) { - struct automemberRegexRule *curr_rule = (struct automemberRegexRule *)list; - /* Order rules by target group DN */ - if (slapi_sdn_compare(rule->target_group_dn, curr_rule->target_group_dn) < 0) { - PR_INSERT_BEFORE(&(rule->list), list); - break; - } - - list = PR_NEXT_LINK(list); - - /* If we hit the end of the list, add to the tail. */ - if ((PRCList *)entry->inclusive_rules == list) { - PR_INSERT_BEFORE(&(rule->list), list); - break; - } - } - } else { - /* Add to head of list */ - PR_INSERT_LINK(&(rule->list), (PRCList *)entry->inclusive_rules); - } - } else { - slapi_log_error(SLAPI_LOG_FATAL, AUTOMEMBER_PLUGIN_SUBSYSTEM, - "automember_parse_config_entry: Invalid inclusive " - "regex rule in config entry \"%s\" (rule = \"%s\").\n", - entry->dn, values[i]); - ret = -1; - } - } - slapi_ch_array_free(values); - values = NULL; - } - /* Load the default groups */ values = slapi_entry_attr_get_charray(e, AUTOMEMBER_DEFAULT_GROUP_TYPE); if (values) { @@ -702,6 +616,35 @@ automember_parse_config_entry(Slapi_Entry * e, int apply) goto bail; } + /* Find all child regex rule entries */ + search_pb = slapi_pblock_new(); + slapi_search_internal_set_pb(search_pb, entry->dn, LDAP_SCOPE_SUBTREE, + AUTOMEMBER_REGEX_RULE_FILTER, NULL, 0, NULL, + NULL, automember_get_plugin_id(), 0); + slapi_search_internal_pb(search_pb); + slapi_pblock_get(search_pb, SLAPI_PLUGIN_INTOP_RESULT, &result); + + if (LDAP_SUCCESS != result) { + slapi_log_error(SLAPI_LOG_FATAL, AUTOMEMBER_PLUGIN_SUBSYSTEM, + "automember_parse_config_entry: Error searching " + "for child rule entries for config \"%s\" (err=%d).", + entry->dn, result); + ret = -1; + goto bail; + } + + slapi_pblock_get(search_pb, SLAPI_PLUGIN_INTOP_SEARCH_ENTRIES, + &rule_entries); + + /* Go through each child rule entry and parse it. */ + for (i = 0; rule_entries && (rule_entries[i] != NULL); i++) { + slapi_log_error(SLAPI_LOG_PLUGIN, AUTOMEMBER_PLUGIN_SUBSYSTEM, + "automember_parse_config_entry: parsing regex rule entry " + "\"%s\".\n", slapi_entry_get_dn(rule_entries[i])); + automember_parse_regex_entry(entry, rule_entries[i]); + } + + /* If we were only called to validate config, we can * just bail out before applying the config changes */ if (apply == 0) { @@ -761,6 +704,11 @@ automember_parse_config_entry(Slapi_Entry * e, int apply) ret = 0; } + slapi_ch_free_string(&filter_str); + slapi_filter_free(filter, 1); + slapi_free_search_results_internal(search_pb); + slapi_pblock_destroy(search_pb); + slapi_log_error(SLAPI_LOG_TRACE, AUTOMEMBER_PLUGIN_SUBSYSTEM, "<-- automember_parse_config_entry\n"); @@ -988,110 +936,193 @@ automember_isrepl(Slapi_PBlock *pb) } /* - * automember_parse_regex_rule() + * automember_parse_regex_entry() * - * Parses a regex rule and returns a regex rule struct. The caller - * will need to free this struct when it is finished with it. If - * there is a problem parsing the regex rule, an error will be - * logged and NULL will be returned. + * Parses a rule entry and adds the regex rules to the + * passed in config struct. Invalid regex rules will + * be skipped and logged at the fatal log level. */ -static struct automemberRegexRule * -automember_parse_regex_rule(char *rule_string) +static void +automember_parse_regex_entry(struct configEntry *config, Slapi_Entry *e) { - struct automemberRegexRule *rule = NULL; - Slapi_DN *target_group_dn = NULL; - char *desc = NULL; - char *attr = NULL; - Slapi_Regex *regex = NULL; - const char *recomp_result = NULL; - char *dn_string = NULL; - char *p = NULL; - char *p2 = NULL; + char *target_group = NULL; + char **values = NULL; + PRCList *list; + int i = 0; - /* A rule is in the form "target:desc:attr=regex" */ - /* Find the target group DN. */ - if ((p = strchr(rule_string, ':')) == NULL) { - slapi_log_error(SLAPI_LOG_FATAL, AUTOMEMBER_PLUGIN_SUBSYSTEM, - "automember_parse_regex_rule: Unable to parse " - "regex rule (missing first ':' delimeter).\n"); - goto bail; - } + slapi_log_error(SLAPI_LOG_TRACE, AUTOMEMBER_PLUGIN_SUBSYSTEM, + "--> automember_parse_regex_entry\n"); - /* Ensure the target group DN is not empty. */ - if (p == rule_string) { + /* Make sure the target group was specified. */ + target_group = slapi_entry_attr_get_charptr(e, AUTOMEMBER_TARGET_GROUP_TYPE); + if (!target_group) { slapi_log_error(SLAPI_LOG_FATAL, AUTOMEMBER_PLUGIN_SUBSYSTEM, - "automember_parse_regex_rule: Unable to parse " - " regex rule (missing target group DN).\n"); + "automember_parse_regex_entry: The %s config " + "setting is required for rule entry \"%s\".\n", + AUTOMEMBER_TARGET_GROUP_TYPE, slapi_entry_get_ndn(e)); goto bail; } - if ((dn_string = strndup(rule_string, p - rule_string)) == NULL) { + /* Ensure that the target group DN is valid. */ + if (slapi_dn_syntax_check(NULL, target_group, 1) != 0) { slapi_log_error(SLAPI_LOG_FATAL, AUTOMEMBER_PLUGIN_SUBSYSTEM, - "automember_parse_regex_rule: Error allocating " - "memory.\n"); + "automember_parse_regex_entry: invalid target group DN " + "in rule \"%s\" (dn=\"%s\").\n", slapi_entry_get_ndn(e), + target_group); goto bail; } - /* Ensure that the DN is valid. */ - if (slapi_dn_syntax_check(NULL, dn_string, 1) != 0) { - slapi_log_error(SLAPI_LOG_FATAL, AUTOMEMBER_PLUGIN_SUBSYSTEM, - "automember_parse_regex_rule: Unable to parse " - " regex rule (invalid target group DN).\n"); - slapi_cn_free_string(&dn_string); - goto bail; - } + /* Load inclusive rules */ + values = slapi_entry_attr_get_charray(e, AUTOMEMBER_INC_REGEX_TYPE); + if (values) { + struct automemberRegexRule *rule = NULL; - /* Create a Slapi_DN. */ - target_group_dn = slapi_sdn_new_dn_passin(dn_string); + /* If we haven't loaded any inclusive rules for + * this config definition yet, create a new list. */ + if (config->inclusive_rules == NULL) { + /* Create a list to hold our regex rules */ + config->inclusive_rules = (struct automemberRegexRule *)slapi_ch_calloc(1, sizeof(struct automemberRegexRule)); + PR_INIT_CLIST((PRCList *)config->inclusive_rules); + } - /* Find the description. */ - p++; - if (*p == '\0') { - slapi_log_error(SLAPI_LOG_FATAL, AUTOMEMBER_PLUGIN_SUBSYSTEM, - "automember_parse_regex_rule: Unable to parse " - "regex rule (missing description).\n"); - goto bail; - } + for (i = 0; values && values[i]; ++i) { + rule = automember_parse_regex_rule(values[i]); - p2 = p; - if ((p = strchr(p2, ':')) == NULL) { - slapi_log_error(SLAPI_LOG_FATAL, AUTOMEMBER_PLUGIN_SUBSYSTEM, - "automember_parse_regex_rule: Unable to parse " - "regex rule (missing second ':' delimeter).\n"); - goto bail; + if (rule) { + /* Fill in the target group. */ + rule->target_group_dn = slapi_sdn_new_dn_byval(target_group); + + if (!PR_CLIST_IS_EMPTY((PRCList *)config->inclusive_rules)) { + list = PR_LIST_HEAD((PRCList *)config->inclusive_rules); + while (list != (PRCList *)config->inclusive_rules) { + struct automemberRegexRule *curr_rule = (struct automemberRegexRule *)list; + /* Order rules by target group DN */ + if (slapi_sdn_compare(rule->target_group_dn, curr_rule->target_group_dn) < 0) { + PR_INSERT_BEFORE(&(rule->list), list); + break; + } + + list = PR_NEXT_LINK(list); + + /* If we hit the end of the list, add to the tail. */ + if ((PRCList *)config->inclusive_rules == list) { + PR_INSERT_BEFORE(&(rule->list), list); + break; + } + } + } else { + /* Add to head of list */ + PR_INSERT_LINK(&(rule->list), (PRCList *)config->inclusive_rules); + } + } else { + slapi_log_error(SLAPI_LOG_FATAL, AUTOMEMBER_PLUGIN_SUBSYSTEM, + "automember_parse_regex_entry: Skipping invalid inclusive " + "regex rule in rule entry \"%s\" (rule = \"%s\").\n", + slapi_entry_get_ndn(e), values[i]); + } + } + + slapi_ch_array_free(values); + values = NULL; } - /* We allow an empty description. */ - if (p == p2) { - desc = slapi_ch_strdup(""); - } else { - if ((desc = strndup(p2, p - p2)) == NULL) { - slapi_log_error(SLAPI_LOG_FATAL, AUTOMEMBER_PLUGIN_SUBSYSTEM, - "automember_parse_regex_rule: Unable to allocate " - "memory.\n"); - goto bail; + /* Load exclusive rules. */ + values = slapi_entry_attr_get_charray(e, AUTOMEMBER_EXC_REGEX_TYPE); + if (values) { + struct automemberRegexRule *rule = NULL; + + /* If we haven't loaded any exclusive rules for + * this config definition yet, create a new list. */ + if (config->exclusive_rules == NULL) { + /* Create a list to hold our regex rules */ + config->exclusive_rules = (struct automemberRegexRule *)slapi_ch_calloc(1, sizeof(struct automemberRegexRule)); + PR_INIT_CLIST((PRCList *)config->exclusive_rules); } + + for (i = 0; values && values[i]; ++i) { + rule = automember_parse_regex_rule(values[i]); + + if (rule) { + /* Fill in the target group. */ + rule->target_group_dn = slapi_sdn_new_dn_byval(target_group); + + if (!PR_CLIST_IS_EMPTY((PRCList *)config->exclusive_rules)) { + list = PR_LIST_HEAD((PRCList *)config->exclusive_rules); + while (list != (PRCList *)config->exclusive_rules) { + struct automemberRegexRule *curr_rule = (struct automemberRegexRule *)list; + /* Order rules by target group DN */ + if (slapi_sdn_compare(rule->target_group_dn, curr_rule->target_group_dn) < 0) { + PR_INSERT_BEFORE(&(rule->list), list); + break; + } + + list = PR_NEXT_LINK(list); + + /* If we hit the end of the list, add to the tail. */ + if ((PRCList *)config->exclusive_rules == list) { + PR_INSERT_BEFORE(&(rule->list), list); + break; + } + } + } else { + /* Add to head of list */ + PR_INSERT_LINK(&(rule->list), (PRCList *)config->exclusive_rules); + } + } else { + slapi_log_error(SLAPI_LOG_FATAL, AUTOMEMBER_PLUGIN_SUBSYSTEM, + "automember_parse_regex_entry: Skipping invalid exclusive " + "regex rule in rule entry \"%s\" (rule = \"%s\").\n", + slapi_entry_get_ndn(e), values[i]); + } + } + + slapi_ch_array_free(values); + values = NULL; } +bail: + slapi_ch_free_string(&target_group); + + slapi_log_error(SLAPI_LOG_TRACE, AUTOMEMBER_PLUGIN_SUBSYSTEM, + "<-- automember_parse_regex_entry\n"); +} + +/* + * automember_parse_regex_rule() + * + * Parses a regex rule and returns a regex rule struct. The caller + * will need to free this struct when it is finished with it. If + * there is a problem parsing the regex rule, an error will be + * logged and NULL will be returned. + */ +static struct automemberRegexRule * +automember_parse_regex_rule(char *rule_string) +{ + struct automemberRegexRule *rule = NULL; + char *attr = NULL; + Slapi_Regex *regex = NULL; + const char *recomp_result = NULL; + char *p = NULL; + char *p2 = NULL; + + /* A rule is in the form "attr=regex". */ /* Find the comparison attribute name. */ - p++; - if (*p == '\0') { + if ((p = strchr(rule_string, '=')) == NULL) { slapi_log_error(SLAPI_LOG_FATAL, AUTOMEMBER_PLUGIN_SUBSYSTEM, "automember_parse_regex_rule: Unable to parse " - "regex rule (missing comparison attribute).\n"); + "regex rule (missing '=' delimeter).\n"); goto bail; } - p2 = p; - if ((p = strchr(p2, '=')) == NULL) { + /* Make sure the attribute name is not empty. */ + if (p == rule_string) { slapi_log_error(SLAPI_LOG_FATAL, AUTOMEMBER_PLUGIN_SUBSYSTEM, "automember_parse_regex_rule: Unable to parse " - "regex rule (missing '=' delimeter).\n"); + " regex rule (missing comparison attribute).\n"); goto bail; } - - if ((attr = strndup(p2, p - p2)) == NULL) { + if ((attr = strndup(rule_string, p - rule_string)) == NULL) { slapi_log_error(SLAPI_LOG_FATAL, AUTOMEMBER_PLUGIN_SUBSYSTEM, "automember_parse_regex_rule: Unable to allocate " "memory.\n"); @@ -1130,8 +1161,6 @@ automember_parse_regex_rule(char *rule_string) * We hand off everything we have allocated. All of this will be free'd * when the rule struct itself is freed. */ rule = (struct automemberRegexRule *)slapi_ch_calloc(1, sizeof(struct automemberRegexRule)); - rule->target_group_dn = target_group_dn; - rule->desc = desc; rule->attr = attr; rule->regex_str = slapi_ch_strdup(p); rule->regex = regex; @@ -1139,8 +1168,6 @@ automember_parse_regex_rule(char *rule_string) bail: /* Cleanup if we didn't successfully create a rule. */ if (!rule) { - slapi_sdn_free(&target_group_dn); - slapi_ch_free_string(&desc); slapi_ch_free_string(&attr); slapi_re_free(regex); } @@ -1161,10 +1188,6 @@ automember_free_regex_rule(struct automemberRegexRule *rule) slapi_sdn_free(&(rule->target_group_dn)); } - if (rule->desc) { - slapi_ch_free_string(&(rule->desc)); - } - if (rule->attr) { slapi_ch_free_string(&(rule->attr)); } diff --git a/ldap/servers/plugins/automember/automember.h b/ldap/servers/plugins/automember/automember.h index 979de92..1fb29a5 100644 --- a/ldap/servers/plugins/automember/automember.h +++ b/ldap/servers/plugins/automember/automember.h @@ -71,6 +71,13 @@ #define AUTOMEMBER_DEFAULT_GROUP_TYPE "autoMemberDefaultGroup" #define AUTOMEMBER_GROUPING_ATTR_TYPE "autoMemberGroupingAttr" #define AUTOMEMBER_DISABLED_TYPE "autoMemberDisabled" +#define AUTOMEMBER_TARGET_GROUP_TYPE "autoMemberTargetGroup" + +/* + * Config loading filters + */ +#define AUTOMEMBER_DEFINITION_FILTER "objectclass=autoMemberDefinition" +#define AUTOMEMBER_REGEX_RULE_FILTER "objectclass=autoMemberRegexRule" /* * Helper defines @@ -80,7 +87,6 @@ struct automemberRegexRule { PRCList list; Slapi_DN *target_group_dn; - char *desc; char *attr; char *regex_str; Slapi_Regex *regex; -- 1.7.4