The FreeRADIUS server $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
Loading...
Searching...
No Matches
rlm_escape.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: 4a9d6b2cb0673e0aadc59954b4705abb9c329658 $
19 * @file rlm_escape.c
20 * @brief Register escape/unescape xlat functions.
21 *
22 * @copyright 2018 Arran Cudbard-Bell (a.cudbardb@freeradius.org)
23 */
24#include "lib/unlang/xlat.h"
25RCSID("$Id: 4a9d6b2cb0673e0aadc59954b4705abb9c329658 $")
27
28#include <freeradius-devel/server/base.h>
29
30#include <freeradius-devel/server/module_rlm.h>
31#include <freeradius-devel/util/debug.h>
32#include <freeradius-devel/unlang/xlat_func.h>
33
34#include <ctype.h>
35
36/*
37 * Define a structure for our module configuration.
38 */
39typedef struct {
40 char const *allowed_chars;
42
43static const conf_parser_t module_config[] = {
44 { FR_CONF_OFFSET("safe_characters", rlm_escape_t, allowed_chars), .dflt = "@abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.-_: /" },
46};
47
48static char const hextab[] = "0123456789abcdef";
49
51 { .required = true, .concat = true, .type = FR_TYPE_STRING },
53};
54
55/** Equivalent to the old safe_characters functionality in rlm_sql but with utf8 support
56 *
57 * Example:
58@verbatim
59%escape('<img>foo.jpg</img>') == "=60img=62foo.jpg=60/img=62"
60@endverbatim
61 *
62 * @ingroup xlat_functions
63 */
64static xlat_action_t escape_xlat(TALLOC_CTX *ctx, fr_dcursor_t *out,
65 xlat_ctx_t const *xctx,
66 request_t *request, fr_value_box_list_t *in)
67{
68 rlm_escape_t const *inst = talloc_get_type_abort(xctx->mctx->mi->data, rlm_escape_t);
69 fr_value_box_t *arg = fr_value_box_list_head(in);
70 char const *p = arg->vb_strvalue;
71 size_t len;
73 fr_sbuff_t sbuff;
74 fr_sbuff_uctx_talloc_t sbuff_ctx;
75 int i;
76
77 len = talloc_array_length(inst->allowed_chars) - 1;
78
80 /*
81 * We don't know how long the final escaped string
82 * will be - assign something twice as long as the input
83 * as a starting point. The maximum length would be 12
84 * times the original if every character is 4 byte UTF8.
85 */
86 if (!fr_sbuff_init_talloc(vb, &sbuff, &sbuff_ctx, arg->vb_length * 2, arg->vb_length * 12)) {
87 error:
88 RPEDEBUG("Failed to allocated buffer for escaped string");
89 talloc_free(vb);
90 return XLAT_ACTION_FAIL;
91 }
92
93 while (p[0]) {
94 int chr_len = 1;
95
96 if (fr_utf8_strchr(&chr_len, inst->allowed_chars, len, p) == NULL) {
97 /*
98 * '=' 1 + ([hex]{2}) * chr_len)
99 */
100 for (i = 0; i < chr_len; i++) {
101 if (fr_sbuff_in_sprintf(&sbuff, "=%02X", (uint8_t)p[i]) < 0)
102 goto error;
103 }
104
105 p += chr_len;
106 continue;
107 }
108
109 /*
110 * Allowed character (copy whole mb chars at once)
111 */
112 if (fr_sbuff_in_bstrncpy(&sbuff, p, chr_len) < 0)
113 goto error;
114 p += chr_len;
115 }
116
117 fr_sbuff_trim_talloc(&sbuff, SIZE_MAX);
118 fr_value_box_strdup_shallow(vb, NULL, fr_sbuff_buff(&sbuff), arg->tainted);
119
121 return XLAT_ACTION_DONE;
122}
123
125 { .required = true, .concat = true, .type = FR_TYPE_STRING },
127};
128
129/** Equivalent to the old safe_characters functionality in rlm_sql
130 *
131 * Example:
132@verbatim
133%unescape('=60img=62foo.jpg=60/img=62') == "<img>foo.jpg</img>"
134@endverbatim
135 *
136 * @ingroup xlat_functions
137 */
139 UNUSED xlat_ctx_t const *xctx,
140 request_t *request, fr_value_box_list_t *in)
141{
142 fr_value_box_t *arg = fr_value_box_list_head(in);
143 char const *p, *end;
144 char *out_p;
145 char *c1, *c2, c3;
146 fr_sbuff_t sbuff;
147 fr_value_box_t *vb;
148
149 MEM(vb = fr_value_box_alloc_null(ctx));
150 if (fr_value_box_bstr_alloc(ctx, &out_p, vb, NULL, arg->vb_length, arg->tainted) < 0) {
151 talloc_free(vb);
152 RPEDEBUG("Failed allocating space for unescaped string");
153 return XLAT_ACTION_FAIL;
154 }
155 sbuff = FR_SBUFF_IN(out_p, arg->vb_length);
156
157 p = arg->vb_strvalue;
158 end = p + arg->vb_length;
159 while (*p) {
160 if (*p != '=') {
161 next:
162
163 (void) fr_sbuff_in_char(&sbuff, *p++);
164 continue;
165 }
166
167 /* Is a = char */
168
169 if (((end - p) < 2) ||
170 !(c1 = memchr(hextab, tolower((uint8_t) *(p + 1)), 16)) ||
171 !(c2 = memchr(hextab, tolower((uint8_t) *(p + 2)), 16))) goto next;
172 c3 = ((c1 - hextab) << 4) + (c2 - hextab);
173
174 (void) fr_sbuff_in_char(&sbuff, c3);
175 p += 3;
176 }
177
178 fr_value_box_strtrim(ctx, vb);
180
181 return XLAT_ACTION_DONE;
182}
183
184/*
185 * Do any per-module initialization that is separate to each
186 * configured instance of the module. e.g. set up connections
187 * to external databases, read configuration files, set up
188 * dictionary entries, etc.
189 *
190 * If configuration information is given in the config section
191 * that must be referenced in later calls, store a handle to it
192 * in *instance otherwise put a null pointer there.
193 */
194static int mod_bootstrap(module_inst_ctx_t const *mctx)
195{
196 xlat_t *xlat;
197
198 xlat = module_rlm_xlat_register(mctx->mi->boot, mctx, "escape", escape_xlat, FR_TYPE_STRING);
201
202 xlat = module_rlm_xlat_register(mctx->mi->boot, mctx, "unescape", unescape_xlat, FR_TYPE_STRING);
205
206 return 0;
207}
208
209/*
210 * The module name should be the only globally exported symbol.
211 * That is, everything else should be 'static'.
212 *
213 * If the module needs to temporarily modify it's instantiation
214 * data, the type should be changed to MODULE_TYPE_THREAD_UNSAFE.
215 * The server will then take care of ensuring that the module
216 * is single-threaded.
217 */
220 .common = {
221 .magic = MODULE_MAGIC_INIT,
222 .name = "escape",
223 .inst_size = sizeof(rlm_escape_t),
225 .bootstrap = mod_bootstrap
226 }
227};
#define USES_APPLE_DEPRECATED_API
Definition build.h:470
#define RCSID(id)
Definition build.h:483
#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
Defines a CONF_PAIR to C data type mapping.
Definition cf_parse.h:579
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
static fr_slen_t in
Definition dict.h:824
#define MODULE_MAGIC_INIT
Stop people using different module/library/server versions together.
Definition dl_module.h:63
static xlat_action_t escape_xlat(TALLOC_CTX *ctx, fr_dcursor_t *out, xlat_ctx_t const *xctx, request_t *request, fr_value_box_list_t *in)
Equivalent to the old safe_characters functionality in rlm_sql but with utf8 support.
Definition rlm_escape.c:64
static xlat_action_t unescape_xlat(TALLOC_CTX *ctx, fr_dcursor_t *out, UNUSED xlat_ctx_t const *xctx, request_t *request, fr_value_box_list_t *in)
Equivalent to the old safe_characters functionality in rlm_sql.
Definition rlm_escape.c:138
#define RPEDEBUG(fmt,...)
Definition log.h:376
talloc_free(reap)
@ FR_TYPE_STRING
String of printable characters.
unsigned char uint8_t
module_instance_t const * mi
Instance of the module being instantiated.
Definition module_ctx.h:42
module_instance_t * mi
Instance of the module being instantiated.
Definition module_ctx.h:51
Temporary structure to hold arguments for instantiation calls.
Definition module_ctx.h:50
xlat_t * module_rlm_xlat_register(TALLOC_CTX *ctx, module_inst_ctx_t const *mctx, char const *name, xlat_func_t func, fr_type_t return_type)
Definition module_rlm.c:257
module_t common
Common fields presented by all modules.
Definition module_rlm.h:39
char const * fr_utf8_strchr(int *out_chr_len, char const *str, ssize_t inlen, char const *chr)
Return a pointer to the first UTF8 char in a string.
Definition print.c:174
static const conf_parser_t config[]
Definition base.c:183
static xlat_arg_parser_t const escape_xlat_arg[]
Definition rlm_escape.c:50
char const * allowed_chars
Definition rlm_escape.c:40
static xlat_arg_parser_t const unescape_xlat_arg[]
Definition rlm_escape.c:124
module_rlm_t rlm_escape
Definition rlm_escape.c:219
static int mod_bootstrap(module_inst_ctx_t const *mctx)
Definition rlm_escape.c:194
static char const hextab[]
Definition rlm_escape.c:48
static const conf_parser_t module_config[]
Definition rlm_escape.c:43
int fr_sbuff_trim_talloc(fr_sbuff_t *sbuff, size_t len)
Trim a talloced sbuff to the minimum length required to represent the contained string.
Definition sbuff.c:419
ssize_t fr_sbuff_in_bstrncpy(fr_sbuff_t *sbuff, char const *str, size_t len)
Copy bytes into the sbuff up to the first \0.
Definition sbuff.c:1480
ssize_t fr_sbuff_in_sprintf(fr_sbuff_t *sbuff, char const *fmt,...)
Print using a fmt string to an sbuff.
Definition sbuff.c:1595
#define FR_SBUFF_IN(_start, _len_or_end)
#define fr_sbuff_buff(_sbuff_or_marker)
#define fr_sbuff_in_char(_sbuff,...)
Talloc sbuff extension structure.
Definition sbuff.h:139
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
void * boot
Data allocated during the boostrap phase.
Definition module.h:274
eap_aka_sim_process_conf_t * inst
xlat expansion parsing and evaluation API.
bool required
Argument must be present, and non-empty.
Definition xlat.h:148
#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
int fr_value_box_strtrim(TALLOC_CTX *ctx, fr_value_box_t *vb)
Trim the length of the string buffer to match the length of the C string.
Definition value.c:3953
void fr_value_box_strdup_shallow(fr_value_box_t *dst, fr_dict_attr_t const *enumv, char const *src, bool tainted)
Assign a buffer containing a nul terminated string to a box, but don't copy it.
Definition value.c:4036
int fr_value_box_bstr_alloc(TALLOC_CTX *ctx, char **out, fr_value_box_t *dst, fr_dict_attr_t const *enumv, size_t len, bool tainted)
Alloc and assign an empty \0 terminated string to a fr_value_box_t.
Definition value.c:4071
#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
module_ctx_t const * mctx
Synthesised module calling ctx.
Definition xlat_ctx.h:52
An xlat calling ctx.
Definition xlat_ctx.h:49
void xlat_func_flags_set(xlat_t *x, xlat_func_flags_t flags)
Specify flags that alter the xlat's behaviour.
Definition xlat_func.c:402
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_FUNC_FLAG_PURE
Definition xlat_func.h:38