# initial database for cynara
-System * * * 1
-User * * * 1
+System * * * yes always
+User * * * yes always
+++ /dev/null
-cynarad
-test-cynara
-cynara.names
-cynara.rules
-.*.sw*
INSTALL(FILES rcyn-client.h DESTINATION ${CMAKE_INSTALL_FULL_INCLUDEDIR}/cynara)
###########################################
-# build and install test-cynara
+# build and install cynadm
###########################################
-ADD_EXECUTABLE(test-cynara test-lib-compat.c)
-TARGET_LINK_LIBRARIES(test-cynara cynara)
-INSTALL(TARGETS test-cynara
+ADD_EXECUTABLE(cynadm main-cynadm.c)
+TARGET_LINK_LIBRARIES(cynadm cynara)
+INSTALL(TARGETS cynadm
+ RUNTIME DESTINATION ${CMAKE_INSTALL_FULL_BINDIR})
+
+###########################################
+# build and install test-old-cynara
+###########################################
+ADD_EXECUTABLE(test-old-cynara main-test-old-cynara.c)
+TARGET_LINK_LIBRARIES(test-old-cynara cynara)
+INSTALL(TARGETS test-old-cynara
RUNTIME DESTINATION ${CMAKE_INSTALL_FULL_BINDIR})
###########################################
+++ /dev/null
-.PHONY: all clean
-
-srcssrv = db.c fbuf.c queue.c cyn.c prot.c rcyn-protocol.c socket.c
-
-srcscli = prot.c rcyn-client.c rcyn-protocol.c lib-compat.c cache.c socket.c
-
-incssrv = db.h fbuf.h cyn.h prot.h rcyn-protocol.h socket.h
-
-incscli = prot.h rcyn-client.h rcyn-protocol.h cache.h socket.h
-
-defs = -DRCYN_DEFAULT_CHECK_SOCKET_SPEC=\"tcp:localhost:5555\" \
- -DRCYN_DEFAULT_ADMIN_SOCKET_SPEC=\"tcp:localhost:4444\"
-
-bins = cynarad test-cynara
-
-all: $(bins)
-
-clean:
- rm cynara.names cynara.rules $(bins) 2>/dev/null || true
-
-cynarad: rcyn-server.c $(srcssrv) $(incssrv)
- gcc -o cynarad -g -Wall rcyn-server.c $(srcssrv) $(defs)
-
-test-cynara: test-lib-compat.c $(srcscli) $(incscli)
- gcc -o test-cynara -I../include -g -Wall test-lib-compat.c $(srcscli) $(defs)
-
#include <stdlib.h>
#include <stdint.h>
+#include <stdalign.h>
#include <string.h>
#include <errno.h>
+#include <time.h>
#include <ctype.h>
#include "cache.h"
/**
- * The cache structure is a blob of memory ('content')
- * of 'count' bytes of only 'used' bytes.
- * That blob containts at sequence of records of variable length
- * Each records holds the following values in that given order:
- * - length: 2 bytes unsigned integer LSB first, MSB second
- * - hit count: 1 byte unsigned integer
- * - value: 1 byte unsigned integer
+ * A cache item header
+ *
+ * Each item is followed by values in that given order:
* - client: zero terminated string
* - session: zero terminated string
* - user: zero terminated string
* - permission: zero terminated string
* -
*/
+struct item
+{
+ /** expiration */
+ time_t expire;
+
+ /** length of the cache entry including this header */
+ uint16_t length;
+
+ /** hit indicator */
+ uint8_t hit;
+
+ /** value to store */
+ int8_t value;
+
+ /** fake ending character */
+ char strings;
+};
+typedef struct item item_t;
+
+/**
+ * The cache structure is a blob of memory ('content')
+ * of 'count' bytes of only 'used' bytes.
+ * That blob containts at sequence of records of variable length
+ */
struct cache
{
uint32_t used;
};
static
-uint32_t
-lenat(
+inline
+item_t *
+itemat(
cache_t *cache,
uint32_t pos
) {
- return ((uint32_t)cache->content[pos]) | (((uint32_t)cache->content[pos + 1]) << 8);
+ return (item_t*)(&cache->content[pos]);
}
static
) {
uint32_t e, l;
- l = lenat(cache, pos);
+ l = itemat(cache, pos)->length;
e = pos + l;
cache->used -= l;
if (cache->used > e)
cache_t *cache
) {
uint32_t found = 0, iter = 0;
- uint8_t hmin = 255, hint;
+ uint8_t hmin = 255, hit;
+ item_t *item;
while (iter < cache->used) {
- hint = cache->content[iter + 2];
- if (hint < hmin)
+ item = itemat(cache, iter);
+ hit = item->hit;
+ if (hit < hmin)
found = iter;
- iter += lenat(cache, iter);
+ iter += item->length;
}
if (found < cache->used)
drop_at(cache, found);
void
hit(
cache_t *cache,
- uint32_t pos
+ item_t *target
) {
uint32_t iter = 0;
- uint8_t hint;
+ uint8_t hit;
+ item_t *item;
while (iter < cache->used) {
- if (iter == pos)
- hint = 255;
+ item = itemat(cache, iter);
+ if (item == target)
+ hit = 255;
else {
- hint = cache->content[iter + 2];
- if (hint)
- hint--;
+ hit = item->hit;
+ if (hit)
+ hit--;
}
- cache->content[iter + 2] = hint;
- iter += lenat(cache, iter);
+ item->hit = hit;
+ iter += item->length;
}
}
return 0;
}
-
static
int
match(
}
static
-uint32_t
+item_t*
search(
cache_t *cache,
const char *client,
const char *user,
const char *permission
) {
- char *txt;
- uint32_t iter = 0;
+ time_t now;
+ item_t *item, *found;
+ uint32_t iter;
+ found = NULL;
+ now = time(NULL);
+ iter = 0;
while (iter < cache->used) {
- txt = (char*)&cache->content[iter + 4];
- if (match(txt, client, session, user, permission))
- return iter;
- iter += lenat(cache, iter);
+ item = itemat(cache, iter);
+ if (item->expire && item->expire < now)
+ drop_at(cache, iter);
+ else {
+ if (match(&item->strings, client, session, user, permission))
+ found = item;
+ iter += item->length;
+ }
}
- return iter;
+ return found;
}
int
const char *session,
const char *user,
const char *permission,
- int value
+ int value,
+ time_t expire
) {
- uint32_t pos;
- size_t size, scli, sses, susr, sper;
+ uint16_t length;
+ item_t *item;
+ size_t size;
- if (cache == NULL || value < 0 || value > 255)
+ if (cache == NULL || value < -128 || value > 127)
return -EINVAL;
- pos = search(cache, client, session, user, permission);
- if (pos < cache->used)
- cache->content[pos + 3] = (uint8_t)value;
- else {
- scli = strlen(client);
- sses = strlen(session);
- susr = strlen(user);
- sper = strlen(permission);
- size = scli + sses + susr + sper + 8;
+ item = search(cache, client, session, user, permission);
+ if (item == NULL) {
+ /* create an item */
+ size = (size_t)(&((item_t*)0)->strings)
+ + strlen(client)
+ + strlen(session)
+ + strlen(user)
+ + strlen(permission);
+ size = (size + alignof(item_t) - 1) & ~(alignof(item_t) - 1);
if (size > 65535)
return -EINVAL;
- if (size > cache->count)
+ length = (uint16_t)size;
+ if (length > cache->count)
return -ENOMEM;
- while(cache->used + (uint32_t)size > cache->count)
+ while(cache->used + length > cache->count)
drop_lre(cache);
- pos = cache->used;
- cache->content[pos + 0] = (uint8_t)(size & 255);
- cache->content[pos + 1] = (uint8_t)((size >> 8) & 255);
- cache->content[pos + 2] = (uint8_t)255;
- cache->content[pos + 3] = (uint8_t)value;
- stpcpy(1 + stpcpy(1 + stpcpy(1 + stpcpy((char*)&cache->content[pos + 4], client), session), user), permission);
+ item = itemat(cache, cache->used);
+ item->length = length;
+ stpcpy(1 + stpcpy(1 + stpcpy(1 + stpcpy(&item->strings, client), session), user), permission);
cache->used += (uint32_t)size;
}
+ item->expire = expire;
+ item->hit = 255;
+ item->value = (int8_t)value;
return 0;
}
const char *user,
const char *permission
) {
- uint32_t pos;
+ item_t *item;
- pos = search(cache, client, session, user, permission);
- if (pos < cache->used) {
- hit(cache, pos);
- return (int)cache->content[pos + 3];
+ item = search(cache, client, session, user, permission);
+ if (item) {
+ hit(cache, item);
+ return (int)item->value;
}
return -ENOENT;
}
const char *session,
const char *user,
const char *permission,
- int value
+ int value,
+ time_t expire
);
extern
int rc;
struct callback *c;
+ db_cleanup(0);
rc = db_sync();
for (c = observers; c ; c = c->next)
c->callback(c->closure);
const char *session,
const char *user,
const char *permission,
- uint32_t value
+ const char *value,
+ time_t expire
) {
if (!lock)
return -EPERM;
- return queue_set(client, session, user, permission, value);
+ return queue_set(client, session, user, permission, value, expire);
}
int
const char *session,
const char *user,
const char *permission,
- uint32_t value),
+ const char *value,
+ time_t expire),
const char *client,
const char *session,
const char *user,
const char *session,
const char *user,
const char *permission,
- uint32_t *value
+ const char **value,
+ time_t *expire
) {
int rc;
- rc = db_test(client, session, user, permission, value);
+ rc = db_test(client, session, user, permission, value, expire);
if (rc <= 0)
*value = DEFAULT;
else
int
cyn_check_async(
- void (*check_cb)(void *closure, uint32_t value),
+ void (*check_cb)(void *closure, const char *value, time_t expire),
void *closure,
const char *client,
const char *session,
const char *user,
const char *permission
) {
- uint32_t value;
+ const char *value;
+ time_t expire;
- cyn_test(client, session, user, permission, &value);
- if (value == ALLOW || value == DENY) {
- check_cb(closure, value);
+ cyn_test(client, session, user, permission, &value, &expire);
+ if (!strcmp(value, ALLOW) || !strcmp(value, DENY)) {
+ check_cb(closure, value, expire);
return 0;
}
/* TODO: try to resolve AGENT?? */
- check_cb(closure, value);
+ check_cb(closure, value, expire);
return 0;
}
#pragma once
-#define DENY 0
-#define ALLOW 1
-#define ASK 2
+#define DENY "no"
+#define ALLOW "yes"
+#define ASK "ask"
#define DEFAULT DENY
/** enter critical recoverable section */
const char *session,
const char *user,
const char *permission,
- uint32_t value
+ const char *value,
+ time_t expire
);
extern
const char *session,
const char *user,
const char *permission,
- uint32_t *value
+ const char **value,
+ time_t *expire
);
extern
const char *session,
const char *user,
const char *permission,
- uint32_t value),
+ const char *value,
+ time_t expire),
const char *client,
const char *session,
const char *user,
extern
int
cyn_check_async(
- void (*check_cb)(void *closure, uint32_t value),
+ void (*check_cb)(void *closure, const char *value, time_t expire),
void *closure,
const char *client,
const char *session,
#include <stdalign.h>
#include <stdio.h>
#include <string.h>
+#include <time.h>
#include <errno.h>
#include "fbuf.h"
#include "db.h"
+#define NOEXPIRE 0
#define NOIDX 0
#define ANYIDX 40
#define WIDEIDX 42
#define WIDESTR "*"
-/**
- * A rule is a set of 4 integers
+/*
+ * for the first version, save enougth time up to 4149
+ * 4149 = 1970 + (4294967296 * 16) / (365 * 24 * 60 * 60)
+ *
+ * in the next version, time will be relative to a stored base
*/
-struct rule
-{
- uint32_t client, user, permission, value;
-};
-typedef struct rule rule_t;
+#define exp2time(x) (((time_t)(x)) << 4)
+#define time2expl(x) ((uint32_t)((x) >> 4))
+#define time2exph(x) time2expl((x) + 15)
/**
- * Sessions
+ * A rule is a set of 32 bits integers
*/
-struct session
+struct rule
{
- struct session *next, *prev;
- rule_t *rules;
- const char *name;
- uint32_t count;
+ union {
+ uint32_t ids[5];
+ struct {
+ /** client string id */
+ uint32_t client;
+
+ /** session string id */
+ uint32_t session;
+
+ /** user string id */
+ uint32_t user;
+
+ /** permission string id */
+ uint32_t permission;
+
+ /** value string id */
+ uint32_t value;
+ };
+ };
+
+ /** expiration */
+ uint32_t expire;
};
-typedef struct session session_t;
+typedef struct rule rule_t;
/*
* The cynara-agl database is made of 2 memory mapped files:
/** the name indexes sorted */
static uint32_t *names_sorted;
-/** the sessions */
-static session_t sessions = {
- .next = &sessions,
- .prev = &sessions,
- .name = WIDESTR
-};
+/** count of rules */
+static uint32_t rules_count;
+
+/** the rules */
+static rule_t *rules;
/** return the name of 'index' */
static
return is_any(text) || 0 == strcmp(text, WIDESTR);
}
-/** get in 'session' the session for 'name' and create it if 'needed' */
+/** set the 'value' to the rule at 'index' */
static
-int
-get_session(
- const char *name,
- bool needed,
- session_t **session
+void
+touch_at(
+ uint32_t index
) {
- session_t *s;
- size_t len;
-
- /* start on ANY sessions */
- s = &sessions;
- if (is_any_or_wide(name))
- goto found;
-
- /* look to other sessions */
- s = s->next;
- while(s != &sessions) {
- if (!strcmp(s->name, name))
- goto found;
- s = s->next;
- }
-
- /* not found */
- if (!needed) {
- errno = ENOENT;
- return -1;
- }
-
- /* check length */
- len = strnlen(name, MAX_NAME_LENGTH + 1);
- if (len > MAX_NAME_LENGTH) {
- errno = EINVAL;
- return -1;
- }
+ uint32_t pos;
- /* create it */
- s = malloc(sizeof * s + len + 1);
- if (s == NULL)
- return -1; /* out of memory */
-
- /* init new session */
- s->rules = NULL;
- s->count = 0;
- s->name = strcpy((char*)(s + 1), name);
- s->next = &sessions;
- s->prev = sessions.prev;
- sessions.prev = s;
- s->prev->next = s;
-found:
- *session = s;
- return 0;
+ pos = (uint32_t)(((void*)&rules[index]) - frules.buffer);
+ if (pos < frules.saved)
+ frules.saved = pos;
}
-/** for 'session' set the value the rule at 'index' */
+/** set the 'value' to the rule at 'index' */
static
void
-session_set_at(
- session_t *session,
+set_at(
uint32_t index,
- uint32_t value
+ uint32_t value,
+ uint32_t expire
) {
- uint32_t pos;
-
- assert(index < session->count);
- session->rules[index].value = value;
- if (session == &sessions) {
- pos = (uint32_t)(((void*)&session->rules[index]) - frules.buffer);
- if (pos < frules.saved)
- frules.saved = pos;
- }
+ assert(index < rules_count);
+ rules[index].value = value;
+ rules[index].expire = expire;
+ touch_at(index);
}
-/** drop of 'session' the rule at 'index' */
+/** drop the rule at 'index' */
static
void
-session_drop_at(
- session_t *session,
+drop_at(
uint32_t index
) {
uint32_t pos;
- assert(index < session->count);
- if (index < --session->count)
- session->rules[index] = session->rules[session->count];
- if (session == &sessions) {
- pos = (uint32_t)(((void*)&session->rules[index]) - frules.buffer);
- if (pos < frules.saved)
- frules.saved = pos;
- pos = (uint32_t)(((void*)&session->rules[session->count]) - frules.buffer);
- frules.used = pos;
- }
+ assert(index < rules_count);
+ if (index < --rules_count)
+ rules[index] = rules[rules_count];
+ pos = (uint32_t)(((void*)&rules[rules_count]) - frules.buffer);
+ frules.used = pos;
+ touch_at(index);
}
-/** add to 'session' the rule 'client' x 'user' x 'permission' x 'value' */
+/** add the rule 'client' x 'session' x 'user' x 'permission' x 'value' */
static
int
-session_add(
- session_t *session,
+add_rule(
uint32_t client,
+ uint32_t session,
uint32_t user,
uint32_t permission,
- uint32_t value
+ uint32_t value,
+ uint32_t expire
) {
int rc;
uint32_t c;
rule_t *rule;
- if (session == &sessions) {
- c = frules.used + (uint32_t)sizeof *rule;
- rc = fbuf_ensure_capacity(&frules, c);
- if (rc)
- return rc;
- frules.used = c;
- session->rules = (rule_t*)(frules.buffer + uuidlen);
- } else {
- c = session->count + 32 - (session->count & 31);
- rule = realloc(session->rules, c * sizeof *rule);
- if (rule == NULL)
- return -ENOMEM;
- session->rules = rule;
- }
- rule = &session->rules[session->count++];
+ c = frules.used + (uint32_t)sizeof *rule;
+ rc = fbuf_ensure_capacity(&frules, c);
+ if (rc)
+ 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->value = value;
+ rule->expire = expire;
+ frules.used = c;
return 0;
}
void
init_rules(
) {
- sessions.rules = (rule_t*)(frules.buffer + uuidlen);
- sessions.count = (frules.used - uuidlen) / sizeof *sessions.rules;
+ rules = (rule_t*)(frules.buffer + uuidlen);
+ rules_count = (frules.used - uuidlen) / sizeof *rules;
}
/** open a fbuf */
bool
db_is_empty(
) {
- return !sessions.count;
+ return !rules_count;
}
/** synchronize db on files */
const char *session,
const char *user,
const char *permission,
- uint32_t value),
+ const char *value,
+ time_t expire),
const char *client,
const char *session,
const char *user,
const char *permission
) {
- uint32_t ucli, uusr, i;
- bool anyperm, anysession;
- session_t *ses;
+ uint32_t ucli, uusr, uses, 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))
return; /* nothing to do! */
anyperm = is_any(permission);
- anysession = is_any(session);
- if (anysession)
- ses = &sessions;
- else {
- if (get_session(session, false, &ses))
- return; /* ignore if no session */
- }
- for(;;) {
- for (i = 0; i < ses->count; i++) {
- if ((ucli == ANYIDX || ucli == ses->rules[i].client)
- && (uusr == ANYIDX || uusr == ses->rules[i].user)
- && (anyperm || !strcasecmp(permission, name_at(ses->rules[i].permission)))) {
- callback(closure,
- name_at(ses->rules[i].client),
- ses->name,
- name_at(ses->rules[i].user),
- name_at(ses->rules[i].permission),
- ses->rules[i].value);
- }
+ 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 (!anysession)
- break;
- ses = ses->next;
- if (ses == &sessions)
- break;
}
}
const char *user,
const char *permission
) {
- uint32_t ucli, uusr, i;
- bool anyperm, anysession;
- session_t *ses;
+ 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))
return 0; /* nothing to do! */
anyperm = is_any(permission);
- anysession = is_any(session);
- if (anysession)
- ses = &sessions;
- else {
- if (get_session(session, false, &ses))
- return 0; /* ignore if no session */
- }
- for(;;) {
- i = 0;
- while (i < ses->count) {
- if ((ucli == ANYIDX || ucli == ses->rules[i].client)
- && (uusr == ANYIDX || uusr == ses->rules[i].user)
- && (anyperm || !strcasecmp(permission, name_at(ses->rules[i].permission))))
- session_drop_at(ses, i);
- else
- i++;
- }
- if (!anysession)
- break;
- ses = ses->next;
- if (ses == &sessions)
- break;
+ 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))))
+ drop_at(i);
+ else
+ i++;
}
return 0;
}
const char *session,
const char *user,
const char *permission,
- uint32_t value
+ const char *value,
+ time_t expire
) {
int rc;
- uint32_t ucli, uusr, uperm, i;
- session_t *ses;
+ uint32_t ucli, uses, uusr, uperm, uval, i;
/* normalize */
client = is_any_or_wide(client) ? WIDESTR : client;
user = is_any_or_wide(user) ? WIDESTR : user;
permission = is_any_or_wide(permission) ? WIDESTR : permission;
- /* get the session */
- rc = get_session(session, true, &ses);
- if (rc)
- goto error;
-
/* get/create strings */
rc = db_get_name_index(&ucli, client, true);
+ if (rc)
+ goto error;
+ rc = db_get_name_index(&uses, session, true);
if (rc)
goto error;
rc = db_get_name_index(&uusr, user, true);
+ if (rc)
+ goto error;
+ rc = db_get_name_index(&uval, value, true);
if (rc)
goto error;
/* search the existing rule */
- for (i = 0 ; i < ses->count ; i++) {
- if (ucli == ses->rules[i].client
- && uusr == ses->rules[i].user
- && !strcasecmp(permission, name_at(ses->rules[i].permission))) {
+ 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))) {
/* found */
- session_set_at(ses, i, value);
+ set_at(i, uval, time2exph(expire));
return 0;
}
}
if (rc)
goto error;
- rc = session_add(ses, ucli, uusr, uperm, value);
+ rc = add_rule(ucli, uses, uusr, uperm, uval, time2exph(expire));
return 0;
error:
const char *session,
const char *user,
const char *permission,
- uint32_t *value
+ const char **value,
+ time_t *expire
) {
- uint32_t ucli, uusr, i, val, score, sc;
- session_t *ses;
- rule_t *rule;
+ uint32_t ucli, uses, uusr, i, score, sc, now;
+ rule_t *rule, *found;
/* check */
client = is_any_or_wide(client) ? WIDESTR : client;
permission = is_any_or_wide(permission) ? WIDESTR : permission;
/* search the items */
- val = score = 0;
-#define NOIDX 0
if (db_get_name_index(&ucli, client, false))
ucli = NOIDX;
+ if (db_get_name_index(&uses, session, false))
+ uses = NOIDX;
if (db_get_name_index(&uusr, user, false))
uusr = NOIDX;
- /* get the session */
- if (get_session(session, false, &ses))
- ses = &sessions;
-
-retry:
/* search the existing rule */
- for (i = 0 ; i < ses->count ; i++) {
- rule = &ses->rules[i];
- if ((ucli == rule->client || WIDEIDX == rule->client)
+ now = time2expl(time(NULL));
+ found = NULL;
+ score = 0;
+ 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)))) {
/* found */
- sc = 1 + (rule->client != WIDEIDX)
+ sc = 1 + (rule->client != WIDEIDX) + (rule->session != WIDEIDX)
+ (rule->user != WIDEIDX) + (rule->permission != WIDEIDX);
if (sc > score) {
score = sc;
- val = rule->value;
+ found = rule;
}
}
}
- if (!score && ses != &sessions) {
- ses = &sessions;
- goto retry;
+ if (!found) {
+ *value = NULL;
+ *expire = 0;
+ return 0;
+ }
+ *value = name_at(found->value);
+ *expire = exp2time(found->expire);
+ return 1;
+}
+
+typedef struct gc gc_t;
+struct gc
+{
+ uint32_t *befores;
+ uint32_t *afters;
+};
+
+/** compare indexes. used by qsort and bsearch */
+static
+int
+cmpidxs(
+ const void *pa,
+ const void *pb
+) {
+ uint32_t a = *(const uint32_t*)pa;
+ uint32_t b = *(const uint32_t*)pb;
+ return a < b ? -1 : a != b;
+}
+
+static
+void
+gc_mark(
+ 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;
+}
+
+static
+uint32_t
+gc_after(
+ 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
+int
+gc_init(
+ gc_t *gc
+) {
+ gc->befores = malloc((sizeof *gc->befores + sizeof *gc->afters) * names_count);
+ if (gc->befores == NULL)
+ return -ENOMEM;
+
+ names_count = names_count;
+ memcpy(gc->befores, names_sorted, names_count * sizeof *gc->befores);
+ 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);
+ return 0;
+}
+
+static
+void
+gc_end(
+ gc_t *gc
+) {
+ free(gc->befores);
+}
+
+static
+int
+gc_pack(
+ gc_t *gc
+) {
+ uint32_t i, j, n, next, prev;
+ char *strings;
+
+ /* skip the unchanged initial part */
+ n = names_count;
+ i = 0;
+ while (i < n && gc->afters[i])
+ i++;
+
+ /* at end means no change */
+ if (i == n)
+ return 0;
+
+ /* pack the strings */
+ strings = fnames.buffer;
+ j = i;
+ memcpy(gc->afters, gc->befores, j * sizeof *gc->afters);
+ next = gc->befores[i++];
+ fnames.saved = next;
+ while (i < n) {
+ if (gc->afters[i]) {
+ gc->befores[j] = prev = gc->befores[i];
+ gc->afters[j++] = next;
+ while ((strings[next++] = strings[prev++]));
+ }
+ i++;
+ }
+ fnames.used = next;
+ names_count = j;
+ memcpy(names_sorted, gc->afters, j * sizeof *gc->afters);
+ qsort(names_sorted, j, sizeof *names_sorted, cmpnames);
+
+ return 1;
+}
+
+int
+db_cleanup(
+) {
+ int rc, chg;
+ uint32_t idbef, idaft, i, j, now;
+ gc_t gc;
+ rule_t *rule;
+
+ /* init garbage collector */
+ rc= gc_init(&gc);
+ if (rc < 0)
+ return rc;
+
+ /* default now */
+ now = time2expl(time(NULL));
+
+ /* remove expired entries and mark string ids of remaining ones */
+ i = 0;
+ while (i < rules_count) {
+ rule = &rules[i];
+ if (rule->expire && now >= rule->expire)
+ drop_at(i);
+ else {
+ for (j = 0 ; j < 5 ; j++)
+ gc_mark(&gc, rule->ids[j]);
+ i++;
+ }
+ }
+
+ /* pack the strings */
+ if (gc_pack(&gc)) {
+ /* replace the ids if changed */
+ 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;
+ }
+ if (chg)
+ touch_at(i);
+ i++;
+ }
}
- if (score)
- *value = val;
- return score > 0;
+ /* terminate */
+ gc_end(&gc);
+
+ return 0;
}
const char *session,
const char *user,
const char *permission,
- uint32_t value),
+ const char *value,
+ time_t expire),
const char *client,
const char *session,
const char *user,
const char *session,
const char *user,
const char *permission,
- uint32_t value
+ const char *value,
+ time_t expire
);
/** check rules */
const char *session,
const char *user,
const char *permission,
- uint32_t *value
+ const char **value,
+ time_t *expire
+);
+
+/** cleanup the base */
+int
+db_cleanup(
);
return rc;
}
-static int from_value(uint32_t value)
+static int from_value(const char *value)
{
- switch(value) {
- case 0: return CYNARA_ADMIN_DENY;
- case 1: return CYNARA_ADMIN_ALLOW;
- case 2: return CYNARA_ADMIN_ASK;
- }
- return (int)value;
+ if (!strcmp(value, "yes"))
+ return CYNARA_ADMIN_ALLOW;
+ if (!strcmp(value, "ask"))
+ return CYNARA_ADMIN_ASK;
+ return CYNARA_ADMIN_DENY;
}
-static uint32_t to_value(int value)
+static const char *to_value(int value)
{
switch(value) {
- case CYNARA_ADMIN_DENY: return 0;
- case CYNARA_ADMIN_NONE: return 0;
- case CYNARA_ADMIN_BUCKET: return 0;
- case CYNARA_ADMIN_ALLOW: return 1;
- case CYNARA_ADMIN_ASK: return 2;
+ case CYNARA_ADMIN_DENY:
+ case CYNARA_ADMIN_NONE:
+ case CYNARA_ADMIN_BUCKET: return "no";
+ case CYNARA_ADMIN_ALLOW: return "yes";
+ case CYNARA_ADMIN_ASK: return "ask";
}
- return (uint32_t)value;
+ return "?";
}
/************************************ ERROR ****************************************/
p->client, "*", p->user, p->privilege);
else if (p->result != CYNARA_ADMIN_BUCKET && p->result != CYNARA_ADMIN_NONE)
rc = rcyn_set((rcyn_t*)p_cynara_admin,
- p->client, "*", p->user, p->privilege, to_value(p->result));
+ p->client, "*", p->user, p->privilege, to_value(p->result), 0);
p = *++policies;
}
rc2 = rcyn_leave((rcyn_t*)p_cynara_admin, rc == 0);
const char *session,
const char *user,
const char *permission,
- uint32_t value
+ const char *value,
+ time_t expire
) {
*((int*)closure) = from_value(value);
}
const char *session,
const char *user,
const char *permission,
- uint32_t value
+ const char *value,
+ time_t expire
) {
struct list_data *data = closure;
struct cynara_admin_policy *pol;
--- /dev/null
+/*
+ * Copyright (C) 2018 "IoT.bzh"
+ * Author José Bollo <jose.bollo@iot.bzh>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdint.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <time.h>
+#include <signal.h>
+
+#include "rcyn-client.h"
+
+rcyn_t *rcyn;
+
+char buffer[4000];
+char *str[40];
+int nstr;
+
+static const int MIN = 60;
+static const int HOUR = 60*MIN;
+static const int DAY = 24*HOUR;
+static const int YEAR = 365*DAY;
+
+const char *client, *session, *user, *permission, *value;
+time_t expire;
+int txt2experr;
+
+time_t txt2exp(const char *txt)
+{
+ time_t r, x;
+
+ txt2experr = 0;
+ if (!strcmp(txt, "always"))
+ return 0;
+
+ r = time(NULL);
+ while(*txt) {
+ x = 0;
+ while('0' <= *txt && *txt <= '9')
+ x = 10 * x + (time_t)(*txt++ - '0');
+ switch(*txt) {
+ case 'y': r += x * YEAR; txt++; break;
+ case 'd': r += x *= DAY; txt++; break;
+ case 'h': r += x *= HOUR; txt++; break;
+ case 'm': r += x *= MIN; txt++; break;
+ case 's': txt++; /*@fallthrough@*/
+ case 0: r += x; break;
+ default: txt2experr = 1; return -1;
+ }
+ }
+ return r;
+}
+
+const char *exp2txt(time_t expire)
+{
+ static char buffer[200];
+ int n;
+
+ if (!expire)
+ return "always";
+ expire -= time(NULL);
+ n = 0;
+ if (expire >= YEAR) {
+ n += snprintf(&buffer[n], sizeof buffer - n, "%lldy",
+ (long long)(expire / YEAR));
+ expire = expire % YEAR;
+ }
+ if (expire >= DAY) {
+ n += snprintf(&buffer[n], sizeof buffer - n, "%lldd",
+ (long long)(expire / DAY));
+ expire = expire % DAY;
+ }
+ if (expire >= HOUR) {
+ n += snprintf(&buffer[n], sizeof buffer - n, "%lldh",
+ (long long)(expire / HOUR));
+ expire = expire % HOUR;
+ }
+ if (expire >= MIN) {
+ n += snprintf(&buffer[n], sizeof buffer - n, "%lldm",
+ (long long)(expire / MIN));
+ expire = expire % MIN;
+ }
+ if (expire) {
+ n += snprintf(&buffer[n], sizeof buffer - n, "%llds",
+ (long long)expire);
+ }
+ return buffer;
+}
+
+int plink(int ac, char **av, int *used, int maxi)
+{
+ int r = 0;
+
+ if (maxi < ac)
+ ac = maxi;
+ while (r < ac && strcmp(av[r], ";"))
+ r++;
+
+ *used = r + (r < ac);
+ return r;
+}
+
+int get_csupve(int ac, char **av, int *used, const char *def)
+{
+ int n = plink(ac, av, used, 7);
+
+ client = n > 1 ? av[1] : def;
+ session = n > 2 ? av[2] : def;
+ user = n > 3 ? av[3] : def;
+ permission = n > 4 ? av[4] : def;
+ value = n > 5 ? av[5] : "no";
+ expire = n > 6 ? txt2exp(av[6]) : 0;
+
+ return client && session && user && permission && value && !txt2experr ? 0 : -EINVAL;
+}
+
+int get_csup(int ac, char **av, int *used, const char *def)
+{
+ int n = plink(ac, av, used, 5);
+
+ client = n > 1 ? av[1] : def;
+ session = n > 2 ? av[2] : def;
+ user = n > 3 ? av[3] : def;
+ permission = n > 4 ? av[4] : def;
+
+ return client && session && user && permission ? 0 : -EINVAL;
+}
+
+void listcb(void *closure, const char *client, const char *session,
+ const char *user, const char *permission,
+ const char *value, time_t expire)
+{
+ int *p = closure;
+ const char *e = exp2txt(expire);
+ fprintf(stdout, "%s\t%s\t%s\t%s\t%s\t%s\n", client, session, user, permission, value, e);
+ (*p)++;
+}
+
+int do_list(int ac, char **av)
+{
+ int count, uc, rc;
+
+ rc = get_csup(ac, av, &uc, "#");
+ if (rc == 0) {
+ count = 0;
+ rc = rcyn_get(rcyn, client, session, user, permission, listcb, &count);
+ if (rc < 0)
+ fprintf(stderr, "error %s\n", strerror(-rc));
+ else
+ fprintf(stdout, "%d entries found\n", count);
+ }
+ return uc;
+}
+
+int do_set(int ac, char **av)
+{
+ int uc, rc;
+
+ rc = get_csupve(ac, av, &uc, "*");
+ if (rc == 0)
+ rc = rcyn_enter(rcyn);
+ if (rc == 0) {
+ rc = rcyn_set(rcyn, client, session, user, permission, value, expire);
+ rcyn_leave(rcyn, !rc);
+ }
+ if (rc < 0)
+ fprintf(stderr, "error %s\n", strerror(-rc));
+ return uc;
+}
+
+int do_drop(int ac, char **av)
+{
+ int uc, rc;
+
+ rc = get_csup(ac, av, &uc, "#");
+ if (rc == 0)
+ rc = rcyn_enter(rcyn);
+ if (rc == 0) {
+ rc = rcyn_drop(rcyn, client, session, user, permission);
+ rcyn_leave(rcyn, !rc);
+ }
+ if (rc < 0)
+ fprintf(stderr, "error %s\n", strerror(-rc));
+ return uc;
+}
+
+int do_check(int ac, char **av, int (*f)(rcyn_t*,const char*,const char*,const char*,const char*))
+{
+ int uc, rc;
+
+ rc = get_csup(ac, av, &uc, NULL);
+ if (rc == 0) {
+ rc = f(rcyn, client, session, user, permission);
+ if (rc > 0)
+ fprintf(stdout, "allowed\n");
+ else if (rc == 0)
+ fprintf(stdout, "denied\n");
+ else
+ fprintf(stderr, "error %s\n", strerror(-rc));
+ }
+ return uc;
+}
+
+int do_any(int ac, char **av)
+{
+ if (!ac)
+ return 0;
+
+ if (!strcmp(av[0], "list"))
+ return do_list(ac, av);
+
+ if (!strcmp(av[0], "set"))
+ return do_set(ac, av);
+
+ if (!strcmp(av[0], "drop"))
+ return do_drop(ac, av);
+
+ if (!strcmp(av[0], "check"))
+ return do_check(ac, av, rcyn_check);
+
+ if (!strcmp(av[0], "test"))
+ return do_check(ac, av, rcyn_test);
+
+ if (!strcmp(av[0], "cache"))
+ return do_check(ac, av, rcyn_cache_check);
+
+ if (!strcmp(av[0], "clear")) {
+ rcyn_cache_clear(rcyn);
+ return 1;
+ }
+
+ return 0;
+}
+
+void do_all(int ac, char **av)
+{
+ int rc;
+
+ while(ac) {
+ rc = do_any(ac, av);
+ if (rc <= 0)
+ exit(1);
+ ac -= rc;
+ av += rc;
+ }
+}
+
+int main(int ac, char **av)
+{
+ int rc;
+
+ signal(SIGPIPE, SIG_IGN); /* avoid SIGPIPE! */
+ rc = rcyn_open(&rcyn, rcyn_Admin, 5000);
+ if (rc < 0) {
+ fprintf(stderr, "initialisation failed: %s\n", strerror(-rc));
+ return 1;
+ }
+ if (ac > 1) {
+ do_all(ac - 1, av + 1);
+ return 0;
+ }
+
+ for(;;) {
+ if (!fgets(buffer, sizeof buffer, stdin))
+ break;
+
+ str[nstr = 0] = strtok(buffer, " \t\n");
+ while(str[nstr])
+ str[++nstr] = strtok(NULL, " \t\n");
+
+ ac = 0;
+ while(ac < nstr) {
+ rc = do_any(nstr - ac, &str[ac]);
+ if (rc <= 0)
+ exit(1);
+ ac += rc;
+ }
+ }
+ return 0;
+}
+
#include <stdio.h>
#include <limits.h>
#include <string.h>
+#include <time.h>
#include <getopt.h>
#include <unistd.h>
#include <pwd.h>
"\n"
"otpions:\n"
#if defined(WITH_SYSTEMD_ACTIVATION)
- " -s, --systemd socket activation by systemd\n"
+ " -s, --systemd socket activation by systemd\n"
#endif
" -u, --user xxx set the user\n"
" -g, --group xxx set the group\n"
- " -i, --init xxx initialize if needed the database with content of file xxx\n"
- "\n"
+ " -i, --init xxx initialize if needed the database with file xxx\n"
+ " (default: "DEFAULT_INIT_FILE"\n"
" -b, --dbdir xxx set the directory of database\n"
- " (default: "DEFAULT_DB_DIR")\n"
+ " (default: "DEFAULT_DB_DIR")\n"
" -m, --make-db-dir make the database directory\n"
" -o, --own-db-dir set user and group on database directory\n"
"\n"
" -S, --socketdir xxx set the base xxx for sockets\n"
- " (default: "DEFAULT_SOCKET_DIR")\n"
+ " (default: "DEFAULT_SOCKET_DIR")\n"
" -M, --make-socket-dir make the socket directory\n"
" -O, --own-socket-dir set user and group on socket directory\n"
"\n"
- " -h, --help print this help and exit\n"
- " -v, --version print the version and exit\n"
+ " -h, --help print this help and exit\n"
+ " -v, --version print the version and exit\n"
"\n"
;
ensuredir(p, (int)l, uid, gid);
}
+time_t txt2exp(const char *txt)
+{
+ static const int MIN = 60;
+ static const int HOUR = 60*MIN;
+ static const int DAY = 24*HOUR;
+ static const int YEAR = 365*DAY;
+
+ time_t r, x;
+
+ if (!strcmp(txt, "always"))
+ return 0;
+ r = time(NULL);
+ while(*txt) {
+ x = 0;
+ while('0' <= *txt && *txt <= '9')
+ x = 10 * x + (time_t)(*txt++ - '0');
+ switch(*txt) {
+ case 'y': r += x * YEAR; txt++; break;
+ case 'd': r += x *= DAY; txt++; break;
+ case 'h': r += x *= HOUR; txt++; break;
+ case 'm': r += x *= MIN; txt++; break;
+ case 's': txt++; /*@fallthrough@*/
+ case 0: r += x; break;
+ default: return -1;
+ }
+ }
+ return r;
+}
+
/** initialize the database from file of 'path' */
static void initdb(const char *path)
{
- int rc, lino, x;
+ int rc, lino;
char *item[10];
char buffer[2048];
+ time_t expire;
FILE *f;
f = fopen(path, "r");
item[3] = strtok(NULL, " \t\n\r");
item[4] = strtok(NULL, " \t\n\r");
item[5] = strtok(NULL, " \t\n\r");
+ item[6] = strtok(NULL, " \t\n\r");
if (item[1] == NULL || item[2] == NULL
- || item[3] == NULL || item[4] == NULL) {
+ || item[3] == NULL || item[4] == NULL
+ || item[5] == NULL) {
fprintf(stderr, "field missing (%s:%d)\n", path, lino);
exit(1);
- } else if (item[5] != NULL && item[5][0] != '#') {
+ } else if (item[6] != NULL && item[6][0] != '#') {
fprintf(stderr, "extra field (%s:%d)\n", path, lino);
exit(1);
}
- x = isid(item[4]);
- if (x < 0) {
- fprintf(stderr, "bad value (%s:%d)\n", path, lino);
+ expire = txt2exp(item[5]);
+ if (expire < 0) {
+ fprintf(stderr, "bad expiration %s (%s:%d)\n", item[5], path, lino);
exit(1);
}
- rc = db_set(item[0], item[1], item[2], item[3], x);
+ rc = db_set(item[0], item[1], item[2], item[3], item[4], expire);
if (rc < 0) {
fprintf(stderr, "can't set (%s:%d)\n", path, lino);
exit(1);
static
bool
-qget_char(
- char *value
-) {
- return qread(value, sizeof *value);
-}
-
-static
-bool
-qget_uint32(
- uint32_t *value
+qget_time(
+ time_t *value
) {
return qread(value, sizeof *value);
}
static
bool
-qput_char(
- char value
-) {
- return qwrite(&value, sizeof value);
-}
-
-static
-bool
-qput_uint32(
- uint32_t value
+qput_time(
+ time_t value
) {
return qwrite(&value, sizeof value);
}
const char *user,
const char *permission
) {
- return qput_char(DROP)
- && qput_string(client)
+ return qput_string(client)
&& qput_string(session)
&& qput_string(user)
&& qput_string(permission)
+ && qput_string(0)
? 0 : -(errno = ENOMEM);
}
const char *session,
const char *user,
const char *permission,
- uint32_t value
+ const char *value,
+ time_t expire
) {
- return qput_char(SET)
- && qput_string(client)
+ return qput_string(client)
&& qput_string(session)
&& qput_string(user)
&& qput_string(permission)
- && qput_uint32(value)
+ && qput_string(value)
+ && qput_time(expire)
? 0 : -(errno = ENOMEM);
}
queue_play(
) {
int rc, rc2;
- char op;
const char *client;
const char *session;
const char *user;
const char *permission;
- uint32_t value;
+ const char *value;
+ time_t expire;
rc = 0;
queue.read = 0;
while (queue.read < queue.write) {
rc2 = -EINVAL;
- if (qget_char(&op)
- && qget_string(&client)
+ if (qget_string(&client)
&& qget_string(&session)
&& qget_string(&user)
- && qget_string(&permission)) {
- if (op == DROP)
+ && qget_string(&permission)
+ && qget_string(&value)) {
+ if (!value[0])
rc2 = db_drop(client, session, user, permission);
- else if (qget_uint32(&value))
- rc2 = db_set(client, session, user, permission, value);
+ else {
+ if (qget_time(&expire))
+ rc2 = db_set(client, session, user, permission, value, expire);
+ }
}
if (rc2 != 0 && rc == 0)
rc = rc2;
const char *session,
const char *user,
const char *permission,
- uint32_t value
+ const char *value,
+ time_t expire
);
extern
static
int
status_check(
- rcyn_t *rcyn
+ rcyn_t *rcyn,
+ time_t *expire
) {
- return !strcmp(rcyn->reply.fields[0], _yes_) ? 1
- : !strcmp(rcyn->reply.fields[0], _no_) ? 0
- : -EEXIST;
+ int rc, exp;
+
+ if (!strcmp(rcyn->reply.fields[0], _yes_)) {
+ rc = 1;
+ exp = 1;
+ } else if (!strcmp(rcyn->reply.fields[0], _no_)) {
+ rc = 0;
+ exp = 1;
+ } else if (!strcmp(rcyn->reply.fields[0], _done_)) {
+ rc = -EEXIST;
+ exp = 2;
+ } else {
+ rc = -EPROTO;
+ exp = rcyn->reply.count;
+ }
+ if (exp < rcyn->reply.count)
+ *expire = strtoll(rcyn->reply.fields[exp], NULL, 10);
+ else
+ *expire = 0;
+ return rc;
}
static
ensure_opened(
rcyn_t *rcyn
) {
+ if (rcyn->fd >= 0 && write(rcyn->fd, NULL, 0) < 0)
+ disconnection(rcyn);
return rcyn->fd < 0 ? connection(rcyn) : 0;
}
const char *action
) {
int rc;
+ time_t expire;
if (rcyn->async.requests != NULL)
return -EINPROGRESS;
/* get the response */
rc = wait_pending_reply(rcyn);
if (rc >= 0) {
- rc = status_check(rcyn);
+ rc = status_check(rcyn, &expire);
if (rc >= 0)
- cache_put(rcyn->cache, client, session, user, permission, rc);
+ cache_put(rcyn->cache, client, session, user, permission, rc, expire);
}
}
return rc;
const char *user,
const char *permission
) {
- return check_or_test(rcyn, client, session, user, permission, _check_);
+ return check_or_test(rcyn, client, session, user, permission, _test_);
}
int
const char *session,
const char *user,
const char *permission,
- int value
+ const char *value,
+ time_t expire
) {
- char val[30];
+ char text[30];
+ const char *exp;
int rc;
if (rcyn->type != rcyn_Admin)
if (rc < 0)
return rc;
- snprintf(val, sizeof val, "%u", (unsigned)value);
- rc = putx(rcyn, _set_, client, session, user, permission, val, NULL);
+ if (!expire)
+ exp = NULL;
+ else {
+ snprintf(text, sizeof text, "%lld", (long long)expire);
+ exp = text;
+ }
+ rc = putx(rcyn, _set_, client, session, user, permission, value, exp, NULL);
if (rc >= 0)
rc = wait_done(rcyn);
return rc;
const char *session,
const char *user,
const char *permission,
- uint32_t value
+ const char *value,
+ time_t expire
),
void *closure
) {
rc = putx(rcyn, _get_, client, session, user, permission, NULL);
if (rc >= 0) {
rc = wait_reply(rcyn, true);
- while (rc == 6 && !strcmp(rcyn->reply.fields[0], _item_)) {
+ while ((rc == 6 || rc == 7) && !strcmp(rcyn->reply.fields[0], _item_)) {
callback(closure,
rcyn->reply.fields[1],
rcyn->reply.fields[2],
rcyn->reply.fields[3],
rcyn->reply.fields[4],
- (uint32_t)atoi(rcyn->reply.fields[5]));
+ rcyn->reply.fields[5],
+ rc == 6 ? 0 : (time_t)strtoll(rcyn->reply.fields[6], NULL, 10));
rc = wait_reply(rcyn, true);
}
rc = status_done(rcyn);
const char *first;
asreq_t *ar;
const char *client, *session, *user, *permission;
+ time_t expire;
for (;;) {
/* non blocking wait for a reply */
/* emit the asynchronous answer */
rcyn->async.requests = ar->next;
- rc = status_check(rcyn);
+ rc = status_check(rcyn, &expire);
if (rc >= 0) {
client = (const char*)(ar + 1);
session = &client[1 + strlen(client)];
user = &session[1 + strlen(session)];
permission = &user[1 + strlen(user)];
- cache_put(rcyn->cache, client, session, user, permission, rc);
+ cache_put(rcyn->cache, client, session, user, permission, rc, expire);
}
ar->callback(ar->closure, rc);
free(ar);
const char *session,
const char *user,
const char *permission,
- int value
+ const char *value,
+ time_t expire
);
extern
const char *session,
const char *user,
const char *permission,
- uint32_t value
+ const char *value,
+ time_t expire
),
void *closure
);
test a permission:
c->s test CLIENT SESSION USER PERMISSION
- s->c yes|no|VALUE [CACHING]
+ s->c [yes|no|done VALUE] [EXPIRE]
check a permission:
c->s check CLIENT SESSION USER PERMISSION
- s->c yes|no|VALUE [CACHING]
+ s->c [yes|no|done VALUE] [EXPIRE]
erase (admin):
set (admin):
- c->s set CLIENT SESSION USER PERMISSION VALUE
+ c->s set CLIENT SESSION USER PERMISSION VALUE [EXPIRE]
s->c done|error ...
list permissions (admin):
c->s get CLIENT SESSION USER PERMISSION
- s->c item CLIENT SESSION USER PERMISSION VALUE
+ s->c item CLIENT SESSION USER PERMISSION VALUE [EXPIRE]
s->c ...
s->c done
c->s g(et) CLIENT SESSION USER PERMISSION
c->s l(eave) [commit|rollback]
c->s r(cyn)
- c->s s(et) CLIENT SESSION USER PERMISSION VALUE
+ c->s s(et) CLIENT SESSION USER PERMISSION VALUE EXPIRE
c->s t(est) CLIENT SESSION USER PERMISSION
s->c clear
s->c done
s->c done [CLIENT SESSION USER PERMISSION VALUE]
s->c done|error ...
- s->c item CLIENT SESSION USER PERMISSION VALUE
- s->c yes|no
- s->c yes|no|VALUE [CACHING]
+ s->c item CLIENT SESSION USER PERMISSION VALUE EXPIRE
+ s->c done VALUE EXPIRE
send_done(cli);
}
+/** translate optional expire value */
+static
+const char *
+exp2txt(
+ time_t expire,
+ char *buffer,
+ size_t bufsz
+) {
+ if (!expire)
+ return NULL;
+
+ /* TODO: check size */
+ snprintf(buffer, bufsz, "%lld", (long long)expire);
+ return buffer;
+}
+
/** callback of checking */
static
void
checkcb(
void *closure,
- uint32_t value
+ const char *value,
+ time_t expire
) {
client_t *cli = closure;
- const char *a;
- char val[30];
-
- if (value == DENY)
- a = _no_;
- else if (value == ALLOW)
- a = _yes_;
- else {
- snprintf(val, sizeof val, "%d", value);
- a = val;
- }
- putx(cli, a, NULL);
+ char text[30];
+
+ if (strcmp(value, ALLOW) && strcmp(value, DENY))
+ putx(cli, _done_, value, exp2txt(expire, text, sizeof text), NULL);
+ else
+ putx(cli, value, exp2txt(expire, text, sizeof text), NULL);
flushw(cli);
}
const char *session,
const char *user,
const char *permission,
- uint32_t value
+ const char *value,
+ time_t expire
) {
client_t *cli = closure;
- char val[30];
- snprintf(val, sizeof val, "%d", value);
- putx(cli, _item_, client, session, user, permission, val, NULL);
+ char text[30];
+
+ putx(cli, _item_, client, session, user, permission,
+ value, exp2txt(expire, text, sizeof text), NULL);
}
/** handle a request */
const char *args[]
) {
int rc;
- uint32_t value;
+ const char *value;
+ time_t expire;
/* just ignore empty lines */
if (count == 0)
}
break;
case 's': /* set */
- if (ckarg(args[0], _set_, 1) && count == 6) {
+ if (ckarg(args[0], _set_, 1) && (count == 6 || count == 7)) {
if (cli->type != rcyn_Admin)
break;
if (!cli->entered)
break;
- value = (uint32_t)atol(args[5]);
- rc = cyn_set(args[1], args[2], args[3], args[4], value);
+ if (count == 6)
+ expire = 0;
+ else
+ expire = strtoll(args[6], NULL, 10);
+ rc = cyn_set(args[1], args[2], args[3], args[4], args[5], expire);
send_done_or_error(cli, rc);
return;
}
break;
case 't': /* test */
if (ckarg(args[0], _test_, 1) && count == 5) {
- cyn_test(args[1], args[2], args[3], args[4], &value);
- checkcb(cli, value);
+ cli->checked = 1;
+ cyn_test(args[1], args[2], args[3], args[4], &value, &expire);
+ checkcb(cli, value, expire);
return;
}
break;
return server->stopped == INT_MIN ? 0 : server->stopped;
}
-#if 0
-#if defined(WITH_SYSTEMD_ACTIVATION)
-#include <systemd/sd-daemon.h>
-#endif
-
-
-int main(int ac, char **av)
-{
- int rc;
- const char *check_spec = rcyn_default_check_socket_spec;
- const char *admin_spec = rcyn_default_admin_socket_spec;
- rcyn_server_t *server;
-
- /* connection to the database */
- rc = cyn_init(
- "/var/lib/cynara/cynara.names",
- "/var/lib/cynara/cynara.rules",
- (const char**)((const char *[]){ "System", "*", "*", "*", "1", NULL })
- );
- if (rc < 0) {
- fprintf(stderr, "can't initialise database: %m\n");
- return 1;
- }
-
- /* create the server */
- rc = rcyn_server_create(&server, admin_spec, check_spec);
- if (rc < 0) {
- fprintf(stderr, "can't initialise server: %m\n");
- return 1;
- }
-
- /* ready ! */
-#if defined(WITH_SYSTEMD_ACTIVATION)
- sd_notify(0, "READY=1");
-#endif
-
- /* process inputs */
- rcyn_server_serve(server);
-}
-#endif
-