The FreeRADIUS server $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
Loading...
Searching...
No Matches
rlm_imap.c
Go to the documentation of this file.
1/*
2 * This program is 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 (at
5 * 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: 816e6231a0dd9558741e933e5a48c618899d517b $
19 * @file rlm_imap.c
20 * @brief imap server authentication.
21 *
22 * @copyright 2020 The FreeRADIUS server project
23 * @copyright 2020 Network RADIUS SAS (legal@networkradius.com)
24 */
25RCSID("$Id: 816e6231a0dd9558741e933e5a48c618899d517b $")
26
27#include <freeradius-devel/curl/base.h>
28#include <freeradius-devel/server/base.h>
29#include <freeradius-devel/server/global_lib.h>
30#include <freeradius-devel/server/module_rlm.h>
31#include <freeradius-devel/util/slab.h>
32
33static fr_dict_t const *dict_radius; /*dictionary for radius protocol*/
34
37
40 { .out = &dict_radius, .proto = "radius" },
41 { NULL }
42};
43
46 { .out = &attr_user_name, .name = "User-Name", .type = FR_TYPE_STRING, .dict = &dict_radius },
47 { .out = &attr_user_password, .name = "User-Password", .type = FR_TYPE_STRING, .dict = &dict_radius },
48 { NULL },
49};
50
51extern global_lib_autoinst_t const * const rlm_imap_lib[];
56
57typedef struct {
58 char const *uri; //!< URI of imap server
59 fr_time_delta_t timeout; //!< Timeout for connection and server response
61 fr_curl_conn_config_t conn_config; //!< Reusable CURL handle config
63
66
67typedef struct {
68 imap_slab_list_t *slab; //!< Slab list for connection handles.
69 fr_curl_handle_t *mhandle; //!< Thread specific multi handle. Serves as the dispatch and coralling structure for imap requests.
71
72/*
73 * A mapping of configuration file names to internal variables.
74 */
75static const conf_parser_t module_config[] = {
76 { FR_CONF_OFFSET("uri", rlm_imap_t, uri) },
77 { FR_CONF_OFFSET("timeout", rlm_imap_t, timeout), .dflt = "5.0" },
78 { FR_CONF_OFFSET_SUBSECTION("tls", 0, rlm_imap_t, tls, fr_curl_tls_config ) },//!<loading the tls values
79 { FR_CONF_OFFSET_SUBSECTION("connection", 0, rlm_imap_t, conn_config, fr_curl_conn_config ) },
81};
82
83static void imap_io_module_signal(module_ctx_t const *mctx, request_t *request, UNUSED fr_signal_t action)
84{
85 fr_curl_io_request_t *randle = talloc_get_type_abort(mctx->rctx, fr_curl_io_request_t);
86 rlm_imap_thread_t *t = talloc_get_type_abort(mctx->thread, rlm_imap_thread_t);
87 CURLMcode ret;
88
89 RDEBUG2("Forcefully cancelling pending IMAP request");
90
91 ret = curl_multi_remove_handle(t->mhandle->mandle, randle->candle); /* Gracefully terminate the request */
92 if (ret != CURLM_OK) {
93 RERROR("Failed removing curl handle from multi-handle: %s (%i)", curl_multi_strerror(ret), ret);
94 /* Not much we can do */
95 }
96 t->mhandle->transfers--;
97 imap_slab_release(randle);
98}
99
100/*
101 * Called when the IMAP server responds
102 * It checks if the response was CURLE_OK
103 * If it wasn't we returns REJECT, if it was we returns OK
104*/
106 request_t *request)
107{
109 fr_curl_io_request_t *randle = talloc_get_type_abort(mctx->rctx, fr_curl_io_request_t);
110 fr_curl_tls_t const *tls;
111 long curl_out;
112 long curl_out_valid;
113
114 tls = &inst->tls;
115
116 curl_out_valid = curl_easy_getinfo(randle->candle, CURLINFO_SSL_VERIFYRESULT, &curl_out);
117 if (curl_out_valid == CURLE_OK){
118 RDEBUG2("server certificate %s verified", curl_out ? "was" : "not");
119 } else {
120 RDEBUG2("server certificate result not found");
121 }
122
123 if (randle->result != CURLE_OK) {
124 CURLcode result = randle->result;
125 imap_slab_release(randle);
126 switch(result) {
127 case CURLE_PEER_FAILED_VERIFICATION:
128 case CURLE_LOGIN_DENIED:
130 default:
132 }
133 }
134
135 if (tls->extract_cert_attrs) fr_curl_response_certinfo(request, randle);
136
137 imap_slab_release(randle);
139}
140
141/*
142 * Checks that there is a User-Name and User-Password field in the request
143 * Checks that User-Password is not Blank
144 * Sets the: username, password
145 * website URI
146 * timeout information
147 * and TLS information
148 *
149 * Then it queues the request and yields until a response is given
150 * When it responds, mod_authenticate_resume is called.
151 */
152static unlang_action_t CC_HINT(nonnull(1,2)) mod_authenticate(rlm_rcode_t *p_result, module_ctx_t const *mctx, request_t *request)
153{
154 rlm_imap_thread_t *t = talloc_get_type_abort(mctx->thread, rlm_imap_thread_t);
155
156 fr_pair_t const *username;
157 fr_pair_t const *password;
158 fr_curl_io_request_t *randle;
159
160 username = fr_pair_find_by_da(&request->request_pairs, NULL, attr_user_name);
161 password = fr_pair_find_by_da(&request->request_pairs, NULL, attr_user_password);
162
163 if (!username) {
164 REDEBUG("Attribute \"User-Name\" is required for authentication");
166 }
167
168 if (!password) {
169 RDEBUG2("Attribute \"User-Password\" is required for authentication");
171 }
172
173 if (password->vp_length == 0) {
174 RDEBUG2("\"User-Password\" must not be empty");
176 }
177
178 randle = imap_slab_reserve(t->slab);
179 if (!randle){
181 }
182
183 FR_CURL_REQUEST_SET_OPTION(CURLOPT_USERNAME, username->vp_strvalue);
184 FR_CURL_REQUEST_SET_OPTION(CURLOPT_PASSWORD, password->vp_strvalue);
185
186 if (fr_curl_io_request_enqueue(t->mhandle, request, randle)) {
187 error:
188 imap_slab_release(randle);
190 }
191
193}
194
195/** Clean up CURL handle on freeing
196 *
197 */
199{
200 curl_easy_cleanup(randle->candle);
201
202 return 0;
203}
204
205/** Callback to configure a CURL handle when it is allocated
206 *
207 */
208static int imap_conn_alloc(fr_curl_io_request_t *randle, void *uctx)
209{
210 rlm_imap_t const *inst = talloc_get_type_abort(uctx, rlm_imap_t);
211
212 randle->candle = curl_easy_init();
213 if (unlikely(!randle->candle)) {
214 error:
215 fr_strerror_printf("Unable to initialise CURL handle");
216 return -1;
217 }
218
219 talloc_set_destructor(randle, _mod_conn_free);
220
221#if CURL_AT_LEAST_VERSION(7,45,0)
222 FR_CURL_SET_OPTION(CURLOPT_DEFAULT_PROTOCOL, "imap");
223#endif
224 FR_CURL_SET_OPTION(CURLOPT_URL, inst->uri);
225#if CURL_AT_LEAST_VERSION(7,85,0)
226 FR_CURL_SET_OPTION(CURLOPT_PROTOCOLS_STR, "imap,imaps");
227#else
228 FR_CURL_SET_OPTION(CURLOPT_PROTOCOLS, CURLPROTO_IMAP | CURLPROTO_IMAPS);
229#endif
230 FR_CURL_SET_OPTION(CURLOPT_CONNECTTIMEOUT_MS, fr_time_delta_to_msec(inst->timeout));
231 FR_CURL_SET_OPTION(CURLOPT_TIMEOUT_MS, fr_time_delta_to_msec(inst->timeout));
232
233 if (DEBUG_ENABLED3) FR_CURL_SET_OPTION(CURLOPT_VERBOSE, 1L);
234
235 if (fr_curl_easy_tls_init(randle, &inst->tls) != 0) goto error;
236
237 return 0;
238}
239
240/*
241 * Initialize a new thread with a curl instance
242 */
244{
245 rlm_imap_t *inst = talloc_get_type_abort(mctx->mi->data, rlm_imap_t);
246 rlm_imap_thread_t *t = talloc_get_type_abort(mctx->thread, rlm_imap_thread_t);
247 fr_curl_handle_t *mhandle;
248
249 if (!(t->slab = imap_slab_list_alloc(t, mctx->el, &inst->conn_config.reuse,
250 imap_conn_alloc, NULL, inst,
251 false, false))) {
252 ERROR("Connection handle pool instantiation failed");
253 return -1;
254 }
255
256 mhandle = fr_curl_io_init(t, mctx->el, false);
257 if (!mhandle) return -1;
258
259 t->mhandle = mhandle;
260 return 0;
261}
262
263/*
264 * Close the thread and free the memory
265 */
267{
268 rlm_imap_thread_t *t = talloc_get_type_abort(mctx->thread, rlm_imap_thread_t);
269
271 talloc_free(t->slab);
272 return 0;
273}
274
275/*
276 * The module name should be the only globally exported symbol.
277 * That is, everything else should be 'static'.
278 *
279 * If the module needs to temporarily modify it's instantiation
280 * data, the type should be changed to MODULE_TYPE_THREAD_UNSAFE.
281 * The server will then take care of ensuring that the module
282 * is single-threaded.
283 */
286 .common = {
287 .magic = MODULE_MAGIC_INIT,
288 .name = "imap",
289 .inst_size = sizeof(rlm_imap_t),
290 .thread_inst_size = sizeof(rlm_imap_thread_t),
291 .config = module_config,
292 .thread_instantiate = mod_thread_instantiate,
293 .thread_detach = mod_thread_detach,
294 },
295 .method_group = {
296 .bindings = (module_method_binding_t[]){
297 { .section = SECTION_NAME("authenticate", CF_IDENT_ANY), .method = mod_authenticate },
299 }
300 }
301};
unlang_action_t
Returned by unlang_op_t calls, determine the next action of the interpreter.
Definition action.h:35
#define RCSID(id)
Definition build.h:483
#define unlikely(_x)
Definition build.h:381
#define UNUSED
Definition build.h:315
#define CONF_PARSER_TERMINATOR
Definition cf_parse.h:642
#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_OFFSET_SUBSECTION(_name, _flags, _struct, _field, _subcs)
conf_parser_t which populates a sub-struct using a CONF_SECTION
Definition cf_parse.h:297
Defines a CONF_PAIR to C data type mapping.
Definition cf_parse.h:579
#define CF_IDENT_ANY
Definition cf_util.h:78
fr_curl_handle_t * fr_curl_io_init(TALLOC_CTX *ctx, fr_event_list_t *el, bool multiplex)
#define FR_CURL_REQUEST_SET_OPTION(_x, _y)
Definition base.h:67
CURLcode result
Result of executing the request.
Definition base.h:103
#define FR_CURL_SET_OPTION(_x, _y)
Definition base.h:45
uint64_t transfers
How many transfers are current in progress.
Definition base.h:94
bool extract_cert_attrs
Definition base.h:119
CURLM * mandle
The multi handle.
Definition base.h:95
int fr_curl_io_request_enqueue(fr_curl_handle_t *mhandle, request_t *request, fr_curl_io_request_t *creq)
Sends a request using libcurl.
Definition io.c:482
CURL * candle
Request specific handle.
Definition base.h:102
Uctx data for timer and I/O functions.
Definition base.h:91
Structure representing an individual request being passed to curl for processing.
Definition base.h:101
#define ERROR(fmt,...)
Definition dhcpclient.c:41
fr_dict_attr_t const ** out
Where to write a pointer to the resolved fr_dict_attr_t.
Definition dict.h:268
fr_dict_t const ** out
Where to write a pointer to the loaded/resolved fr_dict_t.
Definition dict.h:281
Specifies an attribute which must be present for the module to function.
Definition dict.h:267
Specifies a dictionary which must be loaded/loadable for the module to function.
Definition dict.h:280
#define MODULE_MAGIC_INIT
Stop people using different module/library/server versions together.
Definition dl_module.h:63
#define GLOBAL_LIB_TERMINATOR
Definition global_lib.h:51
Structure to define how to initialise libraries with global configuration.
Definition global_lib.h:38
int fr_curl_response_certinfo(request_t *request, fr_curl_io_request_t *randle)
Definition base.c:170
int fr_curl_easy_tls_init(fr_curl_io_request_t *randle, fr_curl_tls_t const *conf)
Definition base.c:139
global_lib_autoinst_t fr_curl_autoinst
Definition base.c:387
conf_parser_t fr_curl_conn_config[]
Definition base.c:97
conf_parser_t fr_curl_tls_config[]
Definition base.c:68
#define RERROR(fmt,...)
Definition log.h:298
#define DEBUG_ENABLED3
True if global debug level 1-3 messages are enabled.
Definition log.h:259
talloc_free(reap)
@ FR_TYPE_STRING
String of printable characters.
module_instance_t const * mi
Instance of the module being instantiated.
Definition module_ctx.h:42
void * thread
Thread specific instance data.
Definition module_ctx.h:43
void * rctx
Resume ctx that a module previously set.
Definition module_ctx.h:45
fr_event_list_t * el
Event list to register any IO handlers and timers against.
Definition module_ctx.h:68
void * thread
Thread instance data.
Definition module_ctx.h:67
module_instance_t const * mi
Instance of the module being instantiated.
Definition module_ctx.h:64
Temporary structure to hold arguments for module calls.
Definition module_ctx.h:41
Temporary structure to hold arguments for thread_instantiation calls.
Definition module_ctx.h:63
module_t common
Common fields presented by all modules.
Definition module_rlm.h:39
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:693
#define REDEBUG(fmt,...)
Definition radclient.h:52
#define RDEBUG2(fmt,...)
Definition radclient.h:54
#define RETURN_MODULE_REJECT
Definition rcode.h:55
#define RETURN_MODULE_INVALID
Definition rcode.h:59
#define RETURN_MODULE_OK
Definition rcode.h:57
#define RETURN_MODULE_FAIL
Definition rcode.h:56
rlm_rcode_t
Return codes indicating the result of the module call.
Definition rcode.h:40
static fr_dict_attr_t const * attr_user_password
Definition rlm_imap.c:35
imap_slab_list_t * slab
Slab list for connection handles.
Definition rlm_imap.c:68
fr_time_delta_t timeout
Timeout for connection and server response.
Definition rlm_imap.c:59
fr_curl_tls_t tls
Definition rlm_imap.c:60
static fr_dict_t const * dict_radius
Definition rlm_imap.c:33
static unlang_action_t mod_authenticate(rlm_rcode_t *p_result, module_ctx_t const *mctx, request_t *request)
Definition rlm_imap.c:152
static int imap_conn_alloc(fr_curl_io_request_t *randle, void *uctx)
Callback to configure a CURL handle when it is allocated.
Definition rlm_imap.c:208
static void imap_io_module_signal(module_ctx_t const *mctx, request_t *request, UNUSED fr_signal_t action)
Definition rlm_imap.c:83
char const * uri
URI of imap server.
Definition rlm_imap.c:58
fr_curl_conn_config_t conn_config
Reusable CURL handle config.
Definition rlm_imap.c:61
static int mod_thread_instantiate(module_thread_inst_ctx_t const *mctx)
Definition rlm_imap.c:243
global_lib_autoinst_t const *const rlm_imap_lib[]
Definition rlm_imap.c:52
static unlang_action_t mod_authenticate_resume(rlm_rcode_t *p_result, module_ctx_t const *mctx, request_t *request)
Definition rlm_imap.c:105
static fr_dict_attr_t const * attr_user_name
Definition rlm_imap.c:36
fr_dict_autoload_t rlm_imap_dict[]
Definition rlm_imap.c:39
fr_dict_attr_autoload_t rlm_imap_dict_attr[]
Definition rlm_imap.c:45
module_rlm_t rlm_imap
Definition rlm_imap.c:285
static const conf_parser_t module_config[]
Definition rlm_imap.c:75
static int _mod_conn_free(fr_curl_io_request_t *randle)
Clean up CURL handle on freeing.
Definition rlm_imap.c:198
static int mod_thread_detach(module_thread_inst_ctx_t const *mctx)
Definition rlm_imap.c:266
fr_curl_handle_t * mhandle
Thread specific multi handle. Serves as the dispatch and coralling structure for imap requests.
Definition rlm_imap.c:69
username
#define SECTION_NAME(_name1, _name2)
Define a section name consisting of a verb and a noun.
Definition section.h:40
size_t inst_size
Size of the module's instance data.
Definition module.h:203
void * data
Module's instance data.
Definition module.h:271
#define MODULE_BINDING_TERMINATOR
Terminate a module binding list.
Definition module.h:151
Named methods exported by a module.
Definition module.h:173
fr_signal_t
Signals that can be generated/processed by request signal handlers.
Definition signal.h:38
@ FR_SIGNAL_CANCEL
Request has been cancelled.
Definition signal.h:40
#define FR_SLAB_FUNCS(_name, _type)
Define type specific wrapper functions for slabs and slab elements.
Definition slab.h:120
#define FR_SLAB_TYPES(_name, _type)
Define type specific wrapper structs for slabs and slab elements.
Definition slab.h:72
unlang_action_t unlang_module_yield(request_t *request, module_method_t resume, unlang_module_signal_t signal, fr_signal_t sigmask, void *rctx)
Yield a request back to the interpreter from within a module.
Definition module.c:419
eap_aka_sim_process_conf_t * inst
Stores an attribute, a value and various bits of other data.
Definition pair.h:68
#define talloc_get_type_abort_const
Definition talloc.h:282
static int64_t fr_time_delta_to_msec(fr_time_delta_t delta)
Definition time.h:637
A time delta, a difference in time measured in nanoseconds.
Definition time.h:80
#define fr_strerror_printf(_fmt,...)
Log to thread local error buffer.
Definition strerror.h:64
int nonnull(2, 5))