summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.gitignore1
-rw-r--r--src/CMakeLists.txt35
-rw-r--r--src/cache.c48
-rw-r--r--src/cache.h10
-rw-r--r--src/cyn.c257
-rw-r--r--src/cyn.h110
-rw-r--r--src/data.h39
-rw-r--r--src/db.c322
-rw-r--r--src/db.h48
-rw-r--r--src/dbinit.c125
-rw-r--r--src/dbinit.h22
-rw-r--r--src/expire.c84
-rw-r--r--src/expire.h21
-rw-r--r--src/fbuf.c268
-rw-r--r--src/fbuf.h29
-rw-r--r--src/lib-compat.c72
-rw-r--r--src/main-cynadm.c223
-rw-r--r--src/main-cynarad.c155
-rw-r--r--src/pollitem.c91
-rw-r--r--src/pollitem.h61
-rw-r--r--src/prot.c196
-rw-r--r--src/prot.h27
-rw-r--r--src/queue.c60
-rw-r--r--src/queue.h13
-rw-r--r--src/rcyn-client.c272
-rw-r--r--src/rcyn-client.h78
-rw-r--r--src/rcyn-protocol.c38
-rw-r--r--src/rcyn-protocol.h10
-rw-r--r--src/rcyn-protocol.txt2
-rw-r--r--src/rcyn-server.c211
-rw-r--r--src/rcyn-server.h3
-rw-r--r--src/socket.c2
32 files changed, 1716 insertions, 1217 deletions
diff --git a/.gitignore b/.gitignore
index ac33634..e379367 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,2 +1,3 @@
build/
.*.sw*
+nbproject/
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 549d401..cacd659 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -19,8 +19,11 @@
set(SERVER_SOURCES
cyn.c
db.c
+ dbinit.c
+ expire.c
fbuf.c
main-cynarad.c
+ pollitem.c
prot.c
queue.c
rcyn-protocol.c
@@ -37,20 +40,7 @@ set(LIB_SOURCES
socket.c
)
-###########################################
-# build and install cynarad
-###########################################
-add_executable(cynarad ${SERVER_SOURCES})
-target_compile_definitions(cynarad PRIVATE
- DEFAULT_DB_DIR="${DEFAULT_DB_DIR}"
- DEFAULT_SOCKET_DIR="${DEFAULT_SOCKET_DIR}"
- DEFAULT_INIT_FILE="${DEFAULT_INIT_FILE}"
- RCYN_DEFAULT_CHECK_SOCKET_SPEC="unix:${DEFAULT_SOCKET_DIR}/cynara.check"
- RCYN_DEFAULT_ADMIN_SOCKET_SPEC="unix:${DEFAULT_SOCKET_DIR}/cynara.admin"
-)
-target_link_libraries(cynarad cap)
-install(TARGETS cynarad
- RUNTIME DESTINATION ${CMAKE_INSTALL_FULL_BINDIR})
+add_compile_definitions(_GNU_SOURCE)
###########################################
# build and install libcynara
@@ -72,9 +62,24 @@ INSTALL(TARGETS cynara LIBRARY DESTINATION ${CMAKE_INSTALL_FULL_LIBDIR})
INSTALL(FILES rcyn-client.h DESTINATION ${CMAKE_INSTALL_FULL_INCLUDEDIR}/cynara)
###########################################
+# build and install cynarad
+###########################################
+add_executable(cynarad ${SERVER_SOURCES})
+target_compile_definitions(cynarad PRIVATE
+ DEFAULT_DB_DIR="${DEFAULT_DB_DIR}"
+ DEFAULT_SOCKET_DIR="${DEFAULT_SOCKET_DIR}"
+ DEFAULT_INIT_FILE="${DEFAULT_INIT_FILE}"
+ RCYN_DEFAULT_CHECK_SOCKET_SPEC="unix:${DEFAULT_SOCKET_DIR}/cynara.check"
+ RCYN_DEFAULT_ADMIN_SOCKET_SPEC="unix:${DEFAULT_SOCKET_DIR}/cynara.admin"
+)
+target_link_libraries(cynarad cap)
+install(TARGETS cynarad
+ RUNTIME DESTINATION ${CMAKE_INSTALL_FULL_BINDIR})
+
+###########################################
# build and install cynadm
###########################################
-ADD_EXECUTABLE(cynadm main-cynadm.c)
+ADD_EXECUTABLE(cynadm main-cynadm.c expire.c)
TARGET_LINK_LIBRARIES(cynadm cynara)
INSTALL(TARGETS cynadm
RUNTIME DESTINATION ${CMAKE_INSTALL_FULL_BINDIR})
diff --git a/src/cache.c b/src/cache.c
index 9bbe667..b57536d 100644
--- a/src/cache.c
+++ b/src/cache.c
@@ -17,6 +17,7 @@
#include <stdlib.h>
+#include <stdbool.h>
#include <stdint.h>
#include <stdalign.h>
#include <string.h>
@@ -24,6 +25,7 @@
#include <time.h>
#include <ctype.h>
+#include "rcyn-client.h"
#include "cache.h"
/**
@@ -34,7 +36,7 @@
* - session: zero terminated string
* - user: zero terminated string
* - permission: zero terminated string
- * -
+ * -
*/
struct item
{
@@ -166,18 +168,15 @@ static
int
match(
const char *head,
- const char *client,
- const char *session,
- const char *user,
- const char *permission
+ const rcyn_key_t *key
) {
- head = cmp(head, client);
+ head = cmp(head, key->client);
if (head)
- head = cmp(head, session);
+ head = cmp(head, key->session);
if (head)
- head = cmp(head, user);
+ head = cmp(head, key->user);
if (head)
- head = cmpi(head, permission);
+ head = cmpi(head, key->permission);
return !!head;
}
@@ -185,10 +184,7 @@ static
item_t*
search(
cache_t *cache,
- const char *client,
- const char *session,
- const char *user,
- const char *permission
+ const rcyn_key_t *key
) {
time_t now;
item_t *item, *found;
@@ -202,7 +198,7 @@ search(
if (item->expire && item->expire < now)
drop_at(cache, iter);
else {
- if (match(&item->strings, client, session, user, permission))
+ if (match(&item->strings, key))
found = item;
iter += item->length;
}
@@ -213,10 +209,7 @@ search(
int
cache_put(
cache_t *cache,
- const char *client,
- const char *session,
- const char *user,
- const char *permission,
+ const rcyn_key_t *key,
int value,
time_t expire
) {
@@ -227,14 +220,14 @@ cache_put(
if (cache == NULL || value < -128 || value > 127)
return -EINVAL;
- item = search(cache, client, session, user, permission);
+ item = search(cache, key);
if (item == NULL) {
/* create an item */
size = (size_t)(&((item_t*)0)->strings)
- + strlen(client)
- + strlen(session)
- + strlen(user)
- + strlen(permission);
+ + strlen(key->client)
+ + strlen(key->session)
+ + strlen(key->user)
+ + strlen(key->permission);
size = (size + alignof(item_t) - 1) & ~(alignof(item_t) - 1);
if (size > 65535)
return -EINVAL;
@@ -245,7 +238,7 @@ cache_put(
drop_lre(cache);
item = itemat(cache, cache->used);
item->length = length;
- stpcpy(1 + stpcpy(1 + stpcpy(1 + stpcpy(&item->strings, client), session), user), permission);
+ stpcpy(1 + stpcpy(1 + stpcpy(1 + stpcpy(&item->strings, key->client), key->session), key->user), key->permission);
cache->used += (uint32_t)size;
}
item->expire = expire;
@@ -257,14 +250,11 @@ cache_put(
int
cache_search(
cache_t *cache,
- const char *client,
- const char *session,
- const char *user,
- const char *permission
+ const rcyn_key_t *key
) {
item_t *item;
- item = search(cache, client, session, user, permission);
+ item = search(cache, key);
if (item) {
hit(cache, item);
return (int)item->value;
diff --git a/src/cache.h b/src/cache.h
index bd56601..bf85e8e 100644
--- a/src/cache.h
+++ b/src/cache.h
@@ -24,20 +24,14 @@ extern
int
cache_search(
cache_t *cache,
- const char *client,
- const char *session,
- const char *user,
- const char *permission
+ const rcyn_key_t *key
);
extern
int
cache_put(
cache_t *cache,
- const char *client,
- const char *session,
- const char *user,
- const char *permission,
+ const rcyn_key_t *key,
int value,
time_t expire
);
diff --git a/src/cyn.c b/src/cyn.c
index 914bf52..6f27860 100644
--- a/src/cyn.c
+++ b/src/cyn.c
@@ -15,9 +15,6 @@
* limitations under the License.
*/
-#define _GNU_SOURCE
-
-
#include <assert.h>
#include <stdlib.h>
#include <stdint.h>
@@ -26,6 +23,7 @@
#include <errno.h>
+#include "data.h"
#include "db.h"
#include "queue.h"
#include "cyn.h"
@@ -33,26 +31,48 @@
struct callback
{
struct callback *next;
- void (*callback)(void *closure);
+ union {
+ void *any_cb;
+ on_enter_cb_t *on_enter_cb;
+ on_change_cb_t *on_change_cb;
+ agent_cb_t *agent_cb;
+ };
void *closure;
};
+struct async_check
+{
+ struct async_check *next;
+ on_result_cb_t *on_result_cb;
+ void *closure;
+ data_key_t key;
+ struct callback *next_agent;
+};
+
/** locking critical section */
static const void *lock;
static struct callback *awaiters;
static struct callback *observers;
+static struct callback *agents;
+static struct async_check *asynchecks;
static
int
delcb(
- void (*callback)(void *closure),
+ void *callback,
void *closure,
- struct callback **head
+ struct callback **head,
+ struct async_check *achecks
) {
struct callback *c;
while((c = *head)) {
- if (c->callback == callback && c->closure == closure) {
+ if (c->any_cb == callback && c->closure == closure) {
+ while (achecks) {
+ if (achecks->next_agent == c)
+ achecks->next_agent = c->next;
+ achecks = achecks->next;
+ }
*head = c->next;
free(c);
return 1;
@@ -65,7 +85,7 @@ delcb(
static
int
addcb(
- void (*callback)(void *closure),
+ void *callback,
void *closure,
struct callback **head
) {
@@ -74,27 +94,13 @@ addcb(
c = malloc(sizeof *c);
if (c == NULL)
return -(errno = ENOMEM);
- c->callback = callback;
+ c->any_cb = callback;
c->closure = closure;
c->next = *head;
*head = c;
return 0;
}
-static
-int
-changed(
-) {
- int rc;
- struct callback *c;
-
- db_cleanup(0);
- rc = db_sync();
- for (c = observers; c ; c = c->next)
- c->callback(c->closure);
- return rc;
-}
-
/** enter critical recoverable section */
int
cyn_enter(
@@ -108,7 +114,7 @@ cyn_enter(
int
cyn_enter_async(
- void (*enter_cb)(void *closure),
+ on_enter_cb_t *enter_cb,
void *closure
) {
if (lock)
@@ -121,27 +127,26 @@ cyn_enter_async(
int
cyn_enter_async_cancel(
- void (*enter_cb)(void *closure),
+ on_enter_cb_t *enter_cb,
void *closure
) {
- return delcb(enter_cb, closure, &awaiters);
+ return delcb(enter_cb, closure, &awaiters, 0);
}
int
cyn_on_change_add(
- void (*on_change_cb)(void *closure),
+ on_change_cb_t *on_change_cb,
void *closure
) {
return addcb(on_change_cb, closure, &observers);
}
-
int
cyn_on_change_remove(
- void (*on_change_cb)(void *closure),
+ on_change_cb_t *on_change_cb,
void *closure
) {
- return delcb(on_change_cb, closure, &observers);
+ return delcb(on_change_cb, closure, &observers, 0);
}
/** leave critical recoverable section */
@@ -151,7 +156,7 @@ cyn_leave(
bool commit
) {
int rc;
- struct callback *e, **p;
+ struct callback *c, *e, **p;
if (!magic)
return -EINVAL;
@@ -164,12 +169,18 @@ cyn_leave(
if (!commit)
rc = 0;
else {
+ db_backup();
rc = queue_play();
- if (rc < 0)
+ if (rc == 0) {
+ db_cleanup(0);
+ rc = db_sync();
+ }
+ if (rc < 0) {
db_recover();
- else {
- rc = db_backup();
- changed();
+ db_sync();
+ } else {
+ for (c = observers; c ; c = c->next)
+ c->on_change_cb(c->closure);
}
}
queue_clear();
@@ -185,7 +196,7 @@ cyn_leave(
}
*p = NULL;
lock = e->closure;
- e->callback(e->closure);
+ e->on_enter_cb(e->closure);
free(e);
}
@@ -194,89 +205,169 @@ cyn_leave(
int
cyn_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
) {
if (!lock)
return -EPERM;
- return queue_set(client, session, user, permission, value, expire);
+ return queue_set(key, value);
}
int
cyn_drop(
- const char *client,
- const char *session,
- const char *user,
- const char *permission
+ const data_key_t *key
) {
if (!lock)
return -EPERM;
- return queue_drop(client, session, user, permission);
+ return queue_drop(key);
}
void
cyn_list(
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
+ list_cb_t *callback,
+ const data_key_t *key
) {
- db_for_all(closure, callback, client, session, user, permission);
+ db_for_all(closure, callback, key);
}
int
cyn_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
) {
int rc;
- rc = db_test(client, session, user, permission, value, expire);
- if (rc <= 0)
- *value = DEFAULT;
- else
+ rc = db_test(key, value);
+ if (rc > 0)
rc = 0;
+ else {
+ value->value = DEFAULT;
+ value->expire = 0;
+ }
return rc;
}
+static
+void
+async_on_result(
+ void *closure,
+ const data_value_t *value
+) {
+ struct async_check *achk = closure, **pac;
+ struct callback *agent;
+ int rc;
+ data_value_t v;
+
+ if (!value) {
+ agent = achk->next_agent;
+ while (agent) {
+ achk->next_agent = agent->next;
+ rc = agent->agent_cb(
+ agent->closure,
+ &achk->key,
+ async_on_result,
+ closure);
+ if (!rc)
+ return;
+ agent = achk->next_agent;
+ }
+ v.value = DEFAULT;
+ v.expire = 0;
+ value = &v;
+ }
+
+ achk->on_result_cb(achk->closure, value);
+ pac = &asynchecks;
+ while (*pac != achk)
+ pac = &(*pac)->next;
+ *pac = achk->next;
+ free(achk);
+}
+
+
int
cyn_check_async(
- void (*check_cb)(void *closure, const char *value, time_t expire),
+ on_result_cb_t *on_result_cb,
void *closure,
- const char *client,
- const char *session,
- const char *user,
- const char *permission
+ const data_key_t *key
) {
- const char *value;
- time_t expire;
+ data_value_t value;
+ size_t szcli, szses, szuse, szper;
+ struct async_check *achk;
+ void *ptr;
+
+ cyn_test(key, &value);
+ if (!strcmp(value.value, ALLOW) || !strcmp(value.value, DENY)) {
+ on_result_cb(closure, &value);
+ return 0;
+ }
- cyn_test(client, session, user, permission, &value, &expire);
- if (!strcmp(value, ALLOW) || !strcmp(value, DENY)) {
- check_cb(closure, value, expire);
+ if (!agents) {
+ on_result_cb(closure, &value);
return 0;
}
- /* TODO: try to resolve AGENT?? */
+ szcli = key->client ? 1 + strlen(key->client) : 0;
+ szses = key->session ? 1 + strlen(key->session) : 0;
+ szuse = key->user ? 1 + strlen(key->user) : 0;
+ szper = key->permission ? 1 + strlen(key->permission) : 0;
+ achk = malloc(szcli + szses + szuse + szper + sizeof *achk);
+ if (!achk) {
+ on_result_cb(closure, &value);
+ return -ENOMEM;
+ }
- check_cb(closure, value, expire);
+ ptr = achk;
+ achk->on_result_cb = on_result_cb;
+ achk->closure = closure;
+ if (!key->client)
+ achk->key.client = 0;
+ else {
+ achk->key.client = ptr;
+ memcpy(ptr, key->client, szcli);
+ ptr += szcli;
+ }
+ if (!key->session)
+ achk->key.session = 0;
+ else {
+ achk->key.session = ptr;
+ memcpy(ptr, key->session, szses);
+ ptr += szses;
+ }
+ if (!key->user)
+ achk->key.user = 0;
+ else {
+ achk->key.user = ptr;
+ memcpy(ptr, key->user, szuse);
+ ptr += szuse;
+ }
+ if (!key->permission)
+ achk->key.permission = 0;
+ else {
+ achk->key.permission = ptr;
+ memcpy(ptr, key->permission, szper);
+ }
+ achk->next_agent = agents;
+ achk->next = asynchecks;
+ asynchecks = achk;
+ async_on_result(achk, 0);
return 0;
}
+int
+cyn_agent_add(
+ agent_cb_t *agent_cb,
+ void *closure
+) {
+ return addcb(agent_cb, closure, &agents);
+}
+
+int
+cyn_agent_remove(
+ agent_cb_t *agent_cb,
+ void *closure
+) {
+ return delcb(agent_cb, closure, &agents, asynchecks);
+}
+
diff --git a/src/cyn.h b/src/cyn.h
index 379deef..8f8893a 100644
--- a/src/cyn.h
+++ b/src/cyn.h
@@ -18,10 +18,20 @@
#pragma once
-#define DENY "no"
-#define ALLOW "yes"
-#define ASK "ask"
-#define DEFAULT DENY
+typedef void (on_enter_cb_t)(void *closure);
+typedef void (on_change_cb_t)(void *closure);
+typedef void (on_result_cb_t)(void *closure, const data_value_t *value);
+
+typedef void (list_cb_t)(
+ void *closure,
+ const data_key_t *key,
+ const data_value_t *value);
+
+typedef int (agent_cb_t)(
+ void *agent_closure,
+ const data_key_t *key,
+ on_result_cb_t *on_result_cb,
+ void *on_result_closure);
/** enter critical recoverable section */
extern
@@ -40,89 +50,79 @@ cyn_leave(
extern
int
-cyn_set(
- const char *client,
- const char *session,
- const char *user,
- const char *permission,
- const char *value,
- time_t expire
+cyn_enter_async(
+ on_enter_cb_t *enter_cb,
+ void *closure
);
extern
int
-cyn_drop(
- const char *client,
- const char *session,
- const char *user,
- const char *permission
+cyn_enter_async_cancel(
+ on_enter_cb_t *enter_cb,
+ void *closure
);
extern
int
-cyn_test(
- const char *client,
- const char *session,
- const char *user,
- const char *permission,
- const char **value,
- time_t *expire
+cyn_on_change_add(
+ on_change_cb_t *on_change_cb,
+ void *closure
);
extern
-void
-cyn_list(
- 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
+int
+cyn_on_change_remove(
+ on_change_cb_t *on_change_cb,
+ void *closure
);
extern
int
-cyn_check_async(
- 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
+cyn_set(
+ const data_key_t *key,
+ const data_value_t *value
);
extern
int
-cyn_enter_async(
- void (*enter_cb)(void *closure),
- void *closure
+cyn_drop(
+ const data_key_t *key
);
extern
int
-cyn_enter_async_cancel(
- void (*enter_cb)(void *closure),
- void *closure
+cyn_test(
+ const data_key_t *key,
+ data_value_t *value
+);
+
+extern
+void
+cyn_list(
+ void *closure,
+ list_cb_t *callback,
+ const data_key_t *key
);
extern
int
-cyn_on_change_add(
- void (*on_change_cb)(void *closure),
+cyn_check_async(
+ on_result_cb_t *on_result_cb,
+ void *closure,
+ const data_key_t *key
+);
+
+extern
+int
+cyn_agent_add(
+ agent_cb_t *agent_cb,
void *closure
);
extern
int
-cyn_on_change_remove(
- void (*on_change_cb)(void *closure),
+cyn_agent_remove(
+ agent_cb_t *agent_cb,
void *closure
);
diff --git a/src/data.h b/src/data.h
new file mode 100644
index 0000000..10cc599
--- /dev/null
+++ b/src/data.h
@@ -0,0 +1,39 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#define DENY "no"
+#define ALLOW "yes"
+#define ASK "ask"
+#define DEFAULT DENY
+
+typedef struct data_key data_key_t;
+typedef struct data_value data_value_t;
+
+struct data_key {
+ const char *client;
+ const char *session;
+ const char *user;
+ const char *permission;
+};
+
+struct data_value {
+ const char *value;
+ time_t expire;
+};
+
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++;
diff --git a/src/db.h b/src/db.h
index 192e215..61265fc 100644
--- a/src/db.h
+++ b/src/db.h
@@ -44,19 +44,6 @@ int
db_sync(
);
-/** enter critical recoverable section */
-extern
-int
-db_enter(
-);
-
-/** leave critical recoverable section */
-extern
-int
-db_leave(
- bool commit
-);
-
/** get an index for a name */
extern
int
@@ -85,53 +72,36 @@ 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
);
/** erase rules */
extern
int
db_drop(
- const char *client,
- const char *session,
- const char *user,
- const char *permission
+ const data_key_t *key
);
/** set rules */
extern
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
);
/** check rules */
extern
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
);
/** cleanup the base */
+extern
int
db_cleanup(
);
diff --git a/src/dbinit.c b/src/dbinit.c
new file mode 100644
index 0000000..b1b3c54
--- /dev/null
+++ b/src/dbinit.c
@@ -0,0 +1,125 @@
+/*
+ * 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 <stdlib.h>
+#include <time.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <errno.h>
+
+#include "data.h"
+#include "cyn.h"
+#include "expire.h"
+#include "dbinit.h"
+
+/** initialize the database from file of 'path' */
+int dbinit_add_file(const char *path)
+{
+ int rc, lino;
+ char *item[10];
+ char buffer[2048];
+ data_key_t key;
+ data_value_t value;
+ FILE *f;
+
+ /* enter critical section */
+ rc = cyn_enter(dbinit_add_file);
+ if (rc < 0)
+ return rc;
+
+ /* open the file */
+ f = fopen(path, "r");
+ if (f == NULL) {
+ rc = -errno;
+ fprintf(stderr, "can't open file %s\n", path);
+ goto error;
+ }
+
+ /* read lines of the file */
+ lino = 0;
+ while(fgets(buffer, sizeof buffer, f)) {
+
+ /* parse the line */
+ lino++;
+ item[0] = strtok(buffer, " \t\n\r");
+ item[1] = strtok(NULL, " \t\n\r");
+ item[2] = strtok(NULL, " \t\n\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");
+
+ /* skip empty lines and comments */
+ if (item[0] == NULL)
+ continue;
+ if (item[0][0] == '#')
+ continue;
+
+ /* check items of the rule */
+ if (item[1] == NULL || item[2] == NULL
+ || item[3] == NULL || item[4] == NULL
+ || item[5] == NULL) {
+ fprintf(stderr, "field missing (%s:%d)\n", path, lino);
+ rc = -EINVAL;
+ goto error2;
+ }
+ if (item[6] != NULL && item[6][0] != '#') {
+ fprintf(stderr, "extra field (%s:%d)\n", path, lino);
+ rc = -EINVAL;
+ goto error2;
+ }
+
+ /* create the key and value of the rule */
+ key.client = item[0];
+ key.session = item[1];
+ key.user = item[2];
+ key.permission = item[3];
+ value.value = item[4];
+ value.expire = txt2exp(item[5]);
+ if (value.expire < 0) {
+ fprintf(stderr, "bad expiration %s (%s:%d)\n", item[5], path, lino);
+ rc = -EINVAL;
+ goto error2;
+ }
+
+ /* record the rule */
+ rc = cyn_set(&key, &value);
+ if (rc < 0) {
+ fprintf(stderr, "can't set (%s:%d)\n", path, lino);
+ exit(1);
+ }
+ }
+ if (!feof(f)) {
+ rc = -errno;
+ fprintf(stderr, "error while reading file %s\n", path);
+ goto error2;
+ }
+ rc = 0;
+error2:
+ fclose(f);
+error:
+ if (rc)
+ cyn_leave(dbinit_add_file, 0);
+ else {
+ rc = cyn_leave(dbinit_add_file, 1);
+ if (rc < 0)
+ fprintf(stderr, "unable to commit content of file %s\n", path);
+ }
+ return rc;
+}
diff --git a/src/dbinit.h b/src/dbinit.h
new file mode 100644
index 0000000..bca4afc
--- /dev/null
+++ b/src/dbinit.h
@@ -0,0 +1,22 @@
+/*
+ * 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.
+ */
+
+
+#pragma once
+
+extern int dbinit_add_file(const char *path);
+
diff --git a/src/expire.c b/src/expire.c
new file mode 100644
index 0000000..1571db7
--- /dev/null
+++ b/src/expire.c
@@ -0,0 +1,84 @@
+/*
+ * 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 <time.h>
+#include <string.h>
+#include <stdio.h>
+
+static const int SEC = 1;
+static const int MIN = 60;
+static const int HOUR = 60*60;
+static const int DAY = 24*60*60;
+static const int WEEK = 7*24*60*60;
+static const int YEAR = 365*24*60*60;
+
+time_t txt2exp(const char *txt)
+{
+ time_t r, x;
+
+ /* infinite time */
+ if (!strcmp(txt, "always") || !strcmp(txt, "*"))
+ return 0;
+
+ /* parse */
+ 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 'w': r += x * WEEK; 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 * SEC; break;
+ default: return -1;
+ }
+ }
+ return r;
+}
+
+size_t exp2txt(time_t expire, char *buffer, size_t buflen)
+{
+ char b[100];
+ size_t l;
+ int n;
+
+ if (!expire)
+ strncpy(b, "always", sizeof b);
+ else {
+ expire -= time(NULL);
+ n = 0;
+#define ADD(C,U) \
+ if (expire >= U) { \
+ n += snprintf(&b[n], sizeof b - n, "%lld" #C, (long long)(expire / U)); \
+ expire %= U; \
+ }
+ ADD(y,YEAR)
+ ADD(w,WEEK)
+ ADD(d,DAY)
+ ADD(h,HOUR)
+ ADD(m,MIN)
+ ADD(s,SEC)
+#undef ADD
+ }
+ l = strlen(b);
+ strncpy(buffer, b, buflen);
+ return l;
+}
diff --git a/src/expire.h b/src/expire.h
new file mode 100644
index 0000000..c9e46bc
--- /dev/null
+++ b/src/expire.h
@@ -0,0 +1,21 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+extern time_t txt2exp(const char *txt);
+extern size_t exp2txt(time_t expire, char *buffer, size_t buflen);
diff --git a/src/fbuf.c b/src/fbuf.c
index c1d4475..55b8230 100644
--- a/src/fbuf.c
+++ b/src/fbuf.c
@@ -15,10 +15,6 @@
* limitations under the License.
*/
-
-#define _GNU_SOURCE
-
-
#include <assert.h>
#include <stdlib.h>
#include <stdint.h>
@@ -45,88 +41,101 @@ get_asz(
}
/** open in 'fb' the file of 'name' */
+static
int
-fbuf_open(
+read_file(
fbuf_t *fb,
- const char *name,
- const char *backup
+ const char *name
) {
struct stat st;
- int fd, fdback, rc;
- uint32_t sz, asz;
- void *buffer;
-
- /* open the backup */
- if (backup == NULL)
- fdback = -1;
- else {
- fdback = open(backup, O_RDWR|O_CREAT, 0600);
- if (fdback < 0)
- goto error;
- rc = flock(fdback, LOCK_EX|LOCK_NB);
- if (rc < 0)
- goto error;
- }
+ int fd, rc;
+ uint32_t sz;
/* open the file */
fd = open(name, O_RDWR|O_CREAT, 0600);
if (fd < 0)
goto error;
- /* lock it */
- rc = flock(fd, LOCK_EX|LOCK_NB);
- if (rc < 0)
- goto error2;
-
/* get file stat */
rc = fstat(fd, &st);
if (rc < 0)
- goto error3;
+ goto error2;
/* check file size */
if ((off_t)INT32_MAX < st.st_size) {
errno = EFBIG;
- goto error3;
+ goto error2;
}
-
- /* compute allocation size */
sz = (uint32_t)st.st_size;
- asz = get_asz(sz);
- buffer = malloc(asz);
- if (buffer == NULL)
- goto error3;
+
+ /* allocate memory */
+ rc = fbuf_ensure_capacity(fb, (uint32_t)st.st_size);
+ if (rc < 0)
+ goto error2;
/* read the file */
- if (read(fd, buffer, (size_t)sz) != (ssize_t)sz)
- goto error4;
+ if (read(fd, fb->buffer, (size_t)sz) != (ssize_t)sz)
+ goto error2;
+
+ /* done */
+ fb->used = fb->size = sz;
+ close(fd);
+ return 0;
+
+error2:
+ close(fd);
+error:
+ rc = -errno;
+ fprintf(stderr, "can't read file %s: %m", name);
+ fb->saved = fb->used = fb->size = 0;
+ return rc;
+}
+
+/** open in 'fb' the file of 'name' */
+int
+fbuf_open(
+ fbuf_t *fb,
+ const char *name,
+ const char *backup
+) {
+ int rc;
+ size_t sz;
+
+ /* reset */
+ memset(fb, 0, sizeof *fb);
/* save name */
fb->name = strdup(name);
if (fb->name == NULL)
- goto error4;
+ goto error;
- /* done */
- fb->buffer = buffer;
- fb->saved = fb->used = fb->size = sz;
- fb->capacity = asz;
- fb->fd = fd;
- fb->backup = fdback;
+ /* open the backup */
+ if (backup != NULL)
+ fb->backup = strdup(backup);
+ else {
+ sz = strlen(name);
+ fb->backup = malloc(sz + 2);
+ if (fb->backup != NULL) {
+ memcpy(fb->backup, name, sz);
+ fb->backup[sz] = '~';
+ fb->backup[sz + 1] = 0;
+ }
+ }
+ if (fb->backup == NULL)
+ goto error;
+
+ /* read the file */
+ rc = read_file(fb, fb->name);
+ if (rc < 0)
+ goto error;
+
+ fb->saved = fb->used;
return 0;
-error4:
- free(buffer);
-error3:
- flock(fd, LOCK_UN);
-error2:
- close(fd);
error:
rc = -errno;
fprintf(stderr, "can't open file %s: %m", name);
- if (fdback >= 0) {
- flock(fdback, LOCK_UN);
- close(fdback);
- }
- memset(fb, 0, sizeof *fb);
+ fbuf_close(fb);
return rc;
}
@@ -136,77 +145,42 @@ fbuf_close(
fbuf_t *fb
) {
free(fb->name);
+ free(fb->backup);
free(fb->buffer);
- flock(fb->fd, LOCK_UN);
- close(fb->fd);
- if (fb->backup >= 0) {
- flock(fb->backup, LOCK_UN);
- close(fb->backup);
- }
memset(fb, 0, sizeof *fb);
}
-/** write to file 'fb' at 'offset' the 'count' bytes pointed by 'buffer' */
-int
-fbuf_write(
- fbuf_t *fb,
- const void *buffer,
- uint32_t count,
- uint32_t offset
-) {
- ssize_t rcs;
-
- /* don't call me for nothing */
- assert(count);
-
- /* effective write */
- rcs = pwrite(fb->fd, buffer, (size_t)count, (off_t)offset);
- if (rcs != (ssize_t)count)
- goto error;
-
- return 0;
-error:
- fprintf(stderr, "write of file %s failed: %m", fb->name);
- return -errno;
-}
-
/** write to file 'fb' the unsaved bytes and flush the content to the file */
int
fbuf_sync(
fbuf_t *fb
) {
- int rc;
- bool changed = false;
+ ssize_t rcs;
+ int rc, fd;
- /* write unsaved bytes */
- if (fb->used > fb->saved) {
- rc = fbuf_write(fb, fb->buffer + fb->saved, fb->used - fb->saved, fb->saved);
- if (rc < 0)
- return rc;
- fb->saved = fb->used;
- changed = true;
- }
+ /* is sync needed? */
+ if (fb->used == fb->saved && fb->used == fb->size)
+ return 0;
- /* truncate on needed */
- if (fb->used < fb->size) {
- rc = ftruncate(fb->fd, (off_t)fb->used);
- if (rc < 0)
- goto error;
- changed = true;
- }
- fb->size = fb->used;
+ /* open the file */
+ unlink(fb->name);
+ fd = creat(fb->name, 0600);
+ if (fd < 0)
+ goto error;
- /* force synchronisation of the file */
- if (changed) {
- rc = fsync(fb->fd);
- if (rc < 0)
- goto error;
- }
+ /* write unsaved bytes */
+ rcs = write(fd, fb->buffer, fb->used);
+ close(fd);
+ if (rcs < 0)
+ goto error;
+ fb->size = fb->saved = fb->used;
return 0;
+
error:
+ rc = -errno;
fprintf(stderr, "sync of file %s failed: %m", fb->name);
- return -errno;
+ return rc;
}
/** allocate enough memory in 'fb' to store 'count' bytes */
@@ -316,58 +290,13 @@ fbuf_open_identify(
return rc;
}
-
-/* On versions of glibc before 2.27, we must invoke copy_file_range()
- using syscall(2) */
-#include <features.h>
-#if (__GLIBC__ < 2) || (__GLIBC__ == 2 && __GLIBC_MINOR__ < 27)
-#include <syscall.h>
-static
-loff_t
-copy_file_range(
- int fd_in,
- loff_t *off_in,
- int fd_out,
- loff_t *off_out,
- size_t len,
- unsigned int flags
-) {
- loff_t rc;
-
- rc = syscall(__NR_copy_file_range, fd_in, off_in, fd_out,
- off_out, len, flags);
- return rc;
-}
-#endif
-
-
/** make a backup */
int
fbuf_backup(
fbuf_t *fb
) {
- int rc;
- size_t sz;
- ssize_t wsz;
- loff_t ino, outo;
-
- ino = outo = 0;
- sz = fb->size;
- for (;;) {
- wsz = copy_file_range(fb->fd, &ino, fb->backup, &outo, sz, 0);
- if (wsz < 0) {
- if (errno != EINTR)
- return -errno;
- } else {
- sz -= (size_t)wsz;
- if (sz == 0) {
- rc = ftruncate(fb->backup, outo);
- if (rc == 0)
- rc = fsync(fb->backup);
- return rc < 0 ? -errno : 0;
- }
- }
- }
+ unlink(fb->backup);
+ return link(fb->name, fb->backup);
}
/** recover from latest backup */
@@ -375,29 +304,10 @@ int
fbuf_recover(
fbuf_t *fb
) {
- ssize_t ssz;
- struct stat st;
int rc;
- /* get the size */
- rc = fstat(fb->backup, &st);
- if (rc < 0)
- return -errno;
-
- /* ensure space */
- if (st.st_size > UINT32_MAX)
- return -EFBIG;
- rc = fbuf_ensure_capacity(fb, (uint32_t)st.st_size);
- if (rc < 0)
- return rc;
-
- /* read it */
- ssz = pread(fb->backup, fb->buffer, (size_t)st.st_size, 0);
- if (ssz < 0)
- return -errno;
-
- fb->used = (uint32_t)st.st_size;
- fb->saved = fb->size = 0; /* ensure rewrite of restored data */
- return 0;
+ rc = read_file(fb, fb->backup);
+ fb->saved = 0; /* ensure rewrite of restored data */
+ return rc;
}
diff --git a/src/fbuf.h b/src/fbuf.h
index bf7d9c1..43909fa 100644
--- a/src/fbuf.h
+++ b/src/fbuf.h
@@ -22,29 +22,26 @@
*/
struct fbuf
{
- /** filename for messages */
+ /** filename */
char *name;
+ /** backup filename */
+ char *backup;
+
/** in memory copy of the file */
void *buffer;
- /** size saved to the file */
- uint32_t saved;
-
- /** size currently used */
- uint32_t used;
-
/** size currently allocated */
uint32_t capacity;
/** size of the file */
uint32_t size;
- /** opened file descriptor for the file */
- int fd;
+ /** size saved to the file */
+ uint32_t saved;
- /** opened file descriptor for the backup */
- int backup;
+ /** size currently used */
+ uint32_t used;
};
/** short type */
@@ -67,16 +64,6 @@ fbuf_close(
fbuf_t *fb
);
-/** write to file 'fb' at 'offset' the 'count' bytes pointed by 'buffer' */
-extern
-int
-fbuf_write(
- fbuf_t *fb,
- const void *buffer,
- uint32_t count,
- uint32_t offset
-);
-
/** write to file 'fb' the unsaved bytes and flush the content to the file */
extern
int
diff --git a/src/lib-compat.c b/src/lib-compat.c
index b9934af..175ec5f 100644
--- a/src/lib-compat.c
+++ b/src/lib-compat.c
@@ -27,7 +27,6 @@ cynara_initialize(&m_Cynara, nullptr),
cynara_finish(m_Cynara);
cynara_check(m_Cynara,
*/
-#define _GNU_SOURCE
#include <stdbool.h>
#include <stdlib.h>
@@ -148,7 +147,7 @@ struct cynara_admin;
int cynara_admin_initialize(struct cynara_admin **pp_cynara_admin)
{
- return from_status(rcyn_open((rcyn_t**)pp_cynara_admin, rcyn_Admin, 0));
+ return from_status(rcyn_open((rcyn_t**)pp_cynara_admin, rcyn_Admin, 0, 0));
}
int cynara_admin_finish(struct cynara_admin *p_cynara_admin)
@@ -162,17 +161,24 @@ int cynara_admin_set_policies(struct cynara_admin *p_cynara_admin,
{
int rc, rc2;
const struct cynara_admin_policy *p;
+ rcyn_key_t key;
+ rcyn_value_t value;
+ key.session = "*";
+ value.expire = 0;
rc = rcyn_enter((rcyn_t*)p_cynara_admin);
if (rc == 0) {
p = *policies;
while (rc == 0 && p != NULL) {
+ key.client = p->client;
+ key.user = p->user;
+ key.permission = p->privilege;
if (p->result == CYNARA_ADMIN_DELETE)
- rc = rcyn_drop((rcyn_t*)p_cynara_admin,
- 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), 0);
+ rc = rcyn_drop((rcyn_t*)p_cynara_admin, &key);
+ else if (p->result != CYNARA_ADMIN_BUCKET && p->result != CYNARA_ADMIN_NONE) {
+ value.value = to_value(p->result);
+ rc = rcyn_set((rcyn_t*)p_cynara_admin, &key, &value);
+ }
p = *++policies;
}
rc2 = rcyn_leave((rcyn_t*)p_cynara_admin, rc == 0);
@@ -184,14 +190,10 @@ int cynara_admin_set_policies(struct cynara_admin *p_cynara_admin,
static void check_cb(
void *closure,
- const char *client,
- const char *session,
- const char *user,
- const char *permission,
- const char *value,
- time_t expire
+ const rcyn_key_t *key,
+ const rcyn_value_t *value
) {
- *((int*)closure) = from_value(value);
+ *((int*)closure) = from_value(value->value);
}
int cynara_admin_check(struct cynara_admin *p_cynara_admin,
@@ -199,10 +201,11 @@ int cynara_admin_check(struct cynara_admin *p_cynara_admin,
const char *client, const char *user, const char *privilege,
int *result, char **result_extra)
{
+ rcyn_key_t key = { client, "*", user, privilege };
if (result_extra)
*result_extra = NULL;
*result = CYNARA_ADMIN_DENY;
- return from_status(rcyn_get((rcyn_t*)p_cynara_admin, client, "*", user, privilege, check_cb, result));
+ return from_status(rcyn_get((rcyn_t*)p_cynara_admin, &key, check_cb, result));
}
struct list_data
@@ -215,12 +218,8 @@ struct list_data
static void list_cb(
void *closure,
- const char *client,
- const char *session,
- const char *user,
- const char *permission,
- const char *value,
- time_t expire
+ const rcyn_key_t *key,
+ const rcyn_value_t *value
) {
struct list_data *data = closure;
struct cynara_admin_policy *pol;
@@ -233,13 +232,13 @@ static void list_cb(
goto error;
pol->bucket = strdup(data->bucket ?: "");
- pol->client = strdup(client);
- pol->user = strdup(user);
- pol->privilege = strdup(permission);
+ pol->client = strdup(key->client);
+ pol->user = strdup(key->user);
+ pol->privilege = strdup(key->permission);
if (pol->bucket == NULL || pol->client == NULL || pol->user == NULL || pol->privilege == NULL)
goto error;
- pol->result = from_value(value);
+ pol->result = from_value(value->value);
pol->result_extra = 0;
closure = realloc(data->policies, (data->count + 1) * sizeof *data->policies);
if (closure == NULL)
@@ -265,12 +264,13 @@ int cynara_admin_list_policies(struct cynara_admin *p_cynara_admin, const char *
{
int rc;
struct list_data data;
+ rcyn_key_t key = { client, "*", user, privilege };
data.policies = NULL;
data.bucket = bucket && strcmp(bucket, "#") && strcmp(bucket, "*") ? bucket : NULL;
data.count = 0;
data.error = 0;
- rc = rcyn_get((rcyn_t*)p_cynara_admin, client, "*", user, privilege, list_cb, &data);
+ rc = rcyn_get((rcyn_t*)p_cynara_admin, &key, list_cb, &data);
if (rc == 0 && data.error != 0)
rc = data.error;
if (rc == 0 && !data.error) {
@@ -293,11 +293,11 @@ int cynara_admin_erase(struct cynara_admin *p_cynara_admin,
const char *client, const char *user, const char *privilege)
{
int rc, rc2;
+ rcyn_key_t key = { client, "*", user, privilege };
rc = rcyn_enter((rcyn_t*)p_cynara_admin);
if (rc == 0) {
- rc = rcyn_drop((rcyn_t*)p_cynara_admin,
- client, "*", user, privilege);
+ rc = rcyn_drop((rcyn_t*)p_cynara_admin, &key);
rc2 = rcyn_leave((rcyn_t*)p_cynara_admin, rc == 0);
if (rc == 0)
rc = rc2;
@@ -409,7 +409,7 @@ int cynara_async_initialize(cynara_async **pp_cynara, const cynara_async_configu
if (p_cynara == NULL)
ret = CYNARA_API_OUT_OF_MEMORY;
else {
- ret = from_status(rcyn_open(&p_cynara->rcyn, rcyn_Check, p_conf ? p_conf->szcache : 0));
+ ret = from_status(rcyn_open(&p_cynara->rcyn, rcyn_Check, p_conf ? p_conf->szcache : 0, 0));
if (ret != CYNARA_API_SUCCESS)
free(p_cynara);
else {
@@ -447,7 +447,8 @@ void cynara_async_finish(cynara_async *p_cynara)
int cynara_async_check_cache(cynara_async *p_cynara, const char *client, const char *client_session,
const char *user, const char *privilege)
{
- return from_check_status(rcyn_cache_check(p_cynara->rcyn, client, client_session,user, privilege));
+ rcyn_key_t key = { client, client_session, user, privilege };
+ return from_check_status(rcyn_cache_check(p_cynara->rcyn, &key));
}
static void reqcb(void *closure, int status)
@@ -473,6 +474,7 @@ static int create_reqasync(cynara_async *p_cynara, const char *client,
{
int rc;
struct reqasync *req;
+ rcyn_key_t key = { client, client_session, user, privilege };
req = malloc(sizeof *req);
if (req == NULL)
@@ -485,7 +487,7 @@ static int create_reqasync(cynara_async *p_cynara, const char *client,
req->id = ++p_cynara->ids;
req->canceled = false;
- rc = rcyn_async_check(p_cynara->rcyn, client, client_session, user, privilege, simple, reqcb, req);
+ rc = rcyn_async_check(p_cynara->rcyn, &key, simple, reqcb, req);
if (rc == 0)
p_cynara->reqs = req;
else
@@ -555,7 +557,7 @@ int cynara_configuration_set_cache_size(cynara_configuration *p_conf,
int cynara_initialize(cynara **pp_cynara, const cynara_configuration *p_conf)
{
- return from_status(rcyn_open((rcyn_t**)pp_cynara, rcyn_Check, p_conf ? p_conf->szcache : 0));
+ return from_status(rcyn_open((rcyn_t**)pp_cynara, rcyn_Check, p_conf ? p_conf->szcache : 0, 0));
}
int cynara_finish(cynara *p_cynara)
@@ -567,13 +569,15 @@ int cynara_finish(cynara *p_cynara)
int cynara_check(cynara *p_cynara, const char *client, const char *client_session, const char *user,
const char *privilege)
{
- return from_check_status(rcyn_check((rcyn_t*)p_cynara, client, client_session, user, privilege));
+ rcyn_key_t key = { client, client_session, user, privilege };
+ return from_check_status(rcyn_check((rcyn_t*)p_cynara, &key));
}
int cynara_simple_check(cynara *p_cynara, const char *client, const char *client_session,
const char *user, const char *privilege)
{
- return from_check_status(rcyn_test((rcyn_t*)p_cynara, client, client_session, user, privilege));
+ rcyn_key_t key = { client, client_session, user, privilege };
+ return from_check_status(rcyn_test((rcyn_t*)p_cynara, &key));
}
/************************************* CREDS... & SESSION *********************************/
diff --git a/src/main-cynadm.c b/src/main-cynadm.c
index fa44895..1aaedde 100644
--- a/src/main-cynadm.c
+++ b/src/main-cynadm.c
@@ -20,95 +20,59 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <getopt.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*60;
-static const int DAY = 24*60*60;
-static const int WEEK = 7*24*60*60;
-static const int YEAR = 365*24*60*60;
-
-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 'w': r += x * WEEK; 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 >= WEEK) {
- n += snprintf(&buffer[n], sizeof buffer - n, "%lldw",
- (long long)(expire / WEEK));
- expire = expire % WEEK;
- }
- 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;
-}
+#include "rcyn-protocol.h"
+#include "expire.h"
+
+#define _HELP_ 'h'
+#define _SOCKET_ 's'
+#define _VERSION_ 'v'
+
+static
+const char
+shortopts[] = "hs:v";
+
+static
+const struct option
+longopts[] = {
+ { "help", 0, NULL, _HELP_ },
+ { "socket", 1, NULL, _SOCKET_ },
+ { "version", 0, NULL, _VERSION_ },
+ { NULL, 0, NULL, 0 }
+};
+
+static
+const char
+helptxt[] =
+ "\n"
+ "usage: cynadm [options]...\n"
+ "\n"
+ "otpions:\n"
+ " -s, --socket xxx set the base xxx for sockets\n"
+ " (default: %s)\n"
+ " -h, --help print this help and exit\n"
+ " -v, --version print the version and exit\n"
+ "\n"
+;
+
+static
+const char
+versiontxt[] =
+ "cynadm version 1.99.99\n"
+;
+
+static rcyn_t *rcyn;
+static char buffer[4000];
+static char *str[40];
+static int nstr;
+
+rcyn_key_t key;
+rcyn_value_t value;
int plink(int ac, char **av, int *used, int maxi)
{
@@ -127,35 +91,34 @@ 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;
+ key.client = n > 1 ? av[1] : def;
+ key.session = n > 2 ? av[2] : def;
+ key.user = n > 3 ? av[3] : def;
+ key.permission = n > 4 ? av[4] : def;
+ value.value = n > 5 ? av[5] : "no";
+ value.expire = n > 6 ? txt2exp(av[6]) : 0;
- return client && session && user && permission && value && !txt2experr ? 0 : -EINVAL;
+ return key.client && key.session && key.user && key.permission && value.value && value.expire >= 0 ? 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;
+ key.client = n > 1 ? av[1] : def;
+ key.session = n > 2 ? av[2] : def;
+ key.user = n > 3 ? av[3] : def;
+ key.permission = n > 4 ? av[4] : def;
- return client && session && user && permission ? 0 : -EINVAL;
+ return key.client && key.session && key.user && key.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)
+void listcb(void *closure, const rcyn_key_t *k, const rcyn_value_t *v)
{
+ char buffer[100];
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);
+ exp2txt(v->expire, buffer, sizeof buffer);
+ fprintf(stdout, "%s\t%s\t%s\t%s\t%s\t%s\n", k->client, k->session, k->user, k->permission, v->value, buffer);
(*p)++;
}
@@ -166,7 +129,7 @@ int do_list(int ac, char **av)
rc = get_csup(ac, av, &uc, "#");
if (rc == 0) {
count = 0;
- rc = rcyn_get(rcyn, client, session, user, permission, listcb, &count);
+ rc = rcyn_get(rcyn, &key, listcb, &count);
if (rc < 0)
fprintf(stderr, "error %s\n", strerror(-rc));
else
@@ -183,7 +146,7 @@ int do_set(int ac, char **av)
if (rc == 0)
rc = rcyn_enter(rcyn);
if (rc == 0) {
- rc = rcyn_set(rcyn, client, session, user, permission, value, expire);
+ rc = rcyn_set(rcyn, &key, &value);
rcyn_leave(rcyn, !rc);
}
if (rc < 0)
@@ -199,7 +162,7 @@ int do_drop(int ac, char **av)
if (rc == 0)
rc = rcyn_enter(rcyn);
if (rc == 0) {
- rc = rcyn_drop(rcyn, client, session, user, permission);
+ rc = rcyn_drop(rcyn, &key);
rcyn_leave(rcyn, !rc);
}
if (rc < 0)
@@ -207,13 +170,13 @@ int do_drop(int ac, char **av)
return uc;
}
-int do_check(int ac, char **av, int (*f)(rcyn_t*,const char*,const char*,const char*,const char*))
+int do_check(int ac, char **av, int (*f)(rcyn_t*,const rcyn_key_t*))
{
int uc, rc;
rc = get_csup(ac, av, &uc, NULL);
if (rc == 0) {
- rc = f(rcyn, client, session, user, permission);
+ rc = f(rcyn, &key);
if (rc > 0)
fprintf(stdout, "allowed\n");
else if (rc == 0)
@@ -270,16 +233,57 @@ void do_all(int ac, char **av)
int main(int ac, char **av)
{
+ int opt;
int rc;
+ int help = 0;
+ int version = 0;
+ int error = 0;
+ const char *socket = NULL;
+
+ /* scan arguments */
+ for (;;) {
+ opt = getopt_long(ac, av, shortopts, longopts, NULL);
+ if (opt == -1)
+ break;
+ switch(opt) {
+ case _HELP_:
+ help = 1;
+ break;
+ case _SOCKET_:
+ socket = optarg;
+ break;
+ case _VERSION_:
+ version = 1;
+ break;
+ default:
+ error = 1;
+ break;
+ }
+ }
+
+ /* handles help, version, error */
+ if (help) {
+ fprintf(stdout, helptxt, rcyn_default_admin_socket_spec);
+ return 0;
+ }
+ if (version) {
+ fprintf(stdout, versiontxt);
+ return 0;
+ }
+ if (error)
+ return 1;
+
+ /* initialize server */
signal(SIGPIPE, SIG_IGN); /* avoid SIGPIPE! */
- rc = rcyn_open(&rcyn, rcyn_Admin, 5000);
+ rc = rcyn_open(&rcyn, rcyn_Admin, 5000, socket);
if (rc < 0) {
fprintf(stderr, "initialisation failed: %s\n", strerror(-rc));
return 1;
}
- if (ac > 1) {
- do_all(ac - 1, av + 1);
+
+ if (optind < ac) {
+ do_all(ac - optind, av + optind);
return 0;
}
@@ -301,4 +305,3 @@ int main(int ac, char **av)
}
return 0;
}
-
diff --git a/src/main-cynarad.c b/src/main-cynarad.c
index 1829d74..ac8106e 100644
--- a/src/main-cynarad.c
+++ b/src/main-cynarad.c
@@ -15,8 +15,6 @@
* limitations under the License.
*/
-#define _GNU_SOURCE
-
#include <stdlib.h>
#include <stdint.h>
#include <stdbool.h>
@@ -38,16 +36,15 @@
#include <systemd/sd-daemon.h>
#endif
+#include "data.h"
#include "db.h"
-#include "cyn.h"
#include "rcyn-server.h"
+#include "rcyn-protocol.h"
+#include "dbinit.h"
#if !defined(DEFAULT_DB_DIR)
# define DEFAULT_DB_DIR "/var/lib/cynara"
#endif
-#if !defined(DEFAULT_SOCKET_DIR)
-# define DEFAULT_SOCKET_DIR "/var/run/cynara"
-#endif
#if !defined(DEFAULT_INIT_FILE)
# define DEFAULT_INIT_FILE "/etc/security/cynara.initial"
#endif
@@ -113,13 +110,13 @@ helptxt[] =
" -g, --group xxx set the group\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"
+ " -d, --dbdir xxx set the directory of database\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: %s)\n"
" -M, --make-socket-dir make the socket directory\n"
" -O, --own-socket-dir set user and group on socket directory\n"
"\n"
@@ -136,7 +133,7 @@ versiontxt[] =
static int isid(const char *text);
static void ensure_directory(const char *path, int uid, int gid);
-static void initdb(const char *path);
+
int main(int ac, char **av)
{
int opt;
@@ -160,7 +157,7 @@ int main(int ac, char **av)
struct group *gr;
cap_t caps = { 0 };
rcyn_server_t *server;
- char *spec_socket_admin, *spec_socket_check;
+ char *spec_socket_admin, *spec_socket_check, *spec_socket_agent;
/* scan arguments */
for (;;) {
@@ -214,8 +211,12 @@ int main(int ac, char **av)
}
/* handles help, version, error */
- if (help | version) {
- fprintf(stdout, "%s", help ? helptxt : versiontxt);
+ if (help) {
+ fprintf(stdout, helptxt, rcyn_default_socket_dir);
+ return 0;
+ }
+ if (version) {
+ fprintf(stdout, versiontxt);
return 0;
}
if (error)
@@ -228,21 +229,23 @@ int main(int ac, char **av)
/* set the defaults */
dbdir = dbdir ?: DEFAULT_DB_DIR;
- socketdir = socketdir ?: DEFAULT_SOCKET_DIR;
+ socketdir = socketdir ?: rcyn_default_socket_dir;
user = user ?: DEFAULT_CYNARA_USER;
group = group ?: DEFAULT_CYNARA_GROUP;
init = init ?: DEFAULT_INIT_FILE;
/* compute socket specs */
- spec_socket_admin = spec_socket_check = NULL;
+ spec_socket_admin = spec_socket_check = spec_socket_agent = 0;
if (systemd) {
spec_socket_admin = strdup("sd:admin");
spec_socket_check = strdup("sd:check");
+ spec_socket_agent = strdup("sd:agent");
} else {
- rc = asprintf(&spec_socket_admin, "unix:%s/cynara.admin", socketdir);
- rc = asprintf(&spec_socket_check, "unix:%s/cynara.check", socketdir);
+ rc = asprintf(&spec_socket_admin, "%s:%s/%s", rcyn_default_socket_scheme, socketdir, rcyn_default_admin_socket_base);
+ rc = asprintf(&spec_socket_check, "%s:%s/%s", rcyn_default_socket_scheme, socketdir, rcyn_default_check_socket_base);
+ rc = asprintf(&spec_socket_agent, "%s:%s/%s", rcyn_default_socket_scheme, socketdir, rcyn_default_agent_socket_base);
}
- if (spec_socket_admin == NULL || spec_socket_check == NULL) {
+ if (!spec_socket_admin || !spec_socket_check || !spec_socket_agent) {
fprintf(stderr, "can't make socket paths\n");
return 1;
}
@@ -296,34 +299,37 @@ int main(int ac, char **av)
cap_clear(caps);
rc = cap_set_proc(caps);
+ /* initialize server */
+ signal(SIGPIPE, SIG_IGN); /* avoid SIGPIPE! */
+ rc = rcyn_server_create(&server, spec_socket_admin, spec_socket_check, spec_socket_agent);
+ if (rc < 0) {
+ fprintf(stderr, "can't initialise server: %m\n");
+ return 1;
+ }
+
/* connection to the database */
- rc = db_open(dbdir);
+ rc = chdir(dbdir);
if (rc < 0) {
- fprintf(stderr, "can not open database: %m\n");
+ fprintf(stderr, "can not chroot to database directory %s: %m\n", dbdir);
+ return 1;
+ }
+ rc = db_open(".");
+ if (rc < 0) {
+ fprintf(stderr, "can not open database of directory %s: %m\n", dbdir);
return 1;
}
/* initialisation of the database */
if (db_is_empty()) {
- initdb(init);
+ rc = dbinit_add_file(init);
if (rc == 0)
rc = db_sync();
- if (rc == 0)
- rc = db_backup();
if (rc < 0) {
fprintf(stderr, "can't initialise database: %m\n");
return 1;
}
}
- /* initialize server */
- signal(SIGPIPE, SIG_IGN); /* avoid SIGPIPE! */
- rc = rcyn_server_create(&server, spec_socket_admin, spec_socket_check);
- if (rc < 0) {
- fprintf(stderr, "can't initialise server: %m\n");
- return 1;
- }
-
/* ready ! */
#if defined(WITH_SYSTEMD_ACTIVATION)
if (systemd)
@@ -405,7 +411,7 @@ static void ensuredir(char *path, int length, int uid, int gid)
path[n] = '/';
n = (int)strlen(path);
} else if (errno == ENOENT) {
- /* a part of the path doesn't exist, try to create it */
+ /* a part of the path doesn't exist, try to create it */
e = enddir(path);
if (!e) {
/* can't create it because at root */
@@ -429,95 +435,10 @@ static void ensure_directory(const char *path, int uid, int gid)
l = strlen(path);
if (l > INT_MAX) {
/* ?!?!?!? *#@! */
- fprintf(stderr, "path toooooo long\n");
+ fprintf(stderr, "path toooooo long (%s)\n", path);
exit(1);
}
p = strndupa(path, l);
ensuredir(p, (int)l, uid, gid);
}
-time_t txt2exp(const char *txt)
-{
- static const int MIN = 60;
- static const int HOUR = 60*60;
- static const int DAY = 24*60*60;
- static const int WEEK = 7*24*60*60;
- static const int YEAR = 365*24*60*60;
-
- 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 'w': r += x *= WEEK; 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;
- char *item[10];
- char buffer[2048];
- time_t expire;
- FILE *f;
-
- f = fopen(path, "r");
- if (f == NULL) {
- fprintf(stderr, "can't open file %s\n", path);
- exit(1);
- }
-
- lino = 0;
- while(fgets(buffer, sizeof buffer, f)) {
- lino++;
- item[0] = strtok(buffer, " \t\n\r");
- if (item[0] && item[0][0] != '#') {
- item[1] = strtok(NULL, " \t\n\r");
- item[2] = strtok(NULL, " \t\n\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[5] == NULL) {
- fprintf(stderr, "field missing (%s:%d)\n", path, lino);
- exit(1);
- } else if (item[6] != NULL && item[6][0] != '#') {
- fprintf(stderr, "extra field (%s:%d)\n", path, lino);
- exit(1);
- }
- 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], item[4], expire);
- if (rc < 0) {
- fprintf(stderr, "can't set (%s:%d)\n", path, lino);
- exit(1);
- }
- }
- }
- if (!feof(f)) {
- fprintf(stderr, "error while reading file %s\n", path);
- exit(1);
- }
- fclose(f);
-}
-
diff --git a/src/pollitem.c b/src/pollitem.c
new file mode 100644
index 0000000..d183594
--- /dev/null
+++ b/src/pollitem.c
@@ -0,0 +1,91 @@
+/*
+ * 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 <sys/epoll.h>
+
+/*
+#include <stddef.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <poll.h>
+#include <limits.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+*/
+
+#include "pollitem.h"
+
+static
+int
+pollitem_do(
+ pollitem_t *pollitem,
+ uint32_t events,
+ int pollfd,
+ int op
+) {
+ struct epoll_event ev = { .events = events, .data.ptr = pollitem };
+ return epoll_ctl(pollfd, op, pollitem->fd, &ev);
+}
+
+int
+pollitem_add(
+ pollitem_t *pollitem,
+ uint32_t events,
+ int pollfd
+) {
+ return pollitem_do(pollitem, events, pollfd, EPOLL_CTL_ADD);
+}
+
+int
+pollitem_mod(
+ pollitem_t *pollitem,
+ uint32_t events,
+ int pollfd
+) {
+ return pollitem_do(pollitem, events, pollfd, EPOLL_CTL_MOD);
+}
+
+int
+pollitem_del(
+ pollitem_t *pollitem,
+ int pollfd
+) {
+ return pollitem_do(pollitem, 0, pollfd, EPOLL_CTL_DEL);
+}
+
+int
+pollitem_wait_dispatch(
+ int pollfd,
+ int timeout
+) {
+ int rc;
+ struct epoll_event ev;
+ pollitem_t *pi;
+
+ rc = epoll_wait(pollfd, &ev, 1, timeout);
+ if (rc == 1) {
+ pi = ev.data.ptr;
+ pi->handler(pi, ev.events, pollfd);
+ }
+ return rc;
+}
diff --git a/src/pollitem.h b/src/pollitem.h
new file mode 100644
index 0000000..a60b7b8
--- /dev/null
+++ b/src/pollitem.h
@@ -0,0 +1,61 @@
+/*
+ * 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.
+ */
+
+/** structure for using epoll easily */
+typedef struct pollitem pollitem_t;
+
+struct pollitem
+{
+ /** callback on event */
+ void (*handler)(pollitem_t *pollitem, uint32_t events, int pollfd);
+
+ /** data */
+ void *closure;
+
+ /** file */
+ int fd;
+};
+
+extern
+int
+pollitem_add(
+ pollitem_t *pollitem,
+ uint32_t events,
+ int pollfd
+);
+
+extern
+int
+pollitem_mod(
+ pollitem_t *pollitem,
+ uint32_t events,
+ int pollfd
+);
+
+extern
+int
+pollitem_del(
+ pollitem_t *pollitem,
+ int pollfd
+);
+
+extern
+int
+pollitem_wait_dispatch(
+ int pollfd,
+ int timeout
+);
diff --git a/src/prot.c b/src/prot.c
index bb58acf..711d084 100644
--- a/src/prot.c
+++ b/src/prot.c
@@ -15,8 +15,6 @@
* limitations under the License.
*/
-#define _GNU_SOURCE
-
#include <stdlib.h>
#include <limits.h>
#include <stdarg.h>
@@ -37,6 +35,8 @@ struct buf
/** a count */
unsigned count;
+ /* TODO: add a 3rd unsigned for improving management of read and write */
+
/** a fixed size content */
char content[MAXBUFLEN];
};
@@ -62,77 +62,83 @@ struct prot
/** output buf, pos is to be written position */
buf_t outbuf;
+ /** count of pending output fields */
+ unsigned outfields;
+
+ /** cancel index value value */
+ unsigned cancelidx;
+
/** the fields */
fields_t fields;
};
/**
- * Put the 'count' in 'fields' to the 'buf'
+ * Put the 'car' into the 'buf'
* returns:
* - 0 on success
- * - -EINVAL if the count of fields is too big
* - -ECANCELED if there is not enought space in the buffer
*/
static
int
-buf_put_fields(
+buf_put_car(
buf_t *buf,
- unsigned count,
- const char **fields
+ char car
) {
- unsigned ifield, pos, remain;
- const char *t;
- char c;
+ unsigned pos;
- /* check the count of fields */
- if (count > MAXARGS)
- return -EINVAL;
+ pos = buf->count;
+ if (pos >= MAXBUFLEN)
+ return -ECANCELED;
+
+ buf->count = pos + 1;
+ pos += buf->pos;
+ if (pos >= MAXBUFLEN)
+ pos -= MAXBUFLEN;
+ buf->content[pos] = car;
+ return 0;
+}
+
+
+/**
+ * Put the 'string' into the 'buf' escaping it at need
+ * returns:
+ * - 0 on success
+ * - -ECANCELED if there is not enought space in the buffer
+ */
+static
+int
+buf_put_string(
+ buf_t *buf,
+ const char *string
+) {
+ unsigned pos, remain;
+ char c;
- /* get the writing position and the free count */
- pos = buf->pos + buf->count;
+ remain = buf->count;
+ pos = buf->pos + remain;
if (pos >= MAXBUFLEN)
pos -= MAXBUFLEN;
- remain = MAXBUFLEN - buf->count;
+ remain = MAXBUFLEN - remain;
- /* put all fields */
- for (ifield = 0 ; ifield < count ; ifield++) {
- /* prepend the field separator if needed */
- if (ifield) {
+ /* put all chars of the string */
+ while((c = *string++)) {
+ /* escape special characters */
+ if (c == FS || c == RS || c == ESC) {
if (!remain--)
goto cancel;
- buf->content[pos++] = FS;
+ buf->content[pos++] = ESC;
if (pos == MAXBUFLEN)
pos = 0;
}
- /* put the field if any (NULL aliases "") */
- t = fields[ifield];
- if (t) {
- /* put all chars of the field */
- while((c = *t++)) {
- /* escape special characters */
- if (c == FS || c == RS || c == ESC) {
- if (!remain--)
- goto cancel;
- buf->content[pos++] = ESC;
- if (pos == MAXBUFLEN)
- pos = 0;
- }
- /* put the char */
- if (!remain--)
- goto cancel;
- buf->content[pos++] = c;
- if (pos == MAXBUFLEN)
- pos = 0;
- }
- }
+ /* put the char */
+ if (!remain--)
+ goto cancel;
+ buf->content[pos++] = c;
+ if (pos == MAXBUFLEN)
+ pos = 0;
}
- /* put the end indicator */
- if (!remain--)
- goto cancel;
- buf->content[pos] = RS;
-
/* record the new values */
buf->count = MAXBUFLEN - remain;
return 0;
@@ -340,15 +346,80 @@ prot_reset(
/* initialisation of the structure */
prot->inbuf.pos = prot->inbuf.count = 0;
prot->outbuf.pos = prot->outbuf.count = 0;
+ prot->outfields = 0;
prot->fields.count = -1;
}
+void
+prot_put_cancel(
+ prot_t *prot
+) {
+ unsigned count;
+
+ if (prot->outfields) {
+ count = prot->cancelidx - prot->outbuf.pos;
+ prot->outbuf.count = count > MAXBUFLEN ? count - MAXBUFLEN : count;
+ prot->outfields = 0;
+ }
+}
+
+int
+prot_put_end(
+ prot_t *prot
+) {
+ int rc;
+
+ if (!prot->outfields)
+ rc = 0;
+ else {
+ rc = buf_put_car(&prot->outbuf, RS);
+ prot->outfields = 0;
+ }
+ return rc;
+}
+
+int
+prot_put_field(
+ prot_t *prot,
+ const char *field
+) {
+ int rc;
+
+ if (prot->outfields++)
+ rc = buf_put_car(&prot->outbuf, FS);
+ else {
+ prot->cancelidx = prot->outbuf.pos + prot->outbuf.count;
+ rc = 0;
+ }
+ if (rc >= 0 && field)
+ rc = buf_put_string(&prot->outbuf, field);
+
+ return rc;
+}
+
+int
+prot_put_fields(
+ prot_t *prot,
+ unsigned count,
+ const char **fields
+) {
+ int rc;
+ if (!count)
+ rc = 0;
+ else {
+ rc = prot_put_field(prot, *fields);
+ while (rc >= 0 && --count)
+ rc = prot_put_field(prot, *++fields);
+ }
+ return rc;
+}
+
/**
* Put protocol encoded 'count' 'fields' to the output buffer
* returns:
* - 0 on success
* - -EINVAL if the count of fields is too big
- * - -ECANCELED if there is not enought space in the buffer
+ * - -ECANCELED if there is not enough space in the buffer
*/
int
prot_put(
@@ -356,7 +427,16 @@ prot_put(
unsigned count,
const char **fields
) {
- return buf_put_fields(&prot->outbuf, count, fields);
+ int rc = 0;
+ unsigned index = 0;
+
+ while(!rc && index < count)
+ rc = prot_put_field(prot, fields[index++]);
+ if (rc)
+ prot_put_cancel(prot);
+ else
+ rc = prot_put_end(prot);
+ return rc;
}
/**
@@ -371,21 +451,21 @@ prot_putx(
prot_t *prot,
...
) {
- const char *p, *fields[MAXARGS];
- unsigned n;
+ int rc = 0;
va_list l;
+ const char *p;
va_start(l, prot);
- n = 0;
p = va_arg(l, const char *);
- while (p) {
- if (n == MAXARGS)
- return -EINVAL;
- fields[n++] = p;
+ while(!rc && p) {
+ rc = prot_put_field(prot, p);
p = va_arg(l, const char *);
}
- va_end(l);
- return prot_put(prot, n, fields);
+ if (rc)
+ prot_put_cancel(prot);
+ else
+ rc = prot_put_end(prot);
+ return rc;
}
/**
diff --git a/src/prot.h b/src/prot.h
index b9f83ea..b961a37 100644
--- a/src/prot.h
+++ b/src/prot.h
@@ -46,6 +46,33 @@ prot_reset(
);
extern
+void
+prot_put_cancel(
+ prot_t *prot
+);
+
+extern
+int
+prot_put_end(
+ prot_t *prot
+);
+
+extern
+int
+prot_put_field(
+ prot_t *prot,
+ const char *field
+);
+
+extern
+int
+prot_put_fields(
+ prot_t *prot,
+ unsigned count,
+ const char **fields
+);
+
+extern
int
prot_put(
prot_t *prot,
diff --git a/src/queue.c b/src/queue.c
index 0699bb1..b02d7da 100644
--- a/src/queue.c
+++ b/src/queue.c
@@ -21,6 +21,7 @@
#include <string.h>
#include <errno.h>
+#include "data.h"
#include "db.h"
#define DROP 0
@@ -123,34 +124,27 @@ qput_string(
int
queue_drop(
- const char *client,
- const char *session,
- const char *user,
- const char *permission
+ const data_key_t *key
) {
- return qput_string(client)
- && qput_string(session)
- && qput_string(user)
- && qput_string(permission)
+ return qput_string(key->client)
+ && qput_string(key->session)
+ && qput_string(key->user)
+ && qput_string(key->permission)
&& qput_string(0)
? 0 : -(errno = ENOMEM);
}
int
queue_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
) {
- return qput_string(client)
- && qput_string(session)
- && qput_string(user)
- && qput_string(permission)
- && qput_string(value)
- && qput_time(expire)
+ return qput_string(key->client)
+ && qput_string(key->session)
+ && qput_string(key->user)
+ && qput_string(key->permission)
+ && qput_string(value->value)
+ && qput_time(value->expire)
? 0 : -(errno = ENOMEM);
}
@@ -165,27 +159,23 @@ int
queue_play(
) {
int rc, rc2;
- const char *client;
- const char *session;
- const char *user;
- const char *permission;
- const char *value;
- time_t expire;
+ data_key_t key;
+ data_value_t value;
rc = 0;
queue.read = 0;
while (queue.read < queue.write) {
rc2 = -EINVAL;
- if (qget_string(&client)
- && qget_string(&session)
- && qget_string(&user)
- && qget_string(&permission)
- && qget_string(&value)) {
- if (!value[0])
- rc2 = db_drop(client, session, user, permission);
+ if (qget_string(&key.client)
+ && qget_string(&key.session)
+ && qget_string(&key.user)
+ && qget_string(&key.permission)
+ && qget_string(&value.value)) {
+ if (!value.value[0])
+ rc2 = db_drop(&key);
else {
- if (qget_time(&expire))
- rc2 = db_set(client, session, user, permission, value, expire);
+ if (qget_time(&value.expire))
+ rc2 = db_set(&key, &value);
}
}
if (rc2 != 0 && rc == 0)
diff --git a/src/queue.h b/src/queue.h
index a9fc454..7efc1f8 100644
--- a/src/queue.h
+++ b/src/queue.h
@@ -19,21 +19,14 @@
extern
int
queue_drop(
- const char *client,
- const char *session,
- const char *user,
- const char *permission
+ const data_key_t *key
);
extern
int
queue_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
);
extern
diff --git a/src/rcyn-client.c b/src/rcyn-client.c
index 47a5798..c5fda4b 100644
--- a/src/rcyn-client.c
+++ b/src/rcyn-client.c
@@ -15,8 +15,6 @@
* limitations under the License.
*/
-#define _GNU_SOURCE
-
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
@@ -76,6 +74,9 @@ struct rcyn
/** type of link */
rcyn_type_t type;
+ /** spec of the socket */
+ const char *socketspec;
+
/** protocol manager object */
prot_t *prot;
@@ -117,8 +118,10 @@ flushw(
int rc;
struct pollfd pfd;
- rc = prot_should_write(rcyn->prot);
- while (rc) {
+ for (;;) {
+ rc = prot_should_write(rcyn->prot);
+ if (!rc)
+ break;
rc = prot_write(rcyn->prot, rcyn->fd);
if (rc == -EAGAIN) {
pfd.fd = rcyn->fd;
@@ -130,7 +133,6 @@ flushw(
if (rc < 0) {
break;
}
- rc = prot_should_write(rcyn->prot);
}
return rc;
}
@@ -142,41 +144,99 @@ flushw(
*/
static
int
-putx(
+putxkv(
rcyn_t *rcyn,
- ...
+ const char *command,
+ const char *optarg,
+ const rcyn_key_t *optkey,
+ const rcyn_value_t *optval
) {
- const char *p, *fields[MAXARGS];
- unsigned n;
- va_list l;
- int rc;
-
- /* reconstruct the array of arguments */
- va_start(l, rcyn);
- n = 0;
- p = va_arg(l, const char *);
- while (p && n < MAXARGS) {
- fields[n++] = p;
- p = va_arg(l, const char *);
- }
- va_end(l);
+ int rc, trial;
+ prot_t *prot;
+ char text[30];
- /* put it to the output buffer */
- rc = prot_put(rcyn->prot, n, fields);
- if (rc == -ECANCELED) {
- /* not enough room in the buffer, flush it */
- rc = flushw(rcyn);
- if (rc == 0)
- rc = prot_put(rcyn->prot, n, fields);
- }
- /* client always flushes */
- if (rc == 0) {
- rcyn->pending++;
+ prot = rcyn->prot;
+ for(trial = 0 ; ; trial++) {
+ rc = prot_put_field(prot, command);
+ if (!rc && optarg)
+ rc = prot_put_field(prot, optarg);
+ if (!rc && optkey) {
+ rc = prot_put_field(prot, optkey->client);
+ if (!rc)
+ rc = prot_put_field(prot, optkey->session);
+ if (!rc)
+ rc = prot_put_field(prot, optkey->user);
+ if (!rc)
+ rc = prot_put_field(prot, optkey->permission);
+ }
+ if (!rc && optval) {
+ rc = prot_put_field(prot, optval->value);
+ if (!rc) {
+ if (!optval->expire)
+ text[0] = 0;
+ else
+ snprintf(text, sizeof text, "%lld", (long long)optval->expire);
+ rc = prot_put_field(prot, text);
+ }
+ }
+ if (!rc)
+ rc = prot_put_end(prot);
+ if (!rc) {
+ /* client always flushes */
+ rcyn->pending++;
+ return flushw(rcyn);
+ }
+ prot_put_cancel(prot);
+ if (trial >= 1)
+ return rc;
rc = flushw(rcyn);
+ if (rc)
+ return rc;
}
- return rc;
}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
static
int
wait_input(
@@ -342,26 +402,18 @@ connection(
rcyn_t *rcyn
) {
int rc;
- const char *spec;
-
- /* socket spec */
- switch(rcyn->type) {
- default:
- case rcyn_Check: spec = rcyn_default_check_socket_spec; break;
- case rcyn_Admin: spec = rcyn_default_admin_socket_spec; break;
- }
/* init the client */
rcyn->pending = 0;
rcyn->reply.count = -1;
cache_clear(rcyn->cache);
prot_reset(rcyn->prot);
- rcyn->fd = socket_open(spec, 0);
+ rcyn->fd = socket_open(rcyn->socketspec, 0);
if (rcyn->fd < 0)
return -errno;
/* negociate the protocol */
- rc = putx(rcyn, _rcyn_, "1", NULL);
+ rc = putxkv(rcyn, _rcyn_, "1", 0, 0);
if (rc >= 0) {
rc = wait_pending_reply(rcyn);
if (rc >= 0) {
@@ -395,13 +447,14 @@ int
rcyn_open(
rcyn_t **prcyn,
rcyn_type_t type,
- uint32_t cache_size
+ uint32_t cache_size,
+ const char *socketspec
) {
rcyn_t *rcyn;
int rc;
/* allocate the structure */
- *prcyn = rcyn = malloc(sizeof *rcyn);
+ *prcyn = rcyn = malloc(sizeof *rcyn + (socketspec ? strlen(socketspec) : 0));
if (rcyn == NULL) {
rc = -ENOMEM;
goto error;
@@ -412,9 +465,21 @@ rcyn_open(
if (rc < 0)
goto error2;
+ /* socket spec */
+ if (socketspec)
+ strcpy((char*)(rcyn+1), socketspec);
+ else
+ switch(rcyn->type) {
+ default:
+ case rcyn_Check: socketspec = rcyn_default_check_socket_spec; break;
+ case rcyn_Admin: socketspec = rcyn_default_admin_socket_spec; break;
+ case rcyn_Agent: socketspec = rcyn_default_agent_socket_spec; break;
+ }
+
/* record type and weakly create cache */
cache_create(&rcyn->cache, cache_size < MIN_CACHE_SIZE ? MIN_CACHE_SIZE : cache_size);
rcyn->type = type;
+ rcyn->socketspec = socketspec;
rcyn->async.controlcb = NULL;
rcyn->async.closure = 0;
rcyn->async.requests = NULL;
@@ -457,7 +522,7 @@ rcyn_enter(
if (rc < 0)
return rc;
- rc = putx(rcyn, _enter_, NULL);
+ rc = putxkv(rcyn, _enter_, 0, 0, 0);
if (rc >= 0)
rc = wait_done(rcyn);
return rc;
@@ -478,7 +543,7 @@ rcyn_leave(
if (rc < 0)
return rc;
- rc = putx(rcyn, _leave_, commit ? _commit_ : NULL/*default: rollback*/, NULL);
+ rc = putxkv(rcyn, _leave_, commit ? _commit_ : 0/*default: rollback*/, 0, 0);
if (rc >= 0)
rc = wait_done(rcyn);
return rc;
@@ -488,10 +553,7 @@ static
int
check_or_test(
rcyn_t *rcyn,
- const char *client,
- const char *session,
- const char *user,
- const char *permission,
+ const rcyn_key_t *key,
const char *action
) {
int rc;
@@ -507,19 +569,19 @@ check_or_test(
flushr(rcyn);
/* check cache item */
- rc = cache_search(rcyn->cache, client, session, user, permission);
+ rc = cache_search(rcyn->cache, key);
if (rc >= 0)
return rc;
/* send the request */
- rc = putx(rcyn, action, client, session, user, permission, NULL);
+ rc = putxkv(rcyn, action, 0, key, 0);
if (rc >= 0) {
/* get the response */
rc = wait_pending_reply(rcyn);
if (rc >= 0) {
rc = status_check(rcyn, &expire);
if (rc >= 0)
- cache_put(rcyn->cache, client, session, user, permission, rc, expire);
+ cache_put(rcyn->cache, key, rc, expire);
}
}
return rc;
@@ -528,37 +590,25 @@ check_or_test(
int
rcyn_check(
rcyn_t *rcyn,
- const char *client,
- const char *session,
- const char *user,
- const char *permission
+ const rcyn_key_t *key
) {
- return check_or_test(rcyn, client, session, user, permission, _check_);
+ return check_or_test(rcyn, key, _check_);
}
int
rcyn_test(
rcyn_t *rcyn,
- const char *client,
- const char *session,
- const char *user,
- const char *permission
+ const rcyn_key_t *key
) {
- return check_or_test(rcyn, client, session, user, permission, _test_);
+ return check_or_test(rcyn, key, _test_);
}
int
rcyn_set(
rcyn_t *rcyn,
- const char *client,
- const char *session,
- const char *user,
- const char *permission,
- const char *value,
- time_t expire
+ const rcyn_key_t *key,
+ const rcyn_value_t *value
) {
- char text[30];
- const char *exp;
int rc;
if (rcyn->type != rcyn_Admin)
@@ -569,13 +619,7 @@ rcyn_set(
if (rc < 0)
return rc;
- 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);
+ rc = putxkv(rcyn, _set_, 0, key, value);
if (rc >= 0)
rc = wait_done(rcyn);
return rc;
@@ -584,22 +628,17 @@ rcyn_set(
int
rcyn_get(
rcyn_t *rcyn,
- const char *client,
- const char *session,
- const char *user,
- const char *permission,
+ const rcyn_key_t *key,
void (*callback)(
void *closure,
- const char *client,
- const char *session,
- const char *user,
- const char *permission,
- const char *value,
- time_t expire
+ const rcyn_key_t *key,
+ const rcyn_value_t *value
),
void *closure
) {
int rc;
+ rcyn_key_t k;
+ rcyn_value_t v;
if (rcyn->type != rcyn_Admin)
return -EPERM;
@@ -609,17 +648,17 @@ rcyn_get(
if (rc < 0)
return rc;
- rc = putx(rcyn, _get_, client, session, user, permission, NULL);
+ rc = putxkv(rcyn, _get_, 0, key, 0);
if (rc >= 0) {
rc = wait_reply(rcyn, true);
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],
- rcyn->reply.fields[5],
- rc == 6 ? 0 : (time_t)strtoll(rcyn->reply.fields[6], NULL, 10));
+ k.client = rcyn->reply.fields[1];
+ k.session = rcyn->reply.fields[2];
+ k.user = rcyn->reply.fields[3];
+ k.permission = rcyn->reply.fields[4];
+ v.value = rcyn->reply.fields[5];
+ v.expire = rc == 6 ? 0 : (time_t)strtoll(rcyn->reply.fields[6], NULL, 10);
+ callback(closure, &k, &v);
rc = wait_reply(rcyn, true);
}
rc = status_done(rcyn);
@@ -630,10 +669,7 @@ rcyn_get(
int
rcyn_drop(
rcyn_t *rcyn,
- const char *client,
- const char *session,
- const char *user,
- const char *permission
+ const rcyn_key_t *key
) {
int rc;
@@ -645,7 +681,7 @@ rcyn_drop(
if (rc < 0)
return rc;
- rc = putx(rcyn, _drop_, client, session, user, permission, NULL);
+ rc = putxkv(rcyn, _drop_, 0, key, 0);
if (rc >= 0)
rc = wait_done(rcyn);
return rc;
@@ -671,12 +707,9 @@ rcyn_cache_clear(
int
rcyn_cache_check(
rcyn_t *rcyn,
- const char *client,
- const char *session,
- const char *user,
- const char *permission
+ const rcyn_key_t *key
) {
- return cache_search(rcyn->cache, client, session, user, permission);
+ return cache_search(rcyn->cache, key);
}
@@ -712,8 +745,8 @@ rcyn_async_process(
int rc;
const char *first;
asreq_t *ar;
- const char *client, *session, *user, *permission;
time_t expire;
+ rcyn_key_t key;
for (;;) {
/* non blocking wait for a reply */
@@ -740,11 +773,11 @@ rcyn_async_process(
rcyn->async.requests = ar->next;
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, expire);
+ key.client = (const char*)(ar + 1);
+ key.session = &key.client[1 + strlen(key.client)];
+ key.user = &key.session[1 + strlen(key.session)];
+ key.permission = &key.user[1 + strlen(key.user)];
+ cache_put(rcyn->cache, &key, rc, expire);
}
ar->callback(ar->closure, rc);
free(ar);
@@ -754,10 +787,7 @@ rcyn_async_process(
int
rcyn_async_check(
rcyn_t *rcyn,
- const char *client,
- const char *session,
- const char *user,
- const char *permission,
+ const rcyn_key_t *key,
bool simple,
void (*callback)(
void *closure,
@@ -772,7 +802,7 @@ rcyn_async_check(
return rc;
/* allocate */
- ar = malloc(sizeof *ar + strlen(client) + strlen(session) + strlen(user) + strlen(permission) + 4);
+ ar = malloc(sizeof *ar + strlen(key->client) + strlen(key->session) + strlen(key->user) + strlen(key->permission) + 4);
if (ar == NULL)
return -ENOMEM;
@@ -780,11 +810,10 @@ rcyn_async_check(
ar->next = NULL;
ar->callback = callback;
ar->closure = closure;
- stpcpy(1 + stpcpy(1 + stpcpy(1 + stpcpy((char*)(ar + 1), client), session), user), permission);
+ stpcpy(1 + stpcpy(1 + stpcpy(1 + stpcpy((char*)(ar + 1), key->client), key->session), key->user), key->permission);
/* send the request */
- rc = putx(rcyn, simple ? _test_ : _check_,
- client, session, user, permission, NULL);
+ rc = putxkv(rcyn, simple ? _test_ : _check_, 0, key, 0);
if (rc >= 0)
rc = flushw(rcyn);
if (rc < 0) {
@@ -800,4 +829,3 @@ rcyn_async_check(
return 0;
}
-
diff --git a/src/rcyn-client.h b/src/rcyn-client.h
index 611f843..48ecbf6 100644
--- a/src/rcyn-client.h
+++ b/src/rcyn-client.h
@@ -18,20 +18,36 @@
#pragma once
-typedef enum rcyn_type {
- rcyn_Check,
- rcyn_Admin
-} rcyn_type_t;
-
-struct rcyn;
typedef struct rcyn rcyn_t;
+typedef enum rcyn_type rcyn_type_t;
+typedef struct rcyn_key rcyn_key_t;
+typedef struct rcyn_value rcyn_value_t;
+
+enum rcyn_type {
+ rcyn_Check,
+ rcyn_Admin,
+ rcyn_Agent
+};
+
+struct rcyn_key {
+ const char *client;
+ const char *session;
+ const char *user;
+ const char *permission;
+};
+
+struct rcyn_value {
+ const char *value;
+ time_t expire;
+};
extern
int
rcyn_open(
rcyn_t **rcyn,
rcyn_type_t type,
- uint32_t cache_size
+ uint32_t cache_size,
+ const char *socketspec
);
extern
@@ -57,50 +73,33 @@ extern
int
rcyn_check(
rcyn_t *rcyn,
- const char *client,
- const char *session,
- const char *user,
- const char *permission
+ const rcyn_key_t *key
);
extern
int
rcyn_test(
rcyn_t *rcyn,
- const char *client,
- const char *session,
- const char *user,
- const char *permission
+ const rcyn_key_t *key
);
extern
int
rcyn_set(
rcyn_t *rcyn,
- const char *client,
- const char *session,
- const char *user,
- const char *permission,
- const char *value,
- time_t expire
+ const rcyn_key_t *key,
+ const rcyn_value_t *value
);
extern
int
rcyn_get(
rcyn_t *rcyn,
- const char *client,
- const char *session,
- const char *user,
- const char *permission,
+ const rcyn_key_t *key,
void (*callback)(
void *closure,
- const char *client,
- const char *session,
- const char *user,
- const char *permission,
- const char *value,
- time_t expire
+ const rcyn_key_t *key,
+ const rcyn_value_t *value
),
void *closure
);
@@ -109,10 +108,7 @@ extern
int
rcyn_drop(
rcyn_t *rcyn,
- const char *client,
- const char *session,
- const char *user,
- const char *permission
+ const rcyn_key_t *key
);
extern
@@ -125,10 +121,7 @@ extern
int
rcyn_cache_check(
rcyn_t *rcyn,
- const char *client,
- const char *session,
- const char *user,
- const char *permission
+ const rcyn_key_t *key
);
typedef int (*rcyn_async_ctl_t)(
@@ -155,11 +148,8 @@ extern
int
rcyn_async_check(
rcyn_t *rcyn,
- const char *client,
- const char *session,
- const char *user,
- const char *permission,
- bool test,
+ const rcyn_key_t *key,
+ bool simple,
void (*callback)(
void *closure,
int status),
diff --git a/src/rcyn-protocol.c b/src/rcyn-protocol.c
index 868e81f..d08c81b 100644
--- a/src/rcyn-protocol.c
+++ b/src/rcyn-protocol.c
@@ -18,6 +18,7 @@
#include "rcyn-protocol.h"
const char
+ _agent_[] = "agent",
_check_[] = "check",
_drop_[] = "drop",
_enter_[] = "enter",
@@ -39,12 +40,43 @@ const char
_no_[] = "no",
_yes_[] = "yes";
+#if !defined(RCYN_DEFAULT_SOCKET_SCHEME)
+# define RCYN_DEFAULT_SOCKET_SCHEME "unix"
+#endif
+
+#if !defined(RCYN_DEFAULT_SOCKET_DIR)
+# define RCYN_DEFAULT_SOCKET_DIR "/var/run/cynara"
+#endif
+
+#define DEF_PREFIX RCYN_DEFAULT_SOCKET_SCHEME":"RCYN_DEFAULT_SOCKET_DIR"/"
+
+#if !defined(RCYN_DEFAULT_CHECK_SOCKET_BASE)
+# define RCYN_DEFAULT_CHECK_SOCKET_BASE "cynara.check"
+#endif
+#if !defined(RCYN_DEFAULT_ADMIN_SOCKET_BASE)
+# define RCYN_DEFAULT_ADMIN_SOCKET_BASE "cynara.admin"
+#endif
+#if !defined(RCYN_DEFAULT_AGENT_SOCKET_BASE)
+# define RCYN_DEFAULT_AGENT_SOCKET_BASE "cynara.agent"
+#endif
+
+
#if !defined(RCYN_DEFAULT_CHECK_SOCKET_SPEC)
-# define RCYN_DEFAULT_CHECK_SOCKET_SPEC "unix:/run/platform/cynara.check"
+# define RCYN_DEFAULT_CHECK_SOCKET_SPEC DEF_PREFIX RCYN_DEFAULT_CHECK_SOCKET_BASE
#endif
#if !defined(RCYN_DEFAULT_ADMIN_SOCKET_SPEC)
-# define RCYN_DEFAULT_ADMIN_SOCKET_SPEC "unix:/run/platform/cynara.admin"
+# define RCYN_DEFAULT_ADMIN_SOCKET_SPEC DEF_PREFIX RCYN_DEFAULT_ADMIN_SOCKET_BASE
+#endif
+#if !defined(RCYN_DEFAULT_AGENT_SOCKET_SPEC)
+# define RCYN_DEFAULT_AGENT_SOCKET_SPEC DEF_PREFIX RCYN_DEFAULT_AGENT_SOCKET_BASE
#endif
+
const char
+ rcyn_default_socket_scheme[] = RCYN_DEFAULT_SOCKET_SCHEME,
+ rcyn_default_socket_dir[] = RCYN_DEFAULT_SOCKET_DIR,
+ rcyn_default_check_socket_base[] = RCYN_DEFAULT_CHECK_SOCKET_BASE,
+ rcyn_default_admin_socket_base[] = RCYN_DEFAULT_ADMIN_SOCKET_BASE,
+ rcyn_default_agent_socket_base[] = RCYN_DEFAULT_AGENT_SOCKET_BASE,
rcyn_default_check_socket_spec[] = RCYN_DEFAULT_CHECK_SOCKET_SPEC,
- rcyn_default_admin_socket_spec[] = RCYN_DEFAULT_ADMIN_SOCKET_SPEC;
+ rcyn_default_admin_socket_spec[] = RCYN_DEFAULT_ADMIN_SOCKET_SPEC,
+ rcyn_default_agent_socket_spec[] = RCYN_DEFAULT_AGENT_SOCKET_SPEC;
diff --git a/src/rcyn-protocol.h b/src/rcyn-protocol.h
index 631c0b7..386bd94 100644
--- a/src/rcyn-protocol.h
+++ b/src/rcyn-protocol.h
@@ -18,6 +18,7 @@
#pragma once
extern const char
+ _agent_[],
_check_[],
_drop_[],
_enter_[],
@@ -40,6 +41,11 @@ extern const char
_yes_[];
extern const char
+ rcyn_default_socket_scheme[],
+ rcyn_default_socket_dir[],
+ rcyn_default_check_socket_base[],
+ rcyn_default_admin_socket_base[],
+ rcyn_default_agent_socket_base[],
rcyn_default_check_socket_spec[],
- rcyn_default_admin_socket_spec[];
-
+ rcyn_default_admin_socket_spec[],
+ rcyn_default_agent_socket_spec[];
diff --git a/src/rcyn-protocol.txt b/src/rcyn-protocol.txt
index 7a35ab9..50fd918 100644
--- a/src/rcyn-protocol.txt
+++ b/src/rcyn-protocol.txt
@@ -55,7 +55,7 @@ register agent (agent):
asking (agent ask CLIENT SESSION USER PERMISSION):
s->c ask CLIENT SESSION USER PERMISSION
- c->s done | ([yes|no] [always|session|one-time])
+ c->s done | ([yes|no] [always|session|one-time|EXPIRE])
----------------------------------------------------------
diff --git a/src/rcyn-server.c b/src/rcyn-server.c
index 13f3a2e..14a9243 100644
--- a/src/rcyn-server.c
+++ b/src/rcyn-server.c
@@ -15,8 +15,6 @@
* limitations under the License.
*/
-#define _GNU_SOURCE
-
#include <stdbool.h>
#include <stdint.h>
#include <stddef.h>
@@ -33,76 +31,21 @@
#include <sys/types.h>
#include <sys/socket.h>
+#include "data.h"
#include "prot.h"
#include "cyn.h"
#include "rcyn-protocol.h"
#include "rcyn-server.h"
#include "socket.h"
+#include "pollitem.h"
typedef enum rcyn_type {
rcyn_Check,
+ rcyn_Agent,
rcyn_Admin
} rcyn_type_t;
-/** structure for using epoll easily */
-typedef struct pollitem pollitem_t;
-struct pollitem
-{
- /** callback on event */
- void (*handler)(pollitem_t *pollitem, uint32_t events, int pollfd);
-
- /** data */
- void *closure;
-
- /** file */
- int fd;
-};
-
-static
-int
-pollitem_do(
- pollitem_t *pollitem,
- uint32_t events,
- int pollfd,
- int op
-) {
- struct epoll_event ev = { .events = events, .data.ptr = pollitem };
- return epoll_ctl(pollfd, op, pollitem->fd, &ev);
-}
-
-static
-int
-pollitem_add(
- pollitem_t *pollitem,
- uint32_t events,
- int pollfd
-) {
- return pollitem_do(pollitem, events, pollfd, EPOLL_CTL_ADD);
-}
-
-#if 0
-static
-int
-pollitem_mod(
- pollitem_t *pollitem,
- uint32_t events,
- int pollfd
-) {
- return pollitem_do(pollitem, events, pollfd, EPOLL_CTL_MOD);
-}
-#endif
-
-static
-int
-pollitem_del(
- pollitem_t *pollitem,
- int pollfd
-) {
- return pollitem_do(pollitem, 0, pollfd, EPOLL_CTL_DEL);
-}
-
-
/** structure that represents a rcyn client */
struct client
{
@@ -124,7 +67,7 @@ struct client
/** enter/leave status, record if entered */
unsigned entered: 1;
- /** enter/leave status, record if entring pending */
+ /** enter/leave status, record if enter is pending */
unsigned entering: 1;
/** indicate if some check were made */
@@ -147,6 +90,9 @@ struct rcyn_server
/** the admin socket */
pollitem_t admin;
+ /** the agent socket */
+ pollitem_t agent;
+
/** the check socket */
pollitem_t check;
};
@@ -181,18 +127,20 @@ flushw(
int rc;
struct pollfd pfd;
- rc = prot_should_write(cli->prot);
- while (rc) {
+ for(;;) {
+ rc = prot_should_write(cli->prot);
+ if (!rc)
+ break;
rc = prot_write(cli->prot, cli->pollitem.fd);
if (rc == -EAGAIN) {
pfd.fd = cli->pollitem.fd;
pfd.events = POLLOUT;
do { rc = poll(&pfd, 1, 0); } while (rc < 0 && errno == EINTR);
+ if (rc < 0)
+ rc = -errno;
}
- if (rc < 0) {
+ if (rc < 0)
break;
- }
- rc = prot_should_write(cli->prot);
}
return rc;
}
@@ -298,16 +246,20 @@ static
void
checkcb(
void *closure,
- const char *value,
- time_t expire
+ const data_value_t *value
) {
client_t *cli = closure;
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);
+ if (!value)
+ putx(cli, DEFAULT, "0", NULL);
+ else {
+ exp2txt(value->expire, text, sizeof text);
+ if (strcmp(value->value, ALLOW) && strcmp(value->value, DENY))
+ putx(cli, _done_, value, text, NULL);
+ else
+ putx(cli, value->value, text, NULL);
+ }
flushw(cli);
}
@@ -316,18 +268,14 @@ static
void
getcb(
void *closure,
- 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
) {
client_t *cli = closure;
char text[30];
- putx(cli, _item_, client, session, user, permission,
- value, exp2txt(expire, text, sizeof text), NULL);
+ putx(cli, _item_, key->client, key->session, key->user, key->permission,
+ value->value, exp2txt(value->expire, text, sizeof text), NULL);
}
/** handle a request */
@@ -339,8 +287,8 @@ onrequest(
const char *args[]
) {
int rc;
- const char *value;
- time_t expire;
+ data_key_t key;
+ data_value_t value;
/* just ignore empty lines */
if (count == 0)
@@ -357,10 +305,22 @@ onrequest(
}
switch(args[0][0]) {
+ case 'a': /* agent */
+ if (ckarg(args[0], _agent_, 1) && count == 5) {
+ if (cli->type != rcyn_Agent)
+ break;
+ /* TODO */ break;
+ return;
+ }
+ break;
case 'c': /* check */
if (ckarg(args[0], _check_, 1) && count == 5) {
cli->checked = 1;
- cyn_check_async(checkcb, cli, args[1], args[2], args[3], args[4]);
+ key.client = args[1];
+ key.session = args[2];
+ key.user = args[3];
+ key.permission = args[4];
+ cyn_check_async(checkcb, cli, &key);
return;
}
break;
@@ -370,7 +330,11 @@ onrequest(
break;
if (!cli->entered)
break;
- rc = cyn_drop(args[1], args[2], args[3], args[4]);
+ key.client = args[1];
+ key.session = args[2];
+ key.user = args[3];
+ key.permission = args[4];
+ rc = cyn_drop(&key);
send_done_or_error(cli, rc);
return;
}
@@ -391,7 +355,11 @@ onrequest(
if (ckarg(args[0], _get_, 1) && count == 5) {
if (cli->type != rcyn_Admin)
break;
- cyn_list(cli, getcb, args[1], args[2], args[3], args[4]);
+ key.client = args[1];
+ key.session = args[2];
+ key.user = args[3];
+ key.permission = args[4];
+ cyn_list(cli, getcb, &key);
send_done(cli);
return;
}
@@ -417,10 +385,15 @@ onrequest(
if (!cli->entered)
break;
if (count == 6)
- expire = 0;
+ value.expire = 0;
else
- expire = strtoll(args[6], NULL, 10);
- rc = cyn_set(args[1], args[2], args[3], args[4], args[5], expire);
+ value.expire = strtoll(args[6], NULL, 10);
+ key.client = args[1];
+ key.session = args[2];
+ key.user = args[3];
+ key.permission = args[4];
+ value.value = args[5];
+ rc = cyn_set(&key, &value);
send_done_or_error(cli, rc);
return;
}
@@ -428,8 +401,12 @@ onrequest(
case 't': /* test */
if (ckarg(args[0], _test_, 1) && count == 5) {
cli->checked = 1;
- cyn_test(args[1], args[2], args[3], args[4], &value, &expire);
- checkcb(cli, value, expire);
+ key.client = args[1];
+ key.session = args[2];
+ key.user = args[3];
+ key.permission = args[4];
+ cyn_test(&key, &value);
+ checkcb(cli, &value);
return;
}
break;
@@ -633,6 +610,17 @@ on_admin_server_event(
on_server_event(pollitem, events, pollfd, rcyn_Admin);
}
+/** handle admin server events */
+static
+void
+on_agent_server_event(
+ pollitem_t *pollitem,
+ uint32_t events,
+ int pollfd
+) {
+ on_server_event(pollitem, events, pollfd, rcyn_Agent);
+}
+
/** destroy a server */
void
rcyn_server_destroy(
@@ -654,7 +642,8 @@ int
rcyn_server_create(
rcyn_server_t **server,
const char *admin_socket_spec,
- const char *check_socket_spec
+ const char *check_socket_spec,
+ const char *agent_socket_spec
) {
rcyn_server_t *srv;
int rc;
@@ -668,7 +657,7 @@ rcyn_server_create(
}
/* create the polling fd */
- srv->admin.fd = srv->check.fd = -1;
+ srv->admin.fd = srv->check.fd = srv->agent.fd = -1;
srv->pollfd = epoll_create1(EPOLL_CLOEXEC);
if (srv->pollfd < 0) {
rc = -errno;
@@ -685,7 +674,7 @@ rcyn_server_create(
goto error2;
}
- /* add the server to pollfd */
+ /* add the admin server to pollfd */
srv->admin.handler = on_admin_server_event;
srv->admin.closure = srv;
rc = pollitem_add(&srv->admin, EPOLLIN, srv->pollfd);
@@ -695,7 +684,7 @@ rcyn_server_create(
goto error2;
}
- /* create the server socket */
+ /* create the check server socket */
check_socket_spec = check_socket_spec ?: rcyn_default_check_socket_spec;
srv->check.fd = socket_open(check_socket_spec, 1);
if (srv->check.fd < 0) {
@@ -704,7 +693,7 @@ rcyn_server_create(
goto error2;
}
- /* add the server to pollfd */
+ /* add the check server to pollfd */
srv->check.handler = on_check_server_event;
srv->check.closure = srv;
rc = pollitem_add(&srv->check, EPOLLIN, srv->pollfd);
@@ -713,6 +702,26 @@ rcyn_server_create(
fprintf(stderr, "can't poll check server: %m\n");
goto error2;
}
+
+ /* create the agent server socket */
+ agent_socket_spec = agent_socket_spec ?: rcyn_default_agent_socket_spec;
+ srv->agent.fd = socket_open(agent_socket_spec, 1);
+ if (srv->agent.fd < 0) {
+ rc = -errno;
+ fprintf(stderr, "can't create agent server socket %s: %m\n", agent_socket_spec);
+ goto error2;
+ }
+
+ /* add the agent server to pollfd */
+ srv->agent.handler = on_agent_server_event;
+ srv->agent.closure = srv;
+ rc = pollitem_add(&srv->agent, EPOLLIN, srv->pollfd);
+ if (rc < 0) {
+ rc = -errno;
+ fprintf(stderr, "can't poll agent server: %m\n");
+ goto error2;
+ }
+
return 0;
error2:
@@ -722,6 +731,8 @@ error2:
close(srv->admin.fd);
if (srv->check.fd >= 0)
close(srv->check.fd);
+ if (srv->agent.fd >= 0)
+ close(srv->agent.fd);
free(srv);
error:
*server = NULL;
@@ -742,18 +753,10 @@ int
rcyn_server_serve(
rcyn_server_t *server
) {
- int rc;
- struct epoll_event ev;
- pollitem_t *pi;
-
/* process inputs */
server->stopped = 0;
while(!server->stopped) {
- rc = epoll_wait(server->pollfd, &ev, 1, -1);
- if (rc == 1) {
- pi = ev.data.ptr;
- pi->handler(pi, ev.events, server->pollfd);
- }
+ pollitem_wait_dispatch(server->pollfd, -1);
}
return server->stopped == INT_MIN ? 0 : server->stopped;
}
diff --git a/src/rcyn-server.h b/src/rcyn-server.h
index 2908c52..5758070 100644
--- a/src/rcyn-server.h
+++ b/src/rcyn-server.h
@@ -32,7 +32,8 @@ int
rcyn_server_create(
rcyn_server_t **server,
const char *admin_socket_spec,
- const char *check_socket_spec
+ const char *check_socket_spec,
+ const char *agent_socket_spec
);
extern
diff --git a/src/socket.c b/src/socket.c
index b908cf0..5dbfa9e 100644
--- a/src/socket.c
+++ b/src/socket.c
@@ -15,8 +15,6 @@
* limitations under the License.
*/
-#define _GNU_SOURCE
-
#include <stdlib.h>
#include <string.h>
#include <assert.h>