1/* $OpenLDAP$ */
2/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
3 *
4 * Copyright 2000-2011 The OpenLDAP Foundation.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted only as authorized by the OpenLDAP
9 * Public License.
10 *
11 * A copy of this license is available in the file LICENSE in the
12 * top-level directory of the distribution or, alternatively, at
13 * <http://www.OpenLDAP.org/license.html>.
14 */
15/* ACKNOWLEDGEMENT:
16 * This work was initially developed by Pierangelo Masarati for
17 * inclusion in OpenLDAP Software.
18 */
19
20#ifndef REWRITE_INT_H
21#define REWRITE_INT_H
22
23/*
24 * These are required by every file of the library, so they're included here
25 */
26#include <ac/stdlib.h>
27#include <ac/string.h>
28#include <ac/syslog.h>
29#include <ac/regex.h>
30#include <ac/socket.h>
31#include <ac/unistd.h>
32#include <ac/ctype.h>
33
34#include <lber.h>
35#include <ldap.h>
36#define LDAP_DEFINE_LDAP_DEBUG
37#include <ldap_log.h>
38#include <lutil.h>
39#include <avl.h>
40
41#include <rewrite.h>
42
43#define malloc(x)	ber_memalloc(x)
44#define calloc(x,y)	ber_memcalloc(x,y)
45#define realloc(x,y)	ber_memrealloc(x,y)
46#define free(x)	ber_memfree(x)
47#undef strdup
48#define	strdup(x)	ber_strdup(x)
49
50/* Uncomment to use ldap pvt threads */
51#define USE_REWRITE_LDAP_PVT_THREADS
52#include <ldap_pvt_thread.h>
53
54/*
55 * For details, see RATIONALE.
56 */
57
58#define REWRITE_MAX_MATCH	11	/* 0: overall string; 1-9: submatches */
59#define REWRITE_MAX_PASSES	100
60
61/*
62 * Submatch escape char
63 */
64/* the '\' conflicts with slapd.conf parsing */
65/* #define REWRITE_SUBMATCH_ESCAPE			'\\' */
66#define REWRITE_SUBMATCH_ESCAPE_ORIG		'%'
67#define REWRITE_SUBMATCH_ESCAPE			'$'
68#define IS_REWRITE_SUBMATCH_ESCAPE(c) \
69	((c) == REWRITE_SUBMATCH_ESCAPE || (c) == REWRITE_SUBMATCH_ESCAPE_ORIG)
70
71/*
72 * REGEX flags
73 */
74
75#define REWRITE_FLAG_HONORCASE			'C'
76#define REWRITE_FLAG_BASICREGEX			'R'
77
78/*
79 * Action flags
80 */
81#define REWRITE_FLAG_EXECONCE			':'
82#define REWRITE_FLAG_STOP			'@'
83#define REWRITE_FLAG_UNWILLING			'#'
84#define REWRITE_FLAG_GOTO			'G'	/* requires an arg */
85#define REWRITE_FLAG_USER			'U'	/* requires an arg */
86#define REWRITE_FLAG_MAX_PASSES			'M'	/* requires an arg */
87#define REWRITE_FLAG_IGNORE_ERR			'I'
88
89/*
90 * Map operators
91 */
92#define REWRITE_OPERATOR_SUBCONTEXT		'>'
93#define REWRITE_OPERATOR_COMMAND		'|'
94#define REWRITE_OPERATOR_VARIABLE_SET		'&'
95#define REWRITE_OPERATOR_VARIABLE_GET		'*'
96#define REWRITE_OPERATOR_PARAM_GET		'$'
97
98
99/***********
100 * PRIVATE *
101 ***********/
102
103/*
104 * Action
105 */
106struct rewrite_action {
107	struct rewrite_action          *la_next;
108
109#define REWRITE_ACTION_STOP		0x0001
110#define REWRITE_ACTION_UNWILLING	0x0002
111#define REWRITE_ACTION_GOTO		0x0003
112#define REWRITE_ACTION_IGNORE_ERR	0x0004
113#define REWRITE_ACTION_USER		0x0005
114	int                             la_type;
115	void                           *la_args;
116};
117
118/*
119 * Map
120 */
121struct rewrite_map {
122
123	/*
124	 * Legacy stuff
125	 */
126#define REWRITE_MAP_XFILEMAP		0x0001	/* Rough implementation! */
127#define REWRITE_MAP_XPWDMAP		0x0002  /* uid -> gecos */
128#define REWRITE_MAP_XLDAPMAP		0x0003	/* Not implemented yet! */
129
130	/*
131	 * Maps with args
132	 */
133#define REWRITE_MAP_SUBCONTEXT		0x0101
134
135#define REWRITE_MAP_SET_OP_VAR		0x0102
136#define REWRITE_MAP_SETW_OP_VAR		0x0103
137#define REWRITE_MAP_GET_OP_VAR		0x0104
138#define	REWRITE_MAP_SET_SESN_VAR	0x0105
139#define REWRITE_MAP_SETW_SESN_VAR	0x0106
140#define	REWRITE_MAP_GET_SESN_VAR	0x0107
141#define REWRITE_MAP_GET_PARAM		0x0108
142#define REWRITE_MAP_BUILTIN		0x0109
143	int                             lm_type;
144
145	char                           *lm_name;
146	void                           *lm_data;
147
148	/*
149	 * Old maps store private data in _lm_args;
150	 * new maps store the substitution pattern in _lm_subst
151	 */
152	union {
153	        void                   *_lm_args;
154		struct rewrite_subst   *_lm_subst;
155	} lm_union;
156#define	lm_args lm_union._lm_args
157#define	lm_subst lm_union._lm_subst
158
159#ifdef USE_REWRITE_LDAP_PVT_THREADS
160	ldap_pvt_thread_mutex_t         lm_mutex;
161#endif /* USE_REWRITE_LDAP_PVT_THREADS */
162};
163
164/*
165 * Builtin maps
166 */
167struct rewrite_builtin_map {
168#define REWRITE_BUILTIN_MAP	0x0200
169	int                             lb_type;
170	char                           *lb_name;
171	void                           *lb_private;
172	const rewrite_mapper		   *lb_mapper;
173
174#ifdef USE_REWRITE_LDAP_PVT_THREADS
175	ldap_pvt_thread_mutex_t         lb_mutex;
176#endif /* USE_REWRITE_LDAP_PVT_THREADS */
177};
178
179/*
180 * Submatch substitution
181 */
182struct rewrite_submatch {
183#define REWRITE_SUBMATCH_ASIS		0x0000
184#define REWRITE_SUBMATCH_XMAP		0x0001
185#define REWRITE_SUBMATCH_MAP_W_ARG	0x0002
186	int                             ls_type;
187	struct rewrite_map             *ls_map;
188	int                             ls_submatch;
189	/*
190	 * The first one represents the index of the submatch in case
191	 * the map has single submatch as argument;
192	 * the latter represents the map argument scheme in case
193	 * the map has substitution string argument form
194	 */
195};
196
197/*
198 * Pattern substitution
199 */
200struct rewrite_subst {
201	size_t                          lt_subs_len;
202	struct berval                  *lt_subs;
203
204	int                             lt_num_submatch;
205	struct rewrite_submatch        *lt_submatch;
206};
207
208/*
209 * Rule
210 */
211struct rewrite_rule {
212	struct rewrite_rule            *lr_next;
213	struct rewrite_rule            *lr_prev;
214
215	char                           *lr_pattern;
216	char                           *lr_subststring;
217	char                           *lr_flagstring;
218	regex_t				lr_regex;
219
220	/*
221	 * I was thinking about some kind of per-rule mutex, but there's
222	 * probably no need, because rules after compilation are only read;
223	 * however, I need to check whether regexec is reentrant ...
224	 */
225
226	struct rewrite_subst           *lr_subst;
227
228#define REWRITE_REGEX_ICASE		REG_ICASE
229#define REWRITE_REGEX_EXTENDED		REG_EXTENDED
230	int                             lr_flags;
231
232#define REWRITE_RECURSE			0x0001
233#define REWRITE_EXEC_ONCE          	0x0002
234	int				lr_mode;
235	int				lr_max_passes;
236
237	struct rewrite_action          *lr_action;
238};
239
240/*
241 * Rewrite Context (set of rules)
242 */
243struct rewrite_context {
244	char                           *lc_name;
245	struct rewrite_context         *lc_alias;
246	struct rewrite_rule            *lc_rule;
247};
248
249/*
250 * Session
251 */
252struct rewrite_session {
253	void                           *ls_cookie;
254	Avlnode                        *ls_vars;
255#ifdef USE_REWRITE_LDAP_PVT_THREADS
256	ldap_pvt_thread_rdwr_t          ls_vars_mutex;
257	ldap_pvt_thread_mutex_t		ls_mutex;
258#endif /* USE_REWRITE_LDAP_PVT_THREADS */
259	int				ls_count;
260};
261
262/*
263 * Variable
264 */
265struct rewrite_var {
266	char                           *lv_name;
267	int				lv_flags;
268	struct berval                   lv_value;
269};
270
271/*
272 * Operation
273 */
274struct rewrite_op {
275	int                             lo_num_passes;
276	int                             lo_depth;
277#if 0 /* FIXME: not used anywhere! (debug? then, why strdup?) */
278	char                           *lo_string;
279#endif
280	char                           *lo_result;
281	Avlnode                        *lo_vars;
282	const void                     *lo_cookie;
283};
284
285
286/**********
287 * PUBLIC *
288 **********/
289
290/*
291 * Rewrite info
292 */
293struct rewrite_info {
294	Avlnode                        *li_context;
295	Avlnode                        *li_maps;
296	/*
297	 * No global mutex because maps are read only at
298	 * config time
299	 */
300	Avlnode                        *li_params;
301	Avlnode                        *li_cookies;
302	int                             li_num_cookies;
303
304#ifdef USE_REWRITE_LDAP_PVT_THREADS
305	ldap_pvt_thread_rdwr_t          li_params_mutex;
306        ldap_pvt_thread_rdwr_t          li_cookies_mutex;
307#endif /* USE_REWRITE_LDAP_PVT_THREADS */
308
309	/*
310	 * Default to `off';
311	 * use `rewriteEngine {on|off}' directive to alter
312	 */
313	int				li_state;
314
315	/*
316	 * Defaults to REWRITE_MAXPASSES;
317	 * use `rewriteMaxPasses numPasses' directive to alter
318	 */
319#define REWRITE_MAXPASSES		100
320	int                             li_max_passes;
321	int                             li_max_passes_per_rule;
322
323	/*
324	 * Behavior in case a NULL or non-existent context is required
325	 */
326	int                             li_rewrite_mode;
327};
328
329/***********
330 * PRIVATE *
331 ***********/
332
333LDAP_REWRITE_V (struct rewrite_context*) rewrite_int_curr_context;
334
335/*
336 * Maps
337 */
338
339/*
340 * Parses a map (also in legacy 'x' version)
341 */
342LDAP_REWRITE_F (struct rewrite_map *)
343rewrite_map_parse(
344		struct rewrite_info *info,
345		const char *s,
346		const char **end
347);
348
349LDAP_REWRITE_F (struct rewrite_map *)
350rewrite_xmap_parse(
351		struct rewrite_info *info,
352		const char *s,
353		const char **end
354);
355
356/*
357 * Resolves key in val by means of map (also in legacy 'x' version)
358 */
359LDAP_REWRITE_F (int)
360rewrite_map_apply(
361		struct rewrite_info *info,
362		struct rewrite_op *op,
363		struct rewrite_map *map,
364		struct berval *key,
365		struct berval *val
366);
367
368LDAP_REWRITE_F (int)
369rewrite_xmap_apply(
370		struct rewrite_info *info,
371		struct rewrite_op *op,
372		struct rewrite_map *map,
373		struct berval *key,
374		struct berval *val
375);
376
377LDAP_REWRITE_F (int)
378rewrite_map_destroy(
379		struct rewrite_map **map
380);
381
382LDAP_REWRITE_F (int)
383rewrite_xmap_destroy(
384		struct rewrite_map **map
385);
386
387LDAP_REWRITE_F (void)
388rewrite_builtin_map_free(
389		void *map
390);
391/*
392 * Submatch substitution
393 */
394
395/*
396 * Compiles a substitution pattern
397 */
398LDAP_REWRITE_F (struct rewrite_subst *)
399rewrite_subst_compile(
400		struct rewrite_info *info,
401		const char *result
402);
403
404/*
405 * Substitutes a portion of rewritten string according to substitution
406 * pattern using submatches
407 */
408LDAP_REWRITE_F (int)
409rewrite_subst_apply(
410		struct rewrite_info *info,
411		struct rewrite_op *op,
412		struct rewrite_subst *subst,
413		const char *string,
414		const regmatch_t *match,
415		struct berval *val
416);
417
418LDAP_REWRITE_F (int)
419rewrite_subst_destroy(
420		struct rewrite_subst **subst
421);
422
423
424/*
425 * Rules
426 */
427
428/*
429 * Compiles the rule and appends it at the running context
430 */
431LDAP_REWRITE_F (int)
432rewrite_rule_compile(
433		struct rewrite_info *info,
434		struct rewrite_context *context,
435		const char *pattern,
436		const char *result,
437		const char *flagstring
438);
439
440/*
441 * Rewrites string according to rule; may return:
442 *      REWRITE_REGEXEC_OK:	fine; if *result != NULL rule matched
443 *      			and rewrite succeeded.
444 *      REWRITE_REGEXEC_STOP:   fine, rule matched; stop processing
445 *      			following rules
446 *      REWRITE_REGEXEC_UNWILL: rule matched; force 'unwilling to perform'
447 *      REWRITE_REGEXEC_ERR:	an error occurred
448 */
449LDAP_REWRITE_F (int)
450rewrite_rule_apply(
451		struct rewrite_info *info,
452		struct rewrite_op *op,
453		struct rewrite_rule *rule,
454		const char *string,
455		char **result
456);
457
458LDAP_REWRITE_F (int)
459rewrite_rule_destroy(
460		struct rewrite_rule **rule
461);
462
463/*
464 * Sessions
465 */
466
467/*
468 * Fetches a struct rewrite_session
469 */
470LDAP_REWRITE_F (struct rewrite_session *)
471rewrite_session_find(
472                struct rewrite_info *info,
473                const void *cookie
474);
475
476/*
477 * Defines and inits a variable with session scope
478 */
479LDAP_REWRITE_F (int)
480rewrite_session_var_set_f(
481                struct rewrite_info *info,
482                const void *cookie,
483                const char *name,
484                const char *value,
485		int flags
486);
487
488/*
489 * Gets a var with session scope
490 */
491LDAP_REWRITE_F (int)
492rewrite_session_var_get(
493                struct rewrite_info *info,
494                const void *cookie,
495                const char *name,
496                struct berval *val
497);
498
499/*
500 * Deletes a session
501 */
502LDAP_REWRITE_F (int)
503rewrite_session_delete(
504                struct rewrite_info *info,
505                const void *cookie
506);
507
508/*
509 * Destroys the cookie tree
510 */
511LDAP_REWRITE_F (int)
512rewrite_session_destroy(
513                struct rewrite_info *info
514);
515
516
517/*
518 * Vars
519 */
520
521/*
522 * Finds a var
523 */
524LDAP_REWRITE_F (struct rewrite_var *)
525rewrite_var_find(
526                Avlnode *tree,
527                const char *name
528);
529
530/*
531 * Replaces the value of a variable
532 */
533LDAP_REWRITE_F (int)
534rewrite_var_replace(
535		struct rewrite_var *var,
536		const char *value,
537		int flags
538);
539
540/*
541 * Inserts a newly created var
542 */
543LDAP_REWRITE_F (struct rewrite_var *)
544rewrite_var_insert_f(
545                Avlnode **tree,
546                const char *name,
547                const char *value,
548		int flags
549);
550
551#define rewrite_var_insert(tree, name, value) \
552	rewrite_var_insert_f((tree), (name), (value), \
553			REWRITE_VAR_UPDATE|REWRITE_VAR_COPY_NAME|REWRITE_VAR_COPY_VALUE)
554
555/*
556 * Sets/inserts a var
557 */
558LDAP_REWRITE_F (struct rewrite_var *)
559rewrite_var_set_f(
560                Avlnode **tree,
561                const char *name,
562                const char *value,
563                int flags
564);
565
566#define rewrite_var_set(tree, name, value, insert) \
567	rewrite_var_set_f((tree), (name), (value), \
568			REWRITE_VAR_UPDATE|REWRITE_VAR_COPY_NAME|REWRITE_VAR_COPY_VALUE|((insert)? REWRITE_VAR_INSERT : 0))
569
570/*
571 * Deletes a var tree
572 */
573LDAP_REWRITE_F (int)
574rewrite_var_delete(
575                Avlnode *tree
576);
577
578
579/*
580 * Contexts
581 */
582
583/*
584 * Finds the context named rewriteContext in the context tree
585 */
586LDAP_REWRITE_F (struct rewrite_context *)
587rewrite_context_find(
588		struct rewrite_info *info,
589		const char *rewriteContext
590);
591
592/*
593 * Creates a new context called rewriteContext and stores in into the tree
594 */
595LDAP_REWRITE_F (struct rewrite_context *)
596rewrite_context_create(
597		struct rewrite_info *info,
598		const char *rewriteContext
599);
600
601/*
602 * Rewrites string according to context; may return:
603 *      OK:     fine; if *result != NULL rule matched and rewrite succeeded.
604 *      STOP:   fine, rule matched; stop processing following rules
605 *      UNWILL: rule matched; force 'unwilling to perform'
606 */
607LDAP_REWRITE_F (int)
608rewrite_context_apply(
609		struct rewrite_info *info,
610		struct rewrite_op *op,
611		struct rewrite_context *context,
612		const char *string,
613		char **result
614);
615
616LDAP_REWRITE_F (int)
617rewrite_context_destroy(
618		struct rewrite_context **context
619);
620
621LDAP_REWRITE_F (void)
622rewrite_context_free(
623		void *tmp
624);
625
626#endif /* REWRITE_INT_H */
627
628