1 /* deref.c - dereference overlay */
2 /* $OpenLDAP$ */
3 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
4  *
5  * Copyright 1998-2021 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
deref_parseCtrl(Operation * op,SlapReply * rs,LDAPControl * ctrl)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 			|| !cnt )
188 		{
189 			rs->sr_text = "Dereference control: derefSpec decoding error";
190 			rs->sr_err = LDAP_PROTOCOL_ERROR;
191 			goto done;
192 		}
193 
194 		ds = (DerefSpec *)op->o_tmpcalloc( 1,
195 			sizeof(DerefSpec) + sizeof(AttributeDescription *)*(cnt + 1),
196 			op->o_tmpmemctx );
197 		ds->ds_attributes = (AttributeDescription **)&ds[ 1 ];
198 		ds->ds_nattrs = cnt;
199 
200 		rc = slap_bv2ad( &derefAttr, &ds->ds_derefAttr, &text );
201 		if ( rc != LDAP_SUCCESS ) {
202 			rs->sr_text = "Dereference control: derefAttr decoding error";
203 			rs->sr_err = LDAP_PROTOCOL_ERROR;
204 			goto done;
205 		}
206 
207 		for ( dstmp = dshead; dstmp && dstmp != ds; dstmp = dstmp->ds_next ) {
208 			if ( dstmp->ds_derefAttr == ds->ds_derefAttr ) {
209 				rs->sr_text = "Dereference control: derefAttr must be unique within control";
210 				rs->sr_err = LDAP_PROTOCOL_ERROR;
211 				goto done;
212 			}
213 		}
214 
215 		if ( !( ds->ds_derefAttr->ad_type->sat_syntax->ssyn_flags & SLAP_SYNTAX_DN )) {
216 			if ( ctrl->ldctl_iscritical ) {
217 				rs->sr_text = "Dereference control: derefAttr syntax not distinguishedName";
218 				rs->sr_err = LDAP_PROTOCOL_ERROR;
219 				goto done;
220 			}
221 
222 			rs->sr_err = LDAP_SUCCESS;
223 			goto justcleanup;
224 		}
225 
226 		for ( cnt = 0; !BER_BVISNULL( &attributes[ cnt ] ); cnt++ ) {
227 			rc = slap_bv2ad( &attributes[ cnt ], &ds->ds_attributes[ cnt ], &text );
228 			if ( rc != LDAP_SUCCESS ) {
229 				rs->sr_text = "Dereference control: attribute decoding error";
230 				rs->sr_err = LDAP_PROTOCOL_ERROR;
231 				goto done;
232 			}
233 		}
234 
235 		ber_memfree_x( attributes, op->o_tmpmemctx );
236 		attributes = NULL;
237 
238 		*dsp = ds;
239 		dsp = &ds->ds_next;
240 	}
241 
242 	op->o_ctrlderef = (void *)dshead;
243 
244 	op->o_deref = ctrl->ldctl_iscritical
245 		? SLAP_CONTROL_CRITICAL
246 		: SLAP_CONTROL_NONCRITICAL;
247 
248 	rs->sr_err = LDAP_SUCCESS;
249 
250 done:;
251 	if ( rs->sr_err != LDAP_SUCCESS ) {
252 justcleanup:;
253 		for ( ; dshead; ) {
254 			DerefSpec *dsnext = dshead->ds_next;
255 			op->o_tmpfree( dshead, op->o_tmpmemctx );
256 			dshead = dsnext;
257 		}
258 	}
259 
260 	if ( attributes != NULL ) {
261 		ber_memfree_x( attributes, op->o_tmpmemctx );
262 	}
263 
264 	return rs->sr_err;
265 }
266 
267 static int
deref_cleanup(Operation * op,SlapReply * rs)268 deref_cleanup( Operation *op, SlapReply *rs )
269 {
270 	if ( rs->sr_type == REP_RESULT || rs->sr_err == SLAPD_ABANDON ) {
271 		op->o_tmpfree( op->o_callback, op->o_tmpmemctx );
272 		op->o_callback = NULL;
273 
274 		op->o_tmpfree( op->o_ctrlderef, op->o_tmpmemctx );
275 		op->o_ctrlderef = NULL;
276 	}
277 
278 	return SLAP_CB_CONTINUE;
279 }
280 
281 static int
deref_response(Operation * op,SlapReply * rs)282 deref_response( Operation *op, SlapReply *rs )
283 {
284 	int rc = SLAP_CB_CONTINUE;
285 
286 	if ( rs->sr_type == REP_SEARCH ) {
287 		BerElementBuffer berbuf;
288 		BerElement *ber = (BerElement *) &berbuf;
289 		deref_cb_t *dc = (deref_cb_t *)op->o_callback->sc_private;
290 		DerefSpec *ds;
291 		DerefRes *dr, *drhead = NULL, **drp = &drhead;
292 		struct berval bv = BER_BVNULL;
293 		int nDerefRes = 0, nDerefVals = 0, nAttrs = 0, nVals = 0;
294 		struct berval ctrlval;
295 		LDAPControl *ctrl, *ctrlsp[2];
296 		AccessControlState acl_state = ACL_STATE_INIT;
297 		static char dummy = '\0';
298 		Entry *ebase;
299 		int i;
300 
301 		rc = overlay_entry_get_ov( op, &rs->sr_entry->e_nname, NULL, NULL, 0, &ebase, dc->dc_on );
302 		if ( rc != LDAP_SUCCESS || ebase == NULL ) {
303 			return SLAP_CB_CONTINUE;
304 		}
305 
306 		for ( ds = dc->dc_ds; ds; ds = ds->ds_next ) {
307 			Attribute *a = attr_find( ebase->e_attrs, ds->ds_derefAttr );
308 
309 			if ( a != NULL ) {
310 				DerefVal *dv;
311 				BerVarray *bva;
312 
313 				if ( !access_allowed( op, rs->sr_entry, a->a_desc,
314 						NULL, ACL_READ, &acl_state ) )
315 				{
316 					continue;
317 				}
318 
319 				dr = op->o_tmpcalloc( 1,
320 					sizeof( DerefRes ) + ( sizeof( DerefVal ) + sizeof( BerVarray * ) * ds->ds_nattrs ) * ( a->a_numvals + 1 ),
321 					op->o_tmpmemctx );
322 				dr->dr_spec = *ds;
323 				dv = dr->dr_vals = (DerefVal *)&dr[ 1 ];
324 				bva = (BerVarray *)&dv[ a->a_numvals + 1 ];
325 
326 				bv.bv_len += ds->ds_derefAttr->ad_cname.bv_len;
327 				nAttrs++;
328 				nDerefRes++;
329 
330 				for ( i = 0; !BER_BVISNULL( &a->a_nvals[ i ] ); i++ ) {
331 					Entry *e = NULL;
332 
333 					dv[ i ].dv_attrVals = bva;
334 					bva += ds->ds_nattrs;
335 
336 
337 					if ( !access_allowed( op, rs->sr_entry, a->a_desc,
338 							&a->a_nvals[ i ], ACL_READ, &acl_state ) )
339 					{
340 						dv[ i ].dv_derefSpecVal.bv_val = &dummy;
341 						continue;
342 					}
343 
344 					ber_dupbv_x( &dv[ i ].dv_derefSpecVal, &a->a_vals[ i ], op->o_tmpmemctx );
345 					bv.bv_len += dv[ i ].dv_derefSpecVal.bv_len;
346 					nVals++;
347 					nDerefVals++;
348 
349 					rc = overlay_entry_get_ov( op, &a->a_nvals[ i ], NULL, NULL, 0, &e, dc->dc_on );
350 					if ( rc == LDAP_SUCCESS && e != NULL ) {
351 						int j;
352 
353 						if ( access_allowed( op, e, slap_schema.si_ad_entry,
354 							NULL, ACL_READ, NULL ) )
355 						{
356 							for ( j = 0; j < ds->ds_nattrs; j++ ) {
357 								Attribute *aa;
358 
359 								if ( !access_allowed( op, e, ds->ds_attributes[ j ], NULL,
360 									ACL_READ, &acl_state ) )
361 								{
362 									continue;
363 								}
364 
365 								aa = attr_find( e->e_attrs, ds->ds_attributes[ j ] );
366 								if ( aa != NULL ) {
367 									unsigned k, h, last = aa->a_numvals;
368 
369 									ber_bvarray_dup_x( &dv[ i ].dv_attrVals[ j ],
370 										aa->a_vals, op->o_tmpmemctx );
371 
372 									bv.bv_len += ds->ds_attributes[ j ]->ad_cname.bv_len;
373 
374 									for ( k = 0, h = 0; k < aa->a_numvals; k++ ) {
375 										if ( !access_allowed( op, e,
376 											aa->a_desc,
377 											&aa->a_nvals[ k ],
378 											ACL_READ, &acl_state ) )
379 										{
380 											op->o_tmpfree( dv[ i ].dv_attrVals[ j ][ h ].bv_val,
381 												op->o_tmpmemctx );
382 											dv[ i ].dv_attrVals[ j ][ h ] = dv[ i ].dv_attrVals[ j ][ --last ];
383 											BER_BVZERO( &dv[ i ].dv_attrVals[ j ][ last ] );
384 											continue;
385 										}
386 										bv.bv_len += dv[ i ].dv_attrVals[ j ][ h ].bv_len;
387 										nVals++;
388 										h++;
389 									}
390 									nAttrs++;
391 								}
392 							}
393 						}
394 
395 						overlay_entry_release_ov( op, e, 0, dc->dc_on );
396 					}
397 				}
398 
399 				*drp = dr;
400 				drp = &dr->dr_next;
401 			}
402 		}
403 		overlay_entry_release_ov( op, ebase, 0, dc->dc_on );
404 
405 		if ( drhead == NULL ) {
406 			return SLAP_CB_CONTINUE;
407 		}
408 
409 		/* cook the control value */
410 		bv.bv_len += nVals * sizeof(struct berval)
411 			+ nAttrs * sizeof(struct berval)
412 			+ nDerefVals * sizeof(DerefVal)
413 			+ nDerefRes * sizeof(DerefRes);
414 		bv.bv_val = op->o_tmpalloc( bv.bv_len, op->o_tmpmemctx );
415 
416 		ber_init2( ber, &bv, LBER_USE_DER );
417 		ber_set_option( ber, LBER_OPT_BER_MEMCTX, &op->o_tmpmemctx );
418 
419 		rc = ber_printf( ber, "{" /*}*/ );
420 		for ( dr = drhead; dr != NULL; dr = dr->dr_next ) {
421 			for ( i = 0; !BER_BVISNULL( &dr->dr_vals[ i ].dv_derefSpecVal ); i++ ) {
422 				int j, first = 1;
423 
424 				if ( dr->dr_vals[ i ].dv_derefSpecVal.bv_val == &dummy ) {
425 					continue;
426 				}
427 
428 				rc = ber_printf( ber, "{OO" /*}*/,
429 					&dr->dr_spec.ds_derefAttr->ad_cname,
430 					&dr->dr_vals[ i ].dv_derefSpecVal );
431 				op->o_tmpfree( dr->dr_vals[ i ].dv_derefSpecVal.bv_val, op->o_tmpmemctx );
432 				for ( j = 0; j < dr->dr_spec.ds_nattrs; j++ ) {
433 					if ( dr->dr_vals[ i ].dv_attrVals[ j ] != NULL ) {
434 						if ( first ) {
435 							rc = ber_printf( ber, "t{" /*}*/,
436 								(LBER_CONSTRUCTED|LBER_CLASS_CONTEXT) );
437 							first = 0;
438 						}
439 						rc = ber_printf( ber, "{O[W]}",
440 							&dr->dr_spec.ds_attributes[ j ]->ad_cname,
441 							dr->dr_vals[ i ].dv_attrVals[ j ] );
442 						op->o_tmpfree( dr->dr_vals[ i ].dv_attrVals[ j ],
443 							op->o_tmpmemctx );
444 					}
445 				}
446 				if ( !first ) {
447 					rc = ber_printf( ber, /*{{*/ "}N}" );
448 				} else {
449 					rc = ber_printf( ber, /*{*/ "}" );
450 				}
451 			}
452 		}
453 		rc = ber_printf( ber, /*{*/ "}" );
454 		if ( ber_flatten2( ber, &ctrlval, 0 ) == -1 ) {
455 			if ( op->o_deref == SLAP_CONTROL_CRITICAL ) {
456 				rc = LDAP_CONSTRAINT_VIOLATION;
457 
458 			} else {
459 				rc = SLAP_CB_CONTINUE;
460 			}
461 			goto cleanup;
462 		}
463 
464 		ctrl = op->o_tmpcalloc( 1,
465 			sizeof( LDAPControl ) + ctrlval.bv_len + 1,
466 			op->o_tmpmemctx );
467 		ctrl->ldctl_value.bv_val = (char *)&ctrl[ 1 ];
468 		ctrl->ldctl_oid = LDAP_CONTROL_X_DEREF;
469 		ctrl->ldctl_iscritical = 0;
470 		ctrl->ldctl_value.bv_len = ctrlval.bv_len;
471 		AC_MEMCPY( ctrl->ldctl_value.bv_val, ctrlval.bv_val, ctrlval.bv_len );
472 		ctrl->ldctl_value.bv_val[ ctrl->ldctl_value.bv_len ] = '\0';
473 
474 		ber_free_buf( ber );
475 
476 		ctrlsp[0] = ctrl;
477 		ctrlsp[1] = NULL;
478 		slap_add_ctrls( op, rs, ctrlsp );
479 
480 		rc = SLAP_CB_CONTINUE;
481 
482 cleanup:;
483 		/* release all */
484 		for ( ; drhead != NULL; ) {
485 			DerefRes *drnext = drhead->dr_next;
486 			op->o_tmpfree( drhead, op->o_tmpmemctx );
487 			drhead = drnext;
488 		}
489 
490 	} else if ( rs->sr_type == REP_RESULT ) {
491 		rc = deref_cleanup( op, rs );
492 	}
493 
494 	return rc;
495 }
496 
497 static int
deref_op_search(Operation * op,SlapReply * rs)498 deref_op_search( Operation *op, SlapReply *rs )
499 {
500 	if ( op->o_deref ) {
501 		slap_callback *sc;
502 		deref_cb_t *dc;
503 
504 		sc = op->o_tmpcalloc( 1, sizeof( slap_callback ) + sizeof( deref_cb_t ), op->o_tmpmemctx );
505 
506 		dc = (deref_cb_t *)&sc[ 1 ];
507 		dc->dc_on = (slap_overinst *)op->o_bd->bd_info;
508 		dc->dc_ds = (DerefSpec *)op->o_ctrlderef;
509 
510 		sc->sc_response = deref_response;
511 		sc->sc_cleanup = deref_cleanup;
512 		sc->sc_private = (void *)dc;
513 
514 		sc->sc_next = op->o_callback->sc_next;
515                 op->o_callback->sc_next = sc;
516 	}
517 
518 	return SLAP_CB_CONTINUE;
519 }
520 
521 static int
deref_db_init(BackendDB * be,ConfigReply * cr)522 deref_db_init( BackendDB *be, ConfigReply *cr)
523 {
524 	if ( ov_count == 0 ) {
525 		int rc;
526 
527 		rc = register_supported_control2( LDAP_CONTROL_X_DEREF,
528 			SLAP_CTRL_SEARCH,
529 			NULL,
530 			deref_parseCtrl,
531 			1, /* replace */
532 			&deref_cid );
533 		if ( rc != LDAP_SUCCESS ) {
534 			Debug( LDAP_DEBUG_ANY,
535 				"deref_init: Failed to register control (%d)\n",
536 				rc, 0, 0 );
537 			return rc;
538 		}
539 	}
540 	ov_count++;
541 	return LDAP_SUCCESS;
542 }
543 
544 static int
deref_db_open(BackendDB * be,ConfigReply * cr)545 deref_db_open( BackendDB *be, ConfigReply *cr)
546 {
547 	return overlay_register_control( be, LDAP_CONTROL_X_DEREF );
548 }
549 
550 #ifdef SLAP_CONFIG_DELETE
551 static int
deref_db_destroy(BackendDB * be,ConfigReply * cr)552 deref_db_destroy( BackendDB *be, ConfigReply *cr)
553 {
554 	ov_count--;
555 	overlay_unregister_control( be, LDAP_CONTROL_X_DEREF );
556 	if ( ov_count == 0 ) {
557 		unregister_supported_control( LDAP_CONTROL_X_DEREF );
558 	}
559 	return 0;
560 }
561 #endif /* SLAP_CONFIG_DELETE */
562 
563 int
deref_initialize(void)564 deref_initialize(void)
565 {
566 	deref.on_bi.bi_type = "deref";
567 	deref.on_bi.bi_db_init = deref_db_init;
568 	deref.on_bi.bi_db_open = deref_db_open;
569 #ifdef SLAP_CONFIG_DELETE
570 	deref.on_bi.bi_db_destroy = deref_db_destroy;
571 #endif /* SLAP_CONFIG_DELETE */
572 	deref.on_bi.bi_op_search = deref_op_search;
573 
574 	return overlay_register( &deref );
575 }
576 
577 #if SLAPD_OVER_DEREF == SLAPD_MOD_DYNAMIC
578 int
init_module(int argc,char * argv[])579 init_module( int argc, char *argv[] )
580 {
581 	return deref_initialize();
582 }
583 #endif /* SLAPD_OVER_DEREF == SLAPD_MOD_DYNAMIC */
584 
585 #endif /* SLAPD_OVER_DEREF */
586