search.c revision 1.1.1.10 1 /* $NetBSD: search.c,v 1.1.1.10 2025/09/05 21:09:48 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-2024 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.1.1.10 2025/09/05 21:09:48 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
38 static void
39 monitor_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
57 static int
58 monitor_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, *locked = e;
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 rc = SLAPD_ABANDON;
118 goto freeout;
119 }
120
121 if ( sub )
122 monitor_find_children( op, rs, e, &sub_nv, &sub_ch );
123
124 rc = test_filter( op, e, op->oq_search.rs_filter );
125 if ( rc == LDAP_COMPARE_TRUE ) {
126 rs->sr_entry = e;
127 rc = send_search_entry( op, rs );
128 if ( rc ) {
129 for ( e = sub_ch; e != NULL; e = sub_nv ) {
130 mp = ( monitor_entry_t * )e->e_private;
131 sub_nv = mp->mp_next;
132 monitor_cache_lock( e );
133 monitor_cache_release( mi, e );
134 }
135 goto freeout;
136 }
137 }
138 if ( sub_nv == NULL ) {
139 monitor_cache_release( mi, locked );
140 locked = NULL;
141 }
142
143 if ( sub ) {
144 rc = monitor_send_children( op, rs, sub_nv, sub_ch, sub );
145 if ( rc ) {
146 freeout:
147 if ( locked ) {
148 monitor_cache_release( mi, locked );
149 }
150 if ( nonvolatile == 0 ) {
151 for ( ; e_tmp != NULL; ) {
152 mp = ( monitor_entry_t * )e_tmp->e_private;
153 e = e_tmp;
154 e_tmp = mp->mp_next;
155 monitor_cache_lock( e );
156 monitor_cache_release( mi, e );
157
158 if ( e_tmp == e_nonvolatile ) {
159 break;
160 }
161 }
162 }
163
164 return( rc );
165 }
166 }
167 if ( locked ) {
168 monitor_cache_release( mi, locked );
169 }
170 }
171
172 return LDAP_SUCCESS;
173 }
174
175 int
176 monitor_back_search( Operation *op, SlapReply *rs )
177 {
178 monitor_info_t *mi = ( monitor_info_t * )op->o_bd->be_private;
179 int rc = LDAP_SUCCESS;
180 Entry *e = NULL, *matched = NULL;
181 Entry *e_nv = NULL, *e_ch = NULL;
182 slap_mask_t mask;
183
184 Debug( LDAP_DEBUG_TRACE, "=> monitor_back_search\n" );
185
186
187 /* get entry with reader lock */
188 monitor_cache_dn2entry( op, rs, &op->o_req_ndn, &e, &matched );
189 if ( e == NULL ) {
190 rs->sr_err = LDAP_NO_SUCH_OBJECT;
191 if ( matched ) {
192 if ( !access_allowed_mask( op, matched,
193 slap_schema.si_ad_entry,
194 NULL, ACL_DISCLOSE, NULL, NULL ) )
195 {
196 /* do nothing */ ;
197 } else {
198 rs->sr_matched = matched->e_dn;
199 }
200 }
201
202 send_ldap_result( op, rs );
203 if ( matched ) {
204 monitor_cache_release( mi, matched );
205 rs->sr_matched = NULL;
206 }
207
208 return rs->sr_err;
209 }
210
211 /* NOTE: __NEW__ "search" access is required
212 * on searchBase object */
213 if ( !access_allowed_mask( op, e, slap_schema.si_ad_entry,
214 NULL, ACL_SEARCH, NULL, &mask ) )
215 {
216 monitor_cache_release( mi, e );
217
218 if ( !ACL_GRANT( mask, ACL_DISCLOSE ) ) {
219 rs->sr_err = LDAP_NO_SUCH_OBJECT;
220 } else {
221 rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
222 }
223
224 send_ldap_result( op, rs );
225
226 return rs->sr_err;
227 }
228
229 rs->sr_attrs = op->oq_search.rs_attrs;
230 switch ( op->oq_search.rs_scope ) {
231 case LDAP_SCOPE_BASE:
232 monitor_entry_update( op, rs, e );
233 rc = test_filter( op, e, op->oq_search.rs_filter );
234 if ( rc == LDAP_COMPARE_TRUE ) {
235 rs->sr_entry = e;
236 rs->sr_flags = REP_ENTRY_MUSTRELEASE;
237 send_search_entry( op, rs );
238 rs->sr_entry = NULL;
239 } else {
240 monitor_cache_release( mi, e );
241 }
242 rc = LDAP_SUCCESS;
243 break;
244
245 case LDAP_SCOPE_ONELEVEL:
246 case LDAP_SCOPE_SUBORDINATE:
247 monitor_find_children( op, rs, e, &e_nv, &e_ch );
248 rc = monitor_send_children( op, rs, e_nv, e_ch,
249 op->oq_search.rs_scope == LDAP_SCOPE_SUBORDINATE );
250 monitor_cache_release( mi, e );
251 break;
252
253 case LDAP_SCOPE_SUBTREE:
254 monitor_entry_update( op, rs, e );
255 monitor_find_children( op, rs, e, &e_nv, &e_ch );
256 rc = test_filter( op, e, op->oq_search.rs_filter );
257 if ( rc == LDAP_COMPARE_TRUE ) {
258 rs->sr_entry = e;
259 send_search_entry( op, rs );
260 rs->sr_entry = NULL;
261 }
262
263 rc = monitor_send_children( op, rs, e_nv, e_ch, 1 );
264 monitor_cache_release( mi, e );
265 break;
266
267 default:
268 rc = LDAP_UNWILLING_TO_PERFORM;
269 monitor_cache_release( mi, e );
270 }
271
272 rs->sr_attrs = NULL;
273 rs->sr_err = rc;
274 if ( rs->sr_err != SLAPD_ABANDON ) {
275 send_ldap_result( op, rs );
276 }
277
278 return rs->sr_err;
279 }
280
281