The FreeRADIUS server  $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
rlm_couchbase.c
Go to the documentation of this file.
1 /*
2  * This program is free software; you can redistribute it and/or modify
3  * it under the terms of the GNU General Public License as published by
4  * the Free Software Foundation; either version 2 of the License, or
5  * (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software
14  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
15  */
16 
17 /**
18  * $Id: e2008e764a8d28c48a3944d7a4604149d02856e9 $
19  *
20  * @brief Integrate FreeRADIUS with the Couchbase document database.
21  * @file rlm_couchbase.c
22  *
23  * @author Aaron Hurt (ahurt@anbcs.com)
24  * @copyright 2013-2014 The FreeRADIUS Server Project.
25  */
26 
27 RCSID("$Id: e2008e764a8d28c48a3944d7a4604149d02856e9 $")
28 
29 #define LOG_PREFIX "couchbase - "
30 
31 #include <freeradius-devel/server/base.h>
32 #include <freeradius-devel/server/map.h>
33 #include <freeradius-devel/server/module_rlm.h>
34 #include <freeradius-devel/radius/defs.h>
35 
36 #include <freeradius-devel/json/base.h>
37 
38 #include "mod.h"
39 #include "couchbase.h"
40 
41 /**
42  * Client Configuration
43  */
44 static const conf_parser_t client_config[] = {
45  { FR_CONF_OFFSET("view", rlm_couchbase_t, client_view), .dflt = "_design/client/_view/by_name" },
47 };
48 
49 /**
50  * Module Configuration
51  */
52 static const conf_parser_t module_config[] = {
53  { FR_CONF_OFFSET_FLAGS("server", CONF_FLAG_REQUIRED, rlm_couchbase_t, server_raw) },
55  { FR_CONF_OFFSET("username", rlm_couchbase_t, username) },
56  { FR_CONF_OFFSET("password", rlm_couchbase_t, password) },
57 
58  { FR_CONF_OFFSET("acct_key", rlm_couchbase_t, acct_key), .dflt = "radacct_%{%{Acct-Unique-Session-Id} || %{Acct-Session-Id}}", .quote = T_DOUBLE_QUOTED_STRING },
59  { FR_CONF_OFFSET("doctype", rlm_couchbase_t, doctype), .dflt = "radacct" },
60  { FR_CONF_OFFSET("expire", rlm_couchbase_t, expire), .dflt = 0 },
61 
62  { FR_CONF_OFFSET("user_key", rlm_couchbase_t, user_key), .dflt = "raduser_%md5(%tolower(%{Stripped-User-Name} || %{User-Name}))", .quote = T_DOUBLE_QUOTED_STRING },
63  { FR_CONF_OFFSET("read_clients", rlm_couchbase_t, read_clients) }, /* NULL defaults to "no" */
64  { FR_CONF_POINTER("client", 0, CONF_FLAG_SUBSECTION, NULL), .subcs = (void const *) client_config },
66 };
67 
68 static fr_dict_t const *dict_radius;
69 
72  { .out = &dict_radius, .proto = "radius" },
73  { NULL }
74 };
75 
79 
82  { .out = &attr_acct_status_type, .name = "Acct-Status-Type", .type = FR_TYPE_UINT32, .dict = &dict_radius },
83  { .out = &attr_acct_session_time, .name = "Acct-Session-Time", .type = FR_TYPE_UINT32, .dict = &dict_radius },
84  { .out = &attr_event_timestamp, .name = "Event-Timestamp", .type = FR_TYPE_DATE, .dict = &dict_radius },
85  { NULL }
86 };
87 
88 /** Handle authorization requests using Couchbase document data
89  *
90  * Attempt to fetch the document associated with the requested user by
91  * using the deterministic key defined in the configuration. When a valid
92  * document is found it will be parsed and the containing value pairs will be
93  * injected into the request.
94  *
95  * @param[out] p_result Operation status (#rlm_rcode_t).
96  * @param[in] mctx module calling context.
97  * @param[in] request The authorization request.
98  */
99 static unlang_action_t mod_authorize(rlm_rcode_t *p_result, module_ctx_t const *mctx, request_t *request)
100 {
101  rlm_couchbase_t const *inst = talloc_get_type_abort_const(mctx->inst->data, rlm_couchbase_t); /* our module instance */
102  rlm_couchbase_handle_t *handle = NULL; /* connection pool handle */
103  char buffer[MAX_KEY_SIZE];
104  char const *dockey; /* our document key */
105  lcb_error_t cb_error = LCB_SUCCESS; /* couchbase error holder */
106  rlm_rcode_t rcode = RLM_MODULE_OK; /* return code */
107  ssize_t slen;
108 
109  /* assert packet as not null */
110  fr_assert(request->packet != NULL);
111 
112  /* attempt to build document key */
113  slen = tmpl_expand(&dockey, buffer, sizeof(buffer), request, inst->user_key, NULL, NULL);
114  if (slen < 0) RETURN_MODULE_FAIL;
115  if ((dockey == buffer) && is_truncated((size_t)slen, sizeof(buffer))) {
116  REDEBUG("Key too long, expected < " STRINGIFY(sizeof(buffer)) " bytes, got %zi bytes", slen);
118  }
119 
120  /* get handle */
121  handle = fr_pool_connection_get(inst->pool, request);
122 
123  /* check handle */
124  if (!handle) RETURN_MODULE_FAIL;
125 
126  /* set couchbase instance */
127  lcb_t cb_inst = handle->handle;
128 
129  /* set cookie */
130  cookie_t *cookie = handle->cookie;
131 
132  /* fetch document */
133  cb_error = couchbase_get_key(cb_inst, cookie, dockey);
134 
135  /* check error */
136  if (cb_error != LCB_SUCCESS || !cookie->jobj) {
137  /* log error */
138  RERROR("failed to fetch document or parse return");
139  /* set return */
140  rcode = RLM_MODULE_FAIL;
141  /* return */
142  goto finish;
143  }
144 
145  /* debugging */
146  RDEBUG3("parsed user document == %s", json_object_to_json_string(cookie->jobj));
147 
148  {
149  TALLOC_CTX *pool = talloc_pool(request, 1024); /* We need to do lots of allocs */
150  fr_dcursor_t maps;
151  map_t *map = NULL;
152  fr_dlist_head_t map_head;
153  vp_list_mod_t *vlm;
154  fr_dlist_head_t vlm_head;
155 
156  fr_dcursor_init(&maps, &map_head);
157 
158  /*
159  * Convert JSON data into maps
160  */
161  if ((mod_json_object_to_map(pool, &maps, request, cookie->jobj, request_attr_control) < 0) ||
162  (mod_json_object_to_map(pool, &maps, request, cookie->jobj, request_attr_reply) < 0) ||
163  (mod_json_object_to_map(pool, &maps, request, cookie->jobj, request_attr_request) < 0) ||
164  (mod_json_object_to_map(pool, &maps, request, cookie->jobj, request_attr_state) < 0)) {
165  invalid:
166  talloc_free(pool);
167  rcode = RLM_MODULE_INVALID;
168  goto finish;
169  }
170 
171  fr_dlist_init(&vlm_head, vp_list_mod_t, entry);
172 
173  /*
174  * Convert all the maps into list modifications,
175  * which are guaranteed to succeed.
176  */
177  while ((map = fr_dlist_next(&map_head, map))) {
178  if (map_to_list_mod(pool, &vlm, request, map, NULL, NULL) < 0) goto invalid;
179  fr_dlist_insert_tail(&vlm_head, vlm);
180  }
181 
182  if (fr_dlist_empty(&vlm_head)) {
183  RDEBUG2("Nothing to update");
184  talloc_free(pool);
185  rcode = RLM_MODULE_NOOP;
186  goto finish;
187  }
188 
189  /*
190  * Apply the list of modifications
191  */
192  while ((vlm = fr_dlist_next(&vlm_head, vlm))) {
193  int ret;
194 
195  ret = map_list_mod_apply(request, vlm); /* SHOULD NOT FAIL */
196  if (!fr_cond_assert(ret == 0)) {
197  talloc_free(pool);
198  rcode = RLM_MODULE_FAIL;
199  goto finish;
200  }
201  }
202 
203  talloc_free(pool);
204  }
205 
206 finish:
207  /* free json object */
208  if (cookie->jobj) {
209  json_object_put(cookie->jobj);
210  cookie->jobj = NULL;
211  }
212 
213  /* release handle */
214  if (handle) fr_pool_connection_release(inst->pool, request, handle);
215 
216  /* return */
217  RETURN_MODULE_RCODE(rcode);
218 }
219 
220 /** Write accounting data to Couchbase documents
221  *
222  * Handle accounting requests and store the associated data into JSON documents
223  * in couchbase mapping attribute names to JSON element names per the module configuration.
224  *
225  * When an existing document already exists for the same accounting section the new attributes
226  * will be merged with the currently existing data. When conflicts arrise the new attribute
227  * value will replace or be added to the existing value.
228  *
229  * @param[out] p_result Result of calling the module.
230  * @param mctx module calling context.
231  * @param request The accounting request object.
232  */
233 static unlang_action_t mod_accounting(rlm_rcode_t *p_result, module_ctx_t const *mctx, request_t *request)
234 {
235  rlm_couchbase_t const *inst = talloc_get_type_abort_const(mctx->inst->data, rlm_couchbase_t); /* our module instance */
236  rlm_couchbase_handle_t *handle = NULL; /* connection pool handle */
237  rlm_rcode_t rcode = RLM_MODULE_OK; /* return code */
238  fr_pair_t *vp; /* radius value pair linked list */
239  char buffer[MAX_KEY_SIZE];
240  char const *dockey; /* our document key */
241  char document[MAX_VALUE_SIZE]; /* our document body */
242  char element[MAX_KEY_SIZE]; /* mapped radius attribute to element name */
243  int status = 0; /* account status type */
244  int docfound = 0; /* document found toggle */
245  lcb_error_t cb_error = LCB_SUCCESS; /* couchbase error holder */
246  ssize_t slen;
247 
248 
249  /* assert packet as not null */
250  fr_assert(request->packet != NULL);
251 
252  /* sanity check */
253  if ((vp = fr_pair_find_by_da(&request->request_pairs, NULL, attr_acct_status_type)) == NULL) {
254  /* log debug */
255  RDEBUG2("could not find status type in packet");
256  /* return */
258  }
259 
260  /* set status */
261  status = vp->vp_uint32;
262 
263  /* acknowledge the request but take no action */
264  if (status == FR_STATUS_ACCOUNTING_ON || status == FR_STATUS_ACCOUNTING_OFF) {
265  /* log debug */
266  RDEBUG2("handling accounting on/off request without action");
267  /* return */
269  }
270 
271  /* get handle */
272  handle = fr_pool_connection_get(inst->pool, request);
273 
274  /* check handle */
275  if (!handle) RETURN_MODULE_FAIL;
276 
277  /* set couchbase instance */
278  lcb_t cb_inst = handle->handle;
279 
280  /* set cookie */
281  cookie_t *cookie = handle->cookie;
282 
283  /* attempt to build document key */
284  slen = tmpl_expand(&dockey, buffer, sizeof(buffer), request, inst->acct_key, NULL, NULL);
285  if (slen < 0) {
286  rcode = RLM_MODULE_FAIL;
287  goto finish;
288  }
289  if ((dockey == buffer) && is_truncated((size_t)slen, sizeof(buffer))) {
290  REDEBUG("Key too long, expected < " STRINGIFY(sizeof(buffer)) " bytes, got %zi bytes", slen);
291  rcode = RLM_MODULE_FAIL;
292  /* return */
293  goto finish;
294  }
295 
296  /* attempt to fetch document */
297  cb_error = couchbase_get_key(cb_inst, cookie, dockey);
298 
299  /* check error and object */
300  if (cb_error != LCB_SUCCESS || cookie->jerr != json_tokener_success || !cookie->jobj) {
301  /* log error */
302  RERROR("failed to execute get request or parse returned json object");
303  /* free and reset json object */
304  if (cookie->jobj) {
305  json_object_put(cookie->jobj);
306  cookie->jobj = NULL;
307  }
308  /* check cookie json object */
309  } else if (cookie->jobj) {
310  /* set doc found */
311  docfound = 1;
312  /* debugging */
313  RDEBUG3("parsed json body from couchbase: %s", json_object_to_json_string(cookie->jobj));
314  }
315 
316  /* start json document if needed */
317  if (docfound != 1) {
318  /* debugging */
319  RDEBUG2("no existing document found - creating new json document");
320  /* create new json object */
321  cookie->jobj = json_object_new_object();
322  /* set 'docType' element for new document */
323  json_object_object_add_ex(cookie->jobj, "docType", json_object_new_string(inst->doctype),
324  JSON_C_OBJECT_KEY_IS_CONSTANT);
325  /* default startTimestamp and stopTimestamp to null values */
326  json_object_object_add_ex(cookie->jobj, "startTimestamp", NULL, JSON_C_OBJECT_KEY_IS_CONSTANT);
327  json_object_object_add_ex(cookie->jobj, "stopTimestamp", NULL, JSON_C_OBJECT_KEY_IS_CONSTANT);
328  }
329 
330  /* status specific replacements for start/stop time */
331  switch (status) {
332  case FR_STATUS_START:
333  /* add start time */
334  if ((vp = fr_pair_find_by_da(&request->request_pairs, NULL, attr_acct_status_type)) != NULL) {
335  /* add to json object */
336  json_object_object_add_ex(cookie->jobj, "startTimestamp",
338  JSON_C_OBJECT_KEY_IS_CONSTANT);
339  }
340  break;
341 
342  case FR_STATUS_STOP:
343  /* add stop time */
344  if ((vp = fr_pair_find_by_da(&request->request_pairs, NULL, attr_event_timestamp)) != NULL) {
345  /* add to json object */
346  json_object_object_add_ex(cookie->jobj, "stopTimestamp",
348  JSON_C_OBJECT_KEY_IS_CONSTANT);
349  }
350  /* check start timestamp and adjust if needed */
351  mod_ensure_start_timestamp(cookie->jobj, &request->request_pairs);
352  break;
353 
354  case FR_STATUS_ALIVE:
355  /* check start timestamp and adjust if needed */
356  mod_ensure_start_timestamp(cookie->jobj, &request->request_pairs);
357  break;
358 
359  default:
360  /* don't doing anything */
361  rcode = RLM_MODULE_NOOP;
362  /* return */
363  goto finish;
364  }
365 
366  /* loop through pairs and add to json document */
367  for (vp = fr_pair_list_head(&request->request_pairs);
368  vp;
369  vp = fr_pair_list_next(&request->request_pairs, vp)) {
370  /* map attribute to element */
371  if (mod_attribute_to_element(vp->da->name, inst->map, &element) == 0) {
372  /* debug */
373  RDEBUG3("mapped attribute %s => %s", vp->da->name, element);
374  /* add to json object with mapped name */
375  json_object_object_add(cookie->jobj, element, mod_value_pair_to_json_object(request, vp));
376  }
377  }
378 
379  /* copy json string to document and check size */
380  if (strlcpy(document, json_object_to_json_string(cookie->jobj), sizeof(document)) >= sizeof(document)) {
381  /* this isn't good */
382  RERROR("could not write json document - insufficient buffer space");
383  /* set return */
384  rcode = RLM_MODULE_FAIL;
385  /* return */
386  goto finish;
387  }
388 
389  /* debugging */
390  RDEBUG3("setting '%s' => '%s'", dockey, document);
391 
392  /* store document/key in couchbase */
393  cb_error = couchbase_set_key(cb_inst, dockey, document, inst->expire);
394 
395  /* check return */
396  if (cb_error != LCB_SUCCESS) {
397  RERROR("failed to store document (%s): %s (0x%x)", dockey, lcb_strerror(NULL, cb_error), cb_error);
398  }
399 
400 finish:
401  /* free and reset json object */
402  if (cookie->jobj) {
403  json_object_put(cookie->jobj);
404  cookie->jobj = NULL;
405  }
406 
407  /* release our connection handle */
408  if (handle) {
409  fr_pool_connection_release(inst->pool, request, handle);
410  }
411 
412  /* return */
413  RETURN_MODULE_RCODE(rcode);
414 }
415 
416 
417 /** Detach the module
418  *
419  * Detach the module instance and free any allocated resources.
420  *
421  * @param mctx The module instance.
422  * @return Returns 0 (success) in all conditions.
423  */
424 static int mod_detach(module_detach_ctx_t const *mctx)
425 {
426  rlm_couchbase_t *inst = talloc_get_type_abort(mctx->inst->data, rlm_couchbase_t);
427 
428  if (inst->map) json_object_put(inst->map);
429  if (inst->pool) fr_pool_free(inst->pool);
430  if (inst->api_opts) mod_free_api_opts(inst);
431 
432  return 0;
433 }
434 
435 /** Initialize the rlm_couchbase module
436  *
437  * Initialize the module and create the initial Couchbase connection pool.
438  *
439  * @param mctx The module instance.
440  * @return
441  * - 0 on success.
442  * - -1 on failure.
443  */
444 static int mod_instantiate(module_inst_ctx_t const *mctx)
445 {
446  rlm_couchbase_t *inst = talloc_get_type_abort(mctx->inst->data, rlm_couchbase_t); /* our module instance */
447  CONF_SECTION *conf = mctx->inst->conf;
448 
449  {
450  char *server, *p;
451  size_t len, i;
452  bool sep = false;
453 
454  len = talloc_array_length(inst->server_raw) - 1;
455  server = p = talloc_array(inst, char, len + 1);
456  for (i = 0; i < len; i++) {
457  switch (inst->server_raw[i]) {
458  case '\t':
459  case ' ':
460  case ',':
461  /* Consume multiple separators occurring in sequence */
462  if (sep == true) continue;
463 
464  sep = true;
465  *p++ = ';';
466  break;
467 
468  default:
469  sep = false;
470  *p++ = inst->server_raw[i];
471  break;
472  }
473  }
474 
475  *p = '\0';
476  inst->server = server;
477  }
478 
479  /* setup item map */
481  /* fail */
482  return -1;
483  }
484 
485  /* setup libcouchbase extra options */
486  if (mod_build_api_opts(conf, inst) != 0) {
487  /* fail */
488  return -1;
489  }
490 
491  /* initiate connection pool */
493 
494  /* check connection pool */
495  if (!inst->pool) {
496  ERROR("failed to initiate connection pool");
497  /* fail */
498  return -1;
499  }
500 
501  /* load clients if requested */
502  if (inst->read_clients) {
503  CONF_SECTION *cs, *map, *tmpl; /* conf section */
504 
505  /* attempt to find client section */
506  cs = cf_section_find(conf, "client", NULL);
507  if (!cs) {
508  ERROR("failed to find client section while loading clients");
509  /* fail */
510  return -1;
511  }
512 
513  /* attempt to find attribute subsection */
514  map = cf_section_find(cs, "attribute", NULL);
515  if (!map) {
516  ERROR("failed to find attribute subsection while loading clients");
517  /* fail */
518  return -1;
519  }
520 
521  tmpl = cf_section_find(cs, "template", NULL);
522 
523  /* debugging */
524  DEBUG("preparing to load client documents");
525 
526  /* attempt to load clients */
527  if (mod_load_client_documents(inst, tmpl, map) != 0) {
528  /* fail */
529  return -1;
530  }
531  }
532 
533  /* return okay */
534  return 0;
535 }
536 
537 static int mod_load(void)
538 {
539  INFO("libcouchbase version: %s", lcb_get_version(NULL));
541  return 0;
542 }
543 
544 /*
545  * Hook into the FreeRADIUS module system.
546  */
549  .common = {
550  .magic = MODULE_MAGIC_INIT,
551  .name = "couchbase",
552  .flags = MODULE_TYPE_THREAD_SAFE,
553  .inst_size = sizeof(rlm_couchbase_t),
555  .onload = mod_load,
557  .detach = mod_detach
558  },
559  .method_names = (module_method_name_t[]){
560  { .name1 = "recv", .name2 = CF_IDENT_ANY, .method = mod_authorize },
561  { .name1 = "accounting", .name2 = CF_IDENT_ANY, .method = mod_accounting },
563  }
564 };
unlang_action_t
Returned by unlang_op_t calls, determine the next action of the interpreter.
Definition: action.h:35
static int const char char buffer[256]
Definition: acutest.h:574
#define RCSID(id)
Definition: build.h:444
#define STRINGIFY(x)
Definition: build.h:195
#define CONF_PARSER_TERMINATOR
Definition: cf_parse.h:626
#define FR_CONF_OFFSET(_name, _struct, _field)
conf_parser_t which parses a single CONF_PAIR, writing the result to a field in a struct
Definition: cf_parse.h:268
#define FR_CONF_POINTER(_name, _type, _flags, _res_p)
conf_parser_t which parses a single CONF_PAIR producing a single global result
Definition: cf_parse.h:310
#define FR_CONF_OFFSET_FLAGS(_name, _flags, _struct, _field)
conf_parser_t which parses a single CONF_PAIR, writing the result to a field in a struct
Definition: cf_parse.h:256
@ CONF_FLAG_REQUIRED
Error out if no matching CONF_PAIR is found, and no dflt value is set.
Definition: cf_parse.h:406
@ CONF_FLAG_SUBSECTION
Instead of putting the information into a configuration structure, the configuration file routines MA...
Definition: cf_parse.h:400
Defines a CONF_PAIR to C data type mapping.
Definition: cf_parse.h:563
A section grouping multiple CONF_PAIR.
Definition: cf_priv.h:89
CONF_SECTION * cf_section_find(CONF_SECTION const *cs, char const *name1, char const *name2)
Find a CONF_SECTION with name1 and optionally name2.
Definition: cf_util.c:970
#define CF_IDENT_ANY
Definition: cf_util.h:78
lcb_error_t couchbase_set_key(lcb_t instance, const char *key, const char *document, int expire)
Store a document by key in Couchbase.
Definition: couchbase.c:288
lcb_error_t couchbase_get_key(lcb_t instance, const void *cookie, const char *key)
Retrieve a document by key from Couchbase.
Definition: couchbase.c:325
Couchbase wrapper function prototypes and datatypes.
json_object * jobj
JSON objects handled by the json-c library.
Definition: couchbase.h:45
enum json_tokener_error jerr
Error values produced by the json-c library.
Definition: couchbase.h:47
Information relating to the parsing of Couchbase document payloads.
Definition: couchbase.h:44
#define fr_dcursor_init(_cursor, _head)
Initialise a cursor.
Definition: dcursor.h:728
#define fr_cond_assert(_x)
Calls panic_action ifndef NDEBUG, else logs error and evaluates to value of _x.
Definition: debug.h:137
#define FR_STATUS_STOP
Definition: defs.h:137
#define FR_STATUS_START
Definition: defs.h:136
#define FR_STATUS_ALIVE
Definition: defs.h:138
#define FR_STATUS_ACCOUNTING_OFF
Definition: defs.h:140
#define FR_STATUS_ACCOUNTING_ON
Definition: defs.h:139
#define ERROR(fmt,...)
Definition: dhcpclient.c:41
#define DEBUG(fmt,...)
Definition: dhcpclient.c:39
fr_dict_attr_t const ** out
Where to write a pointer to the resolved fr_dict_attr_t.
Definition: dict.h:250
fr_dict_t const ** out
Where to write a pointer to the loaded/resolved fr_dict_t.
Definition: dict.h:263
Specifies an attribute which must be present for the module to function.
Definition: dict.h:249
Specifies a dictionary which must be loaded/loadable for the module to function.
Definition: dict.h:262
void *_CONST data
Module instance's parsed configuration.
Definition: dl_module.h:165
#define MODULE_MAGIC_INIT
Stop people using different module/library/server versions together.
Definition: dl_module.h:65
CONF_SECTION *_CONST conf
Module's instance configuration.
Definition: dl_module.h:166
dl_module_inst_t const * inst
Definition: dl_module.h:87
#define fr_dlist_init(_head, _type, _field)
Initialise the head structure of a doubly linked list.
Definition: dlist.h:260
static void * fr_dlist_next(fr_dlist_head_t const *list_head, void const *ptr)
Get the next item in a list.
Definition: dlist.h:555
static bool fr_dlist_empty(fr_dlist_head_t const *list_head)
Check whether a list has any items.
Definition: dlist.h:501
static int fr_dlist_insert_tail(fr_dlist_head_t *list_head, void *ptr)
Insert an item into the tail of a list.
Definition: dlist.h:378
Head of a doubly linked list.
Definition: dlist.h:51
void fr_json_version_print(void)
Print JSON-C version.
Definition: json.c:459
#define RDEBUG3(fmt,...)
Definition: log.h:343
#define RERROR(fmt,...)
Definition: log.h:298
talloc_free(reap)
int map_list_mod_apply(request_t *request, vp_list_mod_t const *vlm)
Apply the output of map_to_list_mod to a request.
Definition: map_async.c:922
int map_to_list_mod(TALLOC_CTX *ctx, vp_list_mod_t **out, request_t *request, map_t const *map, fr_value_box_list_t *lhs_result, fr_value_box_list_t *rhs_result)
Evaluate a map creating a new map with TMPL_TYPE_ATTR LHS and TMPL_TYPE_DATA RHS.
Definition: map_async.c:251
A list modification.
Definition: map.h:99
@ FR_TYPE_DATE
Unix time stamp, always has value >2^31.
Definition: merged_model.c:111
@ FR_TYPE_UINT32
32 Bit unsigned integer.
Definition: merged_model.c:99
long int ssize_t
Definition: merged_model.c:24
int mod_attribute_to_element(const char *name, json_object *map, void *buf)
Map attributes to JSON element names.
Definition: mod.c:311
int mod_free_api_opts(rlm_couchbase_t *inst)
Delete a object built by mod_build_api_opts()
Definition: mod.c:63
int mod_build_api_opts(CONF_SECTION *conf, rlm_couchbase_t *inst)
Build a couchbase_opts_t structure from the configuration "couchbase_api" list.
Definition: mod.c:93
int mod_load_client_documents(rlm_couchbase_t *inst, CONF_SECTION *tmpl, CONF_SECTION *map)
Load client entries from Couchbase client documents on startup.
Definition: mod.c:706
int mod_build_attribute_element_map(CONF_SECTION *conf, rlm_couchbase_t *inst)
Build a JSON object map from the configuration "map" list.
Definition: mod.c:237
int mod_ensure_start_timestamp(json_object *json, fr_pair_list_t *vps)
Ensure accounting documents always contain a valid timestamp.
Definition: mod.c:604
int mod_conn_alive(UNUSED void *opaque, void *connection)
Check the health of a connection handle.
Definition: mod.c:208
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.
Definition: mod.c:373
json_object * mod_value_pair_to_json_object(request_t *request, fr_pair_t *vp)
Convert value pairs to json objects.
Definition: mod.c:510
Function prototypes and datatypes used in the module.
#define MAX_VALUE_SIZE
Definition: mod.h:35
void * cookie
Couchbase cookie (cookie_u cookie_t).
Definition: mod.h:73
#define MAX_KEY_SIZE
Definition: mod.h:38
void * handle
Real couchbase instance.
Definition: mod.h:72
Couchbase instance specific information.
Definition: mod.h:71
The main module instance.
Definition: mod.h:44
dl_module_inst_t const * inst
Dynamic loader API handle for the module.
Definition: module_ctx.h:52
dl_module_inst_t const * inst
Dynamic loader API handle for the module.
Definition: module_ctx.h:42
Temporary structure to hold arguments for module calls.
Definition: module_ctx.h:41
Temporary structure to hold arguments for instantiation calls.
Definition: module_ctx.h:51
Specifies a module method identifier.
Definition: module_method.c:36
fr_pool_t * module_rlm_connection_pool_init(CONF_SECTION *module, void *opaque, fr_pool_connection_create_t c, fr_pool_connection_alive_t a, char const *log_prefix, char const *trigger_prefix, fr_pair_list_t *trigger_args)
Initialise a module specific connection pool.
Definition: module_rlm.c:248
module_t common
Common fields presented by all modules.
Definition: module_rlm.h:37
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.
Definition: pair.c:688
void fr_pool_connection_release(fr_pool_t *pool, request_t *request, void *conn)
Release a connection.
Definition: pool.c:1405
void fr_pool_free(fr_pool_t *pool)
Delete a connection pool.
Definition: pool.c:1327
void * fr_pool_connection_get(fr_pool_t *pool, request_t *request)
Reserve a connection in the connection pool.
Definition: pool.c:1390
#define is_truncated(_ret, _max)
Definition: print.h:48
static const conf_parser_t config[]
Definition: base.c:188
#define REDEBUG(fmt,...)
Definition: radclient.h:52
#define RDEBUG2(fmt,...)
Definition: radclient.h:54
#define INFO(fmt,...)
Definition: radict.c:54
static rs_t * conf
Definition: radsniff.c:53
#define RETURN_MODULE_NOOP
Definition: rcode.h:62
#define RETURN_MODULE_RCODE(_rcode)
Definition: rcode.h:64
#define RETURN_MODULE_OK
Definition: rcode.h:57
rlm_rcode_t
Return codes indicating the result of the module call.
Definition: rcode.h:40
@ RLM_MODULE_INVALID
The module considers the request invalid.
Definition: rcode.h:45
@ RLM_MODULE_OK
The module is OK, continue.
Definition: rcode.h:43
@ RLM_MODULE_FAIL
Module failed, don't reply.
Definition: rcode.h:42
@ RLM_MODULE_NOOP
Module succeeded without doing anything.
Definition: rcode.h:48
fr_dict_attr_t const * request_attr_request
Definition: request.c:41
fr_dict_attr_t const * request_attr_control
Definition: request.c:43
fr_dict_attr_t const * request_attr_state
Definition: request.c:44
fr_dict_attr_t const * request_attr_reply
Definition: request.c:42
static void * mod_conn_create(TALLOC_CTX *ctx, void *instance, fr_time_delta_t timeout)
Create a new memcached handle.
static int mod_detach(module_detach_ctx_t const *mctx)
Detach the module.
static int mod_load(void)
fr_dict_autoload_t rlm_couchbase_dict[]
Definition: rlm_couchbase.c:71
fr_dict_attr_t const * attr_acct_session_time
Definition: rlm_couchbase.c:77
static fr_dict_t const * dict_radius
Definition: rlm_couchbase.c:68
fr_dict_attr_autoload_t rlm_couchbase_dict_attr[]
Definition: rlm_couchbase.c:81
static unlang_action_t mod_accounting(rlm_rcode_t *p_result, module_ctx_t const *mctx, request_t *request)
Write accounting data to Couchbase documents.
module_rlm_t rlm_couchbase
static unlang_action_t mod_authorize(rlm_rcode_t *p_result, module_ctx_t const *mctx, request_t *request)
Handle authorization requests using Couchbase document data.
Definition: rlm_couchbase.c:99
fr_dict_attr_t const * attr_acct_status_type
Definition: rlm_couchbase.c:76
static const conf_parser_t client_config[]
Client Configuration.
Definition: rlm_couchbase.c:44
static const conf_parser_t module_config[]
Module Configuration.
Definition: rlm_couchbase.c:52
fr_dict_attr_t const * attr_event_timestamp
Definition: rlm_couchbase.c:78
static int mod_instantiate(module_inst_ctx_t const *mctx)
Initialize the rlm_couchbase module.
static int instantiate(module_inst_ctx_t const *mctx)
Definition: rlm_rest.c:1312
username
Definition: rlm_securid.c:420
@ MODULE_TYPE_THREAD_SAFE
Module is threadsafe.
Definition: module.h:49
#define MODULE_NAME_TERMINATOR
Definition: module.h:135
#define tmpl_expand(_out, _buff, _buff_len, _request, _vpt, _escape, _escape_ctx)
Expand a tmpl to a C type, using existing storage to hold variably sized types.
Definition: tmpl.h:1044
RETURN_MODULE_FAIL
fr_assert(0)
eap_aka_sim_process_conf_t * inst
fr_pair_t * vp
size_t strlcpy(char *dst, char const *src, size_t siz)
Definition: strlcpy.c:34
Value pair map.
Definition: map.h:77
Stores an attribute, a value and various bits of other data.
Definition: pair.h:68
fr_dict_attr_t const *_CONST da
Dictionary attribute defines the attribute number, vendor and type of the pair.
Definition: pair.h:69
#define talloc_get_type_abort_const
Definition: talloc.h:270
@ T_DOUBLE_QUOTED_STRING
Definition: token.h:121
fr_pair_t * fr_pair_list_head(fr_pair_list_t const *list)
Get the head of a valuepair list.
Definition: pair_inline.c:43
fr_pair_t * fr_pair_list_next(fr_pair_list_t const *list, fr_pair_t const *item))
Get the next item in a valuepair list after a specific entry.
Definition: pair_inline.c:70