diff options
Diffstat (limited to 'contrib/slapd-modules/cloak')
-rw-r--r-- | contrib/slapd-modules/cloak/Makefile | 58 | ||||
-rw-r--r-- | contrib/slapd-modules/cloak/cloak.c | 354 | ||||
-rw-r--r-- | contrib/slapd-modules/cloak/slapo-cloak.5 | 82 |
3 files changed, 494 insertions, 0 deletions
diff --git a/contrib/slapd-modules/cloak/Makefile b/contrib/slapd-modules/cloak/Makefile new file mode 100644 index 0000000..c54e6b1 --- /dev/null +++ b/contrib/slapd-modules/cloak/Makefile @@ -0,0 +1,58 @@ +# $OpenLDAP$ + +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/libldap.la \ + $(LDAP_BUILD)/libraries/liblber/liblber.la + +LIBTOOL = $(LDAP_BUILD)/libtool +INSTALL = /usr/bin/install +CC = gcc +OPT = -g -O2 +DEFS = -DSLAPD_OVER_CLOAK=SLAPD_MOD_DYNAMIC +INCS = $(LDAP_INC) +LIBS = $(LDAP_LIB) + +PROGRAMS = cloak.la +MANPAGES = slapo-cloak.5 +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) +mandir = $(exec_prefix)/share/man +man5dir = $(mandir)/man5 + +.SUFFIXES: .c .o .lo + +.c.lo: + $(LIBTOOL) --mode=compile $(CC) $(CFLAGS) $(OPT) $(CPPFLAGS) $(DEFS) $(INCS) -c $< + +all: $(PROGRAMS) + +cloak.la: cloak.lo + $(LIBTOOL) --mode=link $(CC) $(LDFLAGS) -version-info $(LTVER) \ + -rpath $(moduledir) -module -o $@ $? $(LIBS) + +clean: + rm -rf *.o *.lo *.la .libs + +install: install-lib install-man FORCE + +install-lib: $(PROGRAMS) + mkdir -p $(DESTDIR)$(moduledir) + for p in $(PROGRAMS) ; do \ + $(LIBTOOL) --mode=install cp $$p $(DESTDIR)$(moduledir) ; \ + done + +install-man: $(MANPAGES) + mkdir -p $(DESTDIR)$(man5dir) + $(INSTALL) -m 644 $(MANPAGES) $(DESTDIR)$(man5dir) + +FORCE: + diff --git a/contrib/slapd-modules/cloak/cloak.c b/contrib/slapd-modules/cloak/cloak.c new file mode 100644 index 0000000..ced7a80 --- /dev/null +++ b/contrib/slapd-modules/cloak/cloak.c @@ -0,0 +1,354 @@ +/* cloak.c - Overlay to hide some attribute except if explicitly requested */ +/* $OpenLDAP$ */ +/* This work is part of OpenLDAP Software <http://www.openldap.org/>. + * + * Copyright 2008-2022 The OpenLDAP Foundation. + * Portions Copyright 2008 Emmanuel Dreyfus + * 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>. + */ +/* ACKNOWLEDGEMENTS: + * This work was originally developed by the Emmanuel Dreyfus for + * inclusion in OpenLDAP Software. + */ + +#include "portable.h" + +#ifdef SLAPD_OVER_CLOAK + +#include <stdio.h> + +#include "ac/string.h" +#include "ac/socket.h" + +#include "lutil.h" +#include "slap.h" +#include "slap-config.h" + +enum { CLOAK_ATTR = 1 }; + +typedef struct cloak_info_t { + ObjectClass *ci_oc; + AttributeDescription *ci_ad; + struct cloak_info_t *ci_next; +} cloak_info_t; + +#define CLOAK_USAGE "\"cloak-attr <attr> [<class>]\": " + +static int +cloak_cfgen( ConfigArgs *c ) +{ + slap_overinst *on = (slap_overinst *)c->bi; + cloak_info_t *ci = (cloak_info_t *)on->on_bi.bi_private; + + int rc = 0, i; + + if ( c->op == SLAP_CONFIG_EMIT ) { + switch( c->type ) { + case CLOAK_ATTR: + for ( i = 0; ci; i++, ci = ci->ci_next ) { + struct berval bv; + int len; + + assert( ci->ci_ad != NULL ); + + if ( ci->ci_oc != NULL ) + len = snprintf( c->cr_msg, + sizeof( c->cr_msg ), + SLAP_X_ORDERED_FMT "%s %s", i, + ci->ci_ad->ad_cname.bv_val, + ci->ci_oc->soc_cname.bv_val ); + else + len = snprintf( c->cr_msg, + sizeof( c->cr_msg ), + SLAP_X_ORDERED_FMT "%s", i, + ci->ci_ad->ad_cname.bv_val ); + + bv.bv_val = c->cr_msg; + bv.bv_len = len; + value_add_one( &c->rvalue_vals, &bv ); + } + break; + + default: + rc = 1; + break; + } + + return rc; + + } else if ( c->op == LDAP_MOD_DELETE ) { + cloak_info_t *ci_next; + + switch( c->type ) { + case CLOAK_ATTR: + for ( ci_next = ci, i = 0; + ci_next, c->valx < 0 || i < c->valx; + ci = ci_next, i++ ){ + + ci_next = ci->ci_next; + + ch_free ( ci->ci_ad ); + if ( ci->ci_oc != NULL ) + ch_free ( ci->ci_oc ); + + ch_free( ci ); + } + ci = (cloak_info_t *)on->on_bi.bi_private; + break; + + default: + rc = 1; + break; + } + + return rc; + } + + switch( c->type ) { + case CLOAK_ATTR: { + ObjectClass *oc = NULL; + AttributeDescription *ad = NULL; + const char *text; + cloak_info_t **cip = NULL; + cloak_info_t *ci_next = NULL; + + if ( c->argc == 3 ) { + oc = oc_find( c->argv[ 2 ] ); + if ( oc == NULL ) { + snprintf( c->cr_msg, + sizeof( c->cr_msg ), + CLOAK_USAGE + "unable to find ObjectClass \"%s\"", + c->argv[ 2 ] ); + Debug( LDAP_DEBUG_ANY, "%s: %s.\n", + c->log, c->cr_msg ); + return 1; + } + } + + rc = slap_str2ad( c->argv[ 1 ], &ad, &text ); + if ( rc != LDAP_SUCCESS ) { + snprintf( c->cr_msg, sizeof( c->cr_msg ), CLOAK_USAGE + "unable to find AttributeDescription \"%s\"", + c->argv[ 1 ] ); + Debug( LDAP_DEBUG_ANY, "%s: %s.\n", + c->log, c->cr_msg ); + return 1; + } + + for ( i = 0, cip = (cloak_info_t **)&on->on_bi.bi_private; + c->valx < 0 || i < c->valx, *cip; + i++, cip = &(*cip)->ci_next ) { + if ( c->valx >= 0 && *cip == NULL ) { + snprintf( c->cr_msg, sizeof( c->cr_msg ), + CLOAK_USAGE + "invalid index {%d}\n", + c->valx ); + Debug( LDAP_DEBUG_ANY, "%s: %s.\n", + c->log, c->cr_msg ); + return 1; + } + ci_next = *cip; + } + + *cip = (cloak_info_t *)SLAP_CALLOC( 1, sizeof( cloak_info_t ) ); + (*cip)->ci_oc = oc; + (*cip)->ci_ad = ad; + (*cip)->ci_next = ci_next; + + rc = 0; + break; + } + + default: + rc = 1; + break; + } + + return rc; +} + +static int +cloak_search_response_cb( Operation *op, SlapReply *rs ) +{ + slap_callback *sc; + cloak_info_t *ci; + Entry *e = NULL; + Entry *me = NULL; + + assert( op && op->o_callback && rs ); + + if ( rs->sr_type != REP_SEARCH || !rs->sr_entry ) { + return ( SLAP_CB_CONTINUE ); + } + + sc = op->o_callback; + e = rs->sr_entry; + + /* + * First perform a quick scan for an attribute to cloak + */ + for ( ci = (cloak_info_t *)sc->sc_private; ci; ci = ci->ci_next ) { + Attribute *a; + + if ( ci->ci_oc != NULL && + !is_entry_objectclass_or_sub( e, ci->ci_oc ) ) + continue; + + for ( a = e->e_attrs; a; a = a->a_next ) + if ( a->a_desc == ci->ci_ad ) + break; + + if ( a != NULL ) + break; + } + + /* + * Nothing found to cloak + */ + if ( ci == NULL ) + return ( SLAP_CB_CONTINUE ); + + /* + * We are now committed to cloak an attribute. + */ + rs_entry2modifiable( op, rs, (slap_overinst *) op->o_bd->bd_info ); + me = rs->sr_entry; + + for ( ci = (cloak_info_t *)sc->sc_private; ci; ci = ci->ci_next ) { + Attribute *a; + Attribute *pa; + + for ( pa = NULL, a = me->e_attrs; + a; + pa = a, a = a->a_next ) { + + if ( a->a_desc != ci->ci_ad ) + continue; + + Debug( LDAP_DEBUG_TRACE, "cloak_search_response_cb: cloak %s\n", + a->a_desc->ad_cname.bv_val ); + + if ( pa != NULL ) + pa->a_next = a->a_next; + else + me->e_attrs = a->a_next; + + attr_clean( a ); + } + + } + + return ( SLAP_CB_CONTINUE ); +} + +static int +cloak_search_cleanup_cb( Operation *op, SlapReply *rs ) +{ + if ( rs->sr_type == REP_RESULT || rs->sr_err != LDAP_SUCCESS ) { + slap_freeself_cb( op, rs ); + } + + return SLAP_CB_CONTINUE; +} + +static int +cloak_search( Operation *op, SlapReply *rs ) +{ + slap_overinst *on = (slap_overinst *)op->o_bd->bd_info; + cloak_info_t *ci = (cloak_info_t *)on->on_bi.bi_private; + slap_callback *sc; + + if ( op->ors_attrsonly || + op->ors_attrs || + get_manageDSAit( op ) ) + return SLAP_CB_CONTINUE; + + sc = op->o_tmpcalloc( 1, sizeof( *sc ), op->o_tmpmemctx ); + sc->sc_response = cloak_search_response_cb; + sc->sc_cleanup = cloak_search_cleanup_cb; + sc->sc_next = op->o_callback; + sc->sc_private = ci; + op->o_callback = sc; + + return SLAP_CB_CONTINUE; +} + +static slap_overinst cloak_ovl; + +static ConfigTable cloakcfg[] = { + { "cloak-attr", "attribute [class]", + 2, 3, 0, ARG_MAGIC|CLOAK_ATTR, cloak_cfgen, + "( OLcfgCtAt:4.1 NAME 'olcCloakAttribute' " + "DESC 'Cloaked attribute: attribute [class]' " + "EQUALITY caseIgnoreMatch " + "SYNTAX OMsDirectoryString " + "X-ORDERED 'VALUES' )", + NULL, NULL }, + { NULL, NULL, 0, 0, 0, ARG_IGNORED } +}; + +static int +cloak_db_destroy( + BackendDB *be, + ConfigReply *cr ) +{ + slap_overinst *on = (slap_overinst *)be->bd_info; + cloak_info_t *ci = (cloak_info_t *)on->on_bi.bi_private; + + for ( ; ci; ) { + cloak_info_t *tmp = ci; + ci = ci->ci_next; + SLAP_FREE( tmp ); + } + + on->on_bi.bi_private = NULL; + + return 0; +} + +static ConfigOCs cloakocs[] = { + { "( OLcfgCtOc:4.1 " + "NAME 'olcCloakConfig' " + "DESC 'Attribute cloak configuration' " + "SUP olcOverlayConfig " + "MAY ( olcCloakAttribute ) )", + Cft_Overlay, cloakcfg }, + { NULL, 0, NULL } +}; + +#if SLAPD_OVER_CLOAK == SLAPD_MOD_DYNAMIC +static +#endif +int +cloak_initialize( void ) { + int rc; + cloak_ovl.on_bi.bi_type = "cloak"; + cloak_ovl.on_bi.bi_flags = SLAPO_BFLAG_SINGLE; + cloak_ovl.on_bi.bi_db_destroy = cloak_db_destroy; + cloak_ovl.on_bi.bi_op_search = cloak_search; + cloak_ovl.on_bi.bi_cf_ocs = cloakocs; + + rc = config_register_schema ( cloakcfg, cloakocs ); + if ( rc ) + return rc; + + return overlay_register( &cloak_ovl ); +} + +#if SLAPD_OVER_CLOAK == SLAPD_MOD_DYNAMIC +int init_module(int argc, char *argv[]) { + return cloak_initialize(); +} +#endif + +#endif /* defined(SLAPD_OVER_CLOAK) */ + diff --git a/contrib/slapd-modules/cloak/slapo-cloak.5 b/contrib/slapd-modules/cloak/slapo-cloak.5 new file mode 100644 index 0000000..2655d2e --- /dev/null +++ b/contrib/slapd-modules/cloak/slapo-cloak.5 @@ -0,0 +1,82 @@ +.TH SLAPO-CLOAK 5 "RELEASEDATE" "OpenLDAP LDVERSION" +.\" Copyright 1998-2022 The OpenLDAP Foundation, All Rights Reserved. +.\" Copying restrictions apply. See the COPYRIGHT file. +.\" $OpenLDAP$ +.SH NAME +slapo-cloak \- Attribute cloak overlay to slapd +.SH SYNOPSIS +ETCDIR/slapd.conf +.SH DESCRIPTION +The +.B cloak +overlay to +.BR slapd (8) +allows the server to hide specific attributes, unless explicitly requested +by the client. This improve performance when a client requests all attributes +and get a huge binary attribute that is of no interest for it. +This behavior is disabled when the \fImanageDSAit\fP +control (RFC 3296) is used. + +.SH CONFIGURATION +The config directives that are specific to the +.B cloak +overlay must be prefixed by +.BR cloak\- , +to avoid potential conflicts with directives specific to the underlying +database or to other stacked overlays. + +.TP +.B overlay cloak +This directive adds the cloak overlay to the current database, +or to the frontend, if used before any database instantiation; see +.BR slapd.conf (5) +for details. + +.LP +This +.B slapd.conf +configuration option is defined for the cloak overlay. It may have multiple +occurrences, and it must appear after the +.B overlay +directive: +.TP +.B cloak-attr <attribute> [<class>] +The value +.B <attribute> +is the name of the attribute that will be cloaked. + +The optional +.B <class> +restricts cloaking only to entries of the named +.B <class>. + +.SH EXAMPLE +This example hide the +.B jpegPhoto +attribute. Add the following to slapd.conf: + +.LP +.nf + database <database> + # ... + + overlay cloak + cloak-attr jpegPhoto +.fi +.LP +and that slapd loads cloak.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-cloak (5) +overlay supports dynamic configuration via +.BR back-config . +.SH ACKNOWLEDGEMENTS +.P +This module was originally written in 2008 by Emmanuel Dreyfus. |