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