--- /dev/null
+/* $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
+ * <http://www.OpenLDAP.org/license.html>.
+ */
+#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 "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, 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) */
+
--- /dev/null
+.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 <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 written in 2008 by Emmanuel Dreyfus.