diff options
author | José Bollo <jose.bollo@iot.bzh> | 2019-10-03 14:33:21 +0200 |
---|---|---|
committer | José Bollo <jose.bollo@iot.bzh> | 2019-10-04 16:02:32 +0200 |
commit | b5bd40e1e68b739307e20e19d2164c5b370846df (patch) | |
tree | 91d05e9d740e7e0413509ab7a563b3ce14444b62 /compat/src | |
parent | d4a2c432763b033acf7c94ee7e121aca5a3a4f10 (diff) |
Isolate compatibility with old cynara
The compatibility items of the old cynara
librarie are separated and isolated.
The option WITH_CYNARA_COMPAT activates it or not.
Change-Id: Iba77c97d8df31f5f515b57411487943192451ac6
Signed-off-by: José Bollo <jose.bollo@iot.bzh>
Diffstat (limited to 'compat/src')
-rw-r--r-- | compat/src/CMakeLists.txt | 47 | ||||
-rw-r--r-- | compat/src/export-cynara-compat.map | 8 | ||||
-rw-r--r-- | compat/src/lib-compat.c | 699 | ||||
-rw-r--r-- | compat/src/main-test-old-cynara.c | 317 |
4 files changed, 1071 insertions, 0 deletions
diff --git a/compat/src/CMakeLists.txt b/compat/src/CMakeLists.txt new file mode 100644 index 0000000..3bda2da --- /dev/null +++ b/compat/src/CMakeLists.txt @@ -0,0 +1,47 @@ +########################################################################### +# 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. +########################################################################### + +add_compile_definitions(_GNU_SOURCE) + +########################################### +# build and install libcynara-compat +########################################### +add_library(cynara-compat SHARED lib-compat.c) +target_include_directories(cynara-compat PUBLIC ../include) +set_target_properties(cynara-compat + PROPERTIES + VERSION ${CYNARA_VERSION} + SOVERSION ${CYNARA_SOVERSION} +) +target_link_libraries(cynara-compat + PRIVATE cynara-client +) +target_link_options(cynara-compat + PRIVATE + -Wl,--version-script=${CMAKE_CURRENT_SOURCE_DIR}/export-cynara-compat.map +) +install(TARGETS cynara-compat LIBRARY DESTINATION ${CMAKE_INSTALL_FULL_LIBDIR}) + +########################################### +# build and install test-old-cynara +########################################### +add_executable(test-old-cynara main-test-old-cynara.c) +target_link_libraries(test-old-cynara cynara-compat) +install(TARGETS test-old-cynara + RUNTIME DESTINATION ${CMAKE_INSTALL_FULL_BINDIR}) + diff --git a/compat/src/export-cynara-compat.map b/compat/src/export-cynara-compat.map new file mode 100644 index 0000000..7b482f3 --- /dev/null +++ b/compat/src/export-cynara-compat.map @@ -0,0 +1,8 @@ +{ +global: + cynara_*; +local: + *; +}; + + diff --git a/compat/src/lib-compat.c b/compat/src/lib-compat.c new file mode 100644 index 0000000..63696fe --- /dev/null +++ b/compat/src/lib-compat.c @@ -0,0 +1,699 @@ +/* + * 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. + */ +/******************************************************************************/ +/******************************************************************************/ +/* COMPATIBILITY LAYER TO PREVIOUS CYNARA */ +/******************************************************************************/ +/******************************************************************************/ +/* +cynara_admin_initialize(&m_CynaraAdmin), +cynara_admin_finish(m_CynaraAdmin); +cynara_admin_set_policies(m_CynaraAdmin, pp_policies.data()), +cynara_admin_list_policies(m_CynaraAdmin, bucketName.c_str(), appId.c_str(), +cynara_admin_erase(m_CynaraAdmin, bucketName.c_str(), static_cast<int>(recursive), +cynara_admin_check(m_CynaraAdmin, bucket.c_str(), recursive, label.c_str(), + +cynara_initialize(&m_Cynara, nullptr), +cynara_finish(m_Cynara); +cynara_check(m_Cynara, +*/ + +#include <stdbool.h> +#include <stdlib.h> +#include <stdio.h> +#include <stdint.h> +#include <string.h> +#include <unistd.h> +#include <fcntl.h> +#include <errno.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/epoll.h> + +#include <cynara/cynara-admin.h> +#include <cynara/cynara-client.h> +#include <cynara/cynara-client-async.h> +#include <cynara/cynara-creds-commons.h> + +#ifndef CYNARA_ADMIN_ASK +# define CYNARA_ADMIN_ASK 11 +#endif + +#include "rcyn-client.h" + +/******************** ADMIN ********************************/ + +static int from_status(int rc) +{ + switch (-rc) { + case 0: rc = CYNARA_API_SUCCESS; break; + case ENOMEM: rc = CYNARA_API_OUT_OF_MEMORY; break; + case ENOTSUP: rc = CYNARA_API_METHOD_NOT_SUPPORTED; break; + case ENOENT: rc = CYNARA_API_CACHE_MISS; break; + default: rc = CYNARA_API_UNKNOWN_ERROR; break; + } + return rc; +} + +static int from_check_status(int rc) +{ + switch (rc) { + case 0: rc = CYNARA_API_ACCESS_DENIED; break; + case 1: rc = CYNARA_API_ACCESS_ALLOWED; break; + case -EEXIST: rc = CYNARA_API_ACCESS_NOT_RESOLVED; break; + default: rc = from_status(rc); break; + } + return rc; +} + +static int from_value(const char *value) +{ + if (!strcmp(value, "yes")) + return CYNARA_ADMIN_ALLOW; + if (!strcmp(value, "ask")) + return CYNARA_ADMIN_ASK; + return CYNARA_ADMIN_DENY; +} + +static const char *to_value(int value) +{ + switch(value) { + case CYNARA_ADMIN_DENY: + case CYNARA_ADMIN_NONE: + case CYNARA_ADMIN_BUCKET: return "no"; + case CYNARA_ADMIN_ALLOW: return "yes"; + case CYNARA_ADMIN_ASK: return "ask"; + } + return "?"; +} + +/************************************ ERROR ****************************************/ + +static const struct { + int num; + const char *text; +} error_descriptions[] = { + { CYNARA_API_INTERRUPTED, "API call was interrupted by user" }, + { CYNARA_API_ACCESS_NOT_RESOLVED, "access cannot be resolved without further actions" }, + { CYNARA_API_ACCESS_ALLOWED, "access that was checked is allowed" }, + { CYNARA_API_ACCESS_DENIED, "access that was checked is denied" }, + { CYNARA_API_SUCCESS, "successful" }, + { CYNARA_API_CACHE_MISS, "value is not present in cache" }, + { CYNARA_API_MAX_PENDING_REQUESTS, "pending requests reached maximum" }, + { CYNARA_API_OUT_OF_MEMORY, "system is running out of memory" }, + { CYNARA_API_INVALID_PARAM, "parameter is malformed" }, + { CYNARA_API_SERVICE_NOT_AVAILABLE, "service is not available" }, + { CYNARA_API_METHOD_NOT_SUPPORTED, "method is not supported by library" }, + { CYNARA_API_OPERATION_NOT_ALLOWED, "not allowed to perform requested operation" }, + { CYNARA_API_OPERATION_FAILED, "failed to perform requested operation" }, + { CYNARA_API_BUCKET_NOT_FOUND, "service hasn't found requested bucket" }, + { CYNARA_API_UNKNOWN_ERROR, "unknown error" }, + { CYNARA_API_CONFIGURATION_ERROR, "configuration error" }, + { CYNARA_API_INVALID_COMMANDLINE_PARAM, "invalid parameter in command-line" }, + { CYNARA_API_BUFFER_TOO_SHORT, "provided buffer is too short" }, + { CYNARA_API_DATABASE_CORRUPTED, "database is corrupted" }, + { CYNARA_API_PERMISSION_DENIED, "user doesn't have enough permission to perform action" }, +}; + +int cynara_strerror(int errnum, char *buf, size_t buflen) +{ + int i = (int)(sizeof error_descriptions / sizeof *error_descriptions); + while(i) { + if (error_descriptions[--i].num == errnum) { + if (strlen(error_descriptions[i].text) >= buflen) + return CYNARA_API_BUFFER_TOO_SHORT; + if (buf == NULL) + break; + strcpy(buf, error_descriptions[i].text); + return CYNARA_API_SUCCESS; + } + } + return CYNARA_API_INVALID_PARAM; +} + +/******************** ADMIN ********************************/ + +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, 1, 0)); +} + +int cynara_admin_finish(struct cynara_admin *p_cynara_admin) +{ + rcyn_close((rcyn_t*)p_cynara_admin); + return CYNARA_API_SUCCESS; +} + +int cynara_admin_set_policies(struct cynara_admin *p_cynara_admin, + const struct cynara_admin_policy *const *policies) +{ + 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, &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); + if (rc == 0) + rc = rc2; + } + return rc; +} + +static void check_cb( + void *closure, + const rcyn_key_t *key, + const rcyn_value_t *value +) { + *((int*)closure) = from_value(value->value); +} + +int cynara_admin_check(struct cynara_admin *p_cynara_admin, + const char *start_bucket, const int recursive, + 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, &key, check_cb, result)); +} + +struct list_data +{ + struct cynara_admin_policy **policies; + const char *bucket; + unsigned count; + int error; +}; + +static void list_cb( + void *closure, + const rcyn_key_t *key, + const rcyn_value_t *value +) { + struct list_data *data = closure; + struct cynara_admin_policy *pol; + + if (data->error) + return; + + pol = calloc(1, sizeof *pol); + if (pol == NULL) + goto error; + + pol->bucket = strdup(data->bucket ?: ""); + 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->value); + pol->result_extra = 0; + closure = realloc(data->policies, (data->count + 1) * sizeof *data->policies); + if (closure == NULL) + goto error; + + (data->policies = closure)[data->count++] = pol; + return; +error: + if (pol) { + free(pol->bucket); + free(pol->client); + free(pol->user); + free(pol->privilege); + free(pol); + } + data->error = -ENOMEM; + +} + +int cynara_admin_list_policies(struct cynara_admin *p_cynara_admin, const char *bucket, + const char *client, const char *user, const char *privilege, + struct cynara_admin_policy ***policies) +{ + 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, &key, list_cb, &data); + if (rc == 0 && data.error != 0) + rc = data.error; + if (rc == 0 && !data.error) { + if ((*policies = realloc(data.policies, (data.count + 1) * sizeof *data.policies)) != NULL) + policies[0][data.count] = NULL; + else + rc = -ENOMEM; + } + if (rc) { + while(data.count) + free(data.policies[--data.count]); + free(data.policies); + *policies = NULL; + } + return from_status(rc); +} + +int cynara_admin_erase(struct cynara_admin *p_cynara_admin, + const char *start_bucket, int recursive, + 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, &key); + rc2 = rcyn_leave((rcyn_t*)p_cynara_admin, rc == 0); + if (rc == 0) + rc = rc2; + } + return from_status(rc); +} + + +int cynara_admin_list_policies_descriptions(struct cynara_admin *p_cynara_admin, + struct cynara_admin_policy_descr ***descriptions) +{ + struct cynara_admin_policy_descr **d = malloc(4 * sizeof *d), *s; + if (d) { + d[0] = malloc(sizeof *s); + d[1] = malloc(sizeof *s); + d[2] = malloc(sizeof *s); + d[3] = NULL; + if (d[0] != NULL && d[1] != NULL && d[2] != NULL) { + d[0]->name = strdup("Deny"); + d[1]->name = strdup("AskUser"); + d[2]->name = strdup("Allow"); + if (d[0]->name != NULL && d[1]->name != NULL && d[2]->name != NULL) { + d[0]->result = CYNARA_ADMIN_DENY; + d[1]->result = CYNARA_ADMIN_ASK; + d[2]->result = CYNARA_ADMIN_ALLOW; + *descriptions = d; + return CYNARA_API_SUCCESS; + } + free(d[0]->name); + free(d[1]->name); + free(d[2]->name); + } + free(d[0]); + free(d[1]); + free(d[2]); + } + *descriptions = NULL; + return CYNARA_API_OUT_OF_MEMORY; +} + +/************************************* CLIENT-ASYNC **************************************/ +struct cynara_async_configuration { uint32_t szcache; }; + +int cynara_async_configuration_create(cynara_async_configuration **pp_conf) +{ + *pp_conf = malloc(sizeof(cynara_async_configuration)); + if (*pp_conf == NULL) + return CYNARA_API_OUT_OF_MEMORY; + (*pp_conf)->szcache = 0; + return CYNARA_API_SUCCESS; +} + +void cynara_async_configuration_destroy(cynara_async_configuration *p_conf) +{ + free(p_conf); +} + +int cynara_async_configuration_set_cache_size(cynara_async_configuration *p_conf, + size_t cache_size) +{ + p_conf->szcache = cache_size > 1000000 ? 1000000 : (uint32_t)cache_size; + return CYNARA_API_SUCCESS; +} + +struct reqasync +{ + struct reqasync *next; + cynara_async *cynasync; + cynara_response_callback callback; + void *user_response_data; + cynara_check_id id; + bool canceled; +}; + +struct cynara_async +{ + rcyn_t *rcyn; + cynara_status_callback callback; + void *user_status_data; + struct reqasync *reqs; + cynara_check_id ids; +}; + +static int async_control_cb(void *closure, int op, int fd, uint32_t events) +{ + cynara_async *p_cynara = closure; + cynara_async_status s = (events & EPOLLOUT) ? CYNARA_STATUS_FOR_RW : CYNARA_STATUS_FOR_READ; + switch(op) { + case EPOLL_CTL_ADD: + p_cynara->callback(-1, fd, s, p_cynara->user_status_data); + break; + case EPOLL_CTL_MOD: + p_cynara->callback(fd, fd, s, p_cynara->user_status_data); + break; + case EPOLL_CTL_DEL: + p_cynara->callback(fd, -1, 0, p_cynara->user_status_data); + break; + } + return 0; +} + +int cynara_async_initialize(cynara_async **pp_cynara, const cynara_async_configuration *p_conf, + cynara_status_callback callback, void *user_status_data) +{ + int ret; + cynara_async *p_cynara; + + p_cynara = malloc(sizeof *p_cynara); + 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 : 1, 0)); + if (ret != CYNARA_API_SUCCESS) + free(p_cynara); + else { + p_cynara->callback = callback; + p_cynara->user_status_data = user_status_data; + p_cynara->reqs = NULL; + p_cynara->ids = 0; + rcyn_async_setup(p_cynara->rcyn, async_control_cb, p_cynara); + *pp_cynara = p_cynara; + } + } + return ret; +} + +void cynara_async_finish(cynara_async *p_cynara) +{ + struct reqasync *req; + + for(req = p_cynara->reqs ; req ; req = req->next) { + if (!req->canceled) { + req->callback(req->id, CYNARA_CALL_CAUSE_FINISH, 0, req->user_response_data); + req->canceled = true; + } + } + + rcyn_close(p_cynara->rcyn); + + while((req = p_cynara->reqs)) { + p_cynara->reqs = req->next; + free(req); + } + free(p_cynara); +} + +int cynara_async_check_cache(cynara_async *p_cynara, const char *client, const char *client_session, + const char *user, const char *privilege) +{ + int rc; + rcyn_key_t key = { client, client_session, user, privilege }; + rc = from_check_status(rcyn_cache_check(p_cynara->rcyn, &key)); + return rc; +} + +static void reqcb(void *closure, int status) +{ + struct reqasync *req = closure, **p; + + p = &req->cynasync->reqs; + while(*p && *p != req) + p = &(*p)->next; + if (*p) + *p = req->next; + + if (!req->canceled) + req->callback(req->id, CYNARA_CALL_CAUSE_ANSWER, from_check_status(status), req->user_response_data); + + free(req); +} + +static int create_reqasync(cynara_async *p_cynara, const char *client, + const char *client_session, const char *user, const char *privilege, + cynara_check_id *p_check_id, cynara_response_callback callback, + void *user_response_data, bool simple) +{ + int rc; + struct reqasync *req; + rcyn_key_t key = { client, client_session, user, privilege }; + + req = malloc(sizeof *req); + if (req == NULL) + return CYNARA_API_OUT_OF_MEMORY; + + req->next = p_cynara->reqs; + req->cynasync = p_cynara; + req->callback = callback; + req->user_response_data = user_response_data; + req->id = ++p_cynara->ids; + req->canceled = false; + + rc = rcyn_async_check(p_cynara->rcyn, &key, simple, reqcb, req); + if (rc == 0) + p_cynara->reqs = req; + else + free(req); + return from_status(rc); +} + +int cynara_async_create_request(cynara_async *p_cynara, const char *client, + const char *client_session, const char *user, const char *privilege, + cynara_check_id *p_check_id, cynara_response_callback callback, + void *user_response_data) +{ + int rc; + rc = create_reqasync(p_cynara, client, client_session, user, privilege, p_check_id, callback, user_response_data, false); + return rc; +} + +int cynara_async_create_simple_request(cynara_async *p_cynara, const char *client, + const char *client_session, const char *user, + const char *privilege, cynara_check_id *p_check_id, + cynara_response_callback callback, void *user_response_data) +{ + int rc; + rc = create_reqasync(p_cynara, client, client_session, user, privilege, p_check_id, callback, user_response_data, true); + return rc; +} + + +int cynara_async_process(cynara_async *p_cynara) +{ + int rc; + rc = rcyn_async_process(p_cynara->rcyn); + return rc; +} + +int cynara_async_cancel_request(cynara_async *p_cynara, cynara_check_id check_id) +{ + struct reqasync *req = p_cynara->reqs; + + while(req && req->id != check_id) + req = req->next; + if (req && !req->canceled) { + req->canceled = true; + req->callback(req->id, CYNARA_CALL_CAUSE_CANCEL, 0, req->user_response_data); + } + return CYNARA_API_SUCCESS; +} + +/************************************* CLIENT **************************************/ + +struct cynara_configuration { uint32_t szcache; }; + +int cynara_configuration_create(cynara_configuration **pp_conf) +{ + *pp_conf = malloc(sizeof(cynara_configuration)); + if (*pp_conf == NULL) + return CYNARA_API_OUT_OF_MEMORY; + (*pp_conf)->szcache = 0; + return CYNARA_API_SUCCESS; +} + +void cynara_configuration_destroy(cynara_configuration *p_conf) +{ + free(p_conf); +} + +int cynara_configuration_set_cache_size(cynara_configuration *p_conf, + size_t cache_size) +{ + p_conf->szcache = cache_size > 1000000 ? 1000000 : (uint32_t)cache_size; + return CYNARA_API_SUCCESS; +} + +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 : 1, 0)); +} + +int cynara_finish(cynara *p_cynara) +{ + rcyn_close((rcyn_t*)p_cynara); + return CYNARA_API_SUCCESS; +} + +int cynara_check(cynara *p_cynara, const char *client, const char *client_session, const char *user, + const char *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) +{ + rcyn_key_t key = { client, client_session, user, privilege }; + return from_check_status(rcyn_test((rcyn_t*)p_cynara, &key)); +} + +/************************************* CREDS... & SESSION *********************************/ +#define MAX_LABEL_LENGTH 1024 + +#if !defined(DEFAULT_PEERSEC_LABEL) +# define DEFAULT_PEERSEC_LABEL "NoLabel" +#endif + +int cynara_creds_get_default_client_method(enum cynara_client_creds *method) +{ + *method = CLIENT_METHOD_SMACK; + return CYNARA_API_SUCCESS; +} + +int cynara_creds_get_default_user_method(enum cynara_user_creds *method) +{ + *method = USER_METHOD_UID; + return CYNARA_API_SUCCESS; +} + +int cynara_creds_self_get_client(enum cynara_client_creds method, char **client) +{ + char label[MAX_LABEL_LENGTH + 1]; + int len, fd; + + label[0] = 0; + fd = open("/proc/self/current/attr", O_RDONLY); + if (fd >= 0) { + len = (int)read(fd, label, sizeof label - 1); + label[len >= 0 ? len : 0] = 0; + close(fd); + } + return (*client = strdup(label[0] ? label : DEFAULT_PEERSEC_LABEL)) + ? CYNARA_API_SUCCESS : CYNARA_API_OUT_OF_MEMORY; +} + +int cynara_creds_self_get_user(enum cynara_user_creds method, char **user) +{ + return asprintf(user, "%ld", (long)getuid()) > 0 + ? CYNARA_API_SUCCESS : CYNARA_API_OUT_OF_MEMORY; +} + +int cynara_creds_socket_get_client(int fd, enum cynara_client_creds method, char **client) +{ + int rc; + socklen_t length; + struct ucred ucred; + char label[MAX_LABEL_LENGTH + 1]; + + /* get the credentials */ + length = (socklen_t)(sizeof ucred); + rc = getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &ucred, &length); + if (rc < 0 || length != (socklen_t)(sizeof ucred) || !~ucred.uid) + return CYNARA_API_OPERATION_FAILED; + + /* get the security label */ + length = (socklen_t)(sizeof label); + rc = getsockopt(fd, SOL_SOCKET, SO_PEERSEC, label, &length); + if (rc < 0 || length > (socklen_t)(sizeof label)) + return CYNARA_API_OPERATION_FAILED; + + return (*client = strdup(label)) + ? CYNARA_API_SUCCESS : CYNARA_API_OUT_OF_MEMORY; +} + + + +int cynara_creds_socket_get_user(int fd, enum cynara_user_creds method, char **user) +{ + int rc; + socklen_t length; + struct ucred ucred; + + /* get the credentials */ + length = (socklen_t)(sizeof ucred); + rc = getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &ucred, &length); + if (rc < 0 || length != (socklen_t)(sizeof ucred) || !~ucred.uid) + return CYNARA_API_OPERATION_FAILED; + return asprintf(user, "%ld", (long)ucred.uid) > 0 + ? CYNARA_API_SUCCESS : CYNARA_API_OUT_OF_MEMORY; +} + + + +int cynara_creds_socket_get_pid(int fd, pid_t *pid) +{ + int rc; + socklen_t length; + struct ucred ucred; + + /* get the credentials */ + length = (socklen_t)(sizeof ucred); + rc = getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &ucred, &length); + if (rc < 0 || length != (socklen_t)(sizeof ucred) || !~ucred.uid) + return CYNARA_API_OPERATION_FAILED; + *pid = ucred.pid; + return CYNARA_API_SUCCESS; +} + +char *cynara_session_from_pid(pid_t client_pid) +{ + char *r; + + return asprintf(&r, "%ld", (long)client_pid) < 0 ? NULL : r; +} + diff --git a/compat/src/main-test-old-cynara.c b/compat/src/main-test-old-cynara.c new file mode 100644 index 0000000..ccc3baa --- /dev/null +++ b/compat/src/main-test-old-cynara.c @@ -0,0 +1,317 @@ +/* + * Copyright (C) 2018 "IoT.bzh" + * Author José Bollo <jose.bollo@iot.bzh> + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <stdint.h> +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <fcntl.h> +#include <string.h> +#include <sys/epoll.h> + +#include <cynara/cynara-admin.h> +#include <cynara/cynara-client-async.h> +#include <cynara/cynara-client.h> + +#define STD 0 +#define TEST 1 +#define CACHE 2 + +#define STRFY(x) #x +#define CKEX(x) ckex((x),STD,__LINE__,STRFY(x)) +#define TEEX(x) ckex((x),TEST,__LINE__,STRFY(x)) +#define CAEX(x) ckex((x),CACHE,__LINE__,STRFY(x)) + +struct cynara_admin *admin; +struct cynara_async_configuration *aconf; +struct cynara_async *aclient; +struct cynara_configuration *conf; +struct cynara *client; +char buffer[4000]; +int bufill; +char *str[40]; +int nstr; +int pollfd; +int pending; +int ending; + +#define BUCKET "BUCK" + +void ckex(int rc, int type, int line, const char *x) +{ + int err = 1; + switch(type) { + case STD: + err = (rc != CYNARA_API_SUCCESS); + break; + case TEST: + err = (rc != CYNARA_API_ACCESS_DENIED + && rc != CYNARA_API_ACCESS_ALLOWED + && rc != CYNARA_API_ACCESS_NOT_RESOLVED); + break; + case CACHE: + err = (rc != CYNARA_API_ACCESS_DENIED + && rc != CYNARA_API_ACCESS_ALLOWED + && rc != CYNARA_API_ACCESS_NOT_RESOLVED + && rc != CYNARA_API_CACHE_MISS); + break; + } + if (err) { + char buffer[200]; + cynara_strerror(rc, buffer, 200); + printf("ERROR(%d) %s by %s line %d\n", rc, buffer, x, line); + exit(1); + } + printf("SUCCESS[%d] %s\n", rc, x); +} + +int is(const char *first, const char *second, int mincount) +{ + return nstr >= mincount + 2 + && !strcmp(first, str[0]) + && !strcmp(second, str[1]); +} + +void adm_list(char *cli, char *usr, char *perm) +{ + int i; + struct cynara_admin_policy **policies; + CKEX(cynara_admin_list_policies(admin, BUCKET, cli, usr, perm, &policies)); + i = 0; + while(policies[i]) { + printf("%s %s %s %s %d %s\n", + policies[i]->bucket, + policies[i]->client, + policies[i]->user, + policies[i]->privilege, + policies[i]->result, + policies[i]->result_extra ?: ""); + free(policies[i]->bucket); + free(policies[i]->client); + free(policies[i]->user); + free(policies[i]->privilege); + free(policies[i]->result_extra); + free(policies[i]); + i++; + } + free(policies); +} + +void adm_check(char *cli, char *usr, char *perm) +{ + char *rs; + int ri; + + CKEX(cynara_admin_check(admin, BUCKET, 1, cli, usr, perm, &ri, &rs)); + printf("got %d %s \n", ri, rs ?: "NULL"); +} + +void adm_set() +{ + struct cynara_admin_policy **policies, *p; + int n, i; + + n = (nstr - 2) / 4; + policies = malloc((1 + n) * sizeof *policies + n * sizeof **policies); + policies[n] = NULL; + p = (struct cynara_admin_policy*)(&policies[n + 1]); + for (i = 0 ; i < n ; i++, p++) { + policies[i] = p; + p->bucket = BUCKET; + p->client = str[2 + i * 4 + 0]; + p->user = str[2 + i * 4 + 1]; + p->privilege = str[2 + i * 4 + 2]; + p->result = atoi(str[2 + i * 4 + 3]); + p->result_extra = NULL; + } + CKEX(cynara_admin_set_policies(admin, (const struct cynara_admin_policy *const *)policies)); + free(policies); +} + +void adm_erase(char *cli, char *usr, char *perm) +{ + CKEX(cynara_admin_erase(admin, BUCKET, 1, cli, usr, perm)); +} + +void adm_desc() +{ + int i; + struct cynara_admin_policy_descr **d; + CKEX(cynara_admin_list_policies_descriptions(admin, &d)); + i = 0; + while(d[i]) { + printf("desc[%d] %d -> %s\n", i, d[i]->result, d[i]->name); + free(d[i]->name); + free(d[i]); + i++; + } + free(d); +} + +void asy_cache(char *cli, char *ses, char *usr, char *perm) +{ + CAEX(cynara_async_check_cache(aclient, cli, ses, usr, perm)); +} + +void asyncb(cynara_check_id check_id, cynara_async_call_cause cause, + int response, void *user_response_data) +{ + printf("RECEIVE %d %d\n", cause, response); + pending--; + if (ending && !pending) + exit(0); +} + +void asy_check(char *cli, char *ses, char *usr, char *perm, int simple) +{ + pending++; + if (simple) + CKEX(cynara_async_create_simple_request(aclient, cli, ses, usr, perm, NULL, asyncb, NULL)); + else + CKEX(cynara_async_create_request(aclient, cli, ses, usr, perm, NULL, asyncb, NULL)); +} + +void syn_check(char *cli, char *ses, char *usr, char *perm, int simple) +{ + if (simple) + TEEX(cynara_simple_check(client, cli, ses, usr, perm)); + else + TEEX(cynara_check(client, cli, ses, usr, perm)); +} + +void asyncstscb(int old_fd, int new_fd, cynara_async_status status, void *data) +{ + struct epoll_event ev; + + memset(&ev, 0, sizeof ev); + ev.data.fd = new_fd; + ev.events = (status == CYNARA_STATUS_FOR_RW ? EPOLLOUT : 0)|EPOLLIN; + if (old_fd == new_fd) { + if (new_fd != -1) + epoll_ctl(pollfd, EPOLL_CTL_MOD, new_fd, &ev); + } else { + if (old_fd != -1) + epoll_ctl(pollfd, EPOLL_CTL_DEL, old_fd, &ev); + if (new_fd != -1) + epoll_ctl(pollfd, EPOLL_CTL_ADD, new_fd, &ev); + } +} + +int action() +{ + if (is("admin", "listall", 0)) + adm_list("#", "#", "#"); + else if (is("admin", "list", 3)) + adm_list(str[2], str[3], str[4]); + else if (is("admin", "check", 3)) + adm_check(str[2], str[3], str[4]); + else if (is("admin", "set", 4)) + adm_set(); + else if (is("admin", "erase", 3)) + adm_erase(str[2], str[3], str[4]); + else if (is("admin", "desc", 0)) + adm_desc(); + else if (is("async", "cache", 4)) + asy_cache(str[2], str[3], str[4], str[5]); + else if (is("async", "check", 4)) + asy_check(str[2], str[3], str[4], str[5], 0); + else if (is("async", "test", 4)) + asy_check(str[2], str[3], str[4], str[5], 1); + else if (is("sync", "check", 4)) + syn_check(str[2], str[3], str[4], str[5], 0); + else if (is("sync", "test", 4)) + syn_check(str[2], str[3], str[4], str[5], 1); + else if (nstr > 0 && !strcmp(str[0], "exit")) + return 1; + else if (nstr > 0 && str[0][0] != '#') + printf("ERROR bad input\n"); + return 0; +} + +int main(int ac, char **av) +{ + struct epoll_event ev; + char *p; + int rc; + + pollfd = epoll_create(10); + memset(&ev, 0, sizeof ev); + ev.data.fd = 0; + ev.events = EPOLLIN; + epoll_ctl(pollfd, EPOLL_CTL_ADD, 0, &ev); + + CKEX(cynara_admin_initialize(&admin)); + + CKEX(cynara_async_configuration_create(&aconf)); + CKEX(cynara_async_configuration_set_cache_size(aconf, 1000)); + CKEX(cynara_async_initialize(&aclient, aconf, asyncstscb, NULL)); + cynara_async_configuration_destroy(aconf); + + CKEX(cynara_configuration_create(&conf)); + CKEX(cynara_configuration_set_cache_size(conf, 1000)); + CKEX(cynara_initialize(&client, conf)); + cynara_configuration_destroy(conf); + + fcntl(0, F_SETFL, O_NONBLOCK); + bufill = 0; + for(;;) { + memset(&ev, 0, sizeof ev); + epoll_wait(pollfd, &ev, 1, -1); + + if (ev.data.fd == 0) { + if (ev.events & EPOLLIN) { + rc = (int)sizeof buffer - bufill; + rc = (int)read(0, buffer, rc); + if (rc == 0) + break; + if (rc > 0) { + bufill += rc; + while((p = memchr(buffer, '\n', bufill))) { + /* process one line */ + *p++ = 0; + str[nstr = 0] = strtok(buffer, " \t"); + while(str[nstr]) + str[++nstr] = strtok(NULL, " \t"); + if (action()) + goto terminate; + /* next line if any */ + bufill -= (int)(p - buffer); + if (!bufill) + break; + memmove(buffer, p, bufill); + } + } + } + if (ev.events & EPOLLHUP) { + if (!pending) + break; + epoll_ctl(pollfd, EPOLL_CTL_DEL, 0, &ev); + ending = 1; + } + } + else { + cynara_async_process(aclient); + } + + } +terminate: + cynara_finish(client); + cynara_async_finish(aclient); + cynara_admin_finish(admin); +} + |