1 /* deref.c - dereference overlay */
3 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
5 * Copyright 1998-2008 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 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" ] } } }
102 #define o_deref o_ctrlflag[deref_cid]
103 #define o_ctrlderef o_controls[deref_cid]
105 typedef struct DerefSpec {
106 AttributeDescription *ds_derefAttr;
107 AttributeDescription **ds_attributes;
109 struct DerefSpec *ds_next;
112 typedef struct DerefVal {
113 struct berval dv_derefSpecVal;
114 BerVarray *dv_attrVals;
117 typedef struct DerefRes {
120 struct DerefRes *dr_next;
123 typedef struct deref_cb_t {
124 slap_overinst *dc_on;
128 static int deref_cid;
129 static slap_overinst deref;
138 BerElementBuffer berbuf;
139 BerElement *ber = (BerElement *)&berbuf;
142 DerefSpec *dshead = NULL, **dsp = &dshead;
143 BerVarray attributes = NULL;
145 if ( op->o_deref != SLAP_CONTROL_NONE ) {
146 rs->sr_text = "Dereference control specified multiple times";
147 return LDAP_PROTOCOL_ERROR;
150 if ( BER_BVISNULL( &ctrl->ldctl_value ) ) {
151 rs->sr_text = "Dereference control value is absent";
152 return LDAP_PROTOCOL_ERROR;
155 if ( BER_BVISEMPTY( &ctrl->ldctl_value ) ) {
156 rs->sr_text = "Dereference control value is empty";
157 return LDAP_PROTOCOL_ERROR;
160 ber_init2( ber, &ctrl->ldctl_value, 0 );
162 for ( tag = ber_first_element( ber, &len, &last );
164 tag = ber_next_element( ber, &len, last ) )
166 struct berval derefAttr;
167 DerefSpec *ds, *dstmp;
170 ber_len_t cnt = sizeof(struct berval);
173 if ( ber_scanf( ber, "{m{M}}", &derefAttr, &attributes, &cnt, off ) == LBER_ERROR )
175 rs->sr_text = "Dereference control: derefSpec decoding error";
176 rs->sr_err = LDAP_PROTOCOL_ERROR;
180 ds = (DerefSpec *)op->o_tmpcalloc( 1,
181 sizeof(DerefSpec) + sizeof(AttributeDescription *)*(cnt + 1),
183 ds->ds_attributes = (AttributeDescription **)&ds[1];
186 rc = slap_bv2ad( &derefAttr, &ds->ds_derefAttr, &text );
187 if ( rc != LDAP_SUCCESS ) {
188 rs->sr_text = "Dereference control: derefAttr decoding error";
189 rs->sr_err = LDAP_PROTOCOL_ERROR;
193 for ( dstmp = dshead; dstmp && dstmp != ds; dstmp = dstmp->ds_next ) {
194 if ( dstmp->ds_derefAttr == ds->ds_derefAttr ) {
195 rs->sr_text = "Dereference control: derefAttr must be unique within control";
196 rs->sr_err = LDAP_PROTOCOL_ERROR;
201 if ( ds->ds_derefAttr->ad_type->sat_syntax != slap_schema.si_syn_distinguishedName ) {
202 if ( ctrl->ldctl_iscritical ) {
203 rs->sr_text = "Dereference control: derefAttr syntax not distinguishedName";
204 rs->sr_err = LDAP_PROTOCOL_ERROR;
208 rs->sr_err = LDAP_SUCCESS;
212 for ( cnt = 0; !BER_BVISNULL( &attributes[ cnt ] ); cnt++ ) {
213 rc = slap_bv2ad( &attributes[ cnt ], &ds->ds_attributes[ cnt ], &text );
214 if ( rc != LDAP_SUCCESS ) {
215 rs->sr_text = "Dereference control: attribute decoding error";
216 rs->sr_err = LDAP_PROTOCOL_ERROR;
221 ber_memfree_x( attributes, op->o_tmpmemctx );
228 op->o_ctrlderef = (void *)dshead;
230 op->o_deref = ctrl->ldctl_iscritical
231 ? SLAP_CONTROL_CRITICAL
232 : SLAP_CONTROL_NONCRITICAL;
234 rs->sr_err = LDAP_SUCCESS;
237 if ( rs->sr_err != LDAP_SUCCESS ) {
240 DerefSpec *dsnext = dshead->ds_next;
241 op->o_tmpfree( dshead, op->o_tmpmemctx );
246 if ( attributes != NULL ) {
247 ber_memfree_x( attributes, op->o_tmpmemctx );
254 deref_response( Operation *op, SlapReply *rs )
256 int rc = SLAP_CB_CONTINUE;
258 if ( rs->sr_type == REP_SEARCH ) {
259 BerElementBuffer berbuf;
260 BerElement *ber = (BerElement *) &berbuf;
261 deref_cb_t *dc = (deref_cb_t *)op->o_callback->sc_private;
263 DerefRes *dr, *drhead = NULL, **drp = &drhead;
264 BackendInfo *bi = op->o_bd->bd_info;
265 struct berval bv = BER_BVNULL;
266 int nDerefRes = 0, nDerefVals = 0, nAttrs = 0, nVals = 0;
267 struct berval ctrlval;
268 LDAPControl *ctrl, **ctrlsp;
271 op->o_bd->bd_info = (BackendInfo *)dc->dc_on->on_info;
272 for ( ds = dc->dc_ds; ds; ds = ds->ds_next ) {
273 Attribute *a = attr_find( rs->sr_entry->e_attrs, ds->ds_derefAttr );
279 dr = op->o_tmpcalloc( 1,
280 sizeof( DerefRes ) + ( sizeof( DerefVal ) + sizeof( BerVarray * ) * ds->ds_nattrs ) * ( a->a_numvals + 1 ),
283 dv = dr->dr_vals = (DerefVal *)&dr[ 1 ];
284 bva = (BerVarray *)&dv[ a->a_numvals + 1 ];
286 bv.bv_len += ds->ds_derefAttr->ad_cname.bv_len;
290 for ( i = 0; !BER_BVISNULL( &a->a_nvals[ i ] ); i++ ) {
293 dv[ i ].dv_attrVals = bva;
294 bva += ds->ds_nattrs;
296 dv[i].dv_derefSpecVal = a->a_vals[ i ];
297 bv.bv_len += dv[i].dv_derefSpecVal.bv_len;
301 rc = overlay_entry_get_ov( op, &a->a_nvals[ i ], NULL, NULL, 0, &e, dc->dc_on );
302 if ( rc == LDAP_SUCCESS && e != NULL ) {
305 for ( j = 0; j < ds->ds_nattrs; j++ ) {
306 Attribute *aa = attr_find( e->e_attrs, ds->ds_attributes[ j ] );
310 dv[i].dv_attrVals[ j ] = aa->a_vals;
312 bv.bv_len += ds->ds_attributes[ j ]->ad_cname.bv_len;
313 for ( k = 0; !BER_BVISNULL( &aa->a_vals[ k ] ); k++ ) {
314 bv.bv_len += aa->a_vals[ k ].bv_len;
321 overlay_entry_release_ov( op, e, 0, dc->dc_on );
329 op->o_bd->bd_info = bi;
331 if ( drhead == NULL ) {
332 return SLAP_CB_CONTINUE;
335 /* cook the control value */
336 bv.bv_len += nVals * sizeof(struct berval)
337 + nAttrs * sizeof(struct berval)
338 + nDerefVals * sizeof(DerefVal)
339 + nDerefRes * sizeof(DerefRes);
340 bv.bv_val = op->o_tmpalloc( bv.bv_len, op->o_tmpmemctx );
342 ber_init2( ber, &bv, LBER_USE_DER );
343 ber_set_option( ber, LBER_OPT_BER_MEMCTX, &op->o_tmpmemctx );
346 rc = ber_printf( ber, "{" /*}*/ );
347 for ( dr = drhead; dr != NULL; dr = dr->dr_next ) {
348 rc = ber_printf( ber, "{{O{" /*}}}*/,
349 &dr->dr_spec.ds_derefAttr->ad_cname );
350 for ( i = 0; i < dr->dr_spec.ds_nattrs; i++ ) {
351 rc = ber_printf( ber, "O",
352 &dr->dr_spec.ds_attributes[ i ]->ad_cname );
354 rc = ber_printf( ber, /*{{*/ "}}{" /*}*/ );
355 for ( i = 0; !BER_BVISNULL( &dr->dr_vals[ i ].dv_derefSpecVal ); i++ ) {
358 rc = ber_printf( ber, "{O{" /*}}*/ ,
359 &dr->dr_vals[ i ].dv_derefSpecVal );
360 for ( j = 0; j < dr->dr_spec.ds_nattrs; j++ ) {
361 if ( dr->dr_vals[ i ].dv_attrVals[ j ] != NULL ) {
362 rc = ber_printf( ber, "[W]", dr->dr_vals[ i ].dv_attrVals[ j ] );
364 rc = ber_printf( ber, "b", 0 );
367 rc = ber_printf( ber, /*{{*/ "}}" );
369 rc = ber_printf( ber, /*{{*/ "}}" );
371 rc = ber_printf( ber, /*{*/ "}" );
374 rc = ber_printf( ber, "{" /*}*/ );
375 for ( dr = drhead; dr != NULL; dr = dr->dr_next ) {
376 for ( i = 0; !BER_BVISNULL( &dr->dr_vals[ i ].dv_derefSpecVal ); i++ ) {
379 rc = ber_printf( ber, "{OO{" /*}*/,
380 &dr->dr_spec.ds_derefAttr->ad_cname,
381 &dr->dr_vals[ i ].dv_derefSpecVal );
382 for ( j = 0; j < dr->dr_spec.ds_nattrs; j++ ) {
383 if ( dr->dr_vals[ i ].dv_attrVals[ j ] != NULL ) {
384 rc = ber_printf( ber, "{O[W]}",
385 &dr->dr_spec.ds_attributes[ j ]->ad_cname,
386 dr->dr_vals[ i ].dv_attrVals[ j ] );
389 rc = ber_printf( ber, /*{*/ "}N}" );
392 rc = ber_printf( ber, /*{*/ "}" );
393 if ( ber_flatten2( ber, &ctrlval, 0 ) == -1 ) {
394 if ( op->o_deref == SLAP_CONTROL_CRITICAL ) {
395 rc = LDAP_CONSTRAINT_VIOLATION;
398 rc = SLAP_CB_CONTINUE;
403 ctrl = op->o_tmpcalloc( 1,
404 sizeof( LDAPControl ) + ctrlval.bv_len + 1,
406 ctrl->ldctl_value.bv_val = (char *)&ctrl[ 1 ];
407 ctrl->ldctl_oid = LDAP_CONTROL_X_DEREF;
408 ctrl->ldctl_iscritical = 0;
409 ctrl->ldctl_value.bv_len = ctrlval.bv_len;
410 lutil_strncopy( ctrl->ldctl_value.bv_val, ctrlval.bv_val, ctrlval.bv_len );
411 ctrl->ldctl_value.bv_val[ ctrl->ldctl_value.bv_len ] = '\0';
416 if ( rs->sr_ctrls ) {
417 for ( ; rs->sr_ctrls[ i ] != NULL; i++ )
421 ctrlsp = op->o_tmpcalloc( i, sizeof(LDAPControl *), op->o_tmpmemctx );
423 if ( rs->sr_ctrls != NULL ) {
424 for ( ; rs->sr_ctrls[ i ] != NULL; i++ ) {
425 ctrlsp[ i ] = rs->sr_ctrls[ i ];
428 ctrlsp[ i++ ] = ctrl;
429 ctrlsp[ i++ ] = NULL;
430 if ( rs->sr_flags & REP_CTRLS_MUSTBEFREED ) {
431 op->o_tmpfree( rs->sr_ctrls, op->o_tmpmemctx );
433 rs->sr_ctrls = ctrlsp;
434 rs->sr_flags |= REP_CTRLS_MUSTBEFREED;
436 rc = SLAP_CB_CONTINUE;
440 for ( ; drhead != NULL; ) {
441 DerefRes *drnext = drhead->dr_next;
442 op->o_tmpfree( drhead, op->o_tmpmemctx );
451 deref_cleanup( Operation *op, SlapReply *rs )
453 if ( rs->sr_type == REP_RESULT || rs->sr_err == SLAPD_ABANDON ) {
454 op->o_tmpfree( op->o_callback, op->o_tmpmemctx );
455 op->o_callback = NULL;
457 op->o_tmpfree( op->o_ctrlderef, op->o_tmpmemctx );
458 op->o_ctrlderef = NULL;
461 return SLAP_CB_CONTINUE;
465 deref_op_search( Operation *op, SlapReply *rs )
471 sc = op->o_tmpcalloc( 1, sizeof( slap_callback ) + sizeof( deref_cb_t ), op->o_tmpmemctx );
473 dc = (deref_cb_t *)&sc[ 1 ];
474 dc->dc_on = (slap_overinst *)op->o_bd->bd_info;
475 dc->dc_ds = (DerefSpec *)op->o_ctrlderef;
477 sc->sc_response = deref_response;
478 sc->sc_cleanup = deref_cleanup;
479 sc->sc_private = (void *)dc;
481 sc->sc_next = op->o_callback->sc_next;
482 op->o_callback->sc_next = sc;
485 return SLAP_CB_CONTINUE;
493 rc = register_supported_control( LDAP_CONTROL_X_DEREF,
494 SLAP_CTRL_SEARCH, NULL,
495 deref_parseCtrl, &deref_cid );
496 if ( rc != LDAP_SUCCESS ) {
497 Debug( LDAP_DEBUG_ANY,
498 "deref_init: Failed to register control (%d)\n",
503 deref.on_bi.bi_type = "deref";
504 deref.on_bi.bi_op_search = deref_op_search;
506 return overlay_register( &deref );
509 #if SLAPD_OVER_DEREF == SLAPD_MOD_DYNAMIC
511 init_module( int argc, char *argv[] )
513 return deref_initialize();
515 #endif /* SLAPD_OVER_DEREF == SLAPD_MOD_DYNAMIC */
517 #endif /* SLAPD_OVER_DEREF */