1/* cloak.c - Overlay to hide some attribute except if explicitely requested */ 2/* $OpenLDAP$ */ 3/* This work is part of OpenLDAP Software <http://www.openldap.org/>. 4 * 5 * Copyright 2008-2011 The OpenLDAP Foundation. 6 * Portions Copyright 2008 Emmanuel Dreyfus 7 * All rights reserved. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted only as authorized by the OpenLDAP 11 * Public License. 12 * 13 * A copy of this license is available in the file LICENSE in the 14 * top-level directory of the distribution or, alternatively, at 15 * <http://www.OpenLDAP.org/license.html>. 16 */ 17/* ACKNOWLEDGEMENTS: 18 * This work was originally developed by the Emmanuel Dreyfus for 19 * inclusion in OpenLDAP Software. 20 */ 21 22#include "portable.h" 23 24#ifdef SLAPD_OVER_CLOAK 25 26#include <stdio.h> 27 28#include "ac/string.h" 29#include "ac/socket.h" 30 31#include "lutil.h" 32#include "slap.h" 33#include "config.h" 34 35enum { CLOAK_ATTR = 1 }; 36 37typedef struct cloak_info_t { 38 ObjectClass *ci_oc; 39 AttributeDescription *ci_ad; 40 struct cloak_info_t *ci_next; 41} cloak_info_t; 42 43#define CLOAK_USAGE "\"cloak-attr <attr> [<class>]\": " 44 45static int 46cloak_cfgen( ConfigArgs *c ) 47{ 48 slap_overinst *on = (slap_overinst *)c->bi; 49 cloak_info_t *ci = (cloak_info_t *)on->on_bi.bi_private; 50 51 int rc = 0, i; 52 53 if ( c->op == SLAP_CONFIG_EMIT ) { 54 switch( c->type ) { 55 case CLOAK_ATTR: 56 for ( i = 0; ci; i++, ci = ci->ci_next ) { 57 struct berval bv; 58 int len; 59 60 assert( ci->ci_ad != NULL ); 61 62 if ( ci->ci_oc != NULL ) 63 len = snprintf( c->cr_msg, 64 sizeof( c->cr_msg ), 65 SLAP_X_ORDERED_FMT "%s %s", i, 66 ci->ci_ad->ad_cname.bv_val, 67 ci->ci_oc->soc_cname.bv_val ); 68 else 69 len = snprintf( c->cr_msg, 70 sizeof( c->cr_msg ), 71 SLAP_X_ORDERED_FMT "%s", i, 72 ci->ci_ad->ad_cname.bv_val ); 73 74 bv.bv_val = c->cr_msg; 75 bv.bv_len = len; 76 value_add_one( &c->rvalue_vals, &bv ); 77 } 78 break; 79 80 default: 81 rc = 1; 82 break; 83 } 84 85 return rc; 86 87 } else if ( c->op == LDAP_MOD_DELETE ) { 88 cloak_info_t *ci_next; 89 90 switch( c->type ) { 91 case CLOAK_ATTR: 92 for ( ci_next = ci, i = 0; 93 ci_next, c->valx < 0 || i < c->valx; 94 ci = ci_next, i++ ){ 95 96 ci_next = ci->ci_next; 97 98 ch_free ( ci->ci_ad ); 99 if ( ci->ci_oc != NULL ) 100 ch_free ( ci->ci_oc ); 101 102 ch_free( ci ); 103 } 104 ci = (cloak_info_t *)on->on_bi.bi_private; 105 break; 106 107 default: 108 rc = 1; 109 break; 110 } 111 112 return rc; 113 } 114 115 switch( c->type ) { 116 case CLOAK_ATTR: { 117 ObjectClass *oc = NULL; 118 AttributeDescription *ad = NULL; 119 const char *text; 120 cloak_info_t **cip = NULL; 121 cloak_info_t *ci_next = NULL; 122 123 if ( c->argc == 3 ) { 124 oc = oc_find( c->argv[ 2 ] ); 125 if ( oc == NULL ) { 126 snprintf( c->cr_msg, 127 sizeof( c->cr_msg ), 128 CLOAK_USAGE 129 "unable to find ObjectClass \"%s\"", 130 c->argv[ 2 ] ); 131 Debug( LDAP_DEBUG_ANY, "%s: %s.\n", 132 c->log, c->cr_msg, 0 ); 133 return 1; 134 } 135 } 136 137 rc = slap_str2ad( c->argv[ 1 ], &ad, &text ); 138 if ( rc != LDAP_SUCCESS ) { 139 snprintf( c->cr_msg, sizeof( c->cr_msg ), CLOAK_USAGE 140 "unable to find AttributeDescription \"%s\"", 141 c->argv[ 1 ] ); 142 Debug( LDAP_DEBUG_ANY, "%s: %s.\n", 143 c->log, c->cr_msg, 0 ); 144 return 1; 145 } 146 147 for ( i = 0, cip = (cloak_info_t **)&on->on_bi.bi_private; 148 c->valx < 0 || i < c->valx, *cip; 149 i++, cip = &(*cip)->ci_next ) { 150 if ( c->valx >= 0 && *cip == NULL ) { 151 snprintf( c->cr_msg, sizeof( c->cr_msg ), 152 CLOAK_USAGE 153 "invalid index {%d}\n", 154 c->valx ); 155 Debug( LDAP_DEBUG_ANY, "%s: %s.\n", 156 c->log, c->cr_msg, 0 ); 157 return 1; 158 } 159 ci_next = *cip; 160 } 161 162 *cip = (cloak_info_t *)SLAP_CALLOC( 1, sizeof( cloak_info_t ) ); 163 (*cip)->ci_oc = oc; 164 (*cip)->ci_ad = ad; 165 (*cip)->ci_next = ci_next; 166 167 rc = 0; 168 break; 169 } 170 171 default: 172 rc = 1; 173 break; 174 } 175 176 return rc; 177} 178 179static int 180cloak_search_response_cb( Operation *op, SlapReply *rs ) 181{ 182 slap_callback *sc; 183 cloak_info_t *ci; 184 Entry *e = NULL; 185 Entry *me = NULL; 186 187 assert( op && op->o_callback && rs ); 188 189 if ( rs->sr_type != REP_SEARCH || !rs->sr_entry ) { 190 return ( SLAP_CB_CONTINUE ); 191 } 192 193 sc = op->o_callback; 194 e = rs->sr_entry; 195 196 /* 197 * First perform a quick scan for an attribute to cloak 198 */ 199 for ( ci = (cloak_info_t *)sc->sc_private; ci; ci = ci->ci_next ) { 200 Attribute *a; 201 202 if ( ci->ci_oc != NULL && 203 !is_entry_objectclass_or_sub( e, ci->ci_oc ) ) 204 continue; 205 206 for ( a = e->e_attrs; a; a = a->a_next ) 207 if ( a->a_desc == ci->ci_ad ) 208 break; 209 210 if ( a != NULL ) 211 break; 212 } 213 214 /* 215 * Nothing found to cloak 216 */ 217 if ( ci == NULL ) 218 return ( SLAP_CB_CONTINUE ); 219 220 /* 221 * We are now committed to cloak an attribute. 222 */ 223 rs_entry2modifiable( op, rs, (slap_overinst *) op->o_bd->bd_info ); 224 me = rs->sr_entry; 225 226 for ( ci = (cloak_info_t *)sc->sc_private; ci; ci = ci->ci_next ) { 227 Attribute *a; 228 Attribute *pa; 229 230 for ( pa = NULL, a = me->e_attrs; 231 a; 232 pa = a, a = a->a_next ) { 233 234 if ( a->a_desc != ci->ci_ad ) 235 continue; 236 237 Debug( LDAP_DEBUG_TRACE, "cloak_search_response_cb: cloak %s\n", 238 a->a_desc->ad_cname.bv_val, 239 0, 0 ); 240 241 if ( pa != NULL ) 242 pa->a_next = a->a_next; 243 else 244 me->e_attrs = a->a_next; 245 246 attr_clean( a ); 247 } 248 249 } 250 251 return ( SLAP_CB_CONTINUE ); 252} 253 254static int 255cloak_search_cleanup_cb( Operation *op, SlapReply *rs ) 256{ 257 if ( rs->sr_type == REP_RESULT || rs->sr_err != LDAP_SUCCESS ) { 258 slap_freeself_cb( op, rs ); 259 } 260 261 return SLAP_CB_CONTINUE; 262} 263 264static int 265cloak_search( Operation *op, SlapReply *rs ) 266{ 267 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info; 268 cloak_info_t *ci = (cloak_info_t *)on->on_bi.bi_private; 269 slap_callback *sc; 270 271 if ( op->ors_attrsonly || 272 op->ors_attrs || 273 get_manageDSAit( op ) ) 274 return SLAP_CB_CONTINUE; 275 276 sc = op->o_tmpcalloc( 1, sizeof( *sc ), op->o_tmpmemctx ); 277 sc->sc_response = cloak_search_response_cb; 278 sc->sc_cleanup = cloak_search_cleanup_cb; 279 sc->sc_next = op->o_callback; 280 sc->sc_private = ci; 281 op->o_callback = sc; 282 283 return SLAP_CB_CONTINUE; 284} 285 286static slap_overinst cloak_ovl; 287 288static ConfigTable cloakcfg[] = { 289 { "cloak-attr", "attribute [class]", 290 2, 3, 0, ARG_MAGIC|CLOAK_ATTR, cloak_cfgen, 291 "( OLcfgCtAt:4.1 NAME 'olcCloakAttribute' " 292 "DESC 'Cloaked attribute: attribute [class]' " 293 "EQUALITY caseIgnoreMatch " 294 "SYNTAX OMsDirectoryString " 295 "X-ORDERED 'VALUES' )", 296 NULL, NULL }, 297 { NULL, NULL, 0, 0, 0, ARG_IGNORED } 298}; 299 300static int 301cloak_db_destroy( 302 BackendDB *be, 303 ConfigReply *cr ) 304{ 305 slap_overinst *on = (slap_overinst *)be->bd_info; 306 cloak_info_t *ci = (cloak_info_t *)on->on_bi.bi_private; 307 308 for ( ; ci; ) { 309 cloak_info_t *tmp = ci; 310 ci = ci->ci_next; 311 SLAP_FREE( tmp ); 312 } 313 314 on->on_bi.bi_private = NULL; 315 316 return 0; 317} 318 319static ConfigOCs cloakocs[] = { 320 { "( OLcfgCtOc:4.1 " 321 "NAME 'olcCloakConfig' " 322 "DESC 'Attribute cloak configuration' " 323 "SUP olcOverlayConfig " 324 "MAY ( olcCloakAttribute ) )", 325 Cft_Overlay, cloakcfg }, 326 { NULL, 0, NULL } 327}; 328 329#if SLAPD_OVER_CLOAK == SLAPD_MOD_DYNAMIC 330static 331#endif 332int 333cloak_initialize( void ) { 334 int rc; 335 cloak_ovl.on_bi.bi_type = "cloak"; 336 cloak_ovl.on_bi.bi_db_destroy = cloak_db_destroy; 337 cloak_ovl.on_bi.bi_op_search = cloak_search; 338 cloak_ovl.on_bi.bi_cf_ocs = cloakocs; 339 340 rc = config_register_schema ( cloakcfg, cloakocs ); 341 if ( rc ) 342 return rc; 343 344 return overlay_register( &cloak_ovl ); 345} 346 347#if SLAPD_OVER_CLOAK == SLAPD_MOD_DYNAMIC 348int init_module(int argc, char *argv[]) { 349 return cloak_initialize(); 350} 351#endif 352 353#endif /* defined(SLAPD_OVER_CLOAK) */ 354 355