26 RCSID(
"$Id: 35f236aab2b414ba45eca78ecf0cf48db8c27768 $")
28 #define LOG_PREFIX "couchbase"
30 #include <freeradius-devel/json/base.h>
31 #include <freeradius-devel/server/base.h>
32 #include <freeradius-devel/server/map.h>
47 lcb_t cb_inst = chandle->
handle;
69 DEBUG(
"Releasing the couchbase api options");
71 for (; opts != NULL; opts = opts->
next) {
72 TALLOC_FREE(opts->
key);
73 TALLOC_FREE(opts->
val);
123 inst->api_opts = entry;
160 lcb_error_t cb_error;
168 if (cb_error != LCB_SUCCESS) {
169 ERROR(
"failed to initiate couchbase connection: %s (0x%x)",
170 lcb_strerror(NULL, cb_error), cb_error);
172 lcb_destroy(cb_inst);
182 cookie = talloc_zero(chandle,
cookie_t);
185 cookie->
jerr = json_tokener_success;
190 chandle->
handle = cb_inst;
211 lcb_t cb_inst = chandle->
handle;
212 lcb_error_t cb_error = LCB_SUCCESS;
217 ERROR(
"failed to get couchbase server stats: %s (0x%x)",
218 lcb_strerror(NULL, cb_error), cb_error);
242 const char *attribute, *element;
250 WARN(
"found deprecated 'map' list - please change to 'update'");
255 ERROR(
"failed to find 'update' list in config");
261 inst->map = json_object_new_object();
267 ERROR(
"failed to parse invalid item in 'update' list");
270 json_object_put(
inst->map);
286 json_object_object_add(
inst->map, attribute, json_object_new_string(element));
289 DEBUG3(
"added attribute '%s' to element '%s' mapping", attribute, element);
293 DEBUG3(
"built attribute to element mapping %s", json_object_to_json_string(
inst->map));
313 json_object *j_value;
319 if (json_object_object_get_ex(map,
name, &j_value)) {
332 DEBUG(
"skipping attribute with no map entry - %s",
name);
375 json_object *list_obj;
376 char const *list_name = list->name;
381 if (!json_object_object_get_ex(json, list_name, &list_obj)) {
382 RDEBUG2(
"Couldn't find \"%s\" key in json object - Not adding value pairs for this attribute list",
391 if (!json_object_is_type(list_obj, json_type_object)) {
392 RERROR(
"Invalid json type for \"%s\" key - Attribute lists must be json objects", list_name);
406 json_object_object_foreach(list_obj, attr_name, attr_value_obj) {
407 json_object *value_obj, *op_obj;
411 if (!json_object_is_type(attr_value_obj, json_type_object)) {
412 REDEBUG(
"Invalid json type for \"%s\" key - Attributes must be json objects", attr_name);
419 RDEBUG3(
"Parsing %s - \"%s\" : { %s }", list_name,
420 attr_name, json_object_to_json_string(attr_value_obj));
425 if (!json_object_object_get_ex(attr_value_obj,
"value", &value_obj)) {
426 REDEBUG(
"Missing \"value\" key in: %s - \"%s\" : { %s }", list_name,
427 attr_name, json_object_to_json_string(attr_value_obj));
435 if (json_object_object_get_ex(attr_value_obj,
"op", &op_obj)) {
438 op_str = json_object_get_string(op_obj);
441 REDEBUG(
"Invalid \"op\" key in: %s - \"%s\" : { %s }", list_name,
442 attr_name, json_object_to_json_string(attr_value_obj));
459 RPERROR(
"Invalid attribute \"%s\"", attr_name);
472 RPERROR(
"Failed parsing value for \"%s\"", attr_name);
485 .dict_def = request->dict,
518 switch (
vp->vp_type) {
532 if (
vp->
da->flags.has_value)
break;
533 #ifdef HAVE_JSON_OBJECT_NEW_INT64
535 RDEBUG3(
"creating new int64 for unsigned 32 bit int/byte/short '%s'",
vp->
da->name);
537 return json_object_new_int64(i);
540 RDEBUG3(
"creating new int for unsigned 32 bit int/byte/short '%s'",
vp->
da->name);
542 return json_object_new_int(i);
546 #ifdef HAVE_JSON_OBJECT_NEW_INT64
548 RDEBUG3(
"creating new int64 for signed 32 bit integer '%s'",
vp->
da->name);
550 return json_object_new_int64(
vp->vp_int32);
552 RDEBUG3(
"creating new int for signed 32 bit integer '%s'",
vp->
da->name);
554 return json_object_new_int(
vp->vp_int32);
558 #ifdef HAVE_JSON_OBJECT_NEW_INT64
560 RDEBUG3(
"creating new int64 for 64 bit integer '%s'",
vp->
da->name);
562 return json_object_new_int64(
vp->vp_uint64);
565 RWARN(
"skipping 64 bit integer attribute '%s' - please upgrade json-c to 0.10+",
vp->
da->name);
576 switch (
vp->vp_type) {
579 RDEBUG3(
"assigning string '%s' as string",
vp->
da->name);
581 return json_object_new_string(
vp->vp_strvalue);
585 RDEBUG3(
"assigning unhandled '%s' as string",
vp->
da->name);
589 return json_object_new_string(
value);
606 json_object *j_value;
613 if (json_object_object_get_ex(json,
"startTimestamp", &j_value) == 0) {
615 DEBUG(
"failed to find 'startTimestamp' in current json body");
621 if (json_object_get_string(j_value) != NULL) {
632 DEBUG(
"failed to find event timestamp in current request");
643 ts = (ts -
vp->vp_uint32);
649 DEBUG(
"calculated start timestamp: %s",
value);
651 json_object_object_add_ex(json,
"startTimestamp", json_object_new_string(
value),
652 JSON_C_OBJECT_KEY_IS_CONSTANT);
655 DEBUG(
"failed to format calculated timestamp");
676 json_object *j_value;
678 if (!json_object_object_get_ex((json_object *)
data,
cf_pair_value(cp), &j_value)) {
683 if (!j_value)
return -1;
685 *
out = talloc_strdup(NULL, json_object_get_string(j_value));
686 if (!*
out)
return -1;
713 lcb_error_t cb_error = LCB_SUCCESS;
714 json_object *json, *j_value;
715 json_object *jrows = NULL;
723 if (!handle)
return -1;
726 lcb_t cb_inst = handle->
handle;
732 snprintf(vpath,
sizeof(vpath),
"%s?stale=false",
inst->client_view);
738 if (cb_error != LCB_SUCCESS || cookie->
jerr != json_tokener_success || !cookie->
jobj) {
740 ERROR(
"failed to execute view request or parse return");
744 goto free_and_return;
748 DEBUG3(
"cookie->jobj == %s", json_object_to_json_string(cookie->
jobj));
751 if (json_object_object_get_ex(cookie->
jobj,
"error", &json)) {
753 strlcpy(error, json_object_get_string(json),
sizeof(error));
755 if (json_object_object_get_ex(cookie->
jobj,
"reason", &json)) {
757 strlcat(error,
" - ",
sizeof(error));
759 strlcat(error, json_object_get_string(json),
sizeof(error));
762 ERROR(
"view request failed with error: %s", error);
766 goto free_and_return;
770 if (!json_object_object_get_ex(cookie->
jobj,
"rows", &json)) {
772 ERROR(
"failed to fetch rows from view payload");
776 goto free_and_return;
780 jrows = json_object_get(json);
784 json_object_put(cookie->
jobj);
789 DEBUG3(
"jrows == %s", json_object_to_json_string(jrows));
792 if (!json_object_is_type(jrows, json_type_array) || json_object_array_length(jrows) < 1) {
794 ERROR(
"no valid rows returned from view: %s", vpath);
798 goto free_and_return;
802 for (idx = 0; (
size_t)idx < (
size_t)json_object_array_length(jrows); idx++) {
804 json = json_object_array_get_idx(jrows, idx);
807 if (json_object_object_get_ex(json,
"id", &j_value)) {
809 memset(vid, 0,
sizeof(vid));
811 if (
strlcpy(vid, json_object_get_string(j_value),
sizeof(vid)) >=
sizeof(vid)) {
812 ERROR(
"id from row longer than MAX_KEY_SIZE (%d)",
817 WARN(
"failed to fetch id from row - skipping");
822 if (json_object_object_get_ex(json,
"key", &j_value)) {
824 memset(vkey, 0,
sizeof(vkey));
826 if (
strlcpy(vkey, json_object_get_string(j_value),
sizeof(vkey)) >=
sizeof(vkey)) {
827 ERROR(
"key from row longer than MAX_KEY_SIZE (%d)",
832 WARN(
"failed to fetch key from row - skipping");
840 if (cb_error != LCB_SUCCESS || cookie->
jerr != json_tokener_success || !cookie->
jobj) {
842 ERROR(
"failed to execute get request or parse return");
846 goto free_and_return;
850 DEBUG3(
"cookie->jobj == %s", json_object_to_json_string(cookie->
jobj));
853 client = tmpl ?
cf_section_dup(NULL, NULL, tmpl,
"client", vkey,
true) :
862 goto free_and_return;
870 ERROR(
"failed to allocate client");
876 goto free_and_return;
882 talloc_steal(c, client);
886 ERROR(
"failed to add client '%s' from '%s', possible duplicate?", vkey, vid);
892 goto free_and_return;
900 json_object_put(cookie->
jobj);
909 json_object_put(jrows);
914 json_object_put(cookie->
jobj);
Common header for all CONF_* types.
Configuration AVP similar to a fr_pair_t.
A section grouping multiple CONF_PAIR.
bool cf_item_is_pair(CONF_ITEM const *ci)
Determine if CONF_ITEM is a CONF_PAIR.
CONF_PAIR * cf_item_to_pair(CONF_ITEM const *ci)
Cast a CONF_ITEM to a CONF_PAIR.
char const * cf_pair_attr(CONF_PAIR const *pair)
Return the attr of a CONF_PAIR.
CONF_SECTION * cf_section_find(CONF_SECTION const *cs, char const *name1, char const *name2)
Find a CONF_SECTION with name1 and optionally name2.
char const * cf_pair_value(CONF_PAIR const *pair)
Return the value of a CONF_PAIR.
CONF_SECTION * cf_section_dup(TALLOC_CTX *ctx, CONF_SECTION *parent, CONF_SECTION const *cs, char const *name1, char const *name2, bool copy_meta)
Duplicate a configuration section.
#define cf_section_alloc(_ctx, _parent, _name1, _name2)
#define cf_log_debug(_cf, _fmt,...)
#define cf_item_next(_ci, _curr)
lcb_error_t couchbase_query_view(lcb_t instance, const void *cookie, const char *path, const char *post)
Query a Couchbase design document view.
lcb_error_t couchbase_server_stats(lcb_t instance, const void *cookie)
Request Couchbase server statistics.
lcb_error_t couchbase_init_connection(lcb_t *instance, const char *host, const char *bucket, const char *user, const char *pass, lcb_uint32_t timeout, const couchbase_opts_t *opts)
Initialize a Couchbase connection instance.
lcb_error_t couchbase_get_key(lcb_t instance, const void *cookie, const char *key)
Retrieve a document by key from Couchbase.
Couchbase wrapper function prototypes and datatypes.
json_object * jobj
JSON objects handled by the json-c library.
HIDDEN fr_dict_attr_t const * attr_event_timestamp
HIDDEN fr_dict_attr_t const * attr_acct_session_time
char * val
Value for the key used in lcb_cntl_string().
char * key
Key value for lcb_cntl_string().
enum json_tokener_error jerr
Error values produced by the json-c library.
couchbase_opts_t * next
Linked list.
Information relating to the parsing of Couchbase document payloads.
static void * fr_dcursor_tail(fr_dcursor_t *cursor)
Wind cursor to the tail item in the list.
static int fr_dcursor_insert(fr_dcursor_t *cursor, void *v)
Insert directly after the current item.
static void fr_dcursor_free_list(fr_dcursor_t *cursor)
Free the current item and all items after it.
static fr_time_delta_t timeout
fr_dict_attr_t const * fr_dict_attr_by_name(fr_dict_attr_err_t *err, fr_dict_attr_t const *parent, char const *attr))
Locate a fr_dict_attr_t by its name.
fr_dict_attr_t const * fr_dict_root(fr_dict_t const *dict)
Return the root attribute of a dictionary.
int fr_json_object_to_value_box(TALLOC_CTX *ctx, fr_value_box_t *out, json_object *object, fr_dict_attr_t const *enumv, bool tainted)
Convert json object to fr_value_box_t.
char const * longname
Client identifier.
Describes a host allowed to send packets to the server.
int map_afrom_value_box(TALLOC_CTX *ctx, map_t **out, char const *lhs, fr_token_t lhs_quote, tmpl_rules_t const *lhs_rules, fr_token_t op, fr_value_box_t *rhs, bool steal_rhs_buffs)
Convert a value box to a map.
@ FR_TYPE_STRING
String of printable characters.
@ FR_TYPE_NULL
Invalid (uninitialised) attribute type.
@ FR_TYPE_UINT16
16 Bit unsigned integer.
@ FR_TYPE_UINT8
8 Bit unsigned integer.
@ FR_TYPE_UINT32
32 Bit unsigned integer.
@ FR_TYPE_INT32
32 Bit signed integer.
@ FR_TYPE_UINT64
64 Bit unsigned integer.
struct tm * localtime_r(time_t const *l_clock, struct tm *result)
int mod_attribute_to_element(const char *name, json_object *map, void *buf)
Map attributes to JSON element names.
static int _get_client_value(char **out, CONF_PAIR const *cp, void *data)
Handle client value processing for client_map_section()
int mod_free_api_opts(rlm_couchbase_t *inst)
Delete a object built by mod_build_api_opts()
int mod_build_api_opts(CONF_SECTION *conf, rlm_couchbase_t *inst)
Build a couchbase_opts_t structure from the configuration "couchbase_api" list.
int mod_load_client_documents(rlm_couchbase_t *inst, CONF_SECTION *tmpl, CONF_SECTION *map)
Load client entries from Couchbase client documents on startup.
int mod_build_attribute_element_map(CONF_SECTION *conf, rlm_couchbase_t *inst)
Build a JSON object map from the configuration "map" list.
int mod_ensure_start_timestamp(json_object *json, fr_pair_list_t *vps)
Ensure accounting documents always contain a valid timestamp.
void * mod_conn_create(TALLOC_CTX *ctx, void *instance, fr_time_delta_t timeout)
Create a new connection pool handle.
int mod_conn_alive(UNUSED void *opaque, void *connection)
Check the health of a connection handle.
int mod_json_object_to_map(TALLOC_CTX *ctx, fr_dcursor_t *out, request_t *request, json_object *json, fr_dict_attr_t const *list)
Build value pairs from the passed JSON object and add to the request.
json_object * mod_value_pair_to_json_object(request_t *request, fr_pair_t *vp)
Convert value pairs to json objects.
static int _mod_conn_free(rlm_couchbase_handle_t *chandle)
Delete a connection pool handle and free related resources.
Function prototypes and datatypes used in the module.
void * cookie
Couchbase cookie (cookie_u cookie_t).
void * handle
Real couchbase instance.
Couchbase instance specific information.
The main module instance.
fr_pair_t * fr_pair_find_by_da(fr_pair_list_t const *list, fr_pair_t const *prev, fr_dict_attr_t const *da)
Find the first pair with a matching da.
void fr_pool_connection_release(fr_pool_t *pool, request_t *request, void *conn)
Release a connection.
void * fr_pool_connection_get(fr_pool_t *pool, request_t *request)
Reserve a connection in the connection pool.
#define FR_SBUFF_OUT(_start, _len_or_end)
Optional arguments passed to vp_tmpl functions.
PUBLIC int snprintf(char *string, size_t length, char *format, va_alist)
int client_map_section(CONF_SECTION *out, CONF_SECTION const *map, client_value_cb_t func, void *data)
Create a client CONF_SECTION using a mapping section to map values from a result set to client attrib...
void client_free(fr_client_t *client)
Free a client.
fr_client_t * client_afrom_cs(TALLOC_CTX *ctx, CONF_SECTION *cs, CONF_SECTION *server_cs, size_t extra)
Allocate a new client from a config section.
bool client_add(fr_client_list_t *clients, fr_client_t *client)
Add a client to a fr_client_list_t.
eap_aka_sim_process_conf_t * inst
size_t strlcat(char *dst, char const *src, size_t siz)
size_t strlcpy(char *dst, char const *src, size_t siz)
Stores an attribute, a value and various bits of other data.
fr_dict_attr_t const *_CONST da
Dictionary attribute defines the attribute number, vendor and type of the pair.
#define fr_table_value_by_str(_table, _name, _def)
Convert a string to a value using a sorted or ordered table.
char * talloc_typed_strdup(TALLOC_CTX *ctx, char const *p)
Call talloc_strdup, setting the type on the new chunk correctly.
static int64_t fr_unix_time_to_sec(fr_unix_time_t delta)
static int64_t fr_time_delta_to_sec(fr_time_delta_t delta)
A time delta, a difference in time measured in nanoseconds.
const bool fr_assignment_op[T_TOKEN_LAST]
fr_table_num_ordered_t const fr_tokens_table[]
const bool fr_comparison_op[T_TOKEN_LAST]
ssize_t fr_pair_print_value_quoted(fr_sbuff_t *out, fr_pair_t const *vp, fr_token_t quote)
Print the value of an attribute to a string.
int fr_value_box_cast_in_place(TALLOC_CTX *ctx, fr_value_box_t *vb, fr_type_t dst_type, fr_dict_attr_t const *dst_enumv)
Convert one type of fr_value_box_t to another in place.
void fr_value_box_clear(fr_value_box_t *data)
Clear/free any existing value and metadata.
static size_t char ** out