1/* $NetBSD: null.c,v 1.3 2021/08/14 16:15:00 christos Exp $ */ 2 3/* null.c - the null backend */ 4/* $OpenLDAP$ */ 5/* This work is part of OpenLDAP Software <http://www.openldap.org/>. 6 * 7 * Copyright 2002-2021 The OpenLDAP Foundation. 8 * All rights reserved. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted only as authorized by the OpenLDAP 12 * Public License. 13 * 14 * A copy of this license is available in the file LICENSE in the 15 * top-level directory of the distribution or, alternatively, at 16 * <http://www.OpenLDAP.org/license.html>. 17 */ 18/* ACKNOWLEDGEMENTS: 19 * This work was originally developed by Hallvard Furuseth for inclusion 20 * in OpenLDAP Software. 21 */ 22 23#include <sys/cdefs.h> 24__RCSID("$NetBSD: null.c,v 1.3 2021/08/14 16:15:00 christos Exp $"); 25 26#include "portable.h" 27 28#include <stdio.h> 29#include <ac/string.h> 30 31#include "slap.h" 32#include "slap-config.h" 33 34typedef struct null_info { 35 int ni_bind_allowed; 36 int ni_dosearch; 37 ID ni_nextid; 38 Entry *ni_entry; 39} null_info; 40 41static ConfigTable nullcfg[] = { 42 { "bind", "true|FALSE", 1, 2, 0, ARG_ON_OFF|ARG_OFFSET, 43 (void *)offsetof(null_info, ni_bind_allowed), 44 "( OLcfgDbAt:8.1 NAME 'olcDbBindAllowed' " 45 "DESC 'Allow binds to this database' " 46 "EQUALITY booleanMatch " 47 "SYNTAX OMsBoolean SINGLE-VALUE )", NULL, NULL }, 48 { "dosearch", "true|FALSE", 1, 2, 0, ARG_ON_OFF|ARG_OFFSET, 49 (void *)offsetof(null_info, ni_dosearch), 50 "( OLcfgDbAt:8.2 NAME 'olcDbDoSearch' " 51 "DESC 'Return an entry on searches' " 52 "EQUALITY booleanMatch " 53 "SYNTAX OMsBoolean SINGLE-VALUE )", NULL, NULL }, 54 { NULL, NULL, 0, 0, 0, ARG_IGNORED, 55 NULL, NULL, NULL, NULL } 56}; 57 58static ConfigOCs nullocs[] = { 59 { "( OLcfgDbOc:8.1 " 60 "NAME 'olcNullConfig' " 61 "DESC 'Null backend configuration' " 62 "SUP olcDatabaseConfig " 63 "MAY ( olcDbBindAllowed $ olcDbDoSearch ) )", 64 Cft_Database, nullcfg }, 65 { NULL, 0, NULL } 66}; 67 68 69static int 70null_back_db_open( BackendDB *be, ConfigReply *cr ) 71{ 72 struct null_info *ni = (struct null_info *) be->be_private; 73 struct berval bv[2]; 74 AttributeDescription *ad = NULL; 75 const char *text; 76 Entry *e; 77 78 if ( ni->ni_dosearch ) { 79 e = entry_alloc(); 80 e->e_name = be->be_suffix[0]; 81 e->e_nname = be->be_nsuffix[0]; 82 83 dnRdn( &e->e_nname, &bv[0] ); 84 bv[1].bv_val = strchr(bv[0].bv_val, '=') + 1; 85 bv[1].bv_len = bv[0].bv_len - (bv[1].bv_val - 86 bv[0].bv_val); 87 bv[0].bv_len -= bv[1].bv_len + 1; 88 slap_bv2ad( &bv[0], &ad, &text ); 89 attr_merge_one( e, ad, &bv[1], NULL ); 90 91 ber_str2bv("extensibleObject", 0, 0, &bv[0]); 92 attr_merge_one( e, slap_schema.si_ad_objectClass, &bv[0], NULL); 93 ni->ni_entry = e; 94 } 95 return 0; 96} 97 98/* LDAP operations */ 99 100static int 101null_back_bind( Operation *op, SlapReply *rs ) 102{ 103 struct null_info *ni = (struct null_info *) op->o_bd->be_private; 104 105 if ( ni->ni_bind_allowed || be_isroot_pw( op ) ) { 106 /* front end will send result on success (0) */ 107 return LDAP_SUCCESS; 108 } 109 110 rs->sr_err = LDAP_INVALID_CREDENTIALS; 111 send_ldap_result( op, rs ); 112 113 return rs->sr_err; 114} 115 116 117static int 118null_back_respond( Operation *op, SlapReply *rs, int rc ) 119{ 120 LDAPControl ctrl[SLAP_MAX_RESPONSE_CONTROLS], *ctrls[SLAP_MAX_RESPONSE_CONTROLS]; 121 int c = 0; 122 123 BerElementBuffer ps_berbuf; 124 BerElement *ps_ber = NULL; 125 LDAPControl **preread_ctrl = NULL, 126 **postread_ctrl = NULL; 127 128 rs->sr_err = LDAP_OTHER; 129 130 /* this comes first, as in case of assertion failure 131 * any further processing must stop */ 132 if ( get_assert( op ) ) { 133 rs->sr_err = LDAP_ASSERTION_FAILED; 134 goto respond; 135 } 136 137 if ( op->o_preread ) { 138 Entry e = { 0 }; 139 140 switch ( op->o_tag ) { 141 case LDAP_REQ_MODIFY: 142 case LDAP_REQ_RENAME: 143 case LDAP_REQ_DELETE: 144 e.e_name = op->o_req_dn; 145 e.e_nname = op->o_req_ndn; 146 147 preread_ctrl = &ctrls[c]; 148 *preread_ctrl = NULL; 149 150 if ( slap_read_controls( op, rs, &e, 151 &slap_pre_read_bv, preread_ctrl ) ) 152 { 153 preread_ctrl = NULL; 154 155 Debug( LDAP_DEBUG_TRACE, 156 "<=- null_back_respond: pre-read " 157 "failed!\n" ); 158 159 if ( op->o_preread & SLAP_CONTROL_CRITICAL ) { 160 /* FIXME: is it correct to abort 161 * operation if control fails? */ 162 goto respond; 163 } 164 165 } else { 166 c++; 167 } 168 break; 169 } 170 } 171 172 if ( op->o_postread ) { 173 Entry e = { 0 }; 174 175 switch ( op->o_tag ) { 176 case LDAP_REQ_ADD: 177 case LDAP_REQ_MODIFY: 178 case LDAP_REQ_RENAME: 179 if ( op->o_tag == LDAP_REQ_ADD ) { 180 e.e_name = op->ora_e->e_name; 181 e.e_nname = op->ora_e->e_nname; 182 183 } else { 184 e.e_name = op->o_req_dn; 185 e.e_nname = op->o_req_ndn; 186 } 187 188 postread_ctrl = &ctrls[c]; 189 *postread_ctrl = NULL; 190 191 if ( slap_read_controls( op, rs, &e, 192 &slap_post_read_bv, postread_ctrl ) ) 193 { 194 postread_ctrl = NULL; 195 196 Debug( LDAP_DEBUG_TRACE, 197 "<=- null_back_respond: post-read " 198 "failed!\n" ); 199 200 if ( op->o_postread & SLAP_CONTROL_CRITICAL ) { 201 /* FIXME: is it correct to abort 202 * operation if control fails? */ 203 goto respond; 204 } 205 206 } else { 207 c++; 208 } 209 break; 210 } 211 } 212 213 if ( op->o_noop ) { 214 switch ( op->o_tag ) { 215 case LDAP_REQ_ADD: 216 case LDAP_REQ_MODIFY: 217 case LDAP_REQ_RENAME: 218 case LDAP_REQ_DELETE: 219 case LDAP_REQ_EXTENDED: 220 rc = LDAP_X_NO_OPERATION; 221 break; 222 } 223 } 224 225 if ( get_pagedresults( op ) > SLAP_CONTROL_IGNORED ) { 226 struct berval cookie = BER_BVC( "" ); 227 228 /* should not be here... */ 229 assert( op->o_tag == LDAP_REQ_SEARCH ); 230 231 ctrl[c].ldctl_oid = LDAP_CONTROL_PAGEDRESULTS; 232 ctrl[c].ldctl_iscritical = 0; 233 234 ps_ber = (BerElement *)&ps_berbuf; 235 ber_init2( ps_ber, NULL, LBER_USE_DER ); 236 237 /* return size of 0 -- no estimate */ 238 ber_printf( ps_ber, "{iO}", 0, &cookie ); 239 240 if ( ber_flatten2( ps_ber, &ctrl[c].ldctl_value, 0 ) == -1 ) { 241 goto done; 242 } 243 244 ctrls[c] = &ctrl[c]; 245 c++; 246 } 247 248 /* terminate controls array */ 249 ctrls[c] = NULL; 250 rs->sr_ctrls = ctrls; 251 rs->sr_err = rc; 252 253respond:; 254 send_ldap_result( op, rs ); 255 rs->sr_ctrls = NULL; 256 257done:; 258 if ( ps_ber != NULL ) { 259 (void) ber_free_buf( ps_ber ); 260 } 261 262 if( preread_ctrl != NULL && (*preread_ctrl) != NULL ) { 263 slap_sl_free( (*preread_ctrl)->ldctl_value.bv_val, op->o_tmpmemctx ); 264 slap_sl_free( *preread_ctrl, op->o_tmpmemctx ); 265 } 266 267 if( postread_ctrl != NULL && (*postread_ctrl) != NULL ) { 268 slap_sl_free( (*postread_ctrl)->ldctl_value.bv_val, op->o_tmpmemctx ); 269 slap_sl_free( *postread_ctrl, op->o_tmpmemctx ); 270 } 271 272 return rs->sr_err; 273} 274 275/* add, delete, modify, modrdn, search */ 276static int 277null_back_success( Operation *op, SlapReply *rs ) 278{ 279 return null_back_respond( op, rs, LDAP_SUCCESS ); 280} 281 282/* compare */ 283static int 284null_back_false( Operation *op, SlapReply *rs ) 285{ 286 return null_back_respond( op, rs, LDAP_COMPARE_FALSE ); 287} 288 289static int 290null_back_search( Operation *op, SlapReply *rs ) 291{ 292 struct null_info *ni = (struct null_info *) op->o_bd->be_private; 293 294 if ( ni->ni_entry ) { 295 rs->sr_entry = ni->ni_entry; 296 rs->sr_flags = 0; 297 298 rs->sr_attrs = op->ors_attrs; 299 rs->sr_operational_attrs = NULL; 300 send_search_entry( op, rs ); 301 } 302 return null_back_respond( op, rs, LDAP_SUCCESS ); 303} 304 305/* for overlays */ 306static int 307null_back_entry_get( 308 Operation *op, 309 struct berval *ndn, 310 ObjectClass *oc, 311 AttributeDescription *at, 312 int rw, 313 Entry **ent ) 314{ 315 /* don't admit the object isn't there */ 316 return oc || at ? LDAP_NO_SUCH_ATTRIBUTE : LDAP_BUSY; 317} 318 319static int 320null_back_entry_release( 321 Operation *op, 322 Entry *e, 323 int rw ) 324{ 325 /* we reuse our entry, don't free it */ 326 return 0; 327} 328 329/* Slap tools */ 330 331static int 332null_tool_entry_open( BackendDB *be, int mode ) 333{ 334 return 0; 335} 336 337static int 338null_tool_entry_close( BackendDB *be ) 339{ 340 assert( be != NULL ); 341 return 0; 342} 343 344static ID 345null_tool_entry_first_x( BackendDB *be, struct berval *base, int scope, Filter *f ) 346{ 347 return NOID; 348} 349 350static ID 351null_tool_entry_next( BackendDB *be ) 352{ 353 return NOID; 354} 355 356static Entry * 357null_tool_entry_get( BackendDB *be, ID id ) 358{ 359 assert( slapMode & SLAP_TOOL_MODE ); 360 return NULL; 361} 362 363static ID 364null_tool_entry_put( BackendDB *be, Entry *e, struct berval *text ) 365{ 366 assert( slapMode & SLAP_TOOL_MODE ); 367 assert( text != NULL ); 368 assert( text->bv_val != NULL ); 369 assert( text->bv_val[0] == '\0' ); /* overconservative? */ 370 371 e->e_id = ((struct null_info *) be->be_private)->ni_nextid++; 372 return e->e_id; 373} 374 375 376/* Setup */ 377 378static int 379null_back_db_init( BackendDB *be, ConfigReply *cr ) 380{ 381 struct null_info *ni = ch_calloc( 1, sizeof(struct null_info) ); 382 ni->ni_bind_allowed = 0; 383 ni->ni_nextid = 1; 384 be->be_private = ni; 385 be->be_cf_ocs = be->bd_info->bi_cf_ocs; 386 return 0; 387} 388 389static int 390null_back_db_destroy( Backend *be, ConfigReply *cr ) 391{ 392 struct null_info *ni = be->be_private; 393 394 if ( ni->ni_entry ) { 395 entry_free( ni->ni_entry ); 396 ni->ni_entry = NULL; 397 } 398 free( be->be_private ); 399 return 0; 400} 401 402 403int 404null_back_initialize( BackendInfo *bi ) 405{ 406 static char *controls[] = { 407 LDAP_CONTROL_ASSERT, 408 LDAP_CONTROL_MANAGEDSAIT, 409 LDAP_CONTROL_NOOP, 410 LDAP_CONTROL_PAGEDRESULTS, 411 LDAP_CONTROL_SUBENTRIES, 412 LDAP_CONTROL_PRE_READ, 413 LDAP_CONTROL_POST_READ, 414 LDAP_CONTROL_X_PERMISSIVE_MODIFY, 415 NULL 416 }; 417 418 Debug( LDAP_DEBUG_TRACE, 419 "null_back_initialize: initialize null backend\n" ); 420 421 bi->bi_flags |= 422 SLAP_BFLAG_INCREMENT | 423 SLAP_BFLAG_SUBENTRIES | 424 SLAP_BFLAG_ALIASES | 425 SLAP_BFLAG_REFERRALS; 426 427 bi->bi_controls = controls; 428 429 bi->bi_open = 0; 430 bi->bi_close = 0; 431 bi->bi_config = 0; 432 bi->bi_destroy = 0; 433 434 bi->bi_db_init = null_back_db_init; 435 bi->bi_db_config = config_generic_wrapper; 436 bi->bi_db_open = null_back_db_open; 437 bi->bi_db_close = 0; 438 bi->bi_db_destroy = null_back_db_destroy; 439 440 bi->bi_op_bind = null_back_bind; 441 bi->bi_op_unbind = 0; 442 bi->bi_op_search = null_back_search; 443 bi->bi_op_compare = null_back_false; 444 bi->bi_op_modify = null_back_success; 445 bi->bi_op_modrdn = null_back_success; 446 bi->bi_op_add = null_back_success; 447 bi->bi_op_delete = null_back_success; 448 bi->bi_op_abandon = 0; 449 450 bi->bi_extended = 0; 451 452 bi->bi_chk_referrals = 0; 453 454 bi->bi_connection_init = 0; 455 bi->bi_connection_destroy = 0; 456 457 bi->bi_entry_get_rw = null_back_entry_get; 458 bi->bi_entry_release_rw = null_back_entry_release; 459 460 bi->bi_tool_entry_open = null_tool_entry_open; 461 bi->bi_tool_entry_close = null_tool_entry_close; 462 bi->bi_tool_entry_first = backend_tool_entry_first; 463 bi->bi_tool_entry_first_x = null_tool_entry_first_x; 464 bi->bi_tool_entry_next = null_tool_entry_next; 465 bi->bi_tool_entry_get = null_tool_entry_get; 466 bi->bi_tool_entry_put = null_tool_entry_put; 467 468 bi->bi_cf_ocs = nullocs; 469 return config_register_schema( nullcfg, nullocs ); 470} 471 472#if SLAPD_NULL == SLAPD_MOD_DYNAMIC 473 474/* conditionally define the init_module() function */ 475SLAP_BACKEND_INIT_MODULE( null ) 476 477#endif /* SLAPD_NULL == SLAPD_MOD_DYNAMIC */ 478