summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/defaults.c2
-rw-r--r--src/map.c261
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)",
diff --git a/src/map.c b/src/map.c
index 3faaaf9..810a400 100644
--- a/src/map.c
+++ b/src/map.c
@@ -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 {