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