]> git.sur5r.net Git - openldap/blob - libraries/librewrite/subst.c
Plug unlikely memleak (coverity)
[openldap] / libraries / librewrite / subst.c
1 /* $OpenLDAP$ */
2 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
3  *
4  * Copyright 2000-2014 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                                 goto cleanup;
159                         }
160                         submatch = tmpsm;
161                         submatch[ nsub ].ls_type =
162                                 REWRITE_SUBMATCH_MAP_W_ARG;
163                         submatch[ nsub ].ls_map = map;
164
165                 /*
166                  * Escape '%' ...
167                  */
168                 } else if ( p[ 1 ] == '%' ) {
169                         AC_MEMCPY( &p[ 1 ], &p[ 2 ], strlen( &p[ 1 ] ) );
170                         continue;
171
172                 } else {
173                         goto cleanup;
174                 }
175
176                 nsub++;
177         }
178         
179         /*
180          * Last part of string
181          */
182         tmps = (struct berval * )realloc( subs, sizeof( struct berval )*( nsub + 1 ) );
183         if ( tmps == NULL ) {
184                 /*
185                  * XXX need to free the value subst stuff!
186                  */
187                 free( subs );
188                 goto cleanup;
189         }
190         subs = tmps;
191         l = p - begin;
192         if ( l > 0 ) {
193                 subs_len += l;
194                 subs[ nsub ].bv_len = l;
195                 subs[ nsub ].bv_val = malloc( l + 1 );
196                 if ( subs[ nsub ].bv_val == NULL ) {
197                         goto cleanup;
198                 }
199                 AC_MEMCPY( subs[ nsub ].bv_val, begin, l );
200                 subs[ nsub ].bv_val[ l ] = '\0';
201         } else {
202                 subs[ nsub ].bv_val = NULL;
203                 subs[ nsub ].bv_len = 0;
204         }
205
206         s = calloc( sizeof( struct rewrite_subst ), 1 );
207         if ( s == NULL ) {
208                 goto cleanup;
209         }
210
211         s->lt_subs_len = subs_len;
212         s->lt_subs = subs;
213         s->lt_num_submatch = nsub;
214         s->lt_submatch = submatch;
215         subs = NULL;
216         submatch = NULL;
217
218 cleanup:;
219         if ( subs ) {
220                 for ( l=0; l<nsub; l++ ) {
221                         free( subs[nsub].bv_val );
222                 }
223                 free( subs );
224         }
225         if ( submatch ) {
226                 for ( l=0; l<nsub; l++ ) {
227                         free( submatch[nsub].ls_map );
228                 }
229                 free( submatch );
230         }
231         free( result );
232
233         return s;
234 }
235
236 /*
237  * Copies the match referred to by submatch and fetched in string by match.
238  * Helper for rewrite_rule_apply.
239  */
240 static int
241 submatch_copy(
242                 struct rewrite_submatch *submatch,
243                 const char *string,
244                 const regmatch_t *match,
245                 struct berval *val
246 )
247 {
248         int             c, l;
249         const char      *s;
250
251         assert( submatch != NULL );
252         assert( submatch->ls_type == REWRITE_SUBMATCH_ASIS
253                         || submatch->ls_type == REWRITE_SUBMATCH_XMAP );
254         assert( string != NULL );
255         assert( match != NULL );
256         assert( val != NULL );
257         assert( val->bv_val == NULL );
258         
259         c = submatch->ls_submatch;
260         s = string + match[ c ].rm_so;
261         l = match[ c ].rm_eo - match[ c ].rm_so;
262         
263         val->bv_len = l;
264         val->bv_val = malloc( l + 1 );
265         if ( val->bv_val == NULL ) {
266                 return REWRITE_ERR;
267         }
268         
269         AC_MEMCPY( val->bv_val, s, l );
270         val->bv_val[ l ] = '\0';
271         
272         return REWRITE_SUCCESS;
273 }
274
275 /*
276  * Substitutes a portion of rewritten string according to substitution
277  * pattern using submatches
278  */
279 int
280 rewrite_subst_apply(
281                 struct rewrite_info *info,
282                 struct rewrite_op *op,
283                 struct rewrite_subst *subst,
284                 const char *string,
285                 const regmatch_t *match,
286                 struct berval *val
287 )
288 {
289         struct berval *submatch = NULL;
290         char *res = NULL;
291         int n = 0, l, cl;
292         int rc = REWRITE_REGEXEC_OK;
293
294         assert( info != NULL );
295         assert( op != NULL );
296         assert( subst != NULL );
297         assert( string != NULL );
298         assert( match != NULL );
299         assert( val != NULL );
300
301         assert( val->bv_val == NULL );
302
303         val->bv_val = NULL;
304         val->bv_len = 0;
305
306         /*
307          * Prepare room for submatch expansion
308          */
309         if ( subst->lt_num_submatch > 0 ) {
310                 submatch = calloc( sizeof( struct berval ),
311                                 subst->lt_num_submatch );
312                 if ( submatch == NULL ) {
313                         return REWRITE_REGEXEC_ERR;
314                 }
315         }
316         
317         /*
318          * Resolve submatches (simple subst, map expansion and so).
319          */
320         for ( n = 0, l = 0; n < subst->lt_num_submatch; n++ ) {
321                 struct berval   key = { 0, NULL };
322
323                 submatch[ n ].bv_val = NULL;
324                 
325                 /*
326                  * Get key
327                  */
328                 switch ( subst->lt_submatch[ n ].ls_type ) {
329                 case REWRITE_SUBMATCH_ASIS:
330                 case REWRITE_SUBMATCH_XMAP:
331                         rc = submatch_copy( &subst->lt_submatch[ n ],
332                                         string, match, &key );
333                         if ( rc != REWRITE_SUCCESS ) {
334                                 rc = REWRITE_REGEXEC_ERR;
335                                 goto cleanup;
336                         }
337                         break;
338                         
339                 case REWRITE_SUBMATCH_MAP_W_ARG:
340                         switch ( subst->lt_submatch[ n ].ls_map->lm_type ) {
341                         case REWRITE_MAP_GET_OP_VAR:
342                         case REWRITE_MAP_GET_SESN_VAR:
343                         case REWRITE_MAP_GET_PARAM:
344                                 rc = REWRITE_SUCCESS;
345                                 break;
346
347                         default:
348                                 rc = rewrite_subst_apply( info, op, 
349                                         subst->lt_submatch[ n ].ls_map->lm_subst,
350                                         string, match, &key);
351                         }
352                         
353                         if ( rc != REWRITE_SUCCESS ) {
354                                 goto cleanup;
355                         }
356                         break;
357
358                 default:
359                         Debug( LDAP_DEBUG_ANY, "Not Implemented\n", 0, 0, 0 );
360                         rc = REWRITE_ERR;
361                         break;
362                 }
363                 
364                 if ( rc != REWRITE_SUCCESS ) {
365                         rc = REWRITE_REGEXEC_ERR;
366                         goto cleanup;
367                 }
368
369                 /*
370                  * Resolve key
371                  */
372                 switch ( subst->lt_submatch[ n ].ls_type ) {
373                 case REWRITE_SUBMATCH_ASIS:
374                         submatch[ n ] = key;
375                         rc = REWRITE_SUCCESS;
376                         break;
377                         
378                 case REWRITE_SUBMATCH_XMAP:
379                         rc = rewrite_xmap_apply( info, op,
380                                         subst->lt_submatch[ n ].ls_map,
381                                         &key, &submatch[ n ] );
382                         free( key.bv_val );
383                         key.bv_val = NULL;
384                         break;
385                         
386                 case REWRITE_SUBMATCH_MAP_W_ARG:
387                         rc = rewrite_map_apply( info, op,
388                                         subst->lt_submatch[ n ].ls_map,
389                                         &key, &submatch[ n ] );
390                         free( key.bv_val );
391                         key.bv_val = NULL;
392                         break;
393
394                 default:
395                         /*
396                          * When implemented, this might return the
397                          * exit status of a rewrite context,
398                          * which may include a stop, or an
399                          * unwilling to perform
400                          */
401                         rc = REWRITE_ERR;
402                         break;
403                 }
404
405                 if ( rc != REWRITE_SUCCESS ) {
406                         rc = REWRITE_REGEXEC_ERR;
407                         goto cleanup;
408                 }
409                 
410                 /*
411                  * Increment the length of the resulting string
412                  */
413                 l += submatch[ n ].bv_len;
414         }
415         
416         /*
417          * Alloc result buffer
418          */
419         l += subst->lt_subs_len;
420         res = malloc( l + 1 );
421         if ( res == NULL ) {
422                 rc = REWRITE_REGEXEC_ERR;
423                 goto cleanup;
424         }
425
426         /*
427          * Apply submatches (possibly resolved thru maps)
428          */
429         for ( n = 0, cl = 0; n < subst->lt_num_submatch; n++ ) {
430                 if ( subst->lt_subs[ n ].bv_val != NULL ) {
431                         AC_MEMCPY( res + cl, subst->lt_subs[ n ].bv_val,
432                                         subst->lt_subs[ n ].bv_len );
433                         cl += subst->lt_subs[ n ].bv_len;
434                 }
435                 AC_MEMCPY( res + cl, submatch[ n ].bv_val, 
436                                 submatch[ n ].bv_len );
437                 cl += submatch[ n ].bv_len;
438         }
439         if ( subst->lt_subs[ n ].bv_val != NULL ) {
440                 AC_MEMCPY( res + cl, subst->lt_subs[ n ].bv_val,
441                                 subst->lt_subs[ n ].bv_len );
442                 cl += subst->lt_subs[ n ].bv_len;
443         }
444         res[ cl ] = '\0';
445
446         val->bv_val = res;
447         val->bv_len = l;
448
449 cleanup:;
450         if ( submatch ) {
451                 for ( ; --n >= 0; ) {
452                         if ( submatch[ n ].bv_val ) {
453                                 free( submatch[ n ].bv_val );
454                         }
455                 }
456                 free( submatch );
457         }
458
459         return rc;
460 }
461
462 /*
463  * frees data
464  */
465 int
466 rewrite_subst_destroy(
467                 struct rewrite_subst **psubst
468 )
469 {
470         int                     n;
471         struct rewrite_subst    *subst;
472
473         assert( psubst != NULL );
474         assert( *psubst != NULL );
475
476         subst = *psubst;
477
478         for ( n = 0; n < subst->lt_num_submatch; n++ ) {
479                 if ( subst->lt_subs[ n ].bv_val ) {
480                         free( subst->lt_subs[ n ].bv_val );
481                         subst->lt_subs[ n ].bv_val = NULL;
482                 }
483
484                 switch ( subst->lt_submatch[ n ].ls_type ) {
485                 case REWRITE_SUBMATCH_ASIS:
486                         break;
487
488                 case REWRITE_SUBMATCH_XMAP:
489                         rewrite_xmap_destroy( &subst->lt_submatch[ n ].ls_map );
490                         break;
491
492                 case REWRITE_SUBMATCH_MAP_W_ARG:
493                         rewrite_map_destroy( &subst->lt_submatch[ n ].ls_map );
494                         break;
495
496                 default:
497                         break;
498                 }
499         }
500
501         free( subst->lt_submatch );
502         subst->lt_submatch = NULL;
503
504         /* last one */
505         if ( subst->lt_subs[ n ].bv_val ) {
506                 free( subst->lt_subs[ n ].bv_val );
507                 subst->lt_subs[ n ].bv_val = NULL;
508         }
509
510         free( subst->lt_subs );
511         subst->lt_subs = NULL;
512
513         free( subst );
514         *psubst = NULL;
515
516         return 0;
517 }
518