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: b27095240c97e450b5518f00e475ddabaf26be86 $
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 */
26RCSID("$Id: b27095240c97e450b5518f00e475ddabaf26be86 $")
27
28#include <freeradius-devel/server/base.h>
29#include <freeradius-devel/server/module_rlm.h>
30#include <freeradius-devel/unlang/xlat_func.h>
31
32/** Client field
33 *
34 */
35typedef struct {
36 CONF_SECTION *cs; //!< Client's CONF_SECTION.
37 CONF_PAIR *cp; //!< First instance of the field in the client's CONF_SECTION.
38 char const *field; //!< Field name.
40
41static int _map_proc_client_get_vp(TALLOC_CTX *ctx, fr_pair_list_t *out, request_t *request,
42 map_t const *map, void *uctx)
43{
44 client_get_vp_ctx_t *client = uctx;
47 fr_dict_attr_t const *da;
48 CONF_PAIR const *cp;
49
50 fr_assert(ctx != NULL);
51
53
54 /*
55 * FIXME: allow multiple entries.
56 */
57 if (tmpl_is_attr(map->lhs)) {
58 da = tmpl_attr_tail_da(map->lhs);
59 } else {
60 char *attr;
61
62 if (tmpl_aexpand(ctx, &attr, request, map->lhs, NULL, NULL) <= 0) {
63 RWDEBUG("Failed expanding string");
64 error:
66 return -1;
67 }
68
69 da = fr_dict_attr_by_name(NULL, fr_dict_root(request->local_dict), attr);
70 if (!da) {
71 RWDEBUG("No such attribute '%s'", attr);
72 talloc_free(attr);
73 goto error;
74 }
75
76 talloc_free(attr);
77 }
78
79 for (cp = client->cp;
80 cp;
81 cp = cf_pair_find_next(client->cs, cp, client->field)) {
82 char const *value = cf_pair_value(cp);
83
84 MEM(vp = fr_pair_afrom_da(ctx, da));
85 if (fr_pair_value_from_str(vp, value, talloc_strlen(value), NULL, false) < 0) {
86 RWDEBUG("Failed parsing value \"%pV\" for attribute %s: %s", fr_box_strvalue(value),
87 tmpl_attr_tail_da(map->lhs)->name, fr_strerror());
89 goto error;
90 }
91
93
94 if (map->op != T_OP_ADD_EQ) break; /* Create multiple attribute for multiple CONF_PAIRs */
95 }
96
98
99 return 0;
100}
101
102/** Map multiple attributes from a client into the request
103 *
104 * @param[out] p_result Result of applying the map:
105 * - #RLM_MODULE_NOOP no rows were returned.
106 * - #RLM_MODULE_UPDATED if one or more #fr_pair_t were added to the #request_t.
107 * - #RLM_MODULE_FAIL if an error occurred.
108 * @param[in] mpctx NULL
109 * @param[in] request The current request.
110 * @param[in] client_override If NULL, use the current client, else use the client matching
111 * the ip given.
112 * @param[in] maps Head of the map list.
113 * @return UNLANG_ACTION_CALCULATE_RESULT
114 */
116 request_t *request, fr_value_box_list_t *client_override, map_list_t const *maps)
117{
119 map_t const *map = NULL;
120 fr_client_t *client;
122
123 if (!fr_value_box_list_empty(client_override)) {
124 fr_ipaddr_t ip;
125 char const *client_str;
126 fr_value_box_t *client_override_head = fr_value_box_list_head(client_override);
127
128 /*
129 * Concat don't asprint, as this becomes a noop
130 * in the vast majority of cases.
131 */
133 client_override_head, client_override, FR_TYPE_STRING,
135 SIZE_MAX) < 0) {
136 REDEBUG("Failed concatenating input data");
138 }
139 client_str = client_override_head->vb_strvalue;
140
141 if (fr_inet_pton(&ip, client_str, -1, AF_UNSPEC, false, true) < 0) {
142 REDEBUG("\"%s\" is not a valid IPv4 or IPv6 address", client_str);
143 rcode = RLM_MODULE_FAIL;
144 goto finish;
145 }
146
147 client = client_find(NULL, &ip, IPPROTO_IP);
148 if (!client) {
149 RDEBUG("No client found with IP \"%s\"", client_str);
150 rcode = RLM_MODULE_NOTFOUND;
151 goto finish;
152 }
153
154 if (client->cs) {
155 char const *filename;
156 int line;
157
158 filename = cf_filename(client->cs);
159 line = cf_lineno(client->cs);
160
161 if (filename) {
162 RDEBUG2("Found client matching \"%s\". Defined in \"%s\" line %i",
163 client_str, filename, line);
164 } else {
165 RDEBUG2("Found client matching \"%s\"", client_str);
166 }
167 }
168 } else {
169 client = client_from_request(request);
170 if (!client) {
171 REDEBUG("No client associated with this request");
173 }
174 }
175 uctx.cs = client->cs;
176
177 RINDENT();
178 while ((map = map_list_next(maps, map))) {
179 char *field = NULL;
180
181 if (tmpl_aexpand(request, &field, request, map->rhs, NULL, NULL) < 0) {
182 REDEBUG("Failed expanding RHS at %s", map->lhs->name);
183 rcode = RLM_MODULE_FAIL;
184 talloc_free(field);
185 break;
186 }
187
188 uctx.cp = cf_pair_find(client->cs, field);
189 if (!uctx.cp) {
190 RDEBUG3("No matching client property \"%s\", skipping...", field);
191 goto next; /* No matching CONF_PAIR found */
192 }
193 uctx.field = field;
194
195 /*
196 * Pass the raw data to the callback, which will
197 * create the VP and add it to the map.
198 */
199 if (map_to_request(request, map, _map_proc_client_get_vp, &uctx) < 0) {
200 rcode = RLM_MODULE_FAIL;
201 talloc_free(field);
202 break;
203 }
204 rcode = RLM_MODULE_UPDATED;
205
206 next:
207 talloc_free(field);
208 }
209 REXDENT();
210
211finish:
212 RETURN_UNLANG_RCODE(rcode);
213}
214
216 { .required = true, .single = true, .type = FR_TYPE_STRING },
217 { .single = true, .type = FR_TYPE_STRING },
219};
220
221/** xlat to get client config data
222 *
223 * Example:
224@verbatim
225%request.client(foo, [<ipaddr>])
226@endverbatim
227 *
228 * @ingroup xlat_functions
229 */
230static xlat_action_t xlat_client(TALLOC_CTX *ctx, fr_dcursor_t *out,
231 UNUSED xlat_ctx_t const *xctx,
232 request_t *request, fr_value_box_list_t *in)
233{
234 char const *value = NULL;
235 fr_ipaddr_t ip;
236 CONF_PAIR *cp;
237 fr_client_t *client = NULL;
238 fr_value_box_t *field = fr_value_box_list_head(in);
239 fr_value_box_t *client_ip = fr_value_box_list_next(in, field);
240 fr_value_box_t *vb;
241
242 if (client_ip) {
243 if (fr_inet_pton(&ip, client_ip->vb_strvalue, -1, AF_UNSPEC, false, true) < 0) {
244 RDEBUG("Invalid client IP address \"%s\"", client_ip->vb_strvalue);
245 return XLAT_ACTION_FAIL;
246 }
247
248 client = client_find(NULL, &ip, IPPROTO_IP);
249 if (!client) {
250 RDEBUG("No client found with IP \"%s\"", client_ip->vb_strvalue);
251 return XLAT_ACTION_FAIL;
252 }
253 } else {
254 client = client_from_request(request);
255 if (!client) {
256 REDEBUG("No client associated with this request");
257 return XLAT_ACTION_FAIL;
258 }
259 }
260
261 cp = cf_pair_find(client->cs, field->vb_strvalue);
262 if (!cp || !(value = cf_pair_value(cp))) {
263 if (strcmp(field->vb_strvalue, "shortname") == 0 && client->shortname) {
264 value = client->shortname;
265 }
266 else if (strcmp(field->vb_strvalue, "nas_type") == 0 && client->nas_type) {
267 value = client->nas_type;
268 }
269 if (!value) return XLAT_ACTION_DONE;
270 }
271
272 MEM(vb = fr_value_box_alloc_null(ctx));
273
274 if (fr_value_box_strdup(ctx, vb, NULL, value, false) < 0) {
275 talloc_free(vb);
276 return XLAT_ACTION_FAIL;
277 }
278
280 return XLAT_ACTION_DONE;
281}
282
283
284/*
285 * Find the client definition.
286 */
287static unlang_action_t CC_HINT(nonnull) mod_authorize(unlang_result_t *p_result, UNUSED module_ctx_t const *mctx, request_t *request)
288{
289 size_t length;
290 char const *value;
291 CONF_PAIR *cp;
292 char buffer[2048];
293 fr_client_t *client;
294
295 /*
296 * Ensure we're only being called from the main thread,
297 * with fake packets.
298 */
299 if ((request->packet->socket.inet.src_port != 0) || (!fr_pair_list_empty(&request->request_pairs)) ||
300 (request->parent != NULL)) {
301 REDEBUG("Improper configuration");
303 }
304
305 client = client_from_request(request);
306 if (!client || !client->cs) {
307 REDEBUG("Unknown client definition");
309 }
310
311 cp = cf_pair_find(client->cs, "directory");
312 if (!cp) {
313 REDEBUG("No directory configuration in the client");
315 }
316
317 value = cf_pair_value(cp);
318 if (!value) {
319 REDEBUG("No value given for the directory entry in the client");
321 }
322
323 length = strlen(value);
324 if (length > (sizeof(buffer) - 256)) {
325 REDEBUG("Directory name too long");
327 }
328
329 memcpy(buffer, value, length + 1);
330 fr_inet_ntoh(&request->packet->socket.inet.src_ipaddr, buffer + length, sizeof(buffer) - length - 1);
331
332 /*
333 * Read the buffer and generate the client.
334 */
335 if (!client->server) RETURN_UNLANG_FAIL;
336
337 client = client_read(buffer, client->server_cs, true);
338 if (!client) RETURN_UNLANG_FAIL;
339
340 /*
341 * Replace the client. This is more than a bit of a
342 * hack.
343 */
344 request->client = client;
345
347}
348
349static int mod_load(void)
350{
351 xlat_t *xlat;
352
353 if (unlikely((xlat = xlat_func_register(NULL, "client", xlat_client, FR_TYPE_STRING)) == NULL)) return -1;
355
356 if (unlikely((xlat = xlat_func_register(NULL, "request.client", xlat_client, FR_TYPE_STRING)) == NULL)) return -1;
358
359 map_proc_register(NULL, NULL, "client", map_proc_client, NULL, 0, FR_VALUE_BOX_SAFE_FOR_ANY);
360
361 return 0;
362}
363
364static void mod_unload(void)
365{
366 xlat_func_unregister("client");
367 map_proc_unregister("client");
368}
369
370/*
371 * The module name should be the only globally exported symbol.
372 * That is, everything else should be 'static'.
373 *
374 * If the module needs to temporarily modify it's instantiation
375 * data, the type should be changed to MODULE_TYPE_THREAD_UNSAFE.
376 * The server will then take care of ensuring that the module
377 * is single-threaded.
378 */
381 .common = {
382 .magic = MODULE_MAGIC_INIT,
383 .name = "dynamic_clients",
384 .onload = mod_load,
385 .unload = mod_unload
386 },
387 .method_group = {
388 .bindings = (module_method_binding_t[]){
389 { .section = SECTION_NAME(CF_IDENT_ANY, CF_IDENT_ANY), .method = mod_authorize },
391 }
392 }
393};
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:488
#define unlikely(_x)
Definition build.h:384
#define UNUSED
Definition build.h:318
Configuration AVP similar to a fr_pair_t.
Definition cf_priv.h:72
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:1433
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:1419
char const * cf_pair_value(CONF_PAIR const *pair)
Return the value of a CONF_PAIR.
Definition cf_util.c:1574
#define cf_lineno(_cf)
Definition cf_util.h:101
#define cf_filename(_cf)
Definition cf_util.h:104
#define CF_IDENT_ANY
Definition cf_util.h:75
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:46
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:3528
fr_dict_attr_t const * fr_dict_root(fr_dict_t const *dict)
Return the root attribute of a dictionary.
Definition dict_util.c:2665
static fr_slen_t in
Definition dict.h:882
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:230
talloc_free(hp)
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:356
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:783
IPv4/6 prefix.
char const * server
Name of the virtual server client is associated with.
Definition client.h:133
char const * nas_type
Type of client (arbitrary).
Definition client.h:131
CONF_SECTION * cs
CONF_SECTION that was parsed to generate the client.
Definition client.h:138
char const * shortname
Client nickname.
Definition client.h:88
CONF_SECTION * server_cs
Virtual server that the client is associated with.
Definition client.h:134
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:455
#define RWDEBUG(fmt,...)
Definition log.h:373
#define RDEBUG3(fmt,...)
Definition log.h:355
#define RINDENT()
Indent R* messages by one level.
Definition log.h:442
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:1884
int map_proc_unregister(char const *name)
Unregister a map processor by name.
Definition map_proc.c:177
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:125
Temporary structure to hold arguments for map calls.
Definition map_proc.h:52
@ 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_value_from_str(fr_pair_t *vp, char const *value, size_t inlen, fr_sbuff_unescape_rules_t const *uerules, UNUSED bool tainted)
Convert string value to native attribute value.
Definition pair.c:2621
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:1352
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:290
void fr_pair_list_init(fr_pair_list_t *list)
Initialise a pair list header.
Definition pair.c:46
#define fr_assert(_expr)
Definition rad_assert.h:37
static void client_read(fr_event_list_t *el, int fd, UNUSED int flags, void *uctx)
#define REDEBUG(fmt,...)
#define RDEBUG2(fmt,...)
#define RDEBUG(fmt,...)
#define RETURN_UNLANG_RCODE(_rcode)
Definition rcode.h:61
#define RETURN_UNLANG_FAIL
Definition rcode.h:63
#define RETURN_UNLANG_OK
Definition rcode.h:64
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_NOTFOUND
User not found.
Definition rcode.h:53
@ RLM_MODULE_UPDATED
OK (pairs modified).
Definition rcode.h:55
#define RETURN_UNLANG_NOOP
Definition rcode.h:69
module_rlm_t rlm_client
Definition rlm_client.c:380
static int mod_load(void)
Definition rlm_client.c:349
static unlang_action_t mod_authorize(unlang_result_t *p_result, UNUSED module_ctx_t const *mctx, request_t *request)
Definition rlm_client.c:287
static void mod_unload(void)
Definition rlm_client.c:364
CONF_PAIR * cp
First instance of the field in the client's CONF_SECTION.
Definition rlm_client.c:37
CONF_SECTION * cs
Client's CONF_SECTION.
Definition rlm_client.c:36
static xlat_arg_parser_t const xlat_client_args[]
Definition rlm_client.c:215
static unlang_action_t map_proc_client(unlang_result_t *p_result, UNUSED map_ctx_t const *mpctx, 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:115
char const * field
Field name.
Definition rlm_client.c:38
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:41
Client field.
Definition rlm_client.c:35
#define SECTION_NAME(_name1, _name2)
Define a section name consisting of a verb and a noun.
Definition section.h:39
#define MODULE_BINDING_TERMINATOR
Terminate a module binding list.
Definition module.h:152
Named methods exported by a module.
Definition module.h:174
#define tmpl_is_attr(vpt)
Definition tmpl.h:208
static fr_dict_attr_t const * tmpl_attr_tail_da(tmpl_t const *vpt)
Return the last attribute reference da.
Definition tmpl.h:801
#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:1064
fr_client_t * client_find(fr_client_list_t const *clients, fr_ipaddr_t const *ipaddr, int proto)
Definition client.c:373
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:1121
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
static size_t talloc_strlen(char const *s)
Returns the length of a talloc array containing a string.
Definition talloc.h:136
@ T_OP_ADD_EQ
Definition token.h:67
static fr_slen_t head
Definition xlat.h:420
unsigned int required
Argument must be present, and non-empty.
Definition xlat.h:146
#define XLAT_ARG_PARSER_TERMINATOR
Definition xlat.h:170
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:145
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:553
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:4633
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:6614
@ FR_VALUE_BOX_LIST_FREE
Definition value.h:238
#define fr_box_strvalue(_val)
Definition value.h:308
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:655
static size_t char ** out
Definition value.h:1030
#define FR_VALUE_BOX_SAFE_FOR_ANY
Definition value.h:173
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:363
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:216
void xlat_func_unregister(char const *name)
Unregister an xlat function.
Definition xlat_func.c:516