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