Home | History | Annotate | Line # | Download | only in adremap
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