1/* $OpenLDAP$ */ 2/* This work is part of OpenLDAP Software <http://www.openldap.org/>. 3 * 4 * Copyright 2000-2011 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#include "rewrite-map.h" 24 25/* 26 * Parses a plugin map 27 */ 28static int 29rewrite_parse_builtin_map( 30 struct rewrite_info *info, 31 const char *fname, 32 int lineno, 33 int argc, 34 char **argv 35); 36 37/* 38 * Parses a config line and takes actions to fit content in rewrite structure; 39 * lines handled are of the form: 40 * 41 * rewriteEngine {on|off} 42 * rewriteMaxPasses numPasses [numPassesPerRule] 43 * rewriteContext contextName [alias aliasedContextName] 44 * rewriteRule pattern substPattern [ruleFlags] 45 * rewriteMap mapType mapName [mapArgs] 46 * rewriteParam paramName paramValue 47 */ 48int 49rewrite_parse( 50 struct rewrite_info *info, 51 const char *fname, 52 int lineno, 53 int argc, 54 char **argv 55) 56{ 57 int rc = -1; 58 59 assert( info != NULL ); 60 assert( fname != NULL ); 61 assert( argv != NULL ); 62 assert( argc > 0 ); 63 64 /* 65 * Switch on the rewrite engine 66 */ 67 if ( strcasecmp( argv[ 0 ], "rewriteEngine" ) == 0 ) { 68 if ( argc < 2 ) { 69 Debug( LDAP_DEBUG_ANY, 70 "[%s:%d] rewriteEngine needs 'state'\n%s", 71 fname, lineno, "" ); 72 return -1; 73 74 } else if ( argc > 2 ) { 75 Debug( LDAP_DEBUG_ANY, 76 "[%s:%d] extra fields in rewriteEngine" 77 " will be discarded\n%s", 78 fname, lineno, "" ); 79 } 80 81 if ( strcasecmp( argv[ 1 ], "on" ) == 0 ) { 82 info->li_state = REWRITE_ON; 83 84 } else if ( strcasecmp( argv[ 1 ], "off" ) == 0 ) { 85 info->li_state = REWRITE_OFF; 86 87 } else { 88 Debug( LDAP_DEBUG_ANY, 89 "[%s:%d] unknown 'state' in rewriteEngine;" 90 " assuming 'on'\n%s", 91 fname, lineno, "" ); 92 info->li_state = REWRITE_ON; 93 } 94 rc = REWRITE_SUCCESS; 95 96 /* 97 * Alter max passes 98 */ 99 } else if ( strcasecmp( argv[ 0 ], "rewriteMaxPasses" ) == 0 ) { 100 if ( argc < 2 ) { 101 Debug( LDAP_DEBUG_ANY, 102 "[%s:%d] rewriteMaxPasses needs 'value'\n%s", 103 fname, lineno, "" ); 104 return -1; 105 } 106 107 if ( lutil_atoi( &info->li_max_passes, argv[ 1 ] ) != 0 ) { 108 Debug( LDAP_DEBUG_ANY, 109 "[%s:%d] unable to parse rewriteMaxPasses=\"%s\"\n", 110 fname, lineno, argv[ 1 ] ); 111 return -1; 112 } 113 114 if ( info->li_max_passes <= 0 ) { 115 Debug( LDAP_DEBUG_ANY, 116 "[%s:%d] negative or null rewriteMaxPasses\n", 117 fname, lineno, 0 ); 118 return -1; 119 } 120 121 if ( argc > 2 ) { 122 if ( lutil_atoi( &info->li_max_passes_per_rule, argv[ 2 ] ) != 0 ) { 123 Debug( LDAP_DEBUG_ANY, 124 "[%s:%d] unable to parse rewriteMaxPassesPerRule=\"%s\"\n", 125 fname, lineno, argv[ 2 ] ); 126 return -1; 127 } 128 129 if ( info->li_max_passes_per_rule <= 0 ) { 130 Debug( LDAP_DEBUG_ANY, 131 "[%s:%d] negative or null rewriteMaxPassesPerRule\n", 132 fname, lineno, 0 ); 133 return -1; 134 } 135 136 } else { 137 info->li_max_passes_per_rule = info->li_max_passes; 138 } 139 rc = REWRITE_SUCCESS; 140 141 /* 142 * Start a new rewrite context and set current context 143 */ 144 } else if ( strcasecmp( argv[ 0 ], "rewriteContext" ) == 0 ) { 145 if ( argc < 2 ) { 146 Debug( LDAP_DEBUG_ANY, 147 "[%s:%d] rewriteContext needs 'name'\n%s", 148 fname, lineno, "" ); 149 return -1; 150 } 151 152 /* 153 * Checks for existence (lots of contexts should be 154 * available by default ...) 155 */ 156 rewrite_int_curr_context = rewrite_context_find( info, argv[ 1 ] ); 157 if ( rewrite_int_curr_context == NULL ) { 158 rewrite_int_curr_context = rewrite_context_create( info, 159 argv[ 1 ] ); 160 } 161 if ( rewrite_int_curr_context == NULL ) { 162 return -1; 163 } 164 165 if ( argc > 2 ) { 166 167 /* 168 * A context can alias another (e.g., the `builtin' 169 * contexts for backend operations, if not defined, 170 * alias the `default' rewrite context (with the 171 * notable exception of the searchResult context, 172 * which can be undefined) 173 */ 174 if ( strcasecmp( argv[ 2 ], "alias" ) == 0 ) { 175 struct rewrite_context *aliased; 176 177 if ( argc == 3 ) { 178 Debug( LDAP_DEBUG_ANY, 179 "[%s:%d] rewriteContext" 180 " needs 'name' after" 181 " 'alias'\n%s", 182 fname, lineno, "" ); 183 return -1; 184 185 } else if ( argc > 4 ) { 186 Debug( LDAP_DEBUG_ANY, 187 "[%s:%d] extra fields in" 188 " rewriteContext" 189 " after aliased name" 190 " will be" 191 " discarded\n%s", 192 fname, lineno, "" ); 193 } 194 195 aliased = rewrite_context_find( info, 196 argv[ 3 ] ); 197 if ( aliased == NULL ) { 198 Debug( LDAP_DEBUG_ANY, 199 "[%s:%d] aliased" 200 " rewriteContext '%s'" 201 " does not exists\n", 202 fname, lineno, 203 argv[ 3 ] ); 204 return -1; 205 } 206 207 rewrite_int_curr_context->lc_alias = aliased; 208 rewrite_int_curr_context = aliased; 209 210 } else { 211 Debug( LDAP_DEBUG_ANY, 212 "[%s:%d] extra fields" 213 " in rewriteContext" 214 " will be discarded\n%s", 215 fname, lineno, "" ); 216 } 217 } 218 rc = REWRITE_SUCCESS; 219 220 /* 221 * Compile a rule in current context 222 */ 223 } else if ( strcasecmp( argv[ 0 ], "rewriteRule" ) == 0 ) { 224 if ( argc < 3 ) { 225 Debug( LDAP_DEBUG_ANY, 226 "[%s:%d] rewriteRule needs 'pattern'" 227 " 'subst' ['flags']\n%s", 228 fname, lineno, "" ); 229 return -1; 230 231 } else if ( argc > 4 ) { 232 Debug( LDAP_DEBUG_ANY, 233 "[%s:%d] extra fields in rewriteRule" 234 " will be discarded\n%s", 235 fname, lineno, "" ); 236 } 237 238 if ( rewrite_int_curr_context == NULL ) { 239 Debug( LDAP_DEBUG_ANY, 240 "[%s:%d] rewriteRule outside a" 241 " context; will add to default\n%s", 242 fname, lineno, "" ); 243 rewrite_int_curr_context = rewrite_context_find( info, 244 REWRITE_DEFAULT_CONTEXT ); 245 246 /* 247 * Default context MUST exist in a properly initialized 248 * struct rewrite_info 249 */ 250 assert( rewrite_int_curr_context != NULL ); 251 } 252 253 rc = rewrite_rule_compile( info, rewrite_int_curr_context, argv[ 1 ], 254 argv[ 2 ], ( argc == 4 ? argv[ 3 ] : "" ) ); 255 256 /* 257 * Add a plugin map to the map tree 258 */ 259 } else if ( strcasecmp( argv[ 0 ], "rewriteMap" ) == 0 ) { 260 if ( argc < 3 ) { 261 Debug( LDAP_DEBUG_ANY, 262 "[%s:%d] rewriteMap needs at least 'type'" 263 " and 'name' ['args']\n%s", 264 fname, lineno, "" ); 265 return -1; 266 } 267 268 rc = rewrite_parse_builtin_map( info, fname, lineno, 269 argc, argv ); 270 271 /* 272 * Set the value of a global scope parameter 273 */ 274 } else if ( strcasecmp( argv[ 0 ], "rewriteParam" ) == 0 ) { 275 if ( argc < 3 ) { 276 Debug( LDAP_DEBUG_ANY, 277 "[%s:%d] rewriteParam needs 'name'" 278 " and 'value'\n%s", 279 fname, lineno, "" ); 280 return -1; 281 } 282 283 rc = rewrite_param_set( info, argv[ 1 ], argv[ 2 ] ); 284 285 /* 286 * Error 287 */ 288 } else { 289 Debug( LDAP_DEBUG_ANY, 290 "[%s:%d] unknown command '%s'\n", 291 fname, lineno, "" ); 292 return -1; 293 } 294 295 return rc; 296} 297 298/* 299 * Compares two maps 300 */ 301static int 302rewrite_builtin_map_cmp( 303 const void *c1, 304 const void *c2 305) 306{ 307 const struct rewrite_builtin_map *m1, *m2; 308 309 m1 = ( const struct rewrite_builtin_map * )c1; 310 m2 = ( const struct rewrite_builtin_map * )c2; 311 312 assert( m1 != NULL ); 313 assert( m2 != NULL ); 314 assert( m1->lb_name != NULL ); 315 assert( m2->lb_name != NULL ); 316 317 return strcasecmp( m1->lb_name, m2->lb_name ); 318} 319 320/* 321 * Duplicate map ? 322 */ 323static int 324rewrite_builtin_map_dup( 325 void *c1, 326 void *c2 327) 328{ 329 struct rewrite_builtin_map *m1, *m2; 330 331 m1 = ( struct rewrite_builtin_map * )c1; 332 m2 = ( struct rewrite_builtin_map * )c2; 333 334 assert( m1 != NULL ); 335 assert( m2 != NULL ); 336 assert( m1->lb_name != NULL ); 337 assert( m2->lb_name != NULL ); 338 339 return ( strcasecmp( m1->lb_name, m2->lb_name ) == 0 ? -1 : 0 ); 340} 341 342/* 343 * Adds a map to the info map tree 344 */ 345static int 346rewrite_builtin_map_insert( 347 struct rewrite_info *info, 348 struct rewrite_builtin_map *map 349) 350{ 351 /* 352 * May need a mutex? 353 */ 354 return avl_insert( &info->li_maps, ( caddr_t )map, 355 rewrite_builtin_map_cmp, 356 rewrite_builtin_map_dup ); 357} 358 359/* 360 * Retrieves a map 361 */ 362struct rewrite_builtin_map * 363rewrite_builtin_map_find( 364 struct rewrite_info *info, 365 const char *name 366) 367{ 368 struct rewrite_builtin_map tmp; 369 370 assert( info != NULL ); 371 assert( name != NULL ); 372 373 tmp.lb_name = ( char * )name; 374 375 return ( struct rewrite_builtin_map * )avl_find( info->li_maps, 376 ( caddr_t )&tmp, rewrite_builtin_map_cmp ); 377} 378 379/* 380 * Parses a plugin map 381 */ 382static int 383rewrite_parse_builtin_map( 384 struct rewrite_info *info, 385 const char *fname, 386 int lineno, 387 int argc, 388 char **argv 389) 390{ 391 struct rewrite_builtin_map *map; 392 393#define MAP_TYPE 1 394#define MAP_NAME 2 395 396 assert( info != NULL ); 397 assert( fname != NULL ); 398 assert( argc > 2 ); 399 assert( argv != NULL ); 400 assert( strcasecmp( argv[ 0 ], "rewriteMap" ) == 0 ); 401 402 map = calloc( sizeof( struct rewrite_builtin_map ), 1 ); 403 if ( map == NULL ) { 404 return REWRITE_ERR; 405 } 406 407 map->lb_name = strdup( argv[ MAP_NAME ] ); 408 if ( map->lb_name == NULL ) { 409 free( map ); 410 return REWRITE_ERR; 411 } 412 413 /* 414 * Built-in ldap map 415 */ 416 if (( map->lb_mapper = rewrite_mapper_find( argv[ MAP_TYPE ] ))) { 417 map->lb_type = REWRITE_BUILTIN_MAP; 418 419#ifdef USE_REWRITE_LDAP_PVT_THREADS 420 if ( ldap_pvt_thread_mutex_init( & map->lb_mutex ) ) { 421 free( map->lb_name ); 422 free( map ); 423 return REWRITE_ERR; 424 } 425#endif /* USE_REWRITE_LDAP_PVT_THREADS */ 426 427 map->lb_private = map->lb_mapper->rm_config( fname, lineno, 428 argc - 3, argv + 3 ); 429 430 /* 431 * Error 432 */ 433 } else { 434 free( map ); 435 Debug( LDAP_DEBUG_ANY, "[%s:%d] unknown map type\n%s", 436 fname, lineno, "" ); 437 return -1; 438 } 439 440 return rewrite_builtin_map_insert( info, map ); 441} 442