1 /* $NetBSD: database.c,v 1.3 2021/08/14 16:15:00 christos Exp $ */ 2 3 /* database.c - deals with database subsystem */ 4 /* $OpenLDAP$ */ 5 /* This work is part of OpenLDAP Software <http://www.openldap.org/>. 6 * 7 * Copyright 2001-2021 The OpenLDAP Foundation. 8 * Portions Copyright 2001-2003 Pierangelo Masarati. 9 * All rights reserved. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted only as authorized by the OpenLDAP 13 * Public License. 14 * 15 * A copy of this license is available in file LICENSE in the 16 * top-level directory of the distribution or, alternatively, at 17 * <http://www.OpenLDAP.org/license.html>. 18 */ 19 /* ACKNOWLEDGEMENTS: 20 * This work was initially developed by Pierangelo Masarati for inclusion 21 * in OpenLDAP Software. 22 */ 23 24 #include <sys/cdefs.h> 25 __RCSID("$NetBSD: database.c,v 1.3 2021/08/14 16:15:00 christos Exp $"); 26 27 #include "portable.h" 28 29 #include <stdio.h> 30 #include <ac/string.h> 31 #include <ac/unistd.h> 32 33 #include "slap.h" 34 #include "back-monitor.h" 35 36 #if defined(LDAP_SLAPI) 37 #include "slapi.h" 38 static int monitor_back_add_plugin( monitor_info_t *mi, Backend *be, Entry *e ); 39 #endif /* defined(LDAP_SLAPI) */ 40 41 static int 42 monitor_subsys_database_modify( 43 Operation *op, 44 SlapReply *rs, 45 Entry *e ); 46 47 static struct restricted_ops_t { 48 struct berval op; 49 unsigned int tag; 50 } restricted_ops[] = { 51 { BER_BVC( "add" ), SLAP_RESTRICT_OP_ADD }, 52 { BER_BVC( "bind" ), SLAP_RESTRICT_OP_BIND }, 53 { BER_BVC( "compare" ), SLAP_RESTRICT_OP_COMPARE }, 54 { BER_BVC( "delete" ), SLAP_RESTRICT_OP_DELETE }, 55 { BER_BVC( "extended" ), SLAP_RESTRICT_OP_EXTENDED }, 56 { BER_BVC( "modify" ), SLAP_RESTRICT_OP_MODIFY }, 57 { BER_BVC( "rename" ), SLAP_RESTRICT_OP_RENAME }, 58 { BER_BVC( "search" ), SLAP_RESTRICT_OP_SEARCH }, 59 { BER_BVNULL, 0 } 60 }, restricted_exops[] = { 61 { BER_BVC( LDAP_EXOP_START_TLS ), SLAP_RESTRICT_EXOP_START_TLS }, 62 { BER_BVC( LDAP_EXOP_MODIFY_PASSWD ), SLAP_RESTRICT_EXOP_MODIFY_PASSWD }, 63 { BER_BVC( LDAP_EXOP_WHO_AM_I ), SLAP_RESTRICT_EXOP_WHOAMI }, 64 { BER_BVC( LDAP_EXOP_CANCEL ), SLAP_RESTRICT_EXOP_CANCEL }, 65 { BER_BVNULL, 0 } 66 }; 67 68 static int 69 init_readOnly( monitor_info_t *mi, Entry *e, slap_mask_t restrictops ) 70 { 71 struct berval *tf = ( ( restrictops & SLAP_RESTRICT_OP_MASK ) == SLAP_RESTRICT_OP_WRITES ) ? 72 (struct berval *)&slap_true_bv : (struct berval *)&slap_false_bv; 73 74 return attr_merge_one( e, mi->mi_ad_readOnly, tf, NULL ); 75 } 76 77 static int 78 init_restrictedOperation( monitor_info_t *mi, Entry *e, slap_mask_t restrictops ) 79 { 80 int i, rc; 81 82 for ( i = 0; restricted_ops[ i ].op.bv_val; i++ ) { 83 if ( restrictops & restricted_ops[ i ].tag ) { 84 rc = attr_merge_one( e, mi->mi_ad_restrictedOperation, 85 &restricted_ops[ i ].op, 86 &restricted_ops[ i ].op ); 87 if ( rc ) { 88 return rc; 89 } 90 } 91 } 92 93 for ( i = 0; restricted_exops[ i ].op.bv_val; i++ ) { 94 if ( restrictops & restricted_exops[ i ].tag ) { 95 rc = attr_merge_one( e, mi->mi_ad_restrictedOperation, 96 &restricted_exops[ i ].op, 97 &restricted_exops[ i ].op ); 98 if ( rc ) { 99 return rc; 100 } 101 } 102 } 103 104 return LDAP_SUCCESS; 105 } 106 107 static int 108 monitor_subsys_overlay_init_one( 109 monitor_info_t *mi, 110 BackendDB *be, 111 monitor_subsys_t *ms, 112 monitor_subsys_t *ms_overlay, 113 slap_overinst *on, 114 Entry *e_database, 115 Entry **ep_overlay ) 116 { 117 char buf[ BACKMONITOR_BUFSIZE ]; 118 int j, o; 119 Entry *e_overlay; 120 slap_overinst *on2; 121 slap_overinfo *oi = NULL; 122 BackendInfo *bi; 123 monitor_entry_t *mp_overlay; 124 struct berval bv; 125 126 assert( overlay_is_over( be ) ); 127 128 oi = (slap_overinfo *)be->bd_info->bi_private; 129 bi = oi->oi_orig; 130 131 /* find the overlay number, o */ 132 for ( o = 0, on2 = oi->oi_list; on2 && on2 != on; on2 = on2->on_next, o++ ) 133 ; 134 135 if ( on2 == NULL ) { 136 return -1; 137 } 138 139 /* find the overlay type number, j */ 140 for ( on2 = overlay_next( NULL ), j = 0; on2; on2 = overlay_next( on2 ), j++ ) { 141 if ( on2->on_bi.bi_type == on->on_bi.bi_type ) { 142 break; 143 } 144 } 145 assert( on2 != NULL ); 146 147 bv.bv_len = snprintf( buf, sizeof( buf ), "cn=Overlay %d", o ); 148 bv.bv_val = buf; 149 150 e_overlay = monitor_entry_stub( &e_database->e_name, &e_database->e_nname, &bv, 151 mi->mi_oc_monitoredObject, NULL, NULL ); 152 153 if ( e_overlay == NULL ) { 154 Debug( LDAP_DEBUG_ANY, 155 "monitor_subsys_overlay_init_one: " 156 "unable to create entry " 157 "\"cn=Overlay %d,%s\"\n", 158 o, e_database->e_name.bv_val ); 159 return( -1 ); 160 } 161 ber_str2bv( on->on_bi.bi_type, 0, 0, &bv ); 162 attr_merge_normalize_one( e_overlay, mi->mi_ad_monitoredInfo, &bv, NULL ); 163 164 bv.bv_len = snprintf( buf, sizeof( buf ), "cn=Overlay %d,%s", 165 j, ms_overlay->mss_dn.bv_val ); 166 bv.bv_val = buf; 167 attr_merge_normalize_one( e_overlay, slap_schema.si_ad_seeAlso, 168 &bv, NULL ); 169 170 if ( SLAP_MONITOR( be ) ) { 171 attr_merge( e_overlay, slap_schema.si_ad_monitorContext, 172 be->be_suffix, be->be_nsuffix ); 173 174 } else { 175 attr_merge( e_overlay, slap_schema.si_ad_namingContexts, 176 be->be_suffix, NULL ); 177 } 178 179 mp_overlay = monitor_entrypriv_create(); 180 if ( mp_overlay == NULL ) { 181 return -1; 182 } 183 e_overlay->e_private = ( void * )mp_overlay; 184 mp_overlay->mp_info = ms; 185 mp_overlay->mp_flags = ms->mss_flags | MONITOR_F_SUB; 186 187 if ( monitor_cache_add( mi, e_overlay ) ) { 188 Debug( LDAP_DEBUG_ANY, 189 "monitor_subsys_overlay_init_one: " 190 "unable to add entry " 191 "\"cn=Overlay %d,%s\"\n", 192 o, e_database->e_name.bv_val ); 193 return -1; 194 } 195 196 *ep_overlay = e_overlay; 197 ep_overlay = &mp_overlay->mp_next; 198 199 return 0; 200 } 201 202 static int 203 monitor_subsys_database_init_one( 204 monitor_info_t *mi, 205 BackendDB *be, 206 monitor_subsys_t *ms, 207 monitor_subsys_t *ms_backend, 208 monitor_subsys_t *ms_overlay, 209 struct berval *rdn, 210 Entry *e_database, 211 Entry ***epp ) 212 { 213 char buf[ BACKMONITOR_BUFSIZE ]; 214 int j; 215 slap_overinfo *oi = NULL; 216 BackendInfo *bi, *bi2; 217 Entry *e; 218 monitor_entry_t *mp; 219 char *rdnval = strchr( rdn->bv_val, '=' ) + 1; 220 struct berval bv; 221 222 bi = be->bd_info; 223 224 if ( be->be_suffix == NULL ) { 225 Debug( LDAP_DEBUG_ANY, 226 "monitor_subsys_database_init_one: " 227 "missing suffix for %s\n", 228 rdnval ); 229 return( -1 ); 230 } 231 232 if ( overlay_is_over( be ) ) { 233 oi = (slap_overinfo *)be->bd_info->bi_private; 234 bi = oi->oi_orig; 235 } 236 237 e = monitor_entry_stub( &ms->mss_dn, &ms->mss_ndn, rdn, 238 mi->mi_oc_monitoredObject, NULL, NULL ); 239 240 if ( e == NULL ) { 241 Debug( LDAP_DEBUG_ANY, 242 "monitor_subsys_database_init_one: " 243 "unable to create entry \"%s,%s\"\n", 244 rdn->bv_val, ms->mss_dn.bv_val ); 245 return( -1 ); 246 } 247 248 ber_str2bv( bi->bi_type, 0, 0, &bv ); 249 attr_merge_normalize_one( e, mi->mi_ad_monitoredInfo, &bv, NULL ); 250 attr_merge_one( e, mi->mi_ad_monitorIsShadow, 251 SLAP_SHADOW( be ) ? (struct berval *)&slap_true_bv : 252 (struct berval *)&slap_false_bv, NULL ); 253 254 if ( SLAP_MONITOR( be ) ) { 255 attr_merge( e, slap_schema.si_ad_monitorContext, 256 be->be_suffix, be->be_nsuffix ); 257 attr_merge( e_database, slap_schema.si_ad_monitorContext, 258 be->be_suffix, be->be_nsuffix ); 259 260 } else { 261 attr_merge( e, slap_schema.si_ad_namingContexts, 262 be->be_suffix, NULL ); 263 attr_merge( e_database, slap_schema.si_ad_namingContexts, 264 be->be_suffix, NULL ); 265 266 if ( SLAP_GLUE_SUBORDINATE( be ) ) { 267 BackendDB *sup_be = select_backend( &be->be_nsuffix[ 0 ], 1 ); 268 if ( sup_be == NULL ) { 269 Debug( LDAP_DEBUG_ANY, 270 "monitor_subsys_database_init: " 271 "unable to get superior for %s\n", 272 be->be_suffix[ 0 ].bv_val ); 273 274 } else { 275 attr_merge( e, mi->mi_ad_monitorSuperiorDN, 276 sup_be->be_suffix, sup_be->be_nsuffix ); 277 } 278 } 279 } 280 281 (void)init_readOnly( mi, e, be->be_restrictops ); 282 (void)init_restrictedOperation( mi, e, be->be_restrictops ); 283 284 if ( SLAP_SHADOW( be ) && be->be_update_refs ) { 285 attr_merge_normalize( e, mi->mi_ad_monitorUpdateRef, 286 be->be_update_refs, NULL ); 287 } 288 289 if ( oi != NULL ) { 290 slap_overinst *on = oi->oi_list, 291 *on1 = on; 292 293 for ( ; on; on = on->on_next ) { 294 slap_overinst *on2; 295 296 for ( on2 = on1; on2 != on; on2 = on2->on_next ) { 297 if ( on2->on_bi.bi_type == on->on_bi.bi_type ) { 298 break; 299 } 300 } 301 302 if ( on2 != on ) { 303 break; 304 } 305 306 ber_str2bv( on->on_bi.bi_type, 0, 0, &bv ); 307 attr_merge_normalize_one( e, mi->mi_ad_monitorOverlay, 308 &bv, NULL ); 309 310 /* find the overlay number, j */ 311 for ( on2 = overlay_next( NULL ), j = 0; on2; on2 = overlay_next( on2 ), j++ ) { 312 if ( on2->on_bi.bi_type == on->on_bi.bi_type ) { 313 break; 314 } 315 } 316 assert( on2 != NULL ); 317 318 snprintf( buf, sizeof( buf ), 319 "cn=Overlay %d,%s", 320 j, ms_overlay->mss_dn.bv_val ); 321 ber_str2bv( buf, 0, 0, &bv ); 322 attr_merge_normalize_one( e, 323 slap_schema.si_ad_seeAlso, 324 &bv, NULL ); 325 } 326 } 327 328 j = -1; 329 LDAP_STAILQ_FOREACH( bi2, &backendInfo, bi_next ) { 330 j++; 331 if ( bi2->bi_type == bi->bi_type ) { 332 snprintf( buf, sizeof( buf ), 333 "cn=Backend %d,%s", 334 j, ms_backend->mss_dn.bv_val ); 335 bv.bv_val = buf; 336 bv.bv_len = strlen( buf ); 337 attr_merge_normalize_one( e, 338 slap_schema.si_ad_seeAlso, 339 &bv, NULL ); 340 break; 341 } 342 } 343 /* we must find it! */ 344 assert( j >= 0 ); 345 346 mp = monitor_entrypriv_create(); 347 if ( mp == NULL ) { 348 return -1; 349 } 350 e->e_private = ( void * )mp; 351 mp->mp_info = ms; 352 mp->mp_flags = ms->mss_flags 353 | MONITOR_F_SUB; 354 mp->mp_private = be; 355 356 if ( monitor_cache_add( mi, e ) ) { 357 Debug( LDAP_DEBUG_ANY, 358 "monitor_subsys_database_init_one: " 359 "unable to add entry \"%s,%s\"\n", 360 rdn->bv_val, ms->mss_dn.bv_val ); 361 return( -1 ); 362 } 363 364 #if defined(LDAP_SLAPI) 365 monitor_back_add_plugin( mi, be, e ); 366 #endif /* defined(LDAP_SLAPI) */ 367 368 if ( oi != NULL ) { 369 Entry **ep_overlay = &mp->mp_children; 370 slap_overinst *on = oi->oi_list; 371 372 for ( ; on; on = on->on_next ) { 373 monitor_subsys_overlay_init_one( mi, be, 374 ms, ms_overlay, on, e, ep_overlay ); 375 } 376 } 377 378 **epp = e; 379 *epp = &mp->mp_next; 380 381 return 0; 382 } 383 384 static int 385 monitor_back_register_database_and_overlay( 386 BackendDB *be, 387 struct slap_overinst *on, 388 struct berval *ndn_out ) 389 { 390 monitor_info_t *mi; 391 Entry *e_database, **ep; 392 int i, rc; 393 monitor_entry_t *mp; 394 monitor_subsys_t *ms_backend, 395 *ms_database, 396 *ms_overlay; 397 struct berval bv; 398 char buf[ BACKMONITOR_BUFSIZE ]; 399 400 assert( be_monitor != NULL ); 401 402 if ( !monitor_subsys_is_opened() ) { 403 if ( on ) { 404 return monitor_back_register_overlay_limbo( be, on, ndn_out ); 405 406 } else { 407 return monitor_back_register_database_limbo( be, ndn_out ); 408 } 409 } 410 411 mi = ( monitor_info_t * )be_monitor->be_private; 412 413 ms_backend = monitor_back_get_subsys( SLAPD_MONITOR_BACKEND_NAME ); 414 if ( ms_backend == NULL ) { 415 Debug( LDAP_DEBUG_ANY, 416 "monitor_back_register_database: " 417 "unable to get " 418 "\"" SLAPD_MONITOR_BACKEND_NAME "\" " 419 "subsystem\n" ); 420 return -1; 421 } 422 423 ms_database = monitor_back_get_subsys( SLAPD_MONITOR_DATABASE_NAME ); 424 if ( ms_database == NULL ) { 425 Debug( LDAP_DEBUG_ANY, 426 "monitor_back_register_database: " 427 "unable to get " 428 "\"" SLAPD_MONITOR_DATABASE_NAME "\" " 429 "subsystem\n" ); 430 return -1; 431 } 432 433 ms_overlay = monitor_back_get_subsys( SLAPD_MONITOR_OVERLAY_NAME ); 434 if ( ms_overlay == NULL ) { 435 Debug( LDAP_DEBUG_ANY, 436 "monitor_back_register_database: " 437 "unable to get " 438 "\"" SLAPD_MONITOR_OVERLAY_NAME "\" " 439 "subsystem\n" ); 440 return -1; 441 } 442 443 if ( monitor_cache_get( mi, &ms_database->mss_ndn, &e_database ) ) { 444 Debug( LDAP_DEBUG_ANY, 445 "monitor_subsys_database_init: " 446 "unable to get entry \"%s\"\n", 447 ms_database->mss_ndn.bv_val ); 448 return( -1 ); 449 } 450 451 mp = ( monitor_entry_t * )e_database->e_private; 452 for ( i = -1, ep = &mp->mp_children; *ep; i++ ) { 453 mp = ( monitor_entry_t * )(*ep)->e_private; 454 455 assert( mp != NULL ); 456 if ( mp->mp_private == be->bd_self ) { 457 rc = 0; 458 goto done; 459 } 460 ep = &mp->mp_next; 461 } 462 463 bv.bv_val = buf; 464 bv.bv_len = snprintf( buf, sizeof( buf ), "cn=Database %d", i ); 465 if ( bv.bv_len >= sizeof( buf ) ) { 466 rc = -1; 467 goto done; 468 } 469 470 rc = monitor_subsys_database_init_one( mi, be, 471 ms_database, ms_backend, ms_overlay, &bv, e_database, &ep ); 472 if ( rc != 0 ) { 473 goto done; 474 } 475 /* database_init_one advanced ep past where we want. 476 * But it stored the entry we want in mp->mp_next. 477 */ 478 ep = &mp->mp_next; 479 480 done:; 481 monitor_cache_release( mi, e_database ); 482 if ( rc == 0 && ndn_out && ep && *ep ) { 483 if ( on ) { 484 Entry *e_ov; 485 struct berval ov_type; 486 487 ber_str2bv( on->on_bi.bi_type, 0, 0, &ov_type ); 488 489 mp = ( monitor_entry_t * ) (*ep)->e_private; 490 for ( e_ov = mp->mp_children; e_ov; ) { 491 Attribute *a = attr_find( e_ov->e_attrs, mi->mi_ad_monitoredInfo ); 492 493 if ( a != NULL && bvmatch( &a->a_nvals[ 0 ], &ov_type ) ) { 494 *ndn_out = e_ov->e_nname; 495 break; 496 } 497 498 mp = ( monitor_entry_t * ) e_ov->e_private; 499 e_ov = mp->mp_next; 500 } 501 502 } else { 503 *ndn_out = (*ep)->e_nname; 504 } 505 } 506 507 return rc; 508 } 509 510 int 511 monitor_back_register_database( 512 BackendDB *be, 513 struct berval *ndn_out ) 514 { 515 return monitor_back_register_database_and_overlay( be, NULL, ndn_out ); 516 } 517 518 int 519 monitor_back_register_overlay( 520 BackendDB *be, 521 struct slap_overinst *on, 522 struct berval *ndn_out ) 523 { 524 return monitor_back_register_database_and_overlay( be, on, ndn_out ); 525 } 526 527 int 528 monitor_subsys_database_init( 529 BackendDB *be, 530 monitor_subsys_t *ms ) 531 { 532 monitor_info_t *mi; 533 Entry *e_database, **ep; 534 int i, rc; 535 monitor_entry_t *mp; 536 monitor_subsys_t *ms_backend, 537 *ms_overlay; 538 struct berval bv; 539 540 assert( be != NULL ); 541 542 ms->mss_modify = monitor_subsys_database_modify; 543 544 mi = ( monitor_info_t * )be->be_private; 545 546 ms_backend = monitor_back_get_subsys( SLAPD_MONITOR_BACKEND_NAME ); 547 if ( ms_backend == NULL ) { 548 Debug( LDAP_DEBUG_ANY, 549 "monitor_subsys_database_init: " 550 "unable to get " 551 "\"" SLAPD_MONITOR_BACKEND_NAME "\" " 552 "subsystem\n" ); 553 return -1; 554 } 555 556 ms_overlay = monitor_back_get_subsys( SLAPD_MONITOR_OVERLAY_NAME ); 557 if ( ms_overlay == NULL ) { 558 Debug( LDAP_DEBUG_ANY, 559 "monitor_subsys_database_init: " 560 "unable to get " 561 "\"" SLAPD_MONITOR_OVERLAY_NAME "\" " 562 "subsystem\n" ); 563 return -1; 564 } 565 566 if ( monitor_cache_get( mi, &ms->mss_ndn, &e_database ) ) { 567 Debug( LDAP_DEBUG_ANY, 568 "monitor_subsys_database_init: " 569 "unable to get entry \"%s\"\n", 570 ms->mss_ndn.bv_val ); 571 return( -1 ); 572 } 573 574 (void)init_readOnly( mi, e_database, frontendDB->be_restrictops ); 575 (void)init_restrictedOperation( mi, e_database, frontendDB->be_restrictops ); 576 577 mp = ( monitor_entry_t * )e_database->e_private; 578 mp->mp_children = NULL; 579 ep = &mp->mp_children; 580 581 BER_BVSTR( &bv, "cn=Frontend" ); 582 rc = monitor_subsys_database_init_one( mi, frontendDB, 583 ms, ms_backend, ms_overlay, &bv, e_database, &ep ); 584 if ( rc != 0 ) { 585 return rc; 586 } 587 588 i = -1; 589 LDAP_STAILQ_FOREACH( be, &backendDB, be_next ) { 590 char buf[ BACKMONITOR_BUFSIZE ]; 591 592 bv.bv_val = buf; 593 bv.bv_len = snprintf( buf, sizeof( buf ), "cn=Database %d", ++i ); 594 if ( bv.bv_len >= sizeof( buf ) ) { 595 return -1; 596 } 597 598 rc = monitor_subsys_database_init_one( mi, be, 599 ms, ms_backend, ms_overlay, &bv, e_database, &ep ); 600 if ( rc != 0 ) { 601 return rc; 602 } 603 } 604 605 monitor_cache_release( mi, e_database ); 606 607 return( 0 ); 608 } 609 610 /* 611 * v: array of values 612 * cur: must not contain the tags corresponding to the values in v 613 * delta: will contain the tags corresponding to the values in v 614 */ 615 static int 616 value_mask( BerVarray v, slap_mask_t cur, slap_mask_t *delta ) 617 { 618 for ( ; !BER_BVISNULL( v ); v++ ) { 619 struct restricted_ops_t *rops; 620 int i; 621 622 if ( OID_LEADCHAR( v->bv_val[ 0 ] ) ) { 623 rops = restricted_exops; 624 625 } else { 626 rops = restricted_ops; 627 } 628 629 for ( i = 0; !BER_BVISNULL( &rops[ i ].op ); i++ ) { 630 if ( ber_bvstrcasecmp( v, &rops[ i ].op ) != 0 ) { 631 continue; 632 } 633 634 if ( rops[ i ].tag & *delta ) { 635 return LDAP_OTHER; 636 } 637 638 if ( rops[ i ].tag & cur ) { 639 return LDAP_OTHER; 640 } 641 642 cur |= rops[ i ].tag; 643 *delta |= rops[ i ].tag; 644 645 break; 646 } 647 648 if ( BER_BVISNULL( &rops[ i ].op ) ) { 649 return LDAP_INVALID_SYNTAX; 650 } 651 } 652 653 return LDAP_SUCCESS; 654 } 655 656 static int 657 monitor_subsys_database_modify( 658 Operation *op, 659 SlapReply *rs, 660 Entry *e ) 661 { 662 monitor_info_t *mi = (monitor_info_t *)op->o_bd->be_private; 663 int rc = LDAP_OTHER; 664 Attribute *save_attrs, *a; 665 Modifications *ml; 666 Backend *be; 667 int ro_gotval = 1, i, n; 668 slap_mask_t rp_add = 0, rp_delete = 0, rp_cur; 669 struct berval *tf; 670 671 i = sscanf( e->e_nname.bv_val, "cn=database %d,", &n ); 672 if ( i != 1 ) { 673 return SLAP_CB_CONTINUE; 674 } 675 676 if ( n < 0 || n >= nBackendDB ) { 677 rs->sr_text = "invalid database index"; 678 return ( rs->sr_err = LDAP_NO_SUCH_OBJECT ); 679 } 680 681 LDAP_STAILQ_FOREACH( be, &backendDB, be_next ) { 682 if ( n == 0 ) { 683 break; 684 } 685 n--; 686 } 687 /* do not allow some changes on back-monitor (needs work)... */ 688 if ( SLAP_MONITOR( be ) ) { 689 rs->sr_text = "no modifications allowed to monitor database entry"; 690 return ( rs->sr_err = LDAP_UNWILLING_TO_PERFORM ); 691 } 692 693 rp_cur = be->be_restrictops; 694 695 save_attrs = e->e_attrs; 696 e->e_attrs = attrs_dup( e->e_attrs ); 697 698 for ( ml = op->orm_modlist; ml; ml = ml->sml_next ) { 699 Modification *mod = &ml->sml_mod; 700 701 if ( mod->sm_desc == mi->mi_ad_readOnly ) { 702 int val = -1; 703 704 if ( mod->sm_values ) { 705 if ( !BER_BVISNULL( &mod->sm_values[ 1 ] ) ) { 706 rs->sr_text = "attempting to modify multiple values of single-valued attribute"; 707 rc = rs->sr_err = LDAP_CONSTRAINT_VIOLATION; 708 goto done; 709 } 710 711 if ( bvmatch( &slap_true_bv, mod->sm_values )) { 712 val = 1; 713 714 } else if ( bvmatch( &slap_false_bv, mod->sm_values )) { 715 val = 0; 716 717 } else { 718 assert( 0 ); 719 rc = rs->sr_err = LDAP_INVALID_SYNTAX; 720 goto done; 721 } 722 } 723 724 switch ( mod->sm_op ) { 725 case LDAP_MOD_DELETE: 726 if ( ro_gotval < 1 ) { 727 rc = rs->sr_err = LDAP_CONSTRAINT_VIOLATION; 728 goto done; 729 } 730 ro_gotval--; 731 732 if ( val == 0 && ( rp_cur & SLAP_RESTRICT_OP_WRITES ) == SLAP_RESTRICT_OP_WRITES ) { 733 rc = rs->sr_err = LDAP_NO_SUCH_ATTRIBUTE; 734 goto done; 735 } 736 737 if ( val == 1 && ( rp_cur & SLAP_RESTRICT_OP_WRITES ) != SLAP_RESTRICT_OP_WRITES ) { 738 rc = rs->sr_err = LDAP_NO_SUCH_ATTRIBUTE; 739 goto done; 740 } 741 742 break; 743 744 case LDAP_MOD_REPLACE: 745 ro_gotval = 0; 746 /* fall thru */ 747 748 case LDAP_MOD_ADD: 749 if ( ro_gotval > 0 ) { 750 rc = rs->sr_err = LDAP_CONSTRAINT_VIOLATION; 751 goto done; 752 } 753 ro_gotval++; 754 755 if ( val == 1 ) { 756 rp_add |= (~rp_cur) & SLAP_RESTRICT_OP_WRITES; 757 rp_cur |= SLAP_RESTRICT_OP_WRITES; 758 rp_delete &= ~SLAP_RESTRICT_OP_WRITES; 759 760 } else if ( val == 0 ) { 761 rp_delete |= rp_cur & SLAP_RESTRICT_OP_WRITES; 762 rp_cur &= ~SLAP_RESTRICT_OP_WRITES; 763 rp_add &= ~SLAP_RESTRICT_OP_WRITES; 764 } 765 break; 766 767 default: 768 rc = rs->sr_err = LDAP_OTHER; 769 goto done; 770 } 771 772 } else if ( mod->sm_desc == mi->mi_ad_restrictedOperation ) { 773 slap_mask_t mask = 0; 774 775 switch ( mod->sm_op ) { 776 case LDAP_MOD_DELETE: 777 if ( mod->sm_values == NULL ) { 778 rp_delete = rp_cur; 779 rp_cur = 0; 780 rp_add = 0; 781 break; 782 } 783 rc = value_mask( mod->sm_values, ~rp_cur, &mask ); 784 if ( rc == LDAP_SUCCESS ) { 785 rp_delete |= mask; 786 rp_add &= ~mask; 787 rp_cur &= ~mask; 788 789 } else if ( rc == LDAP_OTHER ) { 790 rc = LDAP_NO_SUCH_ATTRIBUTE; 791 } 792 break; 793 794 case LDAP_MOD_REPLACE: 795 rp_delete = rp_cur; 796 rp_cur = 0; 797 rp_add = 0; 798 /* fall thru */ 799 800 case LDAP_MOD_ADD: 801 rc = value_mask( mod->sm_values, rp_cur, &mask ); 802 if ( rc == LDAP_SUCCESS ) { 803 rp_add |= mask; 804 rp_cur |= mask; 805 rp_delete &= ~mask; 806 807 } else if ( rc == LDAP_OTHER ) { 808 rc = rs->sr_err = LDAP_TYPE_OR_VALUE_EXISTS; 809 } 810 break; 811 812 default: 813 rc = rs->sr_err = LDAP_OTHER; 814 break; 815 } 816 817 if ( rc != LDAP_SUCCESS ) { 818 goto done; 819 } 820 821 } else if ( is_at_operational( mod->sm_desc->ad_type )) { 822 /* accept all operational attributes */ 823 attr_delete( &e->e_attrs, mod->sm_desc ); 824 rc = attr_merge( e, mod->sm_desc, mod->sm_values, 825 mod->sm_nvalues ); 826 if ( rc ) { 827 rc = rs->sr_err = LDAP_OTHER; 828 break; 829 } 830 831 } else { 832 rc = rs->sr_err = LDAP_UNWILLING_TO_PERFORM; 833 break; 834 } 835 } 836 837 /* sanity checks: */ 838 if ( ro_gotval < 1 ) { 839 rc = rs->sr_err = LDAP_CONSTRAINT_VIOLATION; 840 goto done; 841 } 842 843 if ( ( rp_cur & SLAP_RESTRICT_OP_EXTENDED ) && ( rp_cur & SLAP_RESTRICT_EXOP_MASK ) ) { 844 rc = rs->sr_err = LDAP_CONSTRAINT_VIOLATION; 845 goto done; 846 } 847 848 if ( rp_delete & rp_add ) { 849 rc = rs->sr_err = LDAP_OTHER; 850 goto done; 851 } 852 853 /* check current value of readOnly */ 854 if ( ( rp_cur & SLAP_RESTRICT_OP_WRITES ) == SLAP_RESTRICT_OP_WRITES ) { 855 tf = (struct berval *)&slap_true_bv; 856 857 } else { 858 tf = (struct berval *)&slap_false_bv; 859 } 860 861 a = attr_find( e->e_attrs, mi->mi_ad_readOnly ); 862 if ( a == NULL ) { 863 rc = LDAP_OTHER; 864 goto done; 865 } 866 867 if ( !bvmatch( &a->a_vals[ 0 ], tf ) ) { 868 attr_delete( &e->e_attrs, mi->mi_ad_readOnly ); 869 rc = attr_merge_one( e, mi->mi_ad_readOnly, tf, tf ); 870 } 871 872 if ( rc == LDAP_SUCCESS ) { 873 if ( rp_delete ) { 874 if ( rp_delete == be->be_restrictops ) { 875 attr_delete( &e->e_attrs, mi->mi_ad_restrictedOperation ); 876 877 } else { 878 a = attr_find( e->e_attrs, mi->mi_ad_restrictedOperation ); 879 if ( a == NULL ) { 880 rc = rs->sr_err = LDAP_OTHER; 881 goto done; 882 } 883 884 for ( i = 0; !BER_BVISNULL( &restricted_ops[ i ].op ); i++ ) { 885 if ( rp_delete & restricted_ops[ i ].tag ) { 886 int j; 887 888 for ( j = 0; !BER_BVISNULL( &a->a_nvals[ j ] ); j++ ) { 889 int k; 890 891 if ( !bvmatch( &a->a_nvals[ j ], &restricted_ops[ i ].op ) ) { 892 continue; 893 } 894 895 ch_free( a->a_vals[ j ].bv_val ); 896 ch_free( a->a_nvals[ j ].bv_val ); 897 898 for ( k = j + 1; !BER_BVISNULL( &a->a_nvals[ k ] ); k++ ) { 899 a->a_vals[ k - 1 ] = a->a_vals[ k ]; 900 a->a_nvals[ k - 1 ] = a->a_nvals[ k ]; 901 } 902 903 BER_BVZERO( &a->a_vals[ k - 1 ] ); 904 BER_BVZERO( &a->a_nvals[ k - 1 ] ); 905 a->a_numvals--; 906 } 907 } 908 } 909 910 for ( i = 0; !BER_BVISNULL( &restricted_exops[ i ].op ); i++ ) { 911 if ( rp_delete & restricted_exops[ i ].tag ) { 912 int j; 913 914 for ( j = 0; !BER_BVISNULL( &a->a_nvals[ j ] ); j++ ) { 915 int k; 916 917 if ( !bvmatch( &a->a_nvals[ j ], &restricted_exops[ i ].op ) ) { 918 continue; 919 } 920 921 ch_free( a->a_vals[ j ].bv_val ); 922 ch_free( a->a_nvals[ j ].bv_val ); 923 924 for ( k = j + 1; !BER_BVISNULL( &a->a_nvals[ k ] ); k++ ) { 925 a->a_vals[ k - 1 ] = a->a_vals[ k ]; 926 a->a_nvals[ k - 1 ] = a->a_nvals[ k ]; 927 } 928 929 BER_BVZERO( &a->a_vals[ k - 1 ] ); 930 BER_BVZERO( &a->a_nvals[ k - 1 ] ); 931 a->a_numvals--; 932 } 933 } 934 } 935 936 if ( a->a_vals == NULL ) { 937 assert( a->a_numvals == 0 ); 938 939 attr_delete( &e->e_attrs, mi->mi_ad_restrictedOperation ); 940 } 941 } 942 } 943 944 if ( rp_add ) { 945 for ( i = 0; !BER_BVISNULL( &restricted_ops[ i ].op ); i++ ) { 946 if ( rp_add & restricted_ops[ i ].tag ) { 947 attr_merge_one( e, mi->mi_ad_restrictedOperation, 948 &restricted_ops[ i ].op, 949 &restricted_ops[ i ].op ); 950 } 951 } 952 953 for ( i = 0; !BER_BVISNULL( &restricted_exops[ i ].op ); i++ ) { 954 if ( rp_add & restricted_exops[ i ].tag ) { 955 attr_merge_one( e, mi->mi_ad_restrictedOperation, 956 &restricted_exops[ i ].op, 957 &restricted_exops[ i ].op ); 958 } 959 } 960 } 961 } 962 963 be->be_restrictops = rp_cur; 964 965 done:; 966 if ( rc == LDAP_SUCCESS ) { 967 attrs_free( save_attrs ); 968 rc = SLAP_CB_CONTINUE; 969 970 } else { 971 Attribute *tmp = e->e_attrs; 972 e->e_attrs = save_attrs; 973 attrs_free( tmp ); 974 } 975 return rc; 976 } 977 978 #if defined(LDAP_SLAPI) 979 static int 980 monitor_back_add_plugin( monitor_info_t *mi, Backend *be, Entry *e_database ) 981 { 982 Slapi_PBlock *pCurrentPB; 983 int i, rc = LDAP_SUCCESS; 984 985 if ( slapi_int_pblock_get_first( be, &pCurrentPB ) != LDAP_SUCCESS ) { 986 /* 987 * LDAP_OTHER is returned if no plugins are installed 988 */ 989 rc = LDAP_OTHER; 990 goto done; 991 } 992 993 i = 0; 994 do { 995 Slapi_PluginDesc *srchdesc; 996 char buf[ BACKMONITOR_BUFSIZE ]; 997 struct berval bv; 998 999 rc = slapi_pblock_get( pCurrentPB, SLAPI_PLUGIN_DESCRIPTION, 1000 &srchdesc ); 1001 if ( rc != LDAP_SUCCESS ) { 1002 goto done; 1003 } 1004 if ( srchdesc ) { 1005 snprintf( buf, sizeof(buf), 1006 "plugin %d name: %s; " 1007 "vendor: %s; " 1008 "version: %s; " 1009 "description: %s", 1010 i, 1011 srchdesc->spd_id, 1012 srchdesc->spd_vendor, 1013 srchdesc->spd_version, 1014 srchdesc->spd_description ); 1015 } else { 1016 snprintf( buf, sizeof(buf), 1017 "plugin %d name: <no description available>", i ); 1018 } 1019 1020 ber_str2bv( buf, 0, 0, &bv ); 1021 attr_merge_normalize_one( e_database, 1022 mi->mi_ad_monitoredInfo, &bv, NULL ); 1023 1024 i++; 1025 1026 } while ( ( slapi_int_pblock_get_next( &pCurrentPB ) == LDAP_SUCCESS ) 1027 && ( pCurrentPB != NULL ) ); 1028 1029 done: 1030 return rc; 1031 } 1032 #endif /* defined(LDAP_SLAPI) */ 1033