1/*	$NetBSD: search.c,v 1.3 2021/08/14 16:15:00 christos Exp $	*/
2
3/* search.c - monitor backend search function */
4/* $OpenLDAP$ */
5/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
6 *
7 * Copyright 2001-2021 The OpenLDAP Foundation.
8 * Portions Copyright 2001-2003 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 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 for inclusion
21 * in OpenLDAP Software.
22 */
23
24#include <sys/cdefs.h>
25__RCSID("$NetBSD: search.c,v 1.3 2021/08/14 16:15:00 christos Exp $");
26
27#include "portable.h"
28
29#include <stdio.h>
30
31#include <ac/string.h>
32#include <ac/socket.h>
33
34#include "slap.h"
35#include "back-monitor.h"
36#include "proto-back-monitor.h"
37
38static void
39monitor_find_children(
40	Operation *op,
41	SlapReply *rs,
42	Entry *e_parent,
43	Entry **nonv,
44	Entry **vol
45)
46{
47	monitor_entry_t *mp;
48
49	mp = ( monitor_entry_t * )e_parent->e_private;
50	*nonv = mp->mp_children;
51
52	if ( MONITOR_HAS_VOLATILE_CH( mp ) ) {
53		monitor_entry_create( op, rs, NULL, e_parent, vol );
54	}
55}
56
57static int
58monitor_send_children(
59	Operation	*op,
60	SlapReply	*rs,
61	Entry		*e_nonvolatile,
62	Entry		*e_ch,
63	int		sub )
64{
65	monitor_info_t	*mi = ( monitor_info_t * )op->o_bd->be_private;
66	Entry 			*e,
67				*e_tmp;
68	monitor_entry_t *mp;
69	int			rc,
70				nonvolatile = 0;
71
72	e = e_nonvolatile;
73
74	/* no volatile entries? */
75	if ( e_ch == NULL ) {
76		/* no persistent entries? return */
77		if ( e == NULL ) {
78			return LDAP_SUCCESS;
79		}
80
81	/* volatile entries */
82	} else {
83		/* if no persistent, return only volatile */
84		if ( e == NULL ) {
85			e = e_ch;
86
87		/* else append persistent to volatile */
88		} else {
89			e_tmp = e_ch;
90			do {
91				mp = ( monitor_entry_t * )e_tmp->e_private;
92				e_tmp = mp->mp_next;
93
94				if ( e_tmp == NULL ) {
95					mp->mp_next = e;
96					break;
97				}
98			} while ( e_tmp );
99			e = e_ch;
100		}
101	}
102
103	/* return entries */
104	for ( ; e != NULL; e = e_tmp ) {
105		Entry *sub_nv = NULL, *sub_ch = NULL;
106
107		monitor_cache_lock( e );
108		monitor_entry_update( op, rs, e );
109
110		if ( e == e_nonvolatile )
111			nonvolatile = 1;
112
113		mp = ( monitor_entry_t * )e->e_private;
114		e_tmp = mp->mp_next;
115
116		if ( op->o_abandon ) {
117			monitor_cache_release( mi, e );
118			rc = SLAPD_ABANDON;
119			goto freeout;
120		}
121
122		if ( sub )
123			monitor_find_children( op, rs, e, &sub_nv, &sub_ch );
124
125		rc = test_filter( op, e, op->oq_search.rs_filter );
126		if ( rc == LDAP_COMPARE_TRUE ) {
127			rs->sr_entry = e;
128			rs->sr_flags = REP_ENTRY_MUSTRELEASE;
129			rc = send_search_entry( op, rs );
130			if ( rc ) {
131				for ( e = sub_ch; e != NULL; e = sub_nv ) {
132					mp = ( monitor_entry_t * )e->e_private;
133					sub_nv = mp->mp_next;
134					monitor_cache_lock( e );
135					monitor_cache_release( mi, e );
136				}
137				goto freeout;
138			}
139		} else {
140			monitor_cache_release( mi, e );
141		}
142
143		if ( sub ) {
144			rc = monitor_send_children( op, rs, sub_nv, sub_ch, sub );
145			if ( rc ) {
146freeout:
147				if ( nonvolatile == 0 ) {
148					for ( ; e_tmp != NULL; ) {
149						mp = ( monitor_entry_t * )e_tmp->e_private;
150						e = e_tmp;
151						e_tmp = mp->mp_next;
152						monitor_cache_lock( e );
153						monitor_cache_release( mi, e );
154
155						if ( e_tmp == e_nonvolatile ) {
156							break;
157						}
158					}
159				}
160
161				return( rc );
162			}
163		}
164	}
165
166	return LDAP_SUCCESS;
167}
168
169int
170monitor_back_search( Operation *op, SlapReply *rs )
171{
172	monitor_info_t	*mi = ( monitor_info_t * )op->o_bd->be_private;
173	int		rc = LDAP_SUCCESS;
174	Entry		*e = NULL, *matched = NULL;
175	Entry		*e_nv = NULL, *e_ch = NULL;
176	slap_mask_t	mask;
177
178	Debug( LDAP_DEBUG_TRACE, "=> monitor_back_search\n" );
179
180
181	/* get entry with reader lock */
182	monitor_cache_dn2entry( op, rs, &op->o_req_ndn, &e, &matched );
183	if ( e == NULL ) {
184		rs->sr_err = LDAP_NO_SUCH_OBJECT;
185		if ( matched ) {
186			if ( !access_allowed_mask( op, matched,
187					slap_schema.si_ad_entry,
188					NULL, ACL_DISCLOSE, NULL, NULL ) )
189			{
190				/* do nothing */ ;
191			} else {
192				rs->sr_matched = matched->e_dn;
193			}
194		}
195
196		send_ldap_result( op, rs );
197		if ( matched ) {
198			monitor_cache_release( mi, matched );
199			rs->sr_matched = NULL;
200		}
201
202		return rs->sr_err;
203	}
204
205	/* NOTE: __NEW__ "search" access is required
206	 * on searchBase object */
207	if ( !access_allowed_mask( op, e, slap_schema.si_ad_entry,
208				NULL, ACL_SEARCH, NULL, &mask ) )
209	{
210		monitor_cache_release( mi, e );
211
212		if ( !ACL_GRANT( mask, ACL_DISCLOSE ) ) {
213			rs->sr_err = LDAP_NO_SUCH_OBJECT;
214		} else {
215			rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
216		}
217
218		send_ldap_result( op, rs );
219
220		return rs->sr_err;
221	}
222
223	rs->sr_attrs = op->oq_search.rs_attrs;
224	switch ( op->oq_search.rs_scope ) {
225	case LDAP_SCOPE_BASE:
226		monitor_entry_update( op, rs, e );
227		rc = test_filter( op, e, op->oq_search.rs_filter );
228 		if ( rc == LDAP_COMPARE_TRUE ) {
229			rs->sr_entry = e;
230			rs->sr_flags = REP_ENTRY_MUSTRELEASE;
231			send_search_entry( op, rs );
232			rs->sr_entry = NULL;
233		} else {
234			monitor_cache_release( mi, e );
235		}
236		rc = LDAP_SUCCESS;
237		break;
238
239	case LDAP_SCOPE_ONELEVEL:
240	case LDAP_SCOPE_SUBORDINATE:
241		monitor_find_children( op, rs, e, &e_nv, &e_ch );
242		monitor_cache_release( mi, e );
243		rc = monitor_send_children( op, rs, e_nv, e_ch,
244			op->oq_search.rs_scope == LDAP_SCOPE_SUBORDINATE );
245		break;
246
247	case LDAP_SCOPE_SUBTREE:
248		monitor_entry_update( op, rs, e );
249		monitor_find_children( op, rs, e, &e_nv, &e_ch );
250		rc = test_filter( op, e, op->oq_search.rs_filter );
251		if ( rc == LDAP_COMPARE_TRUE ) {
252			rs->sr_entry = e;
253			rs->sr_flags = REP_ENTRY_MUSTRELEASE;
254			send_search_entry( op, rs );
255			rs->sr_entry = NULL;
256		} else {
257			monitor_cache_release( mi, e );
258		}
259
260		rc = monitor_send_children( op, rs, e_nv, e_ch, 1 );
261		break;
262
263	default:
264		rc = LDAP_UNWILLING_TO_PERFORM;
265		monitor_cache_release( mi, e );
266	}
267
268	rs->sr_attrs = NULL;
269	rs->sr_err = rc;
270	if ( rs->sr_err != SLAPD_ABANDON ) {
271		send_ldap_result( op, rs );
272	}
273
274	return rs->sr_err;
275}
276
277