Back to index

openldap  2.4.31
config.c
Go to the documentation of this file.
00001 /* $OpenLDAP$ */
00002 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
00003  *
00004  * Copyright 1999-2012 The OpenLDAP Foundation.
00005  * Portions Copyright 1999 Dmitry Kovalev.
00006  * Portions Copyright 2002 Pierangelo Masarati.
00007  * Portions Copyright 2004 Mark Adamson.
00008  * All rights reserved.
00009  *
00010  * Redistribution and use in source and binary forms, with or without
00011  * modification, are permitted only as authorized by the OpenLDAP
00012  * Public License.
00013  *
00014  * A copy of this license is available in the file LICENSE in the
00015  * top-level directory of the distribution or, alternatively, at
00016  * <http://www.OpenLDAP.org/license.html>.
00017  */
00018 /* ACKNOWLEDGEMENTS:
00019  * This work was initially developed by Dmitry Kovalev for inclusion
00020  * by OpenLDAP Software.  Additional significant contributors include
00021  * Pierangelo Masarati.
00022  */
00023 
00024 #include "portable.h"
00025 
00026 #include <stdio.h>
00027 #include "ac/string.h"
00028 #include <sys/types.h>
00029 
00030 #include "slap.h"
00031 #include "config.h"
00032 #include "ldif.h"
00033 #include "lutil.h"
00034 #include "proto-sql.h"
00035 
00036 static int
00037 create_baseObject(
00038        BackendDB     *be,
00039        const char    *fname,
00040        int           lineno );
00041 
00042 static int
00043 read_baseObject(
00044        BackendDB     *be,
00045        const char    *fname );
00046 
00047 static ConfigDriver sql_cf_gen;
00048 
00049 enum {
00050        BSQL_CONCAT_PATT = 1,
00051        BSQL_CREATE_NEEDS_SEL,
00052        BSQL_UPPER_NEEDS_CAST,
00053        BSQL_HAS_LDAPINFO_DN_RU,
00054        BSQL_FAIL_IF_NO_MAPPING,
00055        BSQL_ALLOW_ORPHANS,
00056        BSQL_BASE_OBJECT,
00057        BSQL_LAYER,
00058        BSQL_SUBTREE_SHORTCUT,
00059        BSQL_FETCH_ALL_ATTRS,
00060        BSQL_FETCH_ATTRS,
00061        BSQL_CHECK_SCHEMA,
00062        BSQL_ALIASING_KEYWORD,
00063        BSQL_AUTOCOMMIT
00064 };
00065 
00066 static ConfigTable sqlcfg[] = {
00067        { "dbhost", "hostname", 2, 2, 0, ARG_STRING|ARG_OFFSET,
00068               (void *)offsetof(struct backsql_info, sql_dbhost),
00069               "( OLcfgDbAt:6.1 NAME 'olcDbHost' "
00070                      "DESC 'Hostname of SQL server' "
00071                      "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL },
00072        { "dbname", "name", 2, 2, 0, ARG_STRING|ARG_OFFSET,
00073               (void *)offsetof(struct backsql_info, sql_dbname),
00074               "( OLcfgDbAt:6.2 NAME 'olcDbName' "
00075                      "DESC 'Name of SQL database' "
00076                      "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL },
00077        { "dbuser", "username", 2, 2, 0, ARG_STRING|ARG_OFFSET,
00078               (void *)offsetof(struct backsql_info, sql_dbuser),
00079               "( OLcfgDbAt:6.3 NAME 'olcDbUser' "
00080                      "DESC 'Username for SQL session' "
00081                      "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL },
00082        { "dbpasswd", "password", 2, 2, 0, ARG_STRING|ARG_OFFSET,
00083               (void *)offsetof(struct backsql_info, sql_dbpasswd),
00084               "( OLcfgDbAt:6.4 NAME 'olcDbPass' "
00085                      "DESC 'Password for SQL session' "
00086                      "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL },
00087        { "concat_pattern", "pattern", 2, 2, 0,
00088               ARG_STRING|ARG_MAGIC|BSQL_CONCAT_PATT, (void *)sql_cf_gen,
00089               "( OLcfgDbAt:6.20 NAME 'olcSqlConcatPattern' "
00090                      "DESC 'Pattern used to concatenate strings' "
00091                      "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL },
00092        { "subtree_cond", "SQL expression", 2, 2, 0, ARG_BERVAL|ARG_OFFSET,
00093               (void *)offsetof(struct backsql_info, sql_subtree_cond),
00094               "( OLcfgDbAt:6.21 NAME 'olcSqlSubtreeCond' "
00095                      "DESC 'Where-clause template for a subtree search condition' "
00096                      "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL },
00097        { "children_cond", "SQL expression", 2, 2, 0, ARG_BERVAL|ARG_OFFSET,
00098               (void *)offsetof(struct backsql_info, sql_children_cond),
00099               "( OLcfgDbAt:6.22 NAME 'olcSqlChildrenCond' "
00100                      "DESC 'Where-clause template for a children search condition' "
00101                      "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL },
00102        { "dn_match_cond", "SQL expression", 2, 2, 0, ARG_BERVAL|ARG_OFFSET,
00103               (void *)offsetof(struct backsql_info, sql_dn_match_cond),
00104               "( OLcfgDbAt:6.23 NAME 'olcSqlDnMatchCond' "
00105                      "DESC 'Where-clause template for a DN match search condition' "
00106                      "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL },
00107        { "oc_query", "SQL expression", 2, 2, 0, ARG_STRING|ARG_OFFSET,
00108               (void *)offsetof(struct backsql_info, sql_oc_query),
00109               "( OLcfgDbAt:6.24 NAME 'olcSqlOcQuery' "
00110                      "DESC 'Query used to collect objectClass mapping data' "
00111                      "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL },
00112        { "at_query", "SQL expression", 2, 2, 0, ARG_STRING|ARG_OFFSET,
00113               (void *)offsetof(struct backsql_info, sql_at_query),
00114               "( OLcfgDbAt:6.25 NAME 'olcSqlAtQuery' "
00115                      "DESC 'Query used to collect attributeType mapping data' "
00116                      "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL },
00117        { "insentry_stmt", "SQL expression", 2, 2, 0, ARG_STRING|ARG_OFFSET,
00118               (void *)offsetof(struct backsql_info, sql_insentry_stmt),
00119               "( OLcfgDbAt:6.26 NAME 'olcSqlInsEntryStmt' "
00120                      "DESC 'Statement used to insert a new entry' "
00121                      "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL },
00122        { "create_needs_select", "yes|no", 2, 2, 0,
00123               ARG_ON_OFF|ARG_MAGIC|BSQL_CREATE_NEEDS_SEL, (void *)sql_cf_gen,
00124               "( OLcfgDbAt:6.27 NAME 'olcSqlCreateNeedsSelect' "
00125                      "DESC 'Whether entry creation needs a subsequent select' "
00126                      "SYNTAX OMsBoolean SINGLE-VALUE )", NULL, NULL },
00127        { "upper_func", "SQL function name", 2, 2, 0, ARG_BERVAL|ARG_OFFSET,
00128               (void *)offsetof(struct backsql_info, sql_upper_func),
00129               "( OLcfgDbAt:6.28 NAME 'olcSqlUpperFunc' "
00130                      "DESC 'Function that converts a value to uppercase' "
00131                      "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL },
00132        { "upper_needs_cast", "yes|no", 2, 2, 0,
00133               ARG_ON_OFF|ARG_MAGIC|BSQL_UPPER_NEEDS_CAST, (void *)sql_cf_gen,
00134               "( OLcfgDbAt:6.29 NAME 'olcSqlUpperNeedsCast' "
00135                      "DESC 'Whether olcSqlUpperFunc needs an explicit cast' "
00136                      "SYNTAX OMsBoolean SINGLE-VALUE )", NULL, NULL },
00137        { "strcast_func", "SQL function name", 2, 2, 0, ARG_BERVAL|ARG_OFFSET,
00138               (void *)offsetof(struct backsql_info, sql_strcast_func),
00139               "( OLcfgDbAt:6.30 NAME 'olcSqlStrcastFunc' "
00140                      "DESC 'Function that converts a value to a string' "
00141                      "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL },
00142        { "delentry_stmt", "SQL expression", 2, 2, 0, ARG_STRING|ARG_OFFSET,
00143               (void *)offsetof(struct backsql_info, sql_delentry_stmt),
00144               "( OLcfgDbAt:6.31 NAME 'olcSqlDelEntryStmt' "
00145                      "DESC 'Statement used to delete an existing entry' "
00146                      "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL },
00147        { "renentry_stmt", "SQL expression", 2, 2, 0, ARG_STRING|ARG_OFFSET,
00148               (void *)offsetof(struct backsql_info, sql_renentry_stmt),
00149               "( OLcfgDbAt:6.32 NAME 'olcSqlRenEntryStmt' "
00150                      "DESC 'Statement used to rename an entry' "
00151                      "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL },
00152        { "delobjclasses_stmt", "SQL expression", 2, 2, 0, ARG_STRING|ARG_OFFSET,
00153               (void *)offsetof(struct backsql_info, sql_delobjclasses_stmt),
00154               "( OLcfgDbAt:6.33 NAME 'olcSqlDelObjclassesStmt' "
00155                      "DESC 'Statement used to delete the ID of an entry' "
00156                      "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL },
00157        { "has_ldapinfo_dn_ru", "yes|no", 2, 2, 0,
00158               ARG_ON_OFF|ARG_MAGIC|BSQL_HAS_LDAPINFO_DN_RU, (void *)sql_cf_gen,
00159               "( OLcfgDbAt:6.34 NAME 'olcSqlHasLDAPinfoDnRu' "
00160                      "DESC 'Whether the dn_ru column is present' "
00161                      "SYNTAX OMsBoolean SINGLE-VALUE )", NULL, NULL },
00162        { "fail_if_no_mapping", "yes|no", 2, 2, 0,
00163               ARG_ON_OFF|ARG_MAGIC|BSQL_FAIL_IF_NO_MAPPING, (void *)sql_cf_gen,
00164               "( OLcfgDbAt:6.35 NAME 'olcSqlFailIfNoMapping' "
00165                      "DESC 'Whether to fail on unknown attribute mappings' "
00166                      "SYNTAX OMsBoolean SINGLE-VALUE )", NULL, NULL },
00167        { "allow_orphans", "yes|no", 2, 2, 0,
00168               ARG_ON_OFF|ARG_MAGIC|BSQL_ALLOW_ORPHANS, (void *)sql_cf_gen,
00169               "( OLcfgDbAt:6.36 NAME 'olcSqlAllowOrphans' "
00170                      "DESC 'Whether to allow adding entries with no parent' "
00171                      "SYNTAX OMsBoolean SINGLE-VALUE )", NULL, NULL },
00172        { "baseobject", "[file]", 1, 2, 0,
00173               ARG_STRING|ARG_MAGIC|BSQL_BASE_OBJECT, (void *)sql_cf_gen,
00174               "( OLcfgDbAt:6.37 NAME 'olcSqlBaseObject' "
00175                      "DESC 'Manage an in-memory baseObject entry' "
00176                      "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL },
00177        { "sqllayer", "name", 2, 0, 0,
00178               ARG_MAGIC|BSQL_LAYER, (void *)sql_cf_gen,
00179               "( OLcfgDbAt:6.38 NAME 'olcSqlLayer' "
00180                      "DESC 'Helper used to map DNs between LDAP and SQL' "
00181                      "SYNTAX OMsDirectoryString )", NULL, NULL },
00182        { "use_subtree_shortcut", "yes|no", 2, 2, 0,
00183               ARG_ON_OFF|ARG_MAGIC|BSQL_SUBTREE_SHORTCUT, (void *)sql_cf_gen,
00184               "( OLcfgDbAt:6.39 NAME 'olcSqlUseSubtreeShortcut' "
00185                      "DESC 'Collect all entries when searchBase is DB suffix' "
00186                      "SYNTAX OMsBoolean SINGLE-VALUE )", NULL, NULL },
00187        { "fetch_all_attrs", "yes|no", 2, 2, 0,
00188               ARG_ON_OFF|ARG_MAGIC|BSQL_FETCH_ALL_ATTRS, (void *)sql_cf_gen,
00189               "( OLcfgDbAt:6.40 NAME 'olcSqlFetchAllAttrs' "
00190                      "DESC 'Require all attributes to always be loaded' "
00191                      "SYNTAX OMsBoolean SINGLE-VALUE )", NULL, NULL },
00192        { "fetch_attrs", "attrlist", 2, 0, 0,
00193               ARG_MAGIC|BSQL_FETCH_ATTRS, (void *)sql_cf_gen,
00194               "( OLcfgDbAt:6.41 NAME 'olcSqlFetchAttrs' "
00195                      "DESC 'Set of attributes to always fetch' "
00196                      "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL },
00197        { "check_schema", "yes|no", 2, 2, 0,
00198               ARG_ON_OFF|ARG_MAGIC|BSQL_CHECK_SCHEMA, (void *)sql_cf_gen,
00199               "( OLcfgDbAt:6.42 NAME 'olcSqlCheckSchema' "
00200                      "DESC 'Check schema after modifications' "
00201                      "SYNTAX OMsBoolean SINGLE-VALUE )", NULL, NULL },
00202        { "aliasing_keyword", "string", 2, 2, 0,
00203               ARG_STRING|ARG_MAGIC|BSQL_ALIASING_KEYWORD, (void *)sql_cf_gen,
00204               "( OLcfgDbAt:6.43 NAME 'olcSqlAliasingKeyword' "
00205                      "DESC 'The aliasing keyword' "
00206                      "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL },
00207        { "aliasing_quote", "string", 2, 2, 0, ARG_BERVAL|ARG_OFFSET,
00208               (void *)offsetof(struct backsql_info, sql_aliasing_quote),
00209               "( OLcfgDbAt:6.44 NAME 'olcSqlAliasingQuote' "
00210                      "DESC 'Quoting char of the aliasing keyword' "
00211                      "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL },
00212        { "autocommit", "yes|no", 2, 2, 0,
00213               ARG_ON_OFF|ARG_MAGIC|SQL_AUTOCOMMIT, (void *)sql_cf_gen,
00214               "( OLcfgDbAt:6.45 NAME 'olcSqlAutocommit' "
00215                      "SYNTAX OMsBoolean SINGLE-VALUE )", NULL, NULL },
00216        { NULL, NULL, 0, 0, 0, ARG_IGNORED,
00217               NULL, NULL, NULL, NULL }
00218 };
00219 
00220 static ConfigOCs sqlocs[] = {
00221        {
00222               "( OLcfgDbOc:6.1 "
00223               "NAME 'olcSqlConfig' "
00224               "DESC 'SQL backend configuration' "
00225               "SUP olcDatabaseConfig "
00226               "MUST olcDbName "
00227               "MAY ( olcDbHost $ olcDbUser $ olcDbPass $ olcSqlConcatPattern $ "
00228               "olcSqlSubtreeCond $ olcsqlChildrenCond $ olcSqlDnMatchCond $ "
00229               "olcSqlOcQuery $ olcSqlAtQuery $ olcSqlInsEntryStmt $ "
00230               "olcSqlCreateNeedsSelect $ olcSqlUpperFunc $ olcSqlUpperNeedsCast $ "
00231               "olcSqlStrCastFunc $ olcSqlDelEntryStmt $ olcSqlRenEntryStmt $ "
00232               "olcSqlDelObjClassesStmt $ olcSqlHasLDAPInfoDnRu $ "
00233               "olcSqlFailIfNoMapping $ olcSqlAllowOrphans $ olcSqlBaseObject $ "
00234               "olcSqlLayer $ olcSqlUseSubtreeShortcut $ olcSqlFetchAllAttrs $ "
00235               "olcSqlFetchAttrs $ olcSqlCheckSchema $ olcSqlAliasingKeyword $ "
00236               "olcSqlAliasingQuote $ olcSqlAutocommit ) )",
00237                      Cft_Database, sqlcfg },
00238        { NULL, Cft_Abstract, NULL }
00239 };
00240 
00241 static int
00242 sql_cf_gen( ConfigArgs *c )
00243 {
00244        backsql_info  *bi = (backsql_info *)c->be->be_private;
00245        int rc = 0;
00246 
00247        if ( c->op == SLAP_CONFIG_EMIT ) {
00248               switch( c->type ) {
00249               case BSQL_CONCAT_PATT:
00250                      if ( bi->sql_concat_patt ) {
00251                             c->value_string = ch_strdup( bi->sql_concat_patt );
00252                      } else {
00253                             rc = 1;
00254                      }
00255                      break;
00256               case BSQL_CREATE_NEEDS_SEL:
00257                      if ( bi->sql_flags & BSQLF_CREATE_NEEDS_SELECT )
00258                             c->value_int = 1;
00259                      break;
00260               case BSQL_UPPER_NEEDS_CAST:
00261                      if ( bi->sql_flags & BSQLF_UPPER_NEEDS_CAST )
00262                             c->value_int = 1;
00263                      break;
00264               case BSQL_HAS_LDAPINFO_DN_RU:
00265                      if ( !(bi->sql_flags & BSQLF_DONTCHECK_LDAPINFO_DN_RU) )
00266                             return 1;
00267                      if ( bi->sql_flags & BSQLF_HAS_LDAPINFO_DN_RU )
00268                             c->value_int = 1;
00269                      break;
00270               case BSQL_FAIL_IF_NO_MAPPING:
00271                      if ( bi->sql_flags & BSQLF_FAIL_IF_NO_MAPPING )
00272                             c->value_int = 1;
00273                      break;
00274               case BSQL_ALLOW_ORPHANS:
00275                      if ( bi->sql_flags & BSQLF_ALLOW_ORPHANS )
00276                             c->value_int = 1;
00277                      break;
00278               case BSQL_SUBTREE_SHORTCUT:
00279                      if ( bi->sql_flags & BSQLF_USE_SUBTREE_SHORTCUT )
00280                             c->value_int = 1;
00281                      break;
00282               case BSQL_FETCH_ALL_ATTRS:
00283                      if ( bi->sql_flags & BSQLF_FETCH_ALL_ATTRS )
00284                             c->value_int = 1;
00285                      break;
00286               case BSQL_CHECK_SCHEMA:
00287                      if ( bi->sql_flags & BSQLF_CHECK_SCHEMA )
00288                             c->value_int = 1;
00289                      break;
00290               case BSQL_AUTOCOMMIT:
00291                      if ( bi->sql_flags & BSQLF_AUTOCOMMIT_ON )
00292                             c->value_int = 1;
00293                      break;
00294               case BSQL_BASE_OBJECT:
00295                      if ( bi->sql_base_ob_file ) {
00296                             c->value_string = ch_strdup( bi->sql_base_ob_file );
00297                      } else if ( bi->sql_baseObject ) {
00298                             c->value_string = ch_strdup( "TRUE" );
00299                      } else {
00300                             rc = 1;
00301                      }
00302                      break;
00303               case BSQL_LAYER:
00304                      if ( bi->sql_api ) {
00305                             backsql_api *ba;
00306                             struct berval bv;
00307                             char *ptr;
00308                             int i;
00309                             for ( ba = bi->sql_api; ba; ba = ba->ba_next ) {
00310                                    bv.bv_len = strlen( ba->ba_name );
00311                                    if ( ba->ba_argc ) {
00312                                           for ( i = 0; i<ba->ba_argc; i++ )
00313                                                  bv.bv_len += strlen( ba->ba_argv[i] ) + 3;
00314                                    }
00315                                    bv.bv_val = ch_malloc( bv.bv_len + 1 );
00316                                    ptr = lutil_strcopy( bv.bv_val, ba->ba_name );
00317                                    if ( ba->ba_argc ) {
00318                                           for ( i = 0; i<ba->ba_argc; i++ ) {
00319                                                  *ptr++ = ' ';
00320                                                  *ptr++ = '"';
00321                                                  ptr = lutil_strcopy( ptr, ba->ba_argv[i] );
00322                                                  *ptr++ = '"';
00323                                           }
00324                                    }
00325                                    ber_bvarray_add( &c->rvalue_vals, &bv );
00326                             }
00327                      } else {
00328                             rc = 1;
00329                      }
00330                      break;
00331               case BSQL_ALIASING_KEYWORD:
00332                      if ( !BER_BVISNULL( &bi->sql_aliasing )) {
00333                             struct berval bv;
00334                             bv = bi->sql_aliasing;
00335                             bv.bv_len--;
00336                             value_add_one( &c->rvalue_vals, &bv );
00337                      } else {
00338                             rc = 1;
00339                      }
00340                      break;
00341               case BSQL_FETCH_ATTRS:
00342                      if ( bi->sql_anlist ||
00343                             ( bi->sql_flags & (BSQLF_FETCH_ALL_USERATTRS|
00344                                                            BSQLF_FETCH_ALL_OPATTRS)))
00345                      {
00346                             char buf[BUFSIZ*2], *ptr;
00347                             struct berval bv;
00348 #   define WHATSLEFT    ((ber_len_t) (&buf[sizeof( buf )] - ptr))
00349                             ptr = buf;
00350                             if ( bi->sql_anlist ) {
00351                                    ptr = anlist_unparse( bi->sql_anlist, ptr, WHATSLEFT );
00352                                    if ( ptr == NULL )
00353                                           return 1;
00354                             }
00355                             if ( bi->sql_flags & BSQLF_FETCH_ALL_USERATTRS ) {
00356                                    if ( WHATSLEFT <= STRLENOF( ",*" )) return 1;
00357                                    if ( ptr != buf ) *ptr++ = ',';
00358                                    *ptr++ = '*';
00359                             }
00360                             if ( bi->sql_flags & BSQLF_FETCH_ALL_OPATTRS ) {
00361                                    if ( WHATSLEFT <= STRLENOF( ",+" )) return 1;
00362                                    if ( ptr != buf ) *ptr++ = ',';
00363                                    *ptr++ = '+';
00364                             }
00365                             bv.bv_val = buf;
00366                             bv.bv_len = ptr - buf;
00367                             value_add_one( &c->rvalue_vals, &bv );
00368                      }
00369                      break;
00370               }
00371               return rc;
00372        } else if ( c->op == LDAP_MOD_DELETE ) {  /* FIXME */
00373               return -1;
00374        }
00375 
00376        switch( c->type ) {
00377        case BSQL_CONCAT_PATT:
00378               if ( backsql_split_pattern( c->argv[ 1 ], &bi->sql_concat_func, 2 ) ) {
00379                      snprintf( c->cr_msg, sizeof( c->cr_msg ),
00380                             "%s: unable to parse pattern \"%s\"",
00381                             c->log, c->argv[ 1 ] );
00382                      Debug( LDAP_DEBUG_ANY, "%s\n", c->cr_msg, 0, 0 );
00383                      return -1;
00384               }
00385               bi->sql_concat_patt = c->value_string;
00386               break;
00387        case BSQL_CREATE_NEEDS_SEL:
00388               if ( c->value_int )
00389                      bi->sql_flags |= BSQLF_CREATE_NEEDS_SELECT;
00390               else
00391                      bi->sql_flags &= ~BSQLF_CREATE_NEEDS_SELECT;
00392               break;
00393        case BSQL_UPPER_NEEDS_CAST:
00394               if ( c->value_int )
00395                      bi->sql_flags |= BSQLF_UPPER_NEEDS_CAST;
00396               else
00397                      bi->sql_flags &= ~BSQLF_UPPER_NEEDS_CAST;
00398               break;
00399        case BSQL_HAS_LDAPINFO_DN_RU:
00400               bi->sql_flags |= BSQLF_DONTCHECK_LDAPINFO_DN_RU;
00401               if ( c->value_int )
00402                      bi->sql_flags |= BSQLF_HAS_LDAPINFO_DN_RU;
00403               else
00404                      bi->sql_flags &= ~BSQLF_HAS_LDAPINFO_DN_RU;
00405               break;
00406        case BSQL_FAIL_IF_NO_MAPPING:
00407               if ( c->value_int )
00408                      bi->sql_flags |= BSQLF_FAIL_IF_NO_MAPPING;
00409               else
00410                      bi->sql_flags &= ~BSQLF_FAIL_IF_NO_MAPPING;
00411               break;
00412        case BSQL_ALLOW_ORPHANS:
00413               if ( c->value_int )
00414                      bi->sql_flags |= BSQLF_ALLOW_ORPHANS;
00415               else
00416                      bi->sql_flags &= ~BSQLF_ALLOW_ORPHANS;
00417               break;
00418        case BSQL_SUBTREE_SHORTCUT:
00419               if ( c->value_int )
00420                      bi->sql_flags |= BSQLF_USE_SUBTREE_SHORTCUT;
00421               else
00422                      bi->sql_flags &= ~BSQLF_USE_SUBTREE_SHORTCUT;
00423               break;
00424        case BSQL_FETCH_ALL_ATTRS:
00425               if ( c->value_int )
00426                      bi->sql_flags |= BSQLF_FETCH_ALL_ATTRS;
00427               else
00428                      bi->sql_flags &= BSQLF_FETCH_ALL_ATTRS;
00429               break;
00430        case BSQL_CHECK_SCHEMA:
00431               if ( c->value_int )
00432                      bi->sql_flags |= BSQLF_CHECK_SCHEMA;
00433               else
00434                      bi->sql_flags &= BSQLF_CHECK_SCHEMA;
00435               break;
00436        case BSQL_AUTOCOMMIT:
00437               if ( c->value_int )
00438                      bi->sql_flags |= BSQLF_AUTOCOMMIT_ON;
00439               else
00440                      bi->sql_flags &= BSQLF_AUTOCOMMIT_ON;
00441               break;
00442        case BSQL_BASE_OBJECT:
00443               if ( c->be->be_nsuffix == NULL ) {
00444                      snprintf( c->cr_msg, sizeof( c->cr_msg ),
00445                             "%s: suffix must be set", c->log );
00446                      Debug( LDAP_DEBUG_ANY, "%s\n", c->cr_msg, 0, 0 );
00447                      rc = ARG_BAD_CONF;
00448                      break;
00449               }
00450               if ( bi->sql_baseObject ) {
00451                      Debug( LDAP_DEBUG_CONFIG,
00452                             "%s: "
00453                             "\"baseObject\" already provided (will be overwritten)\n",
00454                             c->log, 0, 0 );
00455                      entry_free( bi->sql_baseObject );
00456               }
00457               if ( c->argc == 2 && !strcmp( c->argv[1], "TRUE" ))
00458                      c->argc = 1;
00459               switch( c->argc ) {
00460               case 1:
00461                      return create_baseObject( c->be, c->fname, c->lineno );
00462 
00463               case 2:
00464                      rc = read_baseObject( c->be, c->argv[ 1 ] );
00465                      if ( rc == 0 ) {
00466                             ch_free( bi->sql_base_ob_file );
00467                             bi->sql_base_ob_file = c->value_string;
00468                      }
00469                      return rc;
00470 
00471               default:
00472                      snprintf( c->cr_msg, sizeof( c->cr_msg ),
00473                             "%s: trailing values in directive", c->log );
00474                      Debug( LDAP_DEBUG_ANY, "%s\n", c->cr_msg, 0, 0 );
00475                      return 1;
00476               }
00477               break;
00478        case BSQL_LAYER:
00479               if ( backsql_api_config( bi, c->argv[ 1 ], c->argc - 2, &c->argv[ 2 ] ) )
00480               {
00481                      snprintf( c->cr_msg, sizeof( c->cr_msg ),
00482                             "%s: unable to load sql layer", c->log );
00483                      Debug( LDAP_DEBUG_ANY, "%s \"%s\"\n",
00484                             c->cr_msg, c->argv[1], 0 );
00485                      return 1;
00486               }
00487               break;
00488        case BSQL_ALIASING_KEYWORD:
00489               if ( ! BER_BVISNULL( &bi->sql_aliasing ) ) {
00490                      ch_free( bi->sql_aliasing.bv_val );
00491               }
00492 
00493               ber_str2bv( c->argv[ 1 ], strlen( c->argv[ 1 ] ) + 1, 1,
00494                      &bi->sql_aliasing );
00495               /* add a trailing space... */
00496               bi->sql_aliasing.bv_val[ bi->sql_aliasing.bv_len - 1] = ' ';
00497               break;
00498        case BSQL_FETCH_ATTRS: {
00499               char          *str, *s, *next;
00500               const char    *delimstr = ",";
00501 
00502               str = ch_strdup( c->argv[ 1 ] );
00503               for ( s = ldap_pvt_strtok( str, delimstr, &next );
00504                             s != NULL;
00505                             s = ldap_pvt_strtok( NULL, delimstr, &next ) )
00506               {
00507                      if ( strlen( s ) == 1 ) {
00508                             if ( *s == '*' ) {
00509                                    bi->sql_flags |= BSQLF_FETCH_ALL_USERATTRS;
00510                                    c->argv[ 1 ][ s - str ] = ',';
00511 
00512                             } else if ( *s == '+' ) {
00513                                    bi->sql_flags |= BSQLF_FETCH_ALL_OPATTRS;
00514                                    c->argv[ 1 ][ s - str ] = ',';
00515                             }
00516                      }
00517               }
00518               ch_free( str );
00519               bi->sql_anlist = str2anlist( bi->sql_anlist, c->argv[ 1 ], delimstr );
00520               if ( bi->sql_anlist == NULL ) {
00521                      return -1;
00522               }
00523               }
00524               break;
00525        }
00526        return rc;
00527 }
00528 
00529 /*
00530  * Read the entries specified in fname and merge the attributes
00531  * to the user defined baseObject entry. Note that if we find any errors
00532  * what so ever, we will discard the entire entries, print an
00533  * error message and return.
00534  */
00535 static int
00536 read_baseObject( 
00537        BackendDB     *be,
00538        const char    *fname )
00539 {
00540        backsql_info  *bi = (backsql_info *)be->be_private;
00541        LDIFFP        *fp;
00542        int           rc = 0, lineno = 0, lmax = 0, ldifrc;
00543        char          *buf = NULL;
00544 
00545        assert( fname != NULL );
00546 
00547        fp = ldif_open( fname, "r" );
00548        if ( fp == NULL ) {
00549               Debug( LDAP_DEBUG_ANY,
00550                      "could not open back-sql baseObject "
00551                      "attr file \"%s\" - absolute path?\n",
00552                      fname, 0, 0 );
00553               perror( fname );
00554               return LDAP_OTHER;
00555        }
00556 
00557        bi->sql_baseObject = entry_alloc();
00558        if ( bi->sql_baseObject == NULL ) {
00559               Debug( LDAP_DEBUG_ANY,
00560                      "read_baseObject_file: entry_alloc failed", 0, 0, 0 );
00561               ldif_close( fp );
00562               return LDAP_NO_MEMORY;
00563        }
00564        bi->sql_baseObject->e_name = be->be_suffix[0];
00565        bi->sql_baseObject->e_nname = be->be_nsuffix[0];
00566        bi->sql_baseObject->e_attrs = NULL;
00567 
00568        while (( ldifrc = ldif_read_record( fp, &lineno, &buf, &lmax )) > 0 ) {
00569               Entry         *e = str2entry( buf );
00570               Attribute     *a;
00571 
00572               if( e == NULL ) {
00573                      fprintf( stderr, "back-sql baseObject: "
00574                                    "could not parse entry (line=%d)\n",
00575                                    lineno );
00576                      rc = LDAP_OTHER;
00577                      break;
00578               }
00579 
00580               /* make sure the DN is the database's suffix */
00581               if ( !be_issuffix( be, &e->e_nname ) ) {
00582                      fprintf( stderr,
00583                             "back-sql: invalid baseObject - "
00584                             "dn=\"%s\" (line=%d)\n",
00585                             e->e_name.bv_val, lineno );
00586                      entry_free( e );
00587                      rc = LDAP_OTHER;
00588                      break;
00589               }
00590 
00591               /*
00592                * we found a valid entry, so walk thru all the attributes in the
00593                * entry, and add each attribute type and description to baseObject
00594                */
00595               for ( a = e->e_attrs; a != NULL; a = a->a_next ) {
00596                      if ( attr_merge( bi->sql_baseObject, a->a_desc,
00597                                           a->a_vals,
00598                                           ( a->a_nvals == a->a_vals ) ?
00599                                           NULL : a->a_nvals ) )
00600                      {
00601                             rc = LDAP_OTHER;
00602                             break;
00603                      }
00604               }
00605 
00606               entry_free( e );
00607               if ( rc ) {
00608                      break;
00609               }
00610        }
00611 
00612        if ( ldifrc < 0 )
00613               rc = LDAP_OTHER;
00614 
00615        if ( rc ) {
00616               entry_free( bi->sql_baseObject );
00617               bi->sql_baseObject = NULL;
00618        }
00619 
00620        ch_free( buf );
00621 
00622        ldif_close( fp );
00623 
00624        Debug( LDAP_DEBUG_CONFIG, "back-sql baseObject file \"%s\" read.\n",
00625                      fname, 0, 0 );
00626 
00627        return rc;
00628 }
00629 
00630 static int
00631 create_baseObject(
00632        BackendDB     *be,
00633        const char    *fname,
00634        int           lineno )
00635 {
00636        backsql_info  *bi = (backsql_info *)be->be_private;
00637        LDAPRDN              rdn;
00638        char          *p;
00639        int           rc, iAVA;
00640        char          buf[1024];
00641 
00642        snprintf( buf, sizeof(buf),
00643                      "dn: %s\n"
00644                      "objectClass: extensibleObject\n"
00645                      "description: builtin baseObject for back-sql\n"
00646                      "description: all entries mapped "
00647                             "in table \"ldap_entries\" "
00648                             "must have "
00649                             "\"" BACKSQL_BASEOBJECT_IDSTR "\" "
00650                             "in the \"parent\" column",
00651                      be->be_suffix[0].bv_val );
00652 
00653        bi->sql_baseObject = str2entry( buf );
00654        if ( bi->sql_baseObject == NULL ) {
00655               Debug( LDAP_DEBUG_TRACE,
00656                      "<==backsql_db_config (%s line %d): "
00657                      "unable to parse baseObject entry\n",
00658                      fname, lineno, 0 );
00659               return 1;
00660        }
00661 
00662        if ( BER_BVISEMPTY( &be->be_suffix[ 0 ] ) ) {
00663               return 0;
00664        }
00665 
00666        rc = ldap_bv2rdn( &be->be_suffix[ 0 ], &rdn, (char **)&p,
00667                      LDAP_DN_FORMAT_LDAP );
00668        if ( rc != LDAP_SUCCESS ) {
00669               snprintf( buf, sizeof(buf),
00670                      "unable to extract RDN "
00671                      "from baseObject DN \"%s\" (%d: %s)",
00672                      be->be_suffix[ 0 ].bv_val,
00673                      rc, ldap_err2string( rc ) );
00674               Debug( LDAP_DEBUG_TRACE,
00675                      "<==backsql_db_config (%s line %d): %s\n",
00676                      fname, lineno, buf );
00677               return 1;
00678        }
00679 
00680        for ( iAVA = 0; rdn[ iAVA ]; iAVA++ ) {
00681               LDAPAVA                            *ava = rdn[ iAVA ];
00682               AttributeDescription        *ad = NULL;
00683               slap_syntax_transform_func  *transf = NULL;
00684               struct berval               bv = BER_BVNULL;
00685               const char                  *text = NULL;
00686 
00687               assert( ava != NULL );
00688 
00689               rc = slap_bv2ad( &ava->la_attr, &ad, &text );
00690               if ( rc != LDAP_SUCCESS ) {
00691                      snprintf( buf, sizeof(buf),
00692                             "AttributeDescription of naming "
00693                             "attribute #%d from baseObject "
00694                             "DN \"%s\": %d: %s",
00695                             iAVA, be->be_suffix[ 0 ].bv_val,
00696                             rc, ldap_err2string( rc ) );
00697                      Debug( LDAP_DEBUG_TRACE,
00698                             "<==backsql_db_config (%s line %d): %s\n",
00699                             fname, lineno, buf );
00700                      return 1;
00701               }
00702               
00703               transf = ad->ad_type->sat_syntax->ssyn_pretty;
00704               if ( transf ) {
00705                      /*
00706                       * transform value by pretty function
00707                       *     if value is empty, use empty_bv
00708                       */
00709                      rc = ( *transf )( ad->ad_type->sat_syntax,
00710                             ava->la_value.bv_len
00711                                    ? &ava->la_value
00712                                    : (struct berval *) &slap_empty_bv,
00713                             &bv, NULL );
00714        
00715                      if ( rc != LDAP_SUCCESS ) {
00716                             snprintf( buf, sizeof(buf),
00717                                    "prettying of attribute #%d "
00718                                    "from baseObject "
00719                                    "DN \"%s\" failed: %d: %s",
00720                                    iAVA, be->be_suffix[ 0 ].bv_val,
00721                                    rc, ldap_err2string( rc ) );
00722                             Debug( LDAP_DEBUG_TRACE,
00723                                    "<==backsql_db_config (%s line %d): "
00724                                    "%s\n",
00725                                    fname, lineno, buf );
00726                             return 1;
00727                      }
00728               }
00729 
00730               if ( !BER_BVISNULL( &bv ) ) {
00731                      if ( ava->la_flags & LDAP_AVA_FREE_VALUE ) {
00732                             ber_memfree( ava->la_value.bv_val );
00733                      }
00734                      ava->la_value = bv;
00735                      ava->la_flags |= LDAP_AVA_FREE_VALUE;
00736               }
00737 
00738               attr_merge_normalize_one( bi->sql_baseObject,
00739                             ad, &ava->la_value, NULL );
00740        }
00741 
00742        ldap_rdnfree( rdn );
00743 
00744        return 0;
00745 }
00746 
00747 int backsql_init_cf( BackendInfo *bi )
00748 {
00749        int rc;
00750 
00751        bi->bi_cf_ocs = sqlocs;
00752        rc = config_register_schema( sqlcfg, sqlocs );
00753        if ( rc ) return rc;
00754        return 0;
00755 }