The FreeRADIUS server $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
Loading...
Searching...
No Matches
token.c
Go to the documentation of this file.
1/*
2 * This library is free software; you can redistribute it and/or
3 * modify it under the terms of the GNU Lesser General Public
4 * License as published by the Free Software Foundation; either
5 * version 2.1 of the License, or (at your option) any later version.
6 *
7 * This library 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 GNU
10 * Lesser General Public License for more details.
11 *
12 * You should have received a copy of the GNU Lesser General Public
13 * License along with this library; if not, write to the Free Software
14 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
15 */
16
17/** Tokenisation code and constants
18 *
19 * This is mostly for the attribute filter and user files.
20 *
21 * @file src/lib/util/token.c
22 *
23 * @copyright 2001,2006 The FreeRADIUS server project
24 */
25RCSID("$Id: 2e43ed544f6f7d7715b2a61f16bc2ffd2e7c5ff8 $")
26
27#include <stdio.h>
28
29#include <freeradius-devel/util/skip.h>
30#include <freeradius-devel/util/strerror.h>
31#include <freeradius-devel/util/token.h>
32
33
35 { L("=~"), T_OP_REG_EQ }, /* order is important! */
36 { L("!~"), T_OP_REG_NE },
37 { L("{"), T_LCBRACE },
38 { L("}"), T_RCBRACE },
39 { L("("), T_LBRACE },
40 { L(")"), T_RBRACE },
41 { L(","), T_COMMA },
42 { L("++"), T_OP_INCRM },
43 { L("+="), T_OP_ADD_EQ },
44 { L("-="), T_OP_SUB_EQ },
45 { L("*="), T_OP_MUL_EQ },
46 { L("/="), T_OP_DIV_EQ },
47 { L(":="), T_OP_SET },
48 { L("=*"), T_OP_CMP_TRUE },
49 { L("!*"), T_OP_CMP_FALSE },
50 { L("=="), T_OP_CMP_EQ },
51 { L("==="), T_OP_CMP_EQ_TYPE },
52 { L("^="), T_OP_PREPEND },
53 { L("|="), T_OP_OR_EQ },
54 { L("&="), T_OP_AND_EQ },
55 { L("="), T_OP_EQ },
56 { L("!="), T_OP_NE },
57 { L("!=="), T_OP_CMP_NE_TYPE },
58 { L(">>="), T_OP_RSHIFT_EQ },
59 { L(">="), T_OP_GE },
60 { L(">"), T_OP_GT },
61 { L("<<="), T_OP_LSHIFT_EQ },
62 { L("<="), T_OP_LE },
63 { L("<"), T_OP_LT },
64 { L("#"), T_HASH },
65 { L(";"), T_SEMICOLON }
66};
68
77
78/*
79 * String versions for all of the tokens.
80 */
81char const *fr_tokens[T_TOKEN_LAST] = {
82 [T_INVALID] = "?",
83 [T_EOL] = "EOL",
84
85 [T_LCBRACE] = "{",
86 [T_RCBRACE] = "}",
87 [T_LBRACE] = "(",
88 [T_RBRACE] = ")",
89 [T_COMMA] = ",",
90 [T_SEMICOLON] = ";",
91
92 [T_ADD] = "+",
93 [T_SUB] = "-",
94 [T_MUL] = "*",
95 [T_DIV] = "/",
96 [T_AND] = "&",
97 [T_OR] = "|",
98 [T_NOT] = "!",
99 [T_XOR] = "^",
100 [T_COMPLEMENT] = "~",
101 [T_MOD] = "%",
102
103 [T_RSHIFT] = ">>",
104 [T_LSHIFT] = "<<",
105
106 [T_LAND] = "&&",
107 [T_LOR] = "||",
108
109 [T_OP_INCRM] = "++",
110
111 [T_OP_ADD_EQ] = "+=",
112 [T_OP_SUB_EQ] = "-=",
113 [T_OP_SET] = ":=",
114 [T_OP_EQ] = "=",
115 [T_OP_OR_EQ] = "|=",
116 [T_OP_AND_EQ] = "&=",
117
118 [T_OP_RSHIFT_EQ] = ">>=",
119 [T_OP_LSHIFT_EQ] = "<<=",
120
121 [T_OP_NE] = "!=",
122 [T_OP_GE] = ">=",
123 [T_OP_GT] = ">",
124 [T_OP_LE] = "<=",
125 [T_OP_LT] = "<",
126 [T_OP_REG_EQ] = "=~",
127 [T_OP_REG_NE] = "!~",
128
129 [T_OP_CMP_TRUE] = "=*",
130 [T_OP_CMP_FALSE] = "!*",
131
132 [T_OP_CMP_EQ] = "==",
133
134 [T_OP_CMP_EQ_TYPE] = "===",
135 [T_OP_CMP_NE_TYPE] = "!==",
136
137 [T_OP_PREPEND] = "^=",
138
139 [T_HASH] = "#",
140 [T_BARE_WORD] = "<BARE-WORD>",
141 [T_DOUBLE_QUOTED_STRING] = "<\"STRING\">",
142 [T_SINGLE_QUOTED_STRING] = "<'STRING'>",
143 [T_BACK_QUOTED_STRING] = "<`STRING`>",
144 [T_SOLIDUS_QUOTED_STRING] = "</STRING/>",
145};
146
147
148/*
149 * This is fine. Don't complain.
150 */
151#ifdef __clang__
152#pragma clang diagnostic ignored "-Wgnu-designator"
153#endif
154
155/** Convert tokens back to a quoting character
156 *
157 * Non-string types convert to '?' to screw ups can be identified easily
158 */
160 [ 0 ... T_HASH ] = '?', /* GCC extension for range initialization, also allowed by clang */
161
162 [T_BARE_WORD] = '\0',
164 [T_SINGLE_QUOTED_STRING] = '\'',
165 [T_BACK_QUOTED_STRING] = '`',
167};
168
169#define T(_x) [T_OP_ ## _x] = true
170
172 T(INCRM), /* only used by LDAP :( */
173
174 T(ADD_EQ),
175 T(SUB_EQ),
176 T(MUL_EQ),
177 T(DIV_EQ),
178 T(AND_EQ),
179 T(OR_EQ),
180 T(RSHIFT_EQ),
181 T(LSHIFT_EQ),
182
183 T(SET),
184 T(EQ),
185 T(PREPEND),
186};
187
189 T(ADD_EQ), /* append */
190 T(SUB_EQ), /* remove */
191 T(AND_EQ), /* intersection */
192 T(OR_EQ), /* union */
193 T(LE), /* merge RHS */
194 T(GE), /* merge LHS */
195
196 T(SET),
197 T(EQ),
198 T(PREPEND), /* prepend */
199};
200
202 T(NE),
203 T(GE),
204 T(GT),
205 T(LE),
206 T(LT),
207 T(REG_EQ),
208 T(REG_NE),
209 T(CMP_TRUE),
210 T(CMP_FALSE),
211 T(CMP_EQ),
212 T(CMP_EQ_TYPE),
213 T(CMP_NE_TYPE),
214};
215
216#undef T
217#define T(_x) [T_ ## _x] = true
218
220 T(ADD),
221 T(SUB),
222 T(MUL),
223 T(DIV),
224 T(AND),
225 T(OR),
226 T(MOD),
227 T(RSHIFT),
228 T(LSHIFT),
229};
230
231
232#undef T
233#define T(_x) [T_## _x] = true
235 T(BARE_WORD),
236 T(DOUBLE_QUOTED_STRING),
237 T(SINGLE_QUOTED_STRING),
238 T(BACK_QUOTED_STRING),
239};
240
241/*
242 * This works only as long as special tokens
243 * are max. 2 characters, but it's fast.
244 */
245#define TOKEN_MATCH(bptr, tptr) \
246 ( (tptr)[0] == (bptr)[0] && \
247 ((tptr)[1] == (bptr)[1] || (tptr)[1] == 0))
248
249/*
250 * Read a word from a buffer and advance pointer.
251 * This function knows about escapes and quotes.
252 *
253 * At end-of-line, buf[0] is set to '\0'.
254 * Returns 0 or special token value.
255 */
256static fr_token_t getthing(char const **ptr, char *buf, int buflen, bool tok,
257 fr_table_num_ordered_t const *tokenlist, size_t tokenlist_len, bool unescape)
258{
259 char *s;
260 char const *p;
261 char quote;
262 bool triple = false;
263 unsigned int x;
264 size_t i;
265 fr_token_t token;
266
267 buf[0] = '\0';
268
269 /* Skip whitespace */
270 p = *ptr;
271
273
274 if (!*p) {
275 *ptr = p;
276 return T_EOL;
277 }
278
279 /*
280 * Might be a 1 or 2 character token.
281 */
282 if (tok) {
283 for (i = 0; i < tokenlist_len; i++) {
284 if (TOKEN_MATCH(p, tokenlist[i].name.str)) {
285 strcpy(buf, tokenlist[i].name.str);
286 p += tokenlist[i].name.len;
287
288 /*
289 * Try to shut up Coverity, which claims fr_token_t can be between 0..63, not
290 * 0..48???
291 */
292 if ((tokenlist[i].value < 0) || (tokenlist[i].value >= T_TOKEN_LAST)) return T_INVALID;
293
294 token = tokenlist[i].value;
295 goto done;
296 }
297 }
298 }
299
300 /* Read word. */
301 quote = '\0';
302 switch (*p) {
303 default:
304 token = T_BARE_WORD;
305 break;
306
307 case '\'':
309 break;
310
311 case '"':
313 break;
314
315 case '`':
316 token = T_BACK_QUOTED_STRING;
317 break;
318 }
319
320 if (token != T_BARE_WORD) {
321 quote = *p;
322
323 /*
324 * Triple-quoted strings are copied over verbatim, without escapes.
325 */
326 if ((buflen >= 3) && (p[1] == quote) && (p[2] == quote)) {
327 p += 3;
328 triple = true;
329 }
330
331 p++;
332 }
333 s = buf;
334
335 while (*p && buflen-- > 1) {
336 /*
337 * We're looking for strings. Stop on spaces, or
338 * (if given a token list), on a token, or on a
339 * comma.
340 */
341 if (!quote) {
342 if (isspace((uint8_t) *p)) break;
343
344
345 if (tok) {
346 for (i = 0; i < tokenlist_len; i++) {
347 if (TOKEN_MATCH(p, tokenlist[i].name.str)) {
348 *s++ = 0;
349 goto done;
350 }
351 }
352 }
353 if (*p == ',') break;
354
355 /*
356 * Copy the character over.
357 */
358 *s++ = *p++;
359 continue;
360 } /* else there was a quotation character */
361
362 /*
363 * Un-escaped quote character. We're done.
364 */
365 if (*p == quote) {
366 if (!triple) {
367 p++;
368 *s++ = 0;
369 goto done;
370 }
371
372 if ((buflen >= 3) && (p[1] == quote) && (p[2] == quote)) {
373 p += 3;
374 *s++ = 0;
375 goto done;
376 }
377
378 *s++ = *p++;
379 continue;
380 }
381
382 /*
383 * Everything but backslash gets copied over.
384 */
385 if (*p != '\\') {
386 *s++ = *p++;
387 continue;
388 }
389
390 /*
391 * There's nothing after the backslash, it's an error.
392 */
393 if (!p[1]) {
394 fr_strerror_const("Unterminated string");
395 return T_INVALID;
396 }
397
398 if (unescape) {
399 p++;
400
401 switch (*p) {
402 case 'r':
403 *s++ = '\r';
404 break;
405 case 'n':
406 *s++ = '\n';
407 break;
408 case 't':
409 *s++ = '\t';
410 break;
411
412 default:
413 if (*p >= '0' && *p <= '9' &&
414 sscanf(p, "%3o", &x) == 1) {
415 *s++ = x;
416 p += 2;
417 } else
418 *s++ = *p;
419 break;
420 }
421 p++;
422
423 } else {
424 /*
425 * Convert backslash-quote to quote, but
426 * leave everything else alone.
427 */
428 if (p[1] == quote) { /* convert '\'' --> ' */
429 p++;
430 } else {
431 if (buflen < 2) {
432 fr_strerror_const("Truncated input");
433 return T_INVALID;
434 }
435
436 *(s++) = *(p++);
437 }
438 *(s++) = *(p++);
439 }
440 }
441
442 *s++ = 0;
443
444 if (quote) {
445 fr_strerror_const("Unterminated string");
446 return T_INVALID;
447 }
448
449done:
450 /* Skip whitespace again. */
452
453 *ptr = p;
454
455 return token;
456}
457
458/*
459 * Read a "word" - this means we don't honor
460 * tokens as delimiters.
461 */
462int getword(char const **ptr, char *buf, int buflen, bool unescape)
463{
464 return getthing(ptr, buf, buflen, false, fr_tokens_table, fr_tokens_table_len, unescape) == T_EOL ? 0 : 1;
465}
466
467
468/*
469 * Read the next word, use tokens as delimiters.
470 */
471fr_token_t gettoken(char const **ptr, char *buf, int buflen, bool unescape)
472{
473 return getthing(ptr, buf, buflen, true, fr_tokens_table, fr_tokens_table_len, unescape);
474}
475
476/*
477 * Expect an operator.
478 */
479fr_token_t getop(char const **ptr)
480{
481 char op[3];
482 fr_token_t token;
483
484 token = getthing(ptr, op, sizeof(op), true, fr_tokens_table, fr_tokens_table_len, false);
485 if (!fr_assignment_op[token] && !fr_comparison_op[token]) {
486 fr_strerror_const("Expected operator");
487 return T_INVALID;
488 }
489 return token;
490}
491
492/*
493 * Expect a string.
494 */
495fr_token_t getstring(char const **ptr, char *buf, int buflen, bool unescape)
496{
497 char const *p;
498
499 if (!ptr || !*ptr || !buf) return T_INVALID;
500
501 p = *ptr;
502
504
505 *ptr = p;
506
507 if ((*p == '"') || (*p == '\'') || (*p == '`')) {
508 return gettoken(ptr, buf, buflen, unescape);
509 }
510
511 return getthing(ptr, buf, buflen, false, fr_tokens_table, fr_tokens_table_len, unescape);
512}
513
514char const *fr_token_name(int token)
515{
516 return fr_table_str_by_value(fr_tokens_table, token, "<INVALID>");
517}
strcpy(log_entry->msg, buffer)
#define RCSID(id)
Definition build.h:487
#define L(_str)
Helper for initialising arrays of string literals.
Definition build.h:209
#define NUM_ELEMENTS(_t)
Definition build.h:339
Test enumeration values.
Definition dict_test.h:92
unsigned char uint8_t
static bool done
Definition radclient.c:83
static char const * name
#define fr_skip_whitespace(_p)
Skip whitespace ('\t', '\n', '\v', '\f', '\r', ' ')
Definition skip.h:36
#define fr_table_str_by_value(_table, _number, _def)
Convert an integer to a string.
Definition table.h:772
fr_table_elem_name_t name
Definition table.h:58
size_t len
Literal string length.
Definition table.h:43
An element in an arbitrarily ordered array of name to num mappings.
Definition table.h:57
An element in a lexicographically sorted array of name to num mappings.
Definition table.h:49
#define MOD(a, b)
const bool fr_assignment_op[T_TOKEN_LAST]
Definition token.c:171
const bool fr_list_assignment_op[T_TOKEN_LAST]
Definition token.c:188
#define TOKEN_MATCH(bptr, tptr)
Definition token.c:245
char const * fr_token_name(int token)
Definition token.c:514
fr_token_t gettoken(char const **ptr, char *buf, int buflen, bool unescape)
Definition token.c:471
fr_table_num_ordered_t const fr_tokens_table[]
Definition token.c:34
static fr_token_t getthing(char const **ptr, char *buf, int buflen, bool tok, fr_table_num_ordered_t const *tokenlist, size_t tokenlist_len, bool unescape)
Definition token.c:256
const bool fr_str_tok[T_TOKEN_LAST]
Definition token.c:234
fr_table_num_sorted_t const fr_token_quotes_table[]
Definition token.c:69
size_t fr_token_quotes_table_len
Definition token.c:76
size_t fr_tokens_table_len
Definition token.c:67
fr_token_t getop(char const **ptr)
Definition token.c:479
const char fr_token_quote[T_TOKEN_LAST]
Convert tokens back to a quoting character.
Definition token.c:159
char const * fr_tokens[T_TOKEN_LAST]
Definition token.c:81
fr_token_t getstring(char const **ptr, char *buf, int buflen, bool unescape)
Definition token.c:495
int getword(char const **ptr, char *buf, int buflen, bool unescape)
Definition token.c:462
const bool fr_comparison_op[T_TOKEN_LAST]
Definition token.c:201
const bool fr_binary_op[T_TOKEN_LAST]
Definition token.c:219
#define T(_x)
Definition token.c:169
enum fr_token fr_token_t
@ T_AND
Definition token.h:55
@ T_OP_SUB_EQ
Definition token.h:70
@ T_INVALID
Definition token.h:39
@ T_SUB
Definition token.h:52
@ T_RSHIFT
Definition token.h:62
@ T_RCBRACE
Definition token.h:42
@ T_NOT
Definition token.h:57
@ T_OP_DIV_EQ
Definition token.h:72
@ T_XOR
Definition token.h:58
@ T_RBRACE
Definition token.h:44
@ T_EOL
Definition token.h:40
@ T_SEMICOLON
Definition token.h:46
@ T_DIV
Definition token.h:54
@ T_SINGLE_QUOTED_STRING
Definition token.h:122
@ T_MOD
Definition token.h:60
@ T_OP_AND_EQ
Definition token.h:74
@ T_OP_CMP_TRUE
Definition token.h:104
@ T_BARE_WORD
Definition token.h:120
@ T_OP_EQ
Definition token.h:83
@ T_OP_MUL_EQ
Definition token.h:71
@ T_LAND
Definition token.h:91
@ T_COMPLEMENT
Definition token.h:59
@ T_ADD
Definition token.h:51
@ T_BACK_QUOTED_STRING
Definition token.h:123
@ T_HASH
Definition token.h:119
@ T_OP_SET
Definition token.h:84
@ T_OP_NE
Definition token.h:97
@ T_OP_ADD_EQ
Definition token.h:69
@ T_OP_CMP_FALSE
Definition token.h:105
@ T_OP_LSHIFT_EQ
Definition token.h:77
@ T_LOR
Definition token.h:92
@ T_LCBRACE
Definition token.h:41
@ T_LSHIFT
Definition token.h:63
@ T_OP_RSHIFT_EQ
Definition token.h:76
@ T_OP_REG_EQ
Definition token.h:102
@ T_OP_CMP_EQ_TYPE
Definition token.h:107
@ T_DOUBLE_QUOTED_STRING
Definition token.h:121
@ T_OP_CMP_EQ
Definition token.h:106
@ T_OP_INCRM
Definition token.h:113
@ T_LBRACE
Definition token.h:43
@ T_MUL
Definition token.h:53
@ T_OP_LE
Definition token.h:100
@ T_OP_CMP_NE_TYPE
Definition token.h:108
@ T_OP_GE
Definition token.h:98
@ T_OP_GT
Definition token.h:99
@ T_OP_OR_EQ
Definition token.h:73
@ T_SOLIDUS_QUOTED_STRING
Definition token.h:124
@ T_OP_LT
Definition token.h:101
@ T_OP_REG_NE
Definition token.h:103
@ T_COMMA
Definition token.h:45
@ T_OR
Definition token.h:56
@ T_OP_PREPEND
Definition token.h:85
#define T_TOKEN_LAST
Definition token.h:129
#define fr_strerror_const(_msg)
Definition strerror.h:223