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