1 /* $NetBSD: deref.c,v 1.7 2021/08/14 16:15:02 christos Exp $ */ 2 3 /* deref.c - dereference overlay */ 4 /* $OpenLDAP$ */ 5 /* This work is part of OpenLDAP Software <http://www.openldap.org/>. 6 * 7 * Copyright 1998-2021 The OpenLDAP Foundation. 8 * Portions Copyright 2008 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 the 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 21 * for inclusion in OpenLDAP Software. 22 */ 23 24 #include <sys/cdefs.h> 25 __RCSID("$NetBSD: deref.c,v 1.7 2021/08/14 16:15:02 christos Exp $"); 26 27 #include "portable.h" 28 29 #ifdef SLAPD_OVER_DEREF 30 31 #include <stdio.h> 32 33 #include "ac/string.h" 34 #include "ac/socket.h" 35 36 #include "slap.h" 37 #include "slap-config.h" 38 39 #include "lutil.h" 40 41 /* 42 * 1. Specification 43 * 44 * 1.1. Request 45 * 46 * controlValue ::= SEQUENCE OF derefSpec DerefSpec 47 * 48 * DerefSpec ::= SEQUENCE { 49 * derefAttr attributeDescription, ; DN-valued 50 * attributes AttributeList } 51 * 52 * AttributeList ::= SEQUENCE OF attr AttributeDescription 53 * 54 * derefAttr MUST be unique within controlValue 55 * 56 * 57 * 1.2. Response 58 * 59 * controlValue ::= SEQUENCE OF DerefRes 60 * 61 * From RFC 4511: 62 * PartialAttribute ::= SEQUENCE { 63 * type AttributeDescription, 64 * vals SET OF value AttributeValue } 65 * 66 * PartialAttributeList ::= SEQUENCE OF 67 * partialAttribute PartialAttribute 68 * 69 * DerefRes ::= SEQUENCE { 70 * derefAttr AttributeDescription, 71 * derefVal LDAPDN, 72 * attrVals [0] PartialAttributeList OPTIONAL } 73 * 74 * If vals is empty, partialAttribute is omitted. 75 * If all vals in attrVals are empty, attrVals is omitted. 76 * 77 * 2. Examples 78 * 79 * 2.1. Example 80 * 81 * 2.1.1. Request 82 * 83 * { { member, { GUID, SID } }, { memberOf, { GUID, SID } } } 84 * 85 * 2.1.2. Response 86 * 87 * { { memberOf, "cn=abartlet,cn=users,dc=abartlet,dc=net", 88 * { { GUID, [ "0bc11d00-e431-40a0-8767-344a320142fa" ] }, 89 * { SID, [ "S-1-2-3-2345" ] } } }, 90 * { memberOf, "cn=ando,cn=users,dc=sys-net,dc=it", 91 * { { GUID, [ "0bc11d00-e431-40a0-8767-344a320142fb" ] }, 92 * { SID, [ "S-1-2-3-2346" ] } } } } 93 * 94 * 2.2. Example 95 * 96 * 2.2.1. Request 97 * 98 * { { member, { cn, uid, drink } } } 99 * 100 * 2.2.2. Response 101 * 102 * { { member, "cn=ando,cn=users,dc=sys-net,dc=it", 103 * { { cn, [ "ando", "Pierangelo Masarati" ] }, 104 * { uid, [ "ando" ] } } }, 105 * { member, "dc=sys-net,dc=it" } } 106 * 107 * 108 * 3. Security considerations 109 * 110 * The control result must not disclose information the client's 111 * identity could not have accessed directly by performing the related 112 * search operations. The presence of a derefVal in the control 113 * response does not imply neither the existence of nor any access 114 * privilege to the corresponding entry. It is merely a consequence 115 * of the read access the client's identity has on the corresponding 116 * attribute's value. 117 */ 118 119 #define o_deref o_ctrlflag[deref_cid] 120 #define o_ctrlderef o_controls[deref_cid] 121 122 typedef struct DerefSpec { 123 AttributeDescription *ds_derefAttr; 124 AttributeDescription **ds_attributes; 125 int ds_nattrs; 126 struct DerefSpec *ds_next; 127 } DerefSpec; 128 129 typedef struct DerefVal { 130 struct berval dv_derefSpecVal; 131 BerVarray *dv_attrVals; 132 } DerefVal; 133 134 typedef struct DerefRes { 135 DerefSpec dr_spec; 136 DerefVal *dr_vals; 137 struct DerefRes *dr_next; 138 } DerefRes; 139 140 typedef struct deref_cb_t { 141 slap_overinst *dc_on; 142 DerefSpec *dc_ds; 143 } deref_cb_t; 144 145 static int deref_cid; 146 static slap_overinst deref; 147 static int ov_count; 148 149 static int 150 deref_parseCtrl ( 151 Operation *op, 152 SlapReply *rs, 153 LDAPControl *ctrl ) 154 { 155 ber_tag_t tag; 156 BerElementBuffer berbuf; 157 BerElement *ber = (BerElement *)&berbuf; 158 ber_len_t len; 159 char *last; 160 DerefSpec *dshead = NULL, **dsp = &dshead; 161 BerVarray attributes = NULL; 162 163 if ( op->o_deref != SLAP_CONTROL_NONE ) { 164 rs->sr_text = "Dereference control specified multiple times"; 165 return LDAP_PROTOCOL_ERROR; 166 } 167 168 if ( BER_BVISNULL( &ctrl->ldctl_value ) ) { 169 rs->sr_text = "Dereference control value is absent"; 170 return LDAP_PROTOCOL_ERROR; 171 } 172 173 if ( BER_BVISEMPTY( &ctrl->ldctl_value ) ) { 174 rs->sr_text = "Dereference control value is empty"; 175 return LDAP_PROTOCOL_ERROR; 176 } 177 178 ber_init2( ber, &ctrl->ldctl_value, 0 ); 179 180 for ( tag = ber_first_element( ber, &len, &last ); 181 tag != LBER_DEFAULT; 182 tag = ber_next_element( ber, &len, last ) ) 183 { 184 struct berval derefAttr; 185 DerefSpec *ds, *dstmp; 186 const char *text; 187 int rc; 188 ber_len_t cnt = sizeof(struct berval); 189 ber_len_t off = 0; 190 191 if ( ber_scanf( ber, "{m{M}}", &derefAttr, &attributes, &cnt, off ) == LBER_ERROR 192 || !cnt ) 193 { 194 rs->sr_text = "Dereference control: derefSpec decoding error"; 195 rs->sr_err = LDAP_PROTOCOL_ERROR; 196 goto done; 197 } 198 199 ds = (DerefSpec *)op->o_tmpcalloc( 1, 200 sizeof(DerefSpec) + sizeof(AttributeDescription *)*(cnt + 1), 201 op->o_tmpmemctx ); 202 ds->ds_attributes = (AttributeDescription **)&ds[ 1 ]; 203 ds->ds_nattrs = cnt; 204 205 rc = slap_bv2ad( &derefAttr, &ds->ds_derefAttr, &text ); 206 if ( rc != LDAP_SUCCESS ) { 207 rs->sr_text = "Dereference control: derefAttr decoding error"; 208 rs->sr_err = LDAP_PROTOCOL_ERROR; 209 goto done; 210 } 211 212 for ( dstmp = dshead; dstmp && dstmp != ds; dstmp = dstmp->ds_next ) { 213 if ( dstmp->ds_derefAttr == ds->ds_derefAttr ) { 214 rs->sr_text = "Dereference control: derefAttr must be unique within control"; 215 rs->sr_err = LDAP_PROTOCOL_ERROR; 216 goto done; 217 } 218 } 219 220 if ( !( ds->ds_derefAttr->ad_type->sat_syntax->ssyn_flags & SLAP_SYNTAX_DN )) { 221 if ( ctrl->ldctl_iscritical ) { 222 rs->sr_text = "Dereference control: derefAttr syntax not distinguishedName"; 223 rs->sr_err = LDAP_PROTOCOL_ERROR; 224 goto done; 225 } 226 227 rs->sr_err = LDAP_SUCCESS; 228 goto justcleanup; 229 } 230 231 for ( cnt = 0; !BER_BVISNULL( &attributes[ cnt ] ); cnt++ ) { 232 rc = slap_bv2ad( &attributes[ cnt ], &ds->ds_attributes[ cnt ], &text ); 233 if ( rc != LDAP_SUCCESS ) { 234 rs->sr_text = "Dereference control: attribute decoding error"; 235 rs->sr_err = LDAP_PROTOCOL_ERROR; 236 goto done; 237 } 238 } 239 240 ber_memfree_x( attributes, op->o_tmpmemctx ); 241 attributes = NULL; 242 243 *dsp = ds; 244 dsp = &ds->ds_next; 245 } 246 247 op->o_ctrlderef = (void *)dshead; 248 249 op->o_deref = ctrl->ldctl_iscritical 250 ? SLAP_CONTROL_CRITICAL 251 : SLAP_CONTROL_NONCRITICAL; 252 253 rs->sr_err = LDAP_SUCCESS; 254 255 done:; 256 if ( rs->sr_err != LDAP_SUCCESS ) { 257 justcleanup:; 258 for ( ; dshead; ) { 259 DerefSpec *dsnext = dshead->ds_next; 260 op->o_tmpfree( dshead, op->o_tmpmemctx ); 261 dshead = dsnext; 262 } 263 } 264 265 if ( attributes != NULL ) { 266 ber_memfree_x( attributes, op->o_tmpmemctx ); 267 } 268 269 return rs->sr_err; 270 } 271 272 static int 273 deref_cleanup( Operation *op, SlapReply *rs ) 274 { 275 if ( rs->sr_type == REP_RESULT || rs->sr_err == SLAPD_ABANDON ) { 276 op->o_tmpfree( op->o_callback, op->o_tmpmemctx ); 277 op->o_callback = NULL; 278 279 op->o_tmpfree( op->o_ctrlderef, op->o_tmpmemctx ); 280 op->o_ctrlderef = NULL; 281 } 282 283 return SLAP_CB_CONTINUE; 284 } 285 286 static int 287 deref_response( Operation *op, SlapReply *rs ) 288 { 289 int rc = SLAP_CB_CONTINUE; 290 291 if ( rs->sr_type == REP_SEARCH ) { 292 BerElementBuffer berbuf; 293 BerElement *ber = (BerElement *) &berbuf; 294 deref_cb_t *dc = (deref_cb_t *)op->o_callback->sc_private; 295 DerefSpec *ds; 296 DerefRes *dr, *drhead = NULL, **drp = &drhead; 297 struct berval bv = BER_BVNULL; 298 int nDerefRes = 0, nDerefVals = 0, nAttrs = 0, nVals = 0; 299 struct berval ctrlval; 300 LDAPControl *ctrl, *ctrlsp[2]; 301 AccessControlState acl_state = ACL_STATE_INIT; 302 static char dummy = '\0'; 303 Entry *ebase; 304 int i; 305 306 rc = overlay_entry_get_ov( op, &rs->sr_entry->e_nname, NULL, NULL, 0, &ebase, dc->dc_on ); 307 if ( rc != LDAP_SUCCESS || ebase == NULL ) { 308 return SLAP_CB_CONTINUE; 309 } 310 311 for ( ds = dc->dc_ds; ds; ds = ds->ds_next ) { 312 Attribute *a = attr_find( ebase->e_attrs, ds->ds_derefAttr ); 313 314 if ( a != NULL ) { 315 DerefVal *dv; 316 BerVarray *bva; 317 318 if ( !access_allowed( op, rs->sr_entry, a->a_desc, 319 NULL, ACL_READ, &acl_state ) ) 320 { 321 continue; 322 } 323 324 dr = op->o_tmpcalloc( 1, 325 sizeof( DerefRes ) + ( sizeof( DerefVal ) + sizeof( BerVarray * ) * ds->ds_nattrs ) * ( a->a_numvals + 1 ), 326 op->o_tmpmemctx ); 327 dr->dr_spec = *ds; 328 dv = dr->dr_vals = (DerefVal *)&dr[ 1 ]; 329 bva = (BerVarray *)&dv[ a->a_numvals + 1 ]; 330 331 bv.bv_len += ds->ds_derefAttr->ad_cname.bv_len; 332 nAttrs++; 333 nDerefRes++; 334 335 for ( i = 0; !BER_BVISNULL( &a->a_nvals[ i ] ); i++ ) { 336 Entry *e = NULL; 337 338 dv[ i ].dv_attrVals = bva; 339 bva += ds->ds_nattrs; 340 341 342 if ( !access_allowed( op, rs->sr_entry, a->a_desc, 343 &a->a_nvals[ i ], ACL_READ, &acl_state ) ) 344 { 345 dv[ i ].dv_derefSpecVal.bv_val = &dummy; 346 continue; 347 } 348 349 ber_dupbv_x( &dv[ i ].dv_derefSpecVal, &a->a_vals[ i ], op->o_tmpmemctx ); 350 bv.bv_len += dv[ i ].dv_derefSpecVal.bv_len; 351 nVals++; 352 nDerefVals++; 353 354 rc = overlay_entry_get_ov( op, &a->a_nvals[ i ], NULL, NULL, 0, &e, dc->dc_on ); 355 if ( rc == LDAP_SUCCESS && e != NULL ) { 356 int j; 357 358 if ( access_allowed( op, e, slap_schema.si_ad_entry, 359 NULL, ACL_READ, NULL ) ) 360 { 361 for ( j = 0; j < ds->ds_nattrs; j++ ) { 362 Attribute *aa; 363 364 if ( !access_allowed( op, e, ds->ds_attributes[ j ], NULL, 365 ACL_READ, &acl_state ) ) 366 { 367 continue; 368 } 369 370 aa = attr_find( e->e_attrs, ds->ds_attributes[ j ] ); 371 if ( aa != NULL ) { 372 unsigned k, h, last = aa->a_numvals; 373 374 ber_bvarray_dup_x( &dv[ i ].dv_attrVals[ j ], 375 aa->a_vals, op->o_tmpmemctx ); 376 377 bv.bv_len += ds->ds_attributes[ j ]->ad_cname.bv_len; 378 379 for ( k = 0, h = 0; k < aa->a_numvals; k++ ) { 380 if ( !access_allowed( op, e, 381 aa->a_desc, 382 &aa->a_nvals[ k ], 383 ACL_READ, &acl_state ) ) 384 { 385 op->o_tmpfree( dv[ i ].dv_attrVals[ j ][ h ].bv_val, 386 op->o_tmpmemctx ); 387 dv[ i ].dv_attrVals[ j ][ h ] = dv[ i ].dv_attrVals[ j ][ --last ]; 388 BER_BVZERO( &dv[ i ].dv_attrVals[ j ][ last ] ); 389 continue; 390 } 391 bv.bv_len += dv[ i ].dv_attrVals[ j ][ h ].bv_len; 392 nVals++; 393 h++; 394 } 395 nAttrs++; 396 } 397 } 398 } 399 400 overlay_entry_release_ov( op, e, 0, dc->dc_on ); 401 } 402 } 403 404 *drp = dr; 405 drp = &dr->dr_next; 406 } 407 } 408 overlay_entry_release_ov( op, ebase, 0, dc->dc_on ); 409 410 if ( drhead == NULL ) { 411 return SLAP_CB_CONTINUE; 412 } 413 414 /* cook the control value */ 415 bv.bv_len += nVals * sizeof(struct berval) 416 + nAttrs * sizeof(struct berval) 417 + nDerefVals * sizeof(DerefVal) 418 + nDerefRes * sizeof(DerefRes); 419 bv.bv_val = op->o_tmpalloc( bv.bv_len, op->o_tmpmemctx ); 420 421 ber_init2( ber, &bv, LBER_USE_DER ); 422 ber_set_option( ber, LBER_OPT_BER_MEMCTX, &op->o_tmpmemctx ); 423 424 rc = ber_printf( ber, "{" /*}*/ ); 425 for ( dr = drhead; dr != NULL; dr = dr->dr_next ) { 426 for ( i = 0; !BER_BVISNULL( &dr->dr_vals[ i ].dv_derefSpecVal ); i++ ) { 427 int j, first = 1; 428 429 if ( dr->dr_vals[ i ].dv_derefSpecVal.bv_val == &dummy ) { 430 continue; 431 } 432 433 rc = ber_printf( ber, "{OO" /*}*/, 434 &dr->dr_spec.ds_derefAttr->ad_cname, 435 &dr->dr_vals[ i ].dv_derefSpecVal ); 436 op->o_tmpfree( dr->dr_vals[ i ].dv_derefSpecVal.bv_val, op->o_tmpmemctx ); 437 for ( j = 0; j < dr->dr_spec.ds_nattrs; j++ ) { 438 if ( dr->dr_vals[ i ].dv_attrVals[ j ] != NULL ) { 439 if ( first ) { 440 rc = ber_printf( ber, "t{" /*}*/, 441 (LBER_CONSTRUCTED|LBER_CLASS_CONTEXT) ); 442 first = 0; 443 } 444 rc = ber_printf( ber, "{O[W]}", 445 &dr->dr_spec.ds_attributes[ j ]->ad_cname, 446 dr->dr_vals[ i ].dv_attrVals[ j ] ); 447 op->o_tmpfree( dr->dr_vals[ i ].dv_attrVals[ j ], 448 op->o_tmpmemctx ); 449 } 450 } 451 if ( !first ) { 452 rc = ber_printf( ber, /*{{*/ "}N}" ); 453 } else { 454 rc = ber_printf( ber, /*{*/ "}" ); 455 } 456 } 457 } 458 rc = ber_printf( ber, /*{*/ "}" ); 459 if ( ber_flatten2( ber, &ctrlval, 0 ) == -1 ) { 460 if ( op->o_deref == SLAP_CONTROL_CRITICAL ) { 461 rc = LDAP_CONSTRAINT_VIOLATION; 462 463 } else { 464 rc = SLAP_CB_CONTINUE; 465 } 466 goto cleanup; 467 } 468 469 ctrl = op->o_tmpcalloc( 1, 470 sizeof( LDAPControl ) + ctrlval.bv_len + 1, 471 op->o_tmpmemctx ); 472 ctrl->ldctl_value.bv_val = (char *)&ctrl[ 1 ]; 473 ctrl->ldctl_oid = LDAP_CONTROL_X_DEREF; 474 ctrl->ldctl_iscritical = 0; 475 ctrl->ldctl_value.bv_len = ctrlval.bv_len; 476 AC_MEMCPY( ctrl->ldctl_value.bv_val, ctrlval.bv_val, ctrlval.bv_len ); 477 ctrl->ldctl_value.bv_val[ ctrl->ldctl_value.bv_len ] = '\0'; 478 479 ber_free_buf( ber ); 480 481 ctrlsp[0] = ctrl; 482 ctrlsp[1] = NULL; 483 slap_add_ctrls( op, rs, ctrlsp ); 484 485 rc = SLAP_CB_CONTINUE; 486 487 cleanup:; 488 /* release all */ 489 for ( ; drhead != NULL; ) { 490 DerefRes *drnext = drhead->dr_next; 491 op->o_tmpfree( drhead, op->o_tmpmemctx ); 492 drhead = drnext; 493 } 494 495 } else if ( rs->sr_type == REP_RESULT ) { 496 rc = deref_cleanup( op, rs ); 497 } 498 499 return rc; 500 } 501 502 static int 503 deref_op_search( Operation *op, SlapReply *rs ) 504 { 505 if ( op->o_deref ) { 506 slap_callback *sc; 507 deref_cb_t *dc; 508 509 sc = op->o_tmpcalloc( 1, sizeof( slap_callback ) + sizeof( deref_cb_t ), op->o_tmpmemctx ); 510 511 dc = (deref_cb_t *)&sc[ 1 ]; 512 dc->dc_on = (slap_overinst *)op->o_bd->bd_info; 513 dc->dc_ds = (DerefSpec *)op->o_ctrlderef; 514 515 sc->sc_response = deref_response; 516 sc->sc_cleanup = deref_cleanup; 517 sc->sc_private = (void *)dc; 518 519 sc->sc_next = op->o_callback->sc_next; 520 op->o_callback->sc_next = sc; 521 } 522 523 return SLAP_CB_CONTINUE; 524 } 525 526 static int 527 deref_db_init( BackendDB *be, ConfigReply *cr) 528 { 529 if ( ov_count == 0 ) { 530 int rc; 531 532 rc = register_supported_control2( LDAP_CONTROL_X_DEREF, 533 SLAP_CTRL_SEARCH, 534 NULL, 535 deref_parseCtrl, 536 1, /* replace */ 537 &deref_cid ); 538 if ( rc != LDAP_SUCCESS ) { 539 Debug( LDAP_DEBUG_ANY, 540 "deref_init: Failed to register control (%d)\n", 541 rc ); 542 return rc; 543 } 544 } 545 ov_count++; 546 return LDAP_SUCCESS; 547 } 548 549 static int 550 deref_db_open( BackendDB *be, ConfigReply *cr) 551 { 552 return overlay_register_control( be, LDAP_CONTROL_X_DEREF ); 553 } 554 555 #ifdef SLAP_CONFIG_DELETE 556 static int 557 deref_db_destroy( BackendDB *be, ConfigReply *cr) 558 { 559 ov_count--; 560 overlay_unregister_control( be, LDAP_CONTROL_X_DEREF ); 561 if ( ov_count == 0 ) { 562 unregister_supported_control( LDAP_CONTROL_X_DEREF ); 563 } 564 return 0; 565 } 566 #endif /* SLAP_CONFIG_DELETE */ 567 568 int 569 deref_initialize(void) 570 { 571 deref.on_bi.bi_type = "deref"; 572 deref.on_bi.bi_flags = SLAPO_BFLAG_SINGLE; 573 deref.on_bi.bi_db_init = deref_db_init; 574 deref.on_bi.bi_db_open = deref_db_open; 575 #ifdef SLAP_CONFIG_DELETE 576 deref.on_bi.bi_db_destroy = deref_db_destroy; 577 #endif /* SLAP_CONFIG_DELETE */ 578 deref.on_bi.bi_op_search = deref_op_search; 579 580 return overlay_register( &deref ); 581 } 582 583 #if SLAPD_OVER_DEREF == SLAPD_MOD_DYNAMIC 584 int 585 init_module( int argc, char *argv[] ) 586 { 587 return deref_initialize(); 588 } 589 #endif /* SLAPD_OVER_DEREF == SLAPD_MOD_DYNAMIC */ 590 591 #endif /* SLAPD_OVER_DEREF */ 592