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#ifndef REWRITE_INT_H 21#define REWRITE_INT_H 22 23/* 24 * These are required by every file of the library, so they're included here 25 */ 26#include <ac/stdlib.h> 27#include <ac/string.h> 28#include <ac/syslog.h> 29#include <ac/regex.h> 30#include <ac/socket.h> 31#include <ac/unistd.h> 32#include <ac/ctype.h> 33 34#include <lber.h> 35#include <ldap.h> 36#define LDAP_DEFINE_LDAP_DEBUG 37#include <ldap_log.h> 38#include <lutil.h> 39#include <avl.h> 40 41#include <rewrite.h> 42 43#define malloc(x) ber_memalloc(x) 44#define calloc(x,y) ber_memcalloc(x,y) 45#define realloc(x,y) ber_memrealloc(x,y) 46#define free(x) ber_memfree(x) 47#undef strdup 48#define strdup(x) ber_strdup(x) 49 50/* Uncomment to use ldap pvt threads */ 51#define USE_REWRITE_LDAP_PVT_THREADS 52#include <ldap_pvt_thread.h> 53 54/* 55 * For details, see RATIONALE. 56 */ 57 58#define REWRITE_MAX_MATCH 11 /* 0: overall string; 1-9: submatches */ 59#define REWRITE_MAX_PASSES 100 60 61/* 62 * Submatch escape char 63 */ 64/* the '\' conflicts with slapd.conf parsing */ 65/* #define REWRITE_SUBMATCH_ESCAPE '\\' */ 66#define REWRITE_SUBMATCH_ESCAPE_ORIG '%' 67#define REWRITE_SUBMATCH_ESCAPE '$' 68#define IS_REWRITE_SUBMATCH_ESCAPE(c) \ 69 ((c) == REWRITE_SUBMATCH_ESCAPE || (c) == REWRITE_SUBMATCH_ESCAPE_ORIG) 70 71/* 72 * REGEX flags 73 */ 74 75#define REWRITE_FLAG_HONORCASE 'C' 76#define REWRITE_FLAG_BASICREGEX 'R' 77 78/* 79 * Action flags 80 */ 81#define REWRITE_FLAG_EXECONCE ':' 82#define REWRITE_FLAG_STOP '@' 83#define REWRITE_FLAG_UNWILLING '#' 84#define REWRITE_FLAG_GOTO 'G' /* requires an arg */ 85#define REWRITE_FLAG_USER 'U' /* requires an arg */ 86#define REWRITE_FLAG_MAX_PASSES 'M' /* requires an arg */ 87#define REWRITE_FLAG_IGNORE_ERR 'I' 88 89/* 90 * Map operators 91 */ 92#define REWRITE_OPERATOR_SUBCONTEXT '>' 93#define REWRITE_OPERATOR_COMMAND '|' 94#define REWRITE_OPERATOR_VARIABLE_SET '&' 95#define REWRITE_OPERATOR_VARIABLE_GET '*' 96#define REWRITE_OPERATOR_PARAM_GET '$' 97 98 99/*********** 100 * PRIVATE * 101 ***********/ 102 103/* 104 * Action 105 */ 106struct rewrite_action { 107 struct rewrite_action *la_next; 108 109#define REWRITE_ACTION_STOP 0x0001 110#define REWRITE_ACTION_UNWILLING 0x0002 111#define REWRITE_ACTION_GOTO 0x0003 112#define REWRITE_ACTION_IGNORE_ERR 0x0004 113#define REWRITE_ACTION_USER 0x0005 114 int la_type; 115 void *la_args; 116}; 117 118/* 119 * Map 120 */ 121struct rewrite_map { 122 123 /* 124 * Legacy stuff 125 */ 126#define REWRITE_MAP_XFILEMAP 0x0001 /* Rough implementation! */ 127#define REWRITE_MAP_XPWDMAP 0x0002 /* uid -> gecos */ 128#define REWRITE_MAP_XLDAPMAP 0x0003 /* Not implemented yet! */ 129 130 /* 131 * Maps with args 132 */ 133#define REWRITE_MAP_SUBCONTEXT 0x0101 134 135#define REWRITE_MAP_SET_OP_VAR 0x0102 136#define REWRITE_MAP_SETW_OP_VAR 0x0103 137#define REWRITE_MAP_GET_OP_VAR 0x0104 138#define REWRITE_MAP_SET_SESN_VAR 0x0105 139#define REWRITE_MAP_SETW_SESN_VAR 0x0106 140#define REWRITE_MAP_GET_SESN_VAR 0x0107 141#define REWRITE_MAP_GET_PARAM 0x0108 142#define REWRITE_MAP_BUILTIN 0x0109 143 int lm_type; 144 145 char *lm_name; 146 void *lm_data; 147 148 /* 149 * Old maps store private data in _lm_args; 150 * new maps store the substitution pattern in _lm_subst 151 */ 152 union { 153 void *_lm_args; 154 struct rewrite_subst *_lm_subst; 155 } lm_union; 156#define lm_args lm_union._lm_args 157#define lm_subst lm_union._lm_subst 158 159#ifdef USE_REWRITE_LDAP_PVT_THREADS 160 ldap_pvt_thread_mutex_t lm_mutex; 161#endif /* USE_REWRITE_LDAP_PVT_THREADS */ 162}; 163 164/* 165 * Builtin maps 166 */ 167struct rewrite_builtin_map { 168#define REWRITE_BUILTIN_MAP 0x0200 169 int lb_type; 170 char *lb_name; 171 void *lb_private; 172 const rewrite_mapper *lb_mapper; 173 174#ifdef USE_REWRITE_LDAP_PVT_THREADS 175 ldap_pvt_thread_mutex_t lb_mutex; 176#endif /* USE_REWRITE_LDAP_PVT_THREADS */ 177}; 178 179/* 180 * Submatch substitution 181 */ 182struct rewrite_submatch { 183#define REWRITE_SUBMATCH_ASIS 0x0000 184#define REWRITE_SUBMATCH_XMAP 0x0001 185#define REWRITE_SUBMATCH_MAP_W_ARG 0x0002 186 int ls_type; 187 struct rewrite_map *ls_map; 188 int ls_submatch; 189 /* 190 * The first one represents the index of the submatch in case 191 * the map has single submatch as argument; 192 * the latter represents the map argument scheme in case 193 * the map has substitution string argument form 194 */ 195}; 196 197/* 198 * Pattern substitution 199 */ 200struct rewrite_subst { 201 size_t lt_subs_len; 202 struct berval *lt_subs; 203 204 int lt_num_submatch; 205 struct rewrite_submatch *lt_submatch; 206}; 207 208/* 209 * Rule 210 */ 211struct rewrite_rule { 212 struct rewrite_rule *lr_next; 213 struct rewrite_rule *lr_prev; 214 215 char *lr_pattern; 216 char *lr_subststring; 217 char *lr_flagstring; 218 regex_t lr_regex; 219 220 /* 221 * I was thinking about some kind of per-rule mutex, but there's 222 * probably no need, because rules after compilation are only read; 223 * however, I need to check whether regexec is reentrant ... 224 */ 225 226 struct rewrite_subst *lr_subst; 227 228#define REWRITE_REGEX_ICASE REG_ICASE 229#define REWRITE_REGEX_EXTENDED REG_EXTENDED 230 int lr_flags; 231 232#define REWRITE_RECURSE 0x0001 233#define REWRITE_EXEC_ONCE 0x0002 234 int lr_mode; 235 int lr_max_passes; 236 237 struct rewrite_action *lr_action; 238}; 239 240/* 241 * Rewrite Context (set of rules) 242 */ 243struct rewrite_context { 244 char *lc_name; 245 struct rewrite_context *lc_alias; 246 struct rewrite_rule *lc_rule; 247}; 248 249/* 250 * Session 251 */ 252struct rewrite_session { 253 void *ls_cookie; 254 Avlnode *ls_vars; 255#ifdef USE_REWRITE_LDAP_PVT_THREADS 256 ldap_pvt_thread_rdwr_t ls_vars_mutex; 257 ldap_pvt_thread_mutex_t ls_mutex; 258#endif /* USE_REWRITE_LDAP_PVT_THREADS */ 259 int ls_count; 260}; 261 262/* 263 * Variable 264 */ 265struct rewrite_var { 266 char *lv_name; 267 int lv_flags; 268 struct berval lv_value; 269}; 270 271/* 272 * Operation 273 */ 274struct rewrite_op { 275 int lo_num_passes; 276 int lo_depth; 277#if 0 /* FIXME: not used anywhere! (debug? then, why strdup?) */ 278 char *lo_string; 279#endif 280 char *lo_result; 281 Avlnode *lo_vars; 282 const void *lo_cookie; 283}; 284 285 286/********** 287 * PUBLIC * 288 **********/ 289 290/* 291 * Rewrite info 292 */ 293struct rewrite_info { 294 Avlnode *li_context; 295 Avlnode *li_maps; 296 /* 297 * No global mutex because maps are read only at 298 * config time 299 */ 300 Avlnode *li_params; 301 Avlnode *li_cookies; 302 int li_num_cookies; 303 304#ifdef USE_REWRITE_LDAP_PVT_THREADS 305 ldap_pvt_thread_rdwr_t li_params_mutex; 306 ldap_pvt_thread_rdwr_t li_cookies_mutex; 307#endif /* USE_REWRITE_LDAP_PVT_THREADS */ 308 309 /* 310 * Default to `off'; 311 * use `rewriteEngine {on|off}' directive to alter 312 */ 313 int li_state; 314 315 /* 316 * Defaults to REWRITE_MAXPASSES; 317 * use `rewriteMaxPasses numPasses' directive to alter 318 */ 319#define REWRITE_MAXPASSES 100 320 int li_max_passes; 321 int li_max_passes_per_rule; 322 323 /* 324 * Behavior in case a NULL or non-existent context is required 325 */ 326 int li_rewrite_mode; 327}; 328 329/*********** 330 * PRIVATE * 331 ***********/ 332 333LDAP_REWRITE_V (struct rewrite_context*) rewrite_int_curr_context; 334 335/* 336 * Maps 337 */ 338 339/* 340 * Parses a map (also in legacy 'x' version) 341 */ 342LDAP_REWRITE_F (struct rewrite_map *) 343rewrite_map_parse( 344 struct rewrite_info *info, 345 const char *s, 346 const char **end 347); 348 349LDAP_REWRITE_F (struct rewrite_map *) 350rewrite_xmap_parse( 351 struct rewrite_info *info, 352 const char *s, 353 const char **end 354); 355 356/* 357 * Resolves key in val by means of map (also in legacy 'x' version) 358 */ 359LDAP_REWRITE_F (int) 360rewrite_map_apply( 361 struct rewrite_info *info, 362 struct rewrite_op *op, 363 struct rewrite_map *map, 364 struct berval *key, 365 struct berval *val 366); 367 368LDAP_REWRITE_F (int) 369rewrite_xmap_apply( 370 struct rewrite_info *info, 371 struct rewrite_op *op, 372 struct rewrite_map *map, 373 struct berval *key, 374 struct berval *val 375); 376 377LDAP_REWRITE_F (int) 378rewrite_map_destroy( 379 struct rewrite_map **map 380); 381 382LDAP_REWRITE_F (int) 383rewrite_xmap_destroy( 384 struct rewrite_map **map 385); 386 387LDAP_REWRITE_F (void) 388rewrite_builtin_map_free( 389 void *map 390); 391/* 392 * Submatch substitution 393 */ 394 395/* 396 * Compiles a substitution pattern 397 */ 398LDAP_REWRITE_F (struct rewrite_subst *) 399rewrite_subst_compile( 400 struct rewrite_info *info, 401 const char *result 402); 403 404/* 405 * Substitutes a portion of rewritten string according to substitution 406 * pattern using submatches 407 */ 408LDAP_REWRITE_F (int) 409rewrite_subst_apply( 410 struct rewrite_info *info, 411 struct rewrite_op *op, 412 struct rewrite_subst *subst, 413 const char *string, 414 const regmatch_t *match, 415 struct berval *val 416); 417 418LDAP_REWRITE_F (int) 419rewrite_subst_destroy( 420 struct rewrite_subst **subst 421); 422 423 424/* 425 * Rules 426 */ 427 428/* 429 * Compiles the rule and appends it at the running context 430 */ 431LDAP_REWRITE_F (int) 432rewrite_rule_compile( 433 struct rewrite_info *info, 434 struct rewrite_context *context, 435 const char *pattern, 436 const char *result, 437 const char *flagstring 438); 439 440/* 441 * Rewrites string according to rule; may return: 442 * REWRITE_REGEXEC_OK: fine; if *result != NULL rule matched 443 * and rewrite succeeded. 444 * REWRITE_REGEXEC_STOP: fine, rule matched; stop processing 445 * following rules 446 * REWRITE_REGEXEC_UNWILL: rule matched; force 'unwilling to perform' 447 * REWRITE_REGEXEC_ERR: an error occurred 448 */ 449LDAP_REWRITE_F (int) 450rewrite_rule_apply( 451 struct rewrite_info *info, 452 struct rewrite_op *op, 453 struct rewrite_rule *rule, 454 const char *string, 455 char **result 456); 457 458LDAP_REWRITE_F (int) 459rewrite_rule_destroy( 460 struct rewrite_rule **rule 461); 462 463/* 464 * Sessions 465 */ 466 467/* 468 * Fetches a struct rewrite_session 469 */ 470LDAP_REWRITE_F (struct rewrite_session *) 471rewrite_session_find( 472 struct rewrite_info *info, 473 const void *cookie 474); 475 476/* 477 * Defines and inits a variable with session scope 478 */ 479LDAP_REWRITE_F (int) 480rewrite_session_var_set_f( 481 struct rewrite_info *info, 482 const void *cookie, 483 const char *name, 484 const char *value, 485 int flags 486); 487 488/* 489 * Gets a var with session scope 490 */ 491LDAP_REWRITE_F (int) 492rewrite_session_var_get( 493 struct rewrite_info *info, 494 const void *cookie, 495 const char *name, 496 struct berval *val 497); 498 499/* 500 * Deletes a session 501 */ 502LDAP_REWRITE_F (int) 503rewrite_session_delete( 504 struct rewrite_info *info, 505 const void *cookie 506); 507 508/* 509 * Destroys the cookie tree 510 */ 511LDAP_REWRITE_F (int) 512rewrite_session_destroy( 513 struct rewrite_info *info 514); 515 516 517/* 518 * Vars 519 */ 520 521/* 522 * Finds a var 523 */ 524LDAP_REWRITE_F (struct rewrite_var *) 525rewrite_var_find( 526 Avlnode *tree, 527 const char *name 528); 529 530/* 531 * Replaces the value of a variable 532 */ 533LDAP_REWRITE_F (int) 534rewrite_var_replace( 535 struct rewrite_var *var, 536 const char *value, 537 int flags 538); 539 540/* 541 * Inserts a newly created var 542 */ 543LDAP_REWRITE_F (struct rewrite_var *) 544rewrite_var_insert_f( 545 Avlnode **tree, 546 const char *name, 547 const char *value, 548 int flags 549); 550 551#define rewrite_var_insert(tree, name, value) \ 552 rewrite_var_insert_f((tree), (name), (value), \ 553 REWRITE_VAR_UPDATE|REWRITE_VAR_COPY_NAME|REWRITE_VAR_COPY_VALUE) 554 555/* 556 * Sets/inserts a var 557 */ 558LDAP_REWRITE_F (struct rewrite_var *) 559rewrite_var_set_f( 560 Avlnode **tree, 561 const char *name, 562 const char *value, 563 int flags 564); 565 566#define rewrite_var_set(tree, name, value, insert) \ 567 rewrite_var_set_f((tree), (name), (value), \ 568 REWRITE_VAR_UPDATE|REWRITE_VAR_COPY_NAME|REWRITE_VAR_COPY_VALUE|((insert)? REWRITE_VAR_INSERT : 0)) 569 570/* 571 * Deletes a var tree 572 */ 573LDAP_REWRITE_F (int) 574rewrite_var_delete( 575 Avlnode *tree 576); 577 578 579/* 580 * Contexts 581 */ 582 583/* 584 * Finds the context named rewriteContext in the context tree 585 */ 586LDAP_REWRITE_F (struct rewrite_context *) 587rewrite_context_find( 588 struct rewrite_info *info, 589 const char *rewriteContext 590); 591 592/* 593 * Creates a new context called rewriteContext and stores in into the tree 594 */ 595LDAP_REWRITE_F (struct rewrite_context *) 596rewrite_context_create( 597 struct rewrite_info *info, 598 const char *rewriteContext 599); 600 601/* 602 * Rewrites string according to context; may return: 603 * OK: fine; if *result != NULL rule matched and rewrite succeeded. 604 * STOP: fine, rule matched; stop processing following rules 605 * UNWILL: rule matched; force 'unwilling to perform' 606 */ 607LDAP_REWRITE_F (int) 608rewrite_context_apply( 609 struct rewrite_info *info, 610 struct rewrite_op *op, 611 struct rewrite_context *context, 612 const char *string, 613 char **result 614); 615 616LDAP_REWRITE_F (int) 617rewrite_context_destroy( 618 struct rewrite_context **context 619); 620 621LDAP_REWRITE_F (void) 622rewrite_context_free( 623 void *tmp 624); 625 626#endif /* REWRITE_INT_H */ 627 628