From f1e2cc411fbad8b9ec705c300c3333a4b58fd550 Mon Sep 17 00:00:00 2001 From: Emmanuel Dreyfus Date: Fri, 9 Jan 2009 05:26:28 +0000 Subject: [PATCH] The cloak overlay hides some attributes unless explicitely requested (ITS #5872) --- contrib/slapd-modules/README | 3 + contrib/slapd-modules/cloak/cloak.c | 328 ++++++++++++++++++++++ contrib/slapd-modules/cloak/slapo-cloak.5 | 82 ++++++ 3 files changed, 413 insertions(+) create mode 100644 contrib/slapd-modules/cloak/cloak.c create mode 100644 contrib/slapd-modules/cloak/slapo-cloak.5 diff --git a/contrib/slapd-modules/README b/contrib/slapd-modules/README index e9dcf043a9..1c36baeb41 100644 --- a/contrib/slapd-modules/README +++ b/contrib/slapd-modules/README @@ -20,6 +20,9 @@ allop (overlay) autogroup (overlay) Automated updates of group memberships. +cloak (overlay) + Hide specific attributes unless explicitely requested + comp_match (plugin) Component Matching rules (RFC 3687). diff --git a/contrib/slapd-modules/cloak/cloak.c b/contrib/slapd-modules/cloak/cloak.c new file mode 100644 index 0000000000..a099ccecd3 --- /dev/null +++ b/contrib/slapd-modules/cloak/cloak.c @@ -0,0 +1,328 @@ +/* $OpenLDAP$ */ +/* cloak.c - Overlay to hide some attribute except if explicitely requested */ +/* + * 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 + * . + */ +#include "portable.h" + +#ifdef SLAPD_OVER_CLOAK + +#include + +#include +#include + +#include "lutil.h" +#include "slap.h" +#include "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 []\": " + +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, 0 ); + 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, 0 ); + 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, 0 ); + return 1; + } + ci_next = *cip; + } + + *cip = (cloak_info_t *)ch_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_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 ) { + slap_freeself_cb( op, rs ); + 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. + */ + if ( rs->sr_flags & REP_ENTRY_MODIFIABLE ) + me = e; + else + me = entry_dup( e ); + + 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_cb: cloak %s\n", + a->a_desc->ad_cname.bv_val, + 0, 0 ); + + if ( pa != NULL ) + pa->a_next = a->a_next; + else + me->e_attrs = a->a_next; + + attr_clean( a ); + } + + } + + if ( me != e ) { + if ( rs->sr_flags & REP_ENTRY_MUSTBEFREED ) + entry_free( e ); + + rs->sr_entry = me; + rs->sr_flags |= REP_ENTRY_MODIFIABLE | REP_ENTRY_MUSTBEFREED; + } + + 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_cb; + sc->sc_cleanup = NULL; + sc->sc_next = NULL; + 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, + "( OLcfgOvAt:22.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 ConfigOCs cloakocs[] = { + { "( OLcfgOvOc:22.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_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 0000000000..6c2410f522 --- /dev/null +++ b/contrib/slapd-modules/cloak/slapo-cloak.5 @@ -0,0 +1,82 @@ +.TH SLAPO-CLOAK 5 "RELEASEDATE" "OpenLDAP LDVERSION" +.\" Copyright 1998-2008 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 explicitely 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 [] +The value +.B +is the name of the attribute that will be cloaked. + +The optional +.B +restricts cloaking only to entries of the named +.B . + +.SH EXAMPLE +This example hide the +.B jpegPhoto +attribute. Add the following to slapd.conf: + +.LP +.nf + 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 written in 2008 by Emmanuel Dreyfus. -- 2.39.2