summaryrefslogtreecommitdiffstats
path: root/contrib/slapd-modules/cloak/cloak.c
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/slapd-modules/cloak/cloak.c')
-rw-r--r--contrib/slapd-modules/cloak/cloak.c354
1 files changed, 354 insertions, 0 deletions
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) */
+