1 /* slapcommon.c - common routine for the slap tools */
2 /* $OpenLDAP: pkg/ldap/servers/slapd/slapcommon.c,v 1.73.2.7 2008/02/11 23:26:44 kurt Exp $ */
3 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
5 * Copyright 1998-2008 The OpenLDAP Foundation.
6 * Portions Copyright 1998-2003 Kurt D. Zeilenga.
7 * Portions Copyright 2003 IBM Corporation.
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted only as authorized by the OpenLDAP
14 * A copy of this license is available in file LICENSE in the
15 * top-level directory of the distribution or, alternatively, at
16 * <http://www.OpenLDAP.org/license.html>.
19 * This work was initially developed by Kurt Zeilenga for inclusion
20 * in OpenLDAP Software. Additional signficant contributors include
22 * Hallvard B. Furuseth
31 #include <ac/stdlib.h>
33 #include <ac/string.h>
34 #include <ac/socket.h>
35 #include <ac/unistd.h>
37 #include "slapcommon.h"
41 tool_vars tool_globals
;
44 static char *leakfilename
;
45 static FILE *leakfile
;
50 #if defined(LDAP_SYSLOG) && defined(LDAP_DEBUG)
52 static char **syslog_unknowns
;
54 static int syslogUser
= SLAP_DEFAULT_SYSLOG_USER
;
55 #endif /* LOG_LOCAL4 */
56 #endif /* LDAP_DEBUG && LDAP_SYSLOG */
59 usage( int tool
, const char *progname
)
63 "usage: %s [-v] [-d debuglevel] [-f configfile] [-F configdir] [-o <name>[=<value>]]",
68 options
= "\n\t[-U authcID | -D authcDN] [-X authzID | -o authzDN=<DN>]"
69 "\n\t-b DN [-u] [attr[/access][:value]] [...]\n";
73 options
= " [-c]\n\t[-g] [-n databasenumber | -b suffix]\n"
74 "\t[-l ldiffile] [-j linenumber] [-q] [-u] [-s] [-w]\n";
78 options
= "\n\t[-U authcID] [-X authzID] [-R realm] [-M mech] ID [...]\n";
82 options
= " [-c]\n\t[-g] [-n databasenumber | -b suffix]"
83 " [-l ldiffile] [-a filter]\n";
87 options
= "\n\t[-N | -P] DN [...]\n";
91 options
= " [-c]\n\t[-g] [-n databasenumber | -b suffix] [attr ...] [-q] [-t]\n";
99 if ( options
!= NULL
) {
100 fputs( options
, stderr
);
102 exit( EXIT_FAILURE
);
106 parse_slapopt( void )
111 p
= strchr( optarg
, '=' );
117 if ( strncasecmp( optarg
, "sockurl", len
) == 0 ) {
118 if ( !BER_BVISNULL( &listener_url
) ) {
119 ber_memfree( listener_url
.bv_val
);
121 ber_str2bv( p
, 0, 1, &listener_url
);
123 } else if ( strncasecmp( optarg
, "domain", len
) == 0 ) {
124 if ( !BER_BVISNULL( &peer_domain
) ) {
125 ber_memfree( peer_domain
.bv_val
);
127 ber_str2bv( p
, 0, 1, &peer_domain
);
129 } else if ( strncasecmp( optarg
, "peername", len
) == 0 ) {
130 if ( !BER_BVISNULL( &peer_name
) ) {
131 ber_memfree( peer_name
.bv_val
);
133 ber_str2bv( p
, 0, 1, &peer_name
);
135 } else if ( strncasecmp( optarg
, "sockname", len
) == 0 ) {
136 if ( !BER_BVISNULL( &sock_name
) ) {
137 ber_memfree( sock_name
.bv_val
);
139 ber_str2bv( p
, 0, 1, &sock_name
);
141 } else if ( strncasecmp( optarg
, "ssf", len
) == 0 ) {
142 if ( lutil_atou( &ssf
, p
) ) {
143 Debug( LDAP_DEBUG_ANY
, "unable to parse ssf=\"%s\".\n", p
, 0, 0 );
147 } else if ( strncasecmp( optarg
, "transport_ssf", len
) == 0 ) {
148 if ( lutil_atou( &transport_ssf
, p
) ) {
149 Debug( LDAP_DEBUG_ANY
, "unable to parse transport_ssf=\"%s\".\n", p
, 0, 0 );
153 } else if ( strncasecmp( optarg
, "tls_ssf", len
) == 0 ) {
154 if ( lutil_atou( &tls_ssf
, p
) ) {
155 Debug( LDAP_DEBUG_ANY
, "unable to parse tls_ssf=\"%s\".\n", p
, 0, 0 );
159 } else if ( strncasecmp( optarg
, "sasl_ssf", len
) == 0 ) {
160 if ( lutil_atou( &sasl_ssf
, p
) ) {
161 Debug( LDAP_DEBUG_ANY
, "unable to parse sasl_ssf=\"%s\".\n", p
, 0, 0 );
165 } else if ( strncasecmp( optarg
, "authzDN", len
) == 0 ) {
166 ber_str2bv( p
, 0, 1, &authzDN
);
168 #if defined(LDAP_SYSLOG) && defined(LDAP_DEBUG)
169 } else if ( strncasecmp( optarg
, "syslog", len
) == 0 ) {
170 if ( parse_debug_level( p
, &ldap_syslog
, &syslog_unknowns
) ) {
175 } else if ( strncasecmp( optarg
, "syslog-level", len
) == 0 ) {
176 if ( parse_syslog_level( p
, &ldap_syslog_level
) ) {
182 } else if ( strncasecmp( optarg
, "syslog-user", len
) == 0 ) {
183 if ( parse_syslog_user( p
, &syslogUser
) ) {
187 #endif /* LOG_LOCAL4 */
188 #endif /* LDAP_DEBUG && LDAP_SYSLOG */
198 * slap_tool_init - initialize slap utility, handle program options.
202 * argc, argv command line arguments
205 static int need_shutdown
;
209 const char* progname
,
211 int argc
, char **argv
)
214 char *conffile
= NULL
;
215 char *confdir
= NULL
;
216 struct berval base
= BER_BVNULL
;
217 char *filterstr
= NULL
;
218 char *subtree
= NULL
;
219 char *ldiffile
= NULL
;
220 char **debug_unknowns
= NULL
;
222 int mode
= SLAP_TOOL_MODE
;
223 int truncatemode
= 0;
227 /* tools default to "none", so that at least LDAP_DEBUG_ANY
228 * messages show up; use -d 0 to reset */
229 slap_debug
= LDAP_DEBUG_NONE
;
234 leakfilename
= malloc( strlen( progname
) + STRLENOF( ".leak" ) + 1 );
235 sprintf( leakfilename
, "%s.leak", progname
);
236 if( ( leakfile
= fopen( leakfilename
, "w" )) == NULL
) {
239 free( leakfilename
);
244 options
= "b:cd:f:F:gj:l:n:o:qsS:uvw";
248 options
= "a:b:cd:f:F:gl:n:o:s:v";
249 mode
|= SLAP_TOOL_READMAIN
| SLAP_TOOL_READONLY
;
253 options
= "d:f:F:No:Pv";
254 mode
|= SLAP_TOOL_READMAIN
| SLAP_TOOL_READONLY
;
258 options
= "d:f:F:o:Quv";
259 mode
|= SLAP_TOOL_READMAIN
| SLAP_TOOL_READONLY
;
263 options
= "d:f:F:M:o:R:U:vX:";
264 mode
|= SLAP_TOOL_READMAIN
| SLAP_TOOL_READONLY
;
268 options
= "b:cd:f:F:gn:o:qtv";
269 mode
|= SLAP_TOOL_READMAIN
;
273 options
= "b:D:d:f:F:o:uU:vX:";
274 mode
|= SLAP_TOOL_READMAIN
| SLAP_TOOL_READONLY
;
278 fprintf( stderr
, "%s: unknown tool mode (%d)\n", progname
, tool
);
279 exit( EXIT_FAILURE
);
283 while ( (i
= getopt( argc
, argv
, options
)) != EOF
) {
286 filterstr
= ch_strdup( optarg
);
290 ber_str2bv( optarg
, 0, 1, &base
);
293 case 'c': /* enable continue mode */
297 case 'd': { /* turn on debugging */
300 if ( parse_debug_level( optarg
, &level
, &debug_unknowns
) ) {
301 usage( tool
, progname
);
305 /* allow to reset log level */
313 fputs( "must compile with LDAP_DEBUG for debugging\n",
319 ber_str2bv( optarg
, 0, 1, &authcDN
);
322 case 'f': /* specify a conf file */
323 conffile
= ch_strdup( optarg
);
326 case 'F': /* specify a conf dir */
327 confdir
= ch_strdup( optarg
);
330 case 'g': /* disable subordinate glue */
334 case 'j': /* jump to linenumber */
335 if ( lutil_atoi( &jumpline
, optarg
) ) {
336 usage( tool
, progname
);
340 case 'l': /* LDIF file */
341 ldiffile
= ch_strdup( optarg
);
345 ber_str2bv( optarg
, 0, 0, &mech
);
349 if ( dn_mode
&& dn_mode
!= SLAP_TOOL_LDAPDN_NORMAL
) {
350 usage( tool
, progname
);
352 dn_mode
= SLAP_TOOL_LDAPDN_NORMAL
;
355 case 'n': /* which config file db to index */
356 if ( lutil_atoi( &dbnum
, optarg
) ) {
357 usage( tool
, progname
);
362 if ( parse_slapopt() ) {
363 usage( tool
, progname
);
368 if ( dn_mode
&& dn_mode
!= SLAP_TOOL_LDAPDN_PRETTY
) {
369 usage( tool
, progname
);
371 dn_mode
= SLAP_TOOL_LDAPDN_PRETTY
;
379 case 'q': /* turn on quick */
380 mode
|= SLAP_TOOL_QUICK
;
388 if ( lutil_atou( &csnsid
, optarg
)
389 || csnsid
> SLAP_SYNC_SID_MAX
)
391 usage( tool
, progname
);
395 case 's': /* dump subtree */
396 if ( tool
== SLAPADD
)
397 mode
|= SLAP_TOOL_NO_SCHEMA_CHECK
;
398 else if ( tool
== SLAPCAT
)
399 subtree
= ch_strdup( optarg
);
402 case 't': /* turn on truncate */
404 mode
|= SLAP_TRUNCATE_MODE
;
408 ber_str2bv( optarg
, 0, 0, &authcID
);
411 case 'u': /* dry run */
415 case 'v': /* turn on verbose */
419 case 'w': /* write context csn at the end */
424 ber_str2bv( optarg
, 0, 0, &authzID
);
428 usage( tool
, progname
);
433 #if defined(LDAP_SYSLOG) && defined(LDAP_DEBUG)
434 if ( start_syslog
) {
437 logName
= ch_strdup( progname
);
440 logName
= (char *)progname
;
444 openlog( logName
, OPENLOG_OPTIONS
, syslogUser
);
445 #elif defined LOG_DEBUG
446 openlog( logName
, OPENLOG_OPTIONS
);
452 #endif /* LDAP_DEBUG && LDAP_SYSLOG */
457 if ( ( argc
!= optind
) || (dbnum
>= 0 && base
.bv_val
!= NULL
) ) {
458 usage( tool
, progname
);
464 if ( dbnum
>= 0 && base
.bv_val
!= NULL
) {
465 usage( tool
, progname
);
471 if ( argc
== optind
) {
472 usage( tool
, progname
);
477 if ( argc
== optind
&& BER_BVISNULL( &authcID
) ) {
478 usage( tool
, progname
);
483 if ( argc
!= optind
) {
484 usage( tool
, progname
);
489 if ( !BER_BVISNULL( &authcDN
) && !BER_BVISNULL( &authcID
) ) {
490 usage( tool
, progname
);
492 if ( BER_BVISNULL( &base
) ) {
493 usage( tool
, progname
);
495 ber_dupbv( &baseDN
, &base
);
502 if ( ldiffile
== NULL
) {
503 dummy
.fp
= tool
== SLAPCAT
? stdout
: stdin
;
506 } else if ((ldiffp
= ldif_open( ldiffile
, tool
== SLAPCAT
? "w" : "r" ))
510 exit( EXIT_FAILURE
);
514 * initialize stuff and figure out which backend we're dealing with
517 rc
= slap_init( mode
, progname
);
519 fprintf( stderr
, "%s: slap_init failed!\n", progname
);
520 exit( EXIT_FAILURE
);
523 rc
= read_config( conffile
, confdir
);
526 fprintf( stderr
, "%s: bad configuration %s!\n",
527 progname
, confdir
? "directory" : "file" );
528 exit( EXIT_FAILURE
);
531 if ( debug_unknowns
) {
532 rc
= parse_debug_unknowns( debug_unknowns
, &slap_debug
);
533 ldap_charray_free( debug_unknowns
);
534 debug_unknowns
= NULL
;
536 exit( EXIT_FAILURE
);
539 #if defined(LDAP_SYSLOG) && defined(LDAP_DEBUG)
540 if ( syslog_unknowns
) {
541 rc
= parse_debug_unknowns( syslog_unknowns
, &ldap_syslog
);
542 ldap_charray_free( syslog_unknowns
);
543 syslog_unknowns
= NULL
;
545 exit( EXIT_FAILURE
);
556 fprintf( stderr
, "No databases found "
557 "in config file\n" );
558 exit( EXIT_FAILURE
);
567 rc
= glue_sub_attach();
571 "%s: subordinate configuration error\n", progname
);
572 exit( EXIT_FAILURE
);
576 rc
= slap_schema_check();
579 fprintf( stderr
, "%s: slap_schema_prep failed!\n", progname
);
580 exit( EXIT_FAILURE
);
595 filter
= str2filter( filterstr
);
597 if( filter
== NULL
) {
598 fprintf( stderr
, "Invalid filter '%s'\n", filterstr
);
599 exit( EXIT_FAILURE
);
605 ber_str2bv( subtree
, 0, 0, &val
);
606 rc
= dnNormalize( 0, NULL
, NULL
, &val
, &sub_ndn
, NULL
);
607 if( rc
!= LDAP_SUCCESS
) {
608 fprintf( stderr
, "Invalid subtree DN '%s'\n", subtree
);
609 exit( EXIT_FAILURE
);
612 if ( BER_BVISNULL( &base
) && dbnum
== -1 ) {
619 if( base
.bv_val
!= NULL
) {
622 rc
= dnNormalize( 0, NULL
, NULL
, &base
, &nbase
, NULL
);
623 if( rc
!= LDAP_SUCCESS
) {
624 fprintf( stderr
, "%s: slap_init invalid suffix (\"%s\")\n",
625 progname
, base
.bv_val
);
626 exit( EXIT_FAILURE
);
629 be
= select_backend( &nbase
, 0 );
630 ber_memfree( nbase
.bv_val
);
641 fprintf( stderr
, "%s: slap_init no backend for \"%s\"\n",
642 progname
, base
.bv_val
);
643 exit( EXIT_FAILURE
);
645 /* If the named base is a glue master, operate on the
648 if ( SLAP_GLUE_INSTANCE( be
) ) {
652 } else if ( dbnum
== -1 ) {
653 /* no suffix and no dbnum specified, just default to
654 * the first available database
656 if ( nbackends
<= 0 ) {
657 fprintf( stderr
, "No available databases\n" );
658 exit( EXIT_FAILURE
);
660 LDAP_STAILQ_FOREACH( be
, &backendDB
, be_next
) {
663 /* db #0 is cn=config, don't select it as a default */
664 if ( dbnum
< 1 ) continue;
666 if ( SLAP_MONITOR(be
))
669 /* If just doing the first by default and it is a
670 * glue subordinate, find the master.
672 if ( SLAP_GLUE_SUBORDINATE(be
) ) {
680 fprintf( stderr
, "Available database(s) "
681 "do not allow %s\n", progname
);
682 exit( EXIT_FAILURE
);
685 if ( nosubordinates
== 0 && dbnum
> 1 ) {
686 Debug( LDAP_DEBUG_ANY
,
687 "The first database does not allow %s;"
688 " using the first available one (%d)\n",
689 progname
, dbnum
, 0 );
692 } else if ( dbnum
< 0 || dbnum
> (nbackends
-1) ) {
694 "Database number selected via -n is out of range\n"
695 "Must be in the range 0 to %d"
696 " (number of configured databases)\n",
698 exit( EXIT_FAILURE
);
701 LDAP_STAILQ_FOREACH( be
, &backendDB
, be_next
) {
702 if ( dbnum
== 0 ) break;
713 if ( conffile
!= NULL
) {
717 if ( ldiffile
!= NULL
) {
721 /* slapdn doesn't specify a backend to startup */
722 if ( !dryrun
&& tool
!= SLAPDN
) {
725 if ( slap_startup( be
) ) {
728 fprintf( stderr
, "slap_startup failed "
729 "(test would succeed using "
730 "the -u switch)\n" );
734 fprintf( stderr
, "slap_startup failed\n" );
738 exit( EXIT_FAILURE
);
743 void slap_tool_destroy( void )
746 if ( need_shutdown
) {
752 if ( slapMode
== SLAP_SERVER_MODE
) {
753 /* always false. just pulls in necessary symbol references. */
754 lutil_uuidstr(NULL
, 0);
760 ldap_pvt_tls_destroy();
765 mal_dumpleaktrace( leakfile
);
768 if ( !BER_BVISNULL( &authcDN
) ) {
769 ch_free( authcDN
.bv_val
);
772 if ( ldiffp
&& ldiffp
!= &dummy
) {
773 ldif_close( ldiffp
);