/* cloak.c - Overlay to hide some attribute except if explicitly requested */ /* $OpenLDAP$ */ /* This work is part of OpenLDAP Software . * * 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 * . */ /* ACKNOWLEDGEMENTS: * This work was originally developed by the Emmanuel Dreyfus for * inclusion in OpenLDAP Software. */ #include "portable.h" #ifdef SLAPD_OVER_CLOAK #include #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 []\": " 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) */