The FreeRADIUS server  $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
validate.c
Go to the documentation of this file.
1 /**
2  * $Id: 0f5825c50d0720b5db701248432c80023b3fea32 $
3  * @file rlm_yubikey/validate.c
4  * @brief Authentication for yubikey OTP tokens using the ykclient library.
5  *
6  * @author Arran Cudbard-Bell (a.cudbardb@networkradius.com)
7  * @copyright 2013 The FreeRADIUS server project
8  * @copyright 2013 Network RADIUS (legal@networkradius.com)
9  */
10 #define LOG_PREFIX inst->name
11 
12 #include "rlm_yubikey.h"
13 
14 #ifdef HAVE_YKCLIENT
15 #include <freeradius-devel/server/pool.h>
16 
17 /** Frees a ykclient handle
18  *
19  * @param[in] yandle rlm_yubikey_handle_t to close and free.
20  * @return returns 0.
21  */
22 static int _mod_conn_free(ykclient_handle_t **yandle)
23 {
24  ykclient_handle_done(yandle);
25 
26  return 0;
27 }
28 
29 /** Creates a new connection handle for use by the FR connection API.
30  *
31  * Matches the fr_pool_connection_create_t function prototype, is passed to
32  * fr_pool_init, and called when a new connection is required by the
33  * connection pool API.
34  *
35  * @see fr_pool_init
36  * @see fr_pool_connection_create_t
37  * @see connection.c
38  */
39 static void *mod_conn_create(TALLOC_CTX *ctx, void *instance, UNUSED fr_time_delta_t timeout)
40 {
42  ykclient_rc status;
43  ykclient_handle_t *yandle, **marker;
44 
45  status = ykclient_handle_init(inst->ykc, &yandle);
46  if (status != YKCLIENT_OK) {
47  ERROR("%s", ykclient_strerror(status));
48 
49  return NULL;
50  }
51  marker = talloc(ctx, ykclient_handle_t *);
52  talloc_set_destructor(marker, _mod_conn_free);
53  *marker = yandle;
54 
55  return yandle;
56 }
57 
59 {
60  ykclient_rc status;
61  CONF_SECTION *servers;
62 
63  int count = 0;
64 
65  if (!inst->client_id) {
66  ERROR("validation.client_id must be set (to a valid id) when validation is enabled");
67 
68  return -1;
69  }
70 
71  if (!inst->api_key || !*inst->api_key || is_zero(inst->api_key)) {
72  ERROR("validation.api_key must be set (to a valid key) when validation is enabled");
73 
74  return -1;
75  }
76 
77  DEBUG("Initialising ykclient");
78 
79  status = ykclient_global_init();
80  if (status != YKCLIENT_OK) {
81 yk_error:
82  ERROR("%s", ykclient_strerror(status));
83 
84  return -1;
85  }
86 
87  status = ykclient_init(&inst->ykc);
88  if (status != YKCLIENT_OK) goto yk_error;
89 
90  servers = cf_section_find(conf, "servers", CF_IDENT_ANY);
91  if (servers) {
92  CONF_PAIR *uri, *first;
93  /*
94  * If there were no uris configured we just use the default
95  * ykclient uris which point to the yubico servers.
96  */
97  first = uri = cf_pair_find(servers, "uri");
98  if (!uri) {
99  goto init;
100  }
101 
102  while (uri) {
103  count++;
104  uri = cf_pair_find_next(servers, uri, "uri");
105  }
106  inst->uris = talloc_zero_array(inst, char const *, count);
107 
108  uri = first;
109  count = 0;
110  while (uri) {
111  inst->uris[count++] = cf_pair_value(uri);
112  uri = cf_pair_find_next(servers, uri, "uri");
113  }
114  if (count) {
115  status = ykclient_set_url_templates(inst->ykc, count, inst->uris);
116  if (status != YKCLIENT_OK) {
117  goto yk_error;
118  }
119  }
120  }
121 
122 init:
123  status = ykclient_set_client_b64(inst->ykc, inst->client_id, inst->api_key);
124  if (status != YKCLIENT_OK) {
125  ERROR("%s", ykclient_strerror(status));
126 
127  return -1;
128  }
129 
130  inst->pool = module_rlm_connection_pool_init(conf, inst, mod_conn_create, NULL, inst->name, NULL, NULL);
131  if (!inst->pool) {
132  ykclient_done(&inst->ykc);
133 
134  return -1;
135  }
136 
137  return 0;
138 }
139 
141 {
142  fr_pool_free(inst->pool);
143  ykclient_done(&inst->ykc);
144  ykclient_global_done();
145 
146  return 0;
147 }
148 
150  request_t *request, char const *passcode)
151 {
152  rlm_yubikey_t const *inst = talloc_get_type_abort(mctx->mi->data, rlm_yubikey_t);
153  rlm_rcode_t rcode = RLM_MODULE_OK;
154  ykclient_rc status;
155  ykclient_handle_t *yandle;
156 
157  yandle = fr_pool_connection_get(inst->pool, request);
158  if (!yandle) RETURN_MODULE_FAIL;
159 
160  /*
161  * The libcurl multi-handle interface will tear down the TCP sockets for any partially completed
162  * requests when their easy handle is removed from the multistack.
163  *
164  * For performance reasons ykclient will stop processing the request immediately after receiving
165  * a response from one of the servers. If we then immediately call ykclient_handle_cleanup
166  * the connections are destroyed and will need to be re-established the next time the handle
167  * is used.
168  *
169  * To try and prevent this from happening, we leave cleanup until the *next* time
170  * the handle is used, by which time the requests will of hopefully completed and the connections
171  * can be re-used.
172  *
173  */
174  ykclient_handle_cleanup(yandle);
175 
176  status = ykclient_request_process(inst->ykc, yandle, passcode);
177  if (status != YKCLIENT_OK) {
178  REDEBUG("%s", ykclient_strerror(status));
179  switch (status) {
180  case YKCLIENT_BAD_OTP:
181  case YKCLIENT_REPLAYED_OTP:
182  rcode = RLM_MODULE_REJECT;
183  break;
184 
185  case YKCLIENT_NO_SUCH_CLIENT:
186  rcode = RLM_MODULE_NOTFOUND;
187  break;
188 
189  default:
190  rcode = RLM_MODULE_FAIL;
191  }
192  }
193 
194  fr_pool_connection_release(inst->pool, request, yandle);
195 
196  RETURN_MODULE_RCODE(rcode);
197 }
198 #endif
unlang_action_t
Returned by unlang_op_t calls, determine the next action of the interpreter.
Definition: action.h:35
#define UNUSED
Definition: build.h:313
Configuration AVP similar to a fr_pair_t.
Definition: cf_priv.h:70
A section grouping multiple CONF_PAIR.
Definition: cf_priv.h:101
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:1028
CONF_PAIR * cf_pair_find(CONF_SECTION const *cs, char const *attr)
Search for a CONF_PAIR with a specific name.
Definition: cf_util.c:1439
char const * cf_pair_value(CONF_PAIR const *pair)
Return the value of a CONF_PAIR.
Definition: cf_util.c:1594
CONF_PAIR * cf_pair_find_next(CONF_SECTION const *cs, CONF_PAIR const *prev, char const *attr)
Find a pair with a name matching attr, after specified pair.
Definition: cf_util.c:1453
#define CF_IDENT_ANY
Definition: cf_util.h:78
#define ERROR(fmt,...)
Definition: dhcpclient.c:41
#define DEBUG(fmt,...)
Definition: dhcpclient.c:39
static fr_time_delta_t timeout
Definition: dhcpclient.c:54
static bool is_zero(char const *value)
Check whether the string is all zeros.
Definition: misc.h:146
module_instance_t const * mi
Instance of the module being instantiated.
Definition: module_ctx.h:42
Temporary structure to hold arguments for module calls.
Definition: module_ctx.h:41
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:308
void fr_pool_connection_release(fr_pool_t *pool, request_t *request, void *conn)
Release a connection.
Definition: pool.c:1407
void fr_pool_free(fr_pool_t *pool)
Delete a connection pool.
Definition: pool.c:1329
void * fr_pool_connection_get(fr_pool_t *pool, request_t *request)
Reserve a connection in the connection pool.
Definition: pool.c:1392
#define REDEBUG(fmt,...)
Definition: radclient.h:52
static rs_t * conf
Definition: radsniff.c:53
#define RETURN_MODULE_RCODE(_rcode)
Definition: rcode.h:64
rlm_rcode_t
Return codes indicating the result of the module call.
Definition: rcode.h:40
@ 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_REJECT
Immediately reject the request.
Definition: rcode.h:41
@ RLM_MODULE_NOTFOUND
User not found.
Definition: rcode.h:47
static int _mod_conn_free(rlm_cache_memcached_handle_t *mandle)
Free a connection handle.
static void * mod_conn_create(TALLOC_CTX *ctx, void *instance, fr_time_delta_t timeout)
Create a new memcached handle.
int rlm_yubikey_ykclient_init(CONF_SECTION *conf, rlm_yubikey_t *inst)
int rlm_yubikey_ykclient_detach(rlm_yubikey_t *inst)
unlang_action_t rlm_yubikey_validate(rlm_rcode_t *p_result, module_ctx_t const *mctx, request_t *request, char const *passcode)
void * data
Module's instance data.
Definition: module.h:271
return count
Definition: module.c:163
RETURN_MODULE_FAIL
init
Enter the EAP-IDENTITY state.
Definition: state_machine.c:90
eap_aka_sim_process_conf_t * inst
#define talloc_get_type_abort_const
Definition: talloc.h:282
A time delta, a difference in time measured in nanoseconds.
Definition: time.h:80