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