Back to index

openldap  2.4.31
subst.c
Go to the documentation of this file.
00001 /* $OpenLDAP$ */
00002 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
00003  *
00004  * Copyright 2000-2012 The OpenLDAP Foundation.
00005  * All rights reserved.
00006  *
00007  * Redistribution and use in source and binary forms, with or without
00008  * modification, are permitted only as authorized by the OpenLDAP
00009  * Public License.
00010  *
00011  * A copy of this license is available in the file LICENSE in the
00012  * top-level directory of the distribution or, alternatively, at
00013  * <http://www.OpenLDAP.org/license.html>.
00014  */
00015 /* ACKNOWLEDGEMENT:
00016  * This work was initially developed by Pierangelo Masarati for
00017  * inclusion in OpenLDAP Software.
00018  */
00019 
00020 #include <portable.h>
00021 
00022 #include "rewrite-int.h"
00023 
00024 /*
00025  * Compiles a substitution pattern
00026  */
00027 struct rewrite_subst *
00028 rewrite_subst_compile(
00029               struct rewrite_info *info,
00030               const char *str
00031 )
00032 {
00033        size_t subs_len;
00034        struct berval *subs = NULL, *tmps;
00035        struct rewrite_submatch *submatch = NULL;
00036 
00037        struct rewrite_subst *s = NULL;
00038 
00039        char *result, *begin, *p;
00040        int nsub = 0, l;
00041 
00042        assert( info != NULL );
00043        assert( str != NULL );
00044 
00045        result = strdup( str );
00046        if ( result == NULL ) {
00047               return NULL;
00048        }
00049 
00050        /*
00051         * Take care of substitution string
00052         */
00053        for ( p = begin = result, subs_len = 0; p[ 0 ] != '\0'; p++ ) {
00054 
00055               /*
00056                * Keep only single escapes '%'
00057                */
00058               if (  !IS_REWRITE_SUBMATCH_ESCAPE( p[ 0 ] ) ) {
00059                      continue;
00060               } 
00061 
00062               if (  IS_REWRITE_SUBMATCH_ESCAPE( p[ 1 ] ) ) {
00063                      /* Pull &p[1] over p, including the trailing '\0' */
00064                      AC_MEMCPY((char *)p, &p[ 1 ], strlen( p ) );
00065                      continue;
00066               }
00067 
00068               tmps = ( struct berval * )realloc( subs,
00069                             sizeof( struct berval )*( nsub + 1 ) );
00070               if ( tmps == NULL ) {
00071                      goto cleanup;
00072               }
00073               subs = tmps;
00074               
00075               /*
00076                * I think an `if l > 0' at runtime is better outside than
00077                * inside a function call ...
00078                */
00079               l = p - begin;
00080               if ( l > 0 ) {
00081                      subs_len += l;
00082                      subs[ nsub ].bv_len = l;
00083                      subs[ nsub ].bv_val = malloc( l + 1 );
00084                      if ( subs[ nsub ].bv_val == NULL ) {
00085                             goto cleanup;
00086                      }
00087                      AC_MEMCPY( subs[ nsub ].bv_val, begin, l );
00088                      subs[ nsub ].bv_val[ l ] = '\0';
00089               } else {
00090                      subs[ nsub ].bv_val = NULL;
00091                      subs[ nsub ].bv_len = 0;
00092               }
00093               
00094               /*
00095                * Substitution pattern
00096                */
00097               if ( isdigit( (unsigned char) p[ 1 ] ) ) {
00098                      struct rewrite_submatch *tmpsm;
00099                      int d = p[ 1 ] - '0';
00100 
00101                      /*
00102                       * Add a new value substitution scheme
00103                       */
00104 
00105                      tmpsm = ( struct rewrite_submatch * )realloc( submatch,
00106                                    sizeof( struct rewrite_submatch )*( nsub + 1 ) );
00107                      if ( tmpsm == NULL ) {
00108                             goto cleanup;
00109                      }
00110                      submatch = tmpsm;
00111                      submatch[ nsub ].ls_submatch = d;
00112 
00113                      /*
00114                       * If there is no argument, use default
00115                       * (substitute substring as is)
00116                       */
00117                      if ( p[ 2 ] != '{' ) {
00118                             submatch[ nsub ].ls_type = 
00119                                    REWRITE_SUBMATCH_ASIS;
00120                             submatch[ nsub ].ls_map = NULL;
00121                             begin = ++p + 1;
00122 
00123                      } else {
00124                             struct rewrite_map *map;
00125 
00126                             submatch[ nsub ].ls_type =
00127                                    REWRITE_SUBMATCH_XMAP;
00128 
00129                             map = rewrite_xmap_parse( info,
00130                                           p + 3, (const char **)&begin );
00131                             if ( map == NULL ) {
00132                                    goto cleanup;
00133                             }
00134                             submatch[ nsub ].ls_map = map;
00135                             p = begin - 1;
00136                      }
00137 
00138               /*
00139                * Map with args ...
00140                */
00141               } else if ( p[ 1 ] == '{' ) {
00142                      struct rewrite_map *map;
00143                      struct rewrite_submatch *tmpsm;
00144 
00145                      map = rewrite_map_parse( info, p + 2,
00146                                    (const char **)&begin );
00147                      if ( map == NULL ) {
00148                             goto cleanup;
00149                      }
00150                      p = begin - 1;
00151 
00152                      /*
00153                       * Add a new value substitution scheme
00154                       */
00155                      tmpsm = ( struct rewrite_submatch * )realloc( submatch,
00156                                    sizeof( struct rewrite_submatch )*( nsub + 1 ) );
00157                      if ( tmpsm == NULL ) {
00158                             goto cleanup;
00159                      }
00160                      submatch = tmpsm;
00161                      submatch[ nsub ].ls_type =
00162                             REWRITE_SUBMATCH_MAP_W_ARG;
00163                      submatch[ nsub ].ls_map = map;
00164 
00165               /*
00166                * Escape '%' ...
00167                */
00168               } else if ( p[ 1 ] == '%' ) {
00169                      AC_MEMCPY( &p[ 1 ], &p[ 2 ], strlen( &p[ 1 ] ) );
00170                      continue;
00171 
00172               } else {
00173                      goto cleanup;
00174               }
00175 
00176               nsub++;
00177        }
00178        
00179        /*
00180         * Last part of string
00181         */
00182        tmps = (struct berval * )realloc( subs, sizeof( struct berval )*( nsub + 1 ) );
00183        if ( tmps == NULL ) {
00184               /*
00185                * XXX need to free the value subst stuff!
00186                */
00187               free( subs );
00188               goto cleanup;
00189        }
00190        subs = tmps;
00191        l = p - begin;
00192        if ( l > 0 ) {
00193               subs_len += l;
00194               subs[ nsub ].bv_len = l;
00195               subs[ nsub ].bv_val = malloc( l + 1 );
00196               if ( subs[ nsub ].bv_val == NULL ) {
00197                      free( subs );
00198                      goto cleanup;
00199               }
00200               AC_MEMCPY( subs[ nsub ].bv_val, begin, l );
00201               subs[ nsub ].bv_val[ l ] = '\0';
00202        } else {
00203               subs[ nsub ].bv_val = NULL;
00204               subs[ nsub ].bv_len = 0;
00205        }
00206 
00207        s = calloc( sizeof( struct rewrite_subst ), 1 );
00208        if ( s == NULL ) {
00209               goto cleanup;
00210        }
00211 
00212        s->lt_subs_len = subs_len;
00213         s->lt_subs = subs;
00214         s->lt_num_submatch = nsub;
00215         s->lt_submatch = submatch;
00216 
00217 cleanup:;
00218        free( result );
00219 
00220        return s;
00221 }
00222 
00223 /*
00224  * Copies the match referred to by submatch and fetched in string by match.
00225  * Helper for rewrite_rule_apply.
00226  */
00227 static int
00228 submatch_copy(
00229               struct rewrite_submatch *submatch,
00230               const char *string,
00231               const regmatch_t *match,
00232               struct berval *val
00233 )
00234 {
00235        int           c, l;
00236        const char    *s;
00237 
00238        assert( submatch != NULL );
00239        assert( submatch->ls_type == REWRITE_SUBMATCH_ASIS
00240                      || submatch->ls_type == REWRITE_SUBMATCH_XMAP );
00241        assert( string != NULL );
00242        assert( match != NULL );
00243        assert( val != NULL );
00244        assert( val->bv_val == NULL );
00245        
00246        c = submatch->ls_submatch;
00247        s = string + match[ c ].rm_so;
00248        l = match[ c ].rm_eo - match[ c ].rm_so;
00249        
00250        val->bv_len = l;
00251        val->bv_val = malloc( l + 1 );
00252        if ( val->bv_val == NULL ) {
00253               return REWRITE_ERR;
00254        }
00255        
00256        AC_MEMCPY( val->bv_val, s, l );
00257        val->bv_val[ l ] = '\0';
00258        
00259        return REWRITE_SUCCESS;
00260 }
00261 
00262 /*
00263  * Substitutes a portion of rewritten string according to substitution
00264  * pattern using submatches
00265  */
00266 int
00267 rewrite_subst_apply(
00268               struct rewrite_info *info,
00269               struct rewrite_op *op,
00270               struct rewrite_subst *subst,
00271               const char *string,
00272               const regmatch_t *match,
00273               struct berval *val
00274 )
00275 {
00276        struct berval *submatch = NULL;
00277        char *res = NULL;
00278        int n = 0, l, cl;
00279        int rc = REWRITE_REGEXEC_OK;
00280 
00281        assert( info != NULL );
00282        assert( op != NULL );
00283        assert( subst != NULL );
00284        assert( string != NULL );
00285        assert( match != NULL );
00286        assert( val != NULL );
00287 
00288        assert( val->bv_val == NULL );
00289 
00290        val->bv_val = NULL;
00291        val->bv_len = 0;
00292 
00293        /*
00294         * Prepare room for submatch expansion
00295         */
00296        if ( subst->lt_num_submatch > 0 ) {
00297               submatch = calloc( sizeof( struct berval ),
00298                             subst->lt_num_submatch );
00299               if ( submatch == NULL ) {
00300                      return REWRITE_REGEXEC_ERR;
00301               }
00302        }
00303        
00304        /*
00305         * Resolve submatches (simple subst, map expansion and so).
00306         */
00307        for ( n = 0, l = 0; n < subst->lt_num_submatch; n++ ) {
00308               struct berval key = { 0, NULL };
00309 
00310               submatch[ n ].bv_val = NULL;
00311               
00312               /*
00313                * Get key
00314                */
00315               switch ( subst->lt_submatch[ n ].ls_type ) {
00316               case REWRITE_SUBMATCH_ASIS:
00317               case REWRITE_SUBMATCH_XMAP:
00318                      rc = submatch_copy( &subst->lt_submatch[ n ],
00319                                    string, match, &key );
00320                      if ( rc != REWRITE_SUCCESS ) {
00321                             rc = REWRITE_REGEXEC_ERR;
00322                             goto cleanup;
00323                      }
00324                      break;
00325                      
00326               case REWRITE_SUBMATCH_MAP_W_ARG:
00327                      switch ( subst->lt_submatch[ n ].ls_map->lm_type ) {
00328                      case REWRITE_MAP_GET_OP_VAR:
00329                      case REWRITE_MAP_GET_SESN_VAR:
00330                      case REWRITE_MAP_GET_PARAM:
00331                             rc = REWRITE_SUCCESS;
00332                             break;
00333 
00334                      default:
00335                             rc = rewrite_subst_apply( info, op, 
00336                                    subst->lt_submatch[ n ].ls_map->lm_subst,
00337                                    string, match, &key);
00338                      }
00339                      
00340                      if ( rc != REWRITE_SUCCESS ) {
00341                             goto cleanup;
00342                      }
00343                      break;
00344 
00345               default:
00346                      Debug( LDAP_DEBUG_ANY, "Not Implemented\n", 0, 0, 0 );
00347                      rc = REWRITE_ERR;
00348                      break;
00349               }
00350               
00351               if ( rc != REWRITE_SUCCESS ) {
00352                      rc = REWRITE_REGEXEC_ERR;
00353                      goto cleanup;
00354               }
00355 
00356               /*
00357                * Resolve key
00358                */
00359               switch ( subst->lt_submatch[ n ].ls_type ) {
00360               case REWRITE_SUBMATCH_ASIS:
00361                      submatch[ n ] = key;
00362                      rc = REWRITE_SUCCESS;
00363                      break;
00364                      
00365               case REWRITE_SUBMATCH_XMAP:
00366                      rc = rewrite_xmap_apply( info, op,
00367                                    subst->lt_submatch[ n ].ls_map,
00368                                    &key, &submatch[ n ] );
00369                      free( key.bv_val );
00370                      key.bv_val = NULL;
00371                      break;
00372                      
00373               case REWRITE_SUBMATCH_MAP_W_ARG:
00374                      rc = rewrite_map_apply( info, op,
00375                                    subst->lt_submatch[ n ].ls_map,
00376                                    &key, &submatch[ n ] );
00377                      free( key.bv_val );
00378                      key.bv_val = NULL;
00379                      break;
00380 
00381               default:
00382                      /*
00383                       * When implemented, this might return the
00384                          * exit status of a rewrite context,
00385                          * which may include a stop, or an
00386                          * unwilling to perform
00387                          */
00388                      rc = REWRITE_ERR;
00389                      break;
00390               }
00391 
00392               if ( rc != REWRITE_SUCCESS ) {
00393                      rc = REWRITE_REGEXEC_ERR;
00394                      goto cleanup;
00395               }
00396               
00397               /*
00398                  * Increment the length of the resulting string
00399                  */
00400               l += submatch[ n ].bv_len;
00401        }
00402        
00403        /*
00404          * Alloc result buffer
00405          */
00406        l += subst->lt_subs_len;
00407        res = malloc( l + 1 );
00408        if ( res == NULL ) {
00409               rc = REWRITE_REGEXEC_ERR;
00410               goto cleanup;
00411        }
00412 
00413        /*
00414         * Apply submatches (possibly resolved thru maps)
00415         */
00416         for ( n = 0, cl = 0; n < subst->lt_num_submatch; n++ ) {
00417               if ( subst->lt_subs[ n ].bv_val != NULL ) {
00418                      AC_MEMCPY( res + cl, subst->lt_subs[ n ].bv_val,
00419                                    subst->lt_subs[ n ].bv_len );
00420                      cl += subst->lt_subs[ n ].bv_len;
00421               }
00422               AC_MEMCPY( res + cl, submatch[ n ].bv_val, 
00423                             submatch[ n ].bv_len );
00424               cl += submatch[ n ].bv_len;
00425        }
00426        if ( subst->lt_subs[ n ].bv_val != NULL ) {
00427               AC_MEMCPY( res + cl, subst->lt_subs[ n ].bv_val,
00428                             subst->lt_subs[ n ].bv_len );
00429               cl += subst->lt_subs[ n ].bv_len;
00430        }
00431        res[ cl ] = '\0';
00432 
00433        val->bv_val = res;
00434        val->bv_len = l;
00435 
00436 cleanup:;
00437        if ( submatch ) {
00438               for ( ; --n >= 0; ) {
00439                      if ( submatch[ n ].bv_val ) {
00440                             free( submatch[ n ].bv_val );
00441                      }
00442               }
00443               free( submatch );
00444        }
00445 
00446        return rc;
00447 }
00448 
00449 /*
00450  * frees data
00451  */
00452 int
00453 rewrite_subst_destroy(
00454               struct rewrite_subst **psubst
00455 )
00456 {
00457        int                  n;
00458        struct rewrite_subst *subst;
00459 
00460        assert( psubst != NULL );
00461        assert( *psubst != NULL );
00462 
00463        subst = *psubst;
00464 
00465        for ( n = 0; n < subst->lt_num_submatch; n++ ) {
00466               if ( subst->lt_subs[ n ].bv_val ) {
00467                      free( subst->lt_subs[ n ].bv_val );
00468                      subst->lt_subs[ n ].bv_val = NULL;
00469               }
00470 
00471               switch ( subst->lt_submatch[ n ].ls_type ) {
00472               case REWRITE_SUBMATCH_ASIS:
00473                      break;
00474 
00475               case REWRITE_SUBMATCH_XMAP:
00476                      rewrite_xmap_destroy( &subst->lt_submatch[ n ].ls_map );
00477                      break;
00478 
00479               case REWRITE_SUBMATCH_MAP_W_ARG:
00480                      rewrite_map_destroy( &subst->lt_submatch[ n ].ls_map );
00481                      break;
00482 
00483               default:
00484                      break;
00485               }
00486        }
00487 
00488        free( subst->lt_submatch );
00489        subst->lt_submatch = NULL;
00490 
00491        /* last one */
00492        if ( subst->lt_subs[ n ].bv_val ) {
00493               free( subst->lt_subs[ n ].bv_val );
00494               subst->lt_subs[ n ].bv_val = NULL;
00495        }
00496 
00497        free( subst->lt_subs );
00498        subst->lt_subs = NULL;
00499 
00500        free( subst );
00501        *psubst = NULL;
00502 
00503        return 0;
00504 }
00505