]> git.sur5r.net Git - openldap/commitdiff
The cloak overlay hides some attributes unless explicitely requested (ITS #5872)
authorEmmanuel Dreyfus <manu@openldap.org>
Fri, 9 Jan 2009 05:26:28 +0000 (05:26 +0000)
committerEmmanuel Dreyfus <manu@openldap.org>
Fri, 9 Jan 2009 05:26:28 +0000 (05:26 +0000)
contrib/slapd-modules/README
contrib/slapd-modules/cloak/cloak.c [new file with mode: 0644]
contrib/slapd-modules/cloak/slapo-cloak.5 [new file with mode: 0644]

index e9dcf043a9eb5a014d020ec26a97ebde33e95f57..1c36baeb41319c23cac6f3b820bea6c82a8279e9 100644 (file)
@@ -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 (file)
index 0000000..a099cce
--- /dev/null
@@ -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
+ * <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) */
+
diff --git a/contrib/slapd-modules/cloak/slapo-cloak.5 b/contrib/slapd-modules/cloak/slapo-cloak.5
new file mode 100644 (file)
index 0000000..6c2410f
--- /dev/null
@@ -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 <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.