adremap.c revision 1.1 1 1.1 christos /* $NetBSD: adremap.c,v 1.1 2021/08/14 16:05:15 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.1 2021/08/14 16:05:15 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