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