1 1.3 christos /* $NetBSD: retcode.c,v 1.4 2025/09/05 21:16:32 christos Exp $ */ 2 1.2 christos 3 1.1 lukem /* retcode.c - customizable response for client testing purposes */ 4 1.2 christos /* $OpenLDAP$ */ 5 1.1 lukem /* This work is part of OpenLDAP Software <http://www.openldap.org/>. 6 1.1 lukem * 7 1.4 christos * Copyright 2005-2024 The OpenLDAP Foundation. 8 1.1 lukem * Portions Copyright 2005 Pierangelo Masarati <ando (at) sys-net.it> 9 1.1 lukem * All rights reserved. 10 1.1 lukem * 11 1.1 lukem * Redistribution and use in source and binary forms, with or without 12 1.1 lukem * modification, are permitted only as authorized by the OpenLDAP 13 1.1 lukem * Public License. 14 1.1 lukem * 15 1.1 lukem * A copy of this license is available in the file LICENSE in the 16 1.1 lukem * top-level directory of the distribution or, alternatively, at 17 1.1 lukem * <http://www.OpenLDAP.org/license.html>. 18 1.1 lukem */ 19 1.1 lukem /* ACKNOWLEDGEMENTS: 20 1.1 lukem * This work was initially developed by Pierangelo Masarati for inclusion 21 1.1 lukem * in OpenLDAP Software. 22 1.1 lukem */ 23 1.1 lukem 24 1.2 christos #include <sys/cdefs.h> 25 1.3 christos __RCSID("$NetBSD: retcode.c,v 1.4 2025/09/05 21:16:32 christos Exp $"); 26 1.2 christos 27 1.1 lukem #include "portable.h" 28 1.1 lukem 29 1.1 lukem #ifdef SLAPD_OVER_RETCODE 30 1.1 lukem 31 1.1 lukem #include <stdio.h> 32 1.1 lukem 33 1.1 lukem #include <ac/unistd.h> 34 1.1 lukem #include <ac/string.h> 35 1.1 lukem #include <ac/ctype.h> 36 1.1 lukem #include <ac/socket.h> 37 1.1 lukem 38 1.1 lukem #include "slap.h" 39 1.3 christos #include "slap-config.h" 40 1.1 lukem #include "lutil.h" 41 1.1 lukem #include "ldif.h" 42 1.1 lukem 43 1.1 lukem static slap_overinst retcode; 44 1.1 lukem 45 1.1 lukem static AttributeDescription *ad_errCode; 46 1.1 lukem static AttributeDescription *ad_errText; 47 1.1 lukem static AttributeDescription *ad_errOp; 48 1.1 lukem static AttributeDescription *ad_errSleepTime; 49 1.1 lukem static AttributeDescription *ad_errMatchedDN; 50 1.1 lukem static AttributeDescription *ad_errUnsolicitedOID; 51 1.1 lukem static AttributeDescription *ad_errUnsolicitedData; 52 1.1 lukem static AttributeDescription *ad_errDisconnect; 53 1.1 lukem 54 1.1 lukem static ObjectClass *oc_errAbsObject; 55 1.1 lukem static ObjectClass *oc_errObject; 56 1.1 lukem static ObjectClass *oc_errAuxObject; 57 1.1 lukem 58 1.1 lukem typedef enum retcode_op_e { 59 1.1 lukem SN_DG_OP_NONE = 0x0000, 60 1.1 lukem SN_DG_OP_ADD = 0x0001, 61 1.1 lukem SN_DG_OP_BIND = 0x0002, 62 1.1 lukem SN_DG_OP_COMPARE = 0x0004, 63 1.1 lukem SN_DG_OP_DELETE = 0x0008, 64 1.1 lukem SN_DG_OP_MODIFY = 0x0010, 65 1.1 lukem SN_DG_OP_RENAME = 0x0020, 66 1.1 lukem SN_DG_OP_SEARCH = 0x0040, 67 1.1 lukem SN_DG_EXTENDED = 0x0080, 68 1.1 lukem SN_DG_OP_AUTH = SN_DG_OP_BIND, 69 1.1 lukem SN_DG_OP_READ = (SN_DG_OP_COMPARE|SN_DG_OP_SEARCH), 70 1.1 lukem SN_DG_OP_WRITE = (SN_DG_OP_ADD|SN_DG_OP_DELETE|SN_DG_OP_MODIFY|SN_DG_OP_RENAME), 71 1.1 lukem SN_DG_OP_ALL = (SN_DG_OP_AUTH|SN_DG_OP_READ|SN_DG_OP_WRITE|SN_DG_EXTENDED) 72 1.1 lukem } retcode_op_e; 73 1.1 lukem 74 1.1 lukem typedef struct retcode_item_t { 75 1.2 christos struct berval rdi_line; 76 1.1 lukem struct berval rdi_dn; 77 1.1 lukem struct berval rdi_ndn; 78 1.1 lukem struct berval rdi_text; 79 1.1 lukem struct berval rdi_matched; 80 1.1 lukem int rdi_err; 81 1.1 lukem BerVarray rdi_ref; 82 1.1 lukem int rdi_sleeptime; 83 1.1 lukem Entry rdi_e; 84 1.1 lukem slap_mask_t rdi_mask; 85 1.1 lukem struct berval rdi_unsolicited_oid; 86 1.1 lukem struct berval rdi_unsolicited_data; 87 1.1 lukem 88 1.1 lukem unsigned rdi_flags; 89 1.1 lukem #define RDI_PRE_DISCONNECT (0x1U) 90 1.1 lukem #define RDI_POST_DISCONNECT (0x2U) 91 1.1 lukem 92 1.1 lukem struct retcode_item_t *rdi_next; 93 1.1 lukem } retcode_item_t; 94 1.1 lukem 95 1.1 lukem typedef struct retcode_t { 96 1.1 lukem struct berval rd_pdn; 97 1.1 lukem struct berval rd_npdn; 98 1.1 lukem 99 1.1 lukem int rd_sleep; 100 1.1 lukem 101 1.1 lukem retcode_item_t *rd_item; 102 1.1 lukem 103 1.2 christos int rd_indir; 104 1.1 lukem #define RETCODE_FINDIR 0x01 105 1.2 christos #define RETCODE_INDIR( rd ) ( (rd)->rd_indir ) 106 1.1 lukem } retcode_t; 107 1.1 lukem 108 1.1 lukem static int 109 1.1 lukem retcode_entry_response( Operation *op, SlapReply *rs, BackendInfo *bi, Entry *e ); 110 1.1 lukem 111 1.1 lukem static unsigned int 112 1.1 lukem retcode_sleep( int s ) 113 1.1 lukem { 114 1.1 lukem unsigned int r = 0; 115 1.1 lukem 116 1.1 lukem /* sleep as required */ 117 1.1 lukem if ( s < 0 ) { 118 1.1 lukem #if 0 /* use high-order bits for better randomness (Numerical Recipes in "C") */ 119 1.1 lukem r = rand() % (-s); 120 1.1 lukem #endif 121 1.1 lukem r = ((double)(-s))*rand()/(RAND_MAX + 1.0); 122 1.1 lukem } else if ( s > 0 ) { 123 1.1 lukem r = (unsigned int)s; 124 1.1 lukem } 125 1.1 lukem if ( r ) { 126 1.1 lukem sleep( r ); 127 1.1 lukem } 128 1.1 lukem 129 1.1 lukem return r; 130 1.1 lukem } 131 1.1 lukem 132 1.1 lukem static int 133 1.1 lukem retcode_cleanup_cb( Operation *op, SlapReply *rs ) 134 1.1 lukem { 135 1.1 lukem rs->sr_matched = NULL; 136 1.1 lukem rs->sr_text = NULL; 137 1.1 lukem 138 1.1 lukem if ( rs->sr_ref != NULL ) { 139 1.1 lukem ber_bvarray_free( rs->sr_ref ); 140 1.1 lukem rs->sr_ref = NULL; 141 1.1 lukem } 142 1.1 lukem 143 1.1 lukem ch_free( op->o_callback ); 144 1.1 lukem op->o_callback = NULL; 145 1.1 lukem 146 1.1 lukem return SLAP_CB_CONTINUE; 147 1.1 lukem } 148 1.1 lukem 149 1.1 lukem static int 150 1.1 lukem retcode_send_onelevel( Operation *op, SlapReply *rs ) 151 1.1 lukem { 152 1.1 lukem slap_overinst *on = (slap_overinst *)op->o_bd->bd_info; 153 1.1 lukem retcode_t *rd = (retcode_t *)on->on_bi.bi_private; 154 1.1 lukem 155 1.1 lukem retcode_item_t *rdi; 156 1.1 lukem 157 1.1 lukem for ( rdi = rd->rd_item; rdi != NULL; rdi = rdi->rdi_next ) { 158 1.1 lukem if ( op->o_abandon ) { 159 1.1 lukem return rs->sr_err = SLAPD_ABANDON; 160 1.1 lukem } 161 1.1 lukem 162 1.1 lukem rs->sr_err = test_filter( op, &rdi->rdi_e, op->ors_filter ); 163 1.1 lukem if ( rs->sr_err == LDAP_COMPARE_TRUE ) { 164 1.1 lukem /* safe default */ 165 1.1 lukem rs->sr_attrs = op->ors_attrs; 166 1.1 lukem rs->sr_operational_attrs = NULL; 167 1.1 lukem rs->sr_ctrls = NULL; 168 1.1 lukem rs->sr_flags = 0; 169 1.1 lukem rs->sr_err = LDAP_SUCCESS; 170 1.1 lukem rs->sr_entry = &rdi->rdi_e; 171 1.1 lukem 172 1.1 lukem rs->sr_err = send_search_entry( op, rs ); 173 1.2 christos rs->sr_flags = 0; 174 1.1 lukem rs->sr_entry = NULL; 175 1.2 christos rs->sr_attrs = NULL; 176 1.1 lukem 177 1.1 lukem switch ( rs->sr_err ) { 178 1.1 lukem case LDAP_UNAVAILABLE: /* connection closed */ 179 1.1 lukem rs->sr_err = LDAP_OTHER; 180 1.1 lukem /* fallthru */ 181 1.1 lukem case LDAP_SIZELIMIT_EXCEEDED: 182 1.1 lukem goto done; 183 1.1 lukem } 184 1.1 lukem } 185 1.1 lukem rs->sr_err = LDAP_SUCCESS; 186 1.1 lukem } 187 1.1 lukem 188 1.1 lukem done:; 189 1.1 lukem 190 1.1 lukem send_ldap_result( op, rs ); 191 1.1 lukem 192 1.1 lukem return rs->sr_err; 193 1.1 lukem } 194 1.1 lukem 195 1.1 lukem static int 196 1.1 lukem retcode_op_add( Operation *op, SlapReply *rs ) 197 1.1 lukem { 198 1.1 lukem return retcode_entry_response( op, rs, NULL, op->ora_e ); 199 1.1 lukem } 200 1.1 lukem 201 1.1 lukem typedef struct retcode_cb_t { 202 1.1 lukem BackendInfo *rdc_info; 203 1.1 lukem unsigned rdc_flags; 204 1.1 lukem ber_tag_t rdc_tag; 205 1.1 lukem AttributeName *rdc_attrs; 206 1.1 lukem } retcode_cb_t; 207 1.1 lukem 208 1.1 lukem static int 209 1.1 lukem retcode_cb_response( Operation *op, SlapReply *rs ) 210 1.1 lukem { 211 1.1 lukem retcode_cb_t *rdc = (retcode_cb_t *)op->o_callback->sc_private; 212 1.1 lukem 213 1.1 lukem op->o_tag = rdc->rdc_tag; 214 1.1 lukem if ( rs->sr_type == REP_SEARCH ) { 215 1.1 lukem ber_tag_t o_tag = op->o_tag; 216 1.1 lukem int rc; 217 1.1 lukem 218 1.1 lukem if ( op->o_tag == LDAP_REQ_SEARCH ) { 219 1.1 lukem rs->sr_attrs = rdc->rdc_attrs; 220 1.1 lukem } 221 1.1 lukem rc = retcode_entry_response( op, rs, rdc->rdc_info, rs->sr_entry ); 222 1.1 lukem op->o_tag = o_tag; 223 1.1 lukem 224 1.1 lukem return rc; 225 1.1 lukem } 226 1.1 lukem 227 1.1 lukem switch ( rs->sr_err ) { 228 1.1 lukem case LDAP_SUCCESS: 229 1.1 lukem case LDAP_NO_SUCH_OBJECT: 230 1.1 lukem /* in case of noSuchObject, stop the internal search 231 1.1 lukem * for in-directory error stuff */ 232 1.1 lukem if ( !op->o_abandon ) { 233 1.1 lukem rdc->rdc_flags = SLAP_CB_CONTINUE; 234 1.1 lukem } 235 1.1 lukem return 0; 236 1.1 lukem } 237 1.1 lukem 238 1.1 lukem return SLAP_CB_CONTINUE; 239 1.1 lukem } 240 1.1 lukem 241 1.1 lukem static int 242 1.1 lukem retcode_op_internal( Operation *op, SlapReply *rs ) 243 1.1 lukem { 244 1.1 lukem slap_overinst *on = (slap_overinst *)op->o_bd->bd_info; 245 1.1 lukem 246 1.1 lukem Operation op2 = *op; 247 1.1 lukem BackendDB db = *op->o_bd; 248 1.1 lukem slap_callback sc = { 0 }; 249 1.1 lukem retcode_cb_t rdc; 250 1.1 lukem 251 1.1 lukem int rc; 252 1.1 lukem 253 1.1 lukem op2.o_tag = LDAP_REQ_SEARCH; 254 1.1 lukem op2.ors_scope = LDAP_SCOPE_BASE; 255 1.1 lukem op2.ors_deref = LDAP_DEREF_NEVER; 256 1.1 lukem op2.ors_tlimit = SLAP_NO_LIMIT; 257 1.1 lukem op2.ors_slimit = SLAP_NO_LIMIT; 258 1.1 lukem op2.ors_limit = NULL; 259 1.1 lukem op2.ors_attrsonly = 0; 260 1.1 lukem op2.ors_attrs = slap_anlist_all_attributes; 261 1.1 lukem 262 1.1 lukem ber_str2bv_x( "(objectClass=errAbsObject)", 263 1.1 lukem STRLENOF( "(objectClass=errAbsObject)" ), 264 1.1 lukem 1, &op2.ors_filterstr, op2.o_tmpmemctx ); 265 1.1 lukem op2.ors_filter = str2filter_x( &op2, op2.ors_filterstr.bv_val ); 266 1.1 lukem 267 1.2 christos /* errAbsObject is defined by this overlay! */ 268 1.2 christos assert( op2.ors_filter != NULL ); 269 1.2 christos 270 1.1 lukem db.bd_info = on->on_info->oi_orig; 271 1.1 lukem op2.o_bd = &db; 272 1.1 lukem 273 1.1 lukem rdc.rdc_info = on->on_info->oi_orig; 274 1.1 lukem rdc.rdc_flags = RETCODE_FINDIR; 275 1.1 lukem if ( op->o_tag == LDAP_REQ_SEARCH ) { 276 1.1 lukem rdc.rdc_attrs = op->ors_attrs; 277 1.1 lukem } 278 1.1 lukem rdc.rdc_tag = op->o_tag; 279 1.1 lukem sc.sc_response = retcode_cb_response; 280 1.1 lukem sc.sc_private = &rdc; 281 1.1 lukem op2.o_callback = ≻ 282 1.1 lukem 283 1.1 lukem rc = op2.o_bd->be_search( &op2, rs ); 284 1.1 lukem op->o_abandon = op2.o_abandon; 285 1.1 lukem 286 1.2 christos filter_free_x( &op2, op2.ors_filter, 1 ); 287 1.1 lukem ber_memfree_x( op2.ors_filterstr.bv_val, op2.o_tmpmemctx ); 288 1.1 lukem 289 1.1 lukem if ( rdc.rdc_flags == SLAP_CB_CONTINUE ) { 290 1.1 lukem return SLAP_CB_CONTINUE; 291 1.1 lukem } 292 1.1 lukem 293 1.1 lukem return rc; 294 1.1 lukem } 295 1.1 lukem 296 1.1 lukem static int 297 1.1 lukem retcode_op_func( Operation *op, SlapReply *rs ) 298 1.1 lukem { 299 1.1 lukem slap_overinst *on = (slap_overinst *)op->o_bd->bd_info; 300 1.1 lukem retcode_t *rd = (retcode_t *)on->on_bi.bi_private; 301 1.1 lukem 302 1.1 lukem retcode_item_t *rdi; 303 1.1 lukem struct berval nrdn, npdn; 304 1.1 lukem 305 1.1 lukem slap_callback *cb = NULL; 306 1.1 lukem 307 1.1 lukem /* sleep as required */ 308 1.1 lukem retcode_sleep( rd->rd_sleep ); 309 1.1 lukem 310 1.1 lukem if ( !dnIsSuffix( &op->o_req_ndn, &rd->rd_npdn ) ) { 311 1.1 lukem if ( RETCODE_INDIR( rd ) ) { 312 1.1 lukem switch ( op->o_tag ) { 313 1.1 lukem case LDAP_REQ_ADD: 314 1.1 lukem return retcode_op_add( op, rs ); 315 1.1 lukem 316 1.1 lukem case LDAP_REQ_BIND: 317 1.1 lukem /* skip if rootdn */ 318 1.1 lukem /* FIXME: better give the db a chance? */ 319 1.1 lukem if ( be_isroot_pw( op ) ) { 320 1.1 lukem return LDAP_SUCCESS; 321 1.1 lukem } 322 1.1 lukem return retcode_op_internal( op, rs ); 323 1.1 lukem 324 1.1 lukem case LDAP_REQ_SEARCH: 325 1.1 lukem if ( op->ors_scope == LDAP_SCOPE_BASE ) { 326 1.1 lukem rs->sr_err = retcode_op_internal( op, rs ); 327 1.1 lukem switch ( rs->sr_err ) { 328 1.1 lukem case SLAP_CB_CONTINUE: 329 1.1 lukem if ( rs->sr_nentries == 0 ) { 330 1.1 lukem break; 331 1.1 lukem } 332 1.1 lukem rs->sr_err = LDAP_SUCCESS; 333 1.1 lukem /* fallthru */ 334 1.1 lukem 335 1.1 lukem default: 336 1.1 lukem send_ldap_result( op, rs ); 337 1.1 lukem break; 338 1.1 lukem } 339 1.1 lukem return rs->sr_err; 340 1.1 lukem } 341 1.1 lukem break; 342 1.1 lukem 343 1.1 lukem case LDAP_REQ_MODIFY: 344 1.1 lukem case LDAP_REQ_DELETE: 345 1.1 lukem case LDAP_REQ_MODRDN: 346 1.1 lukem case LDAP_REQ_COMPARE: 347 1.1 lukem return retcode_op_internal( op, rs ); 348 1.1 lukem } 349 1.1 lukem } 350 1.1 lukem 351 1.1 lukem return SLAP_CB_CONTINUE; 352 1.1 lukem } 353 1.1 lukem 354 1.1 lukem if ( op->o_tag == LDAP_REQ_SEARCH 355 1.1 lukem && op->ors_scope != LDAP_SCOPE_BASE 356 1.1 lukem && op->o_req_ndn.bv_len == rd->rd_npdn.bv_len ) 357 1.1 lukem { 358 1.1 lukem return retcode_send_onelevel( op, rs ); 359 1.1 lukem } 360 1.1 lukem 361 1.1 lukem dnParent( &op->o_req_ndn, &npdn ); 362 1.1 lukem if ( npdn.bv_len != rd->rd_npdn.bv_len ) { 363 1.1 lukem rs->sr_err = LDAP_NO_SUCH_OBJECT; 364 1.1 lukem rs->sr_matched = rd->rd_pdn.bv_val; 365 1.1 lukem send_ldap_result( op, rs ); 366 1.1 lukem rs->sr_matched = NULL; 367 1.1 lukem return rs->sr_err; 368 1.1 lukem } 369 1.1 lukem 370 1.1 lukem dnRdn( &op->o_req_ndn, &nrdn ); 371 1.1 lukem 372 1.1 lukem for ( rdi = rd->rd_item; rdi != NULL; rdi = rdi->rdi_next ) { 373 1.1 lukem struct berval rdi_nrdn; 374 1.1 lukem 375 1.1 lukem dnRdn( &rdi->rdi_ndn, &rdi_nrdn ); 376 1.1 lukem if ( dn_match( &nrdn, &rdi_nrdn ) ) { 377 1.1 lukem break; 378 1.1 lukem } 379 1.1 lukem } 380 1.1 lukem 381 1.1 lukem if ( rdi != NULL && rdi->rdi_mask != SN_DG_OP_ALL ) { 382 1.1 lukem retcode_op_e o_tag = SN_DG_OP_NONE; 383 1.1 lukem 384 1.1 lukem switch ( op->o_tag ) { 385 1.1 lukem case LDAP_REQ_ADD: 386 1.1 lukem o_tag = SN_DG_OP_ADD; 387 1.1 lukem break; 388 1.1 lukem 389 1.1 lukem case LDAP_REQ_BIND: 390 1.1 lukem o_tag = SN_DG_OP_BIND; 391 1.1 lukem break; 392 1.1 lukem 393 1.1 lukem case LDAP_REQ_COMPARE: 394 1.1 lukem o_tag = SN_DG_OP_COMPARE; 395 1.1 lukem break; 396 1.1 lukem 397 1.1 lukem case LDAP_REQ_DELETE: 398 1.1 lukem o_tag = SN_DG_OP_DELETE; 399 1.1 lukem break; 400 1.1 lukem 401 1.1 lukem case LDAP_REQ_MODIFY: 402 1.1 lukem o_tag = SN_DG_OP_MODIFY; 403 1.1 lukem break; 404 1.1 lukem 405 1.1 lukem case LDAP_REQ_MODRDN: 406 1.1 lukem o_tag = SN_DG_OP_RENAME; 407 1.1 lukem break; 408 1.1 lukem 409 1.1 lukem case LDAP_REQ_SEARCH: 410 1.1 lukem o_tag = SN_DG_OP_SEARCH; 411 1.1 lukem break; 412 1.1 lukem 413 1.1 lukem case LDAP_REQ_EXTENDED: 414 1.1 lukem o_tag = SN_DG_EXTENDED; 415 1.1 lukem break; 416 1.1 lukem 417 1.1 lukem default: 418 1.1 lukem /* Should not happen */ 419 1.1 lukem break; 420 1.1 lukem } 421 1.1 lukem 422 1.1 lukem if ( !( o_tag & rdi->rdi_mask ) ) { 423 1.1 lukem return SLAP_CB_CONTINUE; 424 1.1 lukem } 425 1.1 lukem } 426 1.1 lukem 427 1.1 lukem if ( rdi == NULL ) { 428 1.1 lukem rs->sr_matched = rd->rd_pdn.bv_val; 429 1.1 lukem rs->sr_err = LDAP_NO_SUCH_OBJECT; 430 1.1 lukem rs->sr_text = "retcode not found"; 431 1.1 lukem 432 1.1 lukem } else { 433 1.1 lukem if ( rdi->rdi_flags & RDI_PRE_DISCONNECT ) { 434 1.1 lukem return rs->sr_err = SLAPD_DISCONNECT; 435 1.1 lukem } 436 1.1 lukem 437 1.1 lukem rs->sr_err = rdi->rdi_err; 438 1.1 lukem rs->sr_text = rdi->rdi_text.bv_val; 439 1.1 lukem rs->sr_matched = rdi->rdi_matched.bv_val; 440 1.1 lukem 441 1.1 lukem /* FIXME: we only honor the rdi_ref field in case rdi_err 442 1.1 lukem * is LDAP_REFERRAL otherwise send_ldap_result() bails out */ 443 1.1 lukem if ( rs->sr_err == LDAP_REFERRAL ) { 444 1.1 lukem BerVarray ref; 445 1.1 lukem 446 1.1 lukem if ( rdi->rdi_ref != NULL ) { 447 1.1 lukem ref = rdi->rdi_ref; 448 1.1 lukem } else { 449 1.1 lukem ref = default_referral; 450 1.1 lukem } 451 1.1 lukem 452 1.1 lukem if ( ref != NULL ) { 453 1.1 lukem rs->sr_ref = referral_rewrite( ref, 454 1.1 lukem NULL, &op->o_req_dn, LDAP_SCOPE_DEFAULT ); 455 1.1 lukem 456 1.1 lukem } else { 457 1.1 lukem rs->sr_err = LDAP_OTHER; 458 1.1 lukem rs->sr_text = "bad referral object"; 459 1.1 lukem } 460 1.1 lukem } 461 1.1 lukem 462 1.1 lukem retcode_sleep( rdi->rdi_sleeptime ); 463 1.1 lukem } 464 1.1 lukem 465 1.1 lukem switch ( op->o_tag ) { 466 1.1 lukem case LDAP_REQ_EXTENDED: 467 1.1 lukem if ( rdi == NULL ) { 468 1.1 lukem break; 469 1.1 lukem } 470 1.1 lukem cb = ( slap_callback * )ch_malloc( sizeof( slap_callback ) ); 471 1.1 lukem memset( cb, 0, sizeof( slap_callback ) ); 472 1.1 lukem cb->sc_cleanup = retcode_cleanup_cb; 473 1.1 lukem op->o_callback = cb; 474 1.1 lukem break; 475 1.1 lukem 476 1.1 lukem default: 477 1.1 lukem if ( rdi && !BER_BVISNULL( &rdi->rdi_unsolicited_oid ) ) { 478 1.1 lukem ber_int_t msgid = op->o_msgid; 479 1.1 lukem 480 1.1 lukem /* RFC 4511 unsolicited response */ 481 1.1 lukem 482 1.1 lukem op->o_msgid = 0; 483 1.1 lukem if ( strcmp( rdi->rdi_unsolicited_oid.bv_val, "0" ) == 0 ) { 484 1.1 lukem send_ldap_result( op, rs ); 485 1.1 lukem 486 1.1 lukem } else { 487 1.1 lukem ber_tag_t tag = op->o_tag; 488 1.1 lukem 489 1.1 lukem op->o_tag = LDAP_REQ_EXTENDED; 490 1.1 lukem rs->sr_rspoid = rdi->rdi_unsolicited_oid.bv_val; 491 1.1 lukem if ( !BER_BVISNULL( &rdi->rdi_unsolicited_data ) ) { 492 1.1 lukem rs->sr_rspdata = &rdi->rdi_unsolicited_data; 493 1.1 lukem } 494 1.1 lukem send_ldap_extended( op, rs ); 495 1.1 lukem rs->sr_rspoid = NULL; 496 1.1 lukem rs->sr_rspdata = NULL; 497 1.1 lukem op->o_tag = tag; 498 1.1 lukem 499 1.1 lukem } 500 1.1 lukem op->o_msgid = msgid; 501 1.1 lukem 502 1.1 lukem } else { 503 1.1 lukem send_ldap_result( op, rs ); 504 1.1 lukem } 505 1.1 lukem 506 1.1 lukem if ( rs->sr_ref != NULL ) { 507 1.1 lukem ber_bvarray_free( rs->sr_ref ); 508 1.1 lukem rs->sr_ref = NULL; 509 1.1 lukem } 510 1.1 lukem rs->sr_matched = NULL; 511 1.1 lukem rs->sr_text = NULL; 512 1.1 lukem 513 1.1 lukem if ( rdi && rdi->rdi_flags & RDI_POST_DISCONNECT ) { 514 1.1 lukem return rs->sr_err = SLAPD_DISCONNECT; 515 1.1 lukem } 516 1.1 lukem break; 517 1.1 lukem } 518 1.1 lukem 519 1.1 lukem return rs->sr_err; 520 1.1 lukem } 521 1.1 lukem 522 1.1 lukem static int 523 1.1 lukem retcode_op2str( ber_tag_t op, struct berval *bv ) 524 1.1 lukem { 525 1.1 lukem switch ( op ) { 526 1.1 lukem case LDAP_REQ_BIND: 527 1.1 lukem BER_BVSTR( bv, "bind" ); 528 1.1 lukem return 0; 529 1.1 lukem case LDAP_REQ_ADD: 530 1.1 lukem BER_BVSTR( bv, "add" ); 531 1.1 lukem return 0; 532 1.1 lukem case LDAP_REQ_DELETE: 533 1.1 lukem BER_BVSTR( bv, "delete" ); 534 1.1 lukem return 0; 535 1.1 lukem case LDAP_REQ_MODRDN: 536 1.1 lukem BER_BVSTR( bv, "modrdn" ); 537 1.1 lukem return 0; 538 1.1 lukem case LDAP_REQ_MODIFY: 539 1.1 lukem BER_BVSTR( bv, "modify" ); 540 1.1 lukem return 0; 541 1.1 lukem case LDAP_REQ_COMPARE: 542 1.1 lukem BER_BVSTR( bv, "compare" ); 543 1.1 lukem return 0; 544 1.1 lukem case LDAP_REQ_SEARCH: 545 1.1 lukem BER_BVSTR( bv, "search" ); 546 1.1 lukem return 0; 547 1.1 lukem case LDAP_REQ_EXTENDED: 548 1.1 lukem BER_BVSTR( bv, "extended" ); 549 1.1 lukem return 0; 550 1.1 lukem } 551 1.1 lukem return -1; 552 1.1 lukem } 553 1.1 lukem 554 1.1 lukem static int 555 1.1 lukem retcode_entry_response( Operation *op, SlapReply *rs, BackendInfo *bi, Entry *e ) 556 1.1 lukem { 557 1.1 lukem Attribute *a; 558 1.1 lukem int err; 559 1.1 lukem char *next; 560 1.1 lukem int disconnect = 0; 561 1.1 lukem 562 1.1 lukem if ( get_manageDSAit( op ) ) { 563 1.1 lukem return SLAP_CB_CONTINUE; 564 1.1 lukem } 565 1.1 lukem 566 1.1 lukem if ( !is_entry_objectclass_or_sub( e, oc_errAbsObject ) ) { 567 1.1 lukem return SLAP_CB_CONTINUE; 568 1.1 lukem } 569 1.1 lukem 570 1.1 lukem /* operation */ 571 1.1 lukem a = attr_find( e->e_attrs, ad_errOp ); 572 1.1 lukem if ( a != NULL ) { 573 1.1 lukem int i, 574 1.1 lukem gotit = 0; 575 1.1 lukem struct berval bv = BER_BVNULL; 576 1.1 lukem 577 1.1 lukem (void)retcode_op2str( op->o_tag, &bv ); 578 1.1 lukem 579 1.1 lukem if ( BER_BVISNULL( &bv ) ) { 580 1.1 lukem return SLAP_CB_CONTINUE; 581 1.1 lukem } 582 1.1 lukem 583 1.1 lukem for ( i = 0; !BER_BVISNULL( &a->a_nvals[ i ] ); i++ ) { 584 1.1 lukem if ( bvmatch( &a->a_nvals[ i ], &bv ) ) { 585 1.1 lukem gotit = 1; 586 1.1 lukem break; 587 1.1 lukem } 588 1.1 lukem } 589 1.1 lukem 590 1.1 lukem if ( !gotit ) { 591 1.1 lukem return SLAP_CB_CONTINUE; 592 1.1 lukem } 593 1.1 lukem } 594 1.1 lukem 595 1.1 lukem /* disconnect */ 596 1.1 lukem a = attr_find( e->e_attrs, ad_errDisconnect ); 597 1.1 lukem if ( a != NULL ) { 598 1.1 lukem if ( bvmatch( &a->a_nvals[ 0 ], &slap_true_bv ) ) { 599 1.1 lukem return rs->sr_err = SLAPD_DISCONNECT; 600 1.1 lukem } 601 1.1 lukem disconnect = 1; 602 1.1 lukem } 603 1.1 lukem 604 1.1 lukem /* error code */ 605 1.1 lukem a = attr_find( e->e_attrs, ad_errCode ); 606 1.1 lukem if ( a == NULL ) { 607 1.1 lukem return SLAP_CB_CONTINUE; 608 1.1 lukem } 609 1.1 lukem err = strtol( a->a_nvals[ 0 ].bv_val, &next, 0 ); 610 1.1 lukem if ( next == a->a_nvals[ 0 ].bv_val || next[ 0 ] != '\0' ) { 611 1.1 lukem return SLAP_CB_CONTINUE; 612 1.1 lukem } 613 1.1 lukem rs->sr_err = err; 614 1.1 lukem 615 1.1 lukem /* sleep time */ 616 1.1 lukem a = attr_find( e->e_attrs, ad_errSleepTime ); 617 1.1 lukem if ( a != NULL && a->a_nvals[ 0 ].bv_val[ 0 ] != '-' ) { 618 1.1 lukem int sleepTime; 619 1.1 lukem 620 1.1 lukem if ( lutil_atoi( &sleepTime, a->a_nvals[ 0 ].bv_val ) == 0 ) { 621 1.1 lukem retcode_sleep( sleepTime ); 622 1.1 lukem } 623 1.1 lukem } 624 1.1 lukem 625 1.1 lukem if ( rs->sr_err != LDAP_SUCCESS && !LDAP_API_ERROR( rs->sr_err )) { 626 1.1 lukem BackendDB db = *op->o_bd, 627 1.1 lukem *o_bd = op->o_bd; 628 1.1 lukem void *o_callback = op->o_callback; 629 1.1 lukem 630 1.1 lukem /* message text */ 631 1.1 lukem a = attr_find( e->e_attrs, ad_errText ); 632 1.1 lukem if ( a != NULL ) { 633 1.1 lukem rs->sr_text = a->a_vals[ 0 ].bv_val; 634 1.1 lukem } 635 1.1 lukem 636 1.1 lukem /* matched DN */ 637 1.1 lukem a = attr_find( e->e_attrs, ad_errMatchedDN ); 638 1.1 lukem if ( a != NULL ) { 639 1.1 lukem rs->sr_matched = a->a_vals[ 0 ].bv_val; 640 1.1 lukem } 641 1.1 lukem 642 1.1 lukem if ( bi == NULL ) { 643 1.1 lukem slap_overinst *on = (slap_overinst *)op->o_bd->bd_info; 644 1.1 lukem 645 1.1 lukem bi = on->on_info->oi_orig; 646 1.1 lukem } 647 1.1 lukem 648 1.1 lukem db.bd_info = bi; 649 1.1 lukem op->o_bd = &db; 650 1.1 lukem op->o_callback = NULL; 651 1.1 lukem 652 1.1 lukem /* referral */ 653 1.1 lukem if ( rs->sr_err == LDAP_REFERRAL ) { 654 1.1 lukem BerVarray refs = default_referral; 655 1.1 lukem 656 1.1 lukem a = attr_find( e->e_attrs, slap_schema.si_ad_ref ); 657 1.1 lukem if ( a != NULL ) { 658 1.1 lukem refs = a->a_vals; 659 1.1 lukem } 660 1.1 lukem rs->sr_ref = referral_rewrite( refs, 661 1.1 lukem NULL, &op->o_req_dn, op->oq_search.rs_scope ); 662 1.1 lukem 663 1.1 lukem send_search_reference( op, rs ); 664 1.1 lukem ber_bvarray_free( rs->sr_ref ); 665 1.1 lukem rs->sr_ref = NULL; 666 1.1 lukem 667 1.1 lukem } else { 668 1.1 lukem a = attr_find( e->e_attrs, ad_errUnsolicitedOID ); 669 1.1 lukem if ( a != NULL ) { 670 1.1 lukem struct berval oid = BER_BVNULL, 671 1.1 lukem data = BER_BVNULL; 672 1.1 lukem ber_int_t msgid = op->o_msgid; 673 1.1 lukem 674 1.1 lukem /* RFC 4511 unsolicited response */ 675 1.1 lukem 676 1.1 lukem op->o_msgid = 0; 677 1.1 lukem 678 1.1 lukem oid = a->a_nvals[ 0 ]; 679 1.1 lukem 680 1.1 lukem a = attr_find( e->e_attrs, ad_errUnsolicitedData ); 681 1.1 lukem if ( a != NULL ) { 682 1.1 lukem data = a->a_nvals[ 0 ]; 683 1.1 lukem } 684 1.1 lukem 685 1.1 lukem if ( strcmp( oid.bv_val, "0" ) == 0 ) { 686 1.1 lukem send_ldap_result( op, rs ); 687 1.1 lukem 688 1.1 lukem } else { 689 1.1 lukem ber_tag_t tag = op->o_tag; 690 1.1 lukem 691 1.1 lukem op->o_tag = LDAP_REQ_EXTENDED; 692 1.1 lukem rs->sr_rspoid = oid.bv_val; 693 1.1 lukem if ( !BER_BVISNULL( &data ) ) { 694 1.1 lukem rs->sr_rspdata = &data; 695 1.1 lukem } 696 1.1 lukem send_ldap_extended( op, rs ); 697 1.1 lukem rs->sr_rspoid = NULL; 698 1.1 lukem rs->sr_rspdata = NULL; 699 1.1 lukem op->o_tag = tag; 700 1.1 lukem } 701 1.1 lukem op->o_msgid = msgid; 702 1.1 lukem 703 1.1 lukem } else { 704 1.1 lukem send_ldap_result( op, rs ); 705 1.1 lukem } 706 1.1 lukem } 707 1.1 lukem 708 1.1 lukem rs->sr_text = NULL; 709 1.1 lukem rs->sr_matched = NULL; 710 1.1 lukem op->o_bd = o_bd; 711 1.1 lukem op->o_callback = o_callback; 712 1.1 lukem } 713 1.1 lukem 714 1.1 lukem if ( rs->sr_err != LDAP_SUCCESS ) { 715 1.1 lukem if ( disconnect ) { 716 1.1 lukem return rs->sr_err = SLAPD_DISCONNECT; 717 1.1 lukem } 718 1.1 lukem 719 1.1 lukem return rs->sr_err; 720 1.1 lukem } 721 1.1 lukem 722 1.1 lukem return SLAP_CB_CONTINUE; 723 1.1 lukem } 724 1.1 lukem 725 1.1 lukem static int 726 1.1 lukem retcode_response( Operation *op, SlapReply *rs ) 727 1.1 lukem { 728 1.1 lukem slap_overinst *on = (slap_overinst *)op->o_bd->bd_info; 729 1.1 lukem retcode_t *rd = (retcode_t *)on->on_bi.bi_private; 730 1.1 lukem 731 1.1 lukem if ( rs->sr_type != REP_SEARCH || !RETCODE_INDIR( rd ) ) { 732 1.1 lukem return SLAP_CB_CONTINUE; 733 1.1 lukem } 734 1.1 lukem 735 1.1 lukem return retcode_entry_response( op, rs, NULL, rs->sr_entry ); 736 1.1 lukem } 737 1.1 lukem 738 1.1 lukem static int 739 1.1 lukem retcode_db_init( BackendDB *be, ConfigReply *cr ) 740 1.1 lukem { 741 1.1 lukem slap_overinst *on = (slap_overinst *)be->bd_info; 742 1.1 lukem retcode_t *rd; 743 1.1 lukem 744 1.1 lukem srand( getpid() ); 745 1.1 lukem 746 1.1 lukem rd = (retcode_t *)ch_malloc( sizeof( retcode_t ) ); 747 1.1 lukem memset( rd, 0, sizeof( retcode_t ) ); 748 1.1 lukem 749 1.1 lukem on->on_bi.bi_private = (void *)rd; 750 1.1 lukem 751 1.1 lukem return 0; 752 1.1 lukem } 753 1.1 lukem 754 1.2 christos static void 755 1.2 christos retcode_item_destroy( retcode_item_t *rdi ) 756 1.2 christos { 757 1.2 christos ber_memfree( rdi->rdi_line.bv_val ); 758 1.2 christos 759 1.2 christos ber_memfree( rdi->rdi_dn.bv_val ); 760 1.2 christos ber_memfree( rdi->rdi_ndn.bv_val ); 761 1.2 christos 762 1.2 christos if ( !BER_BVISNULL( &rdi->rdi_text ) ) { 763 1.2 christos ber_memfree( rdi->rdi_text.bv_val ); 764 1.2 christos } 765 1.2 christos 766 1.2 christos if ( !BER_BVISNULL( &rdi->rdi_matched ) ) { 767 1.2 christos ber_memfree( rdi->rdi_matched.bv_val ); 768 1.2 christos } 769 1.2 christos 770 1.2 christos if ( rdi->rdi_ref ) { 771 1.2 christos ber_bvarray_free( rdi->rdi_ref ); 772 1.2 christos } 773 1.2 christos 774 1.2 christos BER_BVZERO( &rdi->rdi_e.e_name ); 775 1.2 christos BER_BVZERO( &rdi->rdi_e.e_nname ); 776 1.2 christos 777 1.2 christos entry_clean( &rdi->rdi_e ); 778 1.2 christos 779 1.2 christos if ( !BER_BVISNULL( &rdi->rdi_unsolicited_oid ) ) { 780 1.2 christos ber_memfree( rdi->rdi_unsolicited_oid.bv_val ); 781 1.2 christos if ( !BER_BVISNULL( &rdi->rdi_unsolicited_data ) ) 782 1.2 christos ber_memfree( rdi->rdi_unsolicited_data.bv_val ); 783 1.2 christos } 784 1.2 christos 785 1.2 christos ch_free( rdi ); 786 1.2 christos } 787 1.2 christos 788 1.2 christos enum { 789 1.2 christos RC_PARENT = 1, 790 1.2 christos RC_ITEM 791 1.2 christos }; 792 1.2 christos 793 1.2 christos static ConfigDriver rc_cf_gen; 794 1.2 christos 795 1.2 christos static ConfigTable rccfg[] = { 796 1.2 christos { "retcode-parent", "dn", 797 1.3 christos 2, 2, 0, ARG_MAGIC|ARG_DN|ARG_QUOTE|RC_PARENT, rc_cf_gen, 798 1.2 christos "( OLcfgOvAt:20.1 NAME 'olcRetcodeParent' " 799 1.2 christos "DESC '' " 800 1.3 christos "EQUALITY distinguishedNameMatch " 801 1.2 christos "SYNTAX OMsDN SINGLE-VALUE )", NULL, NULL }, 802 1.2 christos { "retcode-item", "rdn> <retcode> <...", 803 1.2 christos 3, 0, 0, ARG_MAGIC|RC_ITEM, rc_cf_gen, 804 1.2 christos "( OLcfgOvAt:20.2 NAME 'olcRetcodeItem' " 805 1.2 christos "DESC '' " 806 1.2 christos "EQUALITY caseIgnoreMatch " 807 1.2 christos "SYNTAX OMsDirectoryString " 808 1.2 christos "X-ORDERED 'VALUES' )", NULL, NULL }, 809 1.2 christos { "retcode-indir", "on|off", 810 1.2 christos 1, 2, 0, ARG_OFFSET|ARG_ON_OFF, 811 1.2 christos (void *)offsetof(retcode_t, rd_indir), 812 1.2 christos "( OLcfgOvAt:20.3 NAME 'olcRetcodeInDir' " 813 1.2 christos "DESC '' " 814 1.3 christos "EQUALITY booleanMatch " 815 1.2 christos "SYNTAX OMsBoolean SINGLE-VALUE )", NULL, NULL }, 816 1.2 christos 817 1.2 christos { "retcode-sleep", "sleeptime", 818 1.2 christos 2, 2, 0, ARG_OFFSET|ARG_INT, 819 1.2 christos (void *)offsetof(retcode_t, rd_sleep), 820 1.2 christos "( OLcfgOvAt:20.4 NAME 'olcRetcodeSleep' " 821 1.2 christos "DESC '' " 822 1.3 christos "EQUALITY integerMatch " 823 1.2 christos "SYNTAX OMsInteger SINGLE-VALUE )", NULL, NULL }, 824 1.2 christos 825 1.2 christos { NULL, NULL, 0, 0, 0, ARG_IGNORED } 826 1.2 christos }; 827 1.2 christos 828 1.2 christos static ConfigOCs rcocs[] = { 829 1.2 christos { "( OLcfgOvOc:20.1 " 830 1.2 christos "NAME 'olcRetcodeConfig' " 831 1.2 christos "DESC 'Retcode configuration' " 832 1.2 christos "SUP olcOverlayConfig " 833 1.2 christos "MAY ( olcRetcodeParent " 834 1.2 christos "$ olcRetcodeItem " 835 1.2 christos "$ olcRetcodeInDir " 836 1.2 christos "$ olcRetcodeSleep " 837 1.2 christos ") )", 838 1.2 christos Cft_Overlay, rccfg, NULL, NULL }, 839 1.2 christos { NULL, 0, NULL } 840 1.2 christos }; 841 1.2 christos 842 1.1 lukem static int 843 1.2 christos rc_cf_gen( ConfigArgs *c ) 844 1.1 lukem { 845 1.2 christos slap_overinst *on = (slap_overinst *)c->bi; 846 1.1 lukem retcode_t *rd = (retcode_t *)on->on_bi.bi_private; 847 1.2 christos int rc = ARG_BAD_CONF; 848 1.1 lukem 849 1.2 christos if ( c->op == SLAP_CONFIG_EMIT ) { 850 1.2 christos switch( c->type ) { 851 1.2 christos case RC_PARENT: 852 1.2 christos if ( !BER_BVISEMPTY( &rd->rd_pdn )) { 853 1.2 christos rc = value_add_one( &c->rvalue_vals, 854 1.2 christos &rd->rd_pdn ); 855 1.2 christos if ( rc == 0 ) { 856 1.2 christos rc = value_add_one( &c->rvalue_nvals, 857 1.2 christos &rd->rd_npdn ); 858 1.2 christos } 859 1.2 christos return rc; 860 1.2 christos } 861 1.2 christos rc = 0; 862 1.2 christos break; 863 1.2 christos 864 1.2 christos case RC_ITEM: { 865 1.2 christos retcode_item_t *rdi; 866 1.2 christos int i; 867 1.2 christos 868 1.2 christos for ( rdi = rd->rd_item, i = 0; rdi; rdi = rdi->rdi_next, i++ ) { 869 1.2 christos char buf[4096]; 870 1.2 christos struct berval bv; 871 1.2 christos char *ptr; 872 1.2 christos 873 1.2 christos bv.bv_len = snprintf( buf, sizeof( buf ), SLAP_X_ORDERED_FMT, i ); 874 1.2 christos bv.bv_len += rdi->rdi_line.bv_len; 875 1.2 christos ptr = bv.bv_val = ch_malloc( bv.bv_len + 1 ); 876 1.2 christos ptr = lutil_strcopy( ptr, buf ); 877 1.2 christos ptr = lutil_strncopy( ptr, rdi->rdi_line.bv_val, rdi->rdi_line.bv_len ); 878 1.2 christos ber_bvarray_add( &c->rvalue_vals, &bv ); 879 1.2 christos } 880 1.2 christos rc = 0; 881 1.2 christos } break; 882 1.2 christos 883 1.2 christos default: 884 1.2 christos assert( 0 ); 885 1.2 christos break; 886 1.2 christos } 887 1.2 christos 888 1.2 christos return rc; 889 1.1 lukem 890 1.2 christos } else if ( c->op == LDAP_MOD_DELETE ) { 891 1.2 christos switch( c->type ) { 892 1.2 christos case RC_PARENT: 893 1.2 christos if ( rd->rd_pdn.bv_val ) { 894 1.2 christos ber_memfree ( rd->rd_pdn.bv_val ); 895 1.2 christos rc = 0; 896 1.2 christos } 897 1.2 christos if ( rd->rd_npdn.bv_val ) { 898 1.2 christos ber_memfree ( rd->rd_npdn.bv_val ); 899 1.2 christos } 900 1.2 christos break; 901 1.2 christos 902 1.2 christos case RC_ITEM: 903 1.2 christos if ( c->valx == -1 ) { 904 1.2 christos retcode_item_t *rdi, *next; 905 1.2 christos 906 1.2 christos for ( rdi = rd->rd_item; rdi != NULL; rdi = next ) { 907 1.2 christos next = rdi->rdi_next; 908 1.2 christos retcode_item_destroy( rdi ); 909 1.2 christos } 910 1.2 christos 911 1.2 christos } else { 912 1.2 christos retcode_item_t **rdip, *rdi; 913 1.2 christos int i; 914 1.2 christos 915 1.2 christos for ( rdip = &rd->rd_item, i = 0; i <= c->valx && *rdip; i++, rdip = &(*rdip)->rdi_next ) 916 1.2 christos ; 917 1.2 christos if ( *rdip == NULL ) { 918 1.2 christos return 1; 919 1.2 christos } 920 1.2 christos rdi = *rdip; 921 1.2 christos *rdip = rdi->rdi_next; 922 1.1 lukem 923 1.2 christos retcode_item_destroy( rdi ); 924 1.2 christos } 925 1.2 christos rc = 0; 926 1.2 christos break; 927 1.1 lukem 928 1.2 christos default: 929 1.2 christos assert( 0 ); 930 1.2 christos break; 931 1.1 lukem } 932 1.2 christos return rc; /* FIXME */ 933 1.2 christos } 934 1.1 lukem 935 1.2 christos switch( c->type ) { 936 1.2 christos case RC_PARENT: 937 1.2 christos if ( rd->rd_pdn.bv_val ) { 938 1.2 christos ber_memfree ( rd->rd_pdn.bv_val ); 939 1.1 lukem } 940 1.2 christos if ( rd->rd_npdn.bv_val ) { 941 1.2 christos ber_memfree ( rd->rd_npdn.bv_val ); 942 1.1 lukem } 943 1.2 christos rd->rd_pdn = c->value_dn; 944 1.2 christos rd->rd_npdn = c->value_ndn; 945 1.2 christos rc = 0; 946 1.2 christos break; 947 1.1 lukem 948 1.2 christos case RC_ITEM: { 949 1.1 lukem retcode_item_t rdi = { BER_BVNULL }, **rdip; 950 1.1 lukem struct berval bv, rdn, nrdn; 951 1.1 lukem char *next = NULL; 952 1.2 christos int i; 953 1.1 lukem 954 1.2 christos if ( c->argc < 3 ) { 955 1.2 christos snprintf( c->cr_msg, sizeof(c->cr_msg), 956 1.1 lukem "\"retcode-item <RDN> <retcode> [<text>]\": " 957 1.2 christos "missing args" ); 958 1.2 christos Debug( LDAP_DEBUG_CONFIG, "%s: retcode: %s\n", 959 1.3 christos c->log, c->cr_msg ); 960 1.2 christos return ARG_BAD_CONF; 961 1.1 lukem } 962 1.1 lukem 963 1.2 christos ber_str2bv( c->argv[ 1 ], 0, 0, &bv ); 964 1.1 lukem 965 1.1 lukem rc = dnPrettyNormal( NULL, &bv, &rdn, &nrdn, NULL ); 966 1.1 lukem if ( rc != LDAP_SUCCESS ) { 967 1.2 christos snprintf( c->cr_msg, sizeof(c->cr_msg), 968 1.2 christos "unable to normalize RDN \"%s\": %d", 969 1.2 christos c->argv[ 1 ], rc ); 970 1.2 christos Debug( LDAP_DEBUG_CONFIG, "%s: retcode: %s\n", 971 1.3 christos c->log, c->cr_msg ); 972 1.2 christos return ARG_BAD_CONF; 973 1.1 lukem } 974 1.1 lukem 975 1.1 lukem if ( !dnIsOneLevelRDN( &nrdn ) ) { 976 1.2 christos snprintf( c->cr_msg, sizeof(c->cr_msg), 977 1.2 christos "value \"%s\" is not a RDN", 978 1.2 christos c->argv[ 1 ] ); 979 1.2 christos Debug( LDAP_DEBUG_CONFIG, "%s: retcode: %s\n", 980 1.3 christos c->log, c->cr_msg ); 981 1.2 christos return ARG_BAD_CONF; 982 1.1 lukem } 983 1.1 lukem 984 1.1 lukem if ( BER_BVISNULL( &rd->rd_npdn ) ) { 985 1.1 lukem /* FIXME: we use the database suffix */ 986 1.2 christos if ( c->be->be_nsuffix == NULL ) { 987 1.2 christos snprintf( c->cr_msg, sizeof(c->cr_msg), 988 1.1 lukem "either \"retcode-parent\" " 989 1.2 christos "or \"suffix\" must be defined" ); 990 1.2 christos Debug( LDAP_DEBUG_CONFIG, "%s: retcode: %s\n", 991 1.3 christos c->log, c->cr_msg ); 992 1.2 christos return ARG_BAD_CONF; 993 1.1 lukem } 994 1.1 lukem 995 1.2 christos ber_dupbv( &rd->rd_pdn, &c->be->be_suffix[ 0 ] ); 996 1.2 christos ber_dupbv( &rd->rd_npdn, &c->be->be_nsuffix[ 0 ] ); 997 1.1 lukem } 998 1.1 lukem 999 1.1 lukem build_new_dn( &rdi.rdi_dn, &rd->rd_pdn, &rdn, NULL ); 1000 1.1 lukem build_new_dn( &rdi.rdi_ndn, &rd->rd_npdn, &nrdn, NULL ); 1001 1.1 lukem 1002 1.1 lukem ch_free( rdn.bv_val ); 1003 1.1 lukem ch_free( nrdn.bv_val ); 1004 1.1 lukem 1005 1.2 christos rdi.rdi_err = strtol( c->argv[ 2 ], &next, 0 ); 1006 1.2 christos if ( next == c->argv[ 2 ] || next[ 0 ] != '\0' ) { 1007 1.2 christos snprintf( c->cr_msg, sizeof(c->cr_msg), 1008 1.2 christos "unable to parse return code \"%s\"", 1009 1.2 christos c->argv[ 2 ] ); 1010 1.2 christos Debug( LDAP_DEBUG_CONFIG, "%s: retcode: %s\n", 1011 1.3 christos c->log, c->cr_msg ); 1012 1.2 christos return ARG_BAD_CONF; 1013 1.1 lukem } 1014 1.1 lukem 1015 1.1 lukem rdi.rdi_mask = SN_DG_OP_ALL; 1016 1.1 lukem 1017 1.2 christos if ( c->argc > 3 ) { 1018 1.2 christos for ( i = 3; i < c->argc; i++ ) { 1019 1.2 christos if ( strncasecmp( c->argv[ i ], "op=", STRLENOF( "op=" ) ) == 0 ) 1020 1.1 lukem { 1021 1.1 lukem char **ops; 1022 1.1 lukem int j; 1023 1.1 lukem 1024 1.2 christos ops = ldap_str2charray( &c->argv[ i ][ STRLENOF( "op=" ) ], "," ); 1025 1.1 lukem assert( ops != NULL ); 1026 1.1 lukem 1027 1.1 lukem rdi.rdi_mask = SN_DG_OP_NONE; 1028 1.1 lukem 1029 1.1 lukem for ( j = 0; ops[ j ] != NULL; j++ ) { 1030 1.1 lukem if ( strcasecmp( ops[ j ], "add" ) == 0 ) { 1031 1.1 lukem rdi.rdi_mask |= SN_DG_OP_ADD; 1032 1.1 lukem 1033 1.1 lukem } else if ( strcasecmp( ops[ j ], "bind" ) == 0 ) { 1034 1.1 lukem rdi.rdi_mask |= SN_DG_OP_BIND; 1035 1.1 lukem 1036 1.1 lukem } else if ( strcasecmp( ops[ j ], "compare" ) == 0 ) { 1037 1.1 lukem rdi.rdi_mask |= SN_DG_OP_COMPARE; 1038 1.1 lukem 1039 1.1 lukem } else if ( strcasecmp( ops[ j ], "delete" ) == 0 ) { 1040 1.1 lukem rdi.rdi_mask |= SN_DG_OP_DELETE; 1041 1.1 lukem 1042 1.1 lukem } else if ( strcasecmp( ops[ j ], "modify" ) == 0 ) { 1043 1.1 lukem rdi.rdi_mask |= SN_DG_OP_MODIFY; 1044 1.1 lukem 1045 1.1 lukem } else if ( strcasecmp( ops[ j ], "rename" ) == 0 1046 1.1 lukem || strcasecmp( ops[ j ], "modrdn" ) == 0 ) 1047 1.1 lukem { 1048 1.1 lukem rdi.rdi_mask |= SN_DG_OP_RENAME; 1049 1.1 lukem 1050 1.1 lukem } else if ( strcasecmp( ops[ j ], "search" ) == 0 ) { 1051 1.1 lukem rdi.rdi_mask |= SN_DG_OP_SEARCH; 1052 1.1 lukem 1053 1.1 lukem } else if ( strcasecmp( ops[ j ], "extended" ) == 0 ) { 1054 1.1 lukem rdi.rdi_mask |= SN_DG_EXTENDED; 1055 1.1 lukem 1056 1.1 lukem } else if ( strcasecmp( ops[ j ], "auth" ) == 0 ) { 1057 1.1 lukem rdi.rdi_mask |= SN_DG_OP_AUTH; 1058 1.1 lukem 1059 1.1 lukem } else if ( strcasecmp( ops[ j ], "read" ) == 0 ) { 1060 1.1 lukem rdi.rdi_mask |= SN_DG_OP_READ; 1061 1.1 lukem 1062 1.1 lukem } else if ( strcasecmp( ops[ j ], "write" ) == 0 ) { 1063 1.1 lukem rdi.rdi_mask |= SN_DG_OP_WRITE; 1064 1.1 lukem 1065 1.1 lukem } else if ( strcasecmp( ops[ j ], "all" ) == 0 ) { 1066 1.1 lukem rdi.rdi_mask |= SN_DG_OP_ALL; 1067 1.1 lukem 1068 1.1 lukem } else { 1069 1.2 christos snprintf( c->cr_msg, sizeof(c->cr_msg), 1070 1.2 christos "unknown op \"%s\"", 1071 1.1 lukem ops[ j ] ); 1072 1.1 lukem ldap_charray_free( ops ); 1073 1.2 christos Debug( LDAP_DEBUG_CONFIG, "%s: retcode: %s\n", 1074 1.3 christos c->log, c->cr_msg ); 1075 1.2 christos return ARG_BAD_CONF; 1076 1.1 lukem } 1077 1.1 lukem } 1078 1.1 lukem 1079 1.1 lukem ldap_charray_free( ops ); 1080 1.1 lukem 1081 1.2 christos } else if ( strncasecmp( c->argv[ i ], "text=", STRLENOF( "text=" ) ) == 0 ) 1082 1.1 lukem { 1083 1.1 lukem if ( !BER_BVISNULL( &rdi.rdi_text ) ) { 1084 1.2 christos snprintf( c->cr_msg, sizeof(c->cr_msg), 1085 1.2 christos "\"text\" already provided" ); 1086 1.2 christos Debug( LDAP_DEBUG_CONFIG, "%s: retcode: %s\n", 1087 1.3 christos c->log, c->cr_msg ); 1088 1.2 christos return ARG_BAD_CONF; 1089 1.1 lukem } 1090 1.2 christos ber_str2bv( &c->argv[ i ][ STRLENOF( "text=" ) ], 0, 1, &rdi.rdi_text ); 1091 1.1 lukem 1092 1.2 christos } else if ( strncasecmp( c->argv[ i ], "matched=", STRLENOF( "matched=" ) ) == 0 ) 1093 1.1 lukem { 1094 1.1 lukem struct berval dn; 1095 1.1 lukem 1096 1.1 lukem if ( !BER_BVISNULL( &rdi.rdi_matched ) ) { 1097 1.2 christos snprintf( c->cr_msg, sizeof(c->cr_msg), 1098 1.2 christos "\"matched\" already provided" ); 1099 1.2 christos Debug( LDAP_DEBUG_CONFIG, "%s: retcode: %s\n", 1100 1.3 christos c->log, c->cr_msg ); 1101 1.2 christos return ARG_BAD_CONF; 1102 1.1 lukem } 1103 1.2 christos ber_str2bv( &c->argv[ i ][ STRLENOF( "matched=" ) ], 0, 0, &dn ); 1104 1.1 lukem if ( dnPretty( NULL, &dn, &rdi.rdi_matched, NULL ) != LDAP_SUCCESS ) { 1105 1.2 christos snprintf( c->cr_msg, sizeof(c->cr_msg), 1106 1.2 christos "unable to prettify matched DN \"%s\"", 1107 1.2 christos &c->argv[ i ][ STRLENOF( "matched=" ) ] ); 1108 1.2 christos Debug( LDAP_DEBUG_CONFIG, "%s: retcode: %s\n", 1109 1.3 christos c->log, c->cr_msg ); 1110 1.2 christos return ARG_BAD_CONF; 1111 1.1 lukem } 1112 1.1 lukem 1113 1.2 christos } else if ( strncasecmp( c->argv[ i ], "ref=", STRLENOF( "ref=" ) ) == 0 ) 1114 1.1 lukem { 1115 1.1 lukem char **refs; 1116 1.1 lukem int j; 1117 1.1 lukem 1118 1.1 lukem if ( rdi.rdi_ref != NULL ) { 1119 1.2 christos snprintf( c->cr_msg, sizeof(c->cr_msg), 1120 1.2 christos "\"ref\" already provided" ); 1121 1.2 christos Debug( LDAP_DEBUG_CONFIG, "%s: retcode: %s\n", 1122 1.3 christos c->log, c->cr_msg ); 1123 1.2 christos return ARG_BAD_CONF; 1124 1.1 lukem } 1125 1.1 lukem 1126 1.1 lukem if ( rdi.rdi_err != LDAP_REFERRAL ) { 1127 1.2 christos snprintf( c->cr_msg, sizeof(c->cr_msg), 1128 1.2 christos "providing \"ref\" " 1129 1.2 christos "along with a non-referral " 1130 1.2 christos "resultCode may cause slapd failures " 1131 1.2 christos "related to internal checks" ); 1132 1.2 christos Debug( LDAP_DEBUG_CONFIG, "%s: retcode: %s\n", 1133 1.3 christos c->log, c->cr_msg ); 1134 1.1 lukem } 1135 1.1 lukem 1136 1.2 christos refs = ldap_str2charray( &c->argv[ i ][ STRLENOF( "ref=" ) ], " " ); 1137 1.1 lukem assert( refs != NULL ); 1138 1.1 lukem 1139 1.1 lukem for ( j = 0; refs[ j ] != NULL; j++ ) { 1140 1.1 lukem struct berval bv; 1141 1.1 lukem 1142 1.1 lukem ber_str2bv( refs[ j ], 0, 1, &bv ); 1143 1.1 lukem ber_bvarray_add( &rdi.rdi_ref, &bv ); 1144 1.1 lukem } 1145 1.1 lukem 1146 1.1 lukem ldap_charray_free( refs ); 1147 1.1 lukem 1148 1.2 christos } else if ( strncasecmp( c->argv[ i ], "sleeptime=", STRLENOF( "sleeptime=" ) ) == 0 ) 1149 1.1 lukem { 1150 1.1 lukem if ( rdi.rdi_sleeptime != 0 ) { 1151 1.2 christos snprintf( c->cr_msg, sizeof(c->cr_msg), 1152 1.2 christos "\"sleeptime\" already provided" ); 1153 1.2 christos Debug( LDAP_DEBUG_CONFIG, "%s: retcode: %s\n", 1154 1.3 christos c->log, c->cr_msg ); 1155 1.2 christos return ARG_BAD_CONF; 1156 1.1 lukem } 1157 1.1 lukem 1158 1.2 christos if ( lutil_atoi( &rdi.rdi_sleeptime, &c->argv[ i ][ STRLENOF( "sleeptime=" ) ] ) ) { 1159 1.2 christos snprintf( c->cr_msg, sizeof(c->cr_msg), 1160 1.2 christos "unable to parse \"sleeptime=%s\"", 1161 1.2 christos &c->argv[ i ][ STRLENOF( "sleeptime=" ) ] ); 1162 1.2 christos Debug( LDAP_DEBUG_CONFIG, "%s: retcode: %s\n", 1163 1.3 christos c->log, c->cr_msg ); 1164 1.2 christos return ARG_BAD_CONF; 1165 1.1 lukem } 1166 1.1 lukem 1167 1.2 christos } else if ( strncasecmp( c->argv[ i ], "unsolicited=", STRLENOF( "unsolicited=" ) ) == 0 ) 1168 1.1 lukem { 1169 1.1 lukem char *data; 1170 1.1 lukem 1171 1.1 lukem if ( !BER_BVISNULL( &rdi.rdi_unsolicited_oid ) ) { 1172 1.2 christos snprintf( c->cr_msg, sizeof(c->cr_msg), 1173 1.2 christos "\"unsolicited\" already provided" ); 1174 1.2 christos Debug( LDAP_DEBUG_CONFIG, "%s: retcode: %s\n", 1175 1.3 christos c->log, c->cr_msg ); 1176 1.2 christos return ARG_BAD_CONF; 1177 1.1 lukem } 1178 1.1 lukem 1179 1.2 christos data = strchr( &c->argv[ i ][ STRLENOF( "unsolicited=" ) ], ':' ); 1180 1.1 lukem if ( data != NULL ) { 1181 1.1 lukem struct berval oid; 1182 1.1 lukem 1183 1.2 christos if ( ldif_parse_line2( &c->argv[ i ][ STRLENOF( "unsolicited=" ) ], 1184 1.1 lukem &oid, &rdi.rdi_unsolicited_data, NULL ) ) 1185 1.1 lukem { 1186 1.2 christos snprintf( c->cr_msg, sizeof(c->cr_msg), 1187 1.2 christos "unable to parse \"unsolicited\"" ); 1188 1.2 christos Debug( LDAP_DEBUG_CONFIG, "%s: retcode: %s\n", 1189 1.3 christos c->log, c->cr_msg ); 1190 1.2 christos return ARG_BAD_CONF; 1191 1.1 lukem } 1192 1.1 lukem 1193 1.1 lukem ber_dupbv( &rdi.rdi_unsolicited_oid, &oid ); 1194 1.1 lukem 1195 1.1 lukem } else { 1196 1.2 christos ber_str2bv( &c->argv[ i ][ STRLENOF( "unsolicited=" ) ], 0, 1, 1197 1.1 lukem &rdi.rdi_unsolicited_oid ); 1198 1.1 lukem } 1199 1.1 lukem 1200 1.2 christos } else if ( strncasecmp( c->argv[ i ], "flags=", STRLENOF( "flags=" ) ) == 0 ) 1201 1.1 lukem { 1202 1.2 christos char *arg = &c->argv[ i ][ STRLENOF( "flags=" ) ]; 1203 1.1 lukem if ( strcasecmp( arg, "disconnect" ) == 0 ) { 1204 1.1 lukem rdi.rdi_flags |= RDI_PRE_DISCONNECT; 1205 1.1 lukem 1206 1.1 lukem } else if ( strcasecmp( arg, "pre-disconnect" ) == 0 ) { 1207 1.1 lukem rdi.rdi_flags |= RDI_PRE_DISCONNECT; 1208 1.1 lukem 1209 1.1 lukem } else if ( strcasecmp( arg, "post-disconnect" ) == 0 ) { 1210 1.1 lukem rdi.rdi_flags |= RDI_POST_DISCONNECT; 1211 1.1 lukem 1212 1.1 lukem } else { 1213 1.2 christos snprintf( c->cr_msg, sizeof(c->cr_msg), 1214 1.2 christos "unknown flag \"%s\"", arg ); 1215 1.2 christos Debug( LDAP_DEBUG_CONFIG, "%s: retcode: %s\n", 1216 1.3 christos c->log, c->cr_msg ); 1217 1.2 christos return ARG_BAD_CONF; 1218 1.1 lukem } 1219 1.1 lukem 1220 1.1 lukem } else { 1221 1.2 christos snprintf( c->cr_msg, sizeof(c->cr_msg), 1222 1.2 christos "unknown option \"%s\"", 1223 1.2 christos c->argv[ i ] ); 1224 1.2 christos Debug( LDAP_DEBUG_CONFIG, "%s: retcode: %s\n", 1225 1.3 christos c->log, c->cr_msg ); 1226 1.2 christos return ARG_BAD_CONF; 1227 1.1 lukem } 1228 1.1 lukem } 1229 1.1 lukem } 1230 1.1 lukem 1231 1.2 christos rdi.rdi_line.bv_len = 2*(c->argc - 1) + c->argc - 2; 1232 1.2 christos for ( i = 1; i < c->argc; i++ ) { 1233 1.2 christos rdi.rdi_line.bv_len += strlen( c->argv[ i ] ); 1234 1.2 christos } 1235 1.2 christos next = rdi.rdi_line.bv_val = ch_malloc( rdi.rdi_line.bv_len + 1 ); 1236 1.2 christos 1237 1.2 christos for ( i = 1; i < c->argc; i++ ) { 1238 1.2 christos *next++ = '"'; 1239 1.2 christos next = lutil_strcopy( next, c->argv[ i ] ); 1240 1.2 christos *next++ = '"'; 1241 1.2 christos *next++ = ' '; 1242 1.2 christos } 1243 1.2 christos *--next = '\0'; 1244 1.2 christos 1245 1.4 christos /* We're marked X-ORDERED 'VALUES', valx might be valid */ 1246 1.4 christos for ( i = 0, rdip = &rd->rd_item; 1247 1.4 christos *rdip && (c->valx < 0 || i < c->valx); 1248 1.4 christos rdip = &(*rdip)->rdi_next, i++ ) 1249 1.4 christos /* go to position */ ; 1250 1.1 lukem 1251 1.1 lukem 1252 1.4 christos rdi.rdi_next = *rdip; 1253 1.1 lukem *rdip = ( retcode_item_t * )ch_malloc( sizeof( retcode_item_t ) ); 1254 1.1 lukem *(*rdip) = rdi; 1255 1.1 lukem 1256 1.2 christos rc = 0; 1257 1.2 christos } break; 1258 1.1 lukem 1259 1.2 christos default: 1260 1.2 christos rc = SLAP_CONF_UNKNOWN; 1261 1.2 christos break; 1262 1.1 lukem } 1263 1.1 lukem 1264 1.2 christos return rc; 1265 1.1 lukem } 1266 1.1 lukem 1267 1.1 lukem static int 1268 1.1 lukem retcode_db_open( BackendDB *be, ConfigReply *cr) 1269 1.1 lukem { 1270 1.1 lukem slap_overinst *on = (slap_overinst *)be->bd_info; 1271 1.1 lukem retcode_t *rd = (retcode_t *)on->on_bi.bi_private; 1272 1.1 lukem 1273 1.1 lukem retcode_item_t *rdi; 1274 1.1 lukem 1275 1.1 lukem for ( rdi = rd->rd_item; rdi; rdi = rdi->rdi_next ) { 1276 1.1 lukem LDAPRDN rdn = NULL; 1277 1.1 lukem int rc, j; 1278 1.1 lukem char* p; 1279 1.1 lukem struct berval val[ 3 ]; 1280 1.1 lukem char buf[ SLAP_TEXT_BUFLEN ]; 1281 1.1 lukem 1282 1.1 lukem /* DN */ 1283 1.1 lukem rdi->rdi_e.e_name = rdi->rdi_dn; 1284 1.1 lukem rdi->rdi_e.e_nname = rdi->rdi_ndn; 1285 1.1 lukem 1286 1.1 lukem /* objectClass */ 1287 1.1 lukem val[ 0 ] = oc_errObject->soc_cname; 1288 1.1 lukem val[ 1 ] = slap_schema.si_oc_extensibleObject->soc_cname; 1289 1.1 lukem BER_BVZERO( &val[ 2 ] ); 1290 1.1 lukem 1291 1.1 lukem attr_merge( &rdi->rdi_e, slap_schema.si_ad_objectClass, val, NULL ); 1292 1.1 lukem 1293 1.1 lukem /* RDN avas */ 1294 1.1 lukem rc = ldap_bv2rdn( &rdi->rdi_dn, &rdn, (char **) &p, 1295 1.1 lukem LDAP_DN_FORMAT_LDAP ); 1296 1.1 lukem 1297 1.1 lukem assert( rc == LDAP_SUCCESS ); 1298 1.1 lukem 1299 1.1 lukem for ( j = 0; rdn[ j ]; j++ ) { 1300 1.1 lukem LDAPAVA *ava = rdn[ j ]; 1301 1.1 lukem AttributeDescription *ad = NULL; 1302 1.1 lukem const char *text; 1303 1.1 lukem 1304 1.1 lukem rc = slap_bv2ad( &ava->la_attr, &ad, &text ); 1305 1.1 lukem assert( rc == LDAP_SUCCESS ); 1306 1.1 lukem 1307 1.1 lukem attr_merge_normalize_one( &rdi->rdi_e, ad, 1308 1.1 lukem &ava->la_value, NULL ); 1309 1.1 lukem } 1310 1.1 lukem 1311 1.1 lukem ldap_rdnfree( rdn ); 1312 1.1 lukem 1313 1.1 lukem /* error code */ 1314 1.1 lukem snprintf( buf, sizeof( buf ), "%d", rdi->rdi_err ); 1315 1.1 lukem ber_str2bv( buf, 0, 0, &val[ 0 ] ); 1316 1.1 lukem 1317 1.1 lukem attr_merge_one( &rdi->rdi_e, ad_errCode, &val[ 0 ], NULL ); 1318 1.1 lukem 1319 1.1 lukem if ( rdi->rdi_ref != NULL ) { 1320 1.1 lukem attr_merge_normalize( &rdi->rdi_e, slap_schema.si_ad_ref, 1321 1.1 lukem rdi->rdi_ref, NULL ); 1322 1.1 lukem } 1323 1.1 lukem 1324 1.1 lukem /* text */ 1325 1.1 lukem if ( !BER_BVISNULL( &rdi->rdi_text ) ) { 1326 1.1 lukem val[ 0 ] = rdi->rdi_text; 1327 1.1 lukem 1328 1.1 lukem attr_merge_normalize_one( &rdi->rdi_e, ad_errText, &val[ 0 ], NULL ); 1329 1.1 lukem } 1330 1.1 lukem 1331 1.1 lukem /* matched */ 1332 1.1 lukem if ( !BER_BVISNULL( &rdi->rdi_matched ) ) { 1333 1.1 lukem val[ 0 ] = rdi->rdi_matched; 1334 1.1 lukem 1335 1.1 lukem attr_merge_normalize_one( &rdi->rdi_e, ad_errMatchedDN, &val[ 0 ], NULL ); 1336 1.1 lukem } 1337 1.1 lukem 1338 1.1 lukem /* sleep time */ 1339 1.1 lukem if ( rdi->rdi_sleeptime ) { 1340 1.1 lukem snprintf( buf, sizeof( buf ), "%d", rdi->rdi_sleeptime ); 1341 1.1 lukem ber_str2bv( buf, 0, 0, &val[ 0 ] ); 1342 1.1 lukem 1343 1.1 lukem attr_merge_one( &rdi->rdi_e, ad_errSleepTime, &val[ 0 ], NULL ); 1344 1.1 lukem } 1345 1.1 lukem 1346 1.1 lukem /* operations */ 1347 1.1 lukem if ( rdi->rdi_mask & SN_DG_OP_ADD ) { 1348 1.1 lukem BER_BVSTR( &val[ 0 ], "add" ); 1349 1.1 lukem attr_merge_normalize_one( &rdi->rdi_e, ad_errOp, &val[ 0 ], NULL ); 1350 1.1 lukem } 1351 1.1 lukem 1352 1.1 lukem if ( rdi->rdi_mask & SN_DG_OP_BIND ) { 1353 1.1 lukem BER_BVSTR( &val[ 0 ], "bind" ); 1354 1.1 lukem attr_merge_normalize_one( &rdi->rdi_e, ad_errOp, &val[ 0 ], NULL ); 1355 1.1 lukem } 1356 1.1 lukem 1357 1.1 lukem if ( rdi->rdi_mask & SN_DG_OP_COMPARE ) { 1358 1.1 lukem BER_BVSTR( &val[ 0 ], "compare" ); 1359 1.1 lukem attr_merge_normalize_one( &rdi->rdi_e, ad_errOp, &val[ 0 ], NULL ); 1360 1.1 lukem } 1361 1.1 lukem 1362 1.1 lukem if ( rdi->rdi_mask & SN_DG_OP_DELETE ) { 1363 1.1 lukem BER_BVSTR( &val[ 0 ], "delete" ); 1364 1.1 lukem attr_merge_normalize_one( &rdi->rdi_e, ad_errOp, &val[ 0 ], NULL ); 1365 1.1 lukem } 1366 1.1 lukem 1367 1.1 lukem if ( rdi->rdi_mask & SN_DG_EXTENDED ) { 1368 1.1 lukem BER_BVSTR( &val[ 0 ], "extended" ); 1369 1.1 lukem attr_merge_normalize_one( &rdi->rdi_e, ad_errOp, &val[ 0 ], NULL ); 1370 1.1 lukem } 1371 1.1 lukem 1372 1.1 lukem if ( rdi->rdi_mask & SN_DG_OP_MODIFY ) { 1373 1.1 lukem BER_BVSTR( &val[ 0 ], "modify" ); 1374 1.1 lukem attr_merge_normalize_one( &rdi->rdi_e, ad_errOp, &val[ 0 ], NULL ); 1375 1.1 lukem } 1376 1.1 lukem 1377 1.1 lukem if ( rdi->rdi_mask & SN_DG_OP_RENAME ) { 1378 1.1 lukem BER_BVSTR( &val[ 0 ], "rename" ); 1379 1.1 lukem attr_merge_normalize_one( &rdi->rdi_e, ad_errOp, &val[ 0 ], NULL ); 1380 1.1 lukem } 1381 1.1 lukem 1382 1.1 lukem if ( rdi->rdi_mask & SN_DG_OP_SEARCH ) { 1383 1.1 lukem BER_BVSTR( &val[ 0 ], "search" ); 1384 1.1 lukem attr_merge_normalize_one( &rdi->rdi_e, ad_errOp, &val[ 0 ], NULL ); 1385 1.1 lukem } 1386 1.1 lukem } 1387 1.1 lukem 1388 1.1 lukem return 0; 1389 1.1 lukem } 1390 1.1 lukem 1391 1.1 lukem static int 1392 1.1 lukem retcode_db_destroy( BackendDB *be, ConfigReply *cr ) 1393 1.1 lukem { 1394 1.1 lukem slap_overinst *on = (slap_overinst *)be->bd_info; 1395 1.1 lukem retcode_t *rd = (retcode_t *)on->on_bi.bi_private; 1396 1.1 lukem 1397 1.1 lukem if ( rd ) { 1398 1.1 lukem retcode_item_t *rdi, *next; 1399 1.1 lukem 1400 1.1 lukem for ( rdi = rd->rd_item; rdi != NULL; rdi = next ) { 1401 1.1 lukem next = rdi->rdi_next; 1402 1.2 christos retcode_item_destroy( rdi ); 1403 1.1 lukem } 1404 1.1 lukem 1405 1.1 lukem if ( !BER_BVISNULL( &rd->rd_pdn ) ) { 1406 1.1 lukem ber_memfree( rd->rd_pdn.bv_val ); 1407 1.1 lukem } 1408 1.1 lukem 1409 1.1 lukem if ( !BER_BVISNULL( &rd->rd_npdn ) ) { 1410 1.1 lukem ber_memfree( rd->rd_npdn.bv_val ); 1411 1.1 lukem } 1412 1.1 lukem 1413 1.1 lukem ber_memfree( rd ); 1414 1.1 lukem } 1415 1.1 lukem 1416 1.1 lukem return 0; 1417 1.1 lukem } 1418 1.1 lukem 1419 1.1 lukem #if SLAPD_OVER_RETCODE == SLAPD_MOD_DYNAMIC 1420 1.1 lukem static 1421 1.1 lukem #endif /* SLAPD_OVER_RETCODE == SLAPD_MOD_DYNAMIC */ 1422 1.1 lukem int 1423 1.1 lukem retcode_initialize( void ) 1424 1.1 lukem { 1425 1.1 lukem int i, code; 1426 1.1 lukem 1427 1.1 lukem static struct { 1428 1.1 lukem char *desc; 1429 1.1 lukem AttributeDescription **ad; 1430 1.1 lukem } retcode_at[] = { 1431 1.1 lukem { "( 1.3.6.1.4.1.4203.666.11.4.1.1 " 1432 1.1 lukem "NAME ( 'errCode' ) " 1433 1.1 lukem "DESC 'LDAP error code' " 1434 1.1 lukem "EQUALITY integerMatch " 1435 1.1 lukem "ORDERING integerOrderingMatch " 1436 1.1 lukem "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 " 1437 1.1 lukem "SINGLE-VALUE )", 1438 1.1 lukem &ad_errCode }, 1439 1.1 lukem { "( 1.3.6.1.4.1.4203.666.11.4.1.2 " 1440 1.1 lukem "NAME ( 'errOp' ) " 1441 1.1 lukem "DESC 'Operations the errObject applies to' " 1442 1.1 lukem "EQUALITY caseIgnoreMatch " 1443 1.1 lukem "SUBSTR caseIgnoreSubstringsMatch " 1444 1.1 lukem "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )", 1445 1.1 lukem &ad_errOp}, 1446 1.1 lukem { "( 1.3.6.1.4.1.4203.666.11.4.1.3 " 1447 1.1 lukem "NAME ( 'errText' ) " 1448 1.1 lukem "DESC 'LDAP error textual description' " 1449 1.1 lukem "EQUALITY caseIgnoreMatch " 1450 1.1 lukem "SUBSTR caseIgnoreSubstringsMatch " 1451 1.1 lukem "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 " 1452 1.1 lukem "SINGLE-VALUE )", 1453 1.1 lukem &ad_errText }, 1454 1.1 lukem { "( 1.3.6.1.4.1.4203.666.11.4.1.4 " 1455 1.1 lukem "NAME ( 'errSleepTime' ) " 1456 1.1 lukem "DESC 'Time to wait before returning the error' " 1457 1.1 lukem "EQUALITY integerMatch " 1458 1.1 lukem "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 " 1459 1.1 lukem "SINGLE-VALUE )", 1460 1.1 lukem &ad_errSleepTime }, 1461 1.1 lukem { "( 1.3.6.1.4.1.4203.666.11.4.1.5 " 1462 1.1 lukem "NAME ( 'errMatchedDN' ) " 1463 1.1 lukem "DESC 'Value to be returned as matched DN' " 1464 1.1 lukem "EQUALITY distinguishedNameMatch " 1465 1.1 lukem "SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 " 1466 1.1 lukem "SINGLE-VALUE )", 1467 1.1 lukem &ad_errMatchedDN }, 1468 1.1 lukem { "( 1.3.6.1.4.1.4203.666.11.4.1.6 " 1469 1.1 lukem "NAME ( 'errUnsolicitedOID' ) " 1470 1.1 lukem "DESC 'OID to be returned within unsolicited response' " 1471 1.1 lukem "EQUALITY objectIdentifierMatch " 1472 1.1 lukem "SYNTAX 1.3.6.1.4.1.1466.115.121.1.38 " 1473 1.1 lukem "SINGLE-VALUE )", 1474 1.1 lukem &ad_errUnsolicitedOID }, 1475 1.1 lukem { "( 1.3.6.1.4.1.4203.666.11.4.1.7 " 1476 1.1 lukem "NAME ( 'errUnsolicitedData' ) " 1477 1.1 lukem "DESC 'Data to be returned within unsolicited response' " 1478 1.1 lukem "SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 " 1479 1.1 lukem "SINGLE-VALUE )", 1480 1.1 lukem &ad_errUnsolicitedData }, 1481 1.1 lukem { "( 1.3.6.1.4.1.4203.666.11.4.1.8 " 1482 1.1 lukem "NAME ( 'errDisconnect' ) " 1483 1.1 lukem "DESC 'Disconnect without notice' " 1484 1.1 lukem "SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 " 1485 1.1 lukem "SINGLE-VALUE )", 1486 1.1 lukem &ad_errDisconnect }, 1487 1.1 lukem { NULL } 1488 1.1 lukem }; 1489 1.1 lukem 1490 1.1 lukem static struct { 1491 1.1 lukem char *desc; 1492 1.1 lukem ObjectClass **oc; 1493 1.1 lukem } retcode_oc[] = { 1494 1.1 lukem { "( 1.3.6.1.4.1.4203.666.11.4.3.0 " 1495 1.1 lukem "NAME ( 'errAbsObject' ) " 1496 1.1 lukem "SUP top ABSTRACT " 1497 1.1 lukem "MUST ( errCode ) " 1498 1.1 lukem "MAY ( " 1499 1.1 lukem "cn " 1500 1.1 lukem "$ description " 1501 1.1 lukem "$ errOp " 1502 1.1 lukem "$ errText " 1503 1.1 lukem "$ errSleepTime " 1504 1.1 lukem "$ errMatchedDN " 1505 1.1 lukem "$ errUnsolicitedOID " 1506 1.1 lukem "$ errUnsolicitedData " 1507 1.1 lukem "$ errDisconnect " 1508 1.1 lukem ") )", 1509 1.1 lukem &oc_errAbsObject }, 1510 1.1 lukem { "( 1.3.6.1.4.1.4203.666.11.4.3.1 " 1511 1.1 lukem "NAME ( 'errObject' ) " 1512 1.1 lukem "SUP errAbsObject STRUCTURAL " 1513 1.1 lukem ")", 1514 1.1 lukem &oc_errObject }, 1515 1.1 lukem { "( 1.3.6.1.4.1.4203.666.11.4.3.2 " 1516 1.1 lukem "NAME ( 'errAuxObject' ) " 1517 1.1 lukem "SUP errAbsObject AUXILIARY " 1518 1.1 lukem ")", 1519 1.1 lukem &oc_errAuxObject }, 1520 1.1 lukem { NULL } 1521 1.1 lukem }; 1522 1.1 lukem 1523 1.1 lukem 1524 1.1 lukem for ( i = 0; retcode_at[ i ].desc != NULL; i++ ) { 1525 1.1 lukem code = register_at( retcode_at[ i ].desc, retcode_at[ i ].ad, 0 ); 1526 1.1 lukem if ( code ) { 1527 1.1 lukem Debug( LDAP_DEBUG_ANY, 1528 1.3 christos "retcode: register_at failed\n" ); 1529 1.1 lukem return code; 1530 1.1 lukem } 1531 1.1 lukem 1532 1.1 lukem (*retcode_at[ i ].ad)->ad_type->sat_flags |= SLAP_AT_HIDE; 1533 1.1 lukem } 1534 1.1 lukem 1535 1.1 lukem for ( i = 0; retcode_oc[ i ].desc != NULL; i++ ) { 1536 1.1 lukem code = register_oc( retcode_oc[ i ].desc, retcode_oc[ i ].oc, 0 ); 1537 1.1 lukem if ( code ) { 1538 1.1 lukem Debug( LDAP_DEBUG_ANY, 1539 1.3 christos "retcode: register_oc failed\n" ); 1540 1.1 lukem return code; 1541 1.1 lukem } 1542 1.1 lukem 1543 1.1 lukem (*retcode_oc[ i ].oc)->soc_flags |= SLAP_OC_HIDE; 1544 1.1 lukem } 1545 1.1 lukem 1546 1.1 lukem retcode.on_bi.bi_type = "retcode"; 1547 1.1 lukem 1548 1.1 lukem retcode.on_bi.bi_db_init = retcode_db_init; 1549 1.1 lukem retcode.on_bi.bi_db_open = retcode_db_open; 1550 1.1 lukem retcode.on_bi.bi_db_destroy = retcode_db_destroy; 1551 1.1 lukem 1552 1.1 lukem retcode.on_bi.bi_op_add = retcode_op_func; 1553 1.1 lukem retcode.on_bi.bi_op_bind = retcode_op_func; 1554 1.1 lukem retcode.on_bi.bi_op_compare = retcode_op_func; 1555 1.1 lukem retcode.on_bi.bi_op_delete = retcode_op_func; 1556 1.1 lukem retcode.on_bi.bi_op_modify = retcode_op_func; 1557 1.1 lukem retcode.on_bi.bi_op_modrdn = retcode_op_func; 1558 1.1 lukem retcode.on_bi.bi_op_search = retcode_op_func; 1559 1.1 lukem 1560 1.1 lukem retcode.on_bi.bi_extended = retcode_op_func; 1561 1.1 lukem 1562 1.1 lukem retcode.on_response = retcode_response; 1563 1.1 lukem 1564 1.2 christos retcode.on_bi.bi_cf_ocs = rcocs; 1565 1.2 christos 1566 1.2 christos code = config_register_schema( rccfg, rcocs ); 1567 1.2 christos if ( code ) { 1568 1.2 christos return code; 1569 1.2 christos } 1570 1.2 christos 1571 1.1 lukem return overlay_register( &retcode ); 1572 1.1 lukem } 1573 1.1 lukem 1574 1.1 lukem #if SLAPD_OVER_RETCODE == SLAPD_MOD_DYNAMIC 1575 1.1 lukem int 1576 1.1 lukem init_module( int argc, char *argv[] ) 1577 1.1 lukem { 1578 1.1 lukem return retcode_initialize(); 1579 1.1 lukem } 1580 1.1 lukem #endif /* SLAPD_OVER_RETCODE == SLAPD_MOD_DYNAMIC */ 1581 1.1 lukem 1582 1.1 lukem #endif /* SLAPD_OVER_RETCODE */ 1583