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