1 /* $NetBSD: context.c,v 1.3 2021/08/14 16:14:58 christos Exp $ */
2
3 /* $OpenLDAP$ */
4 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
5 *
6 * Copyright 2000-2021 The OpenLDAP Foundation.
7 * All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted only as authorized by the OpenLDAP
11 * Public License.
12 *
13 * A copy of this license is available in the file LICENSE in the
14 * top-level directory of the distribution or, alternatively, at
15 * <http://www.OpenLDAP.org/license.html>.
16 */
17 /* ACKNOWLEDGEMENT:
18 * This work was initially developed by Pierangelo Masarati for
19 * inclusion in OpenLDAP Software.
20 */
21
22 #include <portable.h>
23
24 #include "rewrite-int.h"
25
26 /*
27 * Compares two struct rewrite_context based on the name;
28 * used by avl stuff
29 */
30 static int
rewrite_context_cmp(const void * c1,const void * c2)31 rewrite_context_cmp(
32 const void *c1,
33 const void *c2
34 )
35 {
36 const struct rewrite_context *lc1, *lc2;
37
38 lc1 = (const struct rewrite_context *)c1;
39 lc2 = (const struct rewrite_context *)c2;
40
41 assert( c1 != NULL );
42 assert( c2 != NULL );
43 assert( lc1->lc_name != NULL );
44 assert( lc2->lc_name != NULL );
45
46 return strcasecmp( lc1->lc_name, lc2->lc_name );
47 }
48
49 /*
50 * Returns -1 in case a duplicate struct rewrite_context
51 * has been inserted; used by avl stuff
52 */
53 static int
rewrite_context_dup(void * c1,void * c2)54 rewrite_context_dup(
55 void *c1,
56 void *c2
57 )
58 {
59 struct rewrite_context *lc1, *lc2;
60
61 lc1 = (struct rewrite_context *)c1;
62 lc2 = (struct rewrite_context *)c2;
63
64 assert( c1 != NULL );
65 assert( c2 != NULL );
66 assert( lc1->lc_name != NULL );
67 assert( lc2->lc_name != NULL );
68
69 return( strcasecmp( lc1->lc_name, lc2->lc_name) == 0 ? -1 : 0 );
70 }
71
72 /*
73 * Finds the context named rewriteContext in the context tree
74 */
75 struct rewrite_context *
rewrite_context_find(struct rewrite_info * info,const char * rewriteContext)76 rewrite_context_find(
77 struct rewrite_info *info,
78 const char *rewriteContext
79 )
80 {
81 struct rewrite_context *context, c;
82
83 assert( info != NULL );
84 assert( rewriteContext != NULL );
85
86 /*
87 * Fetches the required rewrite context
88 */
89 c.lc_name = (char *)rewriteContext;
90 context = (struct rewrite_context *)ldap_avl_find( info->li_context,
91 (caddr_t)&c, rewrite_context_cmp );
92 if ( context == NULL ) {
93 return NULL;
94 }
95
96 /*
97 * De-aliases the context if required
98 */
99 if ( context->lc_alias ) {
100 return context->lc_alias;
101 }
102
103 return context;
104 }
105
106 /*
107 * Creates a new context called rewriteContext and stores in into the tree
108 */
109 struct rewrite_context *
rewrite_context_create(struct rewrite_info * info,const char * rewriteContext)110 rewrite_context_create(
111 struct rewrite_info *info,
112 const char *rewriteContext
113 )
114 {
115 struct rewrite_context *context;
116 int rc;
117
118 assert( info != NULL );
119 assert( rewriteContext != NULL );
120
121 context = calloc( sizeof( struct rewrite_context ), 1 );
122 if ( context == NULL ) {
123 return NULL;
124 }
125
126 /*
127 * Context name
128 */
129 context->lc_name = strdup( rewriteContext );
130 if ( context->lc_name == NULL ) {
131 free( context );
132 return NULL;
133 }
134
135 /*
136 * The first, empty rule
137 */
138 context->lc_rule = calloc( sizeof( struct rewrite_rule ), 1 );
139 if ( context->lc_rule == NULL ) {
140 free( context->lc_name );
141 free( context );
142 return NULL;
143 }
144 memset( context->lc_rule, 0, sizeof( struct rewrite_rule ) );
145
146 /*
147 * Add context to tree
148 */
149 rc = ldap_avl_insert( &info->li_context, (caddr_t)context,
150 rewrite_context_cmp, rewrite_context_dup );
151 if ( rc == -1 ) {
152 free( context->lc_rule );
153 free( context->lc_name );
154 free( context );
155 return NULL;
156 }
157
158 return context;
159 }
160
161 /*
162 * Finds the next rule according to a goto action statement,
163 * or null in case of error.
164 * Helper for rewrite_context_apply.
165 */
166 static struct rewrite_rule *
rewrite_action_goto(struct rewrite_action * action,struct rewrite_rule * rule)167 rewrite_action_goto(
168 struct rewrite_action *action,
169 struct rewrite_rule *rule
170 )
171 {
172 int n;
173
174 assert( action != NULL );
175 assert( action->la_args != NULL );
176 assert( rule != NULL );
177
178 n = ((int *)action->la_args)[ 0 ];
179
180 if ( n > 0 ) {
181 for ( ; n > 1 && rule != NULL ; n-- ) {
182 rule = rule->lr_next;
183 }
184 } else if ( n <= 0 ) {
185 for ( ; n < 1 && rule != NULL ; n++ ) {
186 rule = rule->lr_prev;
187 }
188 }
189
190 return rule;
191 }
192
193 /*
194 * Rewrites string according to context; may return:
195 * OK: fine; if *result != NULL rule matched and rewrite succeeded.
196 * STOP: fine, rule matched; stop processing following rules
197 * UNWILL: rule matched; force 'unwilling to perform'
198 */
199 int
rewrite_context_apply(struct rewrite_info * info,struct rewrite_op * op,struct rewrite_context * context,const char * string,char ** result)200 rewrite_context_apply(
201 struct rewrite_info *info,
202 struct rewrite_op *op,
203 struct rewrite_context *context,
204 const char *string,
205 char **result
206 )
207 {
208 struct rewrite_rule *rule;
209 char *s, *res = NULL;
210 int return_code = REWRITE_REGEXEC_OK;
211
212 assert( info != NULL );
213 assert( op != NULL );
214 assert( context != NULL );
215 assert( context->lc_rule != NULL );
216 assert( string != NULL );
217 assert( result != NULL );
218
219 op->lo_depth++;
220
221 Debug( LDAP_DEBUG_TRACE, "==> rewrite_context_apply"
222 " [depth=%d] string='%s'\n",
223 op->lo_depth, string );
224 assert( op->lo_depth > 0 );
225
226 s = (char *)string;
227
228 for ( rule = context->lc_rule->lr_next;
229 rule != NULL && op->lo_num_passes < info->li_max_passes;
230 rule = rule->lr_next, op->lo_num_passes++ ) {
231 int rc;
232
233 /*
234 * Apply a single rule
235 */
236 rc = rewrite_rule_apply( info, op, rule, s, &res );
237
238 /*
239 * A rule may return:
240 * OK with result != NULL if matched
241 * ERR if anything was wrong
242 * UNWILLING if the server should drop the request
243 * the latter case in honored immediately;
244 * the other two may require some special actions to take
245 * place.
246 */
247 switch ( rc ) {
248
249 case REWRITE_REGEXEC_ERR:
250 Debug( LDAP_DEBUG_ANY, "==> rewrite_context_apply"
251 " error ...\n" );
252
253 /*
254 * Checks for special actions to be taken
255 * in case of error ...
256 */
257 if ( rule->lr_action != NULL ) {
258 struct rewrite_action *action;
259 int do_continue = 0;
260
261 for ( action = rule->lr_action;
262 action != NULL;
263 action = action->la_next ) {
264 switch ( action->la_type ) {
265
266 /*
267 * This action takes precedence
268 * over the others in case of failure
269 */
270 case REWRITE_ACTION_IGNORE_ERR:
271 Debug( LDAP_DEBUG_ANY,
272 "==> rewrite_context_apply"
273 " ignoring error ...\n" );
274 do_continue = 1;
275 break;
276
277 /*
278 * Goto is honored only if it comes
279 * after ignore error
280 */
281 case REWRITE_ACTION_GOTO:
282 if ( do_continue ) {
283 rule = rewrite_action_goto( action, rule );
284 if ( rule == NULL ) {
285 return_code = REWRITE_REGEXEC_ERR;
286 goto rc_end_of_context;
287 }
288 }
289 break;
290
291 /*
292 * Other actions are ignored
293 */
294 default:
295 break;
296 }
297 }
298
299 if ( do_continue ) {
300 if ( rule->lr_next == NULL ) {
301 res = s;
302 }
303 goto rc_continue;
304 }
305 }
306
307 /*
308 * Default behavior is to bail out ...
309 */
310 return_code = REWRITE_REGEXEC_ERR;
311 goto rc_end_of_context;
312
313 /*
314 * OK means there were no errors or special return codes;
315 * if res is defined, it means the rule matched and we
316 * got a successful rewriting
317 */
318 case REWRITE_REGEXEC_OK:
319
320 /*
321 * It matched! Check for actions ...
322 */
323 if ( res != NULL ) {
324 struct rewrite_action *action;
325
326 if ( s != string && s != res ) {
327 free( s );
328 }
329 s = res;
330
331 for ( action = rule->lr_action;
332 action != NULL;
333 action = action->la_next ) {
334
335 switch ( action->la_type ) {
336
337 /*
338 * This ends the rewrite context
339 * successfully
340 */
341 case REWRITE_ACTION_STOP:
342 goto rc_end_of_context;
343
344 /*
345 * This instructs the server to return
346 * an `unwilling to perform' error
347 * message
348 */
349 case REWRITE_ACTION_UNWILLING:
350 return_code = REWRITE_REGEXEC_UNWILLING;
351 goto rc_end_of_context;
352
353 /*
354 * This causes the processing to
355 * jump n rules back and forth
356 */
357 case REWRITE_ACTION_GOTO:
358 rule = rewrite_action_goto( action, rule );
359 if ( rule == NULL ) {
360 return_code = REWRITE_REGEXEC_ERR;
361 goto rc_end_of_context;
362 }
363 break;
364
365 /*
366 * This ends the rewrite context
367 * and returns a user-defined
368 * error code
369 */
370 case REWRITE_ACTION_USER:
371 return_code = ((int *)action->la_args)[ 0 ];
372 goto rc_end_of_context;
373
374 default:
375 /* ... */
376 break;
377 }
378 }
379
380 /*
381 * If result was OK and string didn't match,
382 * in case of last rule we need to set the
383 * result back to the string
384 */
385 } else if ( rule->lr_next == NULL ) {
386 res = s;
387 }
388
389 break;
390
391 /*
392 * A STOP has propagated ...
393 */
394 case REWRITE_REGEXEC_STOP:
395 goto rc_end_of_context;
396
397 /*
398 * This will instruct the server to return
399 * an `unwilling to perform' error message
400 */
401 case REWRITE_REGEXEC_UNWILLING:
402 return_code = REWRITE_REGEXEC_UNWILLING;
403 goto rc_end_of_context;
404
405 /*
406 * A user-defined error code has propagated ...
407 */
408 default:
409 assert( rc >= REWRITE_REGEXEC_USER );
410 goto rc_end_of_context;
411
412 }
413
414 rc_continue:; /* sent here by actions that require to continue */
415
416 }
417
418 rc_end_of_context:;
419 *result = res;
420
421 Debug( LDAP_DEBUG_TRACE, "==> rewrite_context_apply"
422 " [depth=%d] res={%d,'%s'}\n",
423 op->lo_depth, return_code, ( res ? res : "NULL" ) );
424
425 assert( op->lo_depth > 0 );
426 op->lo_depth--;
427
428 return return_code;
429 }
430
431 void
rewrite_context_free(void * tmp)432 rewrite_context_free(
433 void *tmp
434 )
435 {
436 struct rewrite_context *context = (struct rewrite_context *)tmp;
437
438 assert( tmp != NULL );
439
440 rewrite_context_destroy( &context );
441 }
442
443 int
rewrite_context_destroy(struct rewrite_context ** pcontext)444 rewrite_context_destroy(
445 struct rewrite_context **pcontext
446 )
447 {
448 struct rewrite_context *context;
449 struct rewrite_rule *r;
450
451 assert( pcontext != NULL );
452 assert( *pcontext != NULL );
453
454 context = *pcontext;
455
456 assert( context->lc_rule != NULL );
457
458 for ( r = context->lc_rule->lr_next; r; ) {
459 struct rewrite_rule *cr = r;
460
461 r = r->lr_next;
462 rewrite_rule_destroy( &cr );
463 }
464
465 free( context->lc_rule );
466 context->lc_rule = NULL;
467
468 assert( context->lc_name != NULL );
469 free( context->lc_name );
470 context->lc_name = NULL;
471
472 free( context );
473 *pcontext = NULL;
474
475 return 0;
476 }
477