Back to index

openldap  2.4.31
context.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  * Compares two struct rewrite_context based on the name;
00026  * used by avl stuff
00027  */
00028 static int
00029 rewrite_context_cmp(
00030               const void *c1,
00031               const void *c2
00032 )
00033 {
00034        const struct rewrite_context *lc1, *lc2;
00035        
00036        lc1 = (const struct rewrite_context *)c1;
00037        lc2 = (const struct rewrite_context *)c2;
00038        
00039        assert( c1 != NULL );
00040        assert( c2 != NULL );
00041        assert( lc1->lc_name != NULL );
00042        assert( lc2->lc_name != NULL );
00043        
00044        return strcasecmp( lc1->lc_name, lc2->lc_name );
00045 }
00046 
00047 /*
00048  * Returns -1 in case a duplicate struct rewrite_context
00049  * has been inserted; used by avl stuff
00050  */
00051 static int
00052 rewrite_context_dup(
00053               void *c1,
00054               void *c2
00055               )
00056 {
00057        struct rewrite_context *lc1, *lc2;
00058        
00059        lc1 = (struct rewrite_context *)c1;
00060        lc2 = (struct rewrite_context *)c2;
00061        
00062        assert( c1 != NULL );
00063        assert( c2 != NULL );
00064        assert( lc1->lc_name != NULL );
00065        assert( lc2->lc_name != NULL );
00066        
00067        return( strcasecmp( lc1->lc_name, lc2->lc_name) == 0 ? -1 : 0 );
00068 }
00069 
00070 /*
00071  * Finds the context named rewriteContext in the context tree
00072  */
00073 struct rewrite_context *
00074 rewrite_context_find(
00075               struct rewrite_info *info,
00076               const char *rewriteContext
00077 )
00078 {
00079        struct rewrite_context *context, c;
00080 
00081        assert( info != NULL );
00082        assert( rewriteContext != NULL );
00083 
00084        /*
00085         * Fetches the required rewrite context
00086         */
00087        c.lc_name = (char *)rewriteContext;
00088        context = (struct rewrite_context *)avl_find( info->li_context, 
00089                      (caddr_t)&c, rewrite_context_cmp );
00090        if ( context == NULL ) {
00091               return NULL;
00092        }
00093 
00094        /*
00095         * De-aliases the context if required
00096         */
00097        if ( context->lc_alias ) {
00098               return context->lc_alias;
00099        }
00100 
00101        return context;
00102 }
00103 
00104 /*
00105  * Creates a new context called rewriteContext and stores in into the tree
00106  */
00107 struct rewrite_context *
00108 rewrite_context_create(
00109               struct rewrite_info *info,
00110               const char *rewriteContext
00111 )
00112 {
00113        struct rewrite_context *context;
00114        int rc;
00115 
00116        assert( info != NULL );
00117        assert( rewriteContext != NULL );
00118        
00119        context = calloc( sizeof( struct rewrite_context ), 1 );
00120        if ( context == NULL ) {
00121               return NULL;
00122        }
00123        
00124        /*
00125         * Context name
00126         */
00127        context->lc_name = strdup( rewriteContext );
00128        if ( context->lc_name == NULL ) {
00129               free( context );
00130               return NULL;
00131        }
00132 
00133        /*
00134         * The first, empty rule
00135         */
00136        context->lc_rule = calloc( sizeof( struct rewrite_rule ), 1 );
00137        if ( context->lc_rule == NULL ) {
00138               free( context->lc_name );
00139               free( context );
00140               return NULL;
00141        }
00142        memset( context->lc_rule, 0, sizeof( struct rewrite_rule ) );
00143        
00144        /*
00145         * Add context to tree
00146         */
00147        rc = avl_insert( &info->li_context, (caddr_t)context,
00148                      rewrite_context_cmp, rewrite_context_dup );
00149        if ( rc == -1 ) {
00150               free( context->lc_rule );
00151               free( context->lc_name );
00152               free( context );
00153               return NULL;
00154        }
00155 
00156        return context;
00157 }
00158 
00159 /*
00160  * Finds the next rule according to a goto action statement,
00161  * or null in case of error.
00162  * Helper for rewrite_context_apply.
00163  */
00164 static struct rewrite_rule *
00165 rewrite_action_goto(
00166               struct rewrite_action *action,
00167               struct rewrite_rule *rule
00168 )
00169 {
00170        int n;
00171        
00172        assert( action != NULL );
00173        assert( action->la_args != NULL );
00174        assert( rule != NULL );
00175        
00176        n = ((int *)action->la_args)[ 0 ];
00177        
00178        if ( n > 0 ) {
00179               for ( ; n > 1 && rule != NULL ; n-- ) {
00180                      rule = rule->lr_next;
00181               }
00182        } else if ( n <= 0 ) {
00183               for ( ; n < 1 && rule != NULL ; n++ ) {
00184                      rule = rule->lr_prev;
00185               }
00186        }
00187 
00188        return rule;
00189 }
00190 
00191 /*
00192  * Rewrites string according to context; may return:
00193  *      OK:     fine; if *result != NULL rule matched and rewrite succeeded.
00194  *      STOP:   fine, rule matched; stop processing following rules
00195  *      UNWILL: rule matched; force 'unwilling to perform'
00196  */
00197 int
00198 rewrite_context_apply(
00199               struct rewrite_info *info,
00200               struct rewrite_op *op,
00201               struct rewrite_context *context,
00202               const char *string,
00203               char **result
00204 )
00205 {
00206        struct rewrite_rule *rule;
00207        char *s, *res = NULL;
00208        int return_code = REWRITE_REGEXEC_OK;
00209        
00210        assert( info != NULL );
00211        assert( op != NULL );
00212        assert( context != NULL );
00213        assert( context->lc_rule != NULL );
00214        assert( string != NULL );
00215        assert( result != NULL );
00216 
00217        op->lo_depth++;
00218 
00219        Debug( LDAP_DEBUG_TRACE, "==> rewrite_context_apply"
00220                      " [depth=%d] string='%s'\n",
00221                      op->lo_depth, string, 0 );
00222        assert( op->lo_depth > 0 );
00223        
00224        s = (char *)string;
00225        
00226        for ( rule = context->lc_rule->lr_next;
00227                      rule != NULL && op->lo_num_passes < info->li_max_passes;
00228                      rule = rule->lr_next, op->lo_num_passes++ ) {
00229               int rc;
00230               
00231               /*
00232                * Apply a single rule
00233                */
00234               rc = rewrite_rule_apply( info, op, rule, s, &res );
00235               
00236               /*
00237                * A rule may return:
00238                *     OK            with result != NULL if matched
00239                *     ERR           if anything was wrong
00240                *     UNWILLING     if the server should drop the request
00241                * the latter case in honored immediately;
00242                * the other two may require some special actions to take
00243                * place.
00244                */
00245               switch ( rc ) {
00246                      
00247               case REWRITE_REGEXEC_ERR:
00248                      Debug( LDAP_DEBUG_ANY, "==> rewrite_context_apply"
00249                                    " error ...\n", 0, 0, 0);
00250 
00251                      /*
00252                       * Checks for special actions to be taken
00253                       * in case of error ...
00254                       */
00255                      if ( rule->lr_action != NULL ) {
00256                             struct rewrite_action *action;
00257                             int do_continue = 0;
00258                             
00259                             for ( action = rule->lr_action;
00260                                           action != NULL;
00261                                           action = action->la_next ) {
00262                                    switch ( action->la_type ) {
00263                                    
00264                                    /*
00265                                     * This action takes precedence
00266                                     * over the others in case of failure
00267                                     */
00268                                    case REWRITE_ACTION_IGNORE_ERR:
00269                                           Debug( LDAP_DEBUG_ANY,
00270                                    "==> rewrite_context_apply"
00271                                    " ignoring error ...\n", 0, 0, 0 );
00272                                           do_continue = 1;
00273                                           break;
00274 
00275                                    /*
00276                                     * Goto is honored only if it comes
00277                                     * after ignore error
00278                                     */
00279                                    case REWRITE_ACTION_GOTO:
00280                                           if ( do_continue ) {
00281                                                  rule = rewrite_action_goto( action, rule );
00282                                                  if ( rule == NULL ) {
00283                                                         return_code = REWRITE_REGEXEC_ERR;
00284                                                         goto rc_end_of_context;
00285                                                  }
00286                                           }
00287                                           break;
00288 
00289                                    /*
00290                                     * Other actions are ignored
00291                                     */
00292                                    default:
00293                                           break;
00294                                    }
00295                             }
00296 
00297                             if ( do_continue ) {
00298                                    if ( rule->lr_next == NULL ) {
00299                                           res = s;
00300                                    }
00301                                    goto rc_continue;
00302                             }
00303                      }
00304 
00305                      /* 
00306                       * Default behavior is to bail out ...
00307                       */
00308                      return_code = REWRITE_REGEXEC_ERR;
00309                      goto rc_end_of_context;
00310               
00311               /*
00312                * OK means there were no errors or special return codes;
00313                * if res is defined, it means the rule matched and we
00314                * got a sucessful rewriting
00315                */
00316               case REWRITE_REGEXEC_OK:
00317 
00318                      /*
00319                       * It matched! Check for actions ...
00320                       */
00321                      if ( res != NULL ) {
00322                             struct rewrite_action *action;
00323                             
00324                             if ( s != string && s != res ) {
00325                                    free( s );
00326                             }
00327                             s = res;
00328 
00329                             for ( action = rule->lr_action;
00330                                           action != NULL;
00331                                           action = action->la_next ) {
00332 
00333                                    switch ( action->la_type ) {
00334 
00335                                    /*
00336                                     * This ends the rewrite context
00337                                     * successfully
00338                                     */
00339                                    case REWRITE_ACTION_STOP:
00340                                           goto rc_end_of_context;
00341                                    
00342                                    /*
00343                                     * This instructs the server to return
00344                                     * an `unwilling to perform' error
00345                                     * message
00346                                     */
00347                                    case REWRITE_ACTION_UNWILLING:
00348                                           return_code = REWRITE_REGEXEC_UNWILLING;
00349                                           goto rc_end_of_context;
00350                                    
00351                                    /*
00352                                     * This causes the processing to
00353                                     * jump n rules back and forth
00354                                     */
00355                                    case REWRITE_ACTION_GOTO:
00356                                           rule = rewrite_action_goto( action, rule );
00357                                           if ( rule == NULL ) {
00358                                                  return_code = REWRITE_REGEXEC_ERR;
00359                                                  goto rc_end_of_context;
00360                                           }
00361                                           break;
00362 
00363                                    /*
00364                                     * This ends the rewrite context
00365                                     * and returns a user-defined
00366                                     * error code
00367                                     */
00368                                    case REWRITE_ACTION_USER:
00369                                           return_code = ((int *)action->la_args)[ 0 ];
00370                                           goto rc_end_of_context;
00371                                    
00372                                    default:
00373                                           /* ... */
00374                                           break;
00375                                    }
00376                             }
00377 
00378                      /*
00379                       * If result was OK and string didn't match,
00380                       * in case of last rule we need to set the
00381                       * result back to the string
00382                       */
00383                      } else if ( rule->lr_next == NULL ) {
00384                             res = s;
00385                      }
00386                      
00387                      break;
00388 
00389               /*
00390                * A STOP has propagated ...
00391                */
00392               case REWRITE_REGEXEC_STOP:
00393                      goto rc_end_of_context;
00394 
00395               /*
00396                * This will instruct the server to return
00397                * an `unwilling to perform' error message
00398                */
00399               case REWRITE_REGEXEC_UNWILLING:
00400                      return_code = REWRITE_REGEXEC_UNWILLING;
00401                      goto rc_end_of_context;
00402 
00403               /*
00404                * A user-defined error code has propagated ...
00405                */
00406               default:
00407                      assert( rc >= REWRITE_REGEXEC_USER );
00408                      goto rc_end_of_context;
00409 
00410               }
00411               
00412 rc_continue:; /* sent here by actions that require to continue */
00413 
00414        }
00415 
00416 rc_end_of_context:;
00417        *result = res;
00418 
00419        Debug( LDAP_DEBUG_TRACE, "==> rewrite_context_apply"
00420                      " [depth=%d] res={%d,'%s'}\n",
00421                      op->lo_depth, return_code, ( res ? res : "NULL" ) );
00422 
00423        assert( op->lo_depth > 0 );
00424        op->lo_depth--;
00425 
00426        return return_code;
00427 }
00428 
00429 void
00430 rewrite_context_free(
00431               void *tmp
00432 )
00433 {
00434        struct rewrite_context *context = (struct rewrite_context *)tmp;
00435 
00436        assert( tmp != NULL );
00437 
00438        rewrite_context_destroy( &context );
00439 }
00440 
00441 int
00442 rewrite_context_destroy(
00443               struct rewrite_context **pcontext
00444 )
00445 {
00446        struct rewrite_context *context;
00447        struct rewrite_rule *r;
00448 
00449        assert( pcontext != NULL );
00450        assert( *pcontext != NULL );
00451 
00452        context = *pcontext;
00453 
00454        assert( context->lc_rule != NULL );
00455 
00456        for ( r = context->lc_rule->lr_next; r; ) {
00457               struct rewrite_rule *cr = r;
00458 
00459               r = r->lr_next;
00460               rewrite_rule_destroy( &cr );
00461        }
00462 
00463        free( context->lc_rule );
00464        context->lc_rule = NULL;
00465 
00466        assert( context->lc_name != NULL );
00467        free( context->lc_name );
00468        context->lc_name = NULL;
00469 
00470        free( context );
00471        *pcontext = NULL;
00472        
00473        return 0;
00474 }