1 1.1 christos /* $NetBSD: variant.c,v 1.3 2025/09/05 21:16:19 christos Exp $ */ 2 1.1 christos 3 1.1 christos /* variant.c - variant overlay */ 4 1.1 christos /* This work is part of OpenLDAP Software <http://www.openldap.org/>. 5 1.1 christos * 6 1.1 christos * Copyright 2016-2021 Symas Corporation. 7 1.1 christos * All rights reserved. 8 1.1 christos * 9 1.1 christos * Redistribution and use in source and binary forms, with or without 10 1.1 christos * modification, are permitted only as authorized by the OpenLDAP 11 1.1 christos * Public License. 12 1.1 christos * 13 1.1 christos * A copy of this license is available in the file LICENSE in the 14 1.1 christos * top-level directory of the distribution or, alternatively, at 15 1.1 christos * <http://www.OpenLDAP.org/license.html>. 16 1.1 christos */ 17 1.1 christos /* ACKNOWLEDGEMENTS: 18 1.1 christos * This work was developed in 2016-2017 by Ondej Kuznk for Symas Corp. 19 1.1 christos */ 20 1.1 christos 21 1.1 christos #include <sys/cdefs.h> 22 1.1 christos __RCSID("$NetBSD: variant.c,v 1.3 2025/09/05 21:16:19 christos Exp $"); 23 1.1 christos 24 1.1 christos #include "portable.h" 25 1.1 christos 26 1.1 christos #ifdef SLAPD_OVER_VARIANT 27 1.1 christos 28 1.1 christos #include "slap.h" 29 1.1 christos #include "slap-config.h" 30 1.1 christos #include "ldap_queue.h" 31 1.1 christos 32 1.1 christos typedef enum variant_type_t { 33 1.1 christos VARIANT_INFO_PLAIN = 1 << 0, 34 1.1 christos VARIANT_INFO_REGEX = 1 << 1, 35 1.1 christos 36 1.1 christos VARIANT_INFO_ALL = ~0 37 1.1 christos } variant_type_t; 38 1.1 christos 39 1.1 christos typedef struct variant_info_t { 40 1.1 christos int passReplication; 41 1.1 christos LDAP_STAILQ_HEAD(variant_list, variantEntry_info) variants, regex_variants; 42 1.1 christos } variant_info_t; 43 1.1 christos 44 1.1 christos typedef struct variantEntry_info { 45 1.1 christos variant_info_t *ov; 46 1.1 christos struct berval dn; 47 1.1 christos variant_type_t type; 48 1.1 christos regex_t *regex; 49 1.1 christos LDAP_SLIST_HEAD(attribute_list, variantAttr_info) attributes; 50 1.1 christos LDAP_STAILQ_ENTRY(variantEntry_info) next; 51 1.1 christos } variantEntry_info; 52 1.1 christos 53 1.1 christos typedef struct variantAttr_info { 54 1.1 christos variantEntry_info *variant; 55 1.1 christos struct berval dn; 56 1.1 christos AttributeDescription *attr, *alternative; 57 1.1 christos LDAP_SLIST_ENTRY(variantAttr_info) next; 58 1.1 christos } variantAttr_info; 59 1.1 christos 60 1.1 christos static int 61 1.1 christos variant_build_dn( 62 1.1 christos Operation *op, 63 1.1 christos variantAttr_info *vai, 64 1.1 christos int nmatch, 65 1.1 christos regmatch_t *pmatch, 66 1.1 christos struct berval *out ) 67 1.1 christos { 68 1.1 christos struct berval dn, *ndn = &op->o_req_ndn; 69 1.1 christos char *dest, *p, *prev, *end = vai->dn.bv_val + vai->dn.bv_len; 70 1.1 christos size_t len = vai->dn.bv_len; 71 1.1 christos int rc; 72 1.1 christos 73 1.1 christos p = vai->dn.bv_val; 74 1.1 christos while ( (p = memchr( p, '$', end - p )) != NULL ) { 75 1.1 christos len -= 1; 76 1.1 christos p += 1; 77 1.1 christos 78 1.1 christos if ( ( *p >= '0' ) && ( *p <= '9' ) ) { 79 1.1 christos int i = *p - '0'; 80 1.1 christos 81 1.1 christos len += ( pmatch[i].rm_eo - pmatch[i].rm_so ); 82 1.1 christos } else if ( *p != '$' ) { 83 1.1 christos /* Should have been checked at configuration time */ 84 1.1 christos assert(0); 85 1.1 christos } 86 1.1 christos len -= 1; 87 1.1 christos p += 1; 88 1.1 christos } 89 1.1 christos 90 1.1 christos dest = dn.bv_val = ch_realloc( out->bv_val, len + 1 ); 91 1.1 christos dn.bv_len = len; 92 1.1 christos 93 1.1 christos prev = vai->dn.bv_val; 94 1.1 christos while ( (p = memchr( prev, '$', end - prev )) != NULL ) { 95 1.1 christos len = p - prev; 96 1.1 christos AC_MEMCPY( dest, prev, len ); 97 1.1 christos dest += len; 98 1.1 christos p += 1; 99 1.1 christos 100 1.1 christos if ( ( *p >= '0' ) && ( *p <= '9' ) ) { 101 1.1 christos int i = *p - '0'; 102 1.1 christos len = pmatch[i].rm_eo - pmatch[i].rm_so; 103 1.1 christos 104 1.1 christos AC_MEMCPY( dest, ndn->bv_val + pmatch[i].rm_so, len ); 105 1.1 christos dest += len; 106 1.1 christos } else if ( *p == '$' ) { 107 1.1 christos *dest++ = *p; 108 1.1 christos } 109 1.1 christos prev = p + 1; 110 1.1 christos } 111 1.1 christos len = end - prev; 112 1.1 christos AC_MEMCPY( dest, prev, len ); 113 1.1 christos dest += len; 114 1.1 christos *dest = '\0'; 115 1.1 christos 116 1.1 christos rc = dnNormalize( 0, NULL, NULL, &dn, out, NULL ); 117 1.1 christos ch_free( dn.bv_val ); 118 1.1 christos 119 1.1 christos return rc; 120 1.1 christos } 121 1.1 christos 122 1.1 christos static int 123 1.1 christos variant_build_entry( 124 1.1 christos Operation *op, 125 1.1 christos variantEntry_info *vei, 126 1.1 christos struct berval *dn, 127 1.1 christos Entry **ep, 128 1.1 christos int nmatch, 129 1.1 christos regmatch_t *pmatch ) 130 1.1 christos { 131 1.1 christos slap_overinst *on = (slap_overinst *)op->o_bd->bd_info; 132 1.1 christos BackendDB *be_orig = op->o_bd, *db; 133 1.1 christos struct berval ndn = BER_BVNULL; 134 1.1 christos variantAttr_info *vai; 135 1.1 christos Attribute *a; 136 1.1 christos BerVarray nvals; 137 1.1 christos Entry *e; 138 1.1 christos unsigned int i; 139 1.1 christos int rc; 140 1.1 christos 141 1.1 christos assert( ep ); 142 1.1 christos assert( !*ep ); 143 1.1 christos 144 1.1 christos rc = overlay_entry_get_ov( op, dn, NULL, NULL, 0, &e, on ); 145 1.1 christos if ( rc == LDAP_SUCCESS && is_entry_referral( e ) ) { 146 1.1 christos overlay_entry_release_ov( op, e, 0, on ); 147 1.1 christos rc = LDAP_REFERRAL; 148 1.1 christos } 149 1.1 christos 150 1.1 christos if ( rc != LDAP_SUCCESS ) { 151 1.1 christos goto done; 152 1.1 christos } 153 1.1 christos 154 1.1 christos *ep = entry_dup( e ); 155 1.1 christos overlay_entry_release_ov( op, e, 0, on ); 156 1.1 christos 157 1.1 christos LDAP_SLIST_FOREACH( vai, &vei->attributes, next ) { 158 1.1 christos if ( vei->type == VARIANT_INFO_REGEX ) { 159 1.1 christos rc = variant_build_dn( op, vai, nmatch, pmatch, &ndn ); 160 1.1 christos if ( rc != LDAP_SUCCESS ) { 161 1.1 christos goto done; 162 1.1 christos } 163 1.1 christos } else { 164 1.1 christos ndn = vai->dn; 165 1.1 christos } 166 1.1 christos 167 1.1 christos (void)attr_delete( &(*ep)->e_attrs, vai->attr ); 168 1.1 christos op->o_bd = be_orig; 169 1.1 christos 170 1.1 christos /* only select backend if not served by ours, would retrace all 171 1.1 christos * overlays again */ 172 1.1 christos db = select_backend( &ndn, 0 ); 173 1.1 christos if ( db && db != be_orig->bd_self ) { 174 1.1 christos op->o_bd = db; 175 1.1 christos rc = be_entry_get_rw( op, &ndn, NULL, vai->alternative, 0, &e ); 176 1.1 christos } else { 177 1.1 christos rc = overlay_entry_get_ov( 178 1.1 christos op, &ndn, NULL, vai->alternative, 0, &e, on ); 179 1.1 christos } 180 1.1 christos 181 1.1 christos switch ( rc ) { 182 1.1 christos case LDAP_SUCCESS: 183 1.1 christos break; 184 1.1 christos case LDAP_INSUFFICIENT_ACCESS: 185 1.1 christos case LDAP_NO_SUCH_ATTRIBUTE: 186 1.1 christos case LDAP_NO_SUCH_OBJECT: 187 1.1 christos rc = LDAP_SUCCESS; 188 1.1 christos continue; 189 1.1 christos break; 190 1.1 christos default: 191 1.1 christos goto done; 192 1.1 christos break; 193 1.1 christos } 194 1.1 christos 195 1.1 christos a = attr_find( e->e_attrs, vai->alternative ); 196 1.1 christos 197 1.1 christos /* back-ldif doesn't check the attribute exists in the entry before 198 1.1 christos * returning it */ 199 1.1 christos if ( a ) { 200 1.1 christos if ( a->a_nvals ) { 201 1.1 christos nvals = a->a_nvals; 202 1.1 christos } else { 203 1.1 christos nvals = a->a_vals; 204 1.1 christos } 205 1.1 christos 206 1.1 christos for ( i = 0; i < a->a_numvals; i++ ) { 207 1.1 christos if ( backend_access( op, e, &ndn, vai->alternative, &nvals[i], 208 1.1 christos ACL_READ, NULL ) != LDAP_SUCCESS ) { 209 1.1 christos continue; 210 1.1 christos } 211 1.1 christos 212 1.1 christos rc = attr_merge_one( *ep, vai->attr, &a->a_vals[i], &nvals[i] ); 213 1.1 christos if ( rc != LDAP_SUCCESS ) { 214 1.1 christos break; 215 1.1 christos } 216 1.1 christos } 217 1.1 christos } 218 1.1 christos 219 1.1 christos if ( db && db != be_orig->bd_self ) { 220 1.1 christos be_entry_release_rw( op, e, 0 ); 221 1.1 christos } else { 222 1.1 christos overlay_entry_release_ov( op, e, 0, on ); 223 1.1 christos } 224 1.1 christos if ( rc != LDAP_SUCCESS ) { 225 1.1 christos goto done; 226 1.1 christos } 227 1.1 christos } 228 1.1 christos 229 1.1 christos done: 230 1.1 christos op->o_bd = be_orig; 231 1.1 christos if ( rc != LDAP_SUCCESS && *ep ) { 232 1.1 christos entry_free( *ep ); 233 1.1 christos *ep = NULL; 234 1.1 christos } 235 1.1 christos if ( vei->type == VARIANT_INFO_REGEX ) { 236 1.1 christos ch_free( ndn.bv_val ); 237 1.1 christos } 238 1.1 christos 239 1.1 christos return rc; 240 1.1 christos } 241 1.1 christos 242 1.1 christos static int 243 1.1 christos variant_find_config( 244 1.1 christos Operation *op, 245 1.1 christos variant_info_t *ov, 246 1.1 christos struct berval *ndn, 247 1.1 christos int which, 248 1.1 christos variantEntry_info **veip, 249 1.1 christos size_t nmatch, 250 1.1 christos regmatch_t *pmatch ) 251 1.1 christos { 252 1.1 christos variantEntry_info *vei; 253 1.1 christos 254 1.1 christos assert( veip ); 255 1.1 christos 256 1.1 christos if ( which & VARIANT_INFO_PLAIN ) { 257 1.1 christos int diff; 258 1.1 christos 259 1.1 christos LDAP_STAILQ_FOREACH( vei, &ov->variants, next ) { 260 1.1 christos dnMatch( &diff, 0, NULL, NULL, ndn, &vei->dn ); 261 1.1 christos if ( diff ) continue; 262 1.1 christos 263 1.1 christos *veip = vei; 264 1.1 christos return LDAP_SUCCESS; 265 1.1 christos } 266 1.1 christos } 267 1.1 christos 268 1.1 christos if ( which & VARIANT_INFO_REGEX ) { 269 1.1 christos LDAP_STAILQ_FOREACH( vei, &ov->regex_variants, next ) { 270 1.1 christos if ( regexec( vei->regex, ndn->bv_val, nmatch, pmatch, 0 ) ) { 271 1.1 christos continue; 272 1.1 christos } 273 1.1 christos 274 1.1 christos *veip = vei; 275 1.1 christos return LDAP_SUCCESS; 276 1.1 christos } 277 1.1 christos } 278 1.1 christos 279 1.1 christos return SLAP_CB_CONTINUE; 280 1.1 christos } 281 1.1 christos 282 1.1 christos static int 283 1.1 christos variant_op_add( Operation *op, SlapReply *rs ) 284 1.1 christos { 285 1.1 christos slap_overinst *on = (slap_overinst *)op->o_bd->bd_info; 286 1.1 christos variant_info_t *ov = on->on_bi.bi_private; 287 1.1 christos variantEntry_info *vei; 288 1.1 christos int rc; 289 1.1 christos 290 1.3 christos if ( ov->passReplication && be_shadow_update( op ) ) { 291 1.1 christos return SLAP_CB_CONTINUE; 292 1.1 christos } 293 1.1 christos 294 1.1 christos Debug( LDAP_DEBUG_TRACE, "variant_op_add: " 295 1.1 christos "dn=%s\n", op->o_req_ndn.bv_val ); 296 1.1 christos 297 1.1 christos rc = variant_find_config( 298 1.1 christos op, ov, &op->o_req_ndn, VARIANT_INFO_ALL, &vei, 0, NULL ); 299 1.1 christos if ( rc == LDAP_SUCCESS ) { 300 1.1 christos variantAttr_info *vai; 301 1.1 christos 302 1.1 christos LDAP_SLIST_FOREACH( vai, &vei->attributes, next ) { 303 1.1 christos Attribute *a; 304 1.1 christos for ( a = op->ora_e->e_attrs; a; a = a->a_next ) { 305 1.1 christos if ( a->a_desc == vai->attr ) { 306 1.1 christos rc = LDAP_CONSTRAINT_VIOLATION; 307 1.1 christos send_ldap_error( op, rs, rc, 308 1.1 christos "variant: trying to add variant attributes" ); 309 1.1 christos goto done; 310 1.1 christos } 311 1.1 christos } 312 1.1 christos } 313 1.1 christos } 314 1.1 christos rc = SLAP_CB_CONTINUE; 315 1.1 christos 316 1.1 christos done: 317 1.1 christos Debug( LDAP_DEBUG_TRACE, "variant_op_add: " 318 1.1 christos "finished with %d\n", 319 1.1 christos rc ); 320 1.1 christos return rc; 321 1.1 christos } 322 1.1 christos 323 1.1 christos static int 324 1.1 christos variant_op_compare( Operation *op, SlapReply *rs ) 325 1.1 christos { 326 1.1 christos slap_overinst *on = (slap_overinst *)op->o_bd->bd_info; 327 1.1 christos variant_info_t *ov = on->on_bi.bi_private; 328 1.1 christos variantEntry_info *vei; 329 1.1 christos regmatch_t pmatch[10]; 330 1.1 christos int rc, nmatch = sizeof(pmatch) / sizeof(regmatch_t); 331 1.1 christos 332 1.1 christos Debug( LDAP_DEBUG_TRACE, "variant_op_compare: " 333 1.1 christos "dn=%s\n", op->o_req_ndn.bv_val ); 334 1.1 christos 335 1.1 christos rc = variant_find_config( 336 1.1 christos op, ov, &op->o_req_ndn, VARIANT_INFO_ALL, &vei, nmatch, pmatch ); 337 1.1 christos if ( rc == LDAP_SUCCESS ) { 338 1.1 christos Entry *e = NULL; 339 1.1 christos 340 1.1 christos rc = variant_build_entry( op, vei, &op->o_req_ndn, &e, nmatch, pmatch ); 341 1.1 christos /* in case of error, just let the backend deal with the mod and the 342 1.1 christos * client should get a meaningful error back */ 343 1.1 christos if ( rc != LDAP_SUCCESS ) { 344 1.1 christos rc = SLAP_CB_CONTINUE; 345 1.1 christos } else { 346 1.1 christos rc = slap_compare_entry( op, e, op->orc_ava ); 347 1.1 christos 348 1.1 christos entry_free( e ); 349 1.1 christos e = NULL; 350 1.1 christos } 351 1.1 christos } 352 1.1 christos 353 1.1 christos if ( rc != SLAP_CB_CONTINUE ) { 354 1.1 christos rs->sr_err = rc; 355 1.1 christos send_ldap_result( op, rs ); 356 1.1 christos } 357 1.1 christos 358 1.1 christos Debug( LDAP_DEBUG_TRACE, "variant_op_compare: " 359 1.1 christos "finished with %d\n", rc ); 360 1.1 christos return rc; 361 1.1 christos } 362 1.1 christos 363 1.1 christos static int 364 1.1 christos variant_cmp_op( const void *l, const void *r ) 365 1.1 christos { 366 1.1 christos const Operation *left = l, *right = r; 367 1.1 christos int diff; 368 1.1 christos 369 1.1 christos dnMatch( &diff, 0, NULL, NULL, (struct berval *)&left->o_req_ndn, 370 1.1 christos (void *)&right->o_req_ndn ); 371 1.1 christos 372 1.1 christos return diff; 373 1.1 christos } 374 1.1 christos 375 1.1 christos static int 376 1.1 christos variant_run_mod( void *nop, void *arg ) 377 1.1 christos { 378 1.1 christos SlapReply nrs = { REP_RESULT }; 379 1.1 christos slap_callback cb = { 0 }; 380 1.1 christos Operation *op = nop; 381 1.1 christos slap_overinst *on = (slap_overinst *)op->o_bd->bd_info; 382 1.1 christos int *rc = arg; 383 1.1 christos 384 1.1 christos cb.sc_response = slap_null_cb; 385 1.1 christos op->o_callback = &cb; 386 1.1 christos 387 1.1 christos Debug( LDAP_DEBUG_TRACE, "variant_run_mod: " 388 1.1 christos "running mod on dn=%s\n", 389 1.1 christos op->o_req_ndn.bv_val ); 390 1.1 christos *rc = on->on_info->oi_orig->bi_op_modify( op, &nrs ); 391 1.1 christos Debug( LDAP_DEBUG_TRACE, "variant_run_mod: " 392 1.1 christos "finished with %d\n", *rc ); 393 1.1 christos 394 1.1 christos return ( *rc != LDAP_SUCCESS ); 395 1.1 christos } 396 1.1 christos 397 1.1 christos /** Move the Modifications back to the original Op so that they can be disposed 398 1.1 christos * of by the original creator 399 1.1 christos */ 400 1.1 christos static int 401 1.1 christos variant_reassign_mods( void *nop, void *arg ) 402 1.1 christos { 403 1.1 christos Operation *op = nop, *orig_op = arg; 404 1.1 christos Modifications *mod; 405 1.1 christos 406 1.1 christos assert( op->orm_modlist ); 407 1.1 christos 408 1.1 christos for ( mod = op->orm_modlist; mod->sml_next; mod = mod->sml_next ) 409 1.1 christos /* get the tail mod */; 410 1.1 christos 411 1.1 christos mod->sml_next = orig_op->orm_modlist; 412 1.1 christos orig_op->orm_modlist = op->orm_modlist; 413 1.1 christos 414 1.1 christos return LDAP_SUCCESS; 415 1.1 christos } 416 1.1 christos 417 1.1 christos void 418 1.1 christos variant_free_op( void *op ) 419 1.1 christos { 420 1.1 christos ch_free( ((Operation *)op)->o_req_ndn.bv_val ); 421 1.1 christos ch_free( op ); 422 1.1 christos } 423 1.1 christos 424 1.1 christos static int 425 1.1 christos variant_op_mod( Operation *op, SlapReply *rs ) 426 1.1 christos { 427 1.1 christos slap_overinst *on = (slap_overinst *)op->o_bd->bd_info; 428 1.1 christos variant_info_t *ov = on->on_bi.bi_private; 429 1.1 christos variantEntry_info *vei; 430 1.1 christos variantAttr_info *vai; 431 1.1 christos Avlnode *ops = NULL; 432 1.1 christos Entry *e = NULL; 433 1.1 christos Modifications *mod, *nextmod; 434 1.1 christos regmatch_t pmatch[10]; 435 1.1 christos int rc, nmatch = sizeof(pmatch) / sizeof(regmatch_t); 436 1.1 christos 437 1.3 christos if ( ov->passReplication && be_shadow_update( op ) ) { 438 1.1 christos return SLAP_CB_CONTINUE; 439 1.1 christos } 440 1.1 christos 441 1.1 christos Debug( LDAP_DEBUG_TRACE, "variant_op_mod: " 442 1.1 christos "dn=%s\n", op->o_req_ndn.bv_val ); 443 1.1 christos 444 1.1 christos rc = variant_find_config( 445 1.1 christos op, ov, &op->o_req_ndn, VARIANT_INFO_ALL, &vei, nmatch, pmatch ); 446 1.1 christos if ( rc != LDAP_SUCCESS ) { 447 1.1 christos Debug( LDAP_DEBUG_TRACE, "variant_op_mod: " 448 1.1 christos "not a variant\n" ); 449 1.1 christos rc = SLAP_CB_CONTINUE; 450 1.1 christos goto done; 451 1.1 christos } 452 1.1 christos 453 1.1 christos rc = variant_build_entry( op, vei, &op->o_req_ndn, &e, nmatch, pmatch ); 454 1.1 christos /* in case of error, just let the backend deal with the mod and the client 455 1.1 christos * should get a meaningful error back */ 456 1.1 christos if ( rc != LDAP_SUCCESS ) { 457 1.1 christos Debug( LDAP_DEBUG_TRACE, "variant_op_mod: " 458 1.1 christos "failed to retrieve entry\n" ); 459 1.1 christos rc = SLAP_CB_CONTINUE; 460 1.1 christos goto done; 461 1.1 christos } 462 1.1 christos 463 1.1 christos rc = acl_check_modlist( op, e, op->orm_modlist ); 464 1.1 christos entry_free( e ); 465 1.1 christos 466 1.1 christos if ( !rc ) { 467 1.1 christos rc = rs->sr_err = LDAP_INSUFFICIENT_ACCESS; 468 1.1 christos send_ldap_error( op, rs, rc, "" ); 469 1.1 christos return rc; 470 1.1 christos } 471 1.1 christos 472 1.1 christos for ( mod = op->orm_modlist; mod; mod = nextmod ) { 473 1.1 christos Operation needle = { .o_req_ndn = BER_BVNULL }, *nop; 474 1.1 christos 475 1.1 christos nextmod = mod->sml_next; 476 1.1 christos 477 1.1 christos LDAP_SLIST_FOREACH( vai, &vei->attributes, next ) { 478 1.1 christos if ( vai->attr == mod->sml_desc ) { 479 1.1 christos break; 480 1.1 christos } 481 1.1 christos } 482 1.1 christos 483 1.1 christos if ( vai ) { 484 1.1 christos if ( vei->type == VARIANT_INFO_REGEX ) { 485 1.1 christos rc = variant_build_dn( 486 1.1 christos op, vai, nmatch, pmatch, &needle.o_req_ndn ); 487 1.1 christos if ( rc != LDAP_SUCCESS ) { 488 1.1 christos continue; 489 1.1 christos } 490 1.1 christos } else { 491 1.1 christos needle.o_req_ndn = vai->dn; 492 1.1 christos } 493 1.1 christos 494 1.1 christos nop = ldap_avl_find( ops, &needle, variant_cmp_op ); 495 1.1 christos if ( nop == NULL ) { 496 1.1 christos nop = ch_calloc( 1, sizeof(Operation) ); 497 1.1 christos *nop = *op; 498 1.1 christos 499 1.1 christos ber_dupbv( &nop->o_req_ndn, &needle.o_req_ndn ); 500 1.1 christos nop->o_req_dn = nop->o_req_ndn; 501 1.1 christos nop->orm_modlist = NULL; 502 1.1 christos 503 1.1 christos rc = ldap_avl_insert( &ops, nop, variant_cmp_op, ldap_avl_dup_error ); 504 1.1 christos assert( rc == 0 ); 505 1.1 christos } 506 1.1 christos mod->sml_desc = vai->alternative; 507 1.1 christos 508 1.1 christos op->orm_modlist = nextmod; 509 1.1 christos mod->sml_next = nop->orm_modlist; 510 1.1 christos nop->orm_modlist = mod; 511 1.1 christos 512 1.1 christos if ( vei->type == VARIANT_INFO_REGEX ) { 513 1.1 christos ch_free( needle.o_req_ndn.bv_val ); 514 1.1 christos } 515 1.1 christos } 516 1.1 christos } 517 1.1 christos 518 1.1 christos if ( !ops ) { 519 1.1 christos Debug( LDAP_DEBUG_TRACE, "variant_op_mod: " 520 1.1 christos "no variant attributes in mod\n" ); 521 1.1 christos return SLAP_CB_CONTINUE; 522 1.1 christos } 523 1.1 christos 524 1.1 christos /* 525 1.1 christos * First run original Operation 526 1.1 christos * This will take care of making sure the entry exists as well. 527 1.1 christos * 528 1.1 christos * FIXME? 529 1.1 christos * Since we cannot make the subsequent Ops atomic wrt. this one, we just 530 1.1 christos * let it send the response as well. After all, the changes on the main DN 531 1.1 christos * have finished by then 532 1.1 christos */ 533 1.1 christos rc = on->on_info->oi_orig->bi_op_modify( op, rs ); 534 1.1 christos if ( rc == LDAP_SUCCESS ) { 535 1.1 christos /* FIXME: if a mod fails, should we attempt to apply the rest? */ 536 1.1 christos ldap_avl_apply( ops, variant_run_mod, &rc, -1, AVL_INORDER ); 537 1.1 christos } 538 1.1 christos 539 1.1 christos ldap_avl_apply( ops, variant_reassign_mods, op, -1, AVL_INORDER ); 540 1.1 christos ldap_avl_free( ops, variant_free_op ); 541 1.1 christos 542 1.1 christos done: 543 1.1 christos Debug( LDAP_DEBUG_TRACE, "variant_op_mod: " 544 1.1 christos "finished with %d\n", rc ); 545 1.1 christos return rc; 546 1.1 christos } 547 1.1 christos 548 1.1 christos static int 549 1.1 christos variant_search_response( Operation *op, SlapReply *rs ) 550 1.1 christos { 551 1.1 christos slap_overinst *on = op->o_callback->sc_private; 552 1.1 christos variant_info_t *ov = on->on_bi.bi_private; 553 1.1 christos variantEntry_info *vei; 554 1.1 christos int rc; 555 1.1 christos 556 1.1 christos if ( rs->sr_type == REP_RESULT ) { 557 1.1 christos ch_free( op->o_callback ); 558 1.1 christos op->o_callback = NULL; 559 1.1 christos } 560 1.1 christos 561 1.1 christos if ( rs->sr_type != REP_SEARCH ) { 562 1.1 christos return SLAP_CB_CONTINUE; 563 1.1 christos } 564 1.1 christos 565 1.1 christos rc = variant_find_config( 566 1.1 christos op, ov, &rs->sr_entry->e_nname, VARIANT_INFO_PLAIN, &vei, 0, NULL ); 567 1.1 christos if ( rc == LDAP_SUCCESS ) { 568 1.1 christos rs->sr_nentries--; 569 1.1 christos return rc; 570 1.1 christos } 571 1.1 christos 572 1.1 christos return SLAP_CB_CONTINUE; 573 1.1 christos } 574 1.1 christos 575 1.1 christos static int 576 1.1 christos variant_op_search( Operation *op, SlapReply *rs ) 577 1.1 christos { 578 1.1 christos slap_overinst *on = (slap_overinst *)op->o_bd->bd_info; 579 1.1 christos variant_info_t *ov = on->on_bi.bi_private; 580 1.1 christos variantEntry_info *vei; 581 1.1 christos slap_callback *cb; 582 1.1 christos Entry *e = NULL; 583 1.1 christos regmatch_t pmatch[10]; 584 1.1 christos int variantInScope = 0, rc = SLAP_CB_CONTINUE, 585 1.1 christos nmatch = sizeof(pmatch) / sizeof(regmatch_t); 586 1.1 christos 587 1.1 christos if ( ov->passReplication && ( op->o_sync > SLAP_CONTROL_IGNORED ) ) { 588 1.1 christos return SLAP_CB_CONTINUE; 589 1.1 christos } 590 1.1 christos 591 1.1 christos Debug( LDAP_DEBUG_TRACE, "variant_op_search: " 592 1.1 christos "dn=%s, scope=%d\n", 593 1.1 christos op->o_req_ndn.bv_val, op->ors_scope ); 594 1.1 christos 595 1.1 christos LDAP_STAILQ_FOREACH( vei, &ov->variants, next ) { 596 1.1 christos if ( !dnIsSuffixScope( &vei->dn, &op->o_req_ndn, op->ors_scope ) ) 597 1.1 christos continue; 598 1.1 christos 599 1.1 christos variantInScope = 1; 600 1.1 christos 601 1.1 christos rc = variant_build_entry( op, vei, &vei->dn, &e, 0, NULL ); 602 1.1 christos if ( rc == LDAP_NO_SUCH_OBJECT || rc == LDAP_REFERRAL ) { 603 1.1 christos rc = SLAP_CB_CONTINUE; 604 1.1 christos continue; 605 1.1 christos } else if ( rc != LDAP_SUCCESS ) { 606 1.1 christos Debug( LDAP_DEBUG_TRACE, "variant_op_search: " 607 1.1 christos "failed to retrieve entry: dn=%s\n", 608 1.1 christos vei->dn.bv_val ); 609 1.1 christos goto done; 610 1.1 christos } 611 1.1 christos 612 1.1 christos if ( test_filter( op, e, op->ors_filter ) == LDAP_COMPARE_TRUE ) { 613 1.1 christos Debug( LDAP_DEBUG_TRACE, "variant_op_search: " 614 1.1 christos "entry matched: dn=%s\n", 615 1.1 christos vei->dn.bv_val ); 616 1.1 christos rs->sr_entry = e; 617 1.1 christos rs->sr_attrs = op->ors_attrs; 618 1.1 christos rc = send_search_entry( op, rs ); 619 1.1 christos } 620 1.1 christos entry_free( e ); 621 1.1 christos e = NULL; 622 1.1 christos } 623 1.1 christos 624 1.1 christos /* Three options: 625 1.1 christos * - the entry has been handled above, in that case vei->type is VARIANT_INFO_PLAIN 626 1.1 christos * - the entry matches a regex, use the first one and we're finished 627 1.1 christos * - no configuration matches entry - do nothing 628 1.1 christos */ 629 1.1 christos if ( op->ors_scope == LDAP_SCOPE_BASE && 630 1.1 christos variant_find_config( op, ov, &op->o_req_ndn, VARIANT_INFO_ALL, &vei, 631 1.1 christos nmatch, pmatch ) == LDAP_SUCCESS && 632 1.1 christos vei->type == VARIANT_INFO_REGEX ) { 633 1.1 christos rc = variant_build_entry( op, vei, &op->o_req_ndn, &e, nmatch, pmatch ); 634 1.1 christos if ( rc == LDAP_NO_SUCH_OBJECT || rc == LDAP_REFERRAL ) { 635 1.1 christos rc = SLAP_CB_CONTINUE; 636 1.1 christos } else if ( rc != LDAP_SUCCESS ) { 637 1.1 christos Debug( LDAP_DEBUG_TRACE, "variant_op_search: " 638 1.1 christos "failed to retrieve entry: dn=%s\n", 639 1.1 christos vei->dn.bv_val ); 640 1.1 christos goto done; 641 1.1 christos } else { 642 1.1 christos if ( test_filter( op, e, op->ors_filter ) == LDAP_COMPARE_TRUE ) { 643 1.1 christos Debug( LDAP_DEBUG_TRACE, "variant_op_search: " 644 1.1 christos "entry matched: dn=%s\n", 645 1.1 christos vei->dn.bv_val ); 646 1.1 christos rs->sr_entry = e; 647 1.1 christos rs->sr_attrs = op->ors_attrs; 648 1.1 christos rc = send_search_entry( op, rs ); 649 1.1 christos } 650 1.1 christos entry_free( e ); 651 1.1 christos e = NULL; 652 1.1 christos goto done; 653 1.1 christos } 654 1.1 christos } 655 1.1 christos rc = SLAP_CB_CONTINUE; 656 1.1 christos 657 1.1 christos if ( variantInScope ) { 658 1.1 christos cb = ch_calloc( 1, sizeof(slap_callback) ); 659 1.1 christos cb->sc_private = on; 660 1.1 christos cb->sc_response = variant_search_response; 661 1.1 christos cb->sc_next = op->o_callback; 662 1.1 christos 663 1.1 christos op->o_callback = cb; 664 1.1 christos } 665 1.1 christos 666 1.1 christos done: 667 1.1 christos if ( rc != SLAP_CB_CONTINUE ) { 668 1.1 christos rs->sr_err = (rc == LDAP_SUCCESS) ? rc : LDAP_OTHER; 669 1.1 christos send_ldap_result( op, rs ); 670 1.1 christos } 671 1.1 christos Debug( LDAP_DEBUG_TRACE, "variant_op_search: " 672 1.1 christos "finished with %d\n", rc ); 673 1.1 christos return rc; 674 1.1 christos } 675 1.1 christos 676 1.1 christos /* Configuration */ 677 1.1 christos 678 1.1 christos static ConfigLDAPadd variant_ldadd; 679 1.1 christos static ConfigLDAPadd variant_regex_ldadd; 680 1.1 christos static ConfigLDAPadd variant_attr_ldadd; 681 1.1 christos 682 1.1 christos static ConfigDriver variant_set_dn; 683 1.1 christos static ConfigDriver variant_set_regex; 684 1.1 christos static ConfigDriver variant_set_alt_dn; 685 1.1 christos static ConfigDriver variant_set_alt_pattern; 686 1.1 christos static ConfigDriver variant_set_attribute; 687 1.1 christos static ConfigDriver variant_add_alt_attr; 688 1.1 christos static ConfigDriver variant_add_alt_attr_regex; 689 1.1 christos 690 1.1 christos static ConfigCfAdd variant_cfadd; 691 1.1 christos 692 1.1 christos enum 693 1.1 christos { 694 1.1 christos VARIANT_ATTR = 1, 695 1.1 christos VARIANT_ATTR_ALT, 696 1.1 christos 697 1.1 christos VARIANT_LAST, 698 1.1 christos }; 699 1.1 christos 700 1.1 christos static ConfigTable variant_cfg[] = { 701 1.1 christos { "passReplication", "on|off", 2, 2, 0, 702 1.1 christos ARG_ON_OFF|ARG_OFFSET, 703 1.1 christos (void *)offsetof( variant_info_t, passReplication ), 704 1.3 christos "( OLcfgCtAt:9.1 NAME 'olcVariantPassReplication' " 705 1.1 christos "DESC 'Whether to let searches with replication control " 706 1.1 christos "pass unmodified' " 707 1.1 christos "SYNTAX OMsBoolean " 708 1.1 christos "SINGLE-VALUE )", 709 1.1 christos NULL, NULL 710 1.1 christos }, 711 1.1 christos { "variantDN", "dn", 2, 2, 0, 712 1.1 christos ARG_DN|ARG_QUOTE|ARG_MAGIC, 713 1.1 christos variant_set_dn, 714 1.3 christos "( OLcfgCtAt:9.2 NAME 'olcVariantEntry' " 715 1.1 christos "DESC 'DN of the variant entry' " 716 1.1 christos "EQUALITY distinguishedNameMatch " 717 1.1 christos "SYNTAX OMsDN " 718 1.1 christos "SINGLE-VALUE )", 719 1.1 christos NULL, NULL 720 1.1 christos }, 721 1.1 christos { "variantRegex", "regex", 2, 2, 0, 722 1.1 christos ARG_BERVAL|ARG_QUOTE|ARG_MAGIC, 723 1.1 christos variant_set_regex, 724 1.3 christos "( OLcfgCtAt:9.6 NAME 'olcVariantEntryRegex' " 725 1.1 christos "DESC 'Pattern for the variant entry' " 726 1.1 christos "EQUALITY caseExactMatch " 727 1.1 christos "SYNTAX OMsDirectoryString " 728 1.1 christos "SINGLE-VALUE )", 729 1.1 christos NULL, NULL 730 1.1 christos }, 731 1.1 christos /* These have no equivalent in slapd.conf */ 732 1.1 christos { "", NULL, 2, 2, 0, 733 1.1 christos ARG_STRING|ARG_MAGIC|VARIANT_ATTR, 734 1.1 christos variant_set_attribute, 735 1.3 christos "( OLcfgCtAt:9.3 NAME 'olcVariantVariantAttribute' " 736 1.1 christos "DESC 'Attribute to fill in the entry' " 737 1.1 christos "EQUALITY caseIgnoreMatch " 738 1.1 christos "SYNTAX OMsDirectoryString " 739 1.1 christos "SINGLE-VALUE )", 740 1.1 christos NULL, NULL 741 1.1 christos }, 742 1.1 christos { "", NULL, 2, 2, 0, 743 1.1 christos ARG_STRING|ARG_MAGIC|VARIANT_ATTR_ALT, 744 1.1 christos variant_set_attribute, 745 1.3 christos "( OLcfgCtAt:9.4 NAME 'olcVariantAlternativeAttribute' " 746 1.1 christos "DESC 'Attribute to take from the alternative entry' " 747 1.1 christos "EQUALITY caseIgnoreMatch " 748 1.1 christos "SYNTAX OMsDirectoryString " 749 1.1 christos "SINGLE-VALUE )", 750 1.1 christos NULL, NULL 751 1.1 christos }, 752 1.1 christos { "", NULL, 2, 2, 0, 753 1.1 christos ARG_DN|ARG_QUOTE|ARG_MAGIC, 754 1.1 christos variant_set_alt_dn, 755 1.3 christos "( OLcfgCtAt:9.5 NAME 'olcVariantAlternativeEntry' " 756 1.1 christos "DESC 'DN of the alternative entry' " 757 1.1 christos "EQUALITY distinguishedNameMatch " 758 1.1 christos "SYNTAX OMsDN " 759 1.1 christos "SINGLE-VALUE )", 760 1.1 christos NULL, NULL 761 1.1 christos }, 762 1.1 christos { "", NULL, 2, 2, 0, 763 1.1 christos ARG_BERVAL|ARG_QUOTE|ARG_MAGIC, 764 1.1 christos variant_set_alt_pattern, 765 1.3 christos "( OLcfgCtAt:9.7 NAME 'olcVariantAlternativeEntryPattern' " 766 1.1 christos "DESC 'Replacement pattern to locate the alternative entry' " 767 1.1 christos "EQUALITY caseExactMatch " 768 1.1 christos "SYNTAX OMsDirectoryString " 769 1.1 christos "SINGLE-VALUE )", 770 1.1 christos NULL, NULL 771 1.1 christos }, 772 1.1 christos /* slapd.conf alternatives for the four above */ 773 1.1 christos { "variantSpec", "attr attr2 dn", 4, 4, 0, 774 1.1 christos ARG_QUOTE|ARG_MAGIC, 775 1.1 christos variant_add_alt_attr, 776 1.1 christos NULL, NULL, NULL 777 1.1 christos }, 778 1.1 christos { "variantRegexSpec", "attr attr2 pattern", 4, 4, 0, 779 1.1 christos ARG_QUOTE|ARG_MAGIC, 780 1.1 christos variant_add_alt_attr_regex, 781 1.1 christos NULL, NULL, NULL 782 1.1 christos }, 783 1.1 christos 784 1.1 christos { NULL, NULL, 0, 0, 0, ARG_IGNORED } 785 1.1 christos }; 786 1.1 christos 787 1.1 christos static ConfigOCs variant_ocs[] = { 788 1.3 christos { "( OLcfgCtOc:9.1 " 789 1.1 christos "NAME 'olcVariantConfig' " 790 1.1 christos "DESC 'Variant overlay configuration' " 791 1.1 christos "SUP olcOverlayConfig " 792 1.1 christos "MAY ( olcVariantPassReplication ) )", 793 1.1 christos Cft_Overlay, variant_cfg, NULL, variant_cfadd }, 794 1.3 christos { "( OLcfgCtOc:9.2 " 795 1.1 christos "NAME 'olcVariantVariant' " 796 1.1 christos "DESC 'Variant configuration' " 797 1.1 christos "MUST ( olcVariantEntry ) " 798 1.1 christos "MAY ( name ) " 799 1.1 christos "SUP top " 800 1.1 christos "STRUCTURAL )", 801 1.1 christos Cft_Misc, variant_cfg, variant_ldadd }, 802 1.3 christos { "( OLcfgCtOc:9.3 " 803 1.1 christos "NAME 'olcVariantAttribute' " 804 1.1 christos "DESC 'Variant attribute description' " 805 1.1 christos "MUST ( olcVariantVariantAttribute $ " 806 1.1 christos "olcVariantAlternativeAttribute $ " 807 1.1 christos "olcVariantAlternativeEntry " 808 1.1 christos ") " 809 1.1 christos "MAY name " 810 1.1 christos "SUP top " 811 1.1 christos "STRUCTURAL )", 812 1.1 christos Cft_Misc, variant_cfg, variant_attr_ldadd }, 813 1.3 christos { "( OLcfgCtOc:9.4 " 814 1.1 christos "NAME 'olcVariantRegex' " 815 1.1 christos "DESC 'Variant configuration' " 816 1.1 christos "MUST ( olcVariantEntryRegex ) " 817 1.1 christos "MAY ( name ) " 818 1.1 christos "SUP top " 819 1.1 christos "STRUCTURAL )", 820 1.1 christos Cft_Misc, variant_cfg, variant_regex_ldadd }, 821 1.3 christos { "( OLcfgCtOc:9.5 " 822 1.1 christos "NAME 'olcVariantAttributePattern' " 823 1.1 christos "DESC 'Variant attribute description' " 824 1.1 christos "MUST ( olcVariantVariantAttribute $ " 825 1.1 christos "olcVariantAlternativeAttribute $ " 826 1.1 christos "olcVariantAlternativeEntryPattern " 827 1.1 christos ") " 828 1.1 christos "MAY name " 829 1.1 christos "SUP top " 830 1.1 christos "STRUCTURAL )", 831 1.1 christos Cft_Misc, variant_cfg, variant_attr_ldadd }, 832 1.1 christos 833 1.1 christos { NULL, 0, NULL } 834 1.1 christos }; 835 1.1 christos 836 1.1 christos static int 837 1.1 christos variant_set_dn( ConfigArgs *ca ) 838 1.1 christos { 839 1.1 christos variantEntry_info *vei2, *vei = ca->ca_private; 840 1.1 christos slap_overinst *on = (slap_overinst *)ca->bi; 841 1.1 christos variant_info_t *ov = on->on_bi.bi_private; 842 1.1 christos int diff; 843 1.1 christos 844 1.1 christos if ( ca->op == SLAP_CONFIG_EMIT ) { 845 1.1 christos value_add_one( &ca->rvalue_vals, &vei->dn ); 846 1.1 christos return LDAP_SUCCESS; 847 1.1 christos } else if ( ca->op == LDAP_MOD_DELETE ) { 848 1.1 christos ber_memfree( vei->dn.bv_val ); 849 1.1 christos BER_BVZERO( &vei->dn ); 850 1.1 christos return LDAP_SUCCESS; 851 1.1 christos } 852 1.1 christos 853 1.1 christos if ( !vei ) { 854 1.1 christos vei = ch_calloc( 1, sizeof(variantEntry_info) ); 855 1.1 christos vei->ov = ov; 856 1.1 christos vei->type = VARIANT_INFO_PLAIN; 857 1.1 christos LDAP_SLIST_INIT(&vei->attributes); 858 1.1 christos LDAP_STAILQ_ENTRY_INIT(vei, next); 859 1.1 christos LDAP_STAILQ_INSERT_TAIL(&ov->variants, vei, next); 860 1.1 christos 861 1.1 christos ca->ca_private = vei; 862 1.1 christos } 863 1.1 christos vei->dn = ca->value_ndn; 864 1.1 christos ber_memfree( ca->value_dn.bv_val ); 865 1.1 christos 866 1.1 christos /* Each DN should only be listed once */ 867 1.1 christos LDAP_STAILQ_FOREACH( vei2, &vei->ov->variants, next ) { 868 1.1 christos if ( vei == vei2 ) continue; 869 1.1 christos 870 1.1 christos dnMatch( &diff, 0, NULL, NULL, &vei->dn, &vei2->dn ); 871 1.1 christos if ( !diff ) { 872 1.3 christos snprintf( ca->cr_msg, sizeof(ca->cr_msg), 873 1.3 christos "duplicate variant dn: %s", ca->value_ndn.bv_val ); 874 1.3 christos Debug( LDAP_DEBUG_ANY, "%s: %s\n", ca->log, ca->cr_msg ); 875 1.3 christos return LDAP_CONSTRAINT_VIOLATION; 876 1.1 christos } 877 1.1 christos } 878 1.1 christos 879 1.1 christos return LDAP_SUCCESS; 880 1.1 christos } 881 1.1 christos 882 1.1 christos static int 883 1.1 christos variant_set_regex( ConfigArgs *ca ) 884 1.1 christos { 885 1.1 christos variantEntry_info *vei2, *vei = ca->ca_private; 886 1.1 christos slap_overinst *on = (slap_overinst *)ca->bi; 887 1.1 christos variant_info_t *ov = on->on_bi.bi_private; 888 1.1 christos 889 1.1 christos if ( ca->op == SLAP_CONFIG_EMIT ) { 890 1.1 christos ca->value_bv = vei->dn; 891 1.1 christos return LDAP_SUCCESS; 892 1.1 christos } else if ( ca->op == LDAP_MOD_DELETE ) { 893 1.1 christos ber_memfree( vei->dn.bv_val ); 894 1.1 christos BER_BVZERO( &vei->dn ); 895 1.3 christos if ( vei->regex ) { 896 1.3 christos regfree( vei->regex ); 897 1.3 christos ch_free( vei->regex ); 898 1.3 christos vei->regex = NULL; 899 1.3 christos } 900 1.1 christos return LDAP_SUCCESS; 901 1.1 christos } 902 1.1 christos 903 1.1 christos if ( !vei ) { 904 1.1 christos vei = ch_calloc( 1, sizeof(variantEntry_info) ); 905 1.1 christos vei->ov = ov; 906 1.1 christos vei->type = VARIANT_INFO_REGEX; 907 1.1 christos LDAP_SLIST_INIT(&vei->attributes); 908 1.1 christos LDAP_STAILQ_ENTRY_INIT(vei, next); 909 1.1 christos LDAP_STAILQ_INSERT_TAIL(&ov->regex_variants, vei, next); 910 1.1 christos 911 1.1 christos ca->ca_private = vei; 912 1.1 christos } 913 1.1 christos vei->dn = ca->value_bv; 914 1.1 christos 915 1.1 christos /* Each regex should only be listed once */ 916 1.1 christos LDAP_STAILQ_FOREACH( vei2, &vei->ov->regex_variants, next ) { 917 1.1 christos if ( vei == vei2 ) continue; 918 1.1 christos 919 1.1 christos if ( !ber_bvcmp( &ca->value_bv, &vei2->dn ) ) { 920 1.3 christos snprintf( ca->cr_msg, sizeof(ca->cr_msg), 921 1.3 christos "duplicate variant regex: %s", ca->value_dn.bv_val ); 922 1.3 christos Debug( LDAP_DEBUG_ANY, "%s: %s\n", ca->log, ca->cr_msg ); 923 1.3 christos return LDAP_CONSTRAINT_VIOLATION; 924 1.1 christos } 925 1.1 christos } 926 1.1 christos 927 1.1 christos vei->regex = ch_calloc( 1, sizeof(regex_t) ); 928 1.1 christos if ( regcomp( vei->regex, vei->dn.bv_val, REG_EXTENDED ) ) { 929 1.1 christos ch_free( vei->regex ); 930 1.3 christos vei->regex = NULL; 931 1.3 christos snprintf( ca->cr_msg, sizeof(ca->cr_msg), 932 1.3 christos "cannot process regex: %s", vei->dn.bv_val ); 933 1.3 christos Debug( LDAP_DEBUG_ANY, "%s: %s\n", ca->log, ca->cr_msg ); 934 1.3 christos return LDAP_CONSTRAINT_VIOLATION; 935 1.1 christos } 936 1.1 christos 937 1.1 christos return LDAP_SUCCESS; 938 1.1 christos } 939 1.1 christos 940 1.1 christos static int 941 1.1 christos variant_set_alt_dn( ConfigArgs *ca ) 942 1.1 christos { 943 1.1 christos variantAttr_info *vai = ca->ca_private; 944 1.1 christos 945 1.1 christos if ( ca->op == SLAP_CONFIG_EMIT ) { 946 1.1 christos value_add_one( &ca->rvalue_vals, &vai->dn ); 947 1.1 christos return LDAP_SUCCESS; 948 1.1 christos } else if ( ca->op == LDAP_MOD_DELETE ) { 949 1.1 christos ber_memfree( vai->dn.bv_val ); 950 1.1 christos BER_BVZERO( &vai->dn ); 951 1.1 christos return LDAP_SUCCESS; 952 1.1 christos } 953 1.1 christos 954 1.1 christos vai->dn = ca->value_ndn; 955 1.1 christos ber_memfree( ca->value_dn.bv_val ); 956 1.1 christos 957 1.1 christos return LDAP_SUCCESS; 958 1.1 christos } 959 1.1 christos 960 1.1 christos static int 961 1.1 christos variant_set_alt_pattern( ConfigArgs *ca ) 962 1.1 christos { 963 1.1 christos variantAttr_info *vai = ca->ca_private; 964 1.1 christos char *p = ca->value_bv.bv_val, 965 1.1 christos *end = ca->value_bv.bv_val + ca->value_bv.bv_len; 966 1.1 christos 967 1.1 christos if ( ca->op == SLAP_CONFIG_EMIT ) { 968 1.1 christos ca->value_bv = vai->dn; 969 1.1 christos return LDAP_SUCCESS; 970 1.1 christos } else if ( ca->op == LDAP_MOD_DELETE ) { 971 1.1 christos ber_memfree( vai->dn.bv_val ); 972 1.1 christos BER_BVZERO( &vai->dn ); 973 1.1 christos return LDAP_SUCCESS; 974 1.1 christos } 975 1.1 christos 976 1.1 christos while ( (p = memchr( p, '$', end - p )) != NULL ) { 977 1.1 christos p += 1; 978 1.1 christos 979 1.1 christos if ( ( ( *p >= '0' ) && ( *p <= '9' ) ) || ( *p == '$' ) ) { 980 1.1 christos p += 1; 981 1.1 christos } else { 982 1.3 christos snprintf( ca->cr_msg, sizeof(ca->cr_msg), 983 1.3 christos "invalid replacement pattern supplied '%s'", 984 1.1 christos ca->value_bv.bv_val ); 985 1.3 christos Debug( LDAP_DEBUG_ANY, "%s: %s\n", ca->log, ca->cr_msg ); 986 1.3 christos return LDAP_CONSTRAINT_VIOLATION; 987 1.1 christos } 988 1.1 christos } 989 1.1 christos 990 1.1 christos vai->dn = ca->value_bv; 991 1.1 christos 992 1.1 christos return LDAP_SUCCESS; 993 1.1 christos } 994 1.1 christos 995 1.1 christos static int 996 1.1 christos variant_set_attribute( ConfigArgs *ca ) 997 1.1 christos { 998 1.1 christos variantAttr_info *vai2, *vai = ca->ca_private; 999 1.1 christos char *s = ca->value_string; 1000 1.1 christos const char *text; 1001 1.1 christos AttributeDescription **ad; 1002 1.1 christos int rc; 1003 1.1 christos 1004 1.1 christos if ( ca->type == VARIANT_ATTR ) { 1005 1.1 christos ad = &vai->attr; 1006 1.1 christos } else { 1007 1.1 christos ad = &vai->alternative; 1008 1.1 christos } 1009 1.1 christos 1010 1.1 christos if ( ca->op == SLAP_CONFIG_EMIT ) { 1011 1.1 christos ca->value_string = ch_strdup( (*ad)->ad_cname.bv_val ); 1012 1.1 christos return LDAP_SUCCESS; 1013 1.1 christos } else if ( ca->op == LDAP_MOD_DELETE ) { 1014 1.1 christos *ad = NULL; 1015 1.1 christos return LDAP_SUCCESS; 1016 1.1 christos } 1017 1.1 christos 1018 1.1 christos if ( *s == '{' ) { 1019 1.1 christos s = strchr( s, '}' ); 1020 1.1 christos if ( !s ) { 1021 1.3 christos return LDAP_UNDEFINED_TYPE; 1022 1.1 christos } 1023 1.1 christos s += 1; 1024 1.1 christos } 1025 1.1 christos 1026 1.1 christos rc = slap_str2ad( s, ad, &text ); 1027 1.1 christos ber_memfree( ca->value_string ); 1028 1.1 christos if ( rc ) { 1029 1.3 christos snprintf( ca->cr_msg, sizeof(ca->cr_msg), 1030 1.3 christos "attribute %s invalid: %s", s, text ); 1031 1.3 christos Debug( LDAP_DEBUG_ANY, "%s: %s\n", ca->log, ca->cr_msg ); 1032 1.1 christos return rc; 1033 1.1 christos } 1034 1.1 christos 1035 1.1 christos /* Both attributes have to share the same syntax */ 1036 1.1 christos if ( vai->attr && vai->alternative && 1037 1.1 christos vai->attr->ad_type->sat_syntax != 1038 1.1 christos vai->alternative->ad_type->sat_syntax ) { 1039 1.3 christos snprintf( ca->cr_msg, sizeof(ca->cr_msg), 1040 1.3 christos "attribute '%s' syntax doesn't match alternative attribute '%s'", 1041 1.3 christos vai->attr->ad_cname.bv_val, vai->alternative->ad_cname.bv_val ); 1042 1.3 christos Debug( LDAP_DEBUG_ANY, "%s: %s\n", ca->log, ca->cr_msg ); 1043 1.3 christos return LDAP_CONSTRAINT_VIOLATION; 1044 1.1 christos } 1045 1.1 christos 1046 1.1 christos if ( ca->type == VARIANT_ATTR ) { 1047 1.1 christos /* Each attribute should only be listed once */ 1048 1.1 christos LDAP_SLIST_FOREACH( vai2, &vai->variant->attributes, next ) { 1049 1.1 christos if ( vai == vai2 ) continue; 1050 1.1 christos if ( vai->attr == vai2->attr ) { 1051 1.3 christos snprintf( ca->cr_msg, sizeof(ca->cr_msg), 1052 1.3 christos "duplicate attribute '%s'", vai->attr->ad_cname.bv_val ); 1053 1.3 christos Debug( LDAP_DEBUG_ANY, "%s: %s\n", ca->log, ca->cr_msg ); 1054 1.3 christos return LDAP_CONSTRAINT_VIOLATION; 1055 1.1 christos } 1056 1.1 christos } 1057 1.1 christos } 1058 1.1 christos 1059 1.1 christos return LDAP_SUCCESS; 1060 1.1 christos } 1061 1.1 christos 1062 1.1 christos static int 1063 1.1 christos variant_add_alt_attr( ConfigArgs *ca ) 1064 1.1 christos { 1065 1.1 christos slap_overinst *on = (slap_overinst *)ca->bi; 1066 1.1 christos variant_info_t *ov = on->on_bi.bi_private; 1067 1.1 christos variantEntry_info *vei = 1068 1.1 christos LDAP_STAILQ_LAST( &ov->variants, variantEntry_info, next ); 1069 1.1 christos variantAttr_info *vai; 1070 1.1 christos struct berval dn, ndn; 1071 1.1 christos int rc; 1072 1.1 christos 1073 1.1 christos vai = ch_calloc( 1, sizeof(variantAttr_info) ); 1074 1.1 christos vai->variant = vei; 1075 1.1 christos LDAP_SLIST_ENTRY_INIT( vai, next ); 1076 1.1 christos ca->ca_private = vai; 1077 1.1 christos 1078 1.1 christos ca->value_string = ch_strdup( ca->argv[1] ); 1079 1.1 christos ca->type = VARIANT_ATTR; 1080 1.1 christos rc = variant_set_attribute( ca ); 1081 1.1 christos if ( rc != LDAP_SUCCESS ) { 1082 1.1 christos goto done; 1083 1.1 christos } 1084 1.1 christos 1085 1.1 christos ca->value_string = ch_strdup( ca->argv[2] ); 1086 1.1 christos ca->type = VARIANT_ATTR_ALT; 1087 1.1 christos rc = variant_set_attribute( ca ); 1088 1.1 christos if ( rc != LDAP_SUCCESS ) { 1089 1.1 christos goto done; 1090 1.1 christos } 1091 1.1 christos 1092 1.1 christos dn.bv_val = ca->argv[3]; 1093 1.1 christos dn.bv_len = strlen( dn.bv_val ); 1094 1.1 christos rc = dnNormalize( 0, NULL, NULL, &dn, &ndn, NULL ); 1095 1.1 christos if ( rc != LDAP_SUCCESS ) { 1096 1.1 christos goto done; 1097 1.1 christos } 1098 1.1 christos 1099 1.1 christos ca->type = 0; 1100 1.1 christos BER_BVZERO( &ca->value_dn ); 1101 1.1 christos ca->value_ndn = ndn; 1102 1.1 christos rc = variant_set_alt_dn( ca ); 1103 1.1 christos if ( rc != LDAP_SUCCESS ) { 1104 1.1 christos ch_free( ndn.bv_val ); 1105 1.1 christos goto done; 1106 1.1 christos } 1107 1.1 christos 1108 1.1 christos done: 1109 1.1 christos if ( rc == LDAP_SUCCESS ) { 1110 1.1 christos LDAP_SLIST_INSERT_HEAD( &vei->attributes, vai, next ); 1111 1.1 christos } 1112 1.1 christos 1113 1.1 christos return rc; 1114 1.1 christos } 1115 1.1 christos 1116 1.1 christos static int 1117 1.1 christos variant_add_alt_attr_regex( ConfigArgs *ca ) 1118 1.1 christos { 1119 1.1 christos slap_overinst *on = (slap_overinst *)ca->bi; 1120 1.1 christos variant_info_t *ov = on->on_bi.bi_private; 1121 1.1 christos variantEntry_info *vei = 1122 1.1 christos LDAP_STAILQ_LAST( &ov->regex_variants, variantEntry_info, next ); 1123 1.1 christos variantAttr_info *vai; 1124 1.1 christos int rc; 1125 1.1 christos 1126 1.1 christos vai = ch_calloc( 1, sizeof(variantAttr_info) ); 1127 1.1 christos vai->variant = vei; 1128 1.1 christos LDAP_SLIST_ENTRY_INIT( vai, next ); 1129 1.1 christos ca->ca_private = vai; 1130 1.1 christos 1131 1.1 christos ca->value_string = ch_strdup( ca->argv[1] ); 1132 1.1 christos ca->type = VARIANT_ATTR; 1133 1.1 christos rc = variant_set_attribute( ca ); 1134 1.1 christos if ( rc != LDAP_SUCCESS ) { 1135 1.1 christos goto done; 1136 1.1 christos } 1137 1.1 christos 1138 1.1 christos ca->value_string = ch_strdup( ca->argv[2] ); 1139 1.1 christos ca->type = VARIANT_ATTR_ALT; 1140 1.1 christos rc = variant_set_attribute( ca ); 1141 1.1 christos if ( rc != LDAP_SUCCESS ) { 1142 1.1 christos goto done; 1143 1.1 christos } 1144 1.1 christos 1145 1.1 christos ca->type = 0; 1146 1.1 christos ber_str2bv( ca->argv[3], 0, 1, &ca->value_bv ); 1147 1.1 christos rc = variant_set_alt_pattern( ca ); 1148 1.1 christos if ( rc != LDAP_SUCCESS ) { 1149 1.1 christos goto done; 1150 1.1 christos } 1151 1.1 christos 1152 1.1 christos done: 1153 1.1 christos if ( rc == LDAP_SUCCESS ) { 1154 1.1 christos LDAP_SLIST_INSERT_HEAD( &vei->attributes, vai, next ); 1155 1.1 christos } 1156 1.1 christos 1157 1.1 christos return rc; 1158 1.1 christos } 1159 1.1 christos 1160 1.1 christos static int 1161 1.1 christos variant_ldadd_cleanup( ConfigArgs *ca ) 1162 1.1 christos { 1163 1.1 christos variantEntry_info *vei = ca->ca_private; 1164 1.1 christos slap_overinst *on = (slap_overinst *)ca->bi; 1165 1.1 christos variant_info_t *ov = on->on_bi.bi_private; 1166 1.1 christos 1167 1.1 christos if ( ca->reply.err != LDAP_SUCCESS ) { 1168 1.1 christos assert( LDAP_SLIST_EMPTY(&vei->attributes) ); 1169 1.3 christos ch_free( vei->dn.bv_val ); 1170 1.1 christos ch_free( vei ); 1171 1.1 christos return LDAP_SUCCESS; 1172 1.1 christos } 1173 1.1 christos 1174 1.1 christos if ( vei->type == VARIANT_INFO_PLAIN ) { 1175 1.1 christos LDAP_STAILQ_INSERT_TAIL(&ov->variants, vei, next); 1176 1.1 christos } else { 1177 1.1 christos LDAP_STAILQ_INSERT_TAIL(&ov->regex_variants, vei, next); 1178 1.1 christos } 1179 1.1 christos 1180 1.1 christos return LDAP_SUCCESS; 1181 1.1 christos } 1182 1.1 christos 1183 1.1 christos static int 1184 1.1 christos variant_ldadd( CfEntryInfo *cei, Entry *e, ConfigArgs *ca ) 1185 1.1 christos { 1186 1.1 christos slap_overinst *on; 1187 1.1 christos variant_info_t *ov; 1188 1.1 christos variantEntry_info *vei; 1189 1.1 christos 1190 1.1 christos if ( cei->ce_type != Cft_Overlay || !cei->ce_bi || 1191 1.1 christos cei->ce_bi->bi_cf_ocs != variant_ocs ) 1192 1.1 christos return LDAP_CONSTRAINT_VIOLATION; 1193 1.1 christos 1194 1.1 christos on = (slap_overinst *)cei->ce_bi; 1195 1.1 christos ov = on->on_bi.bi_private; 1196 1.1 christos 1197 1.1 christos vei = ch_calloc( 1, sizeof(variantEntry_info) ); 1198 1.1 christos vei->ov = ov; 1199 1.1 christos vei->type = VARIANT_INFO_PLAIN; 1200 1.1 christos LDAP_SLIST_INIT(&vei->attributes); 1201 1.1 christos LDAP_STAILQ_ENTRY_INIT(vei, next); 1202 1.1 christos 1203 1.1 christos ca->bi = cei->ce_bi; 1204 1.1 christos ca->ca_private = vei; 1205 1.1 christos config_push_cleanup( ca, variant_ldadd_cleanup ); 1206 1.1 christos /* config_push_cleanup is only run in the case of online config but we use it to 1207 1.1 christos * save the new config when done with the entry */ 1208 1.1 christos ca->lineno = 0; 1209 1.1 christos 1210 1.1 christos return LDAP_SUCCESS; 1211 1.1 christos } 1212 1.1 christos 1213 1.1 christos static int 1214 1.1 christos variant_regex_ldadd( CfEntryInfo *cei, Entry *e, ConfigArgs *ca ) 1215 1.1 christos { 1216 1.1 christos slap_overinst *on; 1217 1.1 christos variant_info_t *ov; 1218 1.1 christos variantEntry_info *vei; 1219 1.1 christos 1220 1.1 christos if ( cei->ce_type != Cft_Overlay || !cei->ce_bi || 1221 1.1 christos cei->ce_bi->bi_cf_ocs != variant_ocs ) 1222 1.1 christos return LDAP_CONSTRAINT_VIOLATION; 1223 1.1 christos 1224 1.1 christos on = (slap_overinst *)cei->ce_bi; 1225 1.1 christos ov = on->on_bi.bi_private; 1226 1.1 christos 1227 1.1 christos vei = ch_calloc( 1, sizeof(variantEntry_info) ); 1228 1.1 christos vei->ov = ov; 1229 1.1 christos vei->type = VARIANT_INFO_REGEX; 1230 1.1 christos LDAP_SLIST_INIT(&vei->attributes); 1231 1.1 christos LDAP_STAILQ_ENTRY_INIT(vei, next); 1232 1.1 christos 1233 1.1 christos ca->bi = cei->ce_bi; 1234 1.1 christos ca->ca_private = vei; 1235 1.1 christos config_push_cleanup( ca, variant_ldadd_cleanup ); 1236 1.1 christos /* config_push_cleanup is only run in the case of online config but we use it to 1237 1.1 christos * save the new config when done with the entry */ 1238 1.1 christos ca->lineno = 0; 1239 1.1 christos 1240 1.1 christos return LDAP_SUCCESS; 1241 1.1 christos } 1242 1.1 christos 1243 1.1 christos static int 1244 1.1 christos variant_attr_ldadd_cleanup( ConfigArgs *ca ) 1245 1.1 christos { 1246 1.1 christos variantAttr_info *vai = ca->ca_private; 1247 1.1 christos variantEntry_info *vei = vai->variant; 1248 1.1 christos 1249 1.1 christos if ( ca->reply.err != LDAP_SUCCESS ) { 1250 1.3 christos ch_free( vai->dn.bv_val ); 1251 1.1 christos ch_free( vai ); 1252 1.1 christos return LDAP_SUCCESS; 1253 1.1 christos } 1254 1.1 christos 1255 1.1 christos LDAP_SLIST_INSERT_HEAD(&vei->attributes, vai, next); 1256 1.1 christos 1257 1.1 christos return LDAP_SUCCESS; 1258 1.1 christos } 1259 1.1 christos 1260 1.1 christos static int 1261 1.1 christos variant_attr_ldadd( CfEntryInfo *cei, Entry *e, ConfigArgs *ca ) 1262 1.1 christos { 1263 1.1 christos variantEntry_info *vei; 1264 1.1 christos variantAttr_info *vai; 1265 1.1 christos CfEntryInfo *parent = cei->ce_parent; 1266 1.1 christos 1267 1.1 christos if ( cei->ce_type != Cft_Misc || !parent || !parent->ce_bi || 1268 1.1 christos parent->ce_bi->bi_cf_ocs != variant_ocs ) 1269 1.1 christos return LDAP_CONSTRAINT_VIOLATION; 1270 1.1 christos 1271 1.1 christos vei = (variantEntry_info *)cei->ce_private; 1272 1.1 christos 1273 1.1 christos vai = ch_calloc( 1, sizeof(variantAttr_info) ); 1274 1.1 christos vai->variant = vei; 1275 1.1 christos LDAP_SLIST_ENTRY_INIT(vai, next); 1276 1.1 christos 1277 1.1 christos ca->ca_private = vai; 1278 1.1 christos config_push_cleanup( ca, variant_attr_ldadd_cleanup ); 1279 1.1 christos /* config_push_cleanup is only run in the case of online config but we use it to 1280 1.1 christos * save the new config when done with the entry */ 1281 1.1 christos ca->lineno = 0; 1282 1.1 christos 1283 1.1 christos return LDAP_SUCCESS; 1284 1.1 christos } 1285 1.1 christos 1286 1.1 christos static int 1287 1.1 christos variant_cfadd( Operation *op, SlapReply *rs, Entry *p, ConfigArgs *ca ) 1288 1.1 christos { 1289 1.1 christos slap_overinst *on = (slap_overinst *)ca->bi; 1290 1.1 christos variant_info_t *ov = on->on_bi.bi_private; 1291 1.1 christos variantEntry_info *vei; 1292 1.1 christos variantAttr_info *vai; 1293 1.1 christos Entry *e; 1294 1.1 christos struct berval rdn; 1295 1.1 christos int i = 0; 1296 1.1 christos 1297 1.1 christos LDAP_STAILQ_FOREACH( vei, &ov->variants, next ) { 1298 1.1 christos int j = 0; 1299 1.1 christos rdn.bv_len = snprintf( 1300 1.1 christos ca->cr_msg, sizeof(ca->cr_msg), "name={%d}variant", i++ ); 1301 1.1 christos rdn.bv_val = ca->cr_msg; 1302 1.1 christos 1303 1.1 christos ca->ca_private = vei; 1304 1.1 christos e = config_build_entry( 1305 1.1 christos op, rs, p->e_private, ca, &rdn, &variant_ocs[1], NULL ); 1306 1.1 christos assert( e ); 1307 1.1 christos 1308 1.1 christos LDAP_SLIST_FOREACH( vai, &vei->attributes, next ) { 1309 1.1 christos rdn.bv_len = snprintf( ca->cr_msg, sizeof(ca->cr_msg), 1310 1.1 christos "olcVariantVariantAttribute={%d}%s", j++, 1311 1.1 christos vai->attr->ad_cname.bv_val ); 1312 1.1 christos rdn.bv_val = ca->cr_msg; 1313 1.1 christos 1314 1.1 christos ca->ca_private = vai; 1315 1.1 christos config_build_entry( 1316 1.1 christos op, rs, e->e_private, ca, &rdn, &variant_ocs[2], NULL ); 1317 1.1 christos } 1318 1.1 christos } 1319 1.1 christos 1320 1.1 christos LDAP_STAILQ_FOREACH( vei, &ov->regex_variants, next ) { 1321 1.1 christos int j = 0; 1322 1.1 christos rdn.bv_len = snprintf( 1323 1.1 christos ca->cr_msg, sizeof(ca->cr_msg), "name={%d}regex", i++ ); 1324 1.1 christos rdn.bv_val = ca->cr_msg; 1325 1.1 christos 1326 1.1 christos ca->ca_private = vei; 1327 1.1 christos e = config_build_entry( 1328 1.1 christos op, rs, p->e_private, ca, &rdn, &variant_ocs[3], NULL ); 1329 1.1 christos assert( e ); 1330 1.1 christos 1331 1.1 christos LDAP_SLIST_FOREACH( vai, &vei->attributes, next ) { 1332 1.1 christos rdn.bv_len = snprintf( ca->cr_msg, sizeof(ca->cr_msg), 1333 1.1 christos "olcVariantVariantAttribute={%d}%s", j++, 1334 1.1 christos vai->attr->ad_cname.bv_val ); 1335 1.1 christos rdn.bv_val = ca->cr_msg; 1336 1.1 christos 1337 1.1 christos ca->ca_private = vai; 1338 1.1 christos config_build_entry( 1339 1.1 christos op, rs, e->e_private, ca, &rdn, &variant_ocs[4], NULL ); 1340 1.1 christos } 1341 1.1 christos } 1342 1.1 christos return LDAP_SUCCESS; 1343 1.1 christos } 1344 1.1 christos 1345 1.1 christos static slap_overinst variant; 1346 1.1 christos 1347 1.1 christos static int 1348 1.1 christos variant_db_init( BackendDB *be, ConfigReply *cr ) 1349 1.1 christos { 1350 1.1 christos slap_overinst *on = (slap_overinst *)be->bd_info; 1351 1.1 christos variant_info_t *ov; 1352 1.1 christos 1353 1.1 christos if ( SLAP_ISGLOBALOVERLAY(be) ) { 1354 1.1 christos Debug( LDAP_DEBUG_ANY, "variant overlay must be instantiated within " 1355 1.1 christos "a database.\n" ); 1356 1.1 christos return 1; 1357 1.1 christos } 1358 1.1 christos 1359 1.1 christos ov = ch_calloc( 1, sizeof(variant_info_t) ); 1360 1.1 christos LDAP_STAILQ_INIT(&ov->variants); 1361 1.1 christos LDAP_STAILQ_INIT(&ov->regex_variants); 1362 1.1 christos 1363 1.1 christos on->on_bi.bi_private = ov; 1364 1.1 christos 1365 1.1 christos return LDAP_SUCCESS; 1366 1.1 christos } 1367 1.1 christos 1368 1.1 christos static int 1369 1.1 christos variant_db_destroy( BackendDB *be, ConfigReply *cr ) 1370 1.1 christos { 1371 1.1 christos slap_overinst *on = (slap_overinst *)be->bd_info; 1372 1.1 christos variant_info_t *ov = on->on_bi.bi_private; 1373 1.1 christos 1374 1.1 christos if ( ov ) { 1375 1.1 christos while ( !LDAP_STAILQ_EMPTY( &ov->variants ) ) { 1376 1.1 christos variantEntry_info *vei = LDAP_STAILQ_FIRST( &ov->variants ); 1377 1.1 christos LDAP_STAILQ_REMOVE_HEAD( &ov->variants, next ); 1378 1.1 christos 1379 1.1 christos while ( !LDAP_SLIST_EMPTY( &vei->attributes ) ) { 1380 1.1 christos variantAttr_info *vai = LDAP_SLIST_FIRST( &vei->attributes ); 1381 1.1 christos LDAP_SLIST_REMOVE_HEAD( &vei->attributes, next ); 1382 1.1 christos 1383 1.1 christos ber_memfree( vai->dn.bv_val ); 1384 1.1 christos ch_free( vai ); 1385 1.1 christos } 1386 1.1 christos ber_memfree( vei->dn.bv_val ); 1387 1.1 christos ch_free( vei ); 1388 1.1 christos } 1389 1.1 christos while ( !LDAP_STAILQ_EMPTY( &ov->regex_variants ) ) { 1390 1.1 christos variantEntry_info *vei = LDAP_STAILQ_FIRST( &ov->regex_variants ); 1391 1.1 christos LDAP_STAILQ_REMOVE_HEAD( &ov->regex_variants, next ); 1392 1.1 christos 1393 1.1 christos while ( !LDAP_SLIST_EMPTY( &vei->attributes ) ) { 1394 1.1 christos variantAttr_info *vai = LDAP_SLIST_FIRST( &vei->attributes ); 1395 1.1 christos LDAP_SLIST_REMOVE_HEAD( &vei->attributes, next ); 1396 1.1 christos 1397 1.1 christos ber_memfree( vai->dn.bv_val ); 1398 1.1 christos ch_free( vai ); 1399 1.1 christos } 1400 1.1 christos ber_memfree( vei->dn.bv_val ); 1401 1.3 christos regfree( vei->regex ); 1402 1.3 christos ch_free( vei->regex ); 1403 1.1 christos ch_free( vei ); 1404 1.1 christos } 1405 1.1 christos ch_free( ov ); 1406 1.1 christos } 1407 1.1 christos 1408 1.1 christos return LDAP_SUCCESS; 1409 1.1 christos } 1410 1.1 christos 1411 1.1 christos int 1412 1.1 christos variant_initialize() 1413 1.1 christos { 1414 1.1 christos int rc; 1415 1.1 christos 1416 1.1 christos variant.on_bi.bi_type = "variant"; 1417 1.1 christos variant.on_bi.bi_db_init = variant_db_init; 1418 1.1 christos variant.on_bi.bi_db_destroy = variant_db_destroy; 1419 1.1 christos 1420 1.1 christos variant.on_bi.bi_op_add = variant_op_add; 1421 1.1 christos variant.on_bi.bi_op_compare = variant_op_compare; 1422 1.1 christos variant.on_bi.bi_op_modify = variant_op_mod; 1423 1.1 christos variant.on_bi.bi_op_search = variant_op_search; 1424 1.1 christos 1425 1.1 christos variant.on_bi.bi_cf_ocs = variant_ocs; 1426 1.1 christos 1427 1.1 christos rc = config_register_schema( variant_cfg, variant_ocs ); 1428 1.1 christos if ( rc ) return rc; 1429 1.1 christos 1430 1.1 christos return overlay_register( &variant ); 1431 1.1 christos } 1432 1.1 christos 1433 1.1 christos #if SLAPD_OVER_VARIANT == SLAPD_MOD_DYNAMIC 1434 1.1 christos int 1435 1.1 christos init_module( int argc, char *argv[] ) 1436 1.1 christos { 1437 1.1 christos return variant_initialize(); 1438 1.1 christos } 1439 1.1 christos #endif 1440 1.1 christos 1441 1.1 christos #endif /* SLAPD_OVER_VARIANT */ 1442