mirror of
https://git.openldap.org/openldap/openldap.git
synced 2024-12-03 02:41:24 +08:00
New ADremap overlay
This commit is contained in:
parent
e4278b5731
commit
b6208a4474
@ -5,3 +5,4 @@ OLcfgCt{Oc|At}:2 autogroup
|
||||
OLcfgCt{Oc|At}:3 nssov
|
||||
OLcfgCt{Oc|At}:4 cloak
|
||||
OLcfgCt{Oc|At}:5 lastbind
|
||||
OLcfgCt{Oc|At}:6 adremap
|
||||
|
56
contrib/slapd-modules/adremap/Makefile
Normal file
56
contrib/slapd-modules/adremap/Makefile
Normal file
@ -0,0 +1,56 @@
|
||||
# $OpenLDAP$
|
||||
# Copyright 2015 Howard Chu <hyc@symas.com>
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted only as authorized by the OpenLDAP
|
||||
# Public License.
|
||||
#
|
||||
# A copy of this license is available in the file LICENSE in the
|
||||
# top-level directory of the distribution or, alternatively, at
|
||||
# <http://www.OpenLDAP.org/license.html>.
|
||||
|
||||
LDAP_SRC = ../../..
|
||||
LDAP_BUILD = $(LDAP_SRC)
|
||||
LDAP_INC = -I$(LDAP_BUILD)/include -I$(LDAP_SRC)/include -I$(LDAP_SRC)/servers/slapd
|
||||
LDAP_LIB = $(LDAP_BUILD)/libraries/libldap_r/libldap_r.la \
|
||||
$(LDAP_BUILD)/libraries/liblber/liblber.la
|
||||
|
||||
LIBTOOL = $(LDAP_BUILD)/libtool
|
||||
CC = gcc
|
||||
OPT = -g -O2 -Wall
|
||||
DEFS = -DSLAPD_OVER_ADREMAP=SLAPD_MOD_DYNAMIC
|
||||
INCS = $(LDAP_INC)
|
||||
LIBS = $(LDAP_LIB)
|
||||
|
||||
PROGRAMS = adremap.la
|
||||
LTVER = 0:0:0
|
||||
|
||||
prefix=/usr/local
|
||||
exec_prefix=$(prefix)
|
||||
ldap_subdir=/openldap
|
||||
|
||||
libdir=$(exec_prefix)/lib
|
||||
libexecdir=$(exec_prefix)/libexec
|
||||
moduledir = $(libexecdir)$(ldap_subdir)
|
||||
|
||||
.SUFFIXES: .c .o .lo
|
||||
|
||||
.c.lo:
|
||||
$(LIBTOOL) --mode=compile $(CC) $(OPT) $(DEFS) $(INCS) -c $<
|
||||
|
||||
all: $(PROGRAMS)
|
||||
|
||||
adremap.la: adremap.lo
|
||||
$(LIBTOOL) --mode=link $(CC) $(OPT) -version-info $(LTVER) \
|
||||
-rpath $(moduledir) -module -o $@ $? $(LIBS)
|
||||
|
||||
clean:
|
||||
rm -rf *.o *.lo *.la .libs
|
||||
|
||||
install: $(PROGRAMS)
|
||||
mkdir -p $(DESTDIR)$(moduledir)
|
||||
for p in $(PROGRAMS) ; do \
|
||||
$(LIBTOOL) --mode=install cp $$p $(DESTDIR)$(moduledir) ; \
|
||||
done
|
||||
|
352
contrib/slapd-modules/adremap/adremap.c
Normal file
352
contrib/slapd-modules/adremap/adremap.c
Normal file
@ -0,0 +1,352 @@
|
||||
/* adremap.c - Case-folding and DN-value remapping for AD proxies */
|
||||
/* $OpenLDAP$ */
|
||||
/*
|
||||
* Copyright 2015 Howard Chu <hyc@symas.com>.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted only as authorized by the OpenLDAP
|
||||
* Public License.
|
||||
*
|
||||
* A copy of this license is available in the file LICENSE in the
|
||||
* top-level directory of the distribution or, alternatively, at
|
||||
* <http://www.OpenLDAP.org/license.html>.
|
||||
*/
|
||||
|
||||
#include "portable.h"
|
||||
|
||||
/*
|
||||
* This file implements an overlay that performs two remapping functions
|
||||
* to allow older POSIX clients to use Microsoft AD:
|
||||
* 1: downcase the values of a configurable list of attributes
|
||||
* 2: dereference some DN-valued attributes and convert to their simple names
|
||||
* e.g. generate memberUid based on member
|
||||
*/
|
||||
|
||||
#ifdef SLAPD_OVER_ADREMAP
|
||||
|
||||
#include <ldap.h>
|
||||
#include "lutil.h"
|
||||
#include "slap.h"
|
||||
#include <ac/errno.h>
|
||||
#include <ac/time.h>
|
||||
#include <ac/string.h>
|
||||
#include <ac/ctype.h>
|
||||
#include "config.h"
|
||||
|
||||
typedef struct adremap_dnv {
|
||||
struct adremap_dnv *ad_next;
|
||||
AttributeDescription *ad_dnattr; /* DN-valued attr to deref */
|
||||
AttributeDescription *ad_deref; /* target attr's value to retrieve */
|
||||
AttributeDescription *ad_newattr; /* New attr to collect new values */
|
||||
} adremap_dnv;
|
||||
/* example: member uid memberUid */
|
||||
|
||||
typedef struct adremap_case {
|
||||
struct adremap_case *ac_next;
|
||||
AttributeDescription *ac_attr;
|
||||
} adremap_case;
|
||||
|
||||
/* Per-instance configuration information */
|
||||
typedef struct adremap_info {
|
||||
adremap_case *ai_case; /* attrs to downcase */
|
||||
adremap_dnv *ai_dnv; /* DN attrs to remap */
|
||||
} adremap_info;
|
||||
|
||||
enum {
|
||||
ADREMAP_CASE = 1,
|
||||
ADREMAP_DNV
|
||||
};
|
||||
|
||||
static ConfigDriver adremap_cf_case;
|
||||
static ConfigDriver adremap_cf_dnv;
|
||||
|
||||
/* configuration attribute and objectclass */
|
||||
static ConfigTable adremapcfg[] = {
|
||||
{ "adremap-downcase", "attrs", 2, 0, 0,
|
||||
ARG_MAGIC|ADREMAP_CASE, adremap_cf_case,
|
||||
"( OLcfgCtAt:6.1 "
|
||||
"NAME 'olcADremapDowncase' "
|
||||
"DESC 'List of attributes to casefold to lower case' "
|
||||
"SYNTAX OMsDirectoryString )", NULL, NULL },
|
||||
{ "adremap-dnmap", "dnattr simpleattr newattr", 4, 4, 0,
|
||||
ARG_MAGIC|ADREMAP_DNV, adremap_cf_dnv,
|
||||
"( OLcfgCtAt:6.2 "
|
||||
"NAME 'olcADremapDNmap' "
|
||||
"DESC 'DN attr to map, attr from target to use, attr to generate' "
|
||||
"SYNTAX OMsDirectoryString )", NULL, NULL },
|
||||
{ NULL, NULL, 0, 0, 0, ARG_IGNORED }
|
||||
};
|
||||
|
||||
static ConfigOCs adremapocs[] = {
|
||||
{ "( OLcfgCtOc:6.1 "
|
||||
"NAME 'olcADremapConfig' "
|
||||
"DESC 'AD remap configuration' "
|
||||
"SUP olcOverlayConfig "
|
||||
"MAY ( olcADremapDowncase $ olcADremapDNmap ) )",
|
||||
Cft_Overlay, adremapcfg, NULL, NULL },
|
||||
{ NULL, 0, NULL }
|
||||
};
|
||||
|
||||
static int
|
||||
adremap_cf_case(ConfigArgs *c)
|
||||
{
|
||||
BackendDB *be = (BackendDB *)c->be;
|
||||
slap_overinst *on = (slap_overinst *)c->bi;
|
||||
adremap_info *ai = on->on_bi.bi_private;
|
||||
adremap_case *ac, **a2;
|
||||
int rc = ARG_BAD_CONF;
|
||||
|
||||
switch(c->op) {
|
||||
case SLAP_CONFIG_EMIT:
|
||||
for (ac = ai->ai_case; ac; ac=ac->ac_next) {
|
||||
rc = value_add_one(&c->rvalue_vals, &ac->ac_attr->ad_cname);
|
||||
if (rc) break;
|
||||
}
|
||||
break;
|
||||
case LDAP_MOD_DELETE:
|
||||
if (c->valx < 0) {
|
||||
for (ac = ai->ai_case; ac; ac=ai->ai_case) {
|
||||
ai->ai_case = ac->ac_next;
|
||||
ch_free(ac);
|
||||
}
|
||||
} else {
|
||||
int i;
|
||||
for (i=0, a2 = &ai->ai_case; i<c->valx; i++, a2 = &(*a2)->ac_next);
|
||||
ac = *a2;
|
||||
*a2 = ac->ac_next;
|
||||
ch_free(ac);
|
||||
}
|
||||
rc = 0;
|
||||
break;
|
||||
default: {
|
||||
const char *text;
|
||||
adremap_case ad;
|
||||
ad.ac_attr = NULL;
|
||||
rc = slap_str2ad(c->argv[1], &ad.ac_attr, &text);
|
||||
if (rc) break;
|
||||
for (a2 = &ai->ai_case; *a2; a2 = &(*a2)->ac_next);
|
||||
ac = ch_malloc(sizeof(adremap_case));
|
||||
ac->ac_next = NULL;
|
||||
ac->ac_attr = ad.ac_attr;
|
||||
*a2 = ac;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int
|
||||
adremap_cf_dnv(ConfigArgs *c)
|
||||
{
|
||||
BackendDB *be = (BackendDB *)c->be;
|
||||
slap_overinst *on = (slap_overinst *)c->bi;
|
||||
adremap_info *ai = on->on_bi.bi_private;
|
||||
adremap_dnv *ad, **a2;
|
||||
int rc = ARG_BAD_CONF;
|
||||
|
||||
switch(c->op) {
|
||||
case SLAP_CONFIG_EMIT:
|
||||
for (ad = ai->ai_dnv; ad; ad=ad->ad_next) {
|
||||
char *ptr;
|
||||
struct berval bv;
|
||||
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;
|
||||
bv.bv_val = ch_malloc(bv.bv_len + 1);
|
||||
ptr = lutil_strcopy(bv.bv_val, ad->ad_dnattr->ad_cname.bv_val);
|
||||
*ptr++ = ' ';
|
||||
ptr = lutil_strcopy(ptr, ad->ad_deref->ad_cname.bv_val);
|
||||
*ptr++ = ' ';
|
||||
strcpy(ptr, ad->ad_newattr->ad_cname.bv_val);
|
||||
ber_bvarray_add(&c->rvalue_vals, &bv);
|
||||
}
|
||||
if (ai->ai_dnv) rc = 0;
|
||||
break;
|
||||
case LDAP_MOD_DELETE:
|
||||
if (c->valx < 0) {
|
||||
for (ad = ai->ai_dnv; ad; ad=ai->ai_dnv) {
|
||||
ai->ai_dnv = ad->ad_next;
|
||||
ch_free(ad);
|
||||
}
|
||||
} else {
|
||||
int i;
|
||||
for (i=0, a2 = &ai->ai_dnv; i<c->valx; i++, a2 = &(*a2)->ad_next);
|
||||
ad = *a2;
|
||||
*a2 = ad->ad_next;
|
||||
ch_free(ad);
|
||||
}
|
||||
rc = 0;
|
||||
break;
|
||||
default: {
|
||||
const char *text;
|
||||
adremap_dnv av = {0};
|
||||
rc = slap_str2ad(c->argv[1], &av.ad_dnattr, &text);
|
||||
if (rc) break;
|
||||
if (av.ad_dnattr->ad_type->sat_syntax != slap_schema.si_syn_distinguishedName) {
|
||||
rc = 1;
|
||||
snprintf(c->cr_msg, sizeof(c->cr_msg), "<%s> not a DN-valued attribute",
|
||||
c->argv[0]);
|
||||
Debug(LDAP_DEBUG_ANY, "%s: %s(%s)\n", c->log, c->cr_msg, c->argv[1]);
|
||||
break;
|
||||
}
|
||||
rc = slap_str2ad(c->argv[2], &av.ad_deref, &text);
|
||||
if (rc) break;
|
||||
rc = slap_str2ad(c->argv[3], &av.ad_newattr, &text);
|
||||
if (rc) break;
|
||||
|
||||
for (a2 = &ai->ai_dnv; *a2; a2 = &(*a2)->ad_next);
|
||||
ad = ch_malloc(sizeof(adremap_dnv));
|
||||
ad->ad_next = NULL;
|
||||
ad->ad_dnattr = av.ad_dnattr;
|
||||
ad->ad_deref = av.ad_deref;
|
||||
ad->ad_newattr = av.ad_newattr;
|
||||
*a2 = ad;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int
|
||||
adremap_search_resp(
|
||||
Operation *op,
|
||||
SlapReply *rs
|
||||
)
|
||||
{
|
||||
slap_overinst *on = op->o_callback->sc_private;
|
||||
adremap_info *ai = on->on_bi.bi_private;
|
||||
adremap_case *ac;
|
||||
adremap_dnv *ad;
|
||||
Attribute *a;
|
||||
Entry *e;
|
||||
|
||||
if (rs->sr_type != REP_SEARCH)
|
||||
return SLAP_CB_CONTINUE;
|
||||
|
||||
e = rs->sr_entry;
|
||||
for (ac = ai->ai_case; ac; ac = ac->ac_next) {
|
||||
a = attr_find(e->e_attrs, ac->ac_attr);
|
||||
if (a) {
|
||||
int i, j;
|
||||
if (!(rs->sr_flags & REP_ENTRY_MODIFIABLE)) {
|
||||
e = entry_dup(e);
|
||||
rs_replace_entry(op, rs, on, e);
|
||||
rs->sr_flags |= REP_ENTRY_MODIFIABLE|REP_ENTRY_MUSTBEFREED;
|
||||
a = attr_find(e->e_attrs, ac->ac_attr);
|
||||
}
|
||||
for (i=0; i<a->a_numvals; i++) {
|
||||
unsigned char *c = a->a_vals[i].bv_val;
|
||||
for (j=0; j<a->a_vals[i].bv_len; j++)
|
||||
if (isupper(c[j]))
|
||||
c[j] = tolower(c[j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
for (ad = ai->ai_dnv; ad; ad = ad->ad_next) {
|
||||
a = attr_find(e->e_attrs, ad->ad_dnattr);
|
||||
if (a) {
|
||||
Entry *n;
|
||||
Attribute *dr;
|
||||
int i, rc;
|
||||
if (!(rs->sr_flags & REP_ENTRY_MODIFIABLE)) {
|
||||
e = entry_dup(e);
|
||||
rs_replace_entry(op, rs, on, e);
|
||||
rs->sr_flags |= REP_ENTRY_MODIFIABLE|REP_ENTRY_MUSTBEFREED;
|
||||
a = attr_find(e->e_attrs, ad->ad_dnattr);
|
||||
}
|
||||
for (i=0; i<a->a_numvals; i++) {
|
||||
n = NULL;
|
||||
rc = be_entry_get_rw(op, &a->a_nvals[i], NULL, ad->ad_deref, 0, &n);
|
||||
if (!rc && n) {
|
||||
dr = attr_find(n->e_attrs, ad->ad_deref);
|
||||
if (dr)
|
||||
attr_merge_one(e, ad->ad_newattr, dr->a_vals, dr->a_nvals);
|
||||
be_entry_release_r(op, n);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return SLAP_CB_CONTINUE;
|
||||
}
|
||||
|
||||
static int
|
||||
adremap_search(
|
||||
Operation *op,
|
||||
SlapReply *rs
|
||||
)
|
||||
{
|
||||
slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
|
||||
slap_callback *cb;
|
||||
|
||||
cb = op->o_tmpcalloc(1, sizeof(slap_callback), op->o_tmpmemctx);
|
||||
cb->sc_response = adremap_search_resp;
|
||||
cb->sc_private = on;
|
||||
cb->sc_next = op->o_callback;
|
||||
op->o_callback = cb;
|
||||
return SLAP_CB_CONTINUE;
|
||||
}
|
||||
|
||||
static int
|
||||
adremap_db_init(
|
||||
BackendDB *be,
|
||||
ConfigReply *cr
|
||||
)
|
||||
{
|
||||
slap_overinst *on = (slap_overinst *) be->bd_info;
|
||||
|
||||
/* initialize private structure to store configuration */
|
||||
on->on_bi.bi_private = ch_calloc( 1, sizeof(adremap_info) );
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
adremap_db_destroy(
|
||||
BackendDB *be,
|
||||
ConfigReply *cr
|
||||
)
|
||||
{
|
||||
slap_overinst *on = (slap_overinst *) be->bd_info;
|
||||
adremap_info *ai = (adremap_info *) on->on_bi.bi_private;
|
||||
adremap_case *ac;
|
||||
adremap_dnv *ad;
|
||||
|
||||
/* free config */
|
||||
for (ac = ai->ai_case; ac; ac = ai->ai_case) {
|
||||
ai->ai_case = ac->ac_next;
|
||||
ch_free(ac);
|
||||
}
|
||||
for (ad = ai->ai_dnv; ad; ad = ai->ai_dnv) {
|
||||
ai->ai_dnv = ad->ad_next;
|
||||
ch_free(ad);
|
||||
}
|
||||
free( ai );
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static slap_overinst adremap;
|
||||
|
||||
int adremap_initialize()
|
||||
{
|
||||
int i, code;
|
||||
|
||||
adremap.on_bi.bi_type = "adremap";
|
||||
adremap.on_bi.bi_db_init = adremap_db_init;
|
||||
adremap.on_bi.bi_db_destroy = adremap_db_destroy;
|
||||
adremap.on_bi.bi_op_search = adremap_search;
|
||||
|
||||
/* register configuration directives */
|
||||
adremap.on_bi.bi_cf_ocs = adremapocs;
|
||||
code = config_register_schema( adremapcfg, adremapocs );
|
||||
if ( code ) return code;
|
||||
|
||||
return overlay_register( &adremap );
|
||||
}
|
||||
|
||||
#if SLAPD_OVER_ADREMAP == SLAPD_MOD_DYNAMIC
|
||||
int init_module(int argc, char *argv[]) {
|
||||
return adremap_initialize();
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* defined(SLAPD_OVER_ADREMAP) */
|
94
contrib/slapd-modules/adremap/slapo-adremap.5
Normal file
94
contrib/slapd-modules/adremap/slapo-adremap.5
Normal file
@ -0,0 +1,94 @@
|
||||
.TH SLAPO-ADREMAP 5 "RELEASEDATE" "OpenLDAP LDVERSION"
|
||||
.\" Copyright 2015 Howard Chu, All Rights Reserved.
|
||||
.\" $OpenLDAP$
|
||||
.SH NAME
|
||||
slapo-adremap \- AD Remap overlay to slapd
|
||||
.SH SYNOPSIS
|
||||
ETCDIR/slapd.conf
|
||||
.SH DESCRIPTION
|
||||
The
|
||||
.B adremap
|
||||
overlay to
|
||||
.BR slapd (8)
|
||||
remaps some attribute values for compatibility between Microsoft AD
|
||||
and older POSIX systems' PAM/NSS clients. It can be configured to
|
||||
convert values of given attributes to lower case, and it can be
|
||||
configured to generate RFC2307-compliant group memberships based
|
||||
on RFC2307bis groups. All mapping is only performed on entries
|
||||
returned as search responses.
|
||||
|
||||
.SH CONFIGURATION
|
||||
The config directives that are specific to the
|
||||
.B adremap
|
||||
overlay must be prefixed by
|
||||
.BR adremap\- ,
|
||||
to avoid potential conflicts with directives specific to the underlying
|
||||
database or to other stacked overlays.
|
||||
|
||||
.TP
|
||||
.B overlay adremap
|
||||
This directive adds the
|
||||
.B adremap
|
||||
overlay to the current database, see
|
||||
.BR slapd.conf (5)
|
||||
for details.
|
||||
|
||||
.LP
|
||||
These
|
||||
.B slapd.conf
|
||||
configuration options are defined for the adremap overlay. They must
|
||||
appear after the
|
||||
.B overlay
|
||||
directive. They can each be specified multiple times:
|
||||
.TP
|
||||
.B adremap-downcase <attr>
|
||||
Specify an attributeType whose values will all be mapped to lowercase
|
||||
when returned in search responses.
|
||||
.TP
|
||||
.B adremap-dnmap <dnattr> <derefattr> <newattr>
|
||||
Specify a DN-valued attributeType whose values will be dereferenced. The
|
||||
.B <derefattr>
|
||||
of the target entry will be retrieved and its value will be added to the
|
||||
.B <newattr>
|
||||
in the entry.
|
||||
|
||||
.SH EXAMPLE
|
||||
This example configures the
|
||||
.B adremap
|
||||
overlay to map all
|
||||
.B uid
|
||||
attributes to lowercase, and create
|
||||
.B memberUid
|
||||
values for group entries.
|
||||
Add the following to
|
||||
.BR slapd.conf (5):
|
||||
|
||||
.LP
|
||||
.nf
|
||||
database <database>
|
||||
# ...
|
||||
|
||||
overlay adremap
|
||||
adremap-downcase uid
|
||||
adremap-dnmap member uid memberUid
|
||||
.fi
|
||||
.LP
|
||||
.B slapd
|
||||
must also load
|
||||
.B adremap.la,
|
||||
if compiled as a run-time module;
|
||||
|
||||
.SH FILES
|
||||
.TP
|
||||
ETCDIR/slapd.conf
|
||||
default slapd configuration file
|
||||
.SH SEE ALSO
|
||||
.BR slapd.conf (5),
|
||||
.BR slapd (8).
|
||||
The
|
||||
.BR slapo-adremap (5)
|
||||
overlay supports dynamic configuration via
|
||||
.BR back-config.
|
||||
.SH ACKNOWLEDGEMENTS
|
||||
.P
|
||||
This module was written in 2015 by Howard Chu.
|
Loading…
Reference in New Issue
Block a user