1 /* $NetBSD: adremap.c,v 1.2 2021/08/14 16:14:50 christos Exp $ */ 2 3 /* adremap.c - Case-folding and DN-value remapping for AD proxies */ 4 /* $OpenLDAP$ */ 5 /* 6 * Copyright 2015 Howard Chu <hyc@symas.com>. 7 * All rights reserved. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted only as authorized by the OpenLDAP 11 * Public License. 12 * 13 * A copy of this license is available in the file LICENSE in the 14 * top-level directory of the distribution or, alternatively, at 15 * <http://www.OpenLDAP.org/license.html>. 16 */ 17 18 #include <sys/cdefs.h> 19 __RCSID("$NetBSD: adremap.c,v 1.2 2021/08/14 16:14:50 christos Exp $"); 20 21 #include "portable.h" 22 23 /* 24 * This file implements an overlay that performs two remapping functions 25 * to allow older POSIX clients to use Microsoft AD: 26 * 1: downcase the values of a configurable list of attributes 27 * 2: dereference some DN-valued attributes and convert to their simple names 28 * e.g. generate memberUid based on member 29 */ 30 31 #ifdef SLAPD_OVER_ADREMAP 32 33 #include <ldap.h> 34 #include "lutil.h" 35 #include "slap.h" 36 #include <ac/errno.h> 37 #include <ac/time.h> 38 #include <ac/string.h> 39 #include <ac/ctype.h> 40 #include "slap-config.h" 41 42 typedef struct adremap_dnv { 43 struct adremap_dnv *ad_next; 44 AttributeDescription *ad_dnattr; /* DN-valued attr to deref */ 45 AttributeDescription *ad_deref; /* target attr's value to retrieve */ 46 AttributeDescription *ad_newattr; /* New attr to collect new values */ 47 ObjectClass *ad_group; /* group objectclass on target */ 48 ObjectClass *ad_mapgrp; /* group objectclass to map */ 49 ObjectClass *ad_refgrp; /* objectclass of target DN */ 50 struct berval ad_refbase; /* base DN of target entries */ 51 } adremap_dnv; 52 /* example: member uid memberUid */ 53 54 typedef struct adremap_case { 55 struct adremap_case *ac_next; 56 AttributeDescription *ac_attr; 57 } adremap_case; 58 59 /* Per-instance configuration information */ 60 typedef struct adremap_info { 61 adremap_case *ai_case; /* attrs to downcase */ 62 adremap_dnv *ai_dnv; /* DN attrs to remap */ 63 } adremap_info; 64 65 enum { 66 ADREMAP_CASE = 1, 67 ADREMAP_DNV 68 }; 69 70 static ConfigDriver adremap_cf_case; 71 static ConfigDriver adremap_cf_dnv; 72 73 /* configuration attribute and objectclass */ 74 static ConfigTable adremapcfg[] = { 75 { "adremap-downcase", "attrs", 2, 0, 0, 76 ARG_MAGIC|ADREMAP_CASE, adremap_cf_case, 77 "( OLcfgCtAt:6.1 " 78 "NAME 'olcADremapDowncase' " 79 "DESC 'List of attributes to casefold to lower case' " 80 "EQUALITY caseIgnoreMatch " 81 "SYNTAX OMsDirectoryString )", NULL, NULL }, 82 { "adremap-dnmap", "dnattr targetattr newattr remoteOC localOC targetOC baseDN", 8, 8, 0, 83 ARG_MAGIC|ADREMAP_DNV, adremap_cf_dnv, 84 "( OLcfgCtAt:6.2 " 85 "NAME 'olcADremapDNmap' " 86 "DESC 'DN attr to map, attr from target to use, attr to generate, objectclass of remote" 87 " group, objectclass mapped group, objectclass of target entry, base DN of target entry' " 88 "EQUALITY caseIgnoreMatch " 89 "SYNTAX OMsDirectoryString )", NULL, NULL }, 90 { NULL, NULL, 0, 0, 0, ARG_IGNORED } 91 }; 92 93 static ConfigOCs adremapocs[] = { 94 { "( OLcfgCtOc:6.1 " 95 "NAME 'olcADremapConfig' " 96 "DESC 'AD remap configuration' " 97 "SUP olcOverlayConfig " 98 "MAY ( olcADremapDowncase $ olcADremapDNmap ) )", 99 Cft_Overlay, adremapcfg, NULL, NULL }, 100 { NULL, 0, NULL } 101 }; 102 103 static int 104 adremap_cf_case(ConfigArgs *c) 105 { 106 BackendDB *be = (BackendDB *)c->be; 107 slap_overinst *on = (slap_overinst *)c->bi; 108 adremap_info *ai = on->on_bi.bi_private; 109 adremap_case *ac, **a2; 110 int rc = ARG_BAD_CONF; 111 112 switch(c->op) { 113 case SLAP_CONFIG_EMIT: 114 for (ac = ai->ai_case; ac; ac=ac->ac_next) { 115 rc = value_add_one(&c->rvalue_vals, &ac->ac_attr->ad_cname); 116 if (rc) break; 117 } 118 break; 119 case LDAP_MOD_DELETE: 120 if (c->valx < 0) { 121 for (ac = ai->ai_case; ac; ac=ai->ai_case) { 122 ai->ai_case = ac->ac_next; 123 ch_free(ac); 124 } 125 } else { 126 int i; 127 for (i=0, a2 = &ai->ai_case; i<c->valx; i++, a2 = &(*a2)->ac_next); 128 ac = *a2; 129 *a2 = ac->ac_next; 130 ch_free(ac); 131 } 132 rc = 0; 133 break; 134 default: { 135 const char *text; 136 adremap_case ad; 137 ad.ac_attr = NULL; 138 rc = slap_str2ad(c->argv[1], &ad.ac_attr, &text); 139 if (rc) break; 140 for (a2 = &ai->ai_case; *a2; a2 = &(*a2)->ac_next); 141 ac = ch_malloc(sizeof(adremap_case)); 142 ac->ac_next = NULL; 143 ac->ac_attr = ad.ac_attr; 144 *a2 = ac; 145 break; 146 } 147 } 148 return rc; 149 } 150 151 static int 152 adremap_cf_dnv(ConfigArgs *c) 153 { 154 BackendDB *be = (BackendDB *)c->be; 155 slap_overinst *on = (slap_overinst *)c->bi; 156 adremap_info *ai = on->on_bi.bi_private; 157 adremap_dnv *ad, **a2; 158 int rc = ARG_BAD_CONF; 159 160 switch(c->op) { 161 case SLAP_CONFIG_EMIT: 162 for (ad = ai->ai_dnv; ad; ad=ad->ad_next) { 163 char *ptr; 164 struct berval bv; 165 bv.bv_len = ad->ad_dnattr->ad_cname.bv_len + ad->ad_deref->ad_cname.bv_len + ad->ad_newattr->ad_cname.bv_len + 2; 166 bv.bv_len += ad->ad_group->soc_cname.bv_len + ad->ad_mapgrp->soc_cname.bv_len + ad->ad_refgrp->soc_cname.bv_len + 3; 167 bv.bv_len += ad->ad_refbase.bv_len + 3; 168 bv.bv_val = ch_malloc(bv.bv_len + 1); 169 ptr = lutil_strcopy(bv.bv_val, ad->ad_dnattr->ad_cname.bv_val); 170 *ptr++ = ' '; 171 ptr = lutil_strcopy(ptr, ad->ad_deref->ad_cname.bv_val); 172 *ptr++ = ' '; 173 ptr = lutil_strcopy(ptr, ad->ad_newattr->ad_cname.bv_val); 174 *ptr++ = ' '; 175 ptr = lutil_strcopy(ptr, ad->ad_group->soc_cname.bv_val); 176 *ptr++ = ' '; 177 ptr = lutil_strcopy(ptr, ad->ad_mapgrp->soc_cname.bv_val); 178 *ptr++ = ' '; 179 ptr = lutil_strcopy(ptr, ad->ad_refgrp->soc_cname.bv_val); 180 *ptr++ = ' '; 181 *ptr++ = '"'; 182 ptr = lutil_strcopy(ptr, ad->ad_refbase.bv_val); 183 *ptr++ = '"'; 184 *ptr = '\0'; 185 ber_bvarray_add(&c->rvalue_vals, &bv); 186 } 187 if (ai->ai_dnv) rc = 0; 188 break; 189 case LDAP_MOD_DELETE: 190 if (c->valx < 0) { 191 for (ad = ai->ai_dnv; ad; ad=ai->ai_dnv) { 192 ai->ai_dnv = ad->ad_next; 193 ch_free(ad); 194 } 195 } else { 196 int i; 197 for (i=0, a2 = &ai->ai_dnv; i<c->valx; i++, a2 = &(*a2)->ad_next); 198 ad = *a2; 199 *a2 = ad->ad_next; 200 ch_free(ad); 201 } 202 rc = 0; 203 break; 204 default: { 205 const char *text; 206 adremap_dnv av = {0}; 207 struct berval dn; 208 rc = slap_str2ad(c->argv[1], &av.ad_dnattr, &text); 209 if (rc) break; 210 if (av.ad_dnattr->ad_type->sat_syntax != slap_schema.si_syn_distinguishedName) { 211 rc = 1; 212 snprintf(c->cr_msg, sizeof(c->cr_msg), "<%s> not a DN-valued attribute", 213 c->argv[0]); 214 Debug(LDAP_DEBUG_ANY, "%s: %s(%s)\n", c->log, c->cr_msg, c->argv[1]); 215 break; 216 } 217 rc = slap_str2ad(c->argv[2], &av.ad_deref, &text); 218 if (rc) break; 219 rc = slap_str2ad(c->argv[3], &av.ad_newattr, &text); 220 if (rc) break; 221 av.ad_group = oc_find(c->argv[4]); 222 if (!av.ad_group) { 223 rc = 1; 224 break; 225 } 226 av.ad_mapgrp = oc_find(c->argv[5]); 227 if (!av.ad_mapgrp) { 228 rc = 1; 229 break; 230 } 231 av.ad_refgrp = oc_find(c->argv[6]); 232 if (!av.ad_refgrp) { 233 rc = 1; 234 break; 235 } 236 ber_str2bv(c->argv[7], 0, 0, &dn); 237 rc = dnNormalize(0, NULL, NULL, &dn, &av.ad_refbase, NULL); 238 if (rc) break; 239 240 for (a2 = &ai->ai_dnv; *a2; a2 = &(*a2)->ad_next); 241 ad = ch_malloc(sizeof(adremap_dnv)); 242 ad->ad_next = NULL; 243 ad->ad_dnattr = av.ad_dnattr; 244 ad->ad_deref = av.ad_deref; 245 ad->ad_newattr = av.ad_newattr; 246 ad->ad_group = av.ad_group; 247 ad->ad_mapgrp = av.ad_mapgrp; 248 ad->ad_refgrp = av.ad_refgrp; 249 ad->ad_refbase = av.ad_refbase; 250 *a2 = ad; 251 break; 252 } 253 } 254 return rc; 255 } 256 257 typedef struct adremap_ctx { 258 slap_overinst *on; 259 AttributeName an; 260 AttributeDescription *ad; 261 int an_swap; 262 } adremap_ctx; 263 264 static int 265 adremap_search_resp( 266 Operation *op, 267 SlapReply *rs 268 ) 269 { 270 adremap_ctx *ctx = op->o_callback->sc_private; 271 slap_overinst *on = ctx->on; 272 adremap_info *ai = on->on_bi.bi_private; 273 adremap_case *ac; 274 adremap_dnv *ad; 275 Attribute *a; 276 Entry *e; 277 278 if (rs->sr_type != REP_SEARCH) 279 return SLAP_CB_CONTINUE; 280 281 /* we munged the attr list, restore it to original */ 282 if (ctx->an_swap) { 283 int i; 284 ctx->an_swap = 0; 285 for (i=0; rs->sr_attrs[i].an_name.bv_val; i++) { 286 if (rs->sr_attrs[i].an_desc == ctx->ad) { 287 rs->sr_attrs[i] = ctx->an; 288 break; 289 } 290 } 291 /* Usually rs->sr_attrs is just op->ors_attrs, but 292 * overlays like rwm may make a new copy. Fix both 293 * if needed. 294 */ 295 if (op->ors_attrs != rs->sr_attrs) { 296 for (i=0; op->ors_attrs[i].an_name.bv_val; i++) { 297 if (op->ors_attrs[i].an_desc == ctx->ad) { 298 op->ors_attrs[i] = ctx->an; 299 break; 300 } 301 } 302 } 303 } 304 e = rs->sr_entry; 305 for (ac = ai->ai_case; ac; ac = ac->ac_next) { 306 a = attr_find(e->e_attrs, ac->ac_attr); 307 if (a) { 308 int i, j; 309 if (!(rs->sr_flags & REP_ENTRY_MODIFIABLE)) { 310 e = entry_dup(e); 311 rs_replace_entry(op, rs, on, e); 312 rs->sr_flags |= REP_ENTRY_MODIFIABLE|REP_ENTRY_MUSTBEFREED; 313 a = attr_find(e->e_attrs, ac->ac_attr); 314 } 315 for (i=0; i<a->a_numvals; i++) { 316 unsigned char *c = a->a_vals[i].bv_val; 317 for (j=0; j<a->a_vals[i].bv_len; j++) 318 if (isupper(c[j])) 319 c[j] = tolower(c[j]); 320 } 321 } 322 } 323 for (ad = ai->ai_dnv; ad; ad = ad->ad_next) { 324 a = attr_find(e->e_attrs, ad->ad_dnattr); 325 if (a) { 326 Entry *n; 327 Attribute *dr; 328 int i, rc; 329 if (!(rs->sr_flags & REP_ENTRY_MODIFIABLE)) { 330 e = entry_dup(e); 331 rs_replace_entry(op, rs, on, e); 332 rs->sr_flags |= REP_ENTRY_MODIFIABLE|REP_ENTRY_MUSTBEFREED; 333 a = attr_find(e->e_attrs, ad->ad_dnattr); 334 } 335 for (i=0; i<a->a_numvals; i++) { 336 struct berval dv; 337 dv = ad->ad_deref->ad_cname; 338 /* If the RDN uses the deref attr, just use it directly */ 339 if (a->a_nvals[i].bv_val[dv.bv_len] == '=' && 340 !memcmp(a->a_nvals[i].bv_val, dv.bv_val, dv.bv_len)) { 341 struct berval bv, nv; 342 char *ptr; 343 bv = a->a_vals[i]; 344 nv = a->a_nvals[i]; 345 bv.bv_val += dv.bv_len + 1; 346 ptr = strchr(bv.bv_val, ','); 347 if (ptr) 348 bv.bv_len = ptr - bv.bv_val; 349 else 350 bv.bv_len -= dv.bv_len+1; 351 nv.bv_val += dv.bv_len + 1; 352 ptr = strchr(nv.bv_val, ','); 353 if (ptr) 354 nv.bv_len = ptr - nv.bv_val; 355 else 356 nv.bv_len -= dv.bv_len+1; 357 attr_merge_one(e, ad->ad_newattr, &bv, &nv); 358 } else { 359 /* otherwise look up the deref attr */ 360 n = NULL; 361 rc = be_entry_get_rw(op, &a->a_nvals[i], NULL, ad->ad_deref, 0, &n); 362 if (!rc && n) { 363 dr = attr_find(n->e_attrs, ad->ad_deref); 364 if (dr) 365 attr_merge_one(e, ad->ad_newattr, dr->a_vals, dr->a_nvals); 366 be_entry_release_r(op, n); 367 } 368 } 369 } 370 } 371 } 372 return SLAP_CB_CONTINUE; 373 } 374 375 static int adremap_refsearch( 376 Operation *op, 377 SlapReply *rs 378 ) 379 { 380 if (rs->sr_type == REP_SEARCH) { 381 slap_callback *sc = op->o_callback; 382 struct berval *dn = sc->sc_private; 383 ber_dupbv_x(dn, &rs->sr_entry->e_nname, op->o_tmpmemctx); 384 return LDAP_SUCCESS; 385 } 386 return rs->sr_err; 387 } 388 389 static adremap_dnv *adremap_filter( 390 Operation *op, 391 adremap_info *ai 392 ) 393 { 394 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info; 395 Filter *f = op->ors_filter, *fn = NULL; 396 adremap_dnv *ad = NULL; 397 struct berval bv; 398 int fextra = 0; 399 400 /* Do we need to munge the filter? First see if it's of 401 * the form (objectClass=<mapgrp>) 402 * or form (&(objectClass=<mapgrp>)...) 403 * or form (&(&(objectClass=<mapgrp>)...)...) 404 */ 405 if (f->f_choice == LDAP_FILTER_AND && f->f_and) { 406 fextra = 1; 407 f = f->f_and; 408 fn = f->f_next; 409 } 410 if (f->f_choice == LDAP_FILTER_AND && f->f_and) { 411 fextra = 2; 412 f = f->f_and; 413 } 414 if (f->f_choice == LDAP_FILTER_EQUALITY && 415 f->f_av_desc == slap_schema.si_ad_objectClass) { 416 struct berval bv = f->f_av_value; 417 418 for (ad = ai->ai_dnv; ad; ad = ad->ad_next) { 419 if (!ber_bvstrcasecmp( &bv, &ad->ad_mapgrp->soc_cname )) { 420 /* Now check to see if next element is (<newattr>=foo) */ 421 Filter *fnew; 422 if (fn && fn->f_choice == LDAP_FILTER_EQUALITY && 423 fn->f_av_desc == ad->ad_newattr) { 424 Filter fr[3]; 425 AttributeAssertion aa[2] = {0}; 426 Operation op2; 427 slap_callback cb = {0}; 428 SlapReply rs = {REP_RESULT}; 429 struct berval dn = BER_BVNULL; 430 431 /* It's a match, setup a search with filter 432 * (&(objectclass=<refgrp>)(<deref>=foo)) 433 */ 434 fr[0].f_choice = LDAP_FILTER_AND; 435 fr[0].f_and = &fr[1]; 436 fr[0].f_next = NULL; 437 438 fr[1].f_choice = LDAP_FILTER_EQUALITY; 439 fr[1].f_ava = &aa[0]; 440 fr[1].f_av_desc = slap_schema.si_ad_objectClass; 441 fr[1].f_av_value = ad->ad_refgrp->soc_cname; 442 fr[1].f_next = &fr[2]; 443 444 fr[2].f_choice = LDAP_FILTER_EQUALITY; 445 fr[2].f_ava = &aa[1]; 446 fr[2].f_av_desc = ad->ad_deref; 447 fr[2].f_av_value = fn->f_av_value; 448 fr[2].f_next = NULL; 449 450 /* Search with this filter to retrieve target DN */ 451 op2 = *op; 452 op2.o_callback = &cb; 453 cb.sc_response = adremap_refsearch; 454 cb.sc_private = &dn; 455 op2.o_req_dn = ad->ad_refbase; 456 op2.o_req_ndn = ad->ad_refbase; 457 op2.ors_filter = fr; 458 filter2bv_x(op, fr, &op2.ors_filterstr); 459 op2.ors_deref = LDAP_DEREF_NEVER; 460 op2.ors_slimit = 1; 461 op2.ors_tlimit = SLAP_NO_LIMIT; 462 op2.ors_attrs = slap_anlist_no_attrs; 463 op2.ors_attrsonly = 1; 464 op2.o_no_schema_check = 1; 465 op2.o_bd->bd_info = (BackendInfo *)on->on_info; 466 op2.o_bd->be_search(&op2, &rs); 467 op2.o_bd->bd_info = (BackendInfo *)on; 468 op->o_tmpfree(op2.ors_filterstr.bv_val, op->o_tmpmemctx); 469 470 if (!dn.bv_len) { /* no match was found */ 471 ad = NULL; 472 break; 473 } 474 475 if (rs.sr_err) { /* sizelimit exceeded, etc.: invalid name */ 476 op->o_tmpfree(dn.bv_val, op->o_tmpmemctx); 477 ad = NULL; 478 break; 479 } 480 481 /* Build a new filter of form 482 * (&(objectclass=<group>)(<dnattr>=foo-DN)...) 483 */ 484 f = op->o_tmpalloc(sizeof(Filter), op->o_tmpmemctx); 485 f->f_choice = LDAP_FILTER_AND; 486 fnew = f; 487 f->f_next = NULL; 488 489 f->f_and = op->o_tmpalloc(sizeof(Filter), op->o_tmpmemctx); 490 f = f->f_and; 491 f->f_choice = LDAP_FILTER_EQUALITY; 492 f->f_ava = op->o_tmpcalloc(1, sizeof(AttributeAssertion), op->o_tmpmemctx); 493 f->f_av_desc = slap_schema.si_ad_objectClass; 494 ber_dupbv_x(&f->f_av_value, &ad->ad_group->soc_cname, op->o_tmpmemctx); 495 496 f->f_next = op->o_tmpalloc(sizeof(Filter), op->o_tmpmemctx); 497 f = f->f_next; 498 f->f_choice = LDAP_FILTER_EQUALITY; 499 f->f_ava = op->o_tmpcalloc(1, sizeof(AttributeAssertion), op->o_tmpmemctx); 500 f->f_av_desc = ad->ad_dnattr; 501 f->f_av_value = dn; 502 503 f->f_next = fn->f_next; 504 fn->f_next = NULL; 505 } else { 506 /* Build a new filter of form 507 * (objectclass=<group>) 508 */ 509 f->f_next = NULL; /* disconnect old chain */ 510 511 f = op->o_tmpalloc(sizeof(Filter), op->o_tmpmemctx); 512 f->f_choice = LDAP_FILTER_EQUALITY; 513 f->f_ava = op->o_tmpcalloc(1, sizeof(AttributeAssertion), op->o_tmpmemctx); 514 f->f_av_desc = slap_schema.si_ad_objectClass; 515 ber_dupbv_x(&f->f_av_value, &ad->ad_group->soc_cname, op->o_tmpmemctx); 516 517 /* If there was a wrapping (&), attach it. */ 518 if (fextra) { 519 fnew = op->o_tmpalloc(sizeof(Filter), op->o_tmpmemctx); 520 fnew->f_choice = LDAP_FILTER_AND; 521 fnew->f_and = f; 522 fnew->f_next = NULL; 523 f->f_next = fn; 524 } else { 525 fnew = f; 526 f->f_next = NULL; 527 } 528 } 529 if (fextra > 1) { 530 f = op->o_tmpalloc(sizeof(Filter), op->o_tmpmemctx); 531 f->f_choice = LDAP_FILTER_AND; 532 f->f_and = fnew->f_and; 533 f->f_next = f->f_and->f_next; 534 f->f_and->f_next = op->ors_filter->f_and->f_and->f_next; 535 op->ors_filter->f_and->f_and->f_next = NULL; 536 fnew->f_and = f; 537 } 538 filter_free_x(op, op->ors_filter, 1); 539 op->o_tmpfree(op->ors_filterstr.bv_val, op->o_tmpmemctx); 540 op->ors_filter = fnew; 541 filter2bv_x(op, op->ors_filter, &op->ors_filterstr); 542 break; 543 } 544 } 545 } 546 return ad; 547 } 548 549 static int 550 adremap_search( 551 Operation *op, 552 SlapReply *rs 553 ) 554 { 555 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info; 556 adremap_info *ai = (adremap_info *) on->on_bi.bi_private; 557 adremap_ctx *ctx; 558 adremap_dnv *ad = NULL; 559 slap_callback *cb; 560 561 /* Is this our own internal search? Ignore it */ 562 if (op->o_no_schema_check) 563 return SLAP_CB_CONTINUE; 564 565 if (ai->ai_dnv) 566 /* check for filter match, fallthru if none */ 567 ad = adremap_filter(op, ai); 568 569 cb = op->o_tmpcalloc(1, sizeof(slap_callback)+sizeof(adremap_ctx), op->o_tmpmemctx); 570 cb->sc_response = adremap_search_resp; 571 cb->sc_private = cb+1; 572 cb->sc_next = op->o_callback; 573 op->o_callback = cb; 574 ctx = cb->sc_private; 575 ctx->on = on; 576 if (ad && op->ors_attrs) { /* see if we need to remap a search attr */ 577 int i; 578 for (i=0; op->ors_attrs[i].an_name.bv_val; i++) { 579 if (op->ors_attrs[i].an_desc == ad->ad_newattr) { 580 ctx->an_swap = 1; 581 ctx->ad = ad->ad_dnattr; 582 ctx->an = op->ors_attrs[i]; 583 op->ors_attrs[i].an_desc = ad->ad_dnattr; 584 op->ors_attrs[i].an_name = ad->ad_dnattr->ad_cname; 585 break; 586 } 587 } 588 } 589 return SLAP_CB_CONTINUE; 590 } 591 592 static int 593 adremap_db_init( 594 BackendDB *be, 595 ConfigReply *cr 596 ) 597 { 598 slap_overinst *on = (slap_overinst *) be->bd_info; 599 600 /* initialize private structure to store configuration */ 601 on->on_bi.bi_private = ch_calloc( 1, sizeof(adremap_info) ); 602 603 return 0; 604 } 605 606 static int 607 adremap_db_destroy( 608 BackendDB *be, 609 ConfigReply *cr 610 ) 611 { 612 slap_overinst *on = (slap_overinst *) be->bd_info; 613 adremap_info *ai = (adremap_info *) on->on_bi.bi_private; 614 adremap_case *ac; 615 adremap_dnv *ad; 616 617 /* free config */ 618 for (ac = ai->ai_case; ac; ac = ai->ai_case) { 619 ai->ai_case = ac->ac_next; 620 ch_free(ac); 621 } 622 for (ad = ai->ai_dnv; ad; ad = ai->ai_dnv) { 623 ai->ai_dnv = ad->ad_next; 624 ch_free(ad); 625 } 626 free( ai ); 627 628 return 0; 629 } 630 631 static slap_overinst adremap; 632 633 int adremap_initialize() 634 { 635 int i, code; 636 637 adremap.on_bi.bi_type = "adremap"; 638 adremap.on_bi.bi_flags = SLAPO_BFLAG_SINGLE; 639 adremap.on_bi.bi_db_init = adremap_db_init; 640 adremap.on_bi.bi_db_destroy = adremap_db_destroy; 641 adremap.on_bi.bi_op_search = adremap_search; 642 643 /* register configuration directives */ 644 adremap.on_bi.bi_cf_ocs = adremapocs; 645 code = config_register_schema( adremapcfg, adremapocs ); 646 if ( code ) return code; 647 648 return overlay_register( &adremap ); 649 } 650 651 #if SLAPD_OVER_ADREMAP == SLAPD_MOD_DYNAMIC 652 int init_module(int argc, char *argv[]) { 653 return adremap_initialize(); 654 } 655 #endif 656 657 #endif /* defined(SLAPD_OVER_ADREMAP) */ 658