1 /* deref.c - dereference overlay */
3 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
5 * Copyright 1998-2013 The OpenLDAP Foundation.
6 * Portions Copyright 2008 Pierangelo Masarati.
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted only as authorized by the OpenLDAP
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>.
18 * This work was initially developed by Pierangelo Masarati
19 * for inclusion in OpenLDAP Software.
24 #ifdef SLAPD_OVER_DEREF
28 #include "ac/string.h"
29 #include "ac/socket.h"
41 * controlValue ::= SEQUENCE OF derefSpec DerefSpec
43 * DerefSpec ::= SEQUENCE {
44 * derefAttr attributeDescription, ; DN-valued
45 * attributes AttributeList }
47 * AttributeList ::= SEQUENCE OF attr AttributeDescription
49 * derefAttr MUST be unique within controlValue
54 * controlValue ::= SEQUENCE OF DerefRes
57 * PartialAttribute ::= SEQUENCE {
58 * type AttributeDescription,
59 * vals SET OF value AttributeValue }
61 * PartialAttributeList ::= SEQUENCE OF
62 * partialAttribute PartialAttribute
64 * DerefRes ::= SEQUENCE {
65 * derefAttr AttributeDescription,
67 * attrVals [0] PartialAttributeList OPTIONAL }
69 * If vals is empty, partialAttribute is omitted.
70 * If all vals in attrVals are empty, attrVals is omitted.
78 * { { member, { GUID, SID } }, { memberOf, { GUID, SID } } }
82 * { { memberOf, "cn=abartlet,cn=users,dc=abartlet,dc=net",
83 * { { GUID, [ "0bc11d00-e431-40a0-8767-344a320142fa" ] },
84 * { SID, [ "S-1-2-3-2345" ] } } },
85 * { memberOf, "cn=ando,cn=users,dc=sys-net,dc=it",
86 * { { GUID, [ "0bc11d00-e431-40a0-8767-344a320142fb" ] },
87 * { SID, [ "S-1-2-3-2346" ] } } } }
93 * { { member, { cn, uid, drink } } }
97 * { { member, "cn=ando,cn=users,dc=sys-net,dc=it",
98 * { { cn, [ "ando", "Pierangelo Masarati" ] },
99 * { uid, [ "ando" ] } } },
100 * { member, "dc=sys-net,dc=it" } }
103 * 3. Security considerations
105 * The control result must not disclose information the client's
106 * identity could not have accessed directly by performing the related
107 * search operations. The presence of a derefVal in the control
108 * response does not imply neither the existence of nor any access
109 * privilege to the corresponding entry. It is merely a consequence
110 * of the read access the client's identity has on the corresponding
114 #define o_deref o_ctrlflag[deref_cid]
115 #define o_ctrlderef o_controls[deref_cid]
117 typedef struct DerefSpec {
118 AttributeDescription *ds_derefAttr;
119 AttributeDescription **ds_attributes;
121 struct DerefSpec *ds_next;
124 typedef struct DerefVal {
125 struct berval dv_derefSpecVal;
126 BerVarray *dv_attrVals;
129 typedef struct DerefRes {
132 struct DerefRes *dr_next;
135 typedef struct deref_cb_t {
136 slap_overinst *dc_on;
140 static int deref_cid;
141 static slap_overinst deref;
151 BerElementBuffer berbuf;
152 BerElement *ber = (BerElement *)&berbuf;
155 DerefSpec *dshead = NULL, **dsp = &dshead;
156 BerVarray attributes = NULL;
158 if ( op->o_deref != SLAP_CONTROL_NONE ) {
159 rs->sr_text = "Dereference control specified multiple times";
160 return LDAP_PROTOCOL_ERROR;
163 if ( BER_BVISNULL( &ctrl->ldctl_value ) ) {
164 rs->sr_text = "Dereference control value is absent";
165 return LDAP_PROTOCOL_ERROR;
168 if ( BER_BVISEMPTY( &ctrl->ldctl_value ) ) {
169 rs->sr_text = "Dereference control value is empty";
170 return LDAP_PROTOCOL_ERROR;
173 ber_init2( ber, &ctrl->ldctl_value, 0 );
175 for ( tag = ber_first_element( ber, &len, &last );
177 tag = ber_next_element( ber, &len, last ) )
179 struct berval derefAttr;
180 DerefSpec *ds, *dstmp;
183 ber_len_t cnt = sizeof(struct berval);
186 if ( ber_scanf( ber, "{m{M}}", &derefAttr, &attributes, &cnt, off ) == LBER_ERROR )
188 rs->sr_text = "Dereference control: derefSpec decoding error";
189 rs->sr_err = LDAP_PROTOCOL_ERROR;
193 ds = (DerefSpec *)op->o_tmpcalloc( 1,
194 sizeof(DerefSpec) + sizeof(AttributeDescription *)*(cnt + 1),
196 ds->ds_attributes = (AttributeDescription **)&ds[ 1 ];
199 rc = slap_bv2ad( &derefAttr, &ds->ds_derefAttr, &text );
200 if ( rc != LDAP_SUCCESS ) {
201 rs->sr_text = "Dereference control: derefAttr decoding error";
202 rs->sr_err = LDAP_PROTOCOL_ERROR;
206 for ( dstmp = dshead; dstmp && dstmp != ds; dstmp = dstmp->ds_next ) {
207 if ( dstmp->ds_derefAttr == ds->ds_derefAttr ) {
208 rs->sr_text = "Dereference control: derefAttr must be unique within control";
209 rs->sr_err = LDAP_PROTOCOL_ERROR;
214 if ( !( ds->ds_derefAttr->ad_type->sat_syntax->ssyn_flags & SLAP_SYNTAX_DN )) {
215 if ( ctrl->ldctl_iscritical ) {
216 rs->sr_text = "Dereference control: derefAttr syntax not distinguishedName";
217 rs->sr_err = LDAP_PROTOCOL_ERROR;
221 rs->sr_err = LDAP_SUCCESS;
225 for ( cnt = 0; !BER_BVISNULL( &attributes[ cnt ] ); cnt++ ) {
226 rc = slap_bv2ad( &attributes[ cnt ], &ds->ds_attributes[ cnt ], &text );
227 if ( rc != LDAP_SUCCESS ) {
228 rs->sr_text = "Dereference control: attribute decoding error";
229 rs->sr_err = LDAP_PROTOCOL_ERROR;
234 ber_memfree_x( attributes, op->o_tmpmemctx );
241 op->o_ctrlderef = (void *)dshead;
243 op->o_deref = ctrl->ldctl_iscritical
244 ? SLAP_CONTROL_CRITICAL
245 : SLAP_CONTROL_NONCRITICAL;
247 rs->sr_err = LDAP_SUCCESS;
250 if ( rs->sr_err != LDAP_SUCCESS ) {
253 DerefSpec *dsnext = dshead->ds_next;
254 op->o_tmpfree( dshead, op->o_tmpmemctx );
259 if ( attributes != NULL ) {
260 ber_memfree_x( attributes, op->o_tmpmemctx );
267 deref_cleanup( Operation *op, SlapReply *rs )
269 if ( rs->sr_type == REP_RESULT || rs->sr_err == SLAPD_ABANDON ) {
270 op->o_tmpfree( op->o_callback, op->o_tmpmemctx );
271 op->o_callback = NULL;
273 op->o_tmpfree( op->o_ctrlderef, op->o_tmpmemctx );
274 op->o_ctrlderef = NULL;
277 return SLAP_CB_CONTINUE;
281 deref_response( Operation *op, SlapReply *rs )
283 int rc = SLAP_CB_CONTINUE;
285 if ( rs->sr_type == REP_SEARCH ) {
286 BerElementBuffer berbuf;
287 BerElement *ber = (BerElement *) &berbuf;
288 deref_cb_t *dc = (deref_cb_t *)op->o_callback->sc_private;
290 DerefRes *dr, *drhead = NULL, **drp = &drhead;
291 struct berval bv = BER_BVNULL;
292 int nDerefRes = 0, nDerefVals = 0, nAttrs = 0, nVals = 0;
293 struct berval ctrlval;
294 LDAPControl *ctrl, *ctrlsp[2];
295 AccessControlState acl_state = ACL_STATE_INIT;
296 static char dummy = '\0';
300 rc = overlay_entry_get_ov( op, &rs->sr_entry->e_nname, NULL, NULL, 0, &ebase, dc->dc_on );
301 if ( rc != LDAP_SUCCESS || ebase == NULL ) {
302 return SLAP_CB_CONTINUE;
305 for ( ds = dc->dc_ds; ds; ds = ds->ds_next ) {
306 Attribute *a = attr_find( ebase->e_attrs, ds->ds_derefAttr );
312 if ( !access_allowed( op, rs->sr_entry, a->a_desc,
313 NULL, ACL_READ, &acl_state ) )
318 dr = op->o_tmpcalloc( 1,
319 sizeof( DerefRes ) + ( sizeof( DerefVal ) + sizeof( BerVarray * ) * ds->ds_nattrs ) * ( a->a_numvals + 1 ),
322 dv = dr->dr_vals = (DerefVal *)&dr[ 1 ];
323 bva = (BerVarray *)&dv[ a->a_numvals + 1 ];
325 bv.bv_len += ds->ds_derefAttr->ad_cname.bv_len;
329 for ( i = 0; !BER_BVISNULL( &a->a_nvals[ i ] ); i++ ) {
332 dv[ i ].dv_attrVals = bva;
333 bva += ds->ds_nattrs;
336 if ( !access_allowed( op, rs->sr_entry, a->a_desc,
337 &a->a_nvals[ i ], ACL_READ, &acl_state ) )
339 dv[ i ].dv_derefSpecVal.bv_val = &dummy;
343 ber_dupbv_x( &dv[ i ].dv_derefSpecVal, &a->a_vals[ i ], op->o_tmpmemctx );
344 bv.bv_len += dv[ i ].dv_derefSpecVal.bv_len;
348 rc = overlay_entry_get_ov( op, &a->a_nvals[ i ], NULL, NULL, 0, &e, dc->dc_on );
349 if ( rc == LDAP_SUCCESS && e != NULL ) {
352 if ( access_allowed( op, e, slap_schema.si_ad_entry,
353 NULL, ACL_READ, NULL ) )
355 for ( j = 0; j < ds->ds_nattrs; j++ ) {
358 if ( !access_allowed( op, e, ds->ds_attributes[ j ], NULL,
359 ACL_READ, &acl_state ) )
364 aa = attr_find( e->e_attrs, ds->ds_attributes[ j ] );
366 unsigned k, h, last = aa->a_numvals;
368 ber_bvarray_dup_x( &dv[ i ].dv_attrVals[ j ],
369 aa->a_vals, op->o_tmpmemctx );
371 bv.bv_len += ds->ds_attributes[ j ]->ad_cname.bv_len;
373 for ( k = 0, h = 0; k < aa->a_numvals; k++ ) {
374 if ( !access_allowed( op, e,
377 ACL_READ, &acl_state ) )
379 op->o_tmpfree( dv[ i ].dv_attrVals[ j ][ h ].bv_val,
381 dv[ i ].dv_attrVals[ j ][ h ] = dv[ i ].dv_attrVals[ j ][ --last ];
382 BER_BVZERO( &dv[ i ].dv_attrVals[ j ][ last ] );
385 bv.bv_len += dv[ i ].dv_attrVals[ j ][ h ].bv_len;
394 overlay_entry_release_ov( op, e, 0, dc->dc_on );
402 overlay_entry_release_ov( op, ebase, 0, dc->dc_on );
404 if ( drhead == NULL ) {
405 return SLAP_CB_CONTINUE;
408 /* cook the control value */
409 bv.bv_len += nVals * sizeof(struct berval)
410 + nAttrs * sizeof(struct berval)
411 + nDerefVals * sizeof(DerefVal)
412 + nDerefRes * sizeof(DerefRes);
413 bv.bv_val = op->o_tmpalloc( bv.bv_len, op->o_tmpmemctx );
415 ber_init2( ber, &bv, LBER_USE_DER );
416 ber_set_option( ber, LBER_OPT_BER_MEMCTX, &op->o_tmpmemctx );
418 rc = ber_printf( ber, "{" /*}*/ );
419 for ( dr = drhead; dr != NULL; dr = dr->dr_next ) {
420 for ( i = 0; !BER_BVISNULL( &dr->dr_vals[ i ].dv_derefSpecVal ); i++ ) {
423 if ( dr->dr_vals[ i ].dv_derefSpecVal.bv_val == &dummy ) {
427 rc = ber_printf( ber, "{OO" /*}*/,
428 &dr->dr_spec.ds_derefAttr->ad_cname,
429 &dr->dr_vals[ i ].dv_derefSpecVal );
430 op->o_tmpfree( dr->dr_vals[ i ].dv_derefSpecVal.bv_val, op->o_tmpmemctx );
431 for ( j = 0; j < dr->dr_spec.ds_nattrs; j++ ) {
432 if ( dr->dr_vals[ i ].dv_attrVals[ j ] != NULL ) {
434 rc = ber_printf( ber, "t{" /*}*/,
435 (LBER_CONSTRUCTED|LBER_CLASS_CONTEXT) );
438 rc = ber_printf( ber, "{O[W]}",
439 &dr->dr_spec.ds_attributes[ j ]->ad_cname,
440 dr->dr_vals[ i ].dv_attrVals[ j ] );
441 op->o_tmpfree( dr->dr_vals[ i ].dv_attrVals[ j ],
446 rc = ber_printf( ber, /*{{*/ "}N}" );
448 rc = ber_printf( ber, /*{*/ "}" );
452 rc = ber_printf( ber, /*{*/ "}" );
453 if ( ber_flatten2( ber, &ctrlval, 0 ) == -1 ) {
454 if ( op->o_deref == SLAP_CONTROL_CRITICAL ) {
455 rc = LDAP_CONSTRAINT_VIOLATION;
458 rc = SLAP_CB_CONTINUE;
463 ctrl = op->o_tmpcalloc( 1,
464 sizeof( LDAPControl ) + ctrlval.bv_len + 1,
466 ctrl->ldctl_value.bv_val = (char *)&ctrl[ 1 ];
467 ctrl->ldctl_oid = LDAP_CONTROL_X_DEREF;
468 ctrl->ldctl_iscritical = 0;
469 ctrl->ldctl_value.bv_len = ctrlval.bv_len;
470 AC_MEMCPY( ctrl->ldctl_value.bv_val, ctrlval.bv_val, ctrlval.bv_len );
471 ctrl->ldctl_value.bv_val[ ctrl->ldctl_value.bv_len ] = '\0';
477 slap_add_ctrls( op, rs, ctrlsp );
479 rc = SLAP_CB_CONTINUE;
483 for ( ; drhead != NULL; ) {
484 DerefRes *drnext = drhead->dr_next;
485 op->o_tmpfree( drhead, op->o_tmpmemctx );
489 } else if ( rs->sr_type == REP_RESULT ) {
490 rc = deref_cleanup( op, rs );
497 deref_op_search( Operation *op, SlapReply *rs )
503 sc = op->o_tmpcalloc( 1, sizeof( slap_callback ) + sizeof( deref_cb_t ), op->o_tmpmemctx );
505 dc = (deref_cb_t *)&sc[ 1 ];
506 dc->dc_on = (slap_overinst *)op->o_bd->bd_info;
507 dc->dc_ds = (DerefSpec *)op->o_ctrlderef;
509 sc->sc_response = deref_response;
510 sc->sc_cleanup = deref_cleanup;
511 sc->sc_private = (void *)dc;
513 sc->sc_next = op->o_callback->sc_next;
514 op->o_callback->sc_next = sc;
517 return SLAP_CB_CONTINUE;
521 deref_db_init( BackendDB *be, ConfigReply *cr)
523 if ( ov_count == 0 ) {
526 rc = register_supported_control2( LDAP_CONTROL_X_DEREF,
532 if ( rc != LDAP_SUCCESS ) {
533 Debug( LDAP_DEBUG_ANY,
534 "deref_init: Failed to register control (%d)\n",
544 deref_db_open( BackendDB *be, ConfigReply *cr)
546 return overlay_register_control( be, LDAP_CONTROL_X_DEREF );
549 #ifdef SLAP_CONFIG_DELETE
551 deref_db_destroy( BackendDB *be, ConfigReply *cr)
554 overlay_unregister_control( be, LDAP_CONTROL_X_DEREF );
555 if ( ov_count == 0 ) {
556 unregister_supported_control( LDAP_CONTROL_X_DEREF );
560 #endif /* SLAP_CONFIG_DELETE */
563 deref_initialize(void)
565 deref.on_bi.bi_type = "deref";
566 deref.on_bi.bi_db_init = deref_db_init;
567 deref.on_bi.bi_db_open = deref_db_open;
568 #ifdef SLAP_CONFIG_DELETE
569 deref.on_bi.bi_db_destroy = deref_db_destroy;
570 #endif /* SLAP_CONFIG_DELETE */
571 deref.on_bi.bi_op_search = deref_op_search;
573 return overlay_register( &deref );
576 #if SLAPD_OVER_DEREF == SLAPD_MOD_DYNAMIC
578 init_module( int argc, char *argv[] )
580 return deref_initialize();
582 #endif /* SLAPD_OVER_DEREF == SLAPD_MOD_DYNAMIC */
584 #endif /* SLAPD_OVER_DEREF */