]> git.sur5r.net Git - openldap/blob - libraries/librewrite/subst.c
Happy New Year!
[openldap] / libraries / librewrite / subst.c
1 /* $OpenLDAP$ */
2 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
3  *
4  * Copyright 2000-2017 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  * Compiles a substitution pattern
26  */
27 struct rewrite_subst *
28 rewrite_subst_compile(
29                 struct rewrite_info *info,
30                 const char *str
31 )
32 {
33         size_t subs_len;
34         struct berval *subs = NULL, *tmps;
35         struct rewrite_submatch *submatch = NULL;
36
37         struct rewrite_subst *s = NULL;
38
39         char *result, *begin, *p;
40         int nsub = 0, l;
41
42         assert( info != NULL );
43         assert( str != NULL );
44
45         result = strdup( str );
46         if ( result == NULL ) {
47                 return NULL;
48         }
49
50         /*
51          * Take care of substitution string
52          */
53         for ( p = begin = result, subs_len = 0; p[ 0 ] != '\0'; p++ ) {
54
55                 /*
56                  * Keep only single escapes '%'
57                  */
58                 if (  !IS_REWRITE_SUBMATCH_ESCAPE( p[ 0 ] ) ) {
59                         continue;
60                 } 
61
62                 if (  IS_REWRITE_SUBMATCH_ESCAPE( p[ 1 ] ) ) {
63                         /* Pull &p[1] over p, including the trailing '\0' */
64                         AC_MEMCPY((char *)p, &p[ 1 ], strlen( p ) );
65                         continue;
66                 }
67
68                 tmps = ( struct berval * )realloc( subs,
69                                 sizeof( struct berval )*( nsub + 1 ) );
70                 if ( tmps == NULL ) {
71                         goto cleanup;
72                 }
73                 subs = tmps;
74                 
75                 /*
76                  * I think an `if l > 0' at runtime is better outside than
77                  * inside a function call ...
78                  */
79                 l = p - begin;
80                 if ( l > 0 ) {
81                         subs_len += l;
82                         subs[ nsub ].bv_len = l;
83                         subs[ nsub ].bv_val = malloc( l + 1 );
84                         if ( subs[ nsub ].bv_val == NULL ) {
85                                 goto cleanup;
86                         }
87                         AC_MEMCPY( subs[ nsub ].bv_val, begin, l );
88                         subs[ nsub ].bv_val[ l ] = '\0';
89                 } else {
90                         subs[ nsub ].bv_val = NULL;
91                         subs[ nsub ].bv_len = 0;
92                 }
93                 
94                 /*
95                  * Substitution pattern
96                  */
97                 if ( isdigit( (unsigned char) p[ 1 ] ) ) {
98                         struct rewrite_submatch *tmpsm;
99                         int d = p[ 1 ] - '0';
100
101                         /*
102                          * Add a new value substitution scheme
103                          */
104
105                         tmpsm = ( struct rewrite_submatch * )realloc( submatch,
106                                         sizeof( struct rewrite_submatch )*( nsub + 1 ) );
107                         if ( tmpsm == NULL ) {
108                                 goto cleanup;
109                         }
110                         submatch = tmpsm;
111                         submatch[ nsub ].ls_submatch = d;
112
113                         /*
114                          * If there is no argument, use default
115                          * (substitute substring as is)
116                          */
117                         if ( p[ 2 ] != '{' ) {
118                                 submatch[ nsub ].ls_type = 
119                                         REWRITE_SUBMATCH_ASIS;
120                                 submatch[ nsub ].ls_map = NULL;
121                                 begin = ++p + 1;
122
123                         } else {
124                                 struct rewrite_map *map;
125
126                                 submatch[ nsub ].ls_type =
127                                         REWRITE_SUBMATCH_XMAP;
128
129                                 map = rewrite_xmap_parse( info,
130                                                 p + 3, (const char **)&begin );
131                                 if ( map == NULL ) {
132                                         goto cleanup;
133                                 }
134                                 submatch[ nsub ].ls_map = map;
135                                 p = begin - 1;
136                         }
137
138                 /*
139                  * Map with args ...
140                  */
141                 } else if ( p[ 1 ] == '{' ) {
142                         struct rewrite_map *map;
143                         struct rewrite_submatch *tmpsm;
144
145                         map = rewrite_map_parse( info, p + 2,
146                                         (const char **)&begin );
147                         if ( map == NULL ) {
148                                 goto cleanup;
149                         }
150                         p = begin - 1;
151
152                         /*
153                          * Add a new value substitution scheme
154                          */
155                         tmpsm = ( struct rewrite_submatch * )realloc( submatch,
156                                         sizeof( struct rewrite_submatch )*( nsub + 1 ) );
157                         if ( tmpsm == NULL ) {
158                                 rewrite_map_destroy( &map );
159                                 goto cleanup;
160                         }
161                         submatch = tmpsm;
162                         submatch[ nsub ].ls_type =
163                                 REWRITE_SUBMATCH_MAP_W_ARG;
164                         submatch[ nsub ].ls_map = map;
165
166                 /*
167                  * Escape '%' ...
168                  */
169                 } else if ( p[ 1 ] == '%' ) {
170                         AC_MEMCPY( &p[ 1 ], &p[ 2 ], strlen( &p[ 1 ] ) );
171                         continue;
172
173                 } else {
174                         goto cleanup;
175                 }
176
177                 nsub++;
178         }
179         
180         /*
181          * Last part of string
182          */
183         tmps = (struct berval * )realloc( subs, sizeof( struct berval )*( nsub + 1 ) );
184         if ( tmps == NULL ) {
185                 /*
186                  * XXX need to free the value subst stuff!
187                  */
188                 free( subs );
189                 goto cleanup;
190         }
191         subs = tmps;
192         l = p - begin;
193         if ( l > 0 ) {
194                 subs_len += l;
195                 subs[ nsub ].bv_len = l;
196                 subs[ nsub ].bv_val = malloc( l + 1 );
197                 if ( subs[ nsub ].bv_val == NULL ) {
198                         goto cleanup;
199                 }
200                 AC_MEMCPY( subs[ nsub ].bv_val, begin, l );
201                 subs[ nsub ].bv_val[ l ] = '\0';
202         } else {
203                 subs[ nsub ].bv_val = NULL;
204                 subs[ nsub ].bv_len = 0;
205         }
206
207         s = calloc( sizeof( struct rewrite_subst ), 1 );
208         if ( s == NULL ) {
209                 goto cleanup;
210         }
211
212         s->lt_subs_len = subs_len;
213         s->lt_subs = subs;
214         s->lt_num_submatch = nsub;
215         s->lt_submatch = submatch;
216         subs = NULL;
217         submatch = NULL;
218
219 cleanup:;
220         if ( subs ) {
221                 for ( l=0; l<nsub; l++ ) {
222                         free( subs[nsub].bv_val );
223                 }
224                 free( subs );
225         }
226         if ( submatch ) {
227                 for ( l=0; l<nsub; l++ ) {
228                         free( submatch[nsub].ls_map );
229                 }
230                 free( submatch );
231         }
232         free( result );
233
234         return s;
235 }
236
237 /*
238  * Copies the match referred to by submatch and fetched in string by match.
239  * Helper for rewrite_rule_apply.
240  */
241 static int
242 submatch_copy(
243                 struct rewrite_submatch *submatch,
244                 const char *string,
245                 const regmatch_t *match,
246                 struct berval *val
247 )
248 {
249         int             c, l;
250         const char      *s;
251
252         assert( submatch != NULL );
253         assert( submatch->ls_type == REWRITE_SUBMATCH_ASIS
254                         || submatch->ls_type == REWRITE_SUBMATCH_XMAP );
255         assert( string != NULL );
256         assert( match != NULL );
257         assert( val != NULL );
258         assert( val->bv_val == NULL );
259         
260         c = submatch->ls_submatch;
261         s = string + match[ c ].rm_so;
262         l = match[ c ].rm_eo - match[ c ].rm_so;
263         
264         val->bv_len = l;
265         val->bv_val = malloc( l + 1 );
266         if ( val->bv_val == NULL ) {
267                 return REWRITE_ERR;
268         }
269         
270         AC_MEMCPY( val->bv_val, s, l );
271         val->bv_val[ l ] = '\0';
272         
273         return REWRITE_SUCCESS;
274 }
275
276 /*
277  * Substitutes a portion of rewritten string according to substitution
278  * pattern using submatches
279  */
280 int
281 rewrite_subst_apply(
282                 struct rewrite_info *info,
283                 struct rewrite_op *op,
284                 struct rewrite_subst *subst,
285                 const char *string,
286                 const regmatch_t *match,
287                 struct berval *val
288 )
289 {
290         struct berval *submatch = NULL;
291         char *res = NULL;
292         int n = 0, l, cl;
293         int rc = REWRITE_REGEXEC_OK;
294
295         assert( info != NULL );
296         assert( op != NULL );
297         assert( subst != NULL );
298         assert( string != NULL );
299         assert( match != NULL );
300         assert( val != NULL );
301
302         assert( val->bv_val == NULL );
303
304         val->bv_val = NULL;
305         val->bv_len = 0;
306
307         /*
308          * Prepare room for submatch expansion
309          */
310         if ( subst->lt_num_submatch > 0 ) {
311                 submatch = calloc( sizeof( struct berval ),
312                                 subst->lt_num_submatch );
313                 if ( submatch == NULL ) {
314                         return REWRITE_REGEXEC_ERR;
315                 }
316         }
317         
318         /*
319          * Resolve submatches (simple subst, map expansion and so).
320          */
321         for ( n = 0, l = 0; n < subst->lt_num_submatch; n++ ) {
322                 struct berval   key = { 0, NULL };
323
324                 submatch[ n ].bv_val = NULL;
325                 
326                 /*
327                  * Get key
328                  */
329                 switch ( subst->lt_submatch[ n ].ls_type ) {
330                 case REWRITE_SUBMATCH_ASIS:
331                 case REWRITE_SUBMATCH_XMAP:
332                         rc = submatch_copy( &subst->lt_submatch[ n ],
333                                         string, match, &key );
334                         if ( rc != REWRITE_SUCCESS ) {
335                                 rc = REWRITE_REGEXEC_ERR;
336                                 goto cleanup;
337                         }
338                         break;
339                         
340                 case REWRITE_SUBMATCH_MAP_W_ARG:
341                         switch ( subst->lt_submatch[ n ].ls_map->lm_type ) {
342                         case REWRITE_MAP_GET_OP_VAR:
343                         case REWRITE_MAP_GET_SESN_VAR:
344                         case REWRITE_MAP_GET_PARAM:
345                                 rc = REWRITE_SUCCESS;
346                                 break;
347
348                         default:
349                                 rc = rewrite_subst_apply( info, op, 
350                                         subst->lt_submatch[ n ].ls_map->lm_subst,
351                                         string, match, &key);
352                         }
353                         
354                         if ( rc != REWRITE_SUCCESS ) {
355                                 goto cleanup;
356                         }
357                         break;
358
359                 default:
360                         Debug( LDAP_DEBUG_ANY, "Not Implemented\n", 0, 0, 0 );
361                         rc = REWRITE_ERR;
362                         break;
363                 }
364                 
365                 if ( rc != REWRITE_SUCCESS ) {
366                         rc = REWRITE_REGEXEC_ERR;
367                         goto cleanup;
368                 }
369
370                 /*
371                  * Resolve key
372                  */
373                 switch ( subst->lt_submatch[ n ].ls_type ) {
374                 case REWRITE_SUBMATCH_ASIS:
375                         submatch[ n ] = key;
376                         rc = REWRITE_SUCCESS;
377                         break;
378                         
379                 case REWRITE_SUBMATCH_XMAP:
380                         rc = rewrite_xmap_apply( info, op,
381                                         subst->lt_submatch[ n ].ls_map,
382                                         &key, &submatch[ n ] );
383                         free( key.bv_val );
384                         key.bv_val = NULL;
385                         break;
386                         
387                 case REWRITE_SUBMATCH_MAP_W_ARG:
388                         rc = rewrite_map_apply( info, op,
389                                         subst->lt_submatch[ n ].ls_map,
390                                         &key, &submatch[ n ] );
391                         free( key.bv_val );
392                         key.bv_val = NULL;
393                         break;
394
395                 default:
396                         /*
397                          * When implemented, this might return the
398                          * exit status of a rewrite context,
399                          * which may include a stop, or an
400                          * unwilling to perform
401                          */
402                         rc = REWRITE_ERR;
403                         break;
404                 }
405
406                 if ( rc != REWRITE_SUCCESS ) {
407                         rc = REWRITE_REGEXEC_ERR;
408                         goto cleanup;
409                 }
410                 
411                 /*
412                  * Increment the length of the resulting string
413                  */
414                 l += submatch[ n ].bv_len;
415         }
416         
417         /*
418          * Alloc result buffer
419          */
420         l += subst->lt_subs_len;
421         res = malloc( l + 1 );
422         if ( res == NULL ) {
423                 rc = REWRITE_REGEXEC_ERR;
424                 goto cleanup;
425         }
426
427         /*
428          * Apply submatches (possibly resolved thru maps)
429          */
430         for ( n = 0, cl = 0; n < subst->lt_num_submatch; n++ ) {
431                 if ( subst->lt_subs[ n ].bv_val != NULL ) {
432                         AC_MEMCPY( res + cl, subst->lt_subs[ n ].bv_val,
433                                         subst->lt_subs[ n ].bv_len );
434                         cl += subst->lt_subs[ n ].bv_len;
435                 }
436                 AC_MEMCPY( res + cl, submatch[ n ].bv_val, 
437                                 submatch[ n ].bv_len );
438                 cl += submatch[ n ].bv_len;
439         }
440         if ( subst->lt_subs[ n ].bv_val != NULL ) {
441                 AC_MEMCPY( res + cl, subst->lt_subs[ n ].bv_val,
442                                 subst->lt_subs[ n ].bv_len );
443                 cl += subst->lt_subs[ n ].bv_len;
444         }
445         res[ cl ] = '\0';
446
447         val->bv_val = res;
448         val->bv_len = l;
449
450 cleanup:;
451         if ( submatch ) {
452                 for ( ; --n >= 0; ) {
453                         if ( submatch[ n ].bv_val ) {
454                                 free( submatch[ n ].bv_val );
455                         }
456                 }
457                 free( submatch );
458         }
459
460         return rc;
461 }
462
463 /*
464  * frees data
465  */
466 int
467 rewrite_subst_destroy(
468                 struct rewrite_subst **psubst
469 )
470 {
471         int                     n;
472         struct rewrite_subst    *subst;
473
474         assert( psubst != NULL );
475         assert( *psubst != NULL );
476
477         subst = *psubst;
478
479         for ( n = 0; n < subst->lt_num_submatch; n++ ) {
480                 if ( subst->lt_subs[ n ].bv_val ) {
481                         free( subst->lt_subs[ n ].bv_val );
482                         subst->lt_subs[ n ].bv_val = NULL;
483                 }
484
485                 switch ( subst->lt_submatch[ n ].ls_type ) {
486                 case REWRITE_SUBMATCH_ASIS:
487                         break;
488
489                 case REWRITE_SUBMATCH_XMAP:
490                         rewrite_xmap_destroy( &subst->lt_submatch[ n ].ls_map );
491                         break;
492
493                 case REWRITE_SUBMATCH_MAP_W_ARG:
494                         rewrite_map_destroy( &subst->lt_submatch[ n ].ls_map );
495                         break;
496
497                 default:
498                         break;
499                 }
500         }
501
502         free( subst->lt_submatch );
503         subst->lt_submatch = NULL;
504
505         /* last one */
506         if ( subst->lt_subs[ n ].bv_val ) {
507                 free( subst->lt_subs[ n ].bv_val );
508                 subst->lt_subs[ n ].bv_val = NULL;
509         }
510
511         free( subst->lt_subs );
512         subst->lt_subs = NULL;
513
514         free( subst );
515         *psubst = NULL;
516
517         return 0;
518 }
519