aboutsummaryrefslogtreecommitdiffstats
path: root/src/db.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/db.c')
-rw-r--r--src/db.c322
1 files changed, 177 insertions, 145 deletions
diff --git a/src/db.c b/src/db.c
index f77b76f..111a4f4 100644
--- a/src/db.c
+++ b/src/db.c
@@ -15,10 +15,6 @@
* limitations under the License.
*/
-
-#define _GNU_SOURCE
-
-
#include <assert.h>
#include <stdlib.h>
#include <stdint.h>
@@ -26,9 +22,11 @@
#include <stdalign.h>
#include <stdio.h>
#include <string.h>
+#include <ctype.h>
#include <time.h>
#include <errno.h>
+#include "data.h"
#include "fbuf.h"
#include "db.h"
@@ -52,29 +50,33 @@
#define time2exph(x) time2expl((x) + 15)
/**
- * A rule is a set of 32 bits integers
+ * A query is a set of 32 bits integers
*/
-struct rule
-{
- union {
- uint32_t ids[5];
- struct {
- /** client string id */
- uint32_t client;
+struct key_ids {
+ /** client string id */
+ uint32_t client;
- /** session string id */
- uint32_t session;
+ /** session string id */
+ uint32_t session;
- /** user string id */
- uint32_t user;
+ /** user string id */
+ uint32_t user;
- /** permission string id */
- uint32_t permission;
+ /** permission string id */
+ uint32_t permission;
+};
+typedef struct key_ids key_ids_t;
+
+/**
+ * A rule is a set of 32 bits integers
+ */
+struct rule
+{
+ /** key part */
+ key_ids_t key;
- /** value string id */
- uint32_t value;
- };
- };
+ /** value string id */
+ uint32_t value;
/** expiration */
uint32_t expire;
@@ -98,10 +100,16 @@ static fbuf_t fnames;
/** the file for the rules */
static fbuf_t frules;
-/** identification of names version 1 (uuidgen --sha1 -n @url -N urn:AGL:cynara:db:names:1) */
+/** identification of names version 1
+ * $> uuidgen --sha1 -n @url -N urn:AGL:cynara:db:names:1
+ * $> uuid -v 5 urn:AGL:cynara:db:names:1
+ */
static const char uuid_names_v1[] = "e9481f9e-b2f4-5716-90cf-c286d98d1868\n--\n";
-/** identification of rules version 1 (uuidgen --sha1 -n @url -N urn:AGL:cynara:db:rules:1) */
+/** identification of rules version 1
+ * $> uuidgen --sha1 -n @url -N urn:AGL:cynara:db:rules:1
+ * $> uuid -v 5 ns:URL urn:AGL:cynara:db:rules:1
+ */
static const char uuid_rules_v1[] = "8f7a5b21-48b1-57af-96c9-d5d7192be370\n--\n";
/** length of the identification */
@@ -357,10 +365,10 @@ add_rule(
return rc;
rules = (rule_t*)(frules.buffer + uuidlen);
rule = &rules[rules_count++];
- rule->client = client;
- rule->session = session;
- rule->user = user;
- rule->permission = permission;
+ rule->key.client = client;
+ rule->key.session = session;
+ rule->key.user = user;
+ rule->key.permission = permission;
rule->value = value;
rule->expire = expire;
frules.used = c;
@@ -388,18 +396,23 @@ open_identify(
) {
int rc;
char *file, *backup;
+ size_t sd, sn;
- rc = asprintf(&file, "%s/%s", directory, name);
- if (rc < 0)
+ sd = strlen(directory);
+ sn = strlen(name);
+ file = malloc(((sd + sn) << 1) + 5);
+ if (!file)
rc = -ENOMEM;
else {
- rc = asprintf(&backup, "%s~", file);
- if (rc < 0)
- rc = -ENOMEM;
- else {
- rc = fbuf_open_identify(fb, file, backup, id, idlen);
- free(backup);
- }
+
+ memcpy(file, directory, sd);
+ file[sd] = '/';
+ memcpy(&file[sd + 1], name, sn + 1);
+ backup = &file[sd + sn + 2];
+ memcpy(backup, file, sd + sn + 1);
+ backup[sd + sn + 1] = '~';
+ backup[sd + sn + 2] = 0;
+ rc = fbuf_open_identify(fb, file, backup, id, idlen);
free(file);
}
return rc;
@@ -502,49 +515,62 @@ db_recover(
init_rules();
return 0;
error:
- fprintf(stderr, "db recovering impossible: %m");
+ fprintf(stderr, "db recovery impossible: %m");
exit(5);
return rc;
}
+static int get_query_ids(
+ const data_key_t *in,
+ key_ids_t *out,
+ bool create
+) {
+ int rc;
+
+ rc = db_get_name_index(&out->client, in->client, create);
+ if (rc) goto end;
+ rc = db_get_name_index(&out->session, in->session, create);
+ if (rc) goto end;
+ rc = db_get_name_index(&out->user, in->user, create);
+ if (rc) goto end;
+ rc = db_get_name_index(&out->permission, in->permission, create);
+end:
+ return rc;
+}
+
/** enumerate */
void
db_for_all(
void *closure,
void (*callback)(
void *closure,
- const char *client,
- const char *session,
- const char *user,
- const char *permission,
- const char *value,
- time_t expire),
- const char *client,
- const char *session,
- const char *user,
- const char *permission
+ const data_key_t *key,
+ const data_value_t *value),
+ const data_key_t *key
) {
uint32_t ucli, uusr, uses, i;
- bool anyperm;
+ int anyperm;
+ data_key_t k;
+ data_value_t v;
- if (db_get_name_index(&ucli, client, false)
- || db_get_name_index(&uses, session, false)
- || db_get_name_index(&uusr, user, false))
+ if (db_get_name_index(&ucli, key->client, false)
+ || db_get_name_index(&uses, key->session, false)
+ || db_get_name_index(&uusr, key->user, false))
return; /* nothing to do! */
- anyperm = is_any(permission);
+ anyperm = is_any(key->permission);
for (i = 0; i < rules_count; i++) {
- if ((ucli == ANYIDX || ucli == rules[i].client)
- && (uses == ANYIDX || uses == rules[i].session)
- && (uusr == ANYIDX || uusr == rules[i].user)
- && (anyperm || !strcasecmp(permission, name_at(rules[i].permission)))) {
- callback(closure,
- name_at(rules[i].client),
- name_at(rules[i].session),
- name_at(rules[i].user),
- name_at(rules[i].permission),
- name_at(rules[i].value),
- exp2time(rules[i].expire));
+ if ((ucli == ANYIDX || ucli == rules[i].key.client)
+ && (uses == ANYIDX || uses == rules[i].key.session)
+ && (uusr == ANYIDX || uusr == rules[i].key.user)
+ && (anyperm || !strcasecmp(key->permission, name_at(rules[i].key.permission)))) {
+ k.client = name_at(rules[i].key.client);
+ k.session = name_at(rules[i].key.session);
+ k.user = name_at(rules[i].key.user);
+ k.permission = name_at(rules[i].key.permission);
+ v.value = name_at(rules[i].value);
+ v.expire = exp2time(rules[i].expire);
+ callback(closure, &k, &v);
}
}
}
@@ -552,26 +578,23 @@ db_for_all(
/** drop rules */
int
db_drop(
- const char *client,
- const char *session,
- const char *user,
- const char *permission
+ const data_key_t *key
) {
uint32_t ucli, uses, uusr, i;
bool anyperm;
- if (db_get_name_index(&ucli, client, false)
- || db_get_name_index(&uses, session, false)
- || db_get_name_index(&uusr, user, false))
+ if (db_get_name_index(&ucli, key->client, false)
+ || db_get_name_index(&uses, key->session, false)
+ || db_get_name_index(&uusr, key->user, false))
return 0; /* nothing to do! */
- anyperm = is_any(permission);
+ anyperm = is_any(key->permission);
i = 0;
while (i < rules_count) {
- if ((ucli == ANYIDX || ucli == rules[i].client)
- && (uses == ANYIDX || uses == rules[i].session)
- && (uusr == ANYIDX || uusr == rules[i].user)
- && (anyperm || !strcasecmp(permission, name_at(rules[i].permission))))
+ if ((ucli == ANYIDX || ucli == rules[i].key.client)
+ && (uses == ANYIDX || uses == rules[i].key.session)
+ && (uusr == ANYIDX || uusr == rules[i].key.user)
+ && (anyperm || !strcasecmp(key->permission, name_at(rules[i].key.permission))))
drop_at(i);
else
i++;
@@ -582,54 +605,47 @@ db_drop(
/** set rules */
int
db_set(
- const char *client,
- const char *session,
- const char *user,
- const char *permission,
- const char *value,
- time_t expire
+ const data_key_t *key,
+ const data_value_t *value
) {
int rc;
uint32_t ucli, uses, uusr, uperm, uval, i;
+ const char *perm;
- /* normalize */
- client = is_any_or_wide(client) ? WIDESTR : client;
- session = is_any_or_wide(session) ? WIDESTR : session;
- user = is_any_or_wide(user) ? WIDESTR : user;
- permission = is_any_or_wide(permission) ? WIDESTR : permission;
+ perm = is_any_or_wide(key->permission) ? WIDESTR : key->permission;
/* get/create strings */
- rc = db_get_name_index(&ucli, client, true);
+ rc = db_get_name_index(&ucli, is_any_or_wide(key->client) ? WIDESTR : key->client, true);
if (rc)
goto error;
- rc = db_get_name_index(&uses, session, true);
+ rc = db_get_name_index(&uses, is_any_or_wide(key->session) ? WIDESTR : key->session, true);
if (rc)
goto error;
- rc = db_get_name_index(&uusr, user, true);
+ rc = db_get_name_index(&uusr, is_any_or_wide(key->user) ? WIDESTR : key->user, true);
if (rc)
goto error;
- rc = db_get_name_index(&uval, value, true);
+ rc = db_get_name_index(&uval, value->value, true);
if (rc)
goto error;
/* search the existing rule */
for (i = 0; i < rules_count; i++) {
- if (ucli == rules[i].client
- && uses == rules[i].session
- && uusr == rules[i].user
- && !strcasecmp(permission, name_at(rules[i].permission))) {
+ if (ucli == rules[i].key.client
+ && uses == rules[i].key.session
+ && uusr == rules[i].key.user
+ && !strcasecmp(perm, name_at(rules[i].key.permission))) {
/* found */
- set_at(i, uval, time2exph(expire));
+ set_at(i, uval, time2exph(value->expire));
return 0;
}
}
/* create the rule */
- rc = db_get_name_index(&uperm, permission, true);
+ rc = db_get_name_index(&uperm, perm, true);
if (rc)
goto error;
- rc = add_rule(ucli, uses, uusr, uperm, uval, time2exph(expire));
+ rc = add_rule(ucli, uses, uusr, uperm, uval, time2exph(value->expire));
return 0;
error:
@@ -639,29 +655,21 @@ error:
/** check rules */
int
db_test(
- const char *client,
- const char *session,
- const char *user,
- const char *permission,
- const char **value,
- time_t *expire
+ const data_key_t *key,
+ data_value_t *value
) {
+ const char *perm;
uint32_t ucli, uses, uusr, i, score, sc, now;
rule_t *rule, *found;
- /* check */
- client = is_any_or_wide(client) ? WIDESTR : client;
- session = is_any_or_wide(session) ? WIDESTR : session;
- user = is_any_or_wide(user) ? WIDESTR : user;
- permission = is_any_or_wide(permission) ? WIDESTR : permission;
-
- /* search the items */
- if (db_get_name_index(&ucli, client, false))
+ /* normalize the items */
+ if (db_get_name_index(&ucli, is_any_or_wide(key->client) ? WIDESTR : key->client, false))
ucli = NOIDX;
- if (db_get_name_index(&uses, session, false))
+ if (db_get_name_index(&uses, is_any_or_wide(key->session) ? WIDESTR : key->session, false))
uses = NOIDX;
- if (db_get_name_index(&uusr, user, false))
+ if (db_get_name_index(&uusr, is_any_or_wide(key->user) ? WIDESTR : key->user, false))
uusr = NOIDX;
+ perm = is_any_or_wide(key->permission) ? WIDESTR : key->permission;
/* search the existing rule */
now = time2expl(time(NULL));
@@ -670,14 +678,14 @@ db_test(
for (i = 0 ; i < rules_count ; i++) {
rule = &rules[i];
if ((!rule->expire || rule->expire >= now)
- && (ucli == rule->client || WIDEIDX == rule->client)
- && (uses == rule->session || WIDEIDX == rule->session)
- && (uusr == rule->user || WIDEIDX == rule->user)
- && (WIDEIDX == rule->permission
- || !strcasecmp(permission, name_at(rule->permission)))) {
+ && (ucli == rule->key.client || WIDEIDX == rule->key.client)
+ && (uses == rule->key.session || WIDEIDX == rule->key.session)
+ && (uusr == rule->key.user || WIDEIDX == rule->key.user)
+ && (WIDEIDX == rule->key.permission
+ || !strcasecmp(perm, name_at(rule->key.permission)))) {
/* found */
- sc = 1 + (rule->client != WIDEIDX) + (rule->session != WIDEIDX)
- + (rule->user != WIDEIDX) + (rule->permission != WIDEIDX);
+ sc = 1 + (rule->key.client != WIDEIDX) + (rule->key.session != WIDEIDX)
+ + (rule->key.user != WIDEIDX) + (rule->key.permission != WIDEIDX);
if (sc > score) {
score = sc;
found = rule;
@@ -685,12 +693,13 @@ db_test(
}
}
if (!found) {
- *value = NULL;
- *expire = 0;
+ value->value = NULL;
+ value->expire = 0;
return 0;
}
- *value = name_at(found->value);
- *expire = exp2time(found->expire);
+ value->value = name_at(found->value);
+ value->expire = exp2time(found->expire);
+
return 1;
}
@@ -714,25 +723,46 @@ cmpidxs(
}
static
+uint32_t*
+gc_after_ptr(
+ gc_t *gc,
+ uint32_t *idx
+) {
+ uint32_t *p = bsearch(idx, gc->befores, names_count, sizeof *gc->befores, cmpidxs);
+ assert(p != NULL);
+ return &gc->afters[p - gc->befores];
+}
+
+static
void
gc_mark(
gc_t *gc,
+ uint32_t *idx
+) {
+ *gc_after_ptr(gc, idx) = 1;
+}
+
+static
+void
+gc_mark_id(
+ gc_t *gc,
uint32_t idx
) {
- uint32_t *p = bsearch(&idx, gc->befores, names_count, sizeof *gc->befores, cmpidxs);
- assert(p != NULL);
- gc->afters[p - gc->befores] = 1;
+ gc_mark(gc, &idx);
}
static
-uint32_t
+int
gc_after(
gc_t *gc,
- uint32_t idx
+ uint32_t *idx
) {
- uint32_t *p = bsearch(&idx, gc->befores, names_count, sizeof *gc->befores, cmpidxs);
- assert(p != NULL);
- return gc->afters[p - gc->befores];
+ uint32_t idbef, idaft;
+
+ idbef = *idx;
+ idaft = *gc_after_ptr(gc, idx);
+ *idx = idaft;
+ return (int)(idbef - idaft);
}
static
@@ -749,9 +779,9 @@ gc_init(
qsort(gc->befores, names_count, sizeof *gc->befores, cmpidxs);
gc->afters = &gc->befores[names_count];
memset(gc->afters, 0, names_count * sizeof *gc->afters);
-
- gc_mark(gc, ANYIDX);
- gc_mark(gc, WIDEIDX);
+
+ gc_mark_id(gc, ANYIDX);
+ gc_mark_id(gc, WIDEIDX);
return 0;
}
@@ -807,7 +837,7 @@ int
db_cleanup(
) {
int rc, chg;
- uint32_t idbef, idaft, i, j, now;
+ uint32_t i, now;
gc_t gc;
rule_t *rule;
@@ -826,8 +856,11 @@ db_cleanup(
if (rule->expire && now >= rule->expire)
drop_at(i);
else {
- for (j = 0 ; j < 5 ; j++)
- gc_mark(&gc, rule->ids[j]);
+ gc_mark(&gc, &rule->key.client);
+ gc_mark(&gc, &rule->key.session);
+ gc_mark(&gc, &rule->key.user);
+ gc_mark(&gc, &rule->key.permission);
+ gc_mark(&gc, &rule->value);
i++;
}
}
@@ -838,12 +871,11 @@ db_cleanup(
i = 0;
while (i < rules_count) {
rule = &rules[i];
- for (chg = j = 0 ; j < 5 ; j++) {
- idbef = rule->ids[j];
- idaft = gc_after(&gc, idbef);
- rule->ids[j] = idaft;
- chg += idbef != idaft;
- }
+ chg = gc_after(&gc, &rule->key.client);
+ chg |= gc_after(&gc, &rule->key.session);
+ chg |= gc_after(&gc, &rule->key.user);
+ chg |= gc_after(&gc, &rule->key.permission);
+ chg |= gc_after(&gc, &rule->value);
if (chg)
touch_at(i);
i++;