]> git.sur5r.net Git - openldap/blob - libraries/librewrite/rule.c
Use ldap_unbind_ext(3)
[openldap] / libraries / librewrite / rule.c
1 /* $OpenLDAP$ */
2 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
3  *
4  * Copyright 2000-2003 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 #include <portable.h>
21
22 #include "rewrite-int.h"
23
24 /*
25  * Appends a rule to the double linked list of rules
26  * Helper for rewrite_rule_compile
27  */
28 static int
29 append_rule(
30                 struct rewrite_context *context,
31                 struct rewrite_rule *rule
32 )
33 {
34         struct rewrite_rule *r;
35
36         assert( context != NULL );
37         assert( context->lc_rule != NULL );
38         assert( rule != NULL );
39
40         for ( r = context->lc_rule; r->lr_next != NULL; r = r->lr_next );
41         r->lr_next = rule;
42         rule->lr_prev = r;
43         
44         return REWRITE_SUCCESS;
45 }
46
47 /*
48  * Appends an action to the linked list of actions
49  * Helper for rewrite_rule_compile
50  */
51 static int
52 append_action(
53                 struct rewrite_action *base,
54                 struct rewrite_action *action
55 )
56 {
57         struct rewrite_action *a;
58
59         assert( base != NULL );
60         assert( action != NULL );
61         
62         for ( a = base; a->la_next != NULL; a = a->la_next );
63         a->la_next = action;
64         
65         return REWRITE_SUCCESS;
66 }
67
68 static int
69 destroy_action(
70                 struct rewrite_action **paction
71 )
72 {
73         struct rewrite_action   *action;
74
75         assert( paction );
76         assert( *paction );
77
78         action = *paction;
79
80         /* do something */
81         switch ( action->la_type ) {
82         case REWRITE_FLAG_GOTO: {
83                 int *pi = (int *)action->la_args;
84
85                 if ( pi ) {
86                         free( pi );
87                 }
88                 break;
89         }
90
91         default:
92                 break;
93         }
94         
95         free( action );
96         *paction = NULL;
97         
98         return 0;
99 }
100
101 /*
102  * In case of error it returns NULL and does not free all the memory
103  * it allocated; as this is a once only phase, and an error at this stage
104  * would require the server to stop, there is no need to be paranoid
105  * about memory allocation
106  */
107 int
108 rewrite_rule_compile(
109                 struct rewrite_info *info,
110                 struct rewrite_context *context,
111                 const char *pattern,
112                 const char *result,
113                 const char *flagstring
114 )
115 {
116         int flags = REWRITE_REGEX_EXTENDED | REWRITE_REGEX_ICASE;
117         int mode = REWRITE_RECURSE;
118
119         struct rewrite_rule *rule = NULL;
120         struct rewrite_subst *subst = NULL;
121         struct rewrite_action *action = NULL, *first_action = NULL;
122
123         const char *p;
124
125         assert( info != NULL );
126         assert( context != NULL );
127         assert( pattern != NULL );
128         assert( result != NULL );
129
130         /*
131          * A null flagstring should be allowed
132          */
133
134         /*
135          * Take care of substitution string
136          */
137         subst = rewrite_subst_compile( info, result );
138         if ( subst == NULL ) {
139                 return REWRITE_ERR;
140         }
141
142         /*
143          * Take care of flags
144          */
145         for ( p = flagstring; p[ 0 ] != '\0'; p++ ) {
146                 switch( p[ 0 ] ) {
147                         
148                 /*
149                  * REGEX flags
150                  */
151                 case REWRITE_FLAG_HONORCASE:            /* 'C' */
152                         /*
153                          * Honor case (default is case insensitive)
154                          */
155                         flags &= ~REWRITE_REGEX_ICASE;
156                         break;
157                         
158                 case REWRITE_FLAG_BASICREGEX:           /* 'R' */
159                         /*
160                          * Use POSIX Basic Regular Expression syntax
161                          * instead of POSIX Extended Regular Expression 
162                          * syntax (default)
163                          */
164                         flags &= ~REWRITE_REGEX_EXTENDED;
165                         break;
166                         
167                 /*
168                  * Execution mode flags
169                  */
170                 case REWRITE_FLAG_EXECONCE:             /* ':' */
171                         /*
172                          * Apply rule once only
173                          */
174                         mode &= ~REWRITE_RECURSE;
175                         mode |= REWRITE_EXEC_ONCE;
176                         break;
177                 
178                 /*
179                  * Special action flags
180                  */
181                 case REWRITE_FLAG_STOP:                 /* '@' */
182                         /*
183                          * Bail out after applying rule
184                          */
185                         action = calloc( sizeof( struct rewrite_action ), 1 );
186                         if ( action == NULL ) {
187                                 /* cleanup ... */
188                                 return REWRITE_ERR;
189                         }
190                         
191                         mode &= ~REWRITE_RECURSE;
192                         mode |= REWRITE_EXEC_ONCE;
193                         action->la_type = REWRITE_ACTION_STOP;
194                         break;
195                         
196                 case REWRITE_FLAG_UNWILLING:            /* '#' */
197                         /*
198                          * Matching objs will be marked as gone!
199                          */
200                         action = calloc( sizeof( struct rewrite_action ), 1 );
201                         if ( action == NULL ) {
202                                 /* cleanup ... */
203                                 return REWRITE_ERR;
204                         }
205                         
206                         mode &= ~REWRITE_RECURSE;
207                         mode |= REWRITE_EXEC_ONCE;
208                         action->la_type = REWRITE_ACTION_UNWILLING;
209                         break;
210
211                 case REWRITE_FLAG_GOTO: {                       /* 'G' */
212                         /*
213                          * After applying rule, jump N rules
214                          */
215
216                         char buf[16], *q;
217                         size_t l;
218                         int *d;
219                         
220                         if ( p[ 1 ] != '{' ) {
221                                 /* XXX Need to free stuff */
222                                 return REWRITE_ERR;
223                         }
224
225                         q = strchr( p + 2, '}' );
226                         if ( q == NULL ) {
227                                 /* XXX Need to free stuff */
228                                 return REWRITE_ERR;
229                         }
230
231                         l = q - p + 2;
232                         if ( l >= sizeof( buf ) ) {
233                                 /* XXX Need to free stuff */
234                                 return REWRITE_ERR;
235                         }
236                         AC_MEMCPY( buf, p + 2, l );
237                         buf[ l ] = '\0';
238
239                         d = malloc( sizeof( int ) );
240                         if ( d == NULL ) {
241                                 /* XXX Need to free stuff */
242                                 return REWRITE_ERR;
243                         }
244                         d[ 0 ] = atoi( buf );
245
246                         action = calloc( sizeof( struct rewrite_action ), 1 );
247                         if ( action == NULL ) {
248                                 /* cleanup ... */       
249                                 return REWRITE_ERR;
250                         }
251                         action->la_type = REWRITE_ACTION_GOTO;
252                         action->la_args = (void *)d;
253
254                         p = q;  /* p is incremented by the for ... */
255                 
256                         break;
257                 }
258
259                 case REWRITE_FLAG_IGNORE_ERR:               /* 'I' */
260                         /*
261                          * Ignore errors!
262                          */
263                         action = calloc( sizeof( struct rewrite_action ), 1 );
264                         if ( action == NULL ) {
265                                 /* cleanup ... */
266                                 return REWRITE_ERR;
267                         }
268                         
269                         action->la_type = REWRITE_ACTION_IGNORE_ERR;
270                         break;
271                         
272                 /*
273                  * Other flags ...
274                  */
275                 default:
276                         /*
277                          * Unimplemented feature (complain only)
278                          */
279                         break;
280                 }
281                 
282                 /*
283                  * Stupid way to append to a list ...
284                  */
285                 if ( action != NULL ) {
286                         if ( first_action == NULL ) {
287                                 first_action = action;
288                         } else {
289                                 append_action( first_action, action );
290                         }
291                         action = NULL;
292                 }
293         }
294         
295         /*
296          * Finally, rule allocation
297          */
298         rule = calloc( sizeof( struct rewrite_rule ), 1 );
299         if ( rule == NULL ) {
300                 /* charray_free( res ); */
301                 /*
302                  * XXX need to free the value subst stuff!
303                  */
304                 return REWRITE_ERR;
305         }
306         
307         /*
308          * REGEX compilation (luckily I don't need to take care of this ...)
309          */
310         if ( regcomp( &rule->lr_regex, ( char * )pattern, flags ) != 0 ) {
311                 /* charray_free( res ); */
312                 /*
313                  *XXX need to free the value subst stuff!
314                  */
315                 free( rule );
316                 return REWRITE_ERR;
317         }
318         
319         /*
320          * Just to remember them ...
321          */
322         rule->lr_pattern = strdup( pattern );
323         rule->lr_subststring = strdup( result );
324         rule->lr_flagstring = strdup( flagstring );
325         
326         /*
327          * Load compiled data into rule
328          */
329         rule->lr_subst = subst;
330
331         /*
332          * Set various parameters
333          */
334         rule->lr_flags = flags;         /* don't really need any longer ... */
335         rule->lr_mode = mode;
336         rule->lr_action = first_action;
337         
338         /*
339          * Append rule at the end of the rewrite context
340          */
341         append_rule( context, rule );
342
343         return REWRITE_SUCCESS;
344 }
345
346 /*
347  * Rewrites string according to rule; may return:
348  *      OK:     fine; if *result != NULL rule matched and rewrite succeeded.
349  *      STOP:   fine, rule matched; stop processing following rules
350  *      UNWILL: rule matched; force 'unwilling to perform'
351  */
352 int
353 rewrite_rule_apply(
354                 struct rewrite_info *info,
355                 struct rewrite_op *op,
356                 struct rewrite_rule *rule,
357                 const char *arg,
358                 char **result
359                 )
360 {
361         size_t nmatch = REWRITE_MAX_MATCH;
362         regmatch_t match[ REWRITE_MAX_MATCH ];
363
364         int rc = REWRITE_SUCCESS;
365
366         char *string;
367         int strcnt = 0;
368         struct berval val = { 0, NULL };
369
370         assert( info != NULL );
371         assert( op != NULL );
372         assert( rule != NULL );
373         assert( arg != NULL );
374         assert( result != NULL );
375
376         *result = NULL;
377
378         string = (char *)arg;
379         
380         /*
381          * In case recursive match is required (default)
382          */
383 recurse:;
384
385         Debug( LDAP_DEBUG_TRACE, "==> rewrite_rule_apply"
386                         " rule='%s' string='%s'\n", 
387                         rule->lr_pattern, string, 0 );
388         
389         op->lo_num_passes++;
390         if ( regexec( &rule->lr_regex, string, nmatch, match, 0 ) != 0 ) {
391                 if ( *result == NULL && strcnt > 0 ) {
392                         free( string );
393                         string = NULL;
394                 }
395
396                 /*
397                  * No match is OK; *result = NULL means no match
398                  */
399                 return REWRITE_REGEXEC_OK;
400         }
401
402         rc = rewrite_subst_apply( info, op, rule->lr_subst, string,
403                         match, &val );
404
405         *result = val.bv_val;
406         val.bv_val = NULL;
407         if ( strcnt > 0 ) {
408                 free( string );
409                 string = NULL;
410         }
411
412         if ( rc != REWRITE_REGEXEC_OK ) {
413                 return rc;
414         }
415
416         if ( ( rule->lr_mode & REWRITE_RECURSE ) == REWRITE_RECURSE 
417                         && op->lo_num_passes <= info->li_max_passes ) {
418                 string = *result;
419                 strcnt++;
420
421                 goto recurse;
422         }
423
424         return REWRITE_REGEXEC_OK;
425 }
426
427 int
428 rewrite_rule_destroy(
429                 struct rewrite_rule **prule
430                 )
431 {
432         struct rewrite_rule *rule;
433         struct rewrite_action *action;
434
435         assert( prule );
436         assert( *prule );
437
438         rule = *prule;
439
440         if ( rule->lr_pattern ) {
441                 free( rule->lr_pattern );
442                 rule->lr_pattern = NULL;
443         }
444
445         if ( rule->lr_subststring ) {
446                 free( rule->lr_subststring );
447                 rule->lr_subststring = NULL;
448         }
449
450         if ( rule->lr_flagstring ) {
451                 free( rule->lr_flagstring );
452                 rule->lr_flagstring = NULL;
453         }
454
455         if ( rule->lr_subst ) {
456                 rewrite_subst_destroy( &rule->lr_subst );
457         }
458
459         regfree( &rule->lr_regex );
460
461         for ( action = rule->lr_action; action; ) {
462                 struct rewrite_action *curraction = action;
463
464                 action = action->la_next;
465                 destroy_action( &curraction );
466         }
467
468         free( rule );
469         *prule = NULL;
470
471         return 0;
472 }
473