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