Back to index

openldap  2.4.31
rule.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  * Appends a rule to the double linked list of rules
00026  * Helper for rewrite_rule_compile
00027  */
00028 static int
00029 append_rule(
00030               struct rewrite_context *context,
00031               struct rewrite_rule *rule
00032 )
00033 {
00034        struct rewrite_rule *r;
00035 
00036        assert( context != NULL );
00037        assert( context->lc_rule != NULL );
00038        assert( rule != NULL );
00039 
00040        for ( r = context->lc_rule; r->lr_next != NULL; r = r->lr_next );
00041        r->lr_next = rule;
00042        rule->lr_prev = r;
00043        
00044        return REWRITE_SUCCESS;
00045 }
00046 
00047 /*
00048  * Appends an action to the linked list of actions
00049  * Helper for rewrite_rule_compile
00050  */
00051 static int
00052 append_action(
00053               struct rewrite_action **pbase,
00054               struct rewrite_action *action
00055 )
00056 {
00057        struct rewrite_action **pa;
00058 
00059        assert( pbase != NULL );
00060        assert( action != NULL );
00061        
00062        for ( pa = pbase; *pa != NULL; pa = &(*pa)->la_next );
00063        *pa = action;
00064        
00065        return REWRITE_SUCCESS;
00066 }
00067 
00068 static int
00069 destroy_action(
00070               struct rewrite_action **paction
00071 )
00072 {
00073        struct rewrite_action       *action;
00074 
00075        assert( paction != NULL );
00076        assert( *paction != NULL );
00077 
00078        action = *paction;
00079 
00080        /* do something */
00081        switch ( action->la_type ) {
00082        case REWRITE_FLAG_GOTO:
00083        case REWRITE_FLAG_USER: {
00084               int *pi = (int *)action->la_args;
00085 
00086               if ( pi ) {
00087                      free( pi );
00088               }
00089               break;
00090        }
00091 
00092        default:
00093               break;
00094        }
00095        
00096        free( action );
00097        *paction = NULL;
00098        
00099        return 0;
00100 }
00101 
00102 static void
00103 destroy_actions(
00104        struct rewrite_action *paction
00105 )
00106 {
00107        struct rewrite_action *next;
00108 
00109        for (; paction; paction = next) {
00110               next = paction->la_next;
00111               destroy_action( &paction );
00112        }
00113 }
00114 
00115 /*
00116  */
00117 int
00118 rewrite_rule_compile(
00119               struct rewrite_info *info,
00120               struct rewrite_context *context,
00121               const char *pattern,
00122               const char *result,
00123               const char *flagstring
00124 )
00125 {
00126        int flags = REWRITE_REGEX_EXTENDED | REWRITE_REGEX_ICASE;
00127        int mode = REWRITE_RECURSE;
00128        int max_passes;
00129 
00130        struct rewrite_rule *rule = NULL;
00131        struct rewrite_subst *subst = NULL;
00132        struct rewrite_action *action = NULL, *first_action = NULL;
00133 
00134        const char *p;
00135 
00136        assert( info != NULL );
00137        assert( context != NULL );
00138        assert( pattern != NULL );
00139        assert( result != NULL );
00140        /*
00141         * A null flagstring should be allowed
00142         */
00143 
00144        max_passes = info->li_max_passes_per_rule;
00145 
00146        /*
00147         * Take care of substitution string
00148         */
00149        subst = rewrite_subst_compile( info, result );
00150        if ( subst == NULL ) {
00151               return REWRITE_ERR;
00152        }
00153 
00154        /*
00155         * Take care of flags
00156         */
00157        for ( p = flagstring; p[ 0 ] != '\0'; p++ ) {
00158               switch( p[ 0 ] ) {
00159                      
00160               /*
00161                * REGEX flags
00162                */
00163               case REWRITE_FLAG_HONORCASE:              /* 'C' */
00164                      /*
00165                       * Honor case (default is case insensitive)
00166                       */
00167                      flags &= ~REWRITE_REGEX_ICASE;
00168                      break;
00169                      
00170               case REWRITE_FLAG_BASICREGEX:             /* 'R' */
00171                      /*
00172                       * Use POSIX Basic Regular Expression syntax
00173                       * instead of POSIX Extended Regular Expression 
00174                       * syntax (default)
00175                       */
00176                      flags &= ~REWRITE_REGEX_EXTENDED;
00177                      break;
00178                      
00179               /*
00180                * Execution mode flags
00181                */
00182               case REWRITE_FLAG_EXECONCE:               /* ':' */
00183                      /*
00184                       * Apply rule once only
00185                       */
00186                      mode &= ~REWRITE_RECURSE;
00187                      mode |= REWRITE_EXEC_ONCE;
00188                      break;
00189               
00190               /*
00191                * Special action flags
00192                */
00193               case REWRITE_FLAG_STOP:                   /* '@' */
00194                      /*
00195                       * Bail out after applying rule
00196                       */
00197                      action = calloc( sizeof( struct rewrite_action ), 1 );
00198                      if ( action == NULL ) {
00199                             goto fail;
00200                      }
00201 
00202                      action->la_type = REWRITE_ACTION_STOP;
00203                      break;
00204                      
00205               case REWRITE_FLAG_UNWILLING:              /* '#' */
00206                      /*
00207                       * Matching objs will be marked as gone!
00208                       */
00209                      action = calloc( sizeof( struct rewrite_action ), 1 );
00210                      if ( action == NULL ) {
00211                             goto fail;
00212                      }
00213                      
00214                      mode &= ~REWRITE_RECURSE;
00215                      mode |= REWRITE_EXEC_ONCE;
00216                      action->la_type = REWRITE_ACTION_UNWILLING;
00217                      break;
00218 
00219               case REWRITE_FLAG_GOTO:                          /* 'G' */
00220                      /*
00221                       * After applying rule, jump N rules
00222                       */
00223 
00224               case REWRITE_FLAG_USER: {                 /* 'U' */
00225                      /*
00226                       * After applying rule, return user-defined
00227                       * error code
00228                       */
00229                      char *next = NULL;
00230                      int *d;
00231                      
00232                      if ( p[ 1 ] != '{' ) {
00233                             goto fail;
00234                      }
00235 
00236                      d = malloc( sizeof( int ) );
00237                      if ( d == NULL ) {
00238                             goto fail;
00239                      }
00240 
00241                      d[ 0 ] = strtol( &p[ 2 ], &next, 0 );
00242                      if ( next == &p[ 2 ] || next[0] != '}' ) {
00243                             free( d );
00244                             goto fail;
00245                      }
00246 
00247                      action = calloc( sizeof( struct rewrite_action ), 1 );
00248                      if ( action == NULL ) {
00249                             free( d );
00250                             goto fail;
00251                      }
00252                      switch ( p[ 0 ] ) {
00253                      case REWRITE_FLAG_GOTO:
00254                             action->la_type = REWRITE_ACTION_GOTO;
00255                             break;
00256 
00257                      case REWRITE_FLAG_USER:
00258                             action->la_type = REWRITE_ACTION_USER;
00259                             break;
00260 
00261                      default:
00262                             assert(0);
00263                      }
00264 
00265                      action->la_args = (void *)d;
00266 
00267                      p = next;     /* p is incremented by the for ... */
00268               
00269                      break;
00270               }
00271 
00272               case REWRITE_FLAG_MAX_PASSES: {                  /* 'U' */
00273                      /*
00274                       * Set the number of max passes per rule
00275                       */
00276                      char *next = NULL;
00277                      
00278                      if ( p[ 1 ] != '{' ) {
00279                             goto fail;
00280                      }
00281 
00282                      max_passes = strtol( &p[ 2 ], &next, 0 );
00283                      if ( next == &p[ 2 ] || next[0] != '}' ) {
00284                             goto fail;
00285                      }
00286 
00287                      if ( max_passes < 1 ) {
00288                             /* FIXME: nonsense ... */
00289                             max_passes = 1;
00290                      }
00291 
00292                      p = next;     /* p is incremented by the for ... */
00293               
00294                      break;
00295               }
00296 
00297               case REWRITE_FLAG_IGNORE_ERR:               /* 'I' */
00298                      /*
00299                       * Ignore errors!
00300                       */
00301                      action = calloc( sizeof( struct rewrite_action ), 1 );
00302                      if ( action == NULL ) {
00303                             goto fail;
00304                      }
00305                      
00306                      action->la_type = REWRITE_ACTION_IGNORE_ERR;
00307                      break;
00308                      
00309               /*
00310                * Other flags ...
00311                */
00312               default:
00313                      /*
00314                       * Unimplemented feature (complain only)
00315                       */
00316                      break;
00317               }
00318               
00319               /*
00320                * Stupid way to append to a list ...
00321                */
00322               if ( action != NULL ) {
00323                      append_action( &first_action, action );
00324                      action = NULL;
00325               }
00326        }
00327        
00328        /*
00329         * Finally, rule allocation
00330         */
00331        rule = calloc( sizeof( struct rewrite_rule ), 1 );
00332        if ( rule == NULL ) {
00333               goto fail;
00334        }
00335        
00336        /*
00337         * REGEX compilation (luckily I don't need to take care of this ...)
00338         */
00339        if ( regcomp( &rule->lr_regex, ( char * )pattern, flags ) != 0 ) {
00340               goto fail;
00341        }
00342        
00343        /*
00344         * Just to remember them ...
00345         */
00346        rule->lr_pattern = strdup( pattern );
00347        rule->lr_subststring = strdup( result );
00348        rule->lr_flagstring = strdup( flagstring );
00349        if ( rule->lr_pattern == NULL
00350               || rule->lr_subststring == NULL
00351               || rule->lr_flagstring == NULL )
00352        {
00353               goto fail;
00354        }
00355        
00356        /*
00357         * Load compiled data into rule
00358         */
00359        rule->lr_subst = subst;
00360 
00361        /*
00362         * Set various parameters
00363         */
00364        rule->lr_flags = flags;            /* don't really need any longer ... */
00365        rule->lr_mode = mode;
00366        rule->lr_max_passes = max_passes;
00367        rule->lr_action = first_action;
00368        
00369        /*
00370         * Append rule at the end of the rewrite context
00371         */
00372        append_rule( context, rule );
00373 
00374        return REWRITE_SUCCESS;
00375 
00376 fail:
00377        if ( rule ) {
00378               if ( rule->lr_pattern ) free( rule->lr_pattern );
00379               if ( rule->lr_subststring ) free( rule->lr_subststring );
00380               if ( rule->lr_flagstring ) free( rule->lr_flagstring );
00381               free( rule );
00382        }
00383        destroy_actions( first_action );
00384        free( subst );
00385        return REWRITE_ERR;
00386 }
00387 
00388 /*
00389  * Rewrites string according to rule; may return:
00390  *      OK:     fine; if *result != NULL rule matched and rewrite succeeded.
00391  *      STOP:   fine, rule matched; stop processing following rules
00392  *      UNWILL: rule matched; force 'unwilling to perform'
00393  */
00394 int
00395 rewrite_rule_apply(
00396               struct rewrite_info *info,
00397               struct rewrite_op *op,
00398               struct rewrite_rule *rule,
00399               const char *arg,
00400               char **result
00401               )
00402 {
00403        size_t nmatch = REWRITE_MAX_MATCH;
00404        regmatch_t match[ REWRITE_MAX_MATCH ];
00405 
00406        int rc = REWRITE_SUCCESS;
00407 
00408        char *string;
00409        int strcnt = 0;
00410        struct berval val = { 0, NULL };
00411 
00412        assert( info != NULL );
00413        assert( op != NULL );
00414        assert( rule != NULL );
00415        assert( arg != NULL );
00416        assert( result != NULL );
00417 
00418        *result = NULL;
00419 
00420        string = (char *)arg;
00421        
00422        /*
00423         * In case recursive match is required (default)
00424         */
00425 recurse:;
00426 
00427        Debug( LDAP_DEBUG_TRACE, "==> rewrite_rule_apply"
00428                      " rule='%s' string='%s' [%d pass(es)]\n", 
00429                      rule->lr_pattern, string, strcnt + 1 );
00430        
00431        op->lo_num_passes++;
00432 
00433        rc = regexec( &rule->lr_regex, string, nmatch, match, 0 );
00434        if ( rc != 0 ) {
00435               if ( *result == NULL && string != arg ) {
00436                      free( string );
00437               }
00438 
00439               /*
00440                * No match is OK; *result = NULL means no match
00441                */
00442               return REWRITE_REGEXEC_OK;
00443        }
00444 
00445        rc = rewrite_subst_apply( info, op, rule->lr_subst, string,
00446                      match, &val );
00447 
00448        *result = val.bv_val;
00449        val.bv_val = NULL;
00450        if ( string != arg ) {
00451               free( string );
00452               string = NULL;
00453        }
00454 
00455        if ( rc != REWRITE_REGEXEC_OK ) {
00456               return rc;
00457        }
00458 
00459        if ( ( rule->lr_mode & REWRITE_RECURSE ) == REWRITE_RECURSE 
00460                      && op->lo_num_passes < info->li_max_passes
00461                      && ++strcnt < rule->lr_max_passes ) {
00462               string = *result;
00463 
00464               goto recurse;
00465        }
00466 
00467        return REWRITE_REGEXEC_OK;
00468 }
00469 
00470 int
00471 rewrite_rule_destroy(
00472               struct rewrite_rule **prule
00473               )
00474 {
00475        struct rewrite_rule *rule;
00476 
00477        assert( prule != NULL );
00478        assert( *prule != NULL );
00479 
00480        rule = *prule;
00481 
00482        if ( rule->lr_pattern ) {
00483               free( rule->lr_pattern );
00484               rule->lr_pattern = NULL;
00485        }
00486 
00487        if ( rule->lr_subststring ) {
00488               free( rule->lr_subststring );
00489               rule->lr_subststring = NULL;
00490        }
00491 
00492        if ( rule->lr_flagstring ) {
00493               free( rule->lr_flagstring );
00494               rule->lr_flagstring = NULL;
00495        }
00496 
00497        if ( rule->lr_subst ) {
00498               rewrite_subst_destroy( &rule->lr_subst );
00499        }
00500 
00501        regfree( &rule->lr_regex );
00502 
00503        destroy_actions( rule->lr_action );
00504 
00505        free( rule );
00506        *prule = NULL;
00507 
00508        return 0;
00509 }
00510