]> git.sur5r.net Git - openldap/blob - servers/slapd/overlays/deref.c
96b210aa4f072b07b93bba9173f7718a3378fef9
[openldap] / servers / slapd / overlays / deref.c
1 /* deref.c - dereference overlay */
2 /* $OpenLDAP$ */
3 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
4  *
5  * Copyright 1998-2008 The OpenLDAP Foundation.
6  * Portions Copyright 2008 Pierangelo Masarati.
7  * All rights reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted only as authorized by the OpenLDAP
11  * Public License.
12  *
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>.
16  */
17 /* ACKNOWLEDGEMENTS:
18  * This work was initially developed by Pierangelo Masarati
19  * for inclusion in OpenLDAP Software.
20  */
21
22 #include "portable.h"
23
24 #ifdef SLAPD_OVER_DEREF
25
26 #include <stdio.h>
27
28 #include "ac/string.h"
29 #include "ac/socket.h"
30
31 #include "slap.h"
32 #include "config.h"
33
34 #include "lutil.h"
35
36 /*
37  * 1. Specification
38  *
39  * 1.1. Request
40  *
41  *  controlValue ::= SEQUENCE OF derefSpec DerefSpec
42  *
43  *  DerefSpec ::= SEQUENCE {
44  *      derefAttr       attributeDescription,    ; DN-valued
45  *      attributes      AttributeList }
46  *
47  *  AttributeList ::= SEQUENCE OF attr AttributeDescription
48  *
49  *  derefAttr MUST be unique within controlValue
50  *
51  *
52  * 1.2. Response
53  *
54  *  controlValue ::= SEQUENCE OF DerefRes
55  *
56  * From RFC 4511:
57  *      PartialAttribute ::= SEQUENCE {
58  *           type       AttributeDescription,
59  *           vals       SET OF value AttributeValue }
60  *
61  *      PartialAttributeList ::= SEQUENCE OF
62  *                           partialAttribute PartialAttribute
63  *
64  *  DerefRes ::= SEQUENCE {
65  *      derefAttr       AttributeDescription,
66  *      derefVal        LDAPDN,
67  *      attrVals        PartialAttributeList OPTIONAL }
68  *
69  *  If vals is empty, partialAttribute is omitted.
70  *  If all vals in attrVals are empty, attrVals is omitted.
71  *      
72  * 2. Examples
73  *
74  * 2.1. Example
75  *
76  * 2.1.1. Request
77  *
78  * { { member, { GUID, SID } }, { memberOf, { GUID, SID } } }
79  *
80  * 2.1.2. Response
81  *
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" ] } } }
88  *
89  * 2.2. Example
90  *
91  * 2.2.1. Request
92  *
93  * { { member, { cn, uid, drink } } }
94  *
95  * 2.2.2. Response
96  *
97  * { { member, "cn=ando,cn=users,dc=sys-net,dc=it",
98  *     { cn, [ "ando", "Pierangelo Masarati" ],
99  *       uid, [ "ando" ] } } }
100  */
101
102 #define o_deref                 o_ctrlflag[deref_cid]
103 #define o_ctrlderef             o_controls[deref_cid]
104
105 typedef struct DerefSpec {
106         AttributeDescription    *ds_derefAttr;
107         AttributeDescription    **ds_attributes;
108         int                     ds_nattrs;
109         struct DerefSpec        *ds_next;
110 } DerefSpec;
111
112 typedef struct DerefVal {
113         struct berval   dv_derefSpecVal;
114         BerVarray       *dv_attrVals;
115 } DerefVal;
116
117 typedef struct DerefRes {
118         DerefSpec               dr_spec;
119         DerefVal                *dr_vals;
120         struct DerefRes         *dr_next;
121 } DerefRes;
122
123 typedef struct deref_cb_t {
124         slap_overinst *dc_on;
125         DerefSpec *dc_ds;
126 } deref_cb_t;
127
128 static int                      deref_cid;
129 static slap_overinst            deref;
130
131 static int
132 deref_parseCtrl (
133         Operation *op,
134         SlapReply *rs,
135         LDAPControl *ctrl )
136 {
137         ber_tag_t tag;
138         BerElementBuffer berbuf;
139         BerElement *ber = (BerElement *)&berbuf;
140         ber_len_t len;
141         char *last;
142         DerefSpec *dshead = NULL, **dsp = &dshead;
143         BerVarray attributes = NULL;
144
145         if ( op->o_deref != SLAP_CONTROL_NONE ) {
146                 rs->sr_text = "Dereference control specified multiple times";
147                 return LDAP_PROTOCOL_ERROR;
148         }
149
150         if ( BER_BVISNULL( &ctrl->ldctl_value ) ) {
151                 rs->sr_text = "Dereference control value is absent";
152                 return LDAP_PROTOCOL_ERROR;
153         }
154
155         if ( BER_BVISEMPTY( &ctrl->ldctl_value ) ) {
156                 rs->sr_text = "Dereference control value is empty";
157                 return LDAP_PROTOCOL_ERROR;
158         }
159
160         ber_init2( ber, &ctrl->ldctl_value, 0 );
161
162         for ( tag = ber_first_element( ber, &len, &last );
163                 tag != LBER_DEFAULT;
164                 tag = ber_next_element( ber, &len, last ) )
165         {
166                 struct berval derefAttr;
167                 DerefSpec *ds, *dstmp;
168                 const char *text;
169                 int rc;
170                 ber_len_t cnt = sizeof(struct berval);
171                 ber_len_t off = 0;
172
173                 if ( ber_scanf( ber, "{m{M}}", &derefAttr, &attributes, &cnt, off ) == LBER_ERROR )
174                 {
175                         rs->sr_text = "Dereference control: derefSpec decoding error";
176                         rs->sr_err = LDAP_PROTOCOL_ERROR;
177                         goto done;
178                 }
179
180                 ds = (DerefSpec *)op->o_tmpcalloc( 1,
181                         sizeof(DerefSpec) + sizeof(AttributeDescription *)*(cnt + 1),
182                         op->o_tmpmemctx );
183                 ds->ds_attributes = (AttributeDescription **)&ds[1];
184                 ds->ds_nattrs = cnt;
185
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;
190                         goto done;
191                 }
192
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;
197                                 goto done;
198                         }
199                 }
200
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;
205                                 goto done;
206                         }
207
208                         rs->sr_err = LDAP_SUCCESS;
209                         goto justcleanup;
210                 }
211
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;
217                                 goto done;
218                         }
219                 }
220
221                 ber_memfree_x( attributes, op->o_tmpmemctx );
222                 attributes = NULL;
223
224                 *dsp = ds;
225                 dsp = &ds->ds_next;
226         }
227
228         op->o_ctrlderef = (void *)dshead;
229
230         op->o_deref = ctrl->ldctl_iscritical
231                 ? SLAP_CONTROL_CRITICAL
232                 : SLAP_CONTROL_NONCRITICAL;
233
234         rs->sr_err = LDAP_SUCCESS;
235
236 done:;
237         if ( rs->sr_err != LDAP_SUCCESS ) {
238 justcleanup:;
239                 for ( ; dshead; ) {
240                         DerefSpec *dsnext = dshead->ds_next;
241                         op->o_tmpfree( dshead, op->o_tmpmemctx );
242                         dshead = dsnext;
243                 }
244         }
245
246         if ( attributes != NULL ) {
247                 ber_memfree_x( attributes, op->o_tmpmemctx );
248         }
249
250         return rs->sr_err;
251 }
252
253 static int
254 deref_response( Operation *op, SlapReply *rs )
255 {
256         int rc = SLAP_CB_CONTINUE;
257
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;
262                 DerefSpec *ds;
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;
269                 int i;
270
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 );
274
275                         if ( a != NULL ) {
276                                 DerefVal *dv;
277                                 BerVarray *bva;
278
279                                 dr = op->o_tmpcalloc( 1,
280                                         sizeof( DerefRes ) + ( sizeof( DerefVal ) + sizeof( BerVarray * ) * ds->ds_nattrs ) * ( a->a_numvals + 1 ),
281                                         op->o_tmpmemctx );
282                                 dr->dr_spec = *ds;
283                                 dv = dr->dr_vals = (DerefVal *)&dr[ 1 ];
284                                 bva = (BerVarray *)&dv[ a->a_numvals + 1 ];
285
286                                 bv.bv_len += ds->ds_derefAttr->ad_cname.bv_len;
287                                 nAttrs++;
288                                 nDerefRes++;
289
290                                 for ( i = 0; !BER_BVISNULL( &a->a_nvals[ i ] ); i++ ) {
291                                         Entry *e = NULL;
292
293                                         dv[ i ].dv_attrVals = bva;
294                                         bva += ds->ds_nattrs;
295
296                                         dv[i].dv_derefSpecVal = a->a_vals[ i ];
297                                         bv.bv_len += dv[i].dv_derefSpecVal.bv_len;
298                                         nVals++;
299                                         nDerefVals++;
300
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 ) {
303                                                 int j;
304
305                                                 for ( j = 0; j < ds->ds_nattrs; j++ ) {
306                                                         Attribute *aa = attr_find( e->e_attrs, ds->ds_attributes[ j ] );
307                                                         if ( aa != NULL ) {
308                                                                 int k;
309
310                                                                 dv[i].dv_attrVals[ j ] = aa->a_vals;
311
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;
315                                                                         nVals++;
316                                                                 }
317                                                                 nAttrs++;
318                                                         }
319                                                 }
320
321                                                 overlay_entry_release_ov( op, e, 0, dc->dc_on );
322                                         }
323                                 }
324
325                                 *drp = dr;
326                                 drp = &dr->dr_next;
327                         }
328                 }
329                 op->o_bd->bd_info = bi;
330
331                 if ( drhead == NULL ) {
332                         return SLAP_CB_CONTINUE;
333                 }
334
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 );
341
342                 ber_init2( ber, &bv, LBER_USE_DER );
343                 ber_set_option( ber, LBER_OPT_BER_MEMCTX, &op->o_tmpmemctx );
344
345 #if 0
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 );
353                         }
354                         rc = ber_printf( ber, /*{{*/ "}}{" /*}*/ );
355                         for ( i = 0; !BER_BVISNULL( &dr->dr_vals[ i ].dv_derefSpecVal ); i++ ) {
356                                 int j;
357
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 ] );
363                                         } else {
364                                                 rc = ber_printf( ber, "b", 0 );
365                                         }
366                                 }
367                                 rc = ber_printf( ber, /*{{*/ "}}" );
368                         }
369                         rc = ber_printf( ber, /*{{*/ "}}" );
370                 }
371                 rc = ber_printf( ber, /*{*/ "}" );
372 #endif
373
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++ ) {
377                                 int j;
378
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 ] );
387                                         }
388                                 }
389                                 rc = ber_printf( ber, /*{*/ "}N}" );
390                         }
391                 }
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;
396
397                         } else {
398                                 rc = SLAP_CB_CONTINUE;
399                         }
400                         goto cleanup;
401                 }
402
403                 ctrl = op->o_tmpcalloc( 1,
404                         sizeof( LDAPControl ) + ctrlval.bv_len + 1,
405                         op->o_tmpmemctx );
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';
412
413                 ber_free_buf( ber );
414
415                 i = 0;
416                 if ( rs->sr_ctrls ) {
417                         for ( ; rs->sr_ctrls[ i ] != NULL; i++ )
418                                 /* count'em */ ;
419                 }
420                 i += 2;
421                 ctrlsp = op->o_tmpcalloc( i, sizeof(LDAPControl *), op->o_tmpmemctx );
422                 i = 0;
423                 if ( rs->sr_ctrls != NULL ) {
424                         for ( ; rs->sr_ctrls[ i ] != NULL; i++ ) {
425                                 ctrlsp[ i ] = rs->sr_ctrls[ i ];
426                         }
427                 }
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 );
432                 }
433                 rs->sr_ctrls = ctrlsp;
434                 rs->sr_flags |= REP_CTRLS_MUSTBEFREED;
435
436                 rc = SLAP_CB_CONTINUE;
437
438 cleanup:;
439                 /* release all */
440                 for ( ; drhead != NULL; ) {
441                         DerefRes *drnext = drhead->dr_next;
442                         op->o_tmpfree( drhead, op->o_tmpmemctx );
443                         drhead = drnext;
444                 }
445         }
446
447         return rc;
448 }
449
450 static int
451 deref_cleanup( Operation *op, SlapReply *rs )
452 {
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;
456
457                 op->o_tmpfree( op->o_ctrlderef, op->o_tmpmemctx );
458                 op->o_ctrlderef = NULL;
459         }
460
461         return SLAP_CB_CONTINUE;
462 }
463
464 static int
465 deref_op_search( Operation *op, SlapReply *rs )
466 {
467         if ( op->o_deref ) {
468                 slap_callback *sc;
469                 deref_cb_t *dc;
470
471                 sc = op->o_tmpcalloc( 1, sizeof( slap_callback ) + sizeof( deref_cb_t ), op->o_tmpmemctx );
472
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;
476
477                 sc->sc_response = deref_response;
478                 sc->sc_cleanup = deref_cleanup;
479                 sc->sc_private = (void *)dc;
480
481                 sc->sc_next = op->o_callback->sc_next;
482                 op->o_callback->sc_next = sc;
483         }
484
485         return SLAP_CB_CONTINUE;
486 }
487
488 int
489 deref_initialize()
490 {
491         int rc;
492
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",
499                 rc, 0, 0 );
500                 return rc;
501         }
502
503         deref.on_bi.bi_type = "deref";
504         deref.on_bi.bi_op_search = deref_op_search;
505
506         return overlay_register( &deref );
507 }
508
509 #if SLAPD_OVER_DEREF == SLAPD_MOD_DYNAMIC
510 int
511 init_module( int argc, char *argv[] )
512 {
513         return deref_initialize();
514 }
515 #endif /* SLAPD_OVER_DEREF == SLAPD_MOD_DYNAMIC */
516
517 #endif /* SLAPD_OVER_DEREF */