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: 512cc911bb05b3fc48c8fb4e68244b5d4dad668f $
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: 512cc911bb05b3fc48c8fb4e68244b5d4dad668f $")
26
27#include <freeradius-devel/curl/base.h>
28#include <freeradius-devel/server/base.h>
29#include <freeradius-devel/server/module_rlm.h>
30
31static fr_dict_t const *dict_radius; /*dictionary for radius protocol*/
32
35
38 { .out = &dict_radius, .proto = "radius" },
40};
41
44 { .out = &attr_user_name, .name = "User-Name", .type = FR_TYPE_STRING, .dict = &dict_radius },
45 { .out = &attr_user_password, .name = "User-Password", .type = FR_TYPE_STRING, .dict = &dict_radius },
47};
48
49extern global_lib_autoinst_t const * const rlm_imap_lib[];
54
55typedef struct {
56 char const *uri; //!< URI of imap server
57 fr_time_delta_t timeout; //!< Timeout for connection and server response
59 fr_curl_conn_config_t conn_config; //!< Reusable CURL handle config
61
64
65typedef struct {
66 imap_slab_list_t *slab; //!< Slab list for connection handles.
67 fr_curl_handle_t *mhandle; //!< Thread specific multi handle. Serves as the dispatch and coralling structure for imap requests.
69
70/*
71 * A mapping of configuration file names to internal variables.
72 */
73static const conf_parser_t module_config[] = {
74 { FR_CONF_OFFSET("uri", rlm_imap_t, uri) },
75 { FR_CONF_OFFSET("timeout", rlm_imap_t, timeout), .dflt = "5.0" },
76 { FR_CONF_OFFSET_SUBSECTION("tls", 0, rlm_imap_t, tls, fr_curl_tls_config ) },//!<loading the tls values
77 { FR_CONF_OFFSET_SUBSECTION("connection", 0, rlm_imap_t, conn_config, fr_curl_conn_config ) },
79};
80
81static void imap_io_module_signal(module_ctx_t const *mctx, request_t *request, UNUSED fr_signal_t action)
82{
83 fr_curl_io_request_t *randle = talloc_get_type_abort(mctx->rctx, fr_curl_io_request_t);
84 rlm_imap_thread_t *t = talloc_get_type_abort(mctx->thread, rlm_imap_thread_t);
85 CURLMcode ret;
86
87 RDEBUG2("Forcefully cancelling pending IMAP request");
88
89 ret = curl_multi_remove_handle(t->mhandle->mandle, randle->candle); /* Gracefully terminate the request */
90 if (ret != CURLM_OK) {
91 RERROR("Failed removing curl handle from multi-handle: %s (%i)", curl_multi_strerror(ret), ret);
92 /* Not much we can do */
93 }
94 t->mhandle->transfers--;
95 imap_slab_release(randle);
96}
97
98/*
99 * Called when the IMAP server responds
100 * It checks if the response was CURLE_OK
101 * If it wasn't we returns REJECT, if it was we returns OK
102*/
104 request_t *request)
105{
107 fr_curl_io_request_t *randle = talloc_get_type_abort(mctx->rctx, fr_curl_io_request_t);
108 fr_curl_tls_t const *tls;
109 long curl_out;
110 long curl_out_valid;
111
112 tls = &inst->tls;
113
114 curl_out_valid = curl_easy_getinfo(randle->candle, CURLINFO_SSL_VERIFYRESULT, &curl_out);
115 if (curl_out_valid == CURLE_OK){
116 RDEBUG2("server certificate %s verified", curl_out ? "was" : "not");
117 } else {
118 RDEBUG2("server certificate result not found");
119 }
120
121 if (randle->result != CURLE_OK) {
122 CURLcode result = randle->result;
123 imap_slab_release(randle);
124 switch(result) {
125 case CURLE_PEER_FAILED_VERIFICATION:
126 case CURLE_LOGIN_DENIED:
128 default:
130 }
131 }
132
133 if (tls->extract_cert_attrs) fr_curl_response_certinfo(request, randle);
134
135 imap_slab_release(randle);
137}
138
139/*
140 * Checks that there is a User-Name and User-Password field in the request
141 * Checks that User-Password is not Blank
142 * Sets the: username, password
143 * website URI
144 * timeout information
145 * and TLS information
146 *
147 * Then it queues the request and yields until a response is given
148 * When it responds, mod_authenticate_resume is called.
149 */
150static unlang_action_t CC_HINT(nonnull(1,2)) mod_authenticate(unlang_result_t *p_result, module_ctx_t const *mctx, request_t *request)
151{
152 rlm_imap_thread_t *t = talloc_get_type_abort(mctx->thread, rlm_imap_thread_t);
153
154 fr_pair_t const *username;
155 fr_pair_t const *password;
156 fr_curl_io_request_t *randle;
157
158 username = fr_pair_find_by_da(&request->request_pairs, NULL, attr_user_name);
159 password = fr_pair_find_by_da(&request->request_pairs, NULL, attr_user_password);
160
161 if (!username) {
162 REDEBUG("Attribute \"User-Name\" is required for authentication");
164 }
165
166 if (!password) {
167 RDEBUG2("Attribute \"User-Password\" is required for authentication");
169 }
170
171 if (password->vp_length == 0) {
172 RDEBUG2("\"User-Password\" must not be empty");
174 }
175
176 randle = imap_slab_reserve(t->slab);
177 if (!randle){
179 }
180
181 FR_CURL_REQUEST_SET_OPTION(CURLOPT_USERNAME, username->vp_strvalue);
182 FR_CURL_REQUEST_SET_OPTION(CURLOPT_PASSWORD, password->vp_strvalue);
183
184 if (fr_curl_io_request_enqueue(t->mhandle, request, randle)) {
185 error:
186 imap_slab_release(randle);
188 }
189
191}
192
193/** Clean up CURL handle on freeing
194 *
195 */
197{
198 curl_easy_cleanup(randle->candle);
199
200 return 0;
201}
202
203/** Callback to configure a CURL handle when it is allocated
204 *
205 */
206static int imap_conn_alloc(fr_curl_io_request_t *randle, void *uctx)
207{
208 rlm_imap_t const *inst = talloc_get_type_abort(uctx, rlm_imap_t);
209
210 randle->candle = curl_easy_init();
211 if (unlikely(!randle->candle)) {
212 error:
213 fr_strerror_printf("Unable to initialise CURL handle");
214 return -1;
215 }
216
217 talloc_set_destructor(randle, _mod_conn_free);
218
219#if CURL_AT_LEAST_VERSION(7,45,0)
220 FR_CURL_SET_OPTION(CURLOPT_DEFAULT_PROTOCOL, "imap");
221#endif
222 FR_CURL_SET_OPTION(CURLOPT_URL, inst->uri);
223#if CURL_AT_LEAST_VERSION(7,85,0)
224 FR_CURL_SET_OPTION(CURLOPT_PROTOCOLS_STR, "imap,imaps");
225#else
226 FR_CURL_SET_OPTION(CURLOPT_PROTOCOLS, CURLPROTO_IMAP | CURLPROTO_IMAPS);
227#endif
228 FR_CURL_SET_OPTION(CURLOPT_CONNECTTIMEOUT_MS, fr_time_delta_to_msec(inst->timeout));
229 FR_CURL_SET_OPTION(CURLOPT_TIMEOUT_MS, fr_time_delta_to_msec(inst->timeout));
230
231 if (DEBUG_ENABLED3) FR_CURL_SET_OPTION(CURLOPT_VERBOSE, 1L);
232
233 if (fr_curl_easy_tls_init(randle, &inst->tls) != 0) goto error;
234
235 return 0;
236}
237
238/*
239 * Initialize a new thread with a curl instance
240 */
242{
243 rlm_imap_t *inst = talloc_get_type_abort(mctx->mi->data, rlm_imap_t);
244 rlm_imap_thread_t *t = talloc_get_type_abort(mctx->thread, rlm_imap_thread_t);
245 fr_curl_handle_t *mhandle;
246
247 if (!(t->slab = imap_slab_list_alloc(t, mctx->el, &inst->conn_config.reuse,
248 imap_conn_alloc, NULL, inst,
249 false, false))) {
250 ERROR("Connection handle pool instantiation failed");
251 return -1;
252 }
253
254 mhandle = fr_curl_io_init(t, mctx->el, false);
255 if (!mhandle) return -1;
256
257 t->mhandle = mhandle;
258 return 0;
259}
260
261/*
262 * Close the thread and free the memory
263 */
265{
266 rlm_imap_thread_t *t = talloc_get_type_abort(mctx->thread, rlm_imap_thread_t);
267
269 talloc_free(t->slab);
270 return 0;
271}
272
273/*
274 * The module name should be the only globally exported symbol.
275 * That is, everything else should be 'static'.
276 *
277 * If the module needs to temporarily modify it's instantiation
278 * data, the type should be changed to MODULE_TYPE_THREAD_UNSAFE.
279 * The server will then take care of ensuring that the module
280 * is single-threaded.
281 */
284 .common = {
285 .magic = MODULE_MAGIC_INIT,
286 .name = "imap",
287 .inst_size = sizeof(rlm_imap_t),
288 .thread_inst_size = sizeof(rlm_imap_thread_t),
289 .config = module_config,
290 .thread_instantiate = mod_thread_instantiate,
291 .thread_detach = mod_thread_detach,
292 },
293 .method_group = {
294 .bindings = (module_method_binding_t[]){
295 { .section = SECTION_NAME("authenticate", CF_IDENT_ANY), .method = mod_authenticate },
297 }
298 }
299};
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:506
#define unlikely(_x)
Definition build.h:402
#define UNUSED
Definition build.h:336
#define CONF_PARSER_TERMINATOR
Definition cf_parse.h:657
#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:280
#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:309
Defines a CONF_PAIR to C data type mapping.
Definition cf_parse.h:594
#define CF_IDENT_ANY
Definition cf_util.h:75
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:478
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:40
fr_dict_attr_t const ** out
Where to write a pointer to the resolved fr_dict_attr_t.
Definition dict.h:292
fr_dict_t const ** out
Where to write a pointer to the loaded/resolved fr_dict_t.
Definition dict.h:305
#define DICT_AUTOLOAD_TERMINATOR
Definition dict.h:311
Specifies an attribute which must be present for the module to function.
Definition dict.h:291
Specifies a dictionary which must be loaded/loadable for the module to function.
Definition dict.h:304
#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
talloc_free(hp)
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:396
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:310
#define DEBUG_ENABLED3
True if global debug level 1-3 messages are enabled.
Definition log.h:259
@ 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:707
#define REDEBUG(fmt,...)
#define RDEBUG2(fmt,...)
#define RETURN_UNLANG_INVALID
Definition rcode.h:66
#define RETURN_UNLANG_FAIL
Definition rcode.h:63
#define RETURN_UNLANG_REJECT
Definition rcode.h:62
#define RETURN_UNLANG_OK
Definition rcode.h:64
static fr_dict_attr_t const * attr_user_password
Definition rlm_imap.c:33
static unlang_action_t mod_authenticate_resume(unlang_result_t *p_result, module_ctx_t const *mctx, request_t *request)
Definition rlm_imap.c:103
imap_slab_list_t * slab
Slab list for connection handles.
Definition rlm_imap.c:66
fr_time_delta_t timeout
Timeout for connection and server response.
Definition rlm_imap.c:57
fr_curl_tls_t tls
Definition rlm_imap.c:58
static fr_dict_t const * dict_radius
Definition rlm_imap.c:31
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:206
static void imap_io_module_signal(module_ctx_t const *mctx, request_t *request, UNUSED fr_signal_t action)
Definition rlm_imap.c:81
char const * uri
URI of imap server.
Definition rlm_imap.c:56
fr_curl_conn_config_t conn_config
Reusable CURL handle config.
Definition rlm_imap.c:59
static int mod_thread_instantiate(module_thread_inst_ctx_t const *mctx)
Definition rlm_imap.c:241
static unlang_action_t mod_authenticate(unlang_result_t *p_result, module_ctx_t const *mctx, request_t *request)
Definition rlm_imap.c:150
global_lib_autoinst_t const *const rlm_imap_lib[]
Definition rlm_imap.c:50
static fr_dict_attr_t const * attr_user_name
Definition rlm_imap.c:34
fr_dict_autoload_t rlm_imap_dict[]
Definition rlm_imap.c:37
fr_dict_attr_autoload_t rlm_imap_dict_attr[]
Definition rlm_imap.c:43
module_rlm_t rlm_imap
Definition rlm_imap.c:283
static const conf_parser_t module_config[]
Definition rlm_imap.c:73
static int _mod_conn_free(fr_curl_io_request_t *randle)
Clean up CURL handle on freeing.
Definition rlm_imap.c:196
static int mod_thread_detach(module_thread_inst_ctx_t const *mctx)
Definition rlm_imap.c:264
fr_curl_handle_t * mhandle
Thread specific multi handle. Serves as the dispatch and coralling structure for imap requests.
Definition rlm_imap.c:67
#define SECTION_NAME(_name1, _name2)
Define a section name consisting of a verb and a noun.
Definition section.h:39
size_t inst_size
Size of the module's instance data.
Definition module.h:212
void * data
Module's instance data.
Definition module.h:293
#define MODULE_BINDING_TERMINATOR
Terminate a module binding list.
Definition module.h:152
Named methods exported by a module.
Definition module.h:174
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:124
#define FR_SLAB_TYPES(_name, _type)
Define type specific wrapper structs for slabs and slab elements.
Definition slab.h:75
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:431
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:110
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))