The FreeRADIUS server $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
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: 47ee33a0c4131f3e3589d4b70c4dfa93874b8444 $
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: 47ee33a0c4131f3e3589d4b70c4dfa93874b8444 $")
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
43 bool secret;
44} fr_regcapture_t;
45
46/** Adds subcapture values to request data
47 *
48 * Allows use of %{n} expansions.
49 *
50 * @note If preg was runtime-compiled, it will be consumed and *preg will be set to NULL.
51 * @note regmatch will be consumed and *regmatch will be set to NULL.
52 * @note Their lifetimes will be bound to the match request data.
53 *
54 * @param[in] request Current request.
55 * @param[in,out] preg Compiled pattern. May be set to NULL if
56 * reparented to the regcapture struct.
57 * @param[in,out] regmatch Pointers into value. May be set to NULL if
58 * reparented to the regcapture struct.
59 * @param[in] in value-box which we matched against
60 */
61void regex_sub_to_request(request_t *request, regex_t **preg, fr_regmatch_t **regmatch, fr_value_box_t const *in)
62{
63 fr_regcapture_t *old_rc, *new_rc; /* lldb doesn't like bare new *sigh* */
64
65 /*
66 * Clear out old_rc matches
67 */
68 old_rc = request_data_get(request, request, REQUEST_DATA_REGEX);
69 if (old_rc) {
70 DEBUG4("Clearing %zu matches", old_rc->regmatch->used);
71 talloc_free(old_rc);
72 } else {
73 DEBUG4("No matches");
74 }
75
76 if (!regmatch || ((*regmatch)->used == 0)) return;
77
78 fr_assert(preg && *preg);
79 fr_assert(regmatch);
81
82 DEBUG4("Adding %zu matches", (*regmatch)->used);
83
84 /*
85 * Container struct for all the match data
86 */
87 MEM(new_rc = talloc(request, fr_regcapture_t));
88
89 /*
90 * Steal runtime pregs, leave precompiled ones
91 */
92#if defined(HAVE_REGEX_PCRE2)
93 if (!(*preg)->precompiled) {
94 new_rc->preg = talloc_steal(new_rc, *preg);
95 *preg = NULL;
96 } else {
97 new_rc->preg = *preg; /* Compiled on startup, will hopefully stick around */
98 }
99#endif
100
101 /*
102 * Steal match data
103 */
104 new_rc->regmatch = talloc_steal(new_rc, *regmatch);
105 new_rc->safe_for = in->safe_for;
106 new_rc->secret = in->secret;
107 *regmatch = NULL;
108
109 request_data_talloc_add(request, request, REQUEST_DATA_REGEX, fr_regcapture_t, new_rc, true, false, false);
110}
111
112# if defined(HAVE_REGEX_PCRE2)
113/** Extract a subcapture value from the request
114 *
115 * @note This is the PCRE variant of the function.
116 *
117 * @param[in] ctx To allocate subcapture buffer in.
118 * @param[out] out Where to write the subcapture string.
119 * @param[in] request to extract.
120 * @param[in] num Subcapture index (0 for entire match).
121 * @return
122 * - 0 on success.
123 * - -1 on notfound.
124 */
125int regex_request_to_sub(TALLOC_CTX *ctx, fr_value_box_t *out, request_t *request, uint32_t num)
126{
127 fr_regcapture_t *rc;
128 char *buff;
129 size_t len;
130 int ret;
131 pcre2_match_data *match_data;
132
133 rc = request_data_reference(request, request, REQUEST_DATA_REGEX);
134 if (!rc) {
135 RDEBUG4("No subcapture data found");
136 return -1;
137 }
138 match_data = talloc_get_type_abort(rc->regmatch->match_data, pcre2_match_data);
139
140 ret = pcre2_substring_length_bynumber(match_data, num, &len);
141 switch (ret) {
142 case PCRE2_ERROR_NOMEMORY:
143 MEM(NULL);
144 break;
145
146 /*
147 * Not finding a substring is fine
148 */
149 case PCRE2_ERROR_NOSUBSTRING:
150 RDEBUG4("%i/%zu Not found", num + 1, rc->regmatch->used);
151 return -1;
152
153 default:
154 if (ret < 0) {
155 return -1;
156 }
157
158 MEM(buff = talloc_array(ctx, char, ++len)); /* +1 for \0, it'll get reset by pcre2_substring */
159 pcre2_substring_copy_bynumber(match_data, num, (PCRE2_UCHAR *)buff, &len); /* can't error */
160
161 fr_value_box_init(out, FR_TYPE_STRING, NULL, false);
162 fr_value_box_bstrndup_shallow(out, NULL, buff, len, false);
163 fr_value_box_mark_safe_for(out, rc->safe_for);
164 fr_value_box_set_secret(out, rc->secret);
165
166 RDEBUG4("%i/%zu Found: %pV (%zu)", num + 1, rc->regmatch->used, out, out->vb_length);
167 break;
168 }
169
170 return 0;
171}
172
173/** Extract a named subcapture value from the request
174 *
175 * @note This is the PCRE variant of the function.
176 *
177 * @param[in] ctx To allocate subcapture buffer in.
178 * @param[out] out Where to write the subcapture string.
179 * @param[in] request to extract.
180 * @param[in] name of subcapture.
181 * @return
182 * - 0 on success.
183 * - -1 on notfound.
184 */
185int regex_request_to_sub_named(TALLOC_CTX *ctx, fr_value_box_t *out, request_t *request, char const *name)
186{
187 fr_regcapture_t *rc;
188 char *buff;
189 int ret;
190 size_t len;
191 pcre2_match_data *match_data;
192
193 rc = request_data_reference(request, request, REQUEST_DATA_REGEX);
194 if (!rc) {
195 RDEBUG4("No subcapture data found");
196 return -1;
197 }
198 match_data = rc->regmatch->match_data;
199
200 ret = pcre2_substring_length_byname(match_data, (PCRE2_UCHAR const *)name, &len);
201 switch (ret) {
202 case PCRE2_ERROR_NOMEMORY:
203 MEM(NULL);
204 break;
205
206 /*
207 * Not finding a substring is fine
208 */
209 case PCRE2_ERROR_NOSUBSTRING:
210 RDEBUG4("No named capture group \"%s\"", name);
211 return -1;
212
213 default:
214 if (ret < 0) return -1;
215
216 MEM(buff = talloc_array(ctx, char, ++len)); /* +1 for \0, it'll get reset by pcre2_substring */
217 pcre2_substring_copy_byname(match_data, (PCRE2_UCHAR const *)name, (PCRE2_UCHAR *)buff, &len); /* can't error */
218
219 fr_value_box_init(out, FR_TYPE_STRING, NULL, false);
220 fr_value_box_bstrndup_shallow(out, NULL, buff, len, false);
221 fr_value_box_mark_safe_for(out, rc->safe_for);
222 fr_value_box_set_secret(out, rc->secret);
223
224 RDEBUG4("Found \"%s\": %pV (%zu)", name, out, out->vb_length);
225 break;
226 }
227
228 return 0;
229}
230# else
231/** Extract a subcapture value from the request
232 *
233 * @note This is the POSIX variant of the function.
234 *
235 * @param[in] ctx To allocate subcapture buffer in.
236 * @param[out] out Where to write the subcapture string.
237 * @param[in] request to extract.
238 * @param[in] num Subcapture index (0 for entire match).
239 * @return
240 * - 0 on success.
241 * - -1 on notfound.
242 */
243int regex_request_to_sub(TALLOC_CTX *ctx, fr_value_box_t *out, request_t *request, uint32_t num)
244{
245 fr_regcapture_t *rc;
246 char *buff;
247 char const *start;
248 size_t len;
249 regmatch_t *match_data;
250
251 rc = request_data_reference(request, request, REQUEST_DATA_REGEX);
252 if (!rc) {
253 RDEBUG4("No subcapture data found");
254 return -1;
255 }
256 match_data = rc->regmatch->match_data;
257
258 /*
259 * Greater than our capture array
260 *
261 * -1 means no value in this capture group.
262 */
263 if ((num >= rc->regmatch->used) || (match_data[num].rm_eo == -1) || (match_data[num].rm_so == -1)) {
264 RDEBUG4("%i/%zu Not found", num + 1, rc->regmatch->used);
265 return -1;
266 }
267
268 /*
269 * Sanity checks on the offsets
270 */
271 fr_assert(match_data[num].rm_eo <= (regoff_t)talloc_array_length(rc->regmatch->subject));
272 fr_assert(match_data[num].rm_so <= (regoff_t)talloc_array_length(rc->regmatch->subject));
273
274 start = rc->regmatch->subject + match_data[num].rm_so;
275 len = match_data[num].rm_eo - match_data[num].rm_so;
276
277 MEM(buff = talloc_bstrndup(ctx, start, len));
278
279 fr_value_box_init(out, FR_TYPE_STRING, NULL, false);
280 fr_value_box_bstrndup_shallow(out, NULL, buff, len, false);
281 fr_value_box_mark_safe_for(out, rc->safe_for);
282 fr_value_box_set_secret(out, rc->secret);
283
284 RDEBUG4("%i/%zu Found: %pV (%zu)", num + 1, rc->regmatch->used, out, out->vb_length);
285
286 return 0;
287}
288# endif
289#endif
#define RCSID(id)
Definition build.h:485
#define MEM(x)
Definition debug.h:36
static fr_slen_t in
Definition dict.h:849
#define DEBUG4(_fmt,...)
Definition log.h:267
#define RDEBUG4(fmt,...)
Definition log.h:344
talloc_free(reap)
@ FR_TYPE_STRING
String of printable characters.
unsigned int uint32_t
#define fr_assert(_expr)
Definition rad_assert.h:38
static char * secret
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:41
char * talloc_bstrndup(TALLOC_CTX *ctx, char const *in, size_t inlen)
Binary safe strndup function.
Definition talloc.c:586
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:4687
#define fr_value_box_mark_safe_for(_box, _safe_for)
Definition value.h:1074
static void fr_value_box_set_secret(fr_value_box_t *box, bool secret)
Definition value.h:1111
uintptr_t fr_value_box_safe_for_t
Escaping that's been applied to a value box.
Definition value.h:162
#define fr_value_box_init(_vb, _type, _enumv, _tainted)
Initialise a fr_value_box_t.
Definition value.h:609
static size_t char ** out
Definition value.h:1023