diff options
-rw-r--r-- | src/defaults.c | 2 | ||||
-rw-r--r-- | src/map.c | 261 |
2 files changed, 204 insertions, 59 deletions
diff --git a/src/defaults.c b/src/defaults.c index 29e0d8d..7d8349b 100644 --- a/src/defaults.c +++ b/src/defaults.c @@ -43,7 +43,7 @@ static struct configuration { } config[] = { {"passwd.byname", config_exact, FALSE, "(objectClass=posixAccount)", - {"%{uid}", NULL, NULL}, + {"%{uid}", "user.%{uid}", NULL}, "%{uid}:%regsub(\"userPassword\",\"^\\\\{CRYPT\\\\}(..*)\",\"%1\",\"*\"):%{uidNumber}:%{gidNumber}:%{cn!:}:%{homeDirectory:-/}:%{loginShell!:}"}, {"passwd.byuid", config_exact, FALSE, "(objectClass=posixAccount)", @@ -65,14 +65,17 @@ struct { * entry. */ char *id; /* Keys and value. */ - int n_keys; - char **key; + unsigned int n_keys; + char **keys; unsigned int *key_len; char *value; unsigned int value_len; + /* Key index for comparison. Used by the + * key_trees. */ + int key_index; } *entries; /* Search trees to speed up searches for entries. */ - void *key_tree; + void **key_trees; void *id_tree; /* Callback data supplied by the map writer. */ void *backend_data; @@ -106,23 +109,33 @@ t_compare_entry_by_id(const void *p1, const void *p2) return strcmp(e1->id, e2->id); } static int -t_compare_entry_by_key(const void *p1, const void *p2) +t_compare_entry_by_nth_key(const void *p1, const void *p2) { const struct map_entry *e1, *e2; unsigned int key_len; - int eq; + int eq, i; e1 = p1; e2 = p2; - if (e1->key_len == e2->key_len) { - return memcmp(e1->key, e2->key, e1->key_len); + /* Figure out which key index to use for comparison by pulling it out + * of the template (whichever one that is) -- real entries have + * key_index set to -1. */ + if (e1->key_index >= 0) { + i = e1->key_index; } else { - key_len = (e1->key_len < e2->key_len) ? - e1->key_len : e2->key_len; - eq = memcmp(e1->key, e2->key, key_len); + i = e2->key_index; + } + /* Same length -> straight comparison. */ + if (e1->key_len[i] == e2->key_len[i]) { + return memcmp(e1->keys[i], e2->keys[i], e1->key_len[i]); + } else { + /* Compare the common length. */ + key_len = (e1->key_len[i] < e2->key_len[i]) ? + e1->key_len[i] : e2->key_len[i]; + eq = memcmp(e1->keys[i], e2->keys[i], key_len); if (eq != 0) { return eq; } else { - return (e1->key_len < e2->key_len) ? -1 : 1; + return (e1->key_len[i] < e2->key_len[i]) ? -1 : 1; } } } @@ -167,13 +180,21 @@ map_data_find_map_entry(struct plugin_state *state, { struct map_entry **entry, entry_template; void **p; - if (map == NULL) { + unsigned int i; + if ((map == NULL) || (map->entries == NULL)) { return NULL; } - entry_template.key = (char *) key; - entry_template.key_len = key_len; - entry = tfind(&entry_template, &map->key_tree, t_compare_entry_by_key); - return entry ? *entry : NULL; + for (i = 0; i < map->entries->n_keys; i++) { + entry_template.keys = ((char **) &key) - i; + entry_template.key_len = (&key_len) - i; + entry_template.key_index = i; + entry = tfind(&entry_template, &map->key_trees[i], + t_compare_entry_by_nth_key); + if (entry != NULL) { + return *entry; + } + } + return NULL; } static struct map_entry * @@ -214,7 +235,8 @@ map_data_foreach_entry(struct plugin_state *state, void *cbdata), void *cbdata) { - int i, j, k; + int i, j; + unsigned int k; struct domain *domain; struct map *map; struct map_entry *entry; @@ -232,7 +254,7 @@ map_data_foreach_entry(struct plugin_state *state, if (!(*fn)(domain->name, map->name, map->secure, - entry->key[k], + entry->keys[k], entry->key_len[k], entry->value, entry->value_len, @@ -398,7 +420,7 @@ bool_t map_match_id(struct plugin_state *state, const char *domain_name, const char *map_name, bool_t *secure, - const char *in_id, + const char *in_id, int in_key_index, unsigned int *key_len, char **key, unsigned int *value_len, char **value, const char **id) @@ -413,9 +435,15 @@ map_match_id(struct plugin_state *state, if (entry == NULL) { return FALSE; } + if (entry->n_keys < 1) { + return FALSE; + } + if (in_key_index >= entry->n_keys) { + return FALSE; + } *secure = map->secure; - *key_len = entry->key_len; - *key = entry->key; + *key_len = entry->key_len[in_key_index]; + *key = entry->keys[in_key_index]; *value_len = entry->value_len; *value = entry->value; *id = entry->id; @@ -430,7 +458,7 @@ map_first(struct plugin_state *state, bool_t *secure, unsigned int *first_key_len, char **first_key, unsigned int *first_value_len, char **first_value, - const char **first_id) + const char **first_id, int *first_key_index) { struct map *map; struct map_entry *entry; @@ -443,11 +471,12 @@ map_first(struct plugin_state *state, return FALSE; } *secure = map->secure; - *first_key_len = entry->key_len; - *first_key = entry->key; + *first_key_len = entry->key_len[0]; + *first_key = entry->keys[0]; *first_value_len = entry->value_len; *first_value = entry->value; *first_id = entry->id; + *first_key_index = 0; return TRUE; } @@ -463,6 +492,7 @@ map_next(struct plugin_state *state, { struct map *map; struct map_entry *entry; + unsigned int i; map = map_data_find_map(state, domain_name, map_name); if (map == NULL) { return FALSE; @@ -472,36 +502,63 @@ map_next(struct plugin_state *state, return FALSE; } *secure = map->secure; - *next_key_len = entry->next->key_len; - *next_key = entry->next->key; - *next_value_len = entry->next->value_len; - *next_value = entry->next->value; + for (i = 0; i < entry->n_keys; i++) { + if ((prev_len == entry->key_len[i]) && + (memcmp(prev, entry->keys[i], prev_len) == 0)) { + break; + } + } + if (i + 1 < entry->n_keys) { + *next_key_len = entry->key_len[i + 1]; + *next_key = entry->keys[i + 1]; + *next_value_len = entry->value_len; + *next_value = entry->value; + } else { + *next_key_len = entry->next->key_len[0]; + *next_key = entry->next->keys[0]; + *next_value_len = entry->next->value_len; + *next_value = entry->next->value; + } return TRUE; } bool_t map_next_id(struct plugin_state *state, const char *domain_name, const char *map_name, bool_t *secure, - const char *prev_id, + const char *prev_id, int prev_key_index, unsigned int *next_key_len, char **next_key, unsigned int *next_value_len, char **next_value, - const char **next_id) + const char **next_id, int *next_key_index) { struct map *map; struct map_entry *entry; + unsigned int key_index; map = map_data_find_map(state, domain_name, map_name); if (map == NULL) { return FALSE; } entry = map_data_find_map_entry_id(state, map, prev_id); - if ((entry == NULL) || (entry->next == NULL)) { + if (entry == NULL) { return FALSE; } *secure = map->secure; - *next_key_len = entry->next->key_len; - *next_key = entry->next->key; - *next_value_len = entry->next->value_len; - *next_value = entry->next->value; - *next_id = entry->next->id; + if (prev_key_index + 1 < (int) entry->n_keys) { + *next_key_len = entry->key_len[prev_key_index + 1]; + *next_key = entry->keys[prev_key_index + 1]; + *next_value_len = entry->value_len; + *next_value = entry->value; + *next_id = entry->id; + *next_key_index = prev_key_index + 1; + } else { + if (entry->next == NULL) { + return FALSE; + } + *next_key_len = entry->next->key_len[0]; + *next_key = entry->next->keys[0]; + *next_value_len = entry->next->value_len; + *next_value = entry->next->value; + *next_id = entry->next->id; + *next_key_index = 0; + } return TRUE; } @@ -523,21 +580,31 @@ static void map_data_clear_map_map(struct plugin_state *state, struct map *map) { struct map_entry *entry, *next; + unsigned int i; /* Clear the entries list. */ if (map != NULL) { for (entry = map->entries; entry != NULL; entry = next) { + /* Remove every key for this entry from the applicable + * key trees, and then the ID tree. */ + for (i = 0; i < entry->n_keys; i++) { + entry->key_index = i; + tdelete(entry, &map->key_trees[i], + t_compare_entry_by_nth_key); + entry->key_index = -1; + } tdelete(entry, &map->id_tree, t_compare_entry_by_id); - tdelete(entry, &map->key_tree, t_compare_entry_by_key); next = entry->next; free(entry->id); entry->key_len = 0; - free(entry->key); + for (i = 0; i < entry->n_keys; i++) { + free(entry->keys[i]); + } + free(entry->keys); entry->value_len = 0; free(entry->value); free(entry); } map->entries = NULL; - map->key_tree = NULL; map->id_tree = NULL; } } @@ -615,6 +682,7 @@ void map_data_set_map(struct plugin_state *state, const char *domain_name, const char *map_name, + unsigned int n_keys, bool_t secure, void *backend_data, void (*free_backend_data)(void *backend_data)) @@ -671,13 +739,18 @@ map_data_set_map(struct plugin_state *state, map = &maps[domain->n_maps]; memset(map, 0, sizeof(*map)); map->name = strdup(map_name); + map->key_trees = malloc(n_keys * sizeof(void *)); map->secure = secure; map->backend_data = backend_data; map->free_backend_data = free_backend_data; - if (map->name != NULL) { + map->last_changed = time(NULL); + if ((map->name != NULL) && (map->key_trees != NULL)) { /* Copy in existing data. */ memcpy(maps, domain->maps, sizeof(*map) * domain->n_maps); + /* Clear the key tree set. */ + memset(map->key_trees, 0, + n_keys * sizeof(void *)); /* Switcheroo. */ free(domain->maps); domain->maps = maps; @@ -697,6 +770,7 @@ map_data_set_map(struct plugin_state *state, } map->backend_data = backend_data; map->free_backend_data = free_backend_data; + map->last_changed = time(NULL); } } @@ -707,6 +781,7 @@ map_data_unset_map_entry(struct plugin_state *state, struct map_entry *entry) { struct map_entry *prev, *next; + unsigned int i; if ((map != NULL) && (entry != NULL)) { prev = entry->prev; next = entry->next; @@ -719,10 +794,22 @@ map_data_unset_map_entry(struct plugin_state *state, if (map->entries == entry) { map->entries = next; } - tdelete(entry, &map->key_tree, t_compare_entry_by_key); + /* Remove every key for this entry from the applicable key + * trees, and then the ID tree. */ + for (i = 0; i < entry->n_keys; i++) { + entry->key_index = i; + tdelete(entry, &map->key_trees[i], + t_compare_entry_by_nth_key); + entry->key_index = -1; + } tdelete(entry, &map->id_tree, t_compare_entry_by_id); free(entry->id); - free(entry->key); + /* Free the keys list. */ + for (i = 0; i < entry->n_keys; i++) { + free(entry->keys[i]); + } + free(entry->keys); + /* The value and the key itself. */ free(entry->value); free(entry); } @@ -749,17 +836,16 @@ map_data_set_entry(struct plugin_state *state, const char *domain_name, const char *map_name, const char *id, - unsigned int key_len, - char *key, + unsigned int n_keys, + unsigned int *key_lens, + char **keys, unsigned int value_len, char *value) { struct map *map; struct map_entry *entry; + unsigned int i, key_len; map = map_data_find_map(state, domain_name, map_name); - if (key_len == (unsigned int) -1) { - key_len = strlen(key); - } if (value_len == (unsigned int) -1) { value_len = strlen(value); } @@ -767,26 +853,81 @@ map_data_set_entry(struct plugin_state *state, entry = map_data_find_map_entry_id(state, map, id); if (entry != NULL) { /* There's already an entry with this ID, so let's - * replace its key and value. */ - tdelete(entry, &map->key_tree, t_compare_entry_by_key); + * replace its keys and value. */ + for (i = 0; i < entry->n_keys; i++) { + entry->key_index = i; + tdelete(entry, &map->key_trees[i], + t_compare_entry_by_nth_key); + entry->key_index = -1; + } tdelete(entry, &map->id_tree, t_compare_entry_by_id); - free(entry->key); - entry->key = xmemdup(key, key_len); - entry->key_len = key_len; + /* Free the keys. */ + for (i = 0; i < entry->n_keys; i++) { + free(entry->keys[i]); + } + free(entry->keys); + /* Create a new keys list. */ + entry->keys = malloc((n_keys + 1) * sizeof(char *)); + if (entry->keys != NULL) { + for (i = 0; i < n_keys; i++) { + if (key_lens != NULL) { + key_len = key_lens[i]; + } else { + key_len = -1; + } + if (key_len == (unsigned int) -1) { + key_len = strlen(keys[i]); + } + entry->keys[i] = xmemdup(keys[i], + key_len); + entry->key_len[i] = key_len; + } + entry->keys[i] = NULL; + } + entry->n_keys = n_keys; + /* Replace the value and ID. */ free(entry->value); + free(entry->id); entry->value = xmemdup(value, value_len); entry->value_len = value_len; - free(entry->id); entry->id = strdup(id); - tsearch(entry, &map->key_tree, t_compare_entry_by_key); + /* Add the ID to the tree and all of the keys to their + * trees. */ tsearch(entry, &map->id_tree, t_compare_entry_by_id); + for (i = 0; i < n_keys; i++) { + entry->key_index = i; + tsearch(entry, &map->key_trees[i], + t_compare_entry_by_nth_key); + entry->key_index = -1; + } } else { /* There's no entry with this ID, so create one. */ entry = malloc(sizeof(*entry)); if (entry != NULL) { memset(entry, 0, sizeof(*entry)); - entry->key = xmemdup(key, key_len); - entry->key_len = key_len; + entry->keys = malloc((n_keys + 1) * + sizeof(char *)); + entry->key_len = malloc(n_keys * sizeof(int)); + if ((entry->keys != NULL) && + (entry->key_len != NULL)) { + for (i = 0; i < n_keys; i++) { + if (key_lens != NULL) { + key_len = key_lens[i]; + } else { + key_len = -1; + } + if (key_len == (unsigned int) -1) { + key_len = + strlen(keys[i]); + } + entry->keys[i] = xmemdup(keys[i], + key_len); + entry->key_len[i] = key_len; + } + entry->keys[i] = NULL; + } + entry->n_keys = n_keys; + entry->key_index = -1; entry->value = xmemdup(value, value_len); entry->value_len = value_len; entry->id = strdup(id); @@ -795,8 +936,12 @@ map_data_set_entry(struct plugin_state *state, map->entries->prev = entry; } map->entries = entry; - tsearch(entry, &map->key_tree, - t_compare_entry_by_key); + for (i = 0; i < entry->n_keys; i++) { + entry->key_index = i; + tsearch(entry, &map->key_trees[i], + t_compare_entry_by_nth_key); + entry->key_index = -1; + } tsearch(entry, &map->id_tree, t_compare_entry_by_id); } else { |