config.c revision 1.1.1.7
1/* $NetBSD: config.c,v 1.1.1.7 2019/08/08 13:31:45 christos Exp $ */ 2 3/* $OpenLDAP$ */ 4/* This work is part of OpenLDAP Software <http://www.openldap.org/>. 5 * 6 * Copyright 1999-2019 The OpenLDAP Foundation. 7 * Portions Copyright 1999 Dmitry Kovalev. 8 * Portions Copyright 2002 Pierangelo Masarati. 9 * Portions Copyright 2004 Mark Adamson. 10 * All rights reserved. 11 * 12 * Redistribution and use in source and binary forms, with or without 13 * modification, are permitted only as authorized by the OpenLDAP 14 * Public License. 15 * 16 * A copy of this license is available in the file LICENSE in the 17 * top-level directory of the distribution or, alternatively, at 18 * <http://www.OpenLDAP.org/license.html>. 19 */ 20/* ACKNOWLEDGEMENTS: 21 * This work was initially developed by Dmitry Kovalev for inclusion 22 * by OpenLDAP Software. Additional significant contributors include 23 * Pierangelo Masarati. 24 */ 25 26#include <sys/cdefs.h> 27__RCSID("$NetBSD: config.c,v 1.1.1.7 2019/08/08 13:31:45 christos Exp $"); 28 29#include "portable.h" 30 31#include <stdio.h> 32#include "ac/string.h" 33#include <sys/types.h> 34 35#include "slap.h" 36#include "config.h" 37#include "ldif.h" 38#include "lutil.h" 39#include "proto-sql.h" 40 41static int 42create_baseObject( 43 BackendDB *be, 44 const char *fname, 45 int lineno ); 46 47static int 48read_baseObject( 49 BackendDB *be, 50 const char *fname ); 51 52static ConfigDriver sql_cf_gen; 53 54enum { 55 BSQL_CONCAT_PATT = 1, 56 BSQL_CREATE_NEEDS_SEL, 57 BSQL_UPPER_NEEDS_CAST, 58 BSQL_HAS_LDAPINFO_DN_RU, 59 BSQL_FAIL_IF_NO_MAPPING, 60 BSQL_ALLOW_ORPHANS, 61 BSQL_BASE_OBJECT, 62 BSQL_LAYER, 63 BSQL_SUBTREE_SHORTCUT, 64 BSQL_FETCH_ALL_ATTRS, 65 BSQL_FETCH_ATTRS, 66 BSQL_CHECK_SCHEMA, 67 BSQL_ALIASING_KEYWORD, 68 BSQL_AUTOCOMMIT 69}; 70 71static ConfigTable sqlcfg[] = { 72 { "dbhost", "hostname", 2, 2, 0, ARG_STRING|ARG_OFFSET, 73 (void *)offsetof(struct backsql_info, sql_dbhost), 74 "( OLcfgDbAt:6.1 NAME 'olcDbHost' " 75 "DESC 'Hostname of SQL server' " 76 "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL }, 77 { "dbname", "name", 2, 2, 0, ARG_STRING|ARG_OFFSET, 78 (void *)offsetof(struct backsql_info, sql_dbname), 79 "( OLcfgDbAt:6.2 NAME 'olcDbName' " 80 "DESC 'Name of SQL database' " 81 "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL }, 82 { "dbuser", "username", 2, 2, 0, ARG_STRING|ARG_OFFSET, 83 (void *)offsetof(struct backsql_info, sql_dbuser), 84 "( OLcfgDbAt:6.3 NAME 'olcDbUser' " 85 "DESC 'Username for SQL session' " 86 "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL }, 87 { "dbpasswd", "password", 2, 2, 0, ARG_STRING|ARG_OFFSET, 88 (void *)offsetof(struct backsql_info, sql_dbpasswd), 89 "( OLcfgDbAt:6.4 NAME 'olcDbPass' " 90 "DESC 'Password for SQL session' " 91 "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL }, 92 { "concat_pattern", "pattern", 2, 2, 0, 93 ARG_STRING|ARG_MAGIC|BSQL_CONCAT_PATT, (void *)sql_cf_gen, 94 "( OLcfgDbAt:6.20 NAME 'olcSqlConcatPattern' " 95 "DESC 'Pattern used to concatenate strings' " 96 "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL }, 97 { "subtree_cond", "SQL expression", 2, 0, 0, ARG_BERVAL|ARG_QUOTE|ARG_OFFSET, 98 (void *)offsetof(struct backsql_info, sql_subtree_cond), 99 "( OLcfgDbAt:6.21 NAME 'olcSqlSubtreeCond' " 100 "DESC 'Where-clause template for a subtree search condition' " 101 "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL }, 102 { "children_cond", "SQL expression", 2, 0, 0, ARG_BERVAL|ARG_QUOTE|ARG_OFFSET, 103 (void *)offsetof(struct backsql_info, sql_children_cond), 104 "( OLcfgDbAt:6.22 NAME 'olcSqlChildrenCond' " 105 "DESC 'Where-clause template for a children search condition' " 106 "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL }, 107 { "dn_match_cond", "SQL expression", 2, 0, 0, ARG_BERVAL|ARG_QUOTE|ARG_OFFSET, 108 (void *)offsetof(struct backsql_info, sql_dn_match_cond), 109 "( OLcfgDbAt:6.23 NAME 'olcSqlDnMatchCond' " 110 "DESC 'Where-clause template for a DN match search condition' " 111 "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL }, 112 { "oc_query", "SQL expression", 2, 0, 0, ARG_STRING|ARG_QUOTE|ARG_OFFSET, 113 (void *)offsetof(struct backsql_info, sql_oc_query), 114 "( OLcfgDbAt:6.24 NAME 'olcSqlOcQuery' " 115 "DESC 'Query used to collect objectClass mapping data' " 116 "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL }, 117 { "at_query", "SQL expression", 2, 0, 0, ARG_STRING|ARG_QUOTE|ARG_OFFSET, 118 (void *)offsetof(struct backsql_info, sql_at_query), 119 "( OLcfgDbAt:6.25 NAME 'olcSqlAtQuery' " 120 "DESC 'Query used to collect attributeType mapping data' " 121 "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL }, 122 { "insentry_stmt", "SQL expression", 2, 0, 0, ARG_STRING|ARG_QUOTE|ARG_OFFSET, 123 (void *)offsetof(struct backsql_info, sql_insentry_stmt), 124 "( OLcfgDbAt:6.26 NAME 'olcSqlInsEntryStmt' " 125 "DESC 'Statement used to insert a new entry' " 126 "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL }, 127 { "create_needs_select", "yes|no", 2, 2, 0, 128 ARG_ON_OFF|ARG_MAGIC|BSQL_CREATE_NEEDS_SEL, (void *)sql_cf_gen, 129 "( OLcfgDbAt:6.27 NAME 'olcSqlCreateNeedsSelect' " 130 "DESC 'Whether entry creation needs a subsequent select' " 131 "SYNTAX OMsBoolean SINGLE-VALUE )", NULL, NULL }, 132 { "upper_func", "SQL function name", 2, 2, 0, ARG_BERVAL|ARG_OFFSET, 133 (void *)offsetof(struct backsql_info, sql_upper_func), 134 "( OLcfgDbAt:6.28 NAME 'olcSqlUpperFunc' " 135 "DESC 'Function that converts a value to uppercase' " 136 "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL }, 137 { "upper_needs_cast", "yes|no", 2, 2, 0, 138 ARG_ON_OFF|ARG_MAGIC|BSQL_UPPER_NEEDS_CAST, (void *)sql_cf_gen, 139 "( OLcfgDbAt:6.29 NAME 'olcSqlUpperNeedsCast' " 140 "DESC 'Whether olcSqlUpperFunc needs an explicit cast' " 141 "SYNTAX OMsBoolean SINGLE-VALUE )", NULL, NULL }, 142 { "strcast_func", "SQL function name", 2, 2, 0, ARG_BERVAL|ARG_OFFSET, 143 (void *)offsetof(struct backsql_info, sql_strcast_func), 144 "( OLcfgDbAt:6.30 NAME 'olcSqlStrcastFunc' " 145 "DESC 'Function that converts a value to a string' " 146 "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL }, 147 { "delentry_stmt", "SQL expression", 2, 0, 0, ARG_STRING|ARG_QUOTE|ARG_OFFSET, 148 (void *)offsetof(struct backsql_info, sql_delentry_stmt), 149 "( OLcfgDbAt:6.31 NAME 'olcSqlDelEntryStmt' " 150 "DESC 'Statement used to delete an existing entry' " 151 "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL }, 152 { "renentry_stmt", "SQL expression", 2, 0, 0, ARG_STRING|ARG_QUOTE|ARG_OFFSET, 153 (void *)offsetof(struct backsql_info, sql_renentry_stmt), 154 "( OLcfgDbAt:6.32 NAME 'olcSqlRenEntryStmt' " 155 "DESC 'Statement used to rename an entry' " 156 "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL }, 157 { "delobjclasses_stmt", "SQL expression", 2, 0, 0, ARG_STRING|ARG_QUOTE|ARG_OFFSET, 158 (void *)offsetof(struct backsql_info, sql_delobjclasses_stmt), 159 "( OLcfgDbAt:6.33 NAME 'olcSqlDelObjclassesStmt' " 160 "DESC 'Statement used to delete the ID of an entry' " 161 "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL }, 162 { "has_ldapinfo_dn_ru", "yes|no", 2, 2, 0, 163 ARG_ON_OFF|ARG_MAGIC|BSQL_HAS_LDAPINFO_DN_RU, (void *)sql_cf_gen, 164 "( OLcfgDbAt:6.34 NAME 'olcSqlHasLDAPinfoDnRu' " 165 "DESC 'Whether the dn_ru column is present' " 166 "SYNTAX OMsBoolean SINGLE-VALUE )", NULL, NULL }, 167 { "fail_if_no_mapping", "yes|no", 2, 2, 0, 168 ARG_ON_OFF|ARG_MAGIC|BSQL_FAIL_IF_NO_MAPPING, (void *)sql_cf_gen, 169 "( OLcfgDbAt:6.35 NAME 'olcSqlFailIfNoMapping' " 170 "DESC 'Whether to fail on unknown attribute mappings' " 171 "SYNTAX OMsBoolean SINGLE-VALUE )", NULL, NULL }, 172 { "allow_orphans", "yes|no", 2, 2, 0, 173 ARG_ON_OFF|ARG_MAGIC|BSQL_ALLOW_ORPHANS, (void *)sql_cf_gen, 174 "( OLcfgDbAt:6.36 NAME 'olcSqlAllowOrphans' " 175 "DESC 'Whether to allow adding entries with no parent' " 176 "SYNTAX OMsBoolean SINGLE-VALUE )", NULL, NULL }, 177 { "baseobject", "[file]", 1, 2, 0, 178 ARG_STRING|ARG_MAGIC|BSQL_BASE_OBJECT, (void *)sql_cf_gen, 179 "( OLcfgDbAt:6.37 NAME 'olcSqlBaseObject' " 180 "DESC 'Manage an in-memory baseObject entry' " 181 "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL }, 182 { "sqllayer", "name", 2, 0, 0, 183 ARG_MAGIC|BSQL_LAYER, (void *)sql_cf_gen, 184 "( OLcfgDbAt:6.38 NAME 'olcSqlLayer' " 185 "DESC 'Helper used to map DNs between LDAP and SQL' " 186 "SYNTAX OMsDirectoryString )", NULL, NULL }, 187 { "use_subtree_shortcut", "yes|no", 2, 2, 0, 188 ARG_ON_OFF|ARG_MAGIC|BSQL_SUBTREE_SHORTCUT, (void *)sql_cf_gen, 189 "( OLcfgDbAt:6.39 NAME 'olcSqlUseSubtreeShortcut' " 190 "DESC 'Collect all entries when searchBase is DB suffix' " 191 "SYNTAX OMsBoolean SINGLE-VALUE )", NULL, NULL }, 192 { "fetch_all_attrs", "yes|no", 2, 2, 0, 193 ARG_ON_OFF|ARG_MAGIC|BSQL_FETCH_ALL_ATTRS, (void *)sql_cf_gen, 194 "( OLcfgDbAt:6.40 NAME 'olcSqlFetchAllAttrs' " 195 "DESC 'Require all attributes to always be loaded' " 196 "SYNTAX OMsBoolean SINGLE-VALUE )", NULL, NULL }, 197 { "fetch_attrs", "attrlist", 2, 0, 0, 198 ARG_MAGIC|BSQL_FETCH_ATTRS, (void *)sql_cf_gen, 199 "( OLcfgDbAt:6.41 NAME 'olcSqlFetchAttrs' " 200 "DESC 'Set of attributes to always fetch' " 201 "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL }, 202 { "check_schema", "yes|no", 2, 2, 0, 203 ARG_ON_OFF|ARG_MAGIC|BSQL_CHECK_SCHEMA, (void *)sql_cf_gen, 204 "( OLcfgDbAt:6.42 NAME 'olcSqlCheckSchema' " 205 "DESC 'Check schema after modifications' " 206 "SYNTAX OMsBoolean SINGLE-VALUE )", NULL, NULL }, 207 { "aliasing_keyword", "string", 2, 2, 0, 208 ARG_STRING|ARG_MAGIC|BSQL_ALIASING_KEYWORD, (void *)sql_cf_gen, 209 "( OLcfgDbAt:6.43 NAME 'olcSqlAliasingKeyword' " 210 "DESC 'The aliasing keyword' " 211 "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL }, 212 { "aliasing_quote", "string", 2, 2, 0, ARG_BERVAL|ARG_OFFSET, 213 (void *)offsetof(struct backsql_info, sql_aliasing_quote), 214 "( OLcfgDbAt:6.44 NAME 'olcSqlAliasingQuote' " 215 "DESC 'Quoting char of the aliasing keyword' " 216 "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL }, 217 { "autocommit", "yes|no", 2, 2, 0, 218 ARG_ON_OFF|ARG_MAGIC|BSQL_AUTOCOMMIT, (void *)sql_cf_gen, 219 "( OLcfgDbAt:6.45 NAME 'olcSqlAutocommit' " 220 "SYNTAX OMsBoolean SINGLE-VALUE )", NULL, NULL }, 221 { "id_query", "SQL expression", 2, 0, 0, ARG_STRING|ARG_QUOTE|ARG_OFFSET, 222 (void *)offsetof(struct backsql_info, sql_id_query), 223 "( OLcfgDbAt:6.46 NAME 'olcSqlIdQuery' " 224 "DESC 'Query used to collect entryID mapping data' " 225 "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL }, 226 { NULL, NULL, 0, 0, 0, ARG_IGNORED, 227 NULL, NULL, NULL, NULL } 228}; 229 230static ConfigOCs sqlocs[] = { 231 { 232 "( OLcfgDbOc:6.1 " 233 "NAME 'olcSqlConfig' " 234 "DESC 'SQL backend configuration' " 235 "SUP olcDatabaseConfig " 236 "MUST olcDbName " 237 "MAY ( olcDbHost $ olcDbUser $ olcDbPass $ olcSqlConcatPattern $ " 238 "olcSqlSubtreeCond $ olcsqlChildrenCond $ olcSqlDnMatchCond $ " 239 "olcSqlOcQuery $ olcSqlAtQuery $ olcSqlInsEntryStmt $ " 240 "olcSqlCreateNeedsSelect $ olcSqlUpperFunc $ olcSqlUpperNeedsCast $ " 241 "olcSqlStrCastFunc $ olcSqlDelEntryStmt $ olcSqlRenEntryStmt $ " 242 "olcSqlDelObjClassesStmt $ olcSqlHasLDAPInfoDnRu $ " 243 "olcSqlFailIfNoMapping $ olcSqlAllowOrphans $ olcSqlBaseObject $ " 244 "olcSqlLayer $ olcSqlUseSubtreeShortcut $ olcSqlFetchAllAttrs $ " 245 "olcSqlFetchAttrs $ olcSqlCheckSchema $ olcSqlAliasingKeyword $ " 246 "olcSqlAliasingQuote $ olcSqlAutocommit $ olcSqlIdQuery ) )", 247 Cft_Database, sqlcfg }, 248 { NULL, Cft_Abstract, NULL } 249}; 250 251static int 252sql_cf_gen( ConfigArgs *c ) 253{ 254 backsql_info *bi = (backsql_info *)c->be->be_private; 255 int rc = 0; 256 257 if ( c->op == SLAP_CONFIG_EMIT ) { 258 switch( c->type ) { 259 case BSQL_CONCAT_PATT: 260 if ( bi->sql_concat_patt ) { 261 c->value_string = ch_strdup( bi->sql_concat_patt ); 262 } else { 263 rc = 1; 264 } 265 break; 266 case BSQL_CREATE_NEEDS_SEL: 267 if ( bi->sql_flags & BSQLF_CREATE_NEEDS_SELECT ) 268 c->value_int = 1; 269 break; 270 case BSQL_UPPER_NEEDS_CAST: 271 if ( bi->sql_flags & BSQLF_UPPER_NEEDS_CAST ) 272 c->value_int = 1; 273 break; 274 case BSQL_HAS_LDAPINFO_DN_RU: 275 if ( !(bi->sql_flags & BSQLF_DONTCHECK_LDAPINFO_DN_RU) ) 276 return 1; 277 if ( bi->sql_flags & BSQLF_HAS_LDAPINFO_DN_RU ) 278 c->value_int = 1; 279 break; 280 case BSQL_FAIL_IF_NO_MAPPING: 281 if ( bi->sql_flags & BSQLF_FAIL_IF_NO_MAPPING ) 282 c->value_int = 1; 283 break; 284 case BSQL_ALLOW_ORPHANS: 285 if ( bi->sql_flags & BSQLF_ALLOW_ORPHANS ) 286 c->value_int = 1; 287 break; 288 case BSQL_SUBTREE_SHORTCUT: 289 if ( bi->sql_flags & BSQLF_USE_SUBTREE_SHORTCUT ) 290 c->value_int = 1; 291 break; 292 case BSQL_FETCH_ALL_ATTRS: 293 if ( bi->sql_flags & BSQLF_FETCH_ALL_ATTRS ) 294 c->value_int = 1; 295 break; 296 case BSQL_CHECK_SCHEMA: 297 if ( bi->sql_flags & BSQLF_CHECK_SCHEMA ) 298 c->value_int = 1; 299 break; 300 case BSQL_AUTOCOMMIT: 301 if ( bi->sql_flags & BSQLF_AUTOCOMMIT_ON ) 302 c->value_int = 1; 303 break; 304 case BSQL_BASE_OBJECT: 305 if ( bi->sql_base_ob_file ) { 306 c->value_string = ch_strdup( bi->sql_base_ob_file ); 307 } else if ( bi->sql_baseObject ) { 308 c->value_string = ch_strdup( "TRUE" ); 309 } else { 310 rc = 1; 311 } 312 break; 313 case BSQL_LAYER: 314 if ( bi->sql_api ) { 315 backsql_api *ba; 316 struct berval bv; 317 char *ptr; 318 int i; 319 for ( ba = bi->sql_api; ba; ba = ba->ba_next ) { 320 bv.bv_len = strlen( ba->ba_name ); 321 if ( ba->ba_argc ) { 322 for ( i = 0; i<ba->ba_argc; i++ ) 323 bv.bv_len += strlen( ba->ba_argv[i] ) + 3; 324 } 325 bv.bv_val = ch_malloc( bv.bv_len + 1 ); 326 ptr = lutil_strcopy( bv.bv_val, ba->ba_name ); 327 if ( ba->ba_argc ) { 328 for ( i = 0; i<ba->ba_argc; i++ ) { 329 *ptr++ = ' '; 330 *ptr++ = '"'; 331 ptr = lutil_strcopy( ptr, ba->ba_argv[i] ); 332 *ptr++ = '"'; 333 } 334 } 335 ber_bvarray_add( &c->rvalue_vals, &bv ); 336 } 337 } else { 338 rc = 1; 339 } 340 break; 341 case BSQL_ALIASING_KEYWORD: 342 if ( !BER_BVISNULL( &bi->sql_aliasing )) { 343 struct berval bv; 344 bv = bi->sql_aliasing; 345 bv.bv_len--; 346 value_add_one( &c->rvalue_vals, &bv ); 347 } else { 348 rc = 1; 349 } 350 break; 351 case BSQL_FETCH_ATTRS: 352 if ( bi->sql_anlist || 353 ( bi->sql_flags & (BSQLF_FETCH_ALL_USERATTRS| 354 BSQLF_FETCH_ALL_OPATTRS))) 355 { 356 char buf[BUFSIZ*2], *ptr; 357 struct berval bv; 358# define WHATSLEFT ((ber_len_t) (&buf[sizeof( buf )] - ptr)) 359 ptr = buf; 360 if ( bi->sql_anlist ) { 361 ptr = anlist_unparse( bi->sql_anlist, ptr, WHATSLEFT ); 362 if ( ptr == NULL ) 363 return 1; 364 } 365 if ( bi->sql_flags & BSQLF_FETCH_ALL_USERATTRS ) { 366 if ( WHATSLEFT <= STRLENOF( ",*" )) return 1; 367 if ( ptr != buf ) *ptr++ = ','; 368 *ptr++ = '*'; 369 } 370 if ( bi->sql_flags & BSQLF_FETCH_ALL_OPATTRS ) { 371 if ( WHATSLEFT <= STRLENOF( ",+" )) return 1; 372 if ( ptr != buf ) *ptr++ = ','; 373 *ptr++ = '+'; 374 } 375 bv.bv_val = buf; 376 bv.bv_len = ptr - buf; 377 value_add_one( &c->rvalue_vals, &bv ); 378 } 379 break; 380 } 381 return rc; 382 } else if ( c->op == LDAP_MOD_DELETE ) { /* FIXME */ 383 return -1; 384 } 385 386 switch( c->type ) { 387 case BSQL_CONCAT_PATT: 388 if ( backsql_split_pattern( c->argv[ 1 ], &bi->sql_concat_func, 2 ) ) { 389 snprintf( c->cr_msg, sizeof( c->cr_msg ), 390 "%s: unable to parse pattern \"%s\"", 391 c->log, c->argv[ 1 ] ); 392 Debug( LDAP_DEBUG_ANY, "%s\n", c->cr_msg, 0, 0 ); 393 return -1; 394 } 395 bi->sql_concat_patt = c->value_string; 396 break; 397 case BSQL_CREATE_NEEDS_SEL: 398 if ( c->value_int ) 399 bi->sql_flags |= BSQLF_CREATE_NEEDS_SELECT; 400 else 401 bi->sql_flags &= ~BSQLF_CREATE_NEEDS_SELECT; 402 break; 403 case BSQL_UPPER_NEEDS_CAST: 404 if ( c->value_int ) 405 bi->sql_flags |= BSQLF_UPPER_NEEDS_CAST; 406 else 407 bi->sql_flags &= ~BSQLF_UPPER_NEEDS_CAST; 408 break; 409 case BSQL_HAS_LDAPINFO_DN_RU: 410 bi->sql_flags |= BSQLF_DONTCHECK_LDAPINFO_DN_RU; 411 if ( c->value_int ) 412 bi->sql_flags |= BSQLF_HAS_LDAPINFO_DN_RU; 413 else 414 bi->sql_flags &= ~BSQLF_HAS_LDAPINFO_DN_RU; 415 break; 416 case BSQL_FAIL_IF_NO_MAPPING: 417 if ( c->value_int ) 418 bi->sql_flags |= BSQLF_FAIL_IF_NO_MAPPING; 419 else 420 bi->sql_flags &= ~BSQLF_FAIL_IF_NO_MAPPING; 421 break; 422 case BSQL_ALLOW_ORPHANS: 423 if ( c->value_int ) 424 bi->sql_flags |= BSQLF_ALLOW_ORPHANS; 425 else 426 bi->sql_flags &= ~BSQLF_ALLOW_ORPHANS; 427 break; 428 case BSQL_SUBTREE_SHORTCUT: 429 if ( c->value_int ) 430 bi->sql_flags |= BSQLF_USE_SUBTREE_SHORTCUT; 431 else 432 bi->sql_flags &= ~BSQLF_USE_SUBTREE_SHORTCUT; 433 break; 434 case BSQL_FETCH_ALL_ATTRS: 435 if ( c->value_int ) 436 bi->sql_flags |= BSQLF_FETCH_ALL_ATTRS; 437 else 438 bi->sql_flags &= ~BSQLF_FETCH_ALL_ATTRS; 439 break; 440 case BSQL_CHECK_SCHEMA: 441 if ( c->value_int ) 442 bi->sql_flags |= BSQLF_CHECK_SCHEMA; 443 else 444 bi->sql_flags &= ~BSQLF_CHECK_SCHEMA; 445 break; 446 case BSQL_AUTOCOMMIT: 447 if ( c->value_int ) 448 bi->sql_flags |= BSQLF_AUTOCOMMIT_ON; 449 else 450 bi->sql_flags &= ~BSQLF_AUTOCOMMIT_ON; 451 break; 452 case BSQL_BASE_OBJECT: 453 if ( c->be->be_nsuffix == NULL ) { 454 snprintf( c->cr_msg, sizeof( c->cr_msg ), 455 "%s: suffix must be set", c->log ); 456 Debug( LDAP_DEBUG_ANY, "%s\n", c->cr_msg, 0, 0 ); 457 rc = ARG_BAD_CONF; 458 break; 459 } 460 if ( bi->sql_baseObject ) { 461 Debug( LDAP_DEBUG_CONFIG, 462 "%s: " 463 "\"baseObject\" already provided (will be overwritten)\n", 464 c->log, 0, 0 ); 465 entry_free( bi->sql_baseObject ); 466 } 467 if ( c->argc == 2 && !strcmp( c->argv[1], "TRUE" )) 468 c->argc = 1; 469 switch( c->argc ) { 470 case 1: 471 return create_baseObject( c->be, c->fname, c->lineno ); 472 473 case 2: 474 rc = read_baseObject( c->be, c->argv[ 1 ] ); 475 if ( rc == 0 ) { 476 ch_free( bi->sql_base_ob_file ); 477 bi->sql_base_ob_file = c->value_string; 478 } 479 return rc; 480 481 default: 482 snprintf( c->cr_msg, sizeof( c->cr_msg ), 483 "%s: trailing values in directive", c->log ); 484 Debug( LDAP_DEBUG_ANY, "%s\n", c->cr_msg, 0, 0 ); 485 return 1; 486 } 487 break; 488 case BSQL_LAYER: 489 if ( backsql_api_config( bi, c->argv[ 1 ], c->argc - 2, &c->argv[ 2 ] ) ) 490 { 491 snprintf( c->cr_msg, sizeof( c->cr_msg ), 492 "%s: unable to load sql layer", c->log ); 493 Debug( LDAP_DEBUG_ANY, "%s \"%s\"\n", 494 c->cr_msg, c->argv[1], 0 ); 495 return 1; 496 } 497 break; 498 case BSQL_ALIASING_KEYWORD: 499 if ( ! BER_BVISNULL( &bi->sql_aliasing ) ) { 500 ch_free( bi->sql_aliasing.bv_val ); 501 } 502 503 ber_str2bv( c->argv[ 1 ], strlen( c->argv[ 1 ] ) + 1, 1, 504 &bi->sql_aliasing ); 505 /* add a trailing space... */ 506 bi->sql_aliasing.bv_val[ bi->sql_aliasing.bv_len - 1] = ' '; 507 break; 508 case BSQL_FETCH_ATTRS: { 509 char *str, *s, *next; 510 const char *delimstr = ","; 511 512 str = ch_strdup( c->argv[ 1 ] ); 513 for ( s = ldap_pvt_strtok( str, delimstr, &next ); 514 s != NULL; 515 s = ldap_pvt_strtok( NULL, delimstr, &next ) ) 516 { 517 if ( strlen( s ) == 1 ) { 518 if ( *s == '*' ) { 519 bi->sql_flags |= BSQLF_FETCH_ALL_USERATTRS; 520 c->argv[ 1 ][ s - str ] = ','; 521 522 } else if ( *s == '+' ) { 523 bi->sql_flags |= BSQLF_FETCH_ALL_OPATTRS; 524 c->argv[ 1 ][ s - str ] = ','; 525 } 526 } 527 } 528 ch_free( str ); 529 bi->sql_anlist = str2anlist( bi->sql_anlist, c->argv[ 1 ], delimstr ); 530 if ( bi->sql_anlist == NULL ) { 531 return -1; 532 } 533 } 534 break; 535 } 536 return rc; 537} 538 539/* 540 * Read the entries specified in fname and merge the attributes 541 * to the user defined baseObject entry. Note that if we find any errors 542 * what so ever, we will discard the entire entries, print an 543 * error message and return. 544 */ 545static int 546read_baseObject( 547 BackendDB *be, 548 const char *fname ) 549{ 550 backsql_info *bi = (backsql_info *)be->be_private; 551 LDIFFP *fp; 552 int rc = 0, lmax = 0, ldifrc; 553 unsigned long lineno = 0; 554 char *buf = NULL; 555 556 assert( fname != NULL ); 557 558 fp = ldif_open( fname, "r" ); 559 if ( fp == NULL ) { 560 Debug( LDAP_DEBUG_ANY, 561 "could not open back-sql baseObject " 562 "attr file \"%s\" - absolute path?\n", 563 fname, 0, 0 ); 564 perror( fname ); 565 return LDAP_OTHER; 566 } 567 568 bi->sql_baseObject = entry_alloc(); 569 if ( bi->sql_baseObject == NULL ) { 570 Debug( LDAP_DEBUG_ANY, 571 "read_baseObject_file: entry_alloc failed", 0, 0, 0 ); 572 ldif_close( fp ); 573 return LDAP_NO_MEMORY; 574 } 575 bi->sql_baseObject->e_name = be->be_suffix[0]; 576 bi->sql_baseObject->e_nname = be->be_nsuffix[0]; 577 bi->sql_baseObject->e_attrs = NULL; 578 579 while (( ldifrc = ldif_read_record( fp, &lineno, &buf, &lmax )) > 0 ) { 580 Entry *e = str2entry( buf ); 581 Attribute *a; 582 583 if( e == NULL ) { 584 fprintf( stderr, "back-sql baseObject: " 585 "could not parse entry (line=%lu)\n", 586 lineno ); 587 rc = LDAP_OTHER; 588 break; 589 } 590 591 /* make sure the DN is the database's suffix */ 592 if ( !be_issuffix( be, &e->e_nname ) ) { 593 fprintf( stderr, 594 "back-sql: invalid baseObject - " 595 "dn=\"%s\" (line=%lu)\n", 596 e->e_name.bv_val, lineno ); 597 entry_free( e ); 598 rc = LDAP_OTHER; 599 break; 600 } 601 602 /* 603 * we found a valid entry, so walk thru all the attributes in the 604 * entry, and add each attribute type and description to baseObject 605 */ 606 for ( a = e->e_attrs; a != NULL; a = a->a_next ) { 607 if ( attr_merge( bi->sql_baseObject, a->a_desc, 608 a->a_vals, 609 ( a->a_nvals == a->a_vals ) ? 610 NULL : a->a_nvals ) ) 611 { 612 rc = LDAP_OTHER; 613 break; 614 } 615 } 616 617 entry_free( e ); 618 if ( rc ) { 619 break; 620 } 621 } 622 623 if ( ldifrc < 0 ) 624 rc = LDAP_OTHER; 625 626 if ( rc ) { 627 entry_free( bi->sql_baseObject ); 628 bi->sql_baseObject = NULL; 629 } 630 631 ch_free( buf ); 632 633 ldif_close( fp ); 634 635 Debug( LDAP_DEBUG_CONFIG, "back-sql baseObject file \"%s\" read.\n", 636 fname, 0, 0 ); 637 638 return rc; 639} 640 641static int 642create_baseObject( 643 BackendDB *be, 644 const char *fname, 645 int lineno ) 646{ 647 backsql_info *bi = (backsql_info *)be->be_private; 648 LDAPRDN rdn; 649 char *p; 650 int rc, iAVA; 651 char buf[1024]; 652 653 snprintf( buf, sizeof(buf), 654 "dn: %s\n" 655 "objectClass: extensibleObject\n" 656 "description: builtin baseObject for back-sql\n" 657 "description: all entries mapped " 658 "in table \"ldap_entries\" " 659 "must have " 660 "\"" BACKSQL_BASEOBJECT_IDSTR "\" " 661 "in the \"parent\" column", 662 be->be_suffix[0].bv_val ); 663 664 bi->sql_baseObject = str2entry( buf ); 665 if ( bi->sql_baseObject == NULL ) { 666 Debug( LDAP_DEBUG_TRACE, 667 "<==backsql_db_config (%s line %d): " 668 "unable to parse baseObject entry\n", 669 fname, lineno, 0 ); 670 return 1; 671 } 672 673 if ( BER_BVISEMPTY( &be->be_suffix[ 0 ] ) ) { 674 return 0; 675 } 676 677 rc = ldap_bv2rdn( &be->be_suffix[ 0 ], &rdn, (char **)&p, 678 LDAP_DN_FORMAT_LDAP ); 679 if ( rc != LDAP_SUCCESS ) { 680 snprintf( buf, sizeof(buf), 681 "unable to extract RDN " 682 "from baseObject DN \"%s\" (%d: %s)", 683 be->be_suffix[ 0 ].bv_val, 684 rc, ldap_err2string( rc ) ); 685 Debug( LDAP_DEBUG_TRACE, 686 "<==backsql_db_config (%s line %d): %s\n", 687 fname, lineno, buf ); 688 return 1; 689 } 690 691 for ( iAVA = 0; rdn[ iAVA ]; iAVA++ ) { 692 LDAPAVA *ava = rdn[ iAVA ]; 693 AttributeDescription *ad = NULL; 694 slap_syntax_transform_func *transf = NULL; 695 struct berval bv = BER_BVNULL; 696 const char *text = NULL; 697 698 assert( ava != NULL ); 699 700 rc = slap_bv2ad( &ava->la_attr, &ad, &text ); 701 if ( rc != LDAP_SUCCESS ) { 702 snprintf( buf, sizeof(buf), 703 "AttributeDescription of naming " 704 "attribute #%d from baseObject " 705 "DN \"%s\": %d: %s", 706 iAVA, be->be_suffix[ 0 ].bv_val, 707 rc, ldap_err2string( rc ) ); 708 Debug( LDAP_DEBUG_TRACE, 709 "<==backsql_db_config (%s line %d): %s\n", 710 fname, lineno, buf ); 711 return 1; 712 } 713 714 transf = ad->ad_type->sat_syntax->ssyn_pretty; 715 if ( transf ) { 716 /* 717 * transform value by pretty function 718 * if value is empty, use empty_bv 719 */ 720 rc = ( *transf )( ad->ad_type->sat_syntax, 721 ava->la_value.bv_len 722 ? &ava->la_value 723 : (struct berval *) &slap_empty_bv, 724 &bv, NULL ); 725 726 if ( rc != LDAP_SUCCESS ) { 727 snprintf( buf, sizeof(buf), 728 "prettying of attribute #%d " 729 "from baseObject " 730 "DN \"%s\" failed: %d: %s", 731 iAVA, be->be_suffix[ 0 ].bv_val, 732 rc, ldap_err2string( rc ) ); 733 Debug( LDAP_DEBUG_TRACE, 734 "<==backsql_db_config (%s line %d): " 735 "%s\n", 736 fname, lineno, buf ); 737 return 1; 738 } 739 } 740 741 if ( !BER_BVISNULL( &bv ) ) { 742 if ( ava->la_flags & LDAP_AVA_FREE_VALUE ) { 743 ber_memfree( ava->la_value.bv_val ); 744 } 745 ava->la_value = bv; 746 ava->la_flags |= LDAP_AVA_FREE_VALUE; 747 } 748 749 attr_merge_normalize_one( bi->sql_baseObject, 750 ad, &ava->la_value, NULL ); 751 } 752 753 ldap_rdnfree( rdn ); 754 755 return 0; 756} 757 758int backsql_init_cf( BackendInfo *bi ) 759{ 760 int rc; 761 762 bi->bi_cf_ocs = sqlocs; 763 rc = config_register_schema( sqlcfg, sqlocs ); 764 if ( rc ) return rc; 765 return 0; 766} 767