1 1.3 christos /* $NetBSD: noopsrch.c,v 1.4 2025/09/05 21:16:17 christos Exp $ */ 2 1.1 tron 3 1.1 tron /* noopsrch.c - LDAP Control that counts entries a search would return */ 4 1.1 tron /* $OpenLDAP$ */ 5 1.1 tron /* This work is part of OpenLDAP Software <http://www.openldap.org/>. 6 1.1 tron * 7 1.4 christos * Copyright 2010-2024 The OpenLDAP Foundation. 8 1.1 tron * All rights reserved. 9 1.1 tron * 10 1.1 tron * Redistribution and use in source and binary forms, with or without 11 1.1 tron * modification, are permitted only as authorized by the OpenLDAP 12 1.1 tron * Public License. 13 1.1 tron * 14 1.1 tron * A copy of this license is available in the file LICENSE in the 15 1.1 tron * top-level directory of the distribution or, alternatively, at 16 1.1 tron * <http://www.OpenLDAP.org/license.html>. 17 1.1 tron */ 18 1.1 tron /* ACKNOWLEDGEMENTS: 19 1.1 tron * This work was initially developed by Pierangelo Masarati for inclusion 20 1.1 tron * in OpenLDAP Software. 21 1.1 tron */ 22 1.1 tron 23 1.2 christos #include <sys/cdefs.h> 24 1.3 christos __RCSID("$NetBSD: noopsrch.c,v 1.4 2025/09/05 21:16:17 christos Exp $"); 25 1.2 christos 26 1.1 tron #include "portable.h" 27 1.1 tron 28 1.1 tron /* define SLAPD_OVER_NOOPSRCH=2 to build as run-time loadable module */ 29 1.1 tron #ifdef SLAPD_OVER_NOOPSRCH 30 1.1 tron 31 1.1 tron /* 32 1.1 tron * Control OID 33 1.1 tron */ 34 1.1 tron #define LDAP_CONTROL_X_NOOPSRCH "1.3.6.1.4.1.4203.666.5.18" 35 1.1 tron 36 1.1 tron #include "slap.h" 37 1.1 tron #include "ac/string.h" 38 1.1 tron 39 1.1 tron #define o_noopsrch o_ctrlflag[noopsrch_cid] 40 1.1 tron #define o_ctrlnoopsrch o_controls[noopsrch_cid] 41 1.1 tron 42 1.1 tron static int noopsrch_cid; 43 1.1 tron static slap_overinst noopsrch; 44 1.1 tron 45 1.1 tron static int 46 1.1 tron noopsrch_parseCtrl ( 47 1.1 tron Operation *op, 48 1.1 tron SlapReply *rs, 49 1.1 tron LDAPControl *ctrl ) 50 1.1 tron { 51 1.1 tron if ( op->o_noopsrch != SLAP_CONTROL_NONE ) { 52 1.1 tron rs->sr_text = "No-op Search control specified multiple times"; 53 1.1 tron return LDAP_PROTOCOL_ERROR; 54 1.1 tron } 55 1.1 tron 56 1.1 tron if ( !BER_BVISNULL( &ctrl->ldctl_value ) ) { 57 1.1 tron rs->sr_text = "No-op Search control value is present"; 58 1.1 tron return LDAP_PROTOCOL_ERROR; 59 1.1 tron } 60 1.1 tron 61 1.1 tron op->o_ctrlnoopsrch = (void *)NULL; 62 1.1 tron 63 1.1 tron op->o_noopsrch = ctrl->ldctl_iscritical 64 1.1 tron ? SLAP_CONTROL_CRITICAL 65 1.1 tron : SLAP_CONTROL_NONCRITICAL; 66 1.1 tron 67 1.1 tron rs->sr_err = LDAP_SUCCESS; 68 1.1 tron 69 1.1 tron return rs->sr_err; 70 1.1 tron } 71 1.1 tron 72 1.1 tron int dummy; 73 1.1 tron 74 1.1 tron typedef struct noopsrch_cb_t { 75 1.1 tron slap_overinst *nc_on; 76 1.1 tron ber_int_t nc_nentries; 77 1.1 tron ber_int_t nc_nsearchref; 78 1.1 tron AttributeName *nc_save_attrs; 79 1.1 tron int *nc_pdummy; 80 1.1 tron int nc_save_slimit; 81 1.1 tron } noopsrch_cb_t; 82 1.1 tron 83 1.1 tron static int 84 1.1 tron noopsrch_response( Operation *op, SlapReply *rs ) 85 1.1 tron { 86 1.1 tron noopsrch_cb_t *nc = (noopsrch_cb_t *)op->o_callback->sc_private; 87 1.1 tron 88 1.1 tron /* if the control is global, limits are not computed yet */ 89 1.1 tron if ( nc->nc_pdummy == &dummy ) { 90 1.1 tron nc->nc_save_slimit = op->ors_slimit; 91 1.1 tron op->ors_slimit = SLAP_NO_LIMIT; 92 1.1 tron nc->nc_pdummy = NULL; 93 1.1 tron } 94 1.1 tron 95 1.1 tron if ( rs->sr_type == REP_SEARCH ) { 96 1.1 tron nc->nc_nentries++; 97 1.1 tron #ifdef NOOPSRCH_DEBUG 98 1.3 christos Debug( LDAP_DEBUG_TRACE, "noopsrch_response(REP_SEARCH): nentries=%d\n", nc->nc_nentries ); 99 1.1 tron #endif 100 1.1 tron return 0; 101 1.1 tron 102 1.1 tron } else if ( rs->sr_type == REP_SEARCHREF ) { 103 1.1 tron nc->nc_nsearchref++; 104 1.1 tron return 0; 105 1.1 tron 106 1.1 tron } else if ( rs->sr_type == REP_RESULT ) { 107 1.1 tron BerElementBuffer berbuf; 108 1.1 tron BerElement *ber = (BerElement *) &berbuf; 109 1.1 tron struct berval ctrlval; 110 1.1 tron LDAPControl *ctrl, *ctrlsp[2]; 111 1.1 tron int rc = rs->sr_err; 112 1.1 tron 113 1.1 tron if ( nc->nc_save_slimit >= 0 && nc->nc_nentries >= nc->nc_save_slimit ) { 114 1.1 tron rc = LDAP_SIZELIMIT_EXCEEDED; 115 1.1 tron } 116 1.1 tron 117 1.1 tron #ifdef NOOPSRCH_DEBUG 118 1.1 tron Debug( LDAP_DEBUG_TRACE, "noopsrch_response(REP_RESULT): err=%d nentries=%d nref=%d\n", rc, nc->nc_nentries, nc->nc_nsearchref ); 119 1.1 tron #endif 120 1.1 tron 121 1.1 tron ber_init2( ber, NULL, LBER_USE_DER ); 122 1.1 tron 123 1.1 tron ber_printf( ber, "{iii}", rc, nc->nc_nentries, nc->nc_nsearchref ); 124 1.1 tron if ( ber_flatten2( ber, &ctrlval, 0 ) == -1 ) { 125 1.1 tron ber_free_buf( ber ); 126 1.1 tron if ( op->o_noopsrch == SLAP_CONTROL_CRITICAL ) { 127 1.1 tron return LDAP_CONSTRAINT_VIOLATION; 128 1.1 tron } 129 1.1 tron return SLAP_CB_CONTINUE; 130 1.1 tron } 131 1.1 tron 132 1.1 tron ctrl = op->o_tmpcalloc( 1, 133 1.1 tron sizeof( LDAPControl ) + ctrlval.bv_len + 1, 134 1.1 tron op->o_tmpmemctx ); 135 1.1 tron ctrl->ldctl_value.bv_val = (char *)&ctrl[ 1 ]; 136 1.1 tron ctrl->ldctl_oid = LDAP_CONTROL_X_NOOPSRCH; 137 1.1 tron ctrl->ldctl_iscritical = 0; 138 1.1 tron ctrl->ldctl_value.bv_len = ctrlval.bv_len; 139 1.1 tron AC_MEMCPY( ctrl->ldctl_value.bv_val, ctrlval.bv_val, ctrlval.bv_len ); 140 1.1 tron ctrl->ldctl_value.bv_val[ ctrl->ldctl_value.bv_len ] = '\0'; 141 1.1 tron 142 1.1 tron ber_free_buf( ber ); 143 1.1 tron 144 1.1 tron ctrlsp[0] = ctrl; 145 1.1 tron ctrlsp[1] = NULL; 146 1.1 tron slap_add_ctrls( op, rs, ctrlsp ); 147 1.1 tron } 148 1.2 christos return SLAP_CB_CONTINUE; 149 1.1 tron } 150 1.1 tron 151 1.1 tron static int 152 1.1 tron noopsrch_cleanup( Operation *op, SlapReply *rs ) 153 1.1 tron { 154 1.1 tron if ( rs->sr_type == REP_RESULT || rs->sr_err == SLAPD_ABANDON ) { 155 1.1 tron noopsrch_cb_t *nc = (noopsrch_cb_t *)op->o_callback->sc_private; 156 1.1 tron op->ors_attrs = nc->nc_save_attrs; 157 1.1 tron if ( nc->nc_pdummy == NULL ) { 158 1.1 tron op->ors_slimit = nc->nc_save_slimit; 159 1.1 tron } 160 1.1 tron 161 1.1 tron op->o_tmpfree( op->o_callback, op->o_tmpmemctx ); 162 1.1 tron op->o_callback = NULL; 163 1.1 tron } 164 1.1 tron 165 1.1 tron return SLAP_CB_CONTINUE; 166 1.1 tron } 167 1.1 tron 168 1.1 tron static int 169 1.1 tron noopsrch_op_search( Operation *op, SlapReply *rs ) 170 1.1 tron { 171 1.1 tron if ( op->o_noopsrch != SLAP_CONTROL_NONE ) { 172 1.1 tron slap_callback *sc; 173 1.1 tron noopsrch_cb_t *nc; 174 1.1 tron 175 1.1 tron sc = op->o_tmpcalloc( 1, sizeof( slap_callback ) + sizeof( noopsrch_cb_t ), op->o_tmpmemctx ); 176 1.1 tron 177 1.1 tron nc = (noopsrch_cb_t *)&sc[ 1 ]; 178 1.1 tron nc->nc_on = (slap_overinst *)op->o_bd->bd_info; 179 1.1 tron nc->nc_nentries = 0; 180 1.1 tron nc->nc_nsearchref = 0; 181 1.1 tron nc->nc_save_attrs = op->ors_attrs; 182 1.1 tron nc->nc_pdummy = &dummy; 183 1.1 tron 184 1.1 tron sc->sc_response = noopsrch_response; 185 1.1 tron sc->sc_cleanup = noopsrch_cleanup; 186 1.1 tron sc->sc_private = (void *)nc; 187 1.1 tron 188 1.1 tron op->ors_attrs = slap_anlist_no_attrs; 189 1.1 tron 190 1.1 tron sc->sc_next = op->o_callback->sc_next; 191 1.1 tron op->o_callback->sc_next = sc; 192 1.1 tron } 193 1.1 tron 194 1.1 tron return SLAP_CB_CONTINUE; 195 1.1 tron } 196 1.1 tron 197 1.1 tron static int noopsrch_cnt; 198 1.1 tron 199 1.1 tron static int 200 1.1 tron noopsrch_db_init( BackendDB *be, ConfigReply *cr) 201 1.1 tron { 202 1.1 tron if ( noopsrch_cnt++ == 0 ) { 203 1.1 tron int rc; 204 1.1 tron 205 1.1 tron rc = register_supported_control( LDAP_CONTROL_X_NOOPSRCH, 206 1.1 tron SLAP_CTRL_SEARCH | SLAP_CTRL_GLOBAL_SEARCH, NULL, 207 1.1 tron noopsrch_parseCtrl, &noopsrch_cid ); 208 1.1 tron if ( rc != LDAP_SUCCESS ) { 209 1.1 tron Debug( LDAP_DEBUG_ANY, 210 1.1 tron "noopsrch_initialize: Failed to register control '%s' (%d)\n", 211 1.3 christos LDAP_CONTROL_X_NOOPSRCH, rc ); 212 1.1 tron return rc; 213 1.1 tron } 214 1.1 tron } 215 1.1 tron 216 1.1 tron return LDAP_SUCCESS; 217 1.1 tron } 218 1.1 tron 219 1.1 tron static int 220 1.1 tron noopsrch_db_destroy( BackendDB *be, ConfigReply *cr ) 221 1.1 tron { 222 1.1 tron assert( noopsrch_cnt > 0 ); 223 1.1 tron 224 1.1 tron #ifdef SLAP_CONFIG_DELETE 225 1.1 tron overlay_unregister_control( be, LDAP_CONTROL_X_NOOPSRCH ); 226 1.1 tron if ( --noopsrch_cnt == 0 ) { 227 1.1 tron unregister_supported_control( LDAP_CONTROL_X_NOOPSRCH ); 228 1.1 tron } 229 1.1 tron 230 1.1 tron #endif /* SLAP_CONFIG_DELETE */ 231 1.1 tron 232 1.1 tron return 0; 233 1.1 tron } 234 1.1 tron 235 1.1 tron #if SLAPD_OVER_NOOPSRCH == SLAPD_MOD_DYNAMIC 236 1.1 tron static 237 1.1 tron #endif /* SLAPD_OVER_NOOPSRCH == SLAPD_MOD_DYNAMIC */ 238 1.1 tron int 239 1.1 tron noopsrch_initialize( void ) 240 1.1 tron { 241 1.1 tron 242 1.1 tron noopsrch.on_bi.bi_type = "noopsrch"; 243 1.1 tron 244 1.3 christos noopsrch.on_bi.bi_flags = SLAPO_BFLAG_SINGLE; 245 1.1 tron noopsrch.on_bi.bi_db_init = noopsrch_db_init; 246 1.1 tron noopsrch.on_bi.bi_db_destroy = noopsrch_db_destroy; 247 1.1 tron noopsrch.on_bi.bi_op_search = noopsrch_op_search; 248 1.1 tron 249 1.1 tron return overlay_register( &noopsrch ); 250 1.1 tron } 251 1.1 tron 252 1.1 tron #if SLAPD_OVER_NOOPSRCH == SLAPD_MOD_DYNAMIC 253 1.1 tron int 254 1.1 tron init_module( int argc, char *argv[] ) 255 1.1 tron { 256 1.1 tron return noopsrch_initialize(); 257 1.1 tron } 258 1.1 tron #endif /* SLAPD_OVER_NOOPSRCH == SLAPD_MOD_DYNAMIC */ 259 1.1 tron 260 1.1 tron #endif /* SLAPD_OVER_NOOPSRCH */ 261