Back to index

openldap  2.4.31
slapcommon.c
Go to the documentation of this file.
00001 /* slapcommon.c - common routine for the slap tools */
00002 /* $OpenLDAP$ */
00003 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
00004  *
00005  * Copyright 1998-2012 The OpenLDAP Foundation.
00006  * Portions Copyright 1998-2003 Kurt D. Zeilenga.
00007  * Portions Copyright 2003 IBM Corporation.
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 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 Kurt Zeilenga for inclusion
00020  * in OpenLDAP Software.  Additional signficant contributors include
00021  *    Jong Hyuk Choi
00022  *    Hallvard B. Furuseth
00023  *    Howard Chu
00024  *    Pierangelo Masarati
00025  */
00026 
00027 #include "portable.h"
00028 
00029 #include <stdio.h>
00030 
00031 #include <ac/stdlib.h>
00032 #include <ac/ctype.h>
00033 #include <ac/string.h>
00034 #include <ac/socket.h>
00035 #include <ac/unistd.h>
00036 
00037 #include "slapcommon.h"
00038 #include "lutil.h"
00039 #include "ldif.h"
00040 
00041 tool_vars tool_globals;
00042 
00043 #ifdef CSRIMALLOC
00044 static char *leakfilename;
00045 static FILE *leakfile;
00046 #endif
00047 
00048 static LDIFFP dummy;
00049 
00050 #if defined(LDAP_SYSLOG) && defined(LDAP_DEBUG)
00051 int start_syslog;
00052 static char **syslog_unknowns;
00053 #ifdef LOG_LOCAL4
00054 static int syslogUser = SLAP_DEFAULT_SYSLOG_USER;
00055 #endif /* LOG_LOCAL4 */
00056 #endif /* LDAP_DEBUG && LDAP_SYSLOG */
00057 
00058 static void
00059 usage( int tool, const char *progname )
00060 {
00061        char *options = NULL;
00062        fprintf( stderr,
00063               "usage: %s [-v] [-d debuglevel] [-f configfile] [-F configdir] [-o <name>[=<value>]]",
00064               progname );
00065 
00066        switch( tool ) {
00067        case SLAPACL:
00068               options = "\n\t[-U authcID | -D authcDN] [-X authzID | -o authzDN=<DN>]"
00069                      "\n\t-b DN [-u] [attr[/access][:value]] [...]\n";
00070               break;
00071 
00072        case SLAPADD:
00073               options = " [-c]\n\t[-g] [-n databasenumber | -b suffix]\n"
00074                      "\t[-l ldiffile] [-j linenumber] [-q] [-u] [-s] [-w]\n";
00075               break;
00076 
00077        case SLAPAUTH:
00078               options = "\n\t[-U authcID] [-X authzID] [-R realm] [-M mech] ID [...]\n";
00079               break;
00080 
00081        case SLAPCAT:
00082               options = " [-c]\n\t[-g] [-n databasenumber | -b suffix]"
00083                      " [-l ldiffile] [-a filter] [-s subtree] [-H url]\n";
00084               break;
00085 
00086        case SLAPDN:
00087               options = "\n\t[-N | -P] DN [...]\n";
00088               break;
00089 
00090        case SLAPINDEX:
00091               options = " [-c]\n\t[-g] [-n databasenumber | -b suffix] [attr ...] [-q] [-t]\n";
00092               break;
00093 
00094        case SLAPTEST:
00095               options = " [-n databasenumber] [-u]\n";
00096               break;
00097 
00098        case SLAPSCHEMA:
00099               options = " [-c]\n\t[-g] [-n databasenumber | -b suffix]"
00100                      " [-l errorfile] [-a filter] [-s subtree] [-H url]\n";
00101               break;
00102        }
00103 
00104        if ( options != NULL ) {
00105               fputs( options, stderr );
00106        }
00107        exit( EXIT_FAILURE );
00108 }
00109 
00110 static int
00111 parse_slapopt( int tool, int *mode )
00112 {
00113        size_t len = 0;
00114        char   *p;
00115 
00116        p = strchr( optarg, '=' );
00117        if ( p != NULL ) {
00118               len = p - optarg;
00119               p++;
00120        }
00121 
00122        if ( strncasecmp( optarg, "sockurl", len ) == 0 ) {
00123               if ( !BER_BVISNULL( &listener_url ) ) {
00124                      ber_memfree( listener_url.bv_val );
00125               }
00126               ber_str2bv( p, 0, 1, &listener_url );
00127 
00128        } else if ( strncasecmp( optarg, "domain", len ) == 0 ) {
00129               if ( !BER_BVISNULL( &peer_domain ) ) {
00130                      ber_memfree( peer_domain.bv_val );
00131               }
00132               ber_str2bv( p, 0, 1, &peer_domain );
00133 
00134        } else if ( strncasecmp( optarg, "peername", len ) == 0 ) {
00135               if ( !BER_BVISNULL( &peer_name ) ) {
00136                      ber_memfree( peer_name.bv_val );
00137               }
00138               ber_str2bv( p, 0, 1, &peer_name );
00139 
00140        } else if ( strncasecmp( optarg, "sockname", len ) == 0 ) {
00141               if ( !BER_BVISNULL( &sock_name ) ) {
00142                      ber_memfree( sock_name.bv_val );
00143               }
00144               ber_str2bv( p, 0, 1, &sock_name );
00145 
00146        } else if ( strncasecmp( optarg, "ssf", len ) == 0 ) {
00147               if ( lutil_atou( &ssf, p ) ) {
00148                      Debug( LDAP_DEBUG_ANY, "unable to parse ssf=\"%s\".\n", p, 0, 0 );
00149                      return -1;
00150               }
00151 
00152        } else if ( strncasecmp( optarg, "transport_ssf", len ) == 0 ) {
00153               if ( lutil_atou( &transport_ssf, p ) ) {
00154                      Debug( LDAP_DEBUG_ANY, "unable to parse transport_ssf=\"%s\".\n", p, 0, 0 );
00155                      return -1;
00156               }
00157 
00158        } else if ( strncasecmp( optarg, "tls_ssf", len ) == 0 ) {
00159               if ( lutil_atou( &tls_ssf, p ) ) {
00160                      Debug( LDAP_DEBUG_ANY, "unable to parse tls_ssf=\"%s\".\n", p, 0, 0 );
00161                      return -1;
00162               }
00163 
00164        } else if ( strncasecmp( optarg, "sasl_ssf", len ) == 0 ) {
00165               if ( lutil_atou( &sasl_ssf, p ) ) {
00166                      Debug( LDAP_DEBUG_ANY, "unable to parse sasl_ssf=\"%s\".\n", p, 0, 0 );
00167                      return -1;
00168               }
00169 
00170        } else if ( strncasecmp( optarg, "authzDN", len ) == 0 ) {
00171               ber_str2bv( p, 0, 1, &authzDN );
00172 
00173 #if defined(LDAP_SYSLOG) && defined(LDAP_DEBUG)
00174        } else if ( strncasecmp( optarg, "syslog", len ) == 0 ) {
00175               if ( parse_debug_level( p, &ldap_syslog, &syslog_unknowns ) ) {
00176                      return -1;
00177               }
00178               start_syslog = 1;
00179 
00180        } else if ( strncasecmp( optarg, "syslog-level", len ) == 0 ) {
00181               if ( parse_syslog_level( p, &ldap_syslog_level ) ) {
00182                      return -1;
00183               }
00184               start_syslog = 1;
00185 
00186 #ifdef LOG_LOCAL4
00187        } else if ( strncasecmp( optarg, "syslog-user", len ) == 0 ) {
00188               if ( parse_syslog_user( p, &syslogUser ) ) {
00189                      return -1;
00190               }
00191               start_syslog = 1;
00192 #endif /* LOG_LOCAL4 */
00193 #endif /* LDAP_DEBUG && LDAP_SYSLOG */
00194 
00195        } else if ( strncasecmp( optarg, "schema-check", len ) == 0 ) {
00196               switch ( tool ) {
00197               case SLAPADD:
00198                      if ( strcasecmp( p, "yes" ) == 0 ) {
00199                             *mode &= ~SLAP_TOOL_NO_SCHEMA_CHECK;
00200                      } else if ( strcasecmp( p, "no" ) == 0 ) {
00201                             *mode |= SLAP_TOOL_NO_SCHEMA_CHECK;
00202                      } else {
00203                             Debug( LDAP_DEBUG_ANY, "unable to parse schema-check=\"%s\".\n", p, 0, 0 );
00204                             return -1;
00205                      }
00206                      break;
00207 
00208               default:
00209                      Debug( LDAP_DEBUG_ANY, "schema-check meaningless for tool.\n", 0, 0, 0 );
00210                      break;
00211               }
00212 
00213        } else if ( strncasecmp( optarg, "value-check", len ) == 0 ) {
00214               switch ( tool ) {
00215               case SLAPADD:
00216                      if ( strcasecmp( p, "yes" ) == 0 ) {
00217                             *mode |= SLAP_TOOL_VALUE_CHECK;
00218                      } else if ( strcasecmp( p, "no" ) == 0 ) {
00219                             *mode &= ~SLAP_TOOL_VALUE_CHECK;
00220                      } else {
00221                             Debug( LDAP_DEBUG_ANY, "unable to parse value-check=\"%s\".\n", p, 0, 0 );
00222                             return -1;
00223                      }
00224                      break;
00225 
00226               default:
00227                      Debug( LDAP_DEBUG_ANY, "value-check meaningless for tool.\n", 0, 0, 0 );
00228                      break;
00229               }
00230 
00231        } else if ( strncasecmp( optarg, "ldif-wrap", len ) == 0 ) {
00232               switch ( tool ) {
00233               case SLAPCAT:
00234                      if ( strcasecmp( p, "no" ) == 0 ) {
00235                             ldif_wrap = LDIF_LINE_WIDTH_MAX;
00236 
00237                      } else {
00238                             unsigned int u;
00239                             if ( lutil_atou( &u, p ) ) {
00240                                    Debug( LDAP_DEBUG_ANY, "unable to parse ldif-wrap=\"%s\".\n", p, 0, 0 );
00241                                    return -1;
00242                             }
00243                             ldif_wrap = (ber_len_t)u;
00244                      }
00245                      break;
00246 
00247               default:
00248                      Debug( LDAP_DEBUG_ANY, "value-check meaningless for tool.\n", 0, 0, 0 );
00249                      break;
00250               }
00251 
00252        } else {
00253               return -1;
00254        }
00255 
00256        return 0;
00257 }
00258 
00259 /*
00260  * slap_tool_init - initialize slap utility, handle program options.
00261  * arguments:
00262  *     name          program name
00263  *     tool          tool code
00264  *     argc, argv    command line arguments
00265  */
00266 
00267 static int need_shutdown;
00268 
00269 void
00270 slap_tool_init(
00271        const char* progname,
00272        int tool,
00273        int argc, char **argv )
00274 {
00275        char *options;
00276        char *conffile = NULL;
00277        char *confdir = NULL;
00278        struct berval base = BER_BVNULL;
00279        char *filterstr = NULL;
00280        char *subtree = NULL;
00281        char *ldiffile       = NULL;
00282        char **debug_unknowns = NULL;
00283        int rc, i;
00284        int mode = SLAP_TOOL_MODE;
00285        int truncatemode = 0;
00286        int use_glue = 1;
00287        int writer;
00288 
00289 #ifdef LDAP_DEBUG
00290        /* tools default to "none", so that at least LDAP_DEBUG_ANY 
00291         * messages show up; use -d 0 to reset */
00292        slap_debug = LDAP_DEBUG_NONE;
00293        ldif_debug = slap_debug;
00294 #endif
00295        ldap_syslog = 0;
00296 
00297 #ifdef CSRIMALLOC
00298        leakfilename = malloc( strlen( progname ) + STRLENOF( ".leak" ) + 1 );
00299        sprintf( leakfilename, "%s.leak", progname );
00300        if( ( leakfile = fopen( leakfilename, "w" )) == NULL ) {
00301               leakfile = stderr;
00302        }
00303        free( leakfilename );
00304        leakfilename = NULL;
00305 #endif
00306 
00307        ldif_wrap = LDIF_LINE_WIDTH;
00308 
00309        scope = LDAP_SCOPE_DEFAULT;
00310 
00311        switch( tool ) {
00312        case SLAPADD:
00313               options = "b:cd:f:F:gj:l:n:o:qsS:uvw";
00314               break;
00315 
00316        case SLAPCAT:
00317               options = "a:b:cd:f:F:gH:l:n:o:s:v";
00318               mode |= SLAP_TOOL_READMAIN | SLAP_TOOL_READONLY;
00319               break;
00320 
00321        case SLAPDN:
00322               options = "d:f:F:No:Pv";
00323               mode |= SLAP_TOOL_READMAIN | SLAP_TOOL_READONLY;
00324               break;
00325 
00326        case SLAPSCHEMA:
00327               options = "a:b:cd:f:F:gH:l:n:o:s:v";
00328               mode |= SLAP_TOOL_READMAIN | SLAP_TOOL_READONLY;
00329               break;
00330 
00331        case SLAPTEST:
00332               options = "d:f:F:n:o:Quv";
00333               mode |= SLAP_TOOL_READMAIN | SLAP_TOOL_READONLY;
00334               break;
00335 
00336        case SLAPAUTH:
00337               options = "d:f:F:M:o:R:U:vX:";
00338               mode |= SLAP_TOOL_READMAIN | SLAP_TOOL_READONLY;
00339               break;
00340 
00341        case SLAPINDEX:
00342               options = "b:cd:f:F:gn:o:qtv";
00343               mode |= SLAP_TOOL_READMAIN;
00344               break;
00345 
00346        case SLAPACL:
00347               options = "b:D:d:f:F:o:uU:vX:";
00348               mode |= SLAP_TOOL_READMAIN | SLAP_TOOL_READONLY;
00349               break;
00350 
00351        default:
00352               fprintf( stderr, "%s: unknown tool mode (%d)\n", progname, tool );
00353               exit( EXIT_FAILURE );
00354        }
00355 
00356        dbnum = -1;
00357        while ( (i = getopt( argc, argv, options )) != EOF ) {
00358               switch ( i ) {
00359               case 'a':
00360                      filterstr = ch_strdup( optarg );
00361                      break;
00362 
00363               case 'b':
00364                      ber_str2bv( optarg, 0, 1, &base );
00365                      break;
00366 
00367               case 'c':     /* enable continue mode */
00368                      continuemode++;
00369                      break;
00370 
00371               case 'd': {   /* turn on debugging */
00372                      int    level = 0;
00373 
00374                      if ( parse_debug_level( optarg, &level, &debug_unknowns ) ) {
00375                             usage( tool, progname );
00376                      }
00377 #ifdef LDAP_DEBUG
00378                      if ( level == 0 ) {
00379                             /* allow to reset log level */
00380                             slap_debug = 0;
00381 
00382                      } else {
00383                             slap_debug |= level;
00384                      }
00385 #else
00386                      if ( level != 0 )
00387                             fputs( "must compile with LDAP_DEBUG for debugging\n",
00388                                    stderr );
00389 #endif
00390                      } break;
00391 
00392               case 'D':
00393                      ber_str2bv( optarg, 0, 1, &authcDN );
00394                      break;
00395 
00396               case 'f':     /* specify a conf file */
00397                      conffile = ch_strdup( optarg );
00398                      break;
00399 
00400               case 'F':     /* specify a conf dir */
00401                      confdir = ch_strdup( optarg );
00402                      break;
00403 
00404               case 'g':     /* disable subordinate glue */
00405                      use_glue = 0;
00406                      break;
00407 
00408               case 'H': {
00409                      LDAPURLDesc *ludp;
00410                      int rc;
00411 
00412                      rc = ldap_url_parse_ext( optarg, &ludp,
00413                             LDAP_PVT_URL_PARSE_NOEMPTY_HOST | LDAP_PVT_URL_PARSE_NOEMPTY_DN );
00414                      if ( rc != LDAP_URL_SUCCESS ) {
00415                             usage( tool, progname );
00416                      }
00417 
00418                      /* don't accept host, port, attrs, extensions */
00419                      if ( ldap_pvt_url_scheme2proto( ludp->lud_scheme ) != LDAP_PROTO_TCP ) {
00420                             usage( tool, progname );
00421                      }
00422 
00423                      if ( ludp->lud_host != NULL ) {
00424                             usage( tool, progname );
00425                      }
00426 
00427                      if ( ludp->lud_port != 0 ) {
00428                             usage( tool, progname );
00429                      }
00430 
00431                      if ( ludp->lud_attrs != NULL ) {
00432                             usage( tool, progname );
00433                      }
00434 
00435                      if ( ludp->lud_exts != NULL ) {
00436                             usage( tool, progname );
00437                      }
00438 
00439                      if ( ludp->lud_dn != NULL && ludp->lud_dn[0] != '\0' ) {
00440                             subtree = ludp->lud_dn;
00441                             ludp->lud_dn = NULL;
00442                      }
00443 
00444                      if ( ludp->lud_filter != NULL && ludp->lud_filter[0] != '\0' ) {
00445                             filterstr = ludp->lud_filter;
00446                             ludp->lud_filter = NULL;
00447                      }
00448 
00449                      scope = ludp->lud_scope;
00450 
00451                      ldap_free_urldesc( ludp );
00452                      } break;
00453 
00454               case 'j':     /* jump to linenumber */
00455                      if ( lutil_atoi( &jumpline, optarg ) ) {
00456                             usage( tool, progname );
00457                      }
00458                      break;
00459 
00460               case 'l':     /* LDIF file */
00461                      ldiffile = ch_strdup( optarg );
00462                      break;
00463 
00464               case 'M':
00465                      ber_str2bv( optarg, 0, 0, &mech );
00466                      break;
00467 
00468               case 'N':
00469                      if ( dn_mode && dn_mode != SLAP_TOOL_LDAPDN_NORMAL ) {
00470                             usage( tool, progname );
00471                      }
00472                      dn_mode = SLAP_TOOL_LDAPDN_NORMAL;
00473                      break;
00474 
00475               case 'n':     /* which config file db to index */
00476                      if ( lutil_atoi( &dbnum, optarg ) || dbnum < 0 ) {
00477                             usage( tool, progname );
00478                      }
00479                      break;
00480 
00481               case 'o':
00482                      if ( parse_slapopt( tool, &mode ) ) {
00483                             usage( tool, progname );
00484                      }
00485                      break;
00486 
00487               case 'P':
00488                      if ( dn_mode && dn_mode != SLAP_TOOL_LDAPDN_PRETTY ) {
00489                             usage( tool, progname );
00490                      }
00491                      dn_mode = SLAP_TOOL_LDAPDN_PRETTY;
00492                      break;
00493 
00494               case 'Q':
00495                      quiet++;
00496                      slap_debug = 0;
00497                      break;
00498 
00499               case 'q':     /* turn on quick */
00500                      mode |= SLAP_TOOL_QUICK;
00501                      break;
00502 
00503               case 'R':
00504                      realm = optarg;
00505                      break;
00506 
00507               case 'S':
00508                      if ( lutil_atou( &csnsid, optarg )
00509                             || csnsid > SLAP_SYNC_SID_MAX )
00510                      {
00511                             usage( tool, progname );
00512                      }
00513                      break;
00514 
00515               case 's':
00516                      switch ( tool ) {
00517                      case SLAPADD:
00518                             /* no schema check */
00519                             mode |= SLAP_TOOL_NO_SCHEMA_CHECK;
00520                             break;
00521 
00522                      case SLAPCAT:
00523                      case SLAPSCHEMA:
00524                             /* dump subtree */
00525                             subtree = ch_strdup( optarg );
00526                             break;
00527                      }
00528                      break;
00529 
00530               case 't':     /* turn on truncate */
00531                      truncatemode++;
00532                      mode |= SLAP_TRUNCATE_MODE;
00533                      break;
00534 
00535               case 'U':
00536                      ber_str2bv( optarg, 0, 0, &authcID );
00537                      break;
00538 
00539               case 'u':     /* dry run */
00540                      dryrun++;
00541                      break;
00542 
00543               case 'v':     /* turn on verbose */
00544                      verbose++;
00545                      break;
00546 
00547               case 'w':     /* write context csn at the end */
00548                      update_ctxcsn++;
00549                      break;
00550 
00551               case 'X':
00552                      ber_str2bv( optarg, 0, 0, &authzID );
00553                      break;
00554 
00555               default:
00556                      usage( tool, progname );
00557                      break;
00558               }
00559        }
00560 
00561 #if defined(LDAP_SYSLOG) && defined(LDAP_DEBUG)
00562        if ( start_syslog ) {
00563               char *logName;
00564 #ifdef HAVE_EBCDIC
00565               logName = ch_strdup( progname );
00566               __atoe( logName );
00567 #else
00568               logName = (char *)progname;
00569 #endif
00570 
00571 #ifdef LOG_LOCAL4
00572               openlog( logName, OPENLOG_OPTIONS, syslogUser );
00573 #elif defined LOG_DEBUG
00574               openlog( logName, OPENLOG_OPTIONS );
00575 #endif
00576 #ifdef HAVE_EBCDIC
00577               free( logName );
00578               logName = NULL;
00579 #endif
00580        }
00581 #endif /* LDAP_DEBUG && LDAP_SYSLOG */
00582 
00583        switch ( tool ) {
00584        case SLAPCAT:
00585        case SLAPSCHEMA:
00586               writer = 1;
00587               break;
00588 
00589        default:
00590               writer = 0;
00591               break;
00592        }
00593 
00594        switch ( tool ) {
00595        case SLAPADD:
00596        case SLAPCAT:
00597        case SLAPSCHEMA:
00598               if ( ( argc != optind ) || (dbnum >= 0 && base.bv_val != NULL ) ) {
00599                      usage( tool, progname );
00600               }
00601 
00602               break;
00603 
00604        case SLAPINDEX:
00605               if ( dbnum >= 0 && base.bv_val != NULL ) {
00606                      usage( tool, progname );
00607               }
00608 
00609               break;
00610 
00611        case SLAPDN:
00612               if ( argc == optind ) {
00613                      usage( tool, progname );
00614               }
00615               break;
00616 
00617        case SLAPAUTH:
00618               if ( argc == optind && BER_BVISNULL( &authcID ) ) {
00619                      usage( tool, progname );
00620               }
00621               break;
00622 
00623        case SLAPTEST:
00624               if ( argc != optind ) {
00625                      usage( tool, progname );
00626               }
00627               break;
00628 
00629        case SLAPACL:
00630               if ( !BER_BVISNULL( &authcDN ) && !BER_BVISNULL( &authcID ) ) {
00631                      usage( tool, progname );
00632               }
00633               if ( BER_BVISNULL( &base ) ) {
00634                      usage( tool, progname );
00635               }
00636               ber_dupbv( &baseDN, &base );
00637               break;
00638 
00639        default:
00640               break;
00641        }
00642 
00643        if ( ldiffile == NULL ) {
00644               dummy.fp = writer ? stdout : stdin;
00645               ldiffp = &dummy;
00646 
00647        } else if ((ldiffp = ldif_open( ldiffile, writer ? "w" : "r" ))
00648               == NULL )
00649        {
00650               perror( ldiffile );
00651               exit( EXIT_FAILURE );
00652        }
00653 
00654        /*
00655         * initialize stuff and figure out which backend we're dealing with
00656         */
00657 
00658        rc = slap_init( mode, progname );
00659        if ( rc != 0 ) {
00660               fprintf( stderr, "%s: slap_init failed!\n", progname );
00661               exit( EXIT_FAILURE );
00662        }
00663 
00664        rc = read_config( conffile, confdir );
00665 
00666        if ( rc != 0 ) {
00667               fprintf( stderr, "%s: bad configuration %s!\n",
00668                      progname, confdir ? "directory" : "file" );
00669               exit( EXIT_FAILURE );
00670        }
00671 
00672        if ( debug_unknowns ) {
00673               rc = parse_debug_unknowns( debug_unknowns, &slap_debug );
00674               ldap_charray_free( debug_unknowns );
00675               debug_unknowns = NULL;
00676               if ( rc )
00677                      exit( EXIT_FAILURE );
00678        }
00679 
00680 #if defined(LDAP_SYSLOG) && defined(LDAP_DEBUG)
00681        if ( syslog_unknowns ) {
00682               rc = parse_debug_unknowns( syslog_unknowns, &ldap_syslog );
00683               ldap_charray_free( syslog_unknowns );
00684               syslog_unknowns = NULL;
00685               if ( rc )
00686                      exit( EXIT_FAILURE );
00687        }
00688 #endif
00689 
00690        at_oc_cache = 1;
00691 
00692        switch ( tool ) {
00693        case SLAPADD:
00694        case SLAPCAT:
00695        case SLAPINDEX:
00696        case SLAPSCHEMA:
00697               if ( !nbackends ) {
00698                      fprintf( stderr, "No databases found "
00699                                    "in config file\n" );
00700                      exit( EXIT_FAILURE );
00701               }
00702               break;
00703 
00704        default:
00705               break;
00706        }
00707 
00708        if ( use_glue ) {
00709               rc = glue_sub_attach( 0 );
00710 
00711               if ( rc != 0 ) {
00712                      fprintf( stderr,
00713                             "%s: subordinate configuration error\n", progname );
00714                      exit( EXIT_FAILURE );
00715               }
00716        }
00717 
00718        rc = slap_schema_check();
00719 
00720        if ( rc != 0 ) {
00721               fprintf( stderr, "%s: slap_schema_prep failed!\n", progname );
00722               exit( EXIT_FAILURE );
00723        }
00724 
00725        switch ( tool ) {
00726        case SLAPTEST:
00727               if ( dbnum >= 0 )
00728                      goto get_db;
00729               /* FALLTHRU */
00730        case SLAPDN:
00731        case SLAPAUTH:
00732               be = NULL;
00733               goto startup;
00734 
00735        default:
00736               break;
00737        }
00738 
00739        if( filterstr ) {
00740               filter = str2filter( filterstr );
00741 
00742               if( filter == NULL ) {
00743                      fprintf( stderr, "Invalid filter '%s'\n", filterstr );
00744                      exit( EXIT_FAILURE );
00745               }
00746 
00747               ch_free( filterstr );
00748               filterstr = NULL;
00749        }
00750 
00751        if( subtree ) {
00752               struct berval val;
00753               ber_str2bv( subtree, 0, 0, &val );
00754               rc = dnNormalize( 0, NULL, NULL, &val, &sub_ndn, NULL );
00755               if( rc != LDAP_SUCCESS ) {
00756                      fprintf( stderr, "Invalid subtree DN '%s'\n", subtree );
00757                      exit( EXIT_FAILURE );
00758               }
00759 
00760               if ( BER_BVISNULL( &base ) && dbnum == -1 ) {
00761                      base = val;
00762               } else {
00763                      free( subtree );
00764                      subtree = NULL;
00765               }
00766        }
00767 
00768        if( base.bv_val != NULL ) {
00769               struct berval nbase;
00770 
00771               rc = dnNormalize( 0, NULL, NULL, &base, &nbase, NULL );
00772               if( rc != LDAP_SUCCESS ) {
00773                      fprintf( stderr, "%s: slap_init invalid suffix (\"%s\")\n",
00774                             progname, base.bv_val );
00775                      exit( EXIT_FAILURE );
00776               }
00777 
00778               be = select_backend( &nbase, 0 );
00779               ber_memfree( nbase.bv_val );
00780               BER_BVZERO( &nbase );
00781 
00782               switch ( tool ) {
00783               case SLAPACL:
00784                      goto startup;
00785 
00786               default:
00787                      break;
00788               }
00789 
00790               if( be == NULL ) {
00791                      fprintf( stderr, "%s: slap_init no backend for \"%s\"\n",
00792                             progname, base.bv_val );
00793                      exit( EXIT_FAILURE );
00794               }
00795               /* If the named base is a glue master, operate on the
00796                * entire context
00797                */
00798               if ( SLAP_GLUE_INSTANCE( be ) ) {
00799                      nosubordinates = 1;
00800               }
00801 
00802               ch_free( base.bv_val );
00803               BER_BVZERO( &base );
00804 
00805        } else if ( dbnum == -1 ) {
00806               /* no suffix and no dbnum specified, just default to
00807                * the first available database
00808                */
00809               if ( nbackends <= 0 ) {
00810                      fprintf( stderr, "No available databases\n" );
00811                      exit( EXIT_FAILURE );
00812               }
00813               LDAP_STAILQ_FOREACH( be, &backendDB, be_next ) {
00814                      dbnum++;
00815 
00816                      /* db #0 is cn=config, don't select it as a default */
00817                      if ( dbnum < 1 ) continue;
00818               
00819                      if ( SLAP_MONITOR(be))
00820                             continue;
00821 
00822               /* If just doing the first by default and it is a
00823                * glue subordinate, find the master.
00824                */
00825                      if ( SLAP_GLUE_SUBORDINATE(be) ) {
00826                             nosubordinates = 1;
00827                             continue;
00828                      }
00829                      break;
00830               }
00831 
00832               if ( !be ) {
00833                      fprintf( stderr, "Available database(s) "
00834                                    "do not allow %s\n", progname );
00835                      exit( EXIT_FAILURE );
00836               }
00837               
00838               if ( nosubordinates == 0 && dbnum > 1 ) {
00839                      Debug( LDAP_DEBUG_ANY,
00840                             "The first database does not allow %s;"
00841                             " using the first available one (%d)\n",
00842                             progname, dbnum, 0 );
00843               }
00844 
00845        } else if ( dbnum >= nbackends ) {
00846               fprintf( stderr,
00847                      "Database number selected via -n is out of range\n"
00848                      "Must be in the range 0 to %d"
00849                      " (the number of configured databases)\n",
00850                      nbackends - 1 );
00851               exit( EXIT_FAILURE );
00852 
00853        } else {
00854 get_db:
00855               LDAP_STAILQ_FOREACH( be, &backendDB, be_next ) {
00856                      if ( dbnum == 0 ) break;
00857                      dbnum--;
00858               }
00859        }
00860 
00861        if ( scope != LDAP_SCOPE_DEFAULT && BER_BVISNULL( &sub_ndn ) ) {
00862               if ( be && be->be_nsuffix ) {
00863                      ber_dupbv( &sub_ndn, be->be_nsuffix );
00864 
00865               } else {
00866                      fprintf( stderr,
00867                             "<scope> needs a DN or a valid database\n" );
00868                      exit( EXIT_FAILURE );
00869               }
00870        }
00871 
00872 startup:;
00873        if ( be ) {
00874               BackendDB *bdtmp;
00875 
00876               dbnum = 0;
00877               LDAP_STAILQ_FOREACH( bdtmp, &backendDB, be_next ) {
00878                      if ( bdtmp == be ) break;
00879                      dbnum++;
00880               }
00881        }
00882 
00883 #ifdef CSRIMALLOC
00884        mal_leaktrace(1);
00885 #endif
00886 
00887        if ( conffile != NULL ) {
00888               ch_free( conffile );
00889               conffile = NULL;
00890        }
00891 
00892        if ( confdir != NULL ) {
00893               ch_free( confdir );
00894               confdir = NULL;
00895        }
00896 
00897        if ( ldiffile != NULL ) {
00898               ch_free( ldiffile );
00899               ldiffile = NULL;
00900        }
00901 
00902        /* slapdn doesn't specify a backend to startup */
00903        if ( !dryrun && tool != SLAPDN ) {
00904               need_shutdown = 1;
00905 
00906               if ( slap_startup( be ) ) {
00907                      switch ( tool ) {
00908                      case SLAPTEST:
00909                             fprintf( stderr, "slap_startup failed "
00910                                           "(test would succeed using "
00911                                           "the -u switch)\n" );
00912                             break;
00913 
00914                      default:
00915                             fprintf( stderr, "slap_startup failed\n" );
00916                             break;
00917                      }
00918 
00919                      exit( EXIT_FAILURE );
00920               }
00921        }
00922 }
00923 
00924 int slap_tool_destroy( void )
00925 {
00926        int rc = 0;
00927        if ( !dryrun ) {
00928               if ( need_shutdown ) {
00929                      if ( slap_shutdown( be ))
00930                             rc = EXIT_FAILURE;
00931               }
00932               if ( slap_destroy())
00933                      rc = EXIT_FAILURE;
00934        }
00935 #ifdef SLAPD_MODULES
00936        if ( slapMode == SLAP_SERVER_MODE ) {
00937        /* always false. just pulls in necessary symbol references. */
00938               lutil_uuidstr(NULL, 0);
00939        }
00940        module_kill();
00941 #endif
00942        schema_destroy();
00943 #ifdef HAVE_TLS
00944        ldap_pvt_tls_destroy();
00945 #endif
00946        config_destroy();
00947 
00948 #ifdef CSRIMALLOC
00949        mal_dumpleaktrace( leakfile );
00950 #endif
00951 
00952        if ( !BER_BVISNULL( &authcDN ) ) {
00953               ch_free( authcDN.bv_val );
00954               BER_BVZERO( &authcDN );
00955        }
00956 
00957        if ( ldiffp && ldiffp != &dummy ) {
00958               ldif_close( ldiffp );
00959        }
00960        return rc;
00961 }
00962 
00963 int
00964 slap_tool_update_ctxcsn(
00965        const char *progname,
00966        unsigned long sid,
00967        struct berval *bvtext )
00968 {
00969        struct berval ctxdn;
00970        ID ctxcsn_id;
00971        Entry *ctxcsn_e;
00972        int rc = EXIT_SUCCESS;
00973 
00974        if ( !(update_ctxcsn && !dryrun && sid != SLAP_SYNC_SID_MAX + 1) ) {
00975               return rc;
00976        }
00977 
00978        if ( SLAP_SYNC_SUBENTRY( be )) {
00979               build_new_dn( &ctxdn, &be->be_nsuffix[0],
00980                      (struct berval *)&slap_ldapsync_cn_bv, NULL );
00981        } else {
00982               ctxdn = be->be_nsuffix[0];
00983        }
00984        ctxcsn_id = be->be_dn2id_get( be, &ctxdn );
00985        if ( ctxcsn_id == NOID ) {
00986               if ( SLAP_SYNC_SUBENTRY( be )) {
00987                      ctxcsn_e = slap_create_context_csn_entry( be, NULL );
00988                      for ( sid = 0; sid <= SLAP_SYNC_SID_MAX; sid++ ) {
00989                             if ( maxcsn[ sid ].bv_len ) {
00990                                    attr_merge_one( ctxcsn_e, slap_schema.si_ad_contextCSN,
00991                                           &maxcsn[ sid ], NULL );
00992                             }
00993                      }
00994                      ctxcsn_id = be->be_entry_put( be, ctxcsn_e, bvtext );
00995                      if ( ctxcsn_id == NOID ) {
00996                             fprintf( stderr, "%s: couldn't create context entry\n", progname );
00997                             rc = EXIT_FAILURE;
00998                      }
00999               } else {
01000                      fprintf( stderr, "%s: context entry is missing\n", progname );
01001                      rc = EXIT_FAILURE;
01002               }
01003        } else {
01004               ctxcsn_e = be->be_entry_get( be, ctxcsn_id );
01005               if ( ctxcsn_e != NULL ) {
01006                      Entry *e = entry_dup( ctxcsn_e );
01007                      int change;
01008                      Attribute *attr = attr_find( e->e_attrs, slap_schema.si_ad_contextCSN );
01009                      if ( attr ) {
01010                             int           i;
01011 
01012                             change = 0;
01013 
01014                             for ( i = 0; !BER_BVISNULL( &attr->a_nvals[ i ] ); i++ ) {
01015                                    int rc_sid;
01016                                    int match;
01017                                    const char *text = NULL;
01018 
01019                                    rc_sid = slap_parse_csn_sid( &attr->a_nvals[ i ] );
01020                                    if ( rc_sid < 0 ) {
01021                                           Debug( LDAP_DEBUG_ANY,
01022                                                  "%s: unable to extract SID "
01023                                                  "from #%d contextCSN=%s\n",
01024                                                  progname, i,
01025                                                  attr->a_nvals[ i ].bv_val );
01026                                           continue;
01027                                    }
01028 
01029                                    assert( rc_sid <= SLAP_SYNC_SID_MAX );
01030 
01031                                    sid = (unsigned)rc_sid;
01032 
01033                                    if ( maxcsn[ sid ].bv_len == 0 ) {
01034                                           match = -1;
01035 
01036                                    } else {
01037                                           value_match( &match, slap_schema.si_ad_entryCSN,
01038                                                  slap_schema.si_ad_entryCSN->ad_type->sat_ordering,
01039                                                  SLAP_MR_VALUE_OF_ATTRIBUTE_SYNTAX,
01040                                                  &maxcsn[ sid ], &attr->a_nvals[i], &text );
01041                                    }
01042 
01043                                    if ( match > 0 ) {
01044                                           change = 1;
01045                                    } else {
01046                                           AC_MEMCPY( maxcsn[ sid ].bv_val,
01047                                                  attr->a_nvals[ i ].bv_val,
01048                                                  attr->a_nvals[ i ].bv_len );
01049                                           maxcsn[ sid ].bv_val[ attr->a_nvals[ i ].bv_len ] = '\0';
01050                                           maxcsn[ sid ].bv_len = attr->a_nvals[ i ].bv_len;
01051                                    }
01052                             }
01053 
01054                             if ( change ) {
01055                                    if ( attr->a_nvals != attr->a_vals ) {
01056                                           ber_bvarray_free( attr->a_nvals );
01057                                    }
01058                                    attr->a_nvals = NULL;
01059                                    ber_bvarray_free( attr->a_vals );
01060                                    attr->a_vals = NULL;
01061                                    attr->a_numvals = 0;
01062                             }
01063                      } else {
01064                             change = 1;
01065                      }
01066 
01067                      if ( change ) {
01068                             for ( sid = 0; sid <= SLAP_SYNC_SID_MAX; sid++ ) {
01069                                    if ( maxcsn[ sid ].bv_len ) {
01070                                           attr_merge_one( e, slap_schema.si_ad_contextCSN,
01071                                                  &maxcsn[ sid], NULL );
01072                                    }
01073                             }
01074 
01075                             ctxcsn_id = be->be_entry_modify( be, e, bvtext );
01076                             if( ctxcsn_id == NOID ) {
01077                                    fprintf( stderr, "%s: could not modify ctxcsn (%s)\n",
01078                                           progname, bvtext->bv_val ? bvtext->bv_val : "" );
01079                                    rc = EXIT_FAILURE;
01080                             } else if ( verbose ) {
01081                                    fprintf( stderr, "modified: \"%s\" (%08lx)\n",
01082                                           e->e_dn, (long) ctxcsn_id );
01083                             }
01084                      }
01085                      entry_free( e );
01086               }
01087        } 
01088 
01089        return rc;
01090 }
01091 
01092 /*
01093  * return value:
01094  *     -1:                  update_ctxcsn == 0
01095  *     SLAP_SYNC_SID_MAX + 1:      unable to extract SID
01096  *     0 <= SLAP_SYNC_SID_MAX:     the SID
01097  */
01098 unsigned long
01099 slap_tool_update_ctxcsn_check(
01100        const char *progname,
01101        Entry *e )
01102 {
01103        if ( update_ctxcsn ) {
01104               unsigned long sid = SLAP_SYNC_SID_MAX + 1;
01105               int rc_sid;
01106               Attribute *attr;
01107 
01108               attr = attr_find( e->e_attrs, slap_schema.si_ad_entryCSN );
01109               assert( attr != NULL );
01110 
01111               rc_sid = slap_parse_csn_sid( &attr->a_nvals[ 0 ] );
01112               if ( rc_sid < 0 ) {
01113                      Debug( LDAP_DEBUG_ANY, "%s: could not "
01114                             "extract SID from entryCSN=%s, entry dn=\"%s\"\n",
01115                             progname, attr->a_nvals[ 0 ].bv_val, e->e_name.bv_val );
01116                      return (unsigned long)(-1);
01117 
01118               } else {
01119                      int match;
01120                      const char *text = NULL;
01121 
01122                      assert( rc_sid <= SLAP_SYNC_SID_MAX );
01123 
01124                      sid = (unsigned)rc_sid;
01125                      if ( maxcsn[ sid ].bv_len != 0 ) {
01126                             match = 0;
01127                             value_match( &match, slap_schema.si_ad_entryCSN,
01128                                    slap_schema.si_ad_entryCSN->ad_type->sat_ordering,
01129                                    SLAP_MR_VALUE_OF_ATTRIBUTE_SYNTAX,
01130                                    &maxcsn[ sid ], &attr->a_nvals[0], &text );
01131                      } else {
01132                             match = -1;
01133                      }
01134                      if ( match < 0 ) {
01135                             strcpy( maxcsn[ sid ].bv_val, attr->a_nvals[0].bv_val );
01136                             maxcsn[ sid ].bv_len = attr->a_nvals[0].bv_len;
01137                      }
01138               }
01139        }
01140 
01141        return (unsigned long)(-1);
01142 }
01143 
01144 int
01145 slap_tool_update_ctxcsn_init(void)
01146 {
01147        if ( update_ctxcsn ) {
01148               unsigned long sid;
01149               maxcsn[ 0 ].bv_val = maxcsnbuf;
01150               for ( sid = 1; sid <= SLAP_SYNC_SID_MAX; sid++ ) {
01151                      maxcsn[ sid ].bv_val = maxcsn[ sid - 1 ].bv_val + LDAP_PVT_CSNSTR_BUFSIZE;
01152                      maxcsn[ sid ].bv_len = 0;
01153               }
01154        }
01155 
01156        return 0;
01157 }
01158 
01159 int
01160 slap_tool_entry_check(
01161        const char *progname,
01162        Operation *op,
01163        Entry *e,
01164        int lineno,
01165        const char **text,
01166        char *textbuf,
01167        size_t textlen )
01168 {
01169        /* NOTE: we may want to conditionally enable manage */
01170        int manage = 0;
01171 
01172        Attribute *oc = attr_find( e->e_attrs,
01173               slap_schema.si_ad_objectClass );
01174 
01175        if( oc == NULL ) {
01176               fprintf( stderr, "%s: dn=\"%s\" (line=%d): %s\n",
01177                      progname, e->e_dn, lineno,
01178                      "no objectClass attribute");
01179               return LDAP_NO_SUCH_ATTRIBUTE;
01180        }
01181 
01182        /* check schema */
01183        op->o_bd = be;
01184 
01185        if ( (slapMode & SLAP_TOOL_NO_SCHEMA_CHECK) == 0) {
01186               int rc = entry_schema_check( op, e, NULL, manage, 1, NULL,
01187                      text, textbuf, textlen );
01188 
01189               if( rc != LDAP_SUCCESS ) {
01190                      fprintf( stderr, "%s: dn=\"%s\" (line=%d): (%d) %s\n",
01191                             progname, e->e_dn, lineno, rc, *text );
01192                      return rc;
01193               }
01194               textbuf[ 0 ] = '\0';
01195        }
01196 
01197        if ( (slapMode & SLAP_TOOL_VALUE_CHECK) != 0) {
01198               Modifications *ml = NULL;
01199 
01200               int rc = slap_entry2mods( e, &ml, text, textbuf, textlen );
01201               if ( rc != LDAP_SUCCESS ) {
01202                      fprintf( stderr, "%s: dn=\"%s\" (line=%d): (%d) %s\n",
01203                             progname, e->e_dn, lineno, rc, *text );
01204                      return rc;
01205               }
01206               textbuf[ 0 ] = '\0';
01207 
01208               rc = slap_mods_check( op, ml, text, textbuf, textlen, NULL );
01209               slap_mods_free( ml, 1 );
01210               if ( rc != LDAP_SUCCESS ) {
01211                      fprintf( stderr, "%s: dn=\"%s\" (line=%d): (%d) %s\n",
01212                             progname, e->e_dn, lineno, rc, *text );
01213                      return rc;
01214               }
01215               textbuf[ 0 ] = '\0';
01216        }
01217 
01218        return LDAP_SUCCESS;
01219 }
01220