diff options
Diffstat (limited to 'contrib/slapd-modules/cloak/cloak.c')
-rw-r--r-- | contrib/slapd-modules/cloak/cloak.c | 354 |
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) */ + |