50 #ifdef STRCASECMP_IN_STRINGS_H
73 #ifdef PCRE_STUDY_JIT_COMPILE
74 #define DICT_PCRE_FREE_STUDY(x) pcre_free_study(x)
76 #define DICT_PCRE_FREE_STUDY(x) pcre_free((char *) (x))
82 #define DICT_PCRE_OP_MATCH 1
83 #define DICT_PCRE_OP_IF 2
84 #define DICT_PCRE_OP_ENDIF 3
89 #define PCRE_MAX_CAPTURE 99
108 typedef struct DICT_PCRE_RULE {
111 struct DICT_PCRE_RULE *next;
121 } DICT_PCRE_MATCH_RULE;
128 struct DICT_PCRE_RULE *endif_rule;
136 DICT_PCRE_RULE *head;
140 static int dict_pcre_init = 0;
146 DICT_PCRE *dict_pcre;
147 DICT_PCRE_MATCH_RULE *match_rule;
148 const char *lookup_string;
149 int offsets[PCRE_MAX_CAPTURE * 3];
151 } DICT_PCRE_EXPAND_CONTEXT;
161 } DICT_PCRE_PRESCAN_CONTEXT;
167 #define MAC_PARSE_OK 0
173 #define NULL_STARTOFFSET (0)
174 #define NULL_EXEC_OPTIONS (0)
175 #define NULL_OVECTOR ((int *) 0)
176 #define NULL_OVECTOR_LENGTH (0)
180 static int dict_pcre_expand(
int type,
VSTRING *buf,
void *ptr)
182 DICT_PCRE_EXPAND_CONTEXT *ctxt = (DICT_PCRE_EXPAND_CONTEXT *) ptr;
183 DICT_PCRE_MATCH_RULE *match_rule = ctxt->match_rule;
184 DICT_PCRE *dict_pcre = ctxt->dict_pcre;
194 ret = pcre_get_substring(ctxt->lookup_string, ctxt->offsets,
195 ctxt->matches, n, &pp);
197 if (ret == PCRE_ERROR_NOSUBSTRING)
200 msg_fatal(
"pcre map %s, line %d: pcre_get_substring error: %d",
201 dict_pcre->dict.name, match_rule->rule.lineno, ret);
223 static void dict_pcre_exec_error(
const char *mapname,
int lineno,
int errval)
227 msg_warn(
"pcre map %s, line %d: too many (...)",
230 case PCRE_ERROR_NULL:
231 case PCRE_ERROR_BADOPTION:
232 msg_warn(
"pcre map %s, line %d: bad args to re_exec",
235 case PCRE_ERROR_BADMAGIC:
236 case PCRE_ERROR_UNKNOWN_NODE:
237 msg_warn(
"pcre map %s, line %d: corrupt compiled regexp",
240 #ifdef PCRE_ERROR_NOMEMORY
241 case PCRE_ERROR_NOMEMORY:
242 msg_warn(
"pcre map %s, line %d: out of memory",
246 #ifdef PCRE_ERROR_MATCHLIMIT
247 case PCRE_ERROR_MATCHLIMIT:
248 msg_warn(
"pcre map %s, line %d: backtracking limit exceeded",
252 #ifdef PCRE_ERROR_BADUTF8
253 case PCRE_ERROR_BADUTF8:
254 msg_warn(
"pcre map %s, line %d: bad UTF-8 sequence in search string",
258 #ifdef PCRE_ERROR_BADUTF8_OFFSET
259 case PCRE_ERROR_BADUTF8_OFFSET:
260 msg_warn(
"pcre map %s, line %d: bad UTF-8 start offset in search string",
265 msg_warn(
"pcre map %s, line %d: unknown pcre_exec error: %d",
266 mapname, lineno, errval);
274 #define DICT_PCRE_EXEC(ctxt, map, line, pattern, hints, match, str, len) \
275 ((ctxt).matches = pcre_exec((pattern), (hints), (str), (len), \
276 NULL_STARTOFFSET, NULL_EXEC_OPTIONS, \
277 (ctxt).offsets, PCRE_MAX_CAPTURE * 3), \
278 (ctxt).matches > 0 ? (match) : \
279 (ctxt).matches == PCRE_ERROR_NOMATCH ? !(match) : \
280 (dict_pcre_exec_error((map), (line), (ctxt).matches), 0))
284 static const char *dict_pcre_lookup(
DICT *dict,
const char *lookup_string)
286 DICT_PCRE *dict_pcre = (DICT_PCRE *) dict;
287 DICT_PCRE_RULE *rule;
288 DICT_PCRE_IF_RULE *if_rule;
289 DICT_PCRE_MATCH_RULE *match_rule;
290 int lookup_len = strlen(lookup_string);
291 DICT_PCRE_EXPAND_CONTEXT ctxt;
296 msg_info(
"dict_pcre_lookup: %s: %s", dict->
name, lookup_string);
307 for (rule = dict_pcre->head; rule; rule = rule->next) {
314 case DICT_PCRE_OP_MATCH:
315 match_rule = (DICT_PCRE_MATCH_RULE *) rule;
316 if (!DICT_PCRE_EXEC(ctxt, dict->
name, rule->lineno,
317 match_rule->pattern, match_rule->hints,
318 match_rule->match, lookup_string, lookup_len))
326 if (match_rule->max_sub == 0)
327 return match_rule->replacement;
332 if (dict_pcre->expansion_buf == 0)
335 ctxt.dict_pcre = dict_pcre;
336 ctxt.match_rule = match_rule;
337 ctxt.lookup_string = lookup_string;
339 if (
mac_parse(match_rule->replacement, dict_pcre_expand,
341 msg_fatal(
"pcre map %s, line %d: bad replacement syntax",
342 dict->
name, rule->lineno);
353 case DICT_PCRE_OP_IF:
354 if_rule = (DICT_PCRE_IF_RULE *) rule;
355 if (DICT_PCRE_EXEC(ctxt, dict->
name, rule->lineno,
356 if_rule->pattern, if_rule->hints,
357 if_rule->match, lookup_string, lookup_len))
360 if ((rule = if_rule->endif_rule) == 0)
367 case DICT_PCRE_OP_ENDIF:
371 msg_panic(
"dict_pcre_lookup: impossible operation %d", rule->op);
379 static void dict_pcre_close(
DICT *dict)
381 DICT_PCRE *dict_pcre = (DICT_PCRE *) dict;
382 DICT_PCRE_RULE *rule;
383 DICT_PCRE_RULE *next;
384 DICT_PCRE_MATCH_RULE *match_rule;
385 DICT_PCRE_IF_RULE *if_rule;
387 for (rule = dict_pcre->head; rule; rule = next) {
390 case DICT_PCRE_OP_MATCH:
391 match_rule = (DICT_PCRE_MATCH_RULE *) rule;
392 if (match_rule->pattern)
393 myfree((
void *) match_rule->pattern);
394 if (match_rule->hints)
395 DICT_PCRE_FREE_STUDY(match_rule->hints);
396 if (match_rule->replacement)
397 myfree((
void *) match_rule->replacement);
399 case DICT_PCRE_OP_IF:
400 if_rule = (DICT_PCRE_IF_RULE *) rule;
401 if (if_rule->pattern)
402 myfree((
void *) if_rule->pattern);
404 DICT_PCRE_FREE_STUDY(if_rule->hints);
406 case DICT_PCRE_OP_ENDIF:
409 msg_panic(
"dict_pcre_close: unknown operation %d", rule->op);
413 if (dict_pcre->expansion_buf)
422 static int dict_pcre_get_pattern(
const char *mapname,
int lineno,
char **bufp,
423 DICT_PCRE_REGEXP *pattern)
434 pattern->match = !pattern->match;
440 msg_warn(
"pcre map %s, line %d: no regexp: skipping this rule",
455 }
else if (*p == re_delimiter)
461 msg_warn(
"pcre map %s, line %d: no closing regexp delimiter \"%c\": "
462 "ignoring this rule", mapname, lineno, re_delimiter);
470 pattern->options = PCRE_CASELESS | PCRE_DOTALL;
474 pattern->options ^= PCRE_CASELESS;
477 pattern->options ^= PCRE_MULTILINE;
480 pattern->options ^= PCRE_DOTALL;
483 pattern->options ^= PCRE_EXTENDED;
486 pattern->options ^= PCRE_ANCHORED;
489 pattern->options ^= PCRE_DOLLAR_ENDONLY;
492 pattern->options ^= PCRE_UNGREEDY;
495 pattern->options ^= PCRE_EXTRA;
498 msg_warn(
"pcre map %s, line %d: unknown regexp option \"%c\": "
499 "skipping this rule", mapname, lineno, *p);
510 static int dict_pcre_prescan(
int type,
VSTRING *buf,
void *context)
512 DICT_PCRE_PRESCAN_CONTEXT *ctxt = (DICT_PCRE_PRESCAN_CONTEXT *) context;
526 msg_warn(
"pcre map %s, line %d: non-numeric replacement index \"%s\"",
528 return (MAC_PARSE_ERROR);
532 msg_warn(
"pcre map %s, line %d: out of range replacement index \"%s\"",
534 return (MAC_PARSE_ERROR);
536 if (n > ctxt->max_sub)
540 msg_panic(
"pcre map %s, line %d: multiple literals but no $number",
541 ctxt->mapname, ctxt->lineno);
549 static int dict_pcre_compile(
const char *mapname,
int lineno,
550 DICT_PCRE_REGEXP *pattern,
551 DICT_PCRE_ENGINE *engine)
556 engine->pattern = pcre_compile(pattern->regexp, pattern->options,
557 &error, &errptr, NULL);
558 if (engine->pattern == 0) {
559 msg_warn(
"pcre map %s, line %d: error in regex at offset %d: %s",
560 mapname, lineno, errptr, error);
563 engine->hints = pcre_study(engine->pattern, 0, &error);
565 msg_warn(
"pcre map %s, line %d: error while studying regex: %s",
566 mapname, lineno, error);
567 myfree((
void *) engine->pattern);
575 static DICT_PCRE_RULE *dict_pcre_rule_alloc(
int op,
int lineno,
size_t size)
577 DICT_PCRE_RULE *rule;
579 rule = (DICT_PCRE_RULE *)
mymalloc(size);
581 rule->lineno = lineno;
589 static DICT_PCRE_RULE *dict_pcre_parse_rule(
const char *mapname,
int lineno,
590 char *line,
int nesting,
602 DICT_PCRE_REGEXP regexp;
603 DICT_PCRE_ENGINE engine;
604 DICT_PCRE_PRESCAN_CONTEXT prescan_context;
605 DICT_PCRE_MATCH_RULE *match_rule;
610 if (dict_pcre_get_pattern(mapname, lineno, &p, ®exp) == 0)
619 msg_warn(
"pcre map %s, line %d: no replacement text: "
620 "using empty string", mapname, lineno);
625 prescan_context.mapname = mapname;
626 prescan_context.lineno = lineno;
627 prescan_context.max_sub = 0;
628 prescan_context.literal = 0;
633 #define CREATE_MATCHOP_ERROR_RETURN(rval) do { \
634 if (prescan_context.literal) \
635 myfree(prescan_context.literal); \
639 if (
mac_parse(p, dict_pcre_prescan, (
void *) &prescan_context)
641 msg_warn(
"pcre map %s, line %d: bad replacement syntax: "
642 "skipping this rule", mapname, lineno);
643 CREATE_MATCHOP_ERROR_RETURN(0);
649 if (prescan_context.max_sub > 0 && regexp.match == 0) {
650 msg_warn(
"pcre map %s, line %d: $number found in negative match "
651 "replacement text: skipping this rule", mapname, lineno);
652 CREATE_MATCHOP_ERROR_RETURN(0);
656 "regular expression substitution is not allowed: "
657 "skipping this rule", mapname, lineno);
658 CREATE_MATCHOP_ERROR_RETURN(0);
664 if (dict_pcre_compile(mapname, lineno, ®exp, &engine) == 0)
665 CREATE_MATCHOP_ERROR_RETURN(0);
666 #ifdef PCRE_INFO_CAPTURECOUNT
667 if (pcre_fullinfo(engine.pattern, engine.hints,
668 PCRE_INFO_CAPTURECOUNT,
669 (
void *) &actual_sub) != 0)
670 msg_panic(
"pcre map %s, line %d: pcre_fullinfo failed",
672 if (prescan_context.max_sub > actual_sub) {
673 msg_warn(
"pcre map %s, line %d: out of range replacement index \"%d\": "
674 "skipping this rule", mapname, lineno,
675 (
int) prescan_context.max_sub);
677 myfree((
void *) engine.pattern);
679 DICT_PCRE_FREE_STUDY(engine.hints);
680 CREATE_MATCHOP_ERROR_RETURN(0);
687 match_rule = (DICT_PCRE_MATCH_RULE *)
688 dict_pcre_rule_alloc(DICT_PCRE_OP_MATCH, lineno,
689 sizeof(DICT_PCRE_MATCH_RULE));
690 match_rule->match = regexp.match;
691 match_rule->max_sub = prescan_context.max_sub;
692 if (prescan_context.literal)
693 match_rule->replacement = prescan_context.literal;
695 match_rule->replacement =
mystrdup(p);
696 match_rule->pattern = engine.pattern;
697 match_rule->hints = engine.hints;
698 return ((DICT_PCRE_RULE *) match_rule);
705 DICT_PCRE_REGEXP regexp;
706 DICT_PCRE_ENGINE engine;
707 DICT_PCRE_IF_RULE *if_rule;
716 if (!dict_pcre_get_pattern(mapname, lineno, &p, ®exp))
725 msg_warn(
"pcre map %s, line %d: ignoring extra text after "
726 "IF statement: \"%s\"", mapname, lineno, p);
727 msg_warn(
"pcre map %s, line %d: do not prepend whitespace"
728 " to statements between IF and ENDIF", mapname, lineno);
734 if (dict_pcre_compile(mapname, lineno, ®exp, &engine) == 0)
740 if_rule = (DICT_PCRE_IF_RULE *)
741 dict_pcre_rule_alloc(DICT_PCRE_OP_IF, lineno,
742 sizeof(DICT_PCRE_IF_RULE));
743 if_rule->match = regexp.match;
744 if_rule->pattern = engine.pattern;
745 if_rule->hints = engine.hints;
746 if_rule->endif_rule = 0;
747 return ((DICT_PCRE_RULE *) if_rule);
754 DICT_PCRE_RULE *rule;
762 msg_warn(
"pcre map %s, line %d: ignoring ENDIF without matching IF",
773 msg_warn(
"pcre map %s, line %d: ignoring extra text after ENDIF",
779 rule = dict_pcre_rule_alloc(DICT_PCRE_OP_ENDIF, lineno,
780 sizeof(DICT_PCRE_RULE));
788 msg_warn(
"pcre map %s, line %d: ignoring unrecognized request",
798 const char myname[] =
"dict_pcre_open";
799 DICT_PCRE *dict_pcre;
803 DICT_PCRE_RULE *last_rule = 0;
804 DICT_PCRE_RULE *rule;
809 DICT_PCRE_RULE **rule_stack = 0;
815 #define DICT_PCRE_OPEN_RETURN(d) do { \
818 vstream_fclose(map_fp); \
819 if (line_buffer != 0) \
820 vstring_free(line_buffer); \
827 if (open_flags != O_RDONLY)
829 open_flags, dict_flags,
830 "%s:%s map requires O_RDONLY access mode",
838 open_flags, dict_flags,
839 "open %s: %m", mapname));
847 dict_pcre->dict.
lookup = dict_pcre_lookup;
848 dict_pcre->dict.close = dict_pcre_close;
853 dict_pcre->expansion_buf = 0;
855 if (dict_pcre_init == 0) {
856 pcre_malloc = (
void *(*) (size_t))
mymalloc;
857 pcre_free = (void (*) (
void *))
myfree;
860 dict_pcre->dict.owner.uid = st.st_uid;
861 dict_pcre->dict.owner.status = (st.st_uid != 0);
866 while (
readllines(line_buffer, map_fp, &last_line, &lineno)) {
871 rule = dict_pcre_parse_rule(mapname, lineno, p, nesting, dict_flags);
874 if (rule->op == DICT_PCRE_OP_IF) {
876 rule_stack = (DICT_PCRE_RULE **)
mvect_alloc(&mvect,
877 sizeof(*rule_stack), nesting + 1,
882 rule_stack[nesting] = rule;
884 }
else if (rule->op == DICT_PCRE_OP_ENDIF) {
885 DICT_PCRE_IF_RULE *if_rule;
889 msg_panic(
"%s: ENDIF without IF", myname);
890 if (rule_stack[nesting]->op != DICT_PCRE_OP_IF)
891 msg_panic(
"%s: unexpected rule stack element type %d",
892 myname, rule_stack[nesting]->op);
893 if_rule = (DICT_PCRE_IF_RULE *) rule_stack[nesting];
894 if_rule->endif_rule = rule;
897 dict_pcre->head = rule;
899 last_rule->next = rule;
903 while (nesting-- > 0)
904 msg_warn(
"pcre map %s, line %d: IF has no matching ENDIF",
905 mapname, rule_stack[nesting]->lineno);
910 DICT_PCRE_OPEN_RETURN(
DICT_DEBUG (&dict_pcre->dict));
char * mystrdup(const char *str)
NORETURN msg_panic(const char *fmt,...)
int alldig(const char *string)
int strncasecmp(const char *s1, const char *s2, size_t n)
VSTRING * vstring_strcpy(VSTRING *vp, const char *src)
VSTREAM * vstream_fopen(const char *path, int flags, mode_t mode)
#define VSTRING_TERMINATE(vp)
#define VSTRING_RESET(vp)
void msg_warn(const char *fmt,...)
VSTRING * vstring_alloc(ssize_t len)
char * lowercase(char *string)
const char *(* lookup)(struct DICT *, const char *)
char * mvect_free(MVECT *vect)
char * trimblanks(char *, ssize_t)
NORETURN msg_fatal(const char *fmt,...)
char * mvect_alloc(MVECT *vect, ssize_t elsize, ssize_t nelm, void(*init_fn)(char *, ssize_t), void(*wipe_fn)(char *, ssize_t))
VSTRING * readllines(VSTRING *buf, VSTREAM *fp, int *lineno, int *first_line)
#define DICT_FLAG_PATTERN
void(* MVECT_FN)(char *, ssize_t)
int mac_parse(const char *value, MAC_PARSE_FN action, void *context)
char * mvect_realloc(MVECT *vect, ssize_t nelm)
DICT * dict_pcre_open(const char *, int, int)
VSTRING * vstring_free(VSTRING *vp)
#define DICT_FLAG_NO_REGSUB
#define DICT_FLAG_FOLD_MUL
#define vstream_fileno(vp)
#define MAC_PARSE_VARNAME
DICT * dict_alloc(const char *, const char *, ssize_t)
#define MAC_PARSE_LITERAL
VSTRING * vstring_strcat(VSTRING *vp, const char *src)
DICT * dict_surrogate(const char *dict_type, const char *dict_name, int open_flags, int dict_flags, const char *fmt,...)
void * mymalloc(ssize_t len)
void msg_info(const char *fmt,...)