1/* $NetBSD: config.c,v 1.3 2021/08/14 16:15:01 christos Exp $ */ 2 3/* config.c - sock backend configuration file routine */ 4/* $OpenLDAP$ */ 5/* This work is part of OpenLDAP Software <http://www.openldap.org/>. 6 * 7 * Copyright 2007-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 initially developed by Brian Candler for inclusion 20 * in OpenLDAP Software. Dynamic config support by Howard Chu. 21 */ 22 23#include <sys/cdefs.h> 24__RCSID("$NetBSD: config.c,v 1.3 2021/08/14 16:15:01 christos Exp $"); 25 26#include "portable.h" 27 28#include <stdio.h> 29 30#include <ac/string.h> 31#include <ac/socket.h> 32 33#include "slap.h" 34#include "slap-config.h" 35#include "back-sock.h" 36 37static ConfigDriver bs_cf_gen; 38static int sock_over_setup(); 39static slap_response sock_over_response; 40 41enum { 42 BS_EXT = 1, 43 BS_OPS, 44 BS_RESP, 45 BS_DNPAT 46}; 47 48/* The number of overlay-only config attrs */ 49#define NUM_OV_ATTRS 3 50 51static ConfigTable bscfg[] = { 52 { "sockops", "ops", 2, 0, 0, ARG_MAGIC|BS_OPS, 53 bs_cf_gen, "( OLcfgDbAt:7.3 NAME 'olcOvSocketOps' " 54 "DESC 'Operation types to forward' " 55 "EQUALITY caseIgnoreMatch " 56 "SYNTAX OMsDirectoryString )", NULL, NULL }, 57 { "sockresps", "resps", 2, 0, 0, ARG_MAGIC|BS_RESP, 58 bs_cf_gen, "( OLcfgDbAt:7.4 NAME 'olcOvSocketResps' " 59 "DESC 'Response types to forward' " 60 "EQUALITY caseIgnoreMatch " 61 "SYNTAX OMsDirectoryString )", NULL, NULL }, 62 { "sockdnpat", "regexp", 2, 2, 0, ARG_MAGIC|BS_DNPAT, 63 bs_cf_gen, "( OLcfgDbAt:7.5 NAME 'olcOvSocketDNpat' " 64 "DESC 'DN pattern to match' " 65 "EQUALITY caseIgnoreMatch " 66 "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL }, 67 68 { "socketpath", "pathname", 2, 2, 0, ARG_STRING|ARG_OFFSET, 69 (void *)offsetof(struct sockinfo, si_sockpath), 70 "( OLcfgDbAt:7.1 NAME 'olcDbSocketPath' " 71 "DESC 'Pathname for Unix domain socket' " 72 "EQUALITY caseExactMatch " 73 "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL }, 74 { "extensions", "ext", 2, 0, 0, ARG_MAGIC|BS_EXT, 75 bs_cf_gen, "( OLcfgDbAt:7.2 NAME 'olcDbSocketExtensions' " 76 "DESC 'binddn, peername, or ssf' " 77 "EQUALITY caseIgnoreMatch " 78 "SYNTAX OMsDirectoryString )", NULL, NULL }, 79 { NULL, NULL } 80}; 81 82static ConfigOCs bsocs[] = { 83 { "( OLcfgDbOc:7.1 " 84 "NAME 'olcDbSocketConfig' " 85 "DESC 'Socket backend configuration' " 86 "SUP olcDatabaseConfig " 87 "MUST olcDbSocketPath " 88 "MAY olcDbSocketExtensions )", 89 Cft_Database, bscfg+NUM_OV_ATTRS }, 90 { NULL, 0, NULL } 91}; 92 93static ConfigOCs osocs[] = { 94 { "( OLcfgDbOc:7.2 " 95 "NAME 'olcOvSocketConfig' " 96 "DESC 'Socket overlay configuration' " 97 "SUP olcOverlayConfig " 98 "MUST olcDbSocketPath " 99 "MAY ( olcDbSocketExtensions $ " 100 " olcOvSocketOps $ olcOvSocketResps $ " 101 " olcOvSocketDNpat ) )", 102 Cft_Overlay, bscfg }, 103 { NULL, 0, NULL } 104}; 105 106#define SOCK_OP_BIND 0x001 107#define SOCK_OP_UNBIND 0x002 108#define SOCK_OP_SEARCH 0x004 109#define SOCK_OP_COMPARE 0x008 110#define SOCK_OP_MODIFY 0x010 111#define SOCK_OP_MODRDN 0x020 112#define SOCK_OP_ADD 0x040 113#define SOCK_OP_DELETE 0x080 114#define SOCK_OP_EXTENDED 0x100 115 116#define SOCK_REP_RESULT 0x001 117#define SOCK_REP_SEARCH 0x002 118 119static slap_verbmasks bs_exts[] = { 120 { BER_BVC("binddn"), SOCK_EXT_BINDDN }, 121 { BER_BVC("peername"), SOCK_EXT_PEERNAME }, 122 { BER_BVC("ssf"), SOCK_EXT_SSF }, 123 { BER_BVC("connid"), SOCK_EXT_CONNID }, 124 { BER_BVNULL, 0 } 125}; 126 127static slap_verbmasks ov_ops[] = { 128 { BER_BVC("bind"), SOCK_OP_BIND }, 129 { BER_BVC("unbind"), SOCK_OP_UNBIND }, 130 { BER_BVC("search"), SOCK_OP_SEARCH }, 131 { BER_BVC("compare"), SOCK_OP_COMPARE }, 132 { BER_BVC("modify"), SOCK_OP_MODIFY }, 133 { BER_BVC("modrdn"), SOCK_OP_MODRDN }, 134 { BER_BVC("add"), SOCK_OP_ADD }, 135 { BER_BVC("delete"), SOCK_OP_DELETE }, 136 { BER_BVC("extended"), SOCK_OP_EXTENDED }, 137 { BER_BVNULL, 0 } 138}; 139 140static slap_verbmasks ov_resps[] = { 141 { BER_BVC("result"), SOCK_REP_RESULT }, 142 { BER_BVC("search"), SOCK_REP_SEARCH }, 143 { BER_BVNULL, 0 } 144}; 145 146static int 147bs_cf_gen( ConfigArgs *c ) 148{ 149 struct sockinfo *si; 150 int rc; 151 152 if ( c->be && c->table == Cft_Database ) 153 si = c->be->be_private; 154 else if ( c->bi ) 155 si = c->bi->bi_private; 156 else 157 return ARG_BAD_CONF; 158 159 if ( c->op == SLAP_CONFIG_EMIT ) { 160 switch( c->type ) { 161 case BS_EXT: 162 return mask_to_verbs( bs_exts, si->si_extensions, &c->rvalue_vals ); 163 case BS_OPS: 164 return mask_to_verbs( ov_ops, si->si_ops, &c->rvalue_vals ); 165 case BS_RESP: 166 return mask_to_verbs( ov_resps, si->si_resps, &c->rvalue_vals ); 167 case BS_DNPAT: 168 value_add_one( &c->rvalue_vals, &si->si_dnpatstr ); 169 return 0; 170 } 171 } else if ( c->op == LDAP_MOD_DELETE ) { 172 switch( c->type ) { 173 case BS_EXT: 174 if ( c->valx < 0 ) { 175 si->si_extensions = 0; 176 rc = 0; 177 } else { 178 slap_mask_t dels = 0; 179 rc = verbs_to_mask( c->argc, c->argv, bs_exts, &dels ); 180 if ( rc == 0 ) 181 si->si_extensions ^= dels; 182 } 183 return rc; 184 case BS_OPS: 185 if ( c->valx < 0 ) { 186 si->si_ops = 0; 187 rc = 0; 188 } else { 189 slap_mask_t dels = 0; 190 rc = verbs_to_mask( c->argc, c->argv, ov_ops, &dels ); 191 if ( rc == 0 ) 192 si->si_ops ^= dels; 193 } 194 return rc; 195 case BS_RESP: 196 if ( c->valx < 0 ) { 197 si->si_resps = 0; 198 rc = 0; 199 } else { 200 slap_mask_t dels = 0; 201 rc = verbs_to_mask( c->argc, c->argv, ov_resps, &dels ); 202 if ( rc == 0 ) 203 si->si_resps ^= dels; 204 } 205 return rc; 206 case BS_DNPAT: 207 regfree( &si->si_dnpat ); 208 ch_free( si->si_dnpatstr.bv_val ); 209 BER_BVZERO( &si->si_dnpatstr ); 210 return 0; 211 } 212 213 } else { 214 switch( c->type ) { 215 case BS_EXT: 216 return verbs_to_mask( c->argc, c->argv, bs_exts, &si->si_extensions ); 217 case BS_OPS: 218 return verbs_to_mask( c->argc, c->argv, ov_ops, &si->si_ops ); 219 case BS_RESP: 220 return verbs_to_mask( c->argc, c->argv, ov_resps, &si->si_resps ); 221 case BS_DNPAT: 222 if ( !regcomp( &si->si_dnpat, c->argv[1], REG_EXTENDED|REG_ICASE|REG_NOSUB )) { 223 ber_str2bv( c->argv[1], 0, 1, &si->si_dnpatstr ); 224 return 0; 225 } else { 226 return 1; 227 } 228 } 229 } 230 return 1; 231} 232 233int 234sock_back_init_cf( BackendInfo *bi ) 235{ 236 int rc; 237 bi->bi_cf_ocs = bsocs; 238 239 rc = config_register_schema( bscfg, bsocs ); 240 if ( !rc ) 241 rc = sock_over_setup(); 242 return rc; 243} 244 245/* sock overlay wrapper */ 246static slap_overinst sockover; 247 248static int sock_over_db_init( Backend *be, struct config_reply_s *cr ); 249static int sock_over_db_destroy( Backend *be, struct config_reply_s *cr ); 250 251static BI_op_bind *sockfuncs[] = { 252 sock_back_bind, 253 sock_back_unbind, 254 sock_back_search, 255 sock_back_compare, 256 sock_back_modify, 257 sock_back_modrdn, 258 sock_back_add, 259 sock_back_delete, 260 0, /* abandon not supported */ 261 sock_back_extended 262}; 263 264static const int sockopflags[] = { 265 SOCK_OP_BIND, 266 SOCK_OP_UNBIND, 267 SOCK_OP_SEARCH, 268 SOCK_OP_COMPARE, 269 SOCK_OP_MODIFY, 270 SOCK_OP_MODRDN, 271 SOCK_OP_ADD, 272 SOCK_OP_DELETE, 273 0, /* abandon not supported */ 274 SOCK_OP_EXTENDED 275}; 276 277static int sock_over_op( 278 Operation *op, 279 SlapReply *rs 280) 281{ 282 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info; 283 void *private = op->o_bd->be_private; 284 slap_callback *sc; 285 struct sockinfo *si; 286 slap_operation_t which; 287 288 switch (op->o_tag) { 289 case LDAP_REQ_BIND: which = op_bind; break; 290 case LDAP_REQ_UNBIND: which = op_unbind; break; 291 case LDAP_REQ_SEARCH: which = op_search; break; 292 case LDAP_REQ_COMPARE: which = op_compare; break; 293 case LDAP_REQ_MODIFY: which = op_modify; break; 294 case LDAP_REQ_MODRDN: which = op_modrdn; break; 295 case LDAP_REQ_ADD: which = op_add; break; 296 case LDAP_REQ_DELETE: which = op_delete; break; 297 case LDAP_REQ_EXTENDED: which = op_extended; break; 298 default: 299 return SLAP_CB_CONTINUE; 300 } 301 si = on->on_bi.bi_private; 302 if ( !(si->si_ops & sockopflags[which])) 303 return SLAP_CB_CONTINUE; 304 305 if ( !BER_BVISEMPTY( &si->si_dnpatstr ) && 306 regexec( &si->si_dnpat, op->o_req_ndn.bv_val, 0, NULL, 0 )) 307 return SLAP_CB_CONTINUE; 308 309 op->o_bd->be_private = si; 310 sc = op->o_callback; 311 op->o_callback = NULL; 312 sockfuncs[which]( op, rs ); 313 op->o_bd->be_private = private; 314 op->o_callback = sc; 315 return rs->sr_err; 316} 317 318static int 319sock_over_response( Operation *op, SlapReply *rs ) 320{ 321 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info; 322 struct sockinfo *si = (struct sockinfo *)on->on_bi.bi_private; 323 FILE *fp; 324 325 if ( rs->sr_type == REP_RESULT ) { 326 if ( !( si->si_resps & SOCK_REP_RESULT )) 327 return SLAP_CB_CONTINUE; 328 } else if ( rs->sr_type == REP_SEARCH ) { 329 if ( !( si->si_resps & SOCK_REP_SEARCH )) 330 return SLAP_CB_CONTINUE; 331 } else 332 return SLAP_CB_CONTINUE; 333 334 if (( fp = opensock( si->si_sockpath )) == NULL ) 335 return SLAP_CB_CONTINUE; 336 337 if ( rs->sr_type == REP_RESULT ) { 338 /* write out the result */ 339 fprintf( fp, "RESULT\n" ); 340 fprintf( fp, "msgid: %ld\n", (long) op->o_msgid ); 341 sock_print_conn( fp, op->o_conn, si ); 342 fprintf( fp, "code: %d\n", rs->sr_err ); 343 if ( rs->sr_matched ) 344 fprintf( fp, "matched: %s\n", rs->sr_matched ); 345 if (rs->sr_text ) 346 fprintf( fp, "info: %s\n", rs->sr_text ); 347 } else { 348 /* write out the search entry */ 349 int len; 350 fprintf( fp, "ENTRY\n" ); 351 fprintf( fp, "msgid: %ld\n", (long) op->o_msgid ); 352 sock_print_conn( fp, op->o_conn, si ); 353 ldap_pvt_thread_mutex_lock( &entry2str_mutex ); 354 fprintf( fp, "%s", entry2str( rs->sr_entry, &len ) ); 355 ldap_pvt_thread_mutex_unlock( &entry2str_mutex ); 356 } 357 fprintf( fp, "\n" ); 358 fclose( fp ); 359 360 return SLAP_CB_CONTINUE; 361} 362 363static int 364sock_over_setup() 365{ 366 int rc; 367 368 sockover.on_bi.bi_type = "sock"; 369 sockover.on_bi.bi_db_init = sock_over_db_init; 370 sockover.on_bi.bi_db_destroy = sock_over_db_destroy; 371 372 sockover.on_bi.bi_op_bind = sock_over_op; 373 sockover.on_bi.bi_op_unbind = sock_over_op; 374 sockover.on_bi.bi_op_search = sock_over_op; 375 sockover.on_bi.bi_op_compare = sock_over_op; 376 sockover.on_bi.bi_op_modify = sock_over_op; 377 sockover.on_bi.bi_op_modrdn = sock_over_op; 378 sockover.on_bi.bi_op_add = sock_over_op; 379 sockover.on_bi.bi_op_delete = sock_over_op; 380 sockover.on_bi.bi_extended = sock_over_op; 381 sockover.on_response = sock_over_response; 382 383 sockover.on_bi.bi_cf_ocs = osocs; 384 385 rc = config_register_schema( bscfg, osocs ); 386 if ( rc ) return rc; 387 388 return overlay_register( &sockover ); 389} 390 391static int 392sock_over_db_init( 393 Backend *be, 394 struct config_reply_s *cr 395) 396{ 397 slap_overinst *on = (slap_overinst *)be->bd_info; 398 void *private = be->be_private; 399 void *cf_ocs = be->be_cf_ocs; 400 int rc; 401 402 be->be_private = NULL; 403 rc = sock_back_db_init( be, cr ); 404 on->on_bi.bi_private = be->be_private; 405 be->be_private = private; 406 be->be_cf_ocs = cf_ocs; 407 return rc; 408} 409 410static int 411sock_over_db_destroy( 412 Backend *be, 413 struct config_reply_s *cr 414) 415{ 416 slap_overinst *on = (slap_overinst *)be->bd_info; 417 void *private = be->be_private; 418 int rc; 419 420 be->be_private = on->on_bi.bi_private; 421 rc = sock_back_db_destroy( be, cr ); 422 on->on_bi.bi_private = be->be_private; 423 be->be_private = private; 424 return rc; 425} 426