1/* $OpenLDAP$ */ 2/* This work is part of OpenLDAP Software <http://www.openldap.org/>. 3 * 4 * Copyright 1999-2011 The OpenLDAP Foundation. 5 * Portions Copyright 2001-2003 Pierangelo Masarati. 6 * Portions Copyright 1999-2003 Howard Chu. 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/* ACKNOWLEDGEMENTS: 18 * This work was initially developed by the Howard Chu for inclusion 19 * in OpenLDAP Software and subsequently enhanced by Pierangelo 20 * Masarati. 21 */ 22 23#include "portable.h" 24 25#include <stdio.h> 26 27#include <ac/string.h> 28#include <ac/socket.h> 29 30#include "slap.h" 31#include "lutil.h" 32#include "../back-ldap/back-ldap.h" 33#include "back-meta.h" 34 35static int 36meta_back_new_target( 37 metatarget_t **mtp ) 38{ 39 char *rargv[ 3 ]; 40 metatarget_t *mt; 41 42 *mtp = NULL; 43 44 mt = ch_calloc( sizeof( metatarget_t ), 1 ); 45 46 mt->mt_rwmap.rwm_rw = rewrite_info_init( REWRITE_MODE_USE_DEFAULT ); 47 if ( mt->mt_rwmap.rwm_rw == NULL ) { 48 ch_free( mt ); 49 return -1; 50 } 51 52 /* 53 * the filter rewrite as a string must be disabled 54 * by default; it can be re-enabled by adding rules; 55 * this creates an empty rewriteContext 56 */ 57 rargv[ 0 ] = "rewriteContext"; 58 rargv[ 1 ] = "searchFilter"; 59 rargv[ 2 ] = NULL; 60 rewrite_parse( mt->mt_rwmap.rwm_rw, "<suffix massage>", 1, 2, rargv ); 61 62 rargv[ 0 ] = "rewriteContext"; 63 rargv[ 1 ] = "default"; 64 rargv[ 2 ] = NULL; 65 rewrite_parse( mt->mt_rwmap.rwm_rw, "<suffix massage>", 1, 2, rargv ); 66 67 ldap_pvt_thread_mutex_init( &mt->mt_uri_mutex ); 68 69 mt->mt_idassert_mode = LDAP_BACK_IDASSERT_LEGACY; 70 mt->mt_idassert_authmethod = LDAP_AUTH_NONE; 71 mt->mt_idassert_tls = SB_TLS_DEFAULT; 72 73 /* by default, use proxyAuthz control on each operation */ 74 mt->mt_idassert_flags = LDAP_BACK_AUTH_PRESCRIPTIVE; 75 76 *mtp = mt; 77 78 return 0; 79} 80 81static int 82check_true_false( char *str ) 83{ 84 if ( strcasecmp( str, "true" ) == 0 || strcasecmp( str, "yes" ) == 0 ) { 85 return 1; 86 } 87 88 if ( strcasecmp( str, "false" ) == 0 || strcasecmp( str, "no" ) == 0 ) { 89 return 0; 90 } 91 92 return -1; 93} 94 95int 96meta_subtree_destroy( metasubtree_t *ms ) 97{ 98 if ( ms->ms_next ) { 99 meta_subtree_destroy( ms->ms_next ); 100 } 101 102 switch ( ms->ms_type ) { 103 case META_ST_SUBTREE: 104 case META_ST_SUBORDINATE: 105 ber_memfree( ms->ms_dn.bv_val ); 106 break; 107 108 case META_ST_REGEX: 109 regfree( &ms->ms_regex ); 110 ch_free( ms->ms_regex_pattern ); 111 break; 112 113 default: 114 return -1; 115 } 116 117 ch_free( ms ); 118 119 return 0; 120} 121 122static int 123meta_subtree_config( 124 metatarget_t *mt, 125 int argc, 126 char **argv, 127 char *buf, 128 ber_len_t buflen, 129 char *log_prefix ) 130{ 131 meta_st_t type = META_ST_SUBTREE; 132 char *pattern; 133 struct berval ndn = BER_BVNULL; 134 metasubtree_t *ms = NULL; 135 136 if ( strcasecmp( argv[0], "subtree-exclude" ) == 0 ) { 137 if ( mt->mt_subtree && !mt->mt_subtree_exclude ) { 138 snprintf( buf, buflen, 139 "\"subtree-exclude\" incompatible with previous \"subtree-include\" directives" ); 140 return 1; 141 } 142 143 mt->mt_subtree_exclude = 1; 144 145 } else { 146 if ( mt->mt_subtree && mt->mt_subtree_exclude ) { 147 snprintf( buf, buflen, 148 "\"subtree-include\" incompatible with previous \"subtree-exclude\" directives" ); 149 return 1; 150 } 151 } 152 153 switch ( argc ) { 154 case 1: 155 snprintf( buf, buflen, "missing pattern" ); 156 return 1; 157 158 case 2: 159 break; 160 161 default: 162 snprintf( buf, buflen, "too many args" ); 163 return 1; 164 } 165 166 pattern = argv[1]; 167 if ( strncasecmp( pattern, "dn", STRLENOF( "dn" ) ) == 0 ) { 168 char *style; 169 170 pattern = &pattern[STRLENOF( "dn")]; 171 172 if ( pattern[0] == '.' ) { 173 style = &pattern[1]; 174 175 if ( strncasecmp( style, "subtree", STRLENOF( "subtree" ) ) == 0 ) { 176 type = META_ST_SUBTREE; 177 pattern = &style[STRLENOF( "subtree" )]; 178 179 } else if ( strncasecmp( style, "children", STRLENOF( "children" ) ) == 0 ) { 180 type = META_ST_SUBORDINATE; 181 pattern = &style[STRLENOF( "children" )]; 182 183 } else if ( strncasecmp( style, "sub", STRLENOF( "sub" ) ) == 0 ) { 184 type = META_ST_SUBTREE; 185 pattern = &style[STRLENOF( "sub" )]; 186 187 } else if ( strncasecmp( style, "regex", STRLENOF( "regex" ) ) == 0 ) { 188 type = META_ST_REGEX; 189 pattern = &style[STRLENOF( "regex" )]; 190 191 } else { 192 snprintf( buf, buflen, "unknown style in \"dn.<style>\"" ); 193 return 1; 194 } 195 } 196 197 if ( pattern[0] != ':' ) { 198 snprintf( buf, buflen, "missing colon after \"dn.<style>\"" ); 199 return 1; 200 } 201 pattern++; 202 } 203 204 switch ( type ) { 205 case META_ST_SUBTREE: 206 case META_ST_SUBORDINATE: { 207 struct berval dn; 208 209 ber_str2bv( pattern, 0, 0, &dn ); 210 if ( dnNormalize( 0, NULL, NULL, &dn, &ndn, NULL ) 211 != LDAP_SUCCESS ) 212 { 213 snprintf( buf, buflen, "DN=\"%s\" is invalid", pattern ); 214 return 1; 215 } 216 217 if ( !dnIsSuffix( &ndn, &mt->mt_nsuffix ) ) { 218 snprintf( buf, buflen, 219 "DN=\"%s\" is not a subtree of target \"%s\"", 220 pattern, mt->mt_nsuffix.bv_val ); 221 ber_memfree( ndn.bv_val ); 222 return( 1 ); 223 } 224 } break; 225 226 default: 227 /* silence warnings */ 228 break; 229 } 230 231 ms = ch_calloc( sizeof( metasubtree_t ), 1 ); 232 ms->ms_type = type; 233 234 switch ( ms->ms_type ) { 235 case META_ST_SUBTREE: 236 case META_ST_SUBORDINATE: 237 ms->ms_dn = ndn; 238 break; 239 240 case META_ST_REGEX: { 241 int rc; 242 243 rc = regcomp( &ms->ms_regex, pattern, REG_EXTENDED|REG_ICASE ); 244 if ( rc != 0 ) { 245 char regerr[ SLAP_TEXT_BUFLEN ]; 246 247 regerror( rc, &ms->ms_regex, regerr, sizeof(regerr) ); 248 249 snprintf( buf, sizeof( buf ), 250 "regular expression \"%s\" bad because of %s", 251 pattern, regerr ); 252 ch_free( ms ); 253 return 1; 254 } 255 ms->ms_regex_pattern = ch_strdup( pattern ); 256 } break; 257 } 258 259 if ( mt->mt_subtree == NULL ) { 260 mt->mt_subtree = ms; 261 262 } else { 263 metasubtree_t **msp; 264 265 for ( msp = &mt->mt_subtree; *msp; ) { 266 switch ( ms->ms_type ) { 267 case META_ST_SUBTREE: 268 switch ( (*msp)->ms_type ) { 269 case META_ST_SUBTREE: 270 if ( dnIsSuffix( &(*msp)->ms_dn, &ms->ms_dn ) ) { 271 metasubtree_t *tmp = *msp; 272 Debug( LDAP_DEBUG_CONFIG, 273 "%s: previous rule \"dn.subtree:%s\" is contained in rule \"dn.subtree:%s\" (replaced)\n", 274 log_prefix, pattern, (*msp)->ms_dn.bv_val ); 275 *msp = (*msp)->ms_next; 276 tmp->ms_next = NULL; 277 meta_subtree_destroy( tmp ); 278 continue; 279 280 } else if ( dnIsSuffix( &ms->ms_dn, &(*msp)->ms_dn ) ) { 281 Debug( LDAP_DEBUG_CONFIG, 282 "%s: previous rule \"dn.subtree:%s\" contains rule \"dn.subtree:%s\" (ignored)\n", 283 log_prefix, (*msp)->ms_dn.bv_val, pattern ); 284 meta_subtree_destroy( ms ); 285 ms = NULL; 286 return( 0 ); 287 } 288 break; 289 290 case META_ST_SUBORDINATE: 291 if ( dnIsSuffix( &(*msp)->ms_dn, &ms->ms_dn ) ) { 292 metasubtree_t *tmp = *msp; 293 Debug( LDAP_DEBUG_CONFIG, 294 "%s: previous rule \"dn.children:%s\" is contained in rule \"dn.subtree:%s\" (replaced)\n", 295 log_prefix, pattern, (*msp)->ms_dn.bv_val ); 296 *msp = (*msp)->ms_next; 297 tmp->ms_next = NULL; 298 meta_subtree_destroy( tmp ); 299 continue; 300 301 } else if ( dnIsSuffix( &ms->ms_dn, &(*msp)->ms_dn ) && ms->ms_dn.bv_len > (*msp)->ms_dn.bv_len ) { 302 Debug( LDAP_DEBUG_CONFIG, 303 "%s: previous rule \"dn.children:%s\" contains rule \"dn.subtree:%s\" (ignored)\n", 304 log_prefix, (*msp)->ms_dn.bv_val, pattern ); 305 meta_subtree_destroy( ms ); 306 ms = NULL; 307 return( 0 ); 308 } 309 break; 310 311 case META_ST_REGEX: 312 if ( regexec( &(*msp)->ms_regex, ms->ms_dn.bv_val, 0, NULL, 0 ) == 0 ) { 313 Debug( LDAP_DEBUG_CONFIG, 314 "%s: previous rule \"dn.regex:%s\" may contain rule \"dn.subtree:%s\"\n", 315 log_prefix, (*msp)->ms_regex_pattern, ms->ms_dn.bv_val ); 316 } 317 break; 318 } 319 break; 320 321 case META_ST_SUBORDINATE: 322 switch ( (*msp)->ms_type ) { 323 case META_ST_SUBTREE: 324 if ( dnIsSuffix( &(*msp)->ms_dn, &ms->ms_dn ) ) { 325 metasubtree_t *tmp = *msp; 326 Debug( LDAP_DEBUG_CONFIG, 327 "%s: previous rule \"dn.children:%s\" is contained in rule \"dn.subtree:%s\" (replaced)\n", 328 log_prefix, pattern, (*msp)->ms_dn.bv_val ); 329 *msp = (*msp)->ms_next; 330 tmp->ms_next = NULL; 331 meta_subtree_destroy( tmp ); 332 continue; 333 334 } else if ( dnIsSuffix( &ms->ms_dn, &(*msp)->ms_dn ) && ms->ms_dn.bv_len > (*msp)->ms_dn.bv_len ) { 335 Debug( LDAP_DEBUG_CONFIG, 336 "%s: previous rule \"dn.children:%s\" contains rule \"dn.subtree:%s\" (ignored)\n", 337 log_prefix, (*msp)->ms_dn.bv_val, pattern ); 338 meta_subtree_destroy( ms ); 339 ms = NULL; 340 return( 0 ); 341 } 342 break; 343 344 case META_ST_SUBORDINATE: 345 if ( dnIsSuffix( &(*msp)->ms_dn, &ms->ms_dn ) ) { 346 metasubtree_t *tmp = *msp; 347 Debug( LDAP_DEBUG_CONFIG, 348 "%s: previous rule \"dn.children:%s\" is contained in rule \"dn.children:%s\" (replaced)\n", 349 log_prefix, pattern, (*msp)->ms_dn.bv_val ); 350 *msp = (*msp)->ms_next; 351 tmp->ms_next = NULL; 352 meta_subtree_destroy( tmp ); 353 continue; 354 355 } else if ( dnIsSuffix( &ms->ms_dn, &(*msp)->ms_dn ) ) { 356 Debug( LDAP_DEBUG_CONFIG, 357 "%s: previous rule \"dn.children:%s\" contains rule \"dn.children:%s\" (ignored)\n", 358 log_prefix, (*msp)->ms_dn.bv_val, pattern ); 359 meta_subtree_destroy( ms ); 360 ms = NULL; 361 return( 0 ); 362 } 363 break; 364 365 case META_ST_REGEX: 366 if ( regexec( &(*msp)->ms_regex, ms->ms_dn.bv_val, 0, NULL, 0 ) == 0 ) { 367 Debug( LDAP_DEBUG_CONFIG, 368 "%s: previous rule \"dn.regex:%s\" may contain rule \"dn.subtree:%s\"\n", 369 log_prefix, (*msp)->ms_regex_pattern, ms->ms_dn.bv_val ); 370 } 371 break; 372 } 373 break; 374 375 case META_ST_REGEX: 376 switch ( (*msp)->ms_type ) { 377 case META_ST_SUBTREE: 378 case META_ST_SUBORDINATE: 379 if ( regexec( &ms->ms_regex, (*msp)->ms_dn.bv_val, 0, NULL, 0 ) == 0 ) { 380 Debug( LDAP_DEBUG_CONFIG, 381 "%s: previous rule \"dn.subtree:%s\" may be contained in rule \"dn.regex:%s\"\n", 382 log_prefix, (*msp)->ms_dn.bv_val, ms->ms_regex_pattern ); 383 } 384 break; 385 386 case META_ST_REGEX: 387 /* no check possible */ 388 break; 389 } 390 break; 391 } 392 393 msp = &(*msp)->ms_next; 394 } 395 396 *msp = ms; 397 } 398 399 return 0; 400} 401 402int 403meta_back_db_config( 404 BackendDB *be, 405 const char *fname, 406 int lineno, 407 int argc, 408 char **argv ) 409{ 410 metainfo_t *mi = ( metainfo_t * )be->be_private; 411 412 assert( mi != NULL ); 413 414 /* URI of server to query */ 415 if ( strcasecmp( argv[ 0 ], "uri" ) == 0 ) { 416 int i = mi->mi_ntargets; 417 LDAPURLDesc *ludp; 418 struct berval dn; 419 int rc; 420 int c; 421 422 metatarget_t *mt; 423 424 char **uris = NULL; 425 426 if ( argc == 1 ) { 427 Debug( LDAP_DEBUG_ANY, 428 "%s: line %d: missing URI " 429 "in \"uri <protocol>://<server>[:port]/<naming context>\" line\n", 430 fname, lineno, 0 ); 431 return 1; 432 } 433 434 if ( be->be_nsuffix == NULL ) { 435 Debug( LDAP_DEBUG_ANY, 436 "%s: line %d: the suffix must be defined before any target.\n", 437 fname, lineno, 0 ); 438 return 1; 439 } 440 441 ++mi->mi_ntargets; 442 443 mi->mi_targets = ( metatarget_t ** )ch_realloc( mi->mi_targets, 444 sizeof( metatarget_t * ) * mi->mi_ntargets ); 445 if ( mi->mi_targets == NULL ) { 446 Debug( LDAP_DEBUG_ANY, 447 "%s: line %d: out of memory while storing server name" 448 " in \"uri <protocol>://<server>[:port]/<naming context>\" line\n", 449 fname, lineno, 0 ); 450 return 1; 451 } 452 453 if ( meta_back_new_target( &mi->mi_targets[ i ] ) != 0 ) { 454 Debug( LDAP_DEBUG_ANY, 455 "%s: line %d: unable to init server" 456 " in \"uri <protocol>://<server>[:port]/<naming context>\" line\n", 457 fname, lineno, 0 ); 458 return 1; 459 } 460 461 mt = mi->mi_targets[ i ]; 462 463 mt->mt_rebind_f = mi->mi_rebind_f; 464 mt->mt_urllist_f = mi->mi_urllist_f; 465 mt->mt_urllist_p = mt; 466 467 mt->mt_nretries = mi->mi_nretries; 468 mt->mt_quarantine = mi->mi_quarantine; 469 if ( META_BACK_QUARANTINE( mi ) ) { 470 ldap_pvt_thread_mutex_init( &mt->mt_quarantine_mutex ); 471 } 472 mt->mt_flags = mi->mi_flags; 473 mt->mt_version = mi->mi_version; 474#ifdef SLAPD_META_CLIENT_PR 475 mt->mt_ps = mi->mi_ps; 476#endif /* SLAPD_META_CLIENT_PR */ 477 mt->mt_network_timeout = mi->mi_network_timeout; 478 mt->mt_bind_timeout = mi->mi_bind_timeout; 479 for ( c = 0; c < SLAP_OP_LAST; c++ ) { 480 mt->mt_timeout[ c ] = mi->mi_timeout[ c ]; 481 } 482 483 for ( c = 1; c < argc; c++ ) { 484 char **tmpuris = ldap_str2charray( argv[ c ], "\t" ); 485 486 if ( tmpuris == NULL ) { 487 Debug( LDAP_DEBUG_ANY, 488 "%s: line %d: unable to parse URIs #%d" 489 " in \"uri <protocol>://<server>[:port]/<naming context>\" line\n", 490 fname, lineno, c - 1 ); 491 return 1; 492 } 493 494 if ( c == 0 ) { 495 uris = tmpuris; 496 497 } else { 498 ldap_charray_merge( &uris, tmpuris ); 499 ldap_charray_free( tmpuris ); 500 } 501 } 502 503 for ( c = 0; uris[ c ] != NULL; c++ ) { 504 char *tmpuri = NULL; 505 506 /* 507 * uri MUST be legal! 508 */ 509 if ( ldap_url_parselist_ext( &ludp, uris[ c ], "\t", 510 LDAP_PVT_URL_PARSE_NONE ) != LDAP_SUCCESS 511 || ludp->lud_next != NULL ) 512 { 513 Debug( LDAP_DEBUG_ANY, 514 "%s: line %d: unable to parse URI #%d" 515 " in \"uri <protocol>://<server>[:port]/<naming context>\" line\n", 516 fname, lineno, c ); 517 ldap_charray_free( uris ); 518 return 1; 519 } 520 521 if ( c == 0 ) { 522 523 /* 524 * uri MUST have the <dn> part! 525 */ 526 if ( ludp->lud_dn == NULL ) { 527 Debug( LDAP_DEBUG_ANY, 528 "%s: line %d: missing <naming context> " 529 " in \"uri <protocol>://<server>[:port]/<naming context>\" line\n", 530 fname, lineno, 0 ); 531 ldap_free_urllist( ludp ); 532 ldap_charray_free( uris ); 533 return 1; 534 } 535 536 /* 537 * copies and stores uri and suffix 538 */ 539 ber_str2bv( ludp->lud_dn, 0, 0, &dn ); 540 rc = dnPrettyNormal( NULL, &dn, &mt->mt_psuffix, 541 &mt->mt_nsuffix, NULL ); 542 if ( rc != LDAP_SUCCESS ) { 543 Debug( LDAP_DEBUG_ANY, "%s: line %d: " 544 "target \"%s\" DN is invalid\n", 545 fname, lineno, argv[ 1 ] ); 546 ldap_free_urllist( ludp ); 547 ldap_charray_free( uris ); 548 return( 1 ); 549 } 550 551 ludp->lud_dn[ 0 ] = '\0'; 552 553 switch ( ludp->lud_scope ) { 554 case LDAP_SCOPE_DEFAULT: 555 mt->mt_scope = LDAP_SCOPE_SUBTREE; 556 break; 557 558 case LDAP_SCOPE_SUBTREE: 559 case LDAP_SCOPE_SUBORDINATE: 560 mt->mt_scope = ludp->lud_scope; 561 break; 562 563 default: 564 Debug( LDAP_DEBUG_ANY, "%s: line %d: " 565 "invalid scope for target \"%s\"\n", 566 fname, lineno, argv[ 1 ] ); 567 ldap_free_urllist( ludp ); 568 ldap_charray_free( uris ); 569 return( 1 ); 570 } 571 572 } else { 573 /* check all, to apply the scope check on the first one */ 574 if ( ludp->lud_dn != NULL && ludp->lud_dn[ 0 ] != '\0' ) { 575 Debug( LDAP_DEBUG_ANY, "%s: line %d: " 576 "multiple URIs must have " 577 "no DN part\n", 578 fname, lineno, 0 ); 579 ldap_free_urllist( ludp ); 580 ldap_charray_free( uris ); 581 return( 1 ); 582 583 } 584 } 585 586 tmpuri = ldap_url_list2urls( ludp ); 587 ldap_free_urllist( ludp ); 588 if ( tmpuri == NULL ) { 589 Debug( LDAP_DEBUG_ANY, "%s: line %d: no memory?\n", 590 fname, lineno, 0 ); 591 ldap_charray_free( uris ); 592 return( 1 ); 593 } 594 ldap_memfree( uris[ c ] ); 595 uris[ c ] = tmpuri; 596 } 597 598 mt->mt_uri = ldap_charray2str( uris, " " ); 599 ldap_charray_free( uris ); 600 if ( mt->mt_uri == NULL) { 601 Debug( LDAP_DEBUG_ANY, "%s: line %d: no memory?\n", 602 fname, lineno, 0 ); 603 return( 1 ); 604 } 605 606 /* 607 * uri MUST be a branch of suffix! 608 */ 609 for ( c = 0; !BER_BVISNULL( &be->be_nsuffix[ c ] ); c++ ) { 610 if ( dnIsSuffix( &mt->mt_nsuffix, &be->be_nsuffix[ c ] ) ) { 611 break; 612 } 613 } 614 615 if ( BER_BVISNULL( &be->be_nsuffix[ c ] ) ) { 616 Debug( LDAP_DEBUG_ANY, 617 "%s: line %d: <naming context> of URI must be within the naming context of this database.\n", 618 fname, lineno, 0 ); 619 return 1; 620 } 621 622 /* subtree-exclude */ 623 } else if ( strcasecmp( argv[ 0 ], "subtree-exclude" ) == 0 || 624 strcasecmp( argv[ 0 ], "subtree-include" ) == 0) 625 { 626 char log_prefix[SLAP_TEXT_BUFLEN]; 627 char textbuf[SLAP_TEXT_BUFLEN]; 628 char *arg0; 629 int i = mi->mi_ntargets - 1; 630 631 if ( i < 0 ) { 632 Debug( LDAP_DEBUG_ANY, 633 "%s: line %d: need \"uri\" directive first\n", 634 fname, lineno, 0 ); 635 return 1; 636 } 637 638 if ( strcasecmp( argv[ 0 ], "subtree-exclude" ) == 0 ) { 639 arg0 = "subtree-exclude"; 640 641 } else { 642 arg0 = "subtree-include"; 643 } 644 645 snprintf( log_prefix, sizeof(log_prefix), "%s: line %d: %s", fname, lineno, arg0 ); 646 647 if ( meta_subtree_config( mi->mi_targets[ i ], argc, argv, textbuf, sizeof(textbuf), log_prefix ) ) { 648 Debug( LDAP_DEBUG_ANY, "%s: %s\n", log_prefix, textbuf, 0 ); 649 return 1; 650 } 651 652 /* default target directive */ 653 } else if ( strcasecmp( argv[ 0 ], "default-target" ) == 0 ) { 654 int i = mi->mi_ntargets - 1; 655 656 if ( argc == 1 ) { 657 if ( i < 0 ) { 658 Debug( LDAP_DEBUG_ANY, 659 "%s: line %d: \"default-target\" alone need be" 660 " inside a \"uri\" directive\n", 661 fname, lineno, 0 ); 662 return 1; 663 } 664 mi->mi_defaulttarget = i; 665 666 } else { 667 if ( strcasecmp( argv[ 1 ], "none" ) == 0 ) { 668 if ( i >= 0 ) { 669 Debug( LDAP_DEBUG_ANY, 670 "%s: line %d: \"default-target none\"" 671 " should go before uri definitions\n", 672 fname, lineno, 0 ); 673 } 674 mi->mi_defaulttarget = META_DEFAULT_TARGET_NONE; 675 676 } else { 677 678 if ( lutil_atoi( &mi->mi_defaulttarget, argv[ 1 ] ) != 0 679 || mi->mi_defaulttarget < 0 680 || mi->mi_defaulttarget >= i - 1 ) 681 { 682 Debug( LDAP_DEBUG_ANY, 683 "%s: line %d: illegal target number %d\n", 684 fname, lineno, mi->mi_defaulttarget ); 685 return 1; 686 } 687 } 688 } 689 690 /* ttl of dn cache */ 691 } else if ( strcasecmp( argv[ 0 ], "dncache-ttl" ) == 0 ) { 692 if ( argc != 2 ) { 693 Debug( LDAP_DEBUG_ANY, 694 "%s: line %d: missing ttl in \"dncache-ttl <ttl>\" line\n", 695 fname, lineno, 0 ); 696 return 1; 697 } 698 699 if ( strcasecmp( argv[ 1 ], "forever" ) == 0 ) { 700 mi->mi_cache.ttl = META_DNCACHE_FOREVER; 701 702 } else if ( strcasecmp( argv[ 1 ], "disabled" ) == 0 ) { 703 mi->mi_cache.ttl = META_DNCACHE_DISABLED; 704 705 } else { 706 unsigned long t; 707 708 if ( lutil_parse_time( argv[ 1 ], &t ) != 0 ) { 709 Debug( LDAP_DEBUG_ANY, 710 "%s: line %d: unable to parse ttl \"%s\" in \"dncache-ttl <ttl>\" line\n", 711 fname, lineno, argv[ 1 ] ); 712 return 1; 713 } 714 mi->mi_cache.ttl = (time_t)t; 715 } 716 717 /* network timeout when connecting to ldap servers */ 718 } else if ( strcasecmp( argv[ 0 ], "network-timeout" ) == 0 ) { 719 unsigned long t; 720 time_t *tp = mi->mi_ntargets ? 721 &mi->mi_targets[ mi->mi_ntargets - 1 ]->mt_network_timeout 722 : &mi->mi_network_timeout; 723 724 if ( argc != 2 ) { 725 Debug( LDAP_DEBUG_ANY, 726 "%s: line %d: missing network timeout in \"network-timeout <seconds>\" line\n", 727 fname, lineno, 0 ); 728 return 1; 729 } 730 731 if ( lutil_parse_time( argv[ 1 ], &t ) ) { 732 Debug( LDAP_DEBUG_ANY, 733 "%s: line %d: unable to parse timeout \"%s\" in \"network-timeout <seconds>\" line\n", 734 fname, lineno, argv[ 1 ] ); 735 return 1; 736 737 } 738 739 *tp = (time_t)t; 740 741 /* idle timeout when connecting to ldap servers */ 742 } else if ( strcasecmp( argv[ 0 ], "idle-timeout" ) == 0 ) { 743 unsigned long t; 744 745 switch ( argc ) { 746 case 1: 747 Debug( LDAP_DEBUG_ANY, 748 "%s: line %d: missing timeout value in \"idle-timeout <seconds>\" line\n", 749 fname, lineno, 0 ); 750 return 1; 751 case 2: 752 break; 753 default: 754 Debug( LDAP_DEBUG_ANY, 755 "%s: line %d: extra cruft after timeout value in \"idle-timeout <seconds>\" line\n", 756 fname, lineno, 0 ); 757 return 1; 758 } 759 760 if ( lutil_parse_time( argv[ 1 ], &t ) ) { 761 Debug( LDAP_DEBUG_ANY, 762 "%s: line %d: unable to parse timeout \"%s\" in \"idle-timeout <seconds>\" line\n", 763 fname, lineno, argv[ 1 ] ); 764 return 1; 765 766 } 767 768 mi->mi_idle_timeout = (time_t)t; 769 770 /* conn ttl */ 771 } else if ( strcasecmp( argv[ 0 ], "conn-ttl" ) == 0 ) { 772 unsigned long t; 773 774 switch ( argc ) { 775 case 1: 776 Debug( LDAP_DEBUG_ANY, 777 "%s: line %d: missing ttl value in \"conn-ttl <seconds>\" line\n", 778 fname, lineno, 0 ); 779 return 1; 780 case 2: 781 break; 782 default: 783 Debug( LDAP_DEBUG_ANY, 784 "%s: line %d: extra cruft after ttl value in \"conn-ttl <seconds>\" line\n", 785 fname, lineno, 0 ); 786 return 1; 787 } 788 789 if ( lutil_parse_time( argv[ 1 ], &t ) ) { 790 Debug( LDAP_DEBUG_ANY, 791 "%s: line %d: unable to parse ttl \"%s\" in \"conn-ttl <seconds>\" line\n", 792 fname, lineno, argv[ 1 ] ); 793 return 1; 794 795 } 796 797 mi->mi_conn_ttl = (time_t)t; 798 799 /* bind timeout when connecting to ldap servers */ 800 } else if ( strcasecmp( argv[ 0 ], "bind-timeout" ) == 0 ) { 801 unsigned long t; 802 struct timeval *tp = mi->mi_ntargets ? 803 &mi->mi_targets[ mi->mi_ntargets - 1 ]->mt_bind_timeout 804 : &mi->mi_bind_timeout; 805 806 switch ( argc ) { 807 case 1: 808 Debug( LDAP_DEBUG_ANY, 809 "%s: line %d: missing timeout value in \"bind-timeout <microseconds>\" line\n", 810 fname, lineno, 0 ); 811 return 1; 812 case 2: 813 break; 814 default: 815 Debug( LDAP_DEBUG_ANY, 816 "%s: line %d: extra cruft after timeout value in \"bind-timeout <microseconds>\" line\n", 817 fname, lineno, 0 ); 818 return 1; 819 } 820 821 if ( lutil_atoul( &t, argv[ 1 ] ) != 0 ) { 822 Debug( LDAP_DEBUG_ANY, 823 "%s: line %d: unable to parse timeout \"%s\" in \"bind-timeout <microseconds>\" line\n", 824 fname, lineno, argv[ 1 ] ); 825 return 1; 826 827 } 828 829 tp->tv_sec = t/1000000; 830 tp->tv_usec = t%1000000; 831 832 /* name to use for meta_back_group */ 833 } else if ( strcasecmp( argv[ 0 ], "acl-authcDN" ) == 0 834 || strcasecmp( argv[ 0 ], "binddn" ) == 0 ) 835 { 836 int i = mi->mi_ntargets - 1; 837 struct berval dn; 838 839 if ( i < 0 ) { 840 Debug( LDAP_DEBUG_ANY, 841 "%s: line %d: need \"uri\" directive first\n", 842 fname, lineno, 0 ); 843 return 1; 844 } 845 846 if ( argc != 2 ) { 847 Debug( LDAP_DEBUG_ANY, 848 "%s: line %d: missing name in \"binddn <name>\" line\n", 849 fname, lineno, 0 ); 850 return 1; 851 } 852 853 if ( strcasecmp( argv[ 0 ], "binddn" ) == 0 ) { 854 Debug( LDAP_DEBUG_ANY, "%s: line %d: " 855 "\"binddn\" statement is deprecated; " 856 "use \"acl-authcDN\" instead\n", 857 fname, lineno, 0 ); 858 /* FIXME: some day we'll need to throw an error */ 859 } 860 861 ber_str2bv( argv[ 1 ], 0, 0, &dn ); 862 if ( dnNormalize( 0, NULL, NULL, &dn, &mi->mi_targets[ i ]->mt_binddn, 863 NULL ) != LDAP_SUCCESS ) 864 { 865 Debug( LDAP_DEBUG_ANY, "%s: line %d: " 866 "bind DN '%s' is invalid\n", 867 fname, lineno, argv[ 1 ] ); 868 return( 1 ); 869 } 870 871 /* password to use for meta_back_group */ 872 } else if ( strcasecmp( argv[ 0 ], "acl-passwd" ) == 0 873 || strcasecmp( argv[ 0 ], "bindpw" ) == 0 ) 874 { 875 int i = mi->mi_ntargets - 1; 876 877 if ( i < 0 ) { 878 Debug( LDAP_DEBUG_ANY, 879 "%s: line %d: need \"uri\" directive first\n", 880 fname, lineno, 0 ); 881 return 1; 882 } 883 884 if ( argc != 2 ) { 885 Debug( LDAP_DEBUG_ANY, 886 "%s: line %d: missing password in \"bindpw <password>\" line\n", 887 fname, lineno, 0 ); 888 return 1; 889 } 890 891 if ( strcasecmp( argv[ 0 ], "bindpw" ) == 0 ) { 892 Debug( LDAP_DEBUG_ANY, "%s: line %d: " 893 "\"bindpw\" statement is deprecated; " 894 "use \"acl-passwd\" instead\n", 895 fname, lineno, 0 ); 896 /* FIXME: some day we'll need to throw an error */ 897 } 898 899 ber_str2bv( argv[ 1 ], 0L, 1, &mi->mi_targets[ i ]->mt_bindpw ); 900 901 /* save bind creds for referral rebinds? */ 902 } else if ( strcasecmp( argv[ 0 ], "rebind-as-user" ) == 0 ) { 903 unsigned *flagsp = mi->mi_ntargets ? 904 &mi->mi_targets[ mi->mi_ntargets - 1 ]->mt_flags 905 : &mi->mi_flags; 906 907 if ( argc > 2 ) { 908 Debug( LDAP_DEBUG_ANY, 909 "%s: line %d: \"rebind-as-user {NO|yes}\" takes 1 argument.\n", 910 fname, lineno, 0 ); 911 return( 1 ); 912 } 913 914 if ( argc == 1 ) { 915 Debug( LDAP_DEBUG_ANY, 916 "%s: line %d: deprecated use of \"rebind-as-user {FALSE|true}\" with no arguments.\n", 917 fname, lineno, 0 ); 918 *flagsp |= LDAP_BACK_F_SAVECRED; 919 920 } else { 921 switch ( check_true_false( argv[ 1 ] ) ) { 922 case 0: 923 *flagsp &= ~LDAP_BACK_F_SAVECRED; 924 break; 925 926 case 1: 927 *flagsp |= LDAP_BACK_F_SAVECRED; 928 break; 929 930 default: 931 Debug( LDAP_DEBUG_ANY, 932 "%s: line %d: \"rebind-as-user {FALSE|true}\" unknown argument \"%s\".\n", 933 fname, lineno, argv[ 1 ] ); 934 return 1; 935 } 936 } 937 938 } else if ( strcasecmp( argv[ 0 ], "chase-referrals" ) == 0 ) { 939 unsigned *flagsp = mi->mi_ntargets ? 940 &mi->mi_targets[ mi->mi_ntargets - 1 ]->mt_flags 941 : &mi->mi_flags; 942 943 if ( argc != 2 ) { 944 Debug( LDAP_DEBUG_ANY, 945 "%s: line %d: \"chase-referrals {TRUE|false}\" needs 1 argument.\n", 946 fname, lineno, 0 ); 947 return( 1 ); 948 } 949 950 /* this is the default; we add it because the default might change... */ 951 switch ( check_true_false( argv[ 1 ] ) ) { 952 case 1: 953 *flagsp |= LDAP_BACK_F_CHASE_REFERRALS; 954 break; 955 956 case 0: 957 *flagsp &= ~LDAP_BACK_F_CHASE_REFERRALS; 958 break; 959 960 default: 961 Debug( LDAP_DEBUG_ANY, 962 "%s: line %d: \"chase-referrals {TRUE|false}\": unknown argument \"%s\".\n", 963 fname, lineno, argv[ 1 ] ); 964 return( 1 ); 965 } 966 967 } else if ( strcasecmp( argv[ 0 ], "tls" ) == 0 ) { 968 unsigned *flagsp = mi->mi_ntargets ? 969 &mi->mi_targets[ mi->mi_ntargets - 1 ]->mt_flags 970 : &mi->mi_flags; 971 972 /* start */ 973 if ( strcasecmp( argv[ 1 ], "start" ) == 0 ) { 974 *flagsp |= ( LDAP_BACK_F_USE_TLS | LDAP_BACK_F_TLS_CRITICAL ); 975 976 /* try start tls */ 977 } else if ( strcasecmp( argv[ 1 ], "try-start" ) == 0 ) { 978 *flagsp &= ~LDAP_BACK_F_TLS_CRITICAL; 979 *flagsp |= LDAP_BACK_F_USE_TLS; 980 981 /* propagate start tls */ 982 } else if ( strcasecmp( argv[ 1 ], "propagate" ) == 0 ) { 983 *flagsp |= ( LDAP_BACK_F_PROPAGATE_TLS | LDAP_BACK_F_TLS_CRITICAL ); 984 985 /* try start tls */ 986 } else if ( strcasecmp( argv[ 1 ], "try-propagate" ) == 0 ) { 987 *flagsp &= ~LDAP_BACK_F_TLS_CRITICAL; 988 *flagsp |= LDAP_BACK_F_PROPAGATE_TLS; 989 990 } else { 991 Debug( LDAP_DEBUG_ANY, 992 "%s: line %d: \"tls <what>\": unknown argument \"%s\".\n", 993 fname, lineno, argv[ 1 ] ); 994 return( 1 ); 995 } 996 997 if ( argc > 2 ) { 998 metatarget_t *mt = NULL; 999 int i; 1000 1001 if ( mi->mi_ntargets - 1 < 0 ) { 1002 Debug( LDAP_DEBUG_ANY, 1003 "%s: line %d: need \"uri\" directive first\n", 1004 fname, lineno, 0 ); 1005 return 1; 1006 } 1007 1008 mt = mi->mi_targets[ mi->mi_ntargets - 1 ]; 1009 1010 for ( i = 2; i < argc; i++ ) { 1011 if ( bindconf_tls_parse( argv[i], &mt->mt_tls )) 1012 return 1; 1013 } 1014 bindconf_tls_defaults( &mt->mt_tls ); 1015 } 1016 1017 } else if ( strcasecmp( argv[ 0 ], "t-f-support" ) == 0 ) { 1018 unsigned *flagsp = mi->mi_ntargets ? 1019 &mi->mi_targets[ mi->mi_ntargets - 1 ]->mt_flags 1020 : &mi->mi_flags; 1021 1022 if ( argc != 2 ) { 1023 Debug( LDAP_DEBUG_ANY, 1024 "%s: line %d: \"t-f-support {FALSE|true|discover}\" needs 1 argument.\n", 1025 fname, lineno, 0 ); 1026 return( 1 ); 1027 } 1028 1029 switch ( check_true_false( argv[ 1 ] ) ) { 1030 case 0: 1031 *flagsp &= ~LDAP_BACK_F_T_F_MASK2; 1032 break; 1033 1034 case 1: 1035 *flagsp |= LDAP_BACK_F_T_F; 1036 break; 1037 1038 default: 1039 if ( strcasecmp( argv[ 1 ], "discover" ) == 0 ) { 1040 *flagsp |= LDAP_BACK_F_T_F_DISCOVER; 1041 1042 } else { 1043 Debug( LDAP_DEBUG_ANY, 1044 "%s: line %d: unknown value \"%s\" for \"t-f-support {no|yes|discover}\".\n", 1045 fname, lineno, argv[ 1 ] ); 1046 return 1; 1047 } 1048 break; 1049 } 1050 1051 /* onerr? */ 1052 } else if ( strcasecmp( argv[ 0 ], "onerr" ) == 0 ) { 1053 if ( argc != 2 ) { 1054 Debug( LDAP_DEBUG_ANY, 1055 "%s: line %d: \"onerr {CONTINUE|report|stop}\" takes 1 argument\n", 1056 fname, lineno, 0 ); 1057 return( 1 ); 1058 } 1059 1060 if ( strcasecmp( argv[ 1 ], "continue" ) == 0 ) { 1061 mi->mi_flags &= ~META_BACK_F_ONERR_MASK; 1062 1063 } else if ( strcasecmp( argv[ 1 ], "stop" ) == 0 ) { 1064 mi->mi_flags |= META_BACK_F_ONERR_STOP; 1065 1066 } else if ( strcasecmp( argv[ 1 ], "report" ) == 0 ) { 1067 mi->mi_flags |= META_BACK_F_ONERR_REPORT; 1068 1069 } else { 1070 Debug( LDAP_DEBUG_ANY, 1071 "%s: line %d: \"onerr {CONTINUE|report|stop}\": invalid arg \"%s\".\n", 1072 fname, lineno, argv[ 1 ] ); 1073 return 1; 1074 } 1075 1076 /* bind-defer? */ 1077 } else if ( strcasecmp( argv[ 0 ], "pseudoroot-bind-defer" ) == 0 1078 || strcasecmp( argv[ 0 ], "root-bind-defer" ) == 0 ) 1079 { 1080 if ( argc != 2 ) { 1081 Debug( LDAP_DEBUG_ANY, 1082 "%s: line %d: \"[pseudo]root-bind-defer {TRUE|false}\" takes 1 argument\n", 1083 fname, lineno, 0 ); 1084 return( 1 ); 1085 } 1086 1087 switch ( check_true_false( argv[ 1 ] ) ) { 1088 case 0: 1089 mi->mi_flags &= ~META_BACK_F_DEFER_ROOTDN_BIND; 1090 break; 1091 1092 case 1: 1093 mi->mi_flags |= META_BACK_F_DEFER_ROOTDN_BIND; 1094 break; 1095 1096 default: 1097 Debug( LDAP_DEBUG_ANY, 1098 "%s: line %d: \"[pseudo]root-bind-defer {TRUE|false}\": invalid arg \"%s\".\n", 1099 fname, lineno, argv[ 1 ] ); 1100 return 1; 1101 } 1102 1103 /* single-conn? */ 1104 } else if ( strcasecmp( argv[ 0 ], "single-conn" ) == 0 ) { 1105 if ( argc != 2 ) { 1106 Debug( LDAP_DEBUG_ANY, 1107 "%s: line %d: \"single-conn {FALSE|true}\" takes 1 argument\n", 1108 fname, lineno, 0 ); 1109 return( 1 ); 1110 } 1111 1112 if ( mi->mi_ntargets > 0 ) { 1113 Debug( LDAP_DEBUG_ANY, 1114 "%s: line %d: \"single-conn\" must appear before target definitions\n", 1115 fname, lineno, 0 ); 1116 return( 1 ); 1117 } 1118 1119 switch ( check_true_false( argv[ 1 ] ) ) { 1120 case 0: 1121 mi->mi_flags &= ~LDAP_BACK_F_SINGLECONN; 1122 break; 1123 1124 case 1: 1125 mi->mi_flags |= LDAP_BACK_F_SINGLECONN; 1126 break; 1127 1128 default: 1129 Debug( LDAP_DEBUG_ANY, 1130 "%s: line %d: \"single-conn {FALSE|true}\": invalid arg \"%s\".\n", 1131 fname, lineno, argv[ 1 ] ); 1132 return 1; 1133 } 1134 1135 /* use-temporaries? */ 1136 } else if ( strcasecmp( argv[ 0 ], "use-temporary-conn" ) == 0 ) { 1137 if ( argc != 2 ) { 1138 Debug( LDAP_DEBUG_ANY, 1139 "%s: line %d: \"use-temporary-conn {FALSE|true}\" takes 1 argument\n", 1140 fname, lineno, 0 ); 1141 return( 1 ); 1142 } 1143 1144 if ( mi->mi_ntargets > 0 ) { 1145 Debug( LDAP_DEBUG_ANY, 1146 "%s: line %d: \"use-temporary-conn\" must appear before target definitions\n", 1147 fname, lineno, 0 ); 1148 return( 1 ); 1149 } 1150 1151 switch ( check_true_false( argv[ 1 ] ) ) { 1152 case 0: 1153 mi->mi_flags &= ~LDAP_BACK_F_USE_TEMPORARIES; 1154 break; 1155 1156 case 1: 1157 mi->mi_flags |= LDAP_BACK_F_USE_TEMPORARIES; 1158 break; 1159 1160 default: 1161 Debug( LDAP_DEBUG_ANY, 1162 "%s: line %d: \"use-temporary-conn {FALSE|true}\": invalid arg \"%s\".\n", 1163 fname, lineno, argv[ 1 ] ); 1164 return 1; 1165 } 1166 1167 /* privileged connections pool max size ? */ 1168 } else if ( strcasecmp( argv[ 0 ], "conn-pool-max" ) == 0 ) { 1169 if ( argc != 2 ) { 1170 Debug( LDAP_DEBUG_ANY, 1171 "%s: line %d: \"conn-pool-max <n>\" takes 1 argument\n", 1172 fname, lineno, 0 ); 1173 return( 1 ); 1174 } 1175 1176 if ( mi->mi_ntargets > 0 ) { 1177 Debug( LDAP_DEBUG_ANY, 1178 "%s: line %d: \"conn-pool-max\" must appear before target definitions\n", 1179 fname, lineno, 0 ); 1180 return( 1 ); 1181 } 1182 1183 if ( lutil_atoi( &mi->mi_conn_priv_max, argv[1] ) 1184 || mi->mi_conn_priv_max < LDAP_BACK_CONN_PRIV_MIN 1185 || mi->mi_conn_priv_max > LDAP_BACK_CONN_PRIV_MAX ) 1186 { 1187 Debug( LDAP_DEBUG_ANY, 1188 "%s: line %d: \"conn-pool-max <n>\": invalid arg \"%s\".\n", 1189 fname, lineno, argv[ 1 ] ); 1190 return 1; 1191 } 1192 1193 } else if ( strcasecmp( argv[ 0 ], "cancel" ) == 0 ) { 1194 unsigned flag = 0; 1195 unsigned *flagsp = mi->mi_ntargets ? 1196 &mi->mi_targets[ mi->mi_ntargets - 1 ]->mt_flags 1197 : &mi->mi_flags; 1198 1199 if ( argc != 2 ) { 1200 Debug( LDAP_DEBUG_ANY, 1201 "%s: line %d: \"cancel {abandon|ignore|exop}\" takes 1 argument\n", 1202 fname, lineno, 0 ); 1203 return( 1 ); 1204 } 1205 1206 if ( strcasecmp( argv[ 1 ], "abandon" ) == 0 ) { 1207 flag = LDAP_BACK_F_CANCEL_ABANDON; 1208 1209 } else if ( strcasecmp( argv[ 1 ], "ignore" ) == 0 ) { 1210 flag = LDAP_BACK_F_CANCEL_IGNORE; 1211 1212 } else if ( strcasecmp( argv[ 1 ], "exop" ) == 0 ) { 1213 flag = LDAP_BACK_F_CANCEL_EXOP; 1214 1215 } else if ( strcasecmp( argv[ 1 ], "exop-discover" ) == 0 ) { 1216 flag = LDAP_BACK_F_CANCEL_EXOP_DISCOVER; 1217 1218 } else { 1219 Debug( LDAP_DEBUG_ANY, 1220 "%s: line %d: \"cancel {abandon|ignore|exop[-discover]}\": unknown mode \"%s\" \n", 1221 fname, lineno, argv[ 1 ] ); 1222 return( 1 ); 1223 } 1224 1225 *flagsp &= ~LDAP_BACK_F_CANCEL_MASK2; 1226 *flagsp |= flag; 1227 1228 } else if ( strcasecmp( argv[ 0 ], "timeout" ) == 0 ) { 1229 char *sep; 1230 time_t *tv = mi->mi_ntargets ? 1231 mi->mi_targets[ mi->mi_ntargets - 1 ]->mt_timeout 1232 : mi->mi_timeout; 1233 int c; 1234 1235 if ( argc < 2 ) { 1236 Debug( LDAP_DEBUG_ANY, 1237 "%s: line %d: \"timeout [{add|bind|delete|modify|modrdn}=]<val> [...]\" takes at least 1 argument\n", 1238 fname, lineno, 0 ); 1239 return( 1 ); 1240 } 1241 1242 for ( c = 1; c < argc; c++ ) { 1243 time_t *t = NULL; 1244 unsigned long val; 1245 1246 sep = strchr( argv[ c ], '=' ); 1247 if ( sep != NULL ) { 1248 size_t len = sep - argv[ c ]; 1249 1250 if ( strncasecmp( argv[ c ], "bind", len ) == 0 ) { 1251 t = &tv[ SLAP_OP_BIND ]; 1252 /* unbind makes little sense */ 1253 } else if ( strncasecmp( argv[ c ], "add", len ) == 0 ) { 1254 t = &tv[ SLAP_OP_ADD ]; 1255 } else if ( strncasecmp( argv[ c ], "delete", len ) == 0 ) { 1256 t = &tv[ SLAP_OP_DELETE ]; 1257 } else if ( strncasecmp( argv[ c ], "modrdn", len ) == 0 ) { 1258 t = &tv[ SLAP_OP_MODRDN ]; 1259 } else if ( strncasecmp( argv[ c ], "modify", len ) == 0 ) { 1260 t = &tv[ SLAP_OP_MODIFY ]; 1261 } else if ( strncasecmp( argv[ c ], "compare", len ) == 0 ) { 1262 t = &tv[ SLAP_OP_COMPARE ]; 1263 } else if ( strncasecmp( argv[ c ], "search", len ) == 0 ) { 1264 t = &tv[ SLAP_OP_SEARCH ]; 1265 /* abandon makes little sense */ 1266#if 0 /* not implemented yet */ 1267 } else if ( strncasecmp( argv[ c ], "extended", len ) == 0 ) { 1268 t = &tv[ SLAP_OP_EXTENDED ]; 1269#endif 1270 } else { 1271 char buf[ SLAP_TEXT_BUFLEN ]; 1272 snprintf( buf, sizeof( buf ), 1273 "unknown/unhandled operation \"%s\" for timeout #%d", 1274 argv[ c ], c - 1 ); 1275 Debug( LDAP_DEBUG_ANY, 1276 "%s: line %d: %s.\n", 1277 fname, lineno, buf ); 1278 return 1; 1279 } 1280 sep++; 1281 1282 } else { 1283 sep = argv[ c ]; 1284 } 1285 1286 if ( lutil_parse_time( sep, &val ) != 0 ) { 1287 Debug( LDAP_DEBUG_ANY, 1288 "%s: line %d: unable to parse value \"%s\" for timeout.\n", 1289 fname, lineno, sep ); 1290 return 1; 1291 } 1292 1293 if ( t ) { 1294 *t = (time_t)val; 1295 1296 } else { 1297 int i; 1298 1299 for ( i = 0; i < SLAP_OP_LAST; i++ ) { 1300 tv[ i ] = (time_t)val; 1301 } 1302 } 1303 } 1304 1305 /* name to use as pseudo-root dn */ 1306 } else if ( strcasecmp( argv[ 0 ], "pseudorootdn" ) == 0 ) { 1307 int i = mi->mi_ntargets - 1; 1308 1309 if ( i < 0 ) { 1310 Debug( LDAP_DEBUG_ANY, 1311 "%s: line %d: need \"uri\" directive first\n", 1312 fname, lineno, 0 ); 1313 return 1; 1314 } 1315 1316 if ( argc != 2 ) { 1317 Debug( LDAP_DEBUG_ANY, 1318 "%s: line %d: missing name in \"pseudorootdn <name>\" line\n", 1319 fname, lineno, 0 ); 1320 return 1; 1321 } 1322 1323 /* 1324 * exact replacement: 1325 * 1326 1327idassert-bind bindmethod=simple 1328 binddn=<pseudorootdn> 1329 credentials=<pseudorootpw> 1330 mode=none 1331 flags=non-prescriptive 1332idassert-authzFrom "dn:<rootdn>" 1333 1334 * so that only when authc'd as <rootdn> the proxying occurs 1335 * rebinding as the <pseudorootdn> without proxyAuthz. 1336 */ 1337 1338 Debug( LDAP_DEBUG_ANY, 1339 "%s: line %d: \"pseudorootdn\", \"pseudorootpw\" are no longer supported; " 1340 "use \"idassert-bind\" and \"idassert-authzFrom\" instead.\n", 1341 fname, lineno, 0 ); 1342 1343 { 1344 char binddn[ SLAP_TEXT_BUFLEN ]; 1345 char *cargv[] = { 1346 "idassert-bind", 1347 "bindmethod=simple", 1348 NULL, 1349 "mode=none", 1350 "flags=non-prescriptive", 1351 NULL 1352 }; 1353 int cargc = 5; 1354 int rc; 1355 1356 if ( BER_BVISNULL( &be->be_rootndn ) ) { 1357 Debug( LDAP_DEBUG_ANY, "%s: line %d: \"pseudorootpw\": \"rootdn\" must be defined first.\n", 1358 fname, lineno, 0 ); 1359 return 1; 1360 } 1361 1362 if ( sizeof( binddn ) <= (unsigned) snprintf( binddn, 1363 sizeof( binddn ), "binddn=%s", argv[ 1 ] )) 1364 { 1365 Debug( LDAP_DEBUG_ANY, "%s: line %d: \"pseudorootdn\" too long.\n", 1366 fname, lineno, 0 ); 1367 return 1; 1368 } 1369 cargv[ 2 ] = binddn; 1370 1371 rc = mi->mi_ldap_extra->idassert_parse_cf( fname, lineno, cargc, cargv, &mi->mi_targets[ mi->mi_ntargets - 1 ]->mt_idassert ); 1372 if ( rc == 0 ) { 1373 struct berval bv; 1374 1375 if ( mi->mi_targets[ mi->mi_ntargets - 1 ]->mt_idassert_authz != NULL ) { 1376 Debug( LDAP_DEBUG_ANY, "%s: line %d: \"idassert-authzFrom\" already defined (discarded).\n", 1377 fname, lineno, 0 ); 1378 ber_bvarray_free( mi->mi_targets[ mi->mi_ntargets - 1 ]->mt_idassert_authz ); 1379 mi->mi_targets[ mi->mi_ntargets - 1 ]->mt_idassert_authz = NULL; 1380 } 1381 1382 assert( !BER_BVISNULL( &mi->mi_targets[ mi->mi_ntargets - 1 ]->mt_idassert_authcDN ) ); 1383 1384 bv.bv_len = STRLENOF( "dn:" ) + be->be_rootndn.bv_len; 1385 bv.bv_val = ber_memalloc( bv.bv_len + 1 ); 1386 AC_MEMCPY( bv.bv_val, "dn:", STRLENOF( "dn:" ) ); 1387 AC_MEMCPY( &bv.bv_val[ STRLENOF( "dn:" ) ], be->be_rootndn.bv_val, be->be_rootndn.bv_len + 1 ); 1388 1389 ber_bvarray_add( &mi->mi_targets[ mi->mi_ntargets - 1 ]->mt_idassert_authz, &bv ); 1390 } 1391 1392 return rc; 1393 } 1394 1395 /* password to use as pseudo-root */ 1396 } else if ( strcasecmp( argv[ 0 ], "pseudorootpw" ) == 0 ) { 1397 int i = mi->mi_ntargets - 1; 1398 1399 if ( i < 0 ) { 1400 Debug( LDAP_DEBUG_ANY, 1401 "%s: line %d: need \"uri\" directive first\n", 1402 fname, lineno, 0 ); 1403 return 1; 1404 } 1405 1406 if ( argc != 2 ) { 1407 Debug( LDAP_DEBUG_ANY, 1408 "%s: line %d: missing password in \"pseudorootpw <password>\" line\n", 1409 fname, lineno, 0 ); 1410 return 1; 1411 } 1412 1413 Debug( LDAP_DEBUG_ANY, 1414 "%s: line %d: \"pseudorootdn\", \"pseudorootpw\" are no longer supported; " 1415 "use \"idassert-bind\" and \"idassert-authzFrom\" instead.\n", 1416 fname, lineno, 0 ); 1417 1418 if ( BER_BVISNULL( &mi->mi_targets[ i ]->mt_idassert_authcDN ) ) { 1419 Debug( LDAP_DEBUG_ANY, "%s: line %d: \"pseudorootpw\": \"pseudorootdn\" must be defined first.\n", 1420 fname, lineno, 0 ); 1421 return 1; 1422 } 1423 1424 if ( !BER_BVISNULL( &mi->mi_targets[ i ]->mt_idassert_passwd ) ) { 1425 memset( mi->mi_targets[ i ]->mt_idassert_passwd.bv_val, 0, 1426 mi->mi_targets[ i ]->mt_idassert_passwd.bv_len ); 1427 ber_memfree( mi->mi_targets[ i ]->mt_idassert_passwd.bv_val ); 1428 } 1429 ber_str2bv( argv[ 1 ], 0, 1, &mi->mi_targets[ i ]->mt_idassert_passwd ); 1430 1431 /* idassert-bind */ 1432 } else if ( strcasecmp( argv[ 0 ], "idassert-bind" ) == 0 ) { 1433 if ( mi->mi_ntargets == 0 ) { 1434 Debug( LDAP_DEBUG_ANY, 1435 "%s: line %d: \"idassert-bind\" " 1436 "must appear inside a target specification.\n", 1437 fname, lineno, 0 ); 1438 return 1; 1439 } 1440 1441 return mi->mi_ldap_extra->idassert_parse_cf( fname, lineno, argc, argv, &mi->mi_targets[ mi->mi_ntargets - 1 ]->mt_idassert ); 1442 1443 /* idassert-authzFrom */ 1444 } else if ( strcasecmp( argv[ 0 ], "idassert-authzFrom" ) == 0 ) { 1445 if ( mi->mi_ntargets == 0 ) { 1446 Debug( LDAP_DEBUG_ANY, 1447 "%s: line %d: \"idassert-bind\" " 1448 "must appear inside a target specification.\n", 1449 fname, lineno, 0 ); 1450 return 1; 1451 } 1452 1453 switch ( argc ) { 1454 case 2: 1455 break; 1456 1457 case 1: 1458 Debug( LDAP_DEBUG_ANY, 1459 "%s: line %d: missing <id> in \"idassert-authzFrom <id>\".\n", 1460 fname, lineno, 0 ); 1461 return 1; 1462 1463 default: 1464 Debug( LDAP_DEBUG_ANY, 1465 "%s: line %d: extra cruft after <id> in \"idassert-authzFrom <id>\".\n", 1466 fname, lineno, 0 ); 1467 return 1; 1468 } 1469 1470 return mi->mi_ldap_extra->idassert_authzfrom_parse_cf( fname, lineno, argv[ 1 ], &mi->mi_targets[ mi->mi_ntargets - 1 ]->mt_idassert ); 1471 1472 /* quarantine */ 1473 } else if ( strcasecmp( argv[ 0 ], "quarantine" ) == 0 ) { 1474 char buf[ SLAP_TEXT_BUFLEN ] = { '\0' }; 1475 slap_retry_info_t *ri = mi->mi_ntargets ? 1476 &mi->mi_targets[ mi->mi_ntargets - 1 ]->mt_quarantine 1477 : &mi->mi_quarantine; 1478 1479 if ( ( mi->mi_ntargets == 0 && META_BACK_QUARANTINE( mi ) ) 1480 || ( mi->mi_ntargets > 0 && META_BACK_TGT_QUARANTINE( mi->mi_targets[ mi->mi_ntargets - 1 ] ) ) ) 1481 { 1482 Debug( LDAP_DEBUG_ANY, 1483 "%s: line %d: quarantine already defined.\n", 1484 fname, lineno, 0 ); 1485 return 1; 1486 } 1487 1488 switch ( argc ) { 1489 case 2: 1490 break; 1491 1492 case 1: 1493 Debug( LDAP_DEBUG_ANY, 1494 "%s: line %d: missing arg in \"quarantine <pattern list>\".\n", 1495 fname, lineno, 0 ); 1496 return 1; 1497 1498 default: 1499 Debug( LDAP_DEBUG_ANY, 1500 "%s: line %d: extra cruft after \"quarantine <pattern list>\".\n", 1501 fname, lineno, 0 ); 1502 return 1; 1503 } 1504 1505 if ( ri != &mi->mi_quarantine ) { 1506 ri->ri_interval = NULL; 1507 ri->ri_num = NULL; 1508 } 1509 1510 if ( mi->mi_ntargets > 0 && !META_BACK_QUARANTINE( mi ) ) { 1511 ldap_pvt_thread_mutex_init( &mi->mi_targets[ mi->mi_ntargets - 1 ]->mt_quarantine_mutex ); 1512 } 1513 1514 if ( mi->mi_ldap_extra->retry_info_parse( argv[ 1 ], ri, buf, sizeof( buf ) ) ) { 1515 Debug( LDAP_DEBUG_ANY, 1516 "%s line %d: %s.\n", 1517 fname, lineno, buf ); 1518 return 1; 1519 } 1520 1521 if ( mi->mi_ntargets == 0 ) { 1522 mi->mi_flags |= LDAP_BACK_F_QUARANTINE; 1523 1524 } else { 1525 mi->mi_targets[ mi->mi_ntargets - 1 ]->mt_flags |= LDAP_BACK_F_QUARANTINE; 1526 } 1527 1528#ifdef SLAP_CONTROL_X_SESSION_TRACKING 1529 /* session tracking request */ 1530 } else if ( strcasecmp( argv[ 0 ], "session-tracking-request" ) == 0 ) { 1531 unsigned *flagsp = mi->mi_ntargets ? 1532 &mi->mi_targets[ mi->mi_ntargets - 1 ]->mt_flags 1533 : &mi->mi_flags; 1534 1535 if ( argc != 2 ) { 1536 Debug( LDAP_DEBUG_ANY, 1537 "%s: line %d: \"session-tracking-request {TRUE|false}\" needs 1 argument.\n", 1538 fname, lineno, 0 ); 1539 return( 1 ); 1540 } 1541 1542 /* this is the default; we add it because the default might change... */ 1543 switch ( check_true_false( argv[ 1 ] ) ) { 1544 case 1: 1545 *flagsp |= LDAP_BACK_F_ST_REQUEST; 1546 break; 1547 1548 case 0: 1549 *flagsp &= ~LDAP_BACK_F_ST_REQUEST; 1550 break; 1551 1552 default: 1553 Debug( LDAP_DEBUG_ANY, 1554 "%s: line %d: \"session-tracking-request {TRUE|false}\": unknown argument \"%s\".\n", 1555 fname, lineno, argv[ 1 ] ); 1556 return( 1 ); 1557 } 1558#endif /* SLAP_CONTROL_X_SESSION_TRACKING */ 1559 1560 /* dn massaging */ 1561 } else if ( strcasecmp( argv[ 0 ], "suffixmassage" ) == 0 ) { 1562 BackendDB *tmp_bd; 1563 int i = mi->mi_ntargets - 1, c, rc; 1564 struct berval dn, nvnc, pvnc, nrnc, prnc; 1565 1566 if ( i < 0 ) { 1567 Debug( LDAP_DEBUG_ANY, 1568 "%s: line %d: need \"uri\" directive first\n", 1569 fname, lineno, 0 ); 1570 return 1; 1571 } 1572 1573 /* 1574 * syntax: 1575 * 1576 * suffixmassage <suffix> <massaged suffix> 1577 * 1578 * the <suffix> field must be defined as a valid suffix 1579 * (or suffixAlias?) for the current database; 1580 * the <massaged suffix> shouldn't have already been 1581 * defined as a valid suffix or suffixAlias for the 1582 * current server 1583 */ 1584 if ( argc != 3 ) { 1585 Debug( LDAP_DEBUG_ANY, 1586 "%s: line %d: syntax is \"suffixMassage <suffix> <massaged suffix>\"\n", 1587 fname, lineno, 0 ); 1588 return 1; 1589 } 1590 1591 ber_str2bv( argv[ 1 ], 0, 0, &dn ); 1592 if ( dnPrettyNormal( NULL, &dn, &pvnc, &nvnc, NULL ) != LDAP_SUCCESS ) { 1593 Debug( LDAP_DEBUG_ANY, "%s: line %d: " 1594 "suffix \"%s\" is invalid\n", 1595 fname, lineno, argv[ 1 ] ); 1596 return 1; 1597 } 1598 1599 for ( c = 0; !BER_BVISNULL( &be->be_nsuffix[ c ] ); c++ ) { 1600 if ( dnIsSuffix( &nvnc, &be->be_nsuffix[ 0 ] ) ) { 1601 break; 1602 } 1603 } 1604 1605 if ( BER_BVISNULL( &be->be_nsuffix[ c ] ) ) { 1606 Debug( LDAP_DEBUG_ANY, "%s: line %d: " 1607 "<suffix> \"%s\" must be within the database naming context, in " 1608 "\"suffixMassage <suffix> <massaged suffix>\"\n", 1609 fname, lineno, pvnc.bv_val ); 1610 free( pvnc.bv_val ); 1611 free( nvnc.bv_val ); 1612 return 1; 1613 } 1614 1615 ber_str2bv( argv[ 2 ], 0, 0, &dn ); 1616 if ( dnPrettyNormal( NULL, &dn, &prnc, &nrnc, NULL ) != LDAP_SUCCESS ) { 1617 Debug( LDAP_DEBUG_ANY, "%s: line %d: " 1618 "massaged suffix \"%s\" is invalid\n", 1619 fname, lineno, argv[ 2 ] ); 1620 free( pvnc.bv_val ); 1621 free( nvnc.bv_val ); 1622 return 1; 1623 } 1624 1625 tmp_bd = select_backend( &nrnc, 0 ); 1626 if ( tmp_bd != NULL && tmp_bd->be_private == be->be_private ) { 1627 Debug( LDAP_DEBUG_ANY, 1628 "%s: line %d: warning: <massaged suffix> \"%s\" resolves to this database, in " 1629 "\"suffixMassage <suffix> <massaged suffix>\"\n", 1630 fname, lineno, prnc.bv_val ); 1631 } 1632 1633 /* 1634 * The suffix massaging is emulated by means of the 1635 * rewrite capabilities 1636 */ 1637 rc = suffix_massage_config( mi->mi_targets[ i ]->mt_rwmap.rwm_rw, 1638 &pvnc, &nvnc, &prnc, &nrnc ); 1639 1640 free( pvnc.bv_val ); 1641 free( nvnc.bv_val ); 1642 free( prnc.bv_val ); 1643 free( nrnc.bv_val ); 1644 1645 return rc; 1646 1647 /* rewrite stuff ... */ 1648 } else if ( strncasecmp( argv[ 0 ], "rewrite", 7 ) == 0 ) { 1649 int i = mi->mi_ntargets - 1; 1650 1651 if ( i < 0 ) { 1652 Debug( LDAP_DEBUG_ANY, "%s: line %d: \"rewrite\" " 1653 "statement outside target definition.\n", 1654 fname, lineno, 0 ); 1655 return 1; 1656 } 1657 1658 return rewrite_parse( mi->mi_targets[ i ]->mt_rwmap.rwm_rw, 1659 fname, lineno, argc, argv ); 1660 1661 /* objectclass/attribute mapping */ 1662 } else if ( strcasecmp( argv[ 0 ], "map" ) == 0 ) { 1663 int i = mi->mi_ntargets - 1; 1664 1665 if ( i < 0 ) { 1666 Debug( LDAP_DEBUG_ANY, 1667 "%s: line %d: need \"uri\" directive first\n", 1668 fname, lineno, 0 ); 1669 return 1; 1670 } 1671 1672 return ldap_back_map_config( &mi->mi_targets[ i ]->mt_rwmap.rwm_oc, 1673 &mi->mi_targets[ i ]->mt_rwmap.rwm_at, 1674 fname, lineno, argc, argv ); 1675 1676 } else if ( strcasecmp( argv[ 0 ], "nretries" ) == 0 ) { 1677 int i = mi->mi_ntargets - 1; 1678 int nretries = META_RETRY_UNDEFINED; 1679 1680 if ( argc != 2 ) { 1681 Debug( LDAP_DEBUG_ANY, 1682 "%s: line %d: need value in \"nretries <value>\"\n", 1683 fname, lineno, 0 ); 1684 return 1; 1685 } 1686 1687 if ( strcasecmp( argv[ 1 ], "forever" ) == 0 ) { 1688 nretries = META_RETRY_FOREVER; 1689 1690 } else if ( strcasecmp( argv[ 1 ], "never" ) == 0 ) { 1691 nretries = META_RETRY_NEVER; 1692 1693 } else { 1694 if ( lutil_atoi( &nretries, argv[ 1 ] ) != 0 ) { 1695 Debug( LDAP_DEBUG_ANY, 1696 "%s: line %d: unable to parse value \"%s\" in \"nretries <value>\"\n", 1697 fname, lineno, argv[ 1 ] ); 1698 return 1; 1699 } 1700 } 1701 1702 if ( i < 0 ) { 1703 mi->mi_nretries = nretries; 1704 1705 } else { 1706 mi->mi_targets[ i ]->mt_nretries = nretries; 1707 } 1708 1709 } else if ( strcasecmp( argv[ 0 ], "protocol-version" ) == 0 ) { 1710 int *version = mi->mi_ntargets ? 1711 &mi->mi_targets[ mi->mi_ntargets - 1 ]->mt_version 1712 : &mi->mi_version; 1713 1714 if ( argc != 2 ) { 1715 Debug( LDAP_DEBUG_ANY, 1716 "%s: line %d: need value in \"protocol-version <version>\"\n", 1717 fname, lineno, 0 ); 1718 return 1; 1719 } 1720 1721 if ( lutil_atoi( version, argv[ 1 ] ) != 0 ) { 1722 Debug( LDAP_DEBUG_ANY, 1723 "%s: line %d: unable to parse version \"%s\" in \"protocol-version <version>\"\n", 1724 fname, lineno, argv[ 1 ] ); 1725 return 1; 1726 } 1727 1728 if ( *version != 0 && ( *version < LDAP_VERSION_MIN || *version > LDAP_VERSION_MAX ) ) { 1729 Debug( LDAP_DEBUG_ANY, 1730 "%s: line %d: unsupported version \"%s\" in \"protocol-version <version>\"\n", 1731 fname, lineno, argv[ 1 ] ); 1732 return 1; 1733 } 1734 1735 /* do not return search references */ 1736 } else if ( strcasecmp( argv[ 0 ], "norefs" ) == 0 ) { 1737 unsigned *flagsp = mi->mi_ntargets ? 1738 &mi->mi_targets[ mi->mi_ntargets - 1 ]->mt_flags 1739 : &mi->mi_flags; 1740 1741 if ( argc != 2 ) { 1742 Debug( LDAP_DEBUG_ANY, 1743 "%s: line %d: \"norefs {TRUE|false}\" needs 1 argument.\n", 1744 fname, lineno, 0 ); 1745 return( 1 ); 1746 } 1747 1748 /* this is the default; we add it because the default might change... */ 1749 switch ( check_true_false( argv[ 1 ] ) ) { 1750 case 1: 1751 *flagsp |= LDAP_BACK_F_NOREFS; 1752 break; 1753 1754 case 0: 1755 *flagsp &= ~LDAP_BACK_F_NOREFS; 1756 break; 1757 1758 default: 1759 Debug( LDAP_DEBUG_ANY, 1760 "%s: line %d: \"norefs {TRUE|false}\": unknown argument \"%s\".\n", 1761 fname, lineno, argv[ 1 ] ); 1762 return( 1 ); 1763 } 1764 1765 /* do not propagate undefined search filters */ 1766 } else if ( strcasecmp( argv[ 0 ], "noundeffilter" ) == 0 ) { 1767 unsigned *flagsp = mi->mi_ntargets ? 1768 &mi->mi_targets[ mi->mi_ntargets - 1 ]->mt_flags 1769 : &mi->mi_flags; 1770 1771 if ( argc != 2 ) { 1772 Debug( LDAP_DEBUG_ANY, 1773 "%s: line %d: \"noundeffilter {TRUE|false}\" needs 1 argument.\n", 1774 fname, lineno, 0 ); 1775 return( 1 ); 1776 } 1777 1778 /* this is the default; we add it because the default might change... */ 1779 switch ( check_true_false( argv[ 1 ] ) ) { 1780 case 1: 1781 *flagsp |= LDAP_BACK_F_NOUNDEFFILTER; 1782 break; 1783 1784 case 0: 1785 *flagsp &= ~LDAP_BACK_F_NOUNDEFFILTER; 1786 break; 1787 1788 default: 1789 Debug( LDAP_DEBUG_ANY, 1790 "%s: line %d: \"noundeffilter {TRUE|false}\": unknown argument \"%s\".\n", 1791 fname, lineno, argv[ 1 ] ); 1792 return( 1 ); 1793 } 1794 1795#ifdef SLAPD_META_CLIENT_PR 1796 } else if ( strcasecmp( argv[ 0 ], "client-pr" ) == 0 ) { 1797 int *ps = mi->mi_ntargets ? 1798 &mi->mi_targets[ mi->mi_ntargets - 1 ]->mt_ps 1799 : &mi->mi_ps; 1800 1801 if ( argc != 2 ) { 1802 Debug( LDAP_DEBUG_ANY, 1803 "%s: line %d: \"client-pr {accept-unsolicited|disable|<size>}\" needs 1 argument.\n", 1804 fname, lineno, 0 ); 1805 return( 1 ); 1806 } 1807 1808 if ( strcasecmp( argv[ 1 ], "accept-unsolicited" ) == 0 ) { 1809 *ps = META_CLIENT_PR_ACCEPT_UNSOLICITED; 1810 1811 } else if ( strcasecmp( argv[ 1 ], "disable" ) == 0 ) { 1812 *ps = META_CLIENT_PR_DISABLE; 1813 1814 } else if ( lutil_atoi( ps, argv[ 1 ] ) || *ps < -1 ) { 1815 Debug( LDAP_DEBUG_ANY, 1816 "%s: line %d: \"client-pr {accept-unsolicited|disable|<size>}\" invalid arg \"%s\".\n", 1817 fname, lineno, argv[ 1 ] ); 1818 return( 1 ); 1819 } 1820#endif /* SLAPD_META_CLIENT_PR */ 1821 1822 /* anything else */ 1823 } else { 1824 return SLAP_CONF_UNKNOWN; 1825 } 1826 1827 return 0; 1828} 1829 1830int 1831ldap_back_map_config( 1832 struct ldapmap *oc_map, 1833 struct ldapmap *at_map, 1834 const char *fname, 1835 int lineno, 1836 int argc, 1837 char **argv ) 1838{ 1839 struct ldapmap *map; 1840 struct ldapmapping *mapping; 1841 char *src, *dst; 1842 int is_oc = 0; 1843 1844 if ( argc < 3 || argc > 4 ) { 1845 Debug( LDAP_DEBUG_ANY, 1846 "%s: line %d: syntax is \"map {objectclass | attribute} [<local> | *] {<foreign> | *}\"\n", 1847 fname, lineno, 0 ); 1848 return 1; 1849 } 1850 1851 if ( strcasecmp( argv[ 1 ], "objectclass" ) == 0 ) { 1852 map = oc_map; 1853 is_oc = 1; 1854 1855 } else if ( strcasecmp( argv[ 1 ], "attribute" ) == 0 ) { 1856 map = at_map; 1857 1858 } else { 1859 Debug( LDAP_DEBUG_ANY, "%s: line %d: syntax is " 1860 "\"map {objectclass | attribute} [<local> | *] " 1861 "{<foreign> | *}\"\n", 1862 fname, lineno, 0 ); 1863 return 1; 1864 } 1865 1866 if ( !is_oc && map->map == NULL ) { 1867 /* only init if required */ 1868 ldap_back_map_init( map, &mapping ); 1869 } 1870 1871 if ( strcmp( argv[ 2 ], "*" ) == 0 ) { 1872 if ( argc < 4 || strcmp( argv[ 3 ], "*" ) == 0 ) { 1873 map->drop_missing = ( argc < 4 ); 1874 goto success_return; 1875 } 1876 src = dst = argv[ 3 ]; 1877 1878 } else if ( argc < 4 ) { 1879 src = ""; 1880 dst = argv[ 2 ]; 1881 1882 } else { 1883 src = argv[ 2 ]; 1884 dst = ( strcmp( argv[ 3 ], "*" ) == 0 ? src : argv[ 3 ] ); 1885 } 1886 1887 if ( ( map == at_map ) 1888 && ( strcasecmp( src, "objectclass" ) == 0 1889 || strcasecmp( dst, "objectclass" ) == 0 ) ) 1890 { 1891 Debug( LDAP_DEBUG_ANY, 1892 "%s: line %d: objectclass attribute cannot be mapped\n", 1893 fname, lineno, 0 ); 1894 } 1895 1896 mapping = (struct ldapmapping *)ch_calloc( 2, 1897 sizeof(struct ldapmapping) ); 1898 if ( mapping == NULL ) { 1899 Debug( LDAP_DEBUG_ANY, 1900 "%s: line %d: out of memory\n", 1901 fname, lineno, 0 ); 1902 return 1; 1903 } 1904 ber_str2bv( src, 0, 1, &mapping[ 0 ].src ); 1905 ber_str2bv( dst, 0, 1, &mapping[ 0 ].dst ); 1906 mapping[ 1 ].src = mapping[ 0 ].dst; 1907 mapping[ 1 ].dst = mapping[ 0 ].src; 1908 1909 /* 1910 * schema check 1911 */ 1912 if ( is_oc ) { 1913 if ( src[ 0 ] != '\0' ) { 1914 if ( oc_bvfind( &mapping[ 0 ].src ) == NULL ) { 1915 Debug( LDAP_DEBUG_ANY, 1916 "%s: line %d: warning, source objectClass '%s' " 1917 "should be defined in schema\n", 1918 fname, lineno, src ); 1919 1920 /* 1921 * FIXME: this should become an err 1922 */ 1923 goto error_return; 1924 } 1925 } 1926 1927 if ( oc_bvfind( &mapping[ 0 ].dst ) == NULL ) { 1928 Debug( LDAP_DEBUG_ANY, 1929 "%s: line %d: warning, destination objectClass '%s' " 1930 "is not defined in schema\n", 1931 fname, lineno, dst ); 1932 } 1933 } else { 1934 int rc; 1935 const char *text = NULL; 1936 AttributeDescription *ad = NULL; 1937 1938 if ( src[ 0 ] != '\0' ) { 1939 rc = slap_bv2ad( &mapping[ 0 ].src, &ad, &text ); 1940 if ( rc != LDAP_SUCCESS ) { 1941 Debug( LDAP_DEBUG_ANY, 1942 "%s: line %d: warning, source attributeType '%s' " 1943 "should be defined in schema\n", 1944 fname, lineno, src ); 1945 1946 /* 1947 * FIXME: this should become an err 1948 */ 1949 /* 1950 * we create a fake "proxied" ad 1951 * and add it here. 1952 */ 1953 1954 rc = slap_bv2undef_ad( &mapping[ 0 ].src, 1955 &ad, &text, SLAP_AD_PROXIED ); 1956 if ( rc != LDAP_SUCCESS ) { 1957 char buf[ SLAP_TEXT_BUFLEN ]; 1958 1959 snprintf( buf, sizeof( buf ), 1960 "source attributeType \"%s\": %d (%s)", 1961 src, rc, text ? text : "" ); 1962 Debug( LDAP_DEBUG_ANY, 1963 "%s: line %d: %s\n", 1964 fname, lineno, buf ); 1965 goto error_return; 1966 } 1967 } 1968 1969 ad = NULL; 1970 } 1971 1972 rc = slap_bv2ad( &mapping[ 0 ].dst, &ad, &text ); 1973 if ( rc != LDAP_SUCCESS ) { 1974 Debug( LDAP_DEBUG_ANY, 1975 "%s: line %d: warning, destination attributeType '%s' " 1976 "is not defined in schema\n", 1977 fname, lineno, dst ); 1978 1979 /* 1980 * we create a fake "proxied" ad 1981 * and add it here. 1982 */ 1983 1984 rc = slap_bv2undef_ad( &mapping[ 0 ].dst, 1985 &ad, &text, SLAP_AD_PROXIED ); 1986 if ( rc != LDAP_SUCCESS ) { 1987 char buf[ SLAP_TEXT_BUFLEN ]; 1988 1989 snprintf( buf, sizeof( buf ), 1990 "source attributeType \"%s\": %d (%s)\n", 1991 dst, rc, text ? text : "" ); 1992 Debug( LDAP_DEBUG_ANY, 1993 "%s: line %d: %s\n", 1994 fname, lineno, buf ); 1995 return 1; 1996 } 1997 } 1998 } 1999 2000 if ( (src[ 0 ] != '\0' && avl_find( map->map, (caddr_t)&mapping[ 0 ], mapping_cmp ) != NULL) 2001 || avl_find( map->remap, (caddr_t)&mapping[ 1 ], mapping_cmp ) != NULL) 2002 { 2003 Debug( LDAP_DEBUG_ANY, 2004 "%s: line %d: duplicate mapping found.\n", 2005 fname, lineno, 0 ); 2006 goto error_return; 2007 } 2008 2009 if ( src[ 0 ] != '\0' ) { 2010 avl_insert( &map->map, (caddr_t)&mapping[ 0 ], 2011 mapping_cmp, mapping_dup ); 2012 } 2013 avl_insert( &map->remap, (caddr_t)&mapping[ 1 ], 2014 mapping_cmp, mapping_dup ); 2015 2016success_return:; 2017 return 0; 2018 2019error_return:; 2020 if ( mapping ) { 2021 ch_free( mapping[ 0 ].src.bv_val ); 2022 ch_free( mapping[ 0 ].dst.bv_val ); 2023 ch_free( mapping ); 2024 } 2025 2026 return 1; 2027} 2028 2029 2030#ifdef ENABLE_REWRITE 2031static char * 2032suffix_massage_regexize( const char *s ) 2033{ 2034 char *res, *ptr; 2035 const char *p, *r; 2036 int i; 2037 2038 if ( s[ 0 ] == '\0' ) { 2039 return ch_strdup( "^(.+)$" ); 2040 } 2041 2042 for ( i = 0, p = s; 2043 ( r = strchr( p, ',' ) ) != NULL; 2044 p = r + 1, i++ ) 2045 ; 2046 2047 res = ch_calloc( sizeof( char ), 2048 strlen( s ) 2049 + STRLENOF( "((.+),)?" ) 2050 + STRLENOF( "[ ]?" ) * i 2051 + STRLENOF( "$" ) + 1 ); 2052 2053 ptr = lutil_strcopy( res, "((.+),)?" ); 2054 for ( i = 0, p = s; 2055 ( r = strchr( p, ',' ) ) != NULL; 2056 p = r + 1 , i++ ) { 2057 ptr = lutil_strncopy( ptr, p, r - p + 1 ); 2058 ptr = lutil_strcopy( ptr, "[ ]?" ); 2059 2060 if ( r[ 1 ] == ' ' ) { 2061 r++; 2062 } 2063 } 2064 ptr = lutil_strcopy( ptr, p ); 2065 ptr[ 0 ] = '$'; 2066 ptr++; 2067 ptr[ 0 ] = '\0'; 2068 2069 return res; 2070} 2071 2072static char * 2073suffix_massage_patternize( const char *s, const char *p ) 2074{ 2075 ber_len_t len; 2076 char *res, *ptr; 2077 2078 len = strlen( p ); 2079 2080 if ( s[ 0 ] == '\0' ) { 2081 len++; 2082 } 2083 2084 res = ch_calloc( sizeof( char ), len + STRLENOF( "%1" ) + 1 ); 2085 if ( res == NULL ) { 2086 return NULL; 2087 } 2088 2089 ptr = lutil_strcopy( res, ( p[ 0 ] == '\0' ? "%2" : "%1" ) ); 2090 if ( s[ 0 ] == '\0' ) { 2091 ptr[ 0 ] = ','; 2092 ptr++; 2093 } 2094 lutil_strcopy( ptr, p ); 2095 2096 return res; 2097} 2098 2099int 2100suffix_massage_config( 2101 struct rewrite_info *info, 2102 struct berval *pvnc, 2103 struct berval *nvnc, 2104 struct berval *prnc, 2105 struct berval *nrnc 2106) 2107{ 2108 char *rargv[ 5 ]; 2109 int line = 0; 2110 2111 rargv[ 0 ] = "rewriteEngine"; 2112 rargv[ 1 ] = "on"; 2113 rargv[ 2 ] = NULL; 2114 rewrite_parse( info, "<suffix massage>", ++line, 2, rargv ); 2115 2116 rargv[ 0 ] = "rewriteContext"; 2117 rargv[ 1 ] = "default"; 2118 rargv[ 2 ] = NULL; 2119 rewrite_parse( info, "<suffix massage>", ++line, 2, rargv ); 2120 2121 rargv[ 0 ] = "rewriteRule"; 2122 rargv[ 1 ] = suffix_massage_regexize( pvnc->bv_val ); 2123 rargv[ 2 ] = suffix_massage_patternize( pvnc->bv_val, prnc->bv_val ); 2124 rargv[ 3 ] = ":"; 2125 rargv[ 4 ] = NULL; 2126 rewrite_parse( info, "<suffix massage>", ++line, 4, rargv ); 2127 ch_free( rargv[ 1 ] ); 2128 ch_free( rargv[ 2 ] ); 2129 2130 if ( BER_BVISEMPTY( pvnc ) ) { 2131 rargv[ 0 ] = "rewriteRule"; 2132 rargv[ 1 ] = "^$"; 2133 rargv[ 2 ] = prnc->bv_val; 2134 rargv[ 3 ] = ":"; 2135 rargv[ 4 ] = NULL; 2136 rewrite_parse( info, "<suffix massage>", ++line, 4, rargv ); 2137 } 2138 2139 rargv[ 0 ] = "rewriteContext"; 2140 rargv[ 1 ] = "searchEntryDN"; 2141 rargv[ 2 ] = NULL; 2142 rewrite_parse( info, "<suffix massage>", ++line, 2, rargv ); 2143 2144 rargv[ 0 ] = "rewriteRule"; 2145 rargv[ 1 ] = suffix_massage_regexize( prnc->bv_val ); 2146 rargv[ 2 ] = suffix_massage_patternize( prnc->bv_val, pvnc->bv_val ); 2147 rargv[ 3 ] = ":"; 2148 rargv[ 4 ] = NULL; 2149 rewrite_parse( info, "<suffix massage>", ++line, 4, rargv ); 2150 ch_free( rargv[ 1 ] ); 2151 ch_free( rargv[ 2 ] ); 2152 2153 if ( BER_BVISEMPTY( prnc ) ) { 2154 rargv[ 0 ] = "rewriteRule"; 2155 rargv[ 1 ] = "^$"; 2156 rargv[ 2 ] = pvnc->bv_val; 2157 rargv[ 3 ] = ":"; 2158 rargv[ 4 ] = NULL; 2159 rewrite_parse( info, "<suffix massage>", ++line, 4, rargv ); 2160 } 2161 2162 /* backward compatibility */ 2163 rargv[ 0 ] = "rewriteContext"; 2164 rargv[ 1 ] = "searchResult"; 2165 rargv[ 2 ] = "alias"; 2166 rargv[ 3 ] = "searchEntryDN"; 2167 rargv[ 4 ] = NULL; 2168 rewrite_parse( info, "<suffix massage>", ++line, 4, rargv ); 2169 2170 rargv[ 0 ] = "rewriteContext"; 2171 rargv[ 1 ] = "matchedDN"; 2172 rargv[ 2 ] = "alias"; 2173 rargv[ 3 ] = "searchEntryDN"; 2174 rargv[ 4 ] = NULL; 2175 rewrite_parse( info, "<suffix massage>", ++line, 4, rargv ); 2176 2177 rargv[ 0 ] = "rewriteContext"; 2178 rargv[ 1 ] = "searchAttrDN"; 2179 rargv[ 2 ] = "alias"; 2180 rargv[ 3 ] = "searchEntryDN"; 2181 rargv[ 4 ] = NULL; 2182 rewrite_parse( info, "<suffix massage>", ++line, 4, rargv ); 2183 2184 /* NOTE: this corresponds to #undef'ining RWM_REFERRAL_REWRITE; 2185 * see servers/slapd/overlays/rwm.h for details */ 2186 rargv[ 0 ] = "rewriteContext"; 2187 rargv[ 1 ] = "referralAttrDN"; 2188 rargv[ 2 ] = NULL; 2189 rewrite_parse( info, "<suffix massage>", ++line, 2, rargv ); 2190 2191 rargv[ 0 ] = "rewriteContext"; 2192 rargv[ 1 ] = "referralDN"; 2193 rargv[ 2 ] = NULL; 2194 rewrite_parse( info, "<suffix massage>", ++line, 2, rargv ); 2195 2196 return 0; 2197} 2198#endif /* ENABLE_REWRITE */ 2199 2200