]> git.sur5r.net Git - openldap/blob - servers/slapd/overlays/deref.c
Happy new year (belated)
[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-2014 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        [0] 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  *   { member, "dc=sys-net,dc=it" } }
101  *
102  *
103  * 3. Security considerations
104  *
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
111  * attribute's value.
112  */
113
114 #define o_deref                 o_ctrlflag[deref_cid]
115 #define o_ctrlderef             o_controls[deref_cid]
116
117 typedef struct DerefSpec {
118         AttributeDescription    *ds_derefAttr;
119         AttributeDescription    **ds_attributes;
120         int                     ds_nattrs;
121         struct DerefSpec        *ds_next;
122 } DerefSpec;
123
124 typedef struct DerefVal {
125         struct berval   dv_derefSpecVal;
126         BerVarray       *dv_attrVals;
127 } DerefVal;
128
129 typedef struct DerefRes {
130         DerefSpec               dr_spec;
131         DerefVal                *dr_vals;
132         struct DerefRes         *dr_next;
133 } DerefRes;
134
135 typedef struct deref_cb_t {
136         slap_overinst *dc_on;
137         DerefSpec *dc_ds;
138 } deref_cb_t;
139
140 static int                      deref_cid;
141 static slap_overinst            deref;
142 static int ov_count;
143
144 static int
145 deref_parseCtrl (
146         Operation *op,
147         SlapReply *rs,
148         LDAPControl *ctrl )
149 {
150         ber_tag_t tag;
151         BerElementBuffer berbuf;
152         BerElement *ber = (BerElement *)&berbuf;
153         ber_len_t len;
154         char *last;
155         DerefSpec *dshead = NULL, **dsp = &dshead;
156         BerVarray attributes = NULL;
157
158         if ( op->o_deref != SLAP_CONTROL_NONE ) {
159                 rs->sr_text = "Dereference control specified multiple times";
160                 return LDAP_PROTOCOL_ERROR;
161         }
162
163         if ( BER_BVISNULL( &ctrl->ldctl_value ) ) {
164                 rs->sr_text = "Dereference control value is absent";
165                 return LDAP_PROTOCOL_ERROR;
166         }
167
168         if ( BER_BVISEMPTY( &ctrl->ldctl_value ) ) {
169                 rs->sr_text = "Dereference control value is empty";
170                 return LDAP_PROTOCOL_ERROR;
171         }
172
173         ber_init2( ber, &ctrl->ldctl_value, 0 );
174
175         for ( tag = ber_first_element( ber, &len, &last );
176                 tag != LBER_DEFAULT;
177                 tag = ber_next_element( ber, &len, last ) )
178         {
179                 struct berval derefAttr;
180                 DerefSpec *ds, *dstmp;
181                 const char *text;
182                 int rc;
183                 ber_len_t cnt = sizeof(struct berval);
184                 ber_len_t off = 0;
185
186                 if ( ber_scanf( ber, "{m{M}}", &derefAttr, &attributes, &cnt, off ) == LBER_ERROR )
187                 {
188                         rs->sr_text = "Dereference control: derefSpec decoding error";
189                         rs->sr_err = LDAP_PROTOCOL_ERROR;
190                         goto done;
191                 }
192
193                 ds = (DerefSpec *)op->o_tmpcalloc( 1,
194                         sizeof(DerefSpec) + sizeof(AttributeDescription *)*(cnt + 1),
195                         op->o_tmpmemctx );
196                 ds->ds_attributes = (AttributeDescription **)&ds[ 1 ];
197                 ds->ds_nattrs = cnt;
198
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;
203                         goto done;
204                 }
205
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;
210                                 goto done;
211                         }
212                 }
213
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;
218                                 goto done;
219                         }
220
221                         rs->sr_err = LDAP_SUCCESS;
222                         goto justcleanup;
223                 }
224
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;
230                                 goto done;
231                         }
232                 }
233
234                 ber_memfree_x( attributes, op->o_tmpmemctx );
235                 attributes = NULL;
236
237                 *dsp = ds;
238                 dsp = &ds->ds_next;
239         }
240
241         op->o_ctrlderef = (void *)dshead;
242
243         op->o_deref = ctrl->ldctl_iscritical
244                 ? SLAP_CONTROL_CRITICAL
245                 : SLAP_CONTROL_NONCRITICAL;
246
247         rs->sr_err = LDAP_SUCCESS;
248
249 done:;
250         if ( rs->sr_err != LDAP_SUCCESS ) {
251 justcleanup:;
252                 for ( ; dshead; ) {
253                         DerefSpec *dsnext = dshead->ds_next;
254                         op->o_tmpfree( dshead, op->o_tmpmemctx );
255                         dshead = dsnext;
256                 }
257         }
258
259         if ( attributes != NULL ) {
260                 ber_memfree_x( attributes, op->o_tmpmemctx );
261         }
262
263         return rs->sr_err;
264 }
265
266 static int
267 deref_cleanup( Operation *op, SlapReply *rs )
268 {
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;
272
273                 op->o_tmpfree( op->o_ctrlderef, op->o_tmpmemctx );
274                 op->o_ctrlderef = NULL;
275         }
276
277         return SLAP_CB_CONTINUE;
278 }
279
280 static int
281 deref_response( Operation *op, SlapReply *rs )
282 {
283         int rc = SLAP_CB_CONTINUE;
284
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;
289                 DerefSpec *ds;
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';
297                 Entry *ebase;
298                 int i;
299
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;
303                 }
304
305                 for ( ds = dc->dc_ds; ds; ds = ds->ds_next ) {
306                         Attribute *a = attr_find( ebase->e_attrs, ds->ds_derefAttr );
307
308                         if ( a != NULL ) {
309                                 DerefVal *dv;
310                                 BerVarray *bva;
311
312                                 if ( !access_allowed( op, rs->sr_entry, a->a_desc,
313                                                 NULL, ACL_READ, &acl_state ) )
314                                 {
315                                         continue;
316                                 }
317
318                                 dr = op->o_tmpcalloc( 1,
319                                         sizeof( DerefRes ) + ( sizeof( DerefVal ) + sizeof( BerVarray * ) * ds->ds_nattrs ) * ( a->a_numvals + 1 ),
320                                         op->o_tmpmemctx );
321                                 dr->dr_spec = *ds;
322                                 dv = dr->dr_vals = (DerefVal *)&dr[ 1 ];
323                                 bva = (BerVarray *)&dv[ a->a_numvals + 1 ];
324
325                                 bv.bv_len += ds->ds_derefAttr->ad_cname.bv_len;
326                                 nAttrs++;
327                                 nDerefRes++;
328
329                                 for ( i = 0; !BER_BVISNULL( &a->a_nvals[ i ] ); i++ ) {
330                                         Entry *e = NULL;
331
332                                         dv[ i ].dv_attrVals = bva;
333                                         bva += ds->ds_nattrs;
334
335
336                                         if ( !access_allowed( op, rs->sr_entry, a->a_desc,
337                                                         &a->a_nvals[ i ], ACL_READ, &acl_state ) )
338                                         {
339                                                 dv[ i ].dv_derefSpecVal.bv_val = &dummy;
340                                                 continue;
341                                         }
342
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;
345                                         nVals++;
346                                         nDerefVals++;
347
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 ) {
350                                                 int j;
351
352                                                 if ( access_allowed( op, e, slap_schema.si_ad_entry,
353                                                         NULL, ACL_READ, NULL ) )
354                                                 {
355                                                         for ( j = 0; j < ds->ds_nattrs; j++ ) {
356                                                                 Attribute *aa;
357
358                                                                 if ( !access_allowed( op, e, ds->ds_attributes[ j ], NULL,
359                                                                         ACL_READ, &acl_state ) )
360                                                                 {
361                                                                         continue;
362                                                                 }
363
364                                                                 aa = attr_find( e->e_attrs, ds->ds_attributes[ j ] );
365                                                                 if ( aa != NULL ) {
366                                                                         unsigned k, h, last = aa->a_numvals;
367
368                                                                         ber_bvarray_dup_x( &dv[ i ].dv_attrVals[ j ],
369                                                                                 aa->a_vals, op->o_tmpmemctx );
370
371                                                                         bv.bv_len += ds->ds_attributes[ j ]->ad_cname.bv_len;
372
373                                                                         for ( k = 0, h = 0; k < aa->a_numvals; k++ ) {
374                                                                                 if ( !access_allowed( op, e,
375                                                                                         aa->a_desc,
376                                                                                         &aa->a_nvals[ k ],
377                                                                                         ACL_READ, &acl_state ) )
378                                                                                 {
379                                                                                         op->o_tmpfree( dv[ i ].dv_attrVals[ j ][ h ].bv_val,
380                                                                                                 op->o_tmpmemctx );
381                                                                                         dv[ i ].dv_attrVals[ j ][ h ] = dv[ i ].dv_attrVals[ j ][ --last ];
382                                                                                         BER_BVZERO( &dv[ i ].dv_attrVals[ j ][ last ] );
383                                                                                         continue;
384                                                                                 }
385                                                                                 bv.bv_len += dv[ i ].dv_attrVals[ j ][ h ].bv_len;
386                                                                                 nVals++;
387                                                                                 h++;
388                                                                         }
389                                                                         nAttrs++;
390                                                                 }
391                                                         }
392                                                 }
393
394                                                 overlay_entry_release_ov( op, e, 0, dc->dc_on );
395                                         }
396                                 }
397
398                                 *drp = dr;
399                                 drp = &dr->dr_next;
400                         }
401                 }
402                 overlay_entry_release_ov( op, ebase, 0, dc->dc_on );
403
404                 if ( drhead == NULL ) {
405                         return SLAP_CB_CONTINUE;
406                 }
407
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 );
414
415                 ber_init2( ber, &bv, LBER_USE_DER );
416                 ber_set_option( ber, LBER_OPT_BER_MEMCTX, &op->o_tmpmemctx );
417
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++ ) {
421                                 int j, first = 1;
422
423                                 if ( dr->dr_vals[ i ].dv_derefSpecVal.bv_val == &dummy ) {
424                                         continue;
425                                 }
426
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 ) {
433                                                 if ( first ) {
434                                                         rc = ber_printf( ber, "t{" /*}*/,
435                                                                 (LBER_CONSTRUCTED|LBER_CLASS_CONTEXT) );
436                                                         first = 0;
437                                                 }
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 ],
442                                                         op->o_tmpmemctx );
443                                         }
444                                 }
445                                 if ( !first ) {
446                                         rc = ber_printf( ber, /*{{*/ "}N}" );
447                                 } else {
448                                         rc = ber_printf( ber, /*{*/ "}" );
449                                 }
450                         }
451                 }
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;
456
457                         } else {
458                                 rc = SLAP_CB_CONTINUE;
459                         }
460                         goto cleanup;
461                 }
462
463                 ctrl = op->o_tmpcalloc( 1,
464                         sizeof( LDAPControl ) + ctrlval.bv_len + 1,
465                         op->o_tmpmemctx );
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';
472
473                 ber_free_buf( ber );
474
475                 ctrlsp[0] = ctrl;
476                 ctrlsp[1] = NULL;
477                 slap_add_ctrls( op, rs, ctrlsp );
478
479                 rc = SLAP_CB_CONTINUE;
480
481 cleanup:;
482                 /* release all */
483                 for ( ; drhead != NULL; ) {
484                         DerefRes *drnext = drhead->dr_next;
485                         op->o_tmpfree( drhead, op->o_tmpmemctx );
486                         drhead = drnext;
487                 }
488
489         } else if ( rs->sr_type == REP_RESULT ) {
490                 rc = deref_cleanup( op, rs );
491         }
492
493         return rc;
494 }
495
496 static int
497 deref_op_search( Operation *op, SlapReply *rs )
498 {
499         if ( op->o_deref ) {
500                 slap_callback *sc;
501                 deref_cb_t *dc;
502
503                 sc = op->o_tmpcalloc( 1, sizeof( slap_callback ) + sizeof( deref_cb_t ), op->o_tmpmemctx );
504
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;
508
509                 sc->sc_response = deref_response;
510                 sc->sc_cleanup = deref_cleanup;
511                 sc->sc_private = (void *)dc;
512
513                 sc->sc_next = op->o_callback->sc_next;
514                 op->o_callback->sc_next = sc;
515         }
516
517         return SLAP_CB_CONTINUE;
518 }
519
520 static int
521 deref_db_init( BackendDB *be, ConfigReply *cr)
522 {
523         if ( ov_count == 0 ) {
524                 int rc;
525
526                 rc = register_supported_control2( LDAP_CONTROL_X_DEREF,
527                         SLAP_CTRL_SEARCH,
528                         NULL,
529                         deref_parseCtrl,
530                         1, /* replace */
531                         &deref_cid );
532                 if ( rc != LDAP_SUCCESS ) {
533                         Debug( LDAP_DEBUG_ANY,
534                                 "deref_init: Failed to register control (%d)\n",
535                                 rc, 0, 0 );
536                         return rc;
537                 }
538         }
539         ov_count++;
540         return LDAP_SUCCESS;
541 }
542
543 static int
544 deref_db_open( BackendDB *be, ConfigReply *cr)
545 {
546         return overlay_register_control( be, LDAP_CONTROL_X_DEREF );
547 }
548
549 #ifdef SLAP_CONFIG_DELETE
550 static int
551 deref_db_destroy( BackendDB *be, ConfigReply *cr)
552 {
553         ov_count--;
554         overlay_unregister_control( be, LDAP_CONTROL_X_DEREF );
555         if ( ov_count == 0 ) {
556                 unregister_supported_control( LDAP_CONTROL_X_DEREF );
557         }
558         return 0;
559 }
560 #endif /* SLAP_CONFIG_DELETE */
561
562 int
563 deref_initialize(void)
564 {
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;
572
573         return overlay_register( &deref );
574 }
575
576 #if SLAPD_OVER_DEREF == SLAPD_MOD_DYNAMIC
577 int
578 init_module( int argc, char *argv[] )
579 {
580         return deref_initialize();
581 }
582 #endif /* SLAPD_OVER_DEREF == SLAPD_MOD_DYNAMIC */
583
584 #endif /* SLAPD_OVER_DEREF */