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