The FreeRADIUS server $Id: f3670dba8951ca10eb4948feb3dc3db9423a334f $
Loading...
Searching...
No Matches
validate.c
Go to the documentation of this file.
1/**
2 * $Id: f039e8c5cd2841d4a7cb95c0cdd369985fd9f2be $
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 */
22static 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 */
39static 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 ERROR("%s", ykclient_strerror(status));
82
83 return -1;
84 }
85
86 status = ykclient_init(&inst->ykc);
87 if (status != YKCLIENT_OK) {
88 ERROR("%s", ykclient_strerror(status));
89 ykclient_global_done();
90 return -1;
91 }
92
93 servers = cf_section_find(conf, "servers", CF_IDENT_ANY);
94 if (servers) {
95 CONF_PAIR *uri, *first;
96 /*
97 * If there were no uris configured we just use the default
98 * ykclient uris which point to the yubico servers.
99 */
100 first = uri = cf_pair_find(servers, "uri");
101 if (!uri) {
102 goto init;
103 }
104
105 while (uri) {
106 count++;
107 uri = cf_pair_find_next(servers, uri, "uri");
108 }
109 inst->uris = talloc_zero_array(inst, char const *, count);
110
111 uri = first;
112 count = 0;
113 while (uri) {
114 inst->uris[count++] = cf_pair_value(uri);
115 uri = cf_pair_find_next(servers, uri, "uri");
116 }
117 if (count) {
118 status = ykclient_set_url_templates(inst->ykc, count, inst->uris);
119 if (status != YKCLIENT_OK) {
120 ERROR("%s", ykclient_strerror(status));
121 ykclient_done(&inst->ykc);
122 ykclient_global_done();
123 return -1;
124 }
125 }
126 }
127
128init:
129 status = ykclient_set_client_b64(inst->ykc, inst->client_id, inst->api_key);
130 if (status != YKCLIENT_OK) {
131 ERROR("%s", ykclient_strerror(status));
132 ykclient_done(&inst->ykc);
133 ykclient_global_done();
134 return -1;
135 }
136
137 inst->pool = module_rlm_connection_pool_init(conf, inst, mod_conn_create, NULL, inst->name, NULL, NULL);
138 if (!inst->pool) {
139 ykclient_done(&inst->ykc);
140 ykclient_global_done();
141 return -1;
142 }
143
144 return 0;
145}
146
148{
149 fr_pool_free(inst->pool);
150 ykclient_done(&inst->ykc);
151 ykclient_global_done();
152
153 return 0;
154}
155
157 request_t *request, char const *passcode)
158{
159 rlm_yubikey_t const *inst = talloc_get_type_abort(mctx->mi->data, rlm_yubikey_t);
161 ykclient_rc status;
162 ykclient_handle_t *yandle;
163
164 yandle = fr_pool_connection_get(inst->pool, request);
165 if (!yandle) RETURN_UNLANG_FAIL;
166
167 /*
168 * The libcurl multi-handle interface will tear down the TCP sockets for any partially completed
169 * requests when their easy handle is removed from the multistack.
170 *
171 * For performance reasons ykclient will stop processing the request immediately after receiving
172 * a response from one of the servers. If we then immediately call ykclient_handle_cleanup
173 * the connections are destroyed and will need to be re-established the next time the handle
174 * is used.
175 *
176 * To try and prevent this from happening, we leave cleanup until the *next* time
177 * the handle is used, by which time the requests will of hopefully completed and the connections
178 * can be re-used.
179 *
180 */
181 ykclient_handle_cleanup(yandle);
182
183 status = ykclient_request_process(inst->ykc, yandle, passcode);
184 if (status != YKCLIENT_OK) {
185 REDEBUG("%s", ykclient_strerror(status));
186 switch (status) {
187 case YKCLIENT_BAD_OTP:
188 case YKCLIENT_REPLAYED_OTP:
189 rcode = RLM_MODULE_REJECT;
190 break;
191
192 case YKCLIENT_NO_SUCH_CLIENT:
193 rcode = RLM_MODULE_NOTFOUND;
194 break;
195
196 default:
197 rcode = RLM_MODULE_FAIL;
198 }
199 }
200
201 fr_pool_connection_release(inst->pool, request, yandle);
202
203 RETURN_UNLANG_RCODE(rcode);
204}
205#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:336
Configuration AVP similar to a fr_pair_t.
Definition cf_priv.h:77
A section grouping multiple CONF_PAIR.
Definition cf_priv.h:106
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:1601
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:1194
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:1587
char const * cf_pair_value(CONF_PAIR const *pair)
Return the value of a CONF_PAIR.
Definition cf_util.c:1746
#define CF_IDENT_ANY
Definition cf_util.h:80
#define ERROR(fmt,...)
Definition dhcpclient.c:40
#define DEBUG(fmt,...)
Definition dhcpclient.c:38
static bool is_zero(char const *value)
Check whether the string is all zeros.
Definition misc.h:127
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:283
void fr_pool_connection_release(fr_pool_t *pool, request_t *request, void *conn)
Release a connection.
Definition pool.c:1410
void fr_pool_free(fr_pool_t *pool)
Delete a connection pool.
Definition pool.c:1332
void * fr_pool_connection_get(fr_pool_t *pool, request_t *request)
Reserve a connection in the connection pool.
Definition pool.c:1395
#define REDEBUG(fmt,...)
static rs_t * conf
Definition radsniff.c:52
#define RETURN_UNLANG_RCODE(_rcode)
Definition rcode.h:61
#define RETURN_UNLANG_FAIL
Definition rcode.h:63
rlm_rcode_t
Return codes indicating the result of the module call.
Definition rcode.h:44
@ RLM_MODULE_OK
The module is OK, continue.
Definition rcode.h:49
@ RLM_MODULE_FAIL
Module failed, don't reply.
Definition rcode.h:48
@ RLM_MODULE_REJECT
Immediately reject the request.
Definition rcode.h:47
@ RLM_MODULE_NOTFOUND
User not found.
Definition rcode.h:53
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)
unlang_action_t rlm_yubikey_validate(unlang_result_t *p_result, module_ctx_t const *mctx, request_t *request, char const *passcode)
int rlm_yubikey_ykclient_init(CONF_SECTION *conf, rlm_yubikey_t *inst)
int rlm_yubikey_ykclient_detach(rlm_yubikey_t *inst)
void * data
Module's instance data.
Definition module.h:293
return count
Definition module.c:155
init
Enter the EAP-IDENTITY state.
eap_aka_sim_process_conf_t * inst
#define talloc_get_type_abort_const
Definition talloc.h:117
A time delta, a difference in time measured in nanoseconds.
Definition time.h:80