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