The FreeRADIUS server $Id: f3670dba8951ca10eb4948feb3dc3db9423a334f $
Loading...
Searching...
No Matches
regex.c
Go to the documentation of this file.
1/*
2 * This program 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
5 * (at 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: f549d5adcf81a3b8a81d7ccfb807752a2874cadd $
19 *
20 * @file src/lib/server/regex.c
21 * @brief Regular expression functions used by the server library.
22 *
23 * @copyright 2014 The FreeRADIUS server project
24 */
25
26RCSID("$Id: f549d5adcf81a3b8a81d7ccfb807752a2874cadd $")
27
28#include <freeradius-devel/server/regex.h>
29#include <freeradius-devel/server/request_data.h>
30#include <freeradius-devel/util/debug.h>
31
32#ifdef HAVE_REGEX
33
34#define REQUEST_DATA_REGEX (0xadbeef00)
35
36typedef struct {
37#if defined(HAVE_REGEX_PCRE2)
38 regex_t *preg; //!< Compiled pattern.
39#endif
40 fr_regmatch_t *regmatch; //!< Match vectors.
41
42 fr_value_box_safety_t safety; //!< Safety of the subject the captures came from.
43} fr_regcapture_t;
44
45/** Adds subcapture values to request data
46 *
47 * Allows use of %{n} expansions.
48 *
49 * @note If preg was runtime-compiled, it will be consumed and *preg will be set to NULL.
50 * @note regmatch will be consumed and *regmatch will be set to NULL.
51 * @note Their lifetimes will be bound to the match request data.
52 *
53 * @param[in] request Current request.
54 * @param[in,out] preg Compiled pattern. May be set to NULL if
55 * reparented to the regcapture struct.
56 * @param[in,out] regmatch Pointers into value. May be set to NULL if
57 * reparented to the regcapture struct.
58 * @param[in] safety of the value which we matched against
59 */
60void regex_sub_to_request(request_t *request, regex_t **preg, fr_regmatch_t **regmatch, fr_value_box_safety_t const *safety)
61{
62 fr_regcapture_t *old_rc, *new_rc; /* lldb doesn't like bare new *sigh* */
63
64 /*
65 * Clear out old_rc matches
66 */
67 old_rc = request_data_get(request, request, REQUEST_DATA_REGEX);
68 if (old_rc) {
69 DEBUG4("Clearing %zu matches", old_rc->regmatch->used);
70 talloc_free(old_rc);
71 } else {
72 DEBUG4("No matches");
73 }
74
75 if (!regmatch || ((*regmatch)->used == 0)) return;
76
77 fr_assert(preg && *preg);
78 fr_assert(regmatch);
79 fr_assert(safety);
80
81 DEBUG4("Adding %zu matches", (*regmatch)->used);
82
83 /*
84 * Container struct for all the match data
85 */
86 MEM(new_rc = talloc(request, fr_regcapture_t));
87
88 /*
89 * Steal runtime pregs, leave precompiled ones
90 */
91#if defined(HAVE_REGEX_PCRE2)
92 if (!(*preg)->precompiled) {
93 new_rc->preg = talloc_steal(new_rc, *preg);
94 *preg = NULL;
95 } else {
96 new_rc->preg = *preg; /* Compiled on startup, will hopefully stick around */
97 }
98#endif
99
100 /*
101 * Steal match data
102 */
103 new_rc->regmatch = talloc_steal(new_rc, *regmatch);
104 new_rc->safety = *safety;
105 *regmatch = NULL;
106
107 request_data_talloc_add(request, request, REQUEST_DATA_REGEX, fr_regcapture_t, new_rc, true, false, false);
108}
109
110# if defined(HAVE_REGEX_PCRE2)
111/** Extract a subcapture value from the request
112 *
113 * @note This is the PCRE variant of the function.
114 *
115 * @param[in] ctx To allocate subcapture buffer in.
116 * @param[out] out Where to write the subcapture string.
117 * @param[in] request to extract.
118 * @param[in] num Subcapture index (0 for entire match).
119 * @return
120 * - 0 on success.
121 * - -1 on notfound.
122 */
123int regex_request_to_sub(TALLOC_CTX *ctx, fr_value_box_t *out, request_t *request, uint32_t num)
124{
125 fr_regcapture_t *rc;
126 char *buff;
127 size_t len;
128 int ret;
129 pcre2_match_data *match_data;
130
131 rc = request_data_reference(request, request, REQUEST_DATA_REGEX);
132 if (!rc) {
133 RDEBUG4("No subcapture data found");
134 return -1;
135 }
136 match_data = talloc_get_type_abort(rc->regmatch->match_data, pcre2_match_data);
137
138 ret = pcre2_substring_length_bynumber(match_data, num, &len);
139 switch (ret) {
140 case PCRE2_ERROR_NOMEMORY:
141 MEM(NULL);
142 break;
143
144 /*
145 * Not finding a substring is fine
146 */
147 case PCRE2_ERROR_NOSUBSTRING:
148 RDEBUG4("%i/%zu Not found", num + 1, rc->regmatch->used);
149 return -1;
150
151 default:
152 if (ret < 0) {
153 return -1;
154 }
155
156 MEM(buff = talloc_array(ctx, char, ++len)); /* +1 for \0, it'll get reset by pcre2_substring */
157 pcre2_substring_copy_bynumber(match_data, num, (PCRE2_UCHAR *)buff, &len); /* can't error */
158
159 fr_value_box_init(out, FR_TYPE_STRING, NULL, false);
161 fr_value_box_safety_set(out, &rc->safety);
162
163 RDEBUG4("%i/%zu Found: %pV (%zu)", num + 1, rc->regmatch->used, out, out->vb_length);
164 break;
165 }
166
167 return 0;
168}
169
170/** Extract a named subcapture value from the request
171 *
172 * @note This is the PCRE variant of the function.
173 *
174 * @param[in] ctx To allocate subcapture buffer in.
175 * @param[out] out Where to write the subcapture string.
176 * @param[in] request to extract.
177 * @param[in] name of subcapture.
178 * @return
179 * - 0 on success.
180 * - -1 on notfound.
181 */
182int regex_request_to_sub_named(TALLOC_CTX *ctx, fr_value_box_t *out, request_t *request, char const *name)
183{
184 fr_regcapture_t *rc;
185 char *buff;
186 int ret;
187 size_t len;
188 pcre2_match_data *match_data;
189
190 rc = request_data_reference(request, request, REQUEST_DATA_REGEX);
191 if (!rc) {
192 RDEBUG4("No subcapture data found");
193 return -1;
194 }
195 match_data = rc->regmatch->match_data;
196
197 ret = pcre2_substring_length_byname(match_data, (PCRE2_UCHAR const *)name, &len);
198 switch (ret) {
199 case PCRE2_ERROR_NOMEMORY:
200 MEM(NULL);
201 break;
202
203 /*
204 * Not finding a substring is fine
205 */
206 case PCRE2_ERROR_NOSUBSTRING:
207 RDEBUG4("No named capture group \"%s\"", name);
208 return -1;
209
210 default:
211 if (ret < 0) return -1;
212
213 MEM(buff = talloc_array(ctx, char, ++len)); /* +1 for \0, it'll get reset by pcre2_substring */
214 pcre2_substring_copy_byname(match_data, (PCRE2_UCHAR const *)name, (PCRE2_UCHAR *)buff, &len); /* can't error */
215
216 fr_value_box_init(out, FR_TYPE_STRING, NULL, false);
218 fr_value_box_safety_set(out, &rc->safety);
219
220 RDEBUG4("Found \"%s\": %pV (%zu)", name, out, out->vb_length);
221 break;
222 }
223
224 return 0;
225}
226# else
227/** Extract a subcapture value from the request
228 *
229 * @note This is the POSIX variant of the function.
230 *
231 * @param[in] ctx To allocate subcapture buffer in.
232 * @param[out] out Where to write the subcapture string.
233 * @param[in] request to extract.
234 * @param[in] num Subcapture index (0 for entire match).
235 * @return
236 * - 0 on success.
237 * - -1 on notfound.
238 */
239int regex_request_to_sub(TALLOC_CTX *ctx, fr_value_box_t *out, request_t *request, uint32_t num)
240{
241 fr_regcapture_t *rc;
242 char *buff;
243 char const *start;
244 size_t len;
245 regmatch_t *match_data;
246
247 rc = request_data_reference(request, request, REQUEST_DATA_REGEX);
248 if (!rc) {
249 RDEBUG4("No subcapture data found");
250 return -1;
251 }
252 match_data = rc->regmatch->match_data;
253
254 /*
255 * Greater than our capture array
256 *
257 * -1 means no value in this capture group.
258 */
259 if ((num >= rc->regmatch->used) || (match_data[num].rm_eo == -1) || (match_data[num].rm_so == -1)) {
260 RDEBUG4("%i/%zu Not found", num + 1, rc->regmatch->used);
261 return -1;
262 }
263
264 /*
265 * Sanity checks on the offsets
266 */
267 fr_assert(match_data[num].rm_eo <= (regoff_t)talloc_array_length(rc->regmatch->subject));
268 fr_assert(match_data[num].rm_so <= (regoff_t)talloc_array_length(rc->regmatch->subject));
269
270 start = rc->regmatch->subject + match_data[num].rm_so;
271 len = match_data[num].rm_eo - match_data[num].rm_so;
272
273 MEM(buff = talloc_bstrndup(ctx, start, len));
274
275 fr_value_box_init(out, FR_TYPE_STRING, NULL, false);
277 fr_value_box_safety_set(out, &rc->safety);
278
279 RDEBUG4("%i/%zu Found: %pV (%zu)", num + 1, rc->regmatch->used, out, out->vb_length);
280
281 return 0;
282}
283# endif
284#endif
#define RCSID(id)
Definition build.h:560
#define MEM(x)
Definition debug.h:38
talloc_free(hp)
#define DEBUG4(_fmt,...)
Definition log.h:272
#define RDEBUG4(fmt,...)
Definition log.h:361
@ FR_TYPE_STRING
String of printable characters.
unsigned int uint32_t
#define fr_assert(_expr)
Definition rad_assert.h:37
void * request_data_reference(request_t *request, void const *unique_ptr, int unique_int)
Get opaque data from a request without removing it.
void * request_data_get(request_t *request, void const *unique_ptr, int unique_int)
Get opaque data from a request.
#define request_data_talloc_add(_request, _unique_ptr, _unique_int, _type, _opaque, _free_on_replace, _free_on_parent, _persist)
Add opaque data to a request_t.
static char const * name
static char buff[sizeof("18446744073709551615")+3]
Definition size_tests.c:37
char * talloc_bstrndup(TALLOC_CTX *ctx, char const *in, size_t inlen)
Binary safe strndup function.
Definition talloc.c:618
void fr_value_box_safety_set(fr_value_box_t *box, fr_value_box_safety_t const *safety)
Replace the safety of a box.
Definition value.c:7508
void fr_value_box_bstrndup_shallow(fr_value_box_t *dst, fr_dict_attr_t const *enumv, char const *src, size_t len, bool tainted)
Assign a string to to a fr_value_box_t.
Definition value.c:4986
static fr_sbuff_err_t char ** out
Definition value.h:1062
static fr_sbuff_err_t char size_t * len
Definition value.h:1062
#define fr_value_box_init(_vb, _type, _enumv, _tainted)
Initialise a fr_value_box_t.
Definition value.h:635
The safety of a value.
Definition value.h:181