The FreeRADIUS server $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
Loading...
Searching...
No Matches
rlm_client.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: b6fbff0dfcd0570fa97dfe40577d722a66276e8d $
19 * @file rlm_client.c
20 * @brief Reads client definitions from flat files as required.
21 *
22 * @copyright 2008 The FreeRADIUS server project
23 * @copyright 2008 Alan DeKok (aland@deployingradius.com)
24 * @copyright 2016 Arran Cudbard-Bell (a.cudbardb@freeradius.org)
25 */
26#include "lib/server/cf_util.h"
27RCSID("$Id: b6fbff0dfcd0570fa97dfe40577d722a66276e8d $")
28
29#include <freeradius-devel/server/base.h>
30#include <freeradius-devel/server/module_rlm.h>
31#include <freeradius-devel/server/map_proc.h>
32#include <freeradius-devel/util/debug.h>
33#include <freeradius-devel/unlang/xlat_func.h>
34
35/** Client field
36 *
37 */
38typedef struct {
39 CONF_SECTION *cs; //!< Client's CONF_SECTION.
40 CONF_PAIR *cp; //!< First instance of the field in the client's CONF_SECTION.
41 char const *field; //!< Field name.
43
44static int _map_proc_client_get_vp(TALLOC_CTX *ctx, fr_pair_list_t *out, request_t *request,
45 map_t const *map, void *uctx)
46{
47 client_get_vp_ctx_t *client = uctx;
50 fr_dict_attr_t const *da;
51 CONF_PAIR const *cp;
52
53 fr_assert(ctx != NULL);
54
56
57 /*
58 * FIXME: allow multiple entries.
59 */
60 if (tmpl_is_attr(map->lhs)) {
61 da = tmpl_attr_tail_da(map->lhs);
62 } else {
63 char *attr;
64
65 if (tmpl_aexpand(ctx, &attr, request, map->lhs, NULL, NULL) <= 0) {
66 RWDEBUG("Failed expanding string");
67 error:
69 return -1;
70 }
71
72 da = fr_dict_attr_by_name(NULL, fr_dict_root(request->dict), attr);
73 if (!da) {
74 RWDEBUG("No such attribute '%s'", attr);
75 talloc_free(attr);
76 goto error;
77 }
78
79 talloc_free(attr);
80 }
81
82 for (cp = client->cp;
83 cp;
84 cp = cf_pair_find_next(client->cs, cp, client->field)) {
85 char const *value = cf_pair_value(cp);
86
87 MEM(vp = fr_pair_afrom_da(ctx, da));
88 if (fr_pair_value_from_str(vp, value, talloc_array_length(value) - 1, NULL, false) < 0) {
89 RWDEBUG("Failed parsing value \"%pV\" for attribute %s: %s", fr_box_strvalue(value),
90 tmpl_attr_tail_da(map->lhs)->name, fr_strerror());
92 goto error;
93 }
94
96
97 if (map->op != T_OP_ADD_EQ) break; /* Create multiple attribute for multiple CONF_PAIRs */
98 }
99
101
102 return 0;
103}
104
105/** Map multiple attributes from a client into the request
106 *
107 * @param[out] p_result Result of applying the map:
108 * - #RLM_MODULE_NOOP no rows were returned.
109 * - #RLM_MODULE_UPDATED if one or more #fr_pair_t were added to the #request_t.
110 * - #RLM_MODULE_FAIL if an error occurred.
111 * @param[in] mod_inst NULL.
112 * @param[in] proc_inst NULL.
113 * @param[in] request The current request.
114 * @param[in] client_override If NULL, use the current client, else use the client matching
115 * the ip given.
116 * @param[in] maps Head of the map list.
117 * @return UNLANG_ACTION_CALCULATE_RESULT
118 */
119static unlang_action_t map_proc_client(rlm_rcode_t *p_result, UNUSED void const *mod_inst, UNUSED void *proc_inst,
120 request_t *request, fr_value_box_list_t *client_override, map_list_t const *maps)
121{
123 map_t const *map = NULL;
124 fr_client_t *client;
126
127 if (!fr_value_box_list_empty(client_override)) {
128 fr_ipaddr_t ip;
129 char const *client_str;
130 fr_value_box_t *client_override_head = fr_value_box_list_head(client_override);
131
132 /*
133 * Concat don't asprint, as this becomes a noop
134 * in the vast majority of cases.
135 */
137 client_override_head, client_override, FR_TYPE_STRING,
139 SIZE_MAX) < 0) {
140 REDEBUG("Failed concatenating input data");
142 }
143 client_str = client_override_head->vb_strvalue;
144
145 if (fr_inet_pton(&ip, client_str, -1, AF_UNSPEC, false, true) < 0) {
146 REDEBUG("\"%s\" is not a valid IPv4 or IPv6 address", client_str);
147 rcode = RLM_MODULE_FAIL;
148 goto finish;
149 }
150
151 client = client_find(NULL, &ip, IPPROTO_IP);
152 if (!client) {
153 RDEBUG("No client found with IP \"%s\"", client_str);
154 rcode = RLM_MODULE_NOTFOUND;
155 goto finish;
156 }
157
158 if (client->cs) {
159 char const *filename;
160 int line;
161
162 filename = cf_filename(client->cs);
163 line = cf_lineno(client->cs);
164
165 if (filename) {
166 RDEBUG2("Found client matching \"%s\". Defined in \"%s\" line %i",
167 client_str, filename, line);
168 } else {
169 RDEBUG2("Found client matching \"%s\"", client_str);
170 }
171 }
172 } else {
173 client = client_from_request(request);
174 if (!client) {
175 REDEBUG("No client associated with this request");
177 }
178 }
179 uctx.cs = client->cs;
180
181 RINDENT();
182 while ((map = map_list_next(maps, map))) {
183 char *field = NULL;
184
185 if (tmpl_aexpand(request, &field, request, map->rhs, NULL, NULL) < 0) {
186 REDEBUG("Failed expanding RHS at %s", map->lhs->name);
187 rcode = RLM_MODULE_FAIL;
188 talloc_free(field);
189 break;
190 }
191
192 uctx.cp = cf_pair_find(client->cs, field);
193 if (!uctx.cp) {
194 RDEBUG3("No matching client property \"%s\", skipping...", field);
195 goto next; /* No matching CONF_PAIR found */
196 }
197 uctx.field = field;
198
199 /*
200 * Pass the raw data to the callback, which will
201 * create the VP and add it to the map.
202 */
203 if (map_to_request(request, map, _map_proc_client_get_vp, &uctx) < 0) {
204 rcode = RLM_MODULE_FAIL;
205 talloc_free(field);
206 break;
207 }
208 rcode = RLM_MODULE_UPDATED;
209
210 next:
211 talloc_free(field);
212 }
213 REXDENT();
214
215finish:
216 RETURN_MODULE_RCODE(rcode);
217}
218
220 { .required = true, .single = true, .type = FR_TYPE_STRING },
221 { .single = true, .type = FR_TYPE_STRING },
223};
224
225/** xlat to get client config data
226 *
227 * Example:
228@verbatim
229%client(foo, [<ipaddr>])
230@endverbatim
231 *
232 * @ingroup xlat_functions
233 */
234static xlat_action_t xlat_client(TALLOC_CTX *ctx, fr_dcursor_t *out,
235 UNUSED xlat_ctx_t const *xctx,
236 request_t *request, fr_value_box_list_t *in)
237{
238 char const *value = NULL;
239 fr_ipaddr_t ip;
240 CONF_PAIR *cp;
241 fr_client_t *client = NULL;
242 fr_value_box_t *field = fr_value_box_list_head(in);
243 fr_value_box_t *client_ip = fr_value_box_list_next(in, field);
244 fr_value_box_t *vb;
245
246 if (client_ip) {
247 if (fr_inet_pton(&ip, client_ip->vb_strvalue, -1, AF_UNSPEC, false, true) < 0) {
248 RDEBUG("Invalid client IP address \"%s\"", client_ip->vb_strvalue);
249 return XLAT_ACTION_FAIL;
250 }
251
252 client = client_find(NULL, &ip, IPPROTO_IP);
253 if (!client) {
254 RDEBUG("No client found with IP \"%s\"", client_ip->vb_strvalue);
255 return XLAT_ACTION_FAIL;
256 }
257 } else {
258 client = client_from_request(request);
259 if (!client) {
260 REDEBUG("No client associated with this request");
261 return XLAT_ACTION_FAIL;
262 }
263 }
264
265 cp = cf_pair_find(client->cs, field->vb_strvalue);
266 if (!cp || !(value = cf_pair_value(cp))) {
267 if (strcmp(field->vb_strvalue, "shortname") == 0 && client->shortname) {
268 value = client->shortname;
269 }
270 else if (strcmp(field->vb_strvalue, "nas_type") == 0 && client->nas_type) {
271 value = client->nas_type;
272 }
273 if (!value) return XLAT_ACTION_DONE;
274 }
275
276 MEM(vb = fr_value_box_alloc_null(ctx));
277
278 if (fr_value_box_strdup(ctx, vb, NULL, value, false) < 0) {
279 talloc_free(vb);
280 return XLAT_ACTION_FAIL;
281 }
282
284 return XLAT_ACTION_DONE;
285}
286
287
288/*
289 * Find the client definition.
290 */
291static unlang_action_t CC_HINT(nonnull) mod_authorize(rlm_rcode_t *p_result, UNUSED module_ctx_t const *mctx, request_t *request)
292{
293 size_t length;
294 char const *value;
295 CONF_PAIR *cp;
296 char buffer[2048];
297 fr_client_t *client;
298
299 /*
300 * Ensure we're only being called from the main thread,
301 * with fake packets.
302 */
303 if ((request->packet->socket.inet.src_port != 0) || (!fr_pair_list_empty(&request->request_pairs)) ||
304 (request->parent != NULL)) {
305 REDEBUG("Improper configuration");
307 }
308
309 client = client_from_request(request);
310 if (!client || !client->cs) {
311 REDEBUG("Unknown client definition");
313 }
314
315 cp = cf_pair_find(client->cs, "directory");
316 if (!cp) {
317 REDEBUG("No directory configuration in the client");
319 }
320
321 value = cf_pair_value(cp);
322 if (!value) {
323 REDEBUG("No value given for the directory entry in the client");
325 }
326
327 length = strlen(value);
328 if (length > (sizeof(buffer) - 256)) {
329 REDEBUG("Directory name too long");
331 }
332
333 memcpy(buffer, value, length + 1);
334 fr_inet_ntoh(&request->packet->socket.inet.src_ipaddr, buffer + length, sizeof(buffer) - length - 1);
335
336 /*
337 * Read the buffer and generate the client.
338 */
339 if (!client->server) RETURN_MODULE_FAIL;
340
341 client = client_read(buffer, client->server_cs, true);
342 if (!client) RETURN_MODULE_FAIL;
343
344 /*
345 * Replace the client. This is more than a bit of a
346 * hack.
347 */
348 request->client = client;
349
351}
352
353static int mod_load(void)
354{
355 xlat_t *xlat;
356
357 if (unlikely((xlat = xlat_func_register(NULL, "client", xlat_client, FR_TYPE_STRING)) == NULL)) return -1;
359
360 map_proc_register(NULL, NULL, "client", map_proc_client, NULL, 0, 0);
361
362 return 0;
363}
364
365static void mod_unload(void)
366{
367 xlat_func_unregister("client");
368 map_proc_unregister("client");
369}
370
371/*
372 * The module name should be the only globally exported symbol.
373 * That is, everything else should be 'static'.
374 *
375 * If the module needs to temporarily modify it's instantiation
376 * data, the type should be changed to MODULE_TYPE_THREAD_UNSAFE.
377 * The server will then take care of ensuring that the module
378 * is single-threaded.
379 */
382 .common = {
383 .magic = MODULE_MAGIC_INIT,
384 .name = "dynamic_clients",
385 .onload = mod_load,
386 .unload = mod_unload
387 },
388 .method_group = {
389 .bindings = (module_method_binding_t[]){
390 { .section = SECTION_NAME(CF_IDENT_ANY, CF_IDENT_ANY), .method = mod_authorize },
392 }
393 }
394};
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:576
int const char int line
Definition acutest.h:702
#define RCSID(id)
Definition build.h:483
#define unlikely(_x)
Definition build.h:381
#define UNUSED
Definition build.h:315
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_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
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
API to create and manipulate internal format configurations.
#define cf_lineno(_cf)
Definition cf_util.h:104
#define cf_filename(_cf)
Definition cf_util.h:107
#define CF_IDENT_ANY
Definition cf_util.h:78
static int fr_dcursor_append(fr_dcursor_t *cursor, void *v)
Insert a single item at the end of the list.
Definition dcursor.h:406
#define MEM(x)
Definition debug.h:36
fr_dict_attr_t const * fr_dict_attr_by_name(fr_dict_attr_err_t *err, fr_dict_attr_t const *parent, char const *attr))
Locate a fr_dict_attr_t by its name.
Definition dict_util.c:3263
fr_dict_attr_t const * fr_dict_root(fr_dict_t const *dict)
Return the root attribute of a dictionary.
Definition dict_util.c:2400
static fr_slen_t in
Definition dict.h:824
Test enumeration values.
Definition dict_test.h:92
#define MODULE_MAGIC_INIT
Stop people using different module/library/server versions together.
Definition dl_module.h:63
static xlat_action_t xlat_client(TALLOC_CTX *ctx, fr_dcursor_t *out, UNUSED xlat_ctx_t const *xctx, request_t *request, fr_value_box_list_t *in)
xlat to get client config data
Definition rlm_client.c:234
char const * fr_inet_ntoh(fr_ipaddr_t const *src, char *out, size_t outlen)
Perform reverse resolution of an IP address.
Definition inet.c:355
int fr_inet_pton(fr_ipaddr_t *out, char const *value, ssize_t inlen, int af, bool resolve, bool mask)
Simple wrapper to decide whether an IP value is v4 or v6 and call the appropriate parser.
Definition inet.c:778
IPv4/6 prefix.
char const * server
Name of the virtual server client is associated with.
Definition client.h:129
char const * nas_type
Type of client (arbitrary).
Definition client.h:127
CONF_SECTION * cs
CONF_SECTION that was parsed to generate the client.
Definition client.h:134
char const * shortname
Client nickname.
Definition client.h:88
CONF_SECTION * server_cs
Virtual server that the client is associated with.
Definition client.h:130
Describes a host allowed to send packets to the server.
Definition client.h:80
#define REXDENT()
Exdent (unindent) R* messages by one level.
Definition log.h:443
#define RWDEBUG(fmt,...)
Definition log.h:361
#define RDEBUG3(fmt,...)
Definition log.h:343
#define RINDENT()
Indent R* messages by one level.
Definition log.h:430
int map_to_request(request_t *request, map_t const *map, radius_map_getvalue_t func, void *ctx)
Convert map_t to fr_pair_t (s) and add them to a request_t.
Definition map.c:1781
talloc_free(reap)
int map_proc_unregister(char const *name)
Unregister a map processor by name.
Definition map_proc.c:183
int map_proc_register(TALLOC_CTX *ctx, void const *mod_inst, char const *name, map_proc_func_t evaluate, map_proc_instantiate_t instantiate, size_t inst_size, fr_value_box_safe_for_t literals_safe_for)
Register a map processor.
Definition map_proc.c:131
@ FR_TYPE_STRING
String of printable characters.
Temporary structure to hold arguments for module calls.
Definition module_ctx.h:41
module_t common
Common fields presented by all modules.
Definition module_rlm.h:39
int fr_pair_append(fr_pair_list_t *list, fr_pair_t *to_add)
Add a VP to the end of the list.
Definition pair.c:1345
fr_pair_t * fr_pair_afrom_da(TALLOC_CTX *ctx, fr_dict_attr_t const *da)
Dynamically allocate a new attribute and assign a fr_dict_attr_t.
Definition pair.c:283
void fr_pair_list_init(fr_pair_list_t *list)
Initialise a pair list header.
Definition pair.c:46
int fr_pair_value_from_str(fr_pair_t *vp, char const *value, size_t inlen, fr_sbuff_unescape_rules_t const *uerules, bool tainted)
Convert string value to native attribute value.
Definition pair.c:2589
#define fr_assert(_expr)
Definition rad_assert.h:38
static void client_read(fr_event_list_t *el, int fd, UNUSED int flags, void *uctx)
#define REDEBUG(fmt,...)
Definition radclient.h:52
#define RDEBUG2(fmt,...)
Definition radclient.h:54
#define RDEBUG(fmt,...)
Definition radclient.h: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
#define RETURN_MODULE_FAIL
Definition rcode.h:56
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_NOTFOUND
User not found.
Definition rcode.h:47
@ RLM_MODULE_UPDATED
OK (pairs modified).
Definition rcode.h:49
module_rlm_t rlm_client
Definition rlm_client.c:381
static int mod_load(void)
Definition rlm_client.c:353
static unlang_action_t map_proc_client(rlm_rcode_t *p_result, UNUSED void const *mod_inst, UNUSED void *proc_inst, request_t *request, fr_value_box_list_t *client_override, map_list_t const *maps)
Map multiple attributes from a client into the request.
Definition rlm_client.c:119
static void mod_unload(void)
Definition rlm_client.c:365
CONF_PAIR * cp
First instance of the field in the client's CONF_SECTION.
Definition rlm_client.c:40
CONF_SECTION * cs
Client's CONF_SECTION.
Definition rlm_client.c:39
static xlat_arg_parser_t const xlat_client_args[]
Definition rlm_client.c:219
char const * field
Field name.
Definition rlm_client.c:41
static unlang_action_t mod_authorize(rlm_rcode_t *p_result, UNUSED module_ctx_t const *mctx, request_t *request)
Definition rlm_client.c:291
static int _map_proc_client_get_vp(TALLOC_CTX *ctx, fr_pair_list_t *out, request_t *request, map_t const *map, void *uctx)
Definition rlm_client.c:44
Client field.
Definition rlm_client.c:38
#define SECTION_NAME(_name1, _name2)
Define a section name consisting of a verb and a noun.
Definition section.h:40
#define MODULE_BINDING_TERMINATOR
Terminate a module binding list.
Definition module.h:151
Named methods exported by a module.
Definition module.h:173
#define tmpl_is_attr(vpt)
Definition tmpl.h:213
static fr_dict_attr_t const * tmpl_attr_tail_da(tmpl_t const *vpt)
Return the last attribute reference da.
Definition tmpl.h:812
#define tmpl_aexpand(_ctx, _out, _request, _vpt, _escape, _escape_ctx)
Expand a tmpl to a C type, allocing a new buffer to hold the string.
Definition tmpl.h:1070
fr_client_t * client_find(fr_client_list_t const *clients, fr_ipaddr_t const *ipaddr, int proto)
Definition client.c:378
fr_client_t * client_from_request(request_t *request)
Search up a list of requests trying to locate one which has a client.
Definition client.c:1112
fr_pair_t * vp
Value pair map.
Definition map.h:77
fr_token_t op
The operator that controls insertion of the dst attribute.
Definition map.h:82
tmpl_t * lhs
Typically describes the attribute to add, modify or compare.
Definition map.h:78
tmpl_t * rhs
Typically describes a literal value or a src attribute to copy or compare.
Definition map.h:79
Stores an attribute, a value and various bits of other data.
Definition pair.h:68
@ T_OP_ADD_EQ
Definition token.h:69
bool required
Argument must be present, and non-empty.
Definition xlat.h:148
static fr_slen_t head
Definition xlat.h:422
#define XLAT_ARG_PARSER_TERMINATOR
Definition xlat.h:168
xlat_action_t
Definition xlat.h:37
@ XLAT_ACTION_FAIL
An xlat function failed.
Definition xlat.h:44
@ XLAT_ACTION_DONE
We're done evaluating this level of nesting.
Definition xlat.h:43
Definition for a single argument consumend by an xlat function.
Definition xlat.h:147
bool fr_pair_list_empty(fr_pair_list_t const *list)
Is a valuepair list empty.
void fr_pair_list_free(fr_pair_list_t *list)
Free memory used by a valuepair list.
void fr_pair_list_append(fr_pair_list_t *dst, fr_pair_list_t *src)
Appends a list of fr_pair_t from a temporary list to a destination list.
char const * fr_strerror(void)
Get the last library error.
Definition strerror.c:554
int fr_value_box_strdup(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_dict_attr_t const *enumv, char const *src, bool tainted)
Copy a nul terminated string to a fr_value_box_t.
Definition value.c:3927
int fr_value_box_list_concat_in_place(TALLOC_CTX *ctx, fr_value_box_t *out, fr_value_box_list_t *list, fr_type_t type, fr_value_box_list_action_t proc_action, bool flatten, size_t max_size)
Concatenate a list of value boxes.
Definition value.c:5777
@ FR_VALUE_BOX_LIST_FREE
Definition value.h:221
#define fr_box_strvalue(_val)
Definition value.h:285
int nonnull(2, 5))
#define fr_value_box_alloc_null(_ctx)
Allocate a value box for later use with a value assignment function.
Definition value.h:632
static size_t char ** out
Definition value.h:997
An xlat calling ctx.
Definition xlat_ctx.h:49
int xlat_func_args_set(xlat_t *x, xlat_arg_parser_t const args[])
Register the arguments of an xlat.
Definition xlat_func.c:365
xlat_t * xlat_func_register(TALLOC_CTX *ctx, char const *name, xlat_func_t func, fr_type_t return_type)
Register an xlat function.
Definition xlat_func.c:218
void xlat_func_unregister(char const *name)
Unregister an xlat function.
Definition xlat_func.c:519