]> git.sur5r.net Git - openldap/blob - servers/slapd/slapcommon.c
fix controls propagation (ITS#3813)
[openldap] / servers / slapd / slapcommon.c
1 /* slapcommon.c - common routine for the slap tools */
2 /* $OpenLDAP$ */
3 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
4  *
5  * Copyright 1998-2005 The OpenLDAP Foundation.
6  * Portions Copyright 1998-2003 Kurt D. Zeilenga.
7  * Portions Copyright 2003 IBM Corporation.
8  * All rights reserved.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted only as authorized by the OpenLDAP
12  * Public License.
13  *
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>.
17  */
18 /* ACKNOWLEDGEMENTS:
19  * This work was initially developed by Kurt Zeilenga for inclusion
20  * in OpenLDAP Software.  Additional signficant contributors include
21  *    Jong Hyuk Choi
22  *    Hallvard B. Furuseth
23  *    Howard Chu
24  *    Pierangelo Masarati
25  */
26
27 #include "portable.h"
28
29 #include <stdio.h>
30
31 #include <ac/stdlib.h>
32 #include <ac/ctype.h>
33 #include <ac/string.h>
34 #include <ac/socket.h>
35 #include <ac/unistd.h>
36
37 #include "slapcommon.h"
38 #include "lutil.h"
39
40 tool_vars tool_globals;
41
42 #ifdef CSRIMALLOC
43 static char *leakfilename;
44 static FILE *leakfile;
45 #endif
46
47 static void
48 usage( int tool, const char *progname )
49 {
50         char *options = NULL;
51         fprintf( stderr,
52                 "usage: %s [-v] [-c] [-d debuglevel] [-f configfile]",
53                 progname );
54
55         switch( tool ) {
56         case SLAPADD:
57                 options = "\n\t[-n databasenumber | -b suffix]\n"
58                         "\t[-l ldiffile] [-u] [-p [-w] | -r [-i syncreplidlist] [-w]]\n";
59                 break;
60
61         case SLAPCAT:
62                 options = "\n\t[-n databasenumber | -b suffix] [-l ldiffile] [-m] [-k]\n";
63                 break;
64
65         case SLAPDN:
66                 options = " DN [...]\n";
67                 break;
68
69         case SLAPINDEX:
70                 options = "\n\t[-n databasenumber | -b suffix]\n";
71                 break;
72
73         case SLAPTEST:
74                 options = " [-u]\n";
75                 break;
76         }
77
78         if ( options != NULL ) {
79                 fputs( options, stderr );
80         }
81         exit( EXIT_FAILURE );
82 }
83
84
85 /*
86  * slap_tool_init - initialize slap utility, handle program options.
87  * arguments:
88  *      name            program name
89  *      tool            tool code
90  *      argc, argv      command line arguments
91  */
92
93 void
94 slap_tool_init(
95         const char* progname,
96         int tool,
97         int argc, char **argv )
98 {
99         char *options;
100         char *conffile = SLAPD_DEFAULT_CONFIGFILE;
101         struct berval base = BER_BVNULL;
102         char *subtree = NULL;
103         char *ldiffile  = NULL;
104         int rc, i, dbnum;
105         int mode = SLAP_TOOL_MODE;
106         int truncatemode = 0;
107
108 #ifdef CSRIMALLOC
109         leakfilename = malloc( strlen( progname ) + sizeof(".leak") );
110         sprintf( leakfilename, "%s.leak", progname );
111         if( ( leakfile = fopen( leakfilename, "w" )) == NULL ) {
112                 leakfile = stderr;
113         }
114         free( leakfilename );
115 #endif
116
117         switch( tool ) {
118         case SLAPADD:
119                 options = "b:cd:f:i:l:n:prtuvWw";
120                 break;
121
122         case SLAPCAT:
123                 options = "b:cd:f:kl:mn:s:v";
124                 mode |= SLAP_TOOL_READMAIN | SLAP_TOOL_READONLY;
125                 break;
126
127         case SLAPDN:
128                 options = "d:f:v";
129                 mode |= SLAP_TOOL_READMAIN | SLAP_TOOL_READONLY;
130                 break;
131
132         case SLAPTEST:
133                 options = "d:f:uv";
134                 mode |= SLAP_TOOL_READMAIN | SLAP_TOOL_READONLY;
135                 break;
136                 break;
137
138         case SLAPINDEX:
139                 options = "b:cd:f:n:v";
140                 mode |= SLAP_TOOL_READMAIN;
141                 break;
142
143         default:
144                 fprintf( stderr, "%s: unknown tool mode (%d)\n", progname, tool );
145                 exit( EXIT_FAILURE );
146         }
147
148         dbnum = -1;
149         while ( (i = getopt( argc, argv, options )) != EOF ) {
150                 switch ( i ) {
151                 case 'b':
152                         ber_str2bv( optarg, 0, 1, &base );
153                         break;
154
155                 case 'c':       /* enable continue mode */
156                         continuemode++;
157                         break;
158
159                 case 'd':       /* turn on debugging */
160                         ldap_debug += atoi( optarg );
161                         break;
162
163                 case 'f':       /* specify a conf file */
164                         conffile = strdup( optarg );
165                         break;
166
167                 case 'i': /* specify syncrepl id list */
168                         replica_id_string = strdup( optarg );
169                         if ( !isdigit( (unsigned char) *replica_id_string )) {
170                                 usage( tool, progname );
171                                 exit( EXIT_FAILURE );
172                         }
173                         str2clist( &replica_id_strlist, replica_id_string, "," );
174                         for ( i = 0; replica_id_strlist && replica_id_strlist[i]; i++ ) ;
175                         replica_id_list = ch_calloc( i + 1, sizeof( int ) );
176                         for ( i = 0; replica_id_strlist && replica_id_strlist[i]; i++ ) {
177                                 replica_id_list[i] = atoi( replica_id_strlist[i] );
178                                 if ( replica_id_list[i] >= 1000 ) {
179                                         fprintf(stderr,
180                                                 "%s: syncrepl id %d is out of range [0..999]\n",
181                                                 progname, replica_id_list[i] );
182                                         exit( EXIT_FAILURE );
183                                 }
184                         }
185                         replica_id_list[i] = -1;
186                         break;
187
188                 case 'k':       /* Retrieve sync cookie entry */
189                         retrieve_synccookie = 1;
190                         break;
191
192                 case 'l':       /* LDIF file */
193                         ldiffile = strdup( optarg );
194                         break;
195
196                 case 'm':       /* Retrieve ldapsync entry */
197                         retrieve_ctxcsn = 1;
198                         break;
199
200                 case 'n':       /* which config file db to index */
201                         dbnum = atoi( optarg ) - 1;
202                         break;
203
204                 case 'p':       /* replica promotion */
205                         replica_promotion = 1;          
206                         break;
207
208                 case 'r':       /* replica demotion */
209                         replica_demotion = 1;           
210                         break;
211
212                 case 's':       /* dump subtree */
213                         subtree = strdup( optarg );
214                         break;
215
216                 case 't':       /* turn on truncate */
217                         truncatemode++;
218                         mode |= SLAP_TRUNCATE_MODE;
219                         break;
220
221                 case 'u':       /* dry run */
222                         dryrun++;
223                         break;
224
225                 case 'v':       /* turn on verbose */
226                         verbose++;
227                         break;
228
229                 case 'W':       /* write context csn on every entry add */
230                         update_ctxcsn = SLAP_TOOL_CTXCSN_BATCH;
231                         /* FIXME : update_ctxcsn = SLAP_TOOL_CTXCSN_ENTRY; */
232                         break;
233
234                 case 'w':       /* write context csn on at the end */
235                         update_ctxcsn = SLAP_TOOL_CTXCSN_BATCH;
236                         break;
237
238                 default:
239                         usage( tool, progname );
240                         break;
241                 }
242         }
243
244         switch ( tool ) {
245         case SLAPADD:
246         case SLAPCAT:
247         case SLAPINDEX:
248                 if ( ( argc != optind ) || (dbnum >= 0 && base.bv_val != NULL ) ) {
249                         usage( tool, progname );
250                 }
251
252                 if ( replica_promotion && replica_demotion ) {
253                         usage( tool, progname );
254
255                 } else if ( !replica_promotion && !replica_demotion ) {
256                         if ( update_ctxcsn != SLAP_TOOL_CTXCSN_KEEP ) {
257                                 usage( tool, progname );
258                         }
259                 }
260                 break;
261
262         case SLAPDN:
263                 if ( argc == optind ) {
264                         usage( tool, progname );
265                 }
266                 break;
267
268         case SLAPTEST:
269                 if ( argc != optind ) {
270                         usage( tool, progname );
271                 }
272                 break;
273
274         default:
275                 break;
276         }
277
278         ldap_syslog = 0;
279
280         if ( ldiffile == NULL ) {
281                 ldiffp = tool == SLAPCAT ? stdout : stdin;
282
283         } else if ( ( ldiffp = fopen( ldiffile, tool == SLAPCAT ? "w" : "r" ) )
284                 == NULL )
285         {
286                 perror( ldiffile );
287                 exit( EXIT_FAILURE );
288         }
289
290         /*
291          * initialize stuff and figure out which backend we're dealing with
292          */
293
294 #ifdef SLAPD_MODULES
295         if ( module_init() != 0 ) {
296                 fprintf( stderr, "%s: module_init failed!\n", progname );
297                 exit( EXIT_FAILURE );
298         }
299 #endif
300                 
301         rc = slap_schema_init();
302
303         if ( rc != 0 ) {
304                 fprintf( stderr, "%s: slap_schema_init failed!\n", progname );
305                 exit( EXIT_FAILURE );
306         }
307
308         rc = slap_init( mode, progname );
309
310         if ( rc != 0 ) {
311                 fprintf( stderr, "%s: slap_init failed!\n", progname );
312                 exit( EXIT_FAILURE );
313         }
314
315         if ( overlay_init() ) {
316                 fprintf( stderr, "%s: overlay_init failed!\n", progname );
317                 exit( EXIT_FAILURE );
318         }
319
320         rc = read_config( conffile, 0 );
321
322         if ( rc != 0 ) {
323                 fprintf( stderr, "%s: bad configuration file!\n", progname );
324                 exit( EXIT_FAILURE );
325         }
326
327         switch ( tool ) {
328         case SLAPADD:
329         case SLAPCAT:
330         case SLAPINDEX:
331                 if ( !nbackends ) {
332                         fprintf( stderr, "No databases found "
333                                         "in config file\n" );
334                         exit( EXIT_FAILURE );
335                 }
336                 break;
337
338         default:
339                 break;
340         }
341
342         rc = glue_sub_init();
343
344         if ( rc != 0 ) {
345                 fprintf( stderr, "Subordinate configuration error\n" );
346                 exit( EXIT_FAILURE );
347         }
348
349         rc = slap_schema_check();
350
351         if ( rc != 0 ) {
352                 fprintf( stderr, "%s: slap_schema_prep failed!\n", progname );
353                 exit( EXIT_FAILURE );
354         }
355
356         switch ( tool ) {
357         case SLAPDN:
358         case SLAPTEST:
359                 be = NULL;
360                 goto startup;
361
362         default:
363                 break;
364         }
365
366         if( subtree ) {
367                 struct berval val;
368                 val.bv_val = subtree;
369                 val.bv_len = strlen( subtree );
370                 rc = dnNormalize( 0, NULL, NULL, &val, &sub_ndn, NULL );
371                 if( rc != LDAP_SUCCESS ) {
372                         fprintf( stderr, "Invalid subtree DN '%s'\n", optarg );
373                         exit( EXIT_FAILURE );
374                 }
375
376                 if( base.bv_val == NULL && dbnum == -1 )
377                         base = val;
378                 else
379                         free( subtree );
380         }
381
382         if( base.bv_val != NULL ) {
383                 struct berval nbase;
384
385                 rc = dnNormalize( 0, NULL, NULL, &base, &nbase, NULL );
386                 if( rc != LDAP_SUCCESS ) {
387                         fprintf( stderr, "%s: slap_init invalid suffix (\"%s\")\n",
388                                 progname, base.bv_val );
389                         exit( EXIT_FAILURE );
390                 }
391
392                 be = select_backend( &nbase, 0, 0 );
393                 ber_memfree( nbase.bv_val );
394
395                 if( be == NULL ) {
396                         fprintf( stderr, "%s: slap_init no backend for \"%s\"\n",
397                                 progname, base.bv_val );
398                         exit( EXIT_FAILURE );
399                 }
400                 /* If the named base is a glue master, operate on the
401                  * entire context
402                  */
403                 if (SLAP_GLUE_INSTANCE(be)) {
404                         nosubordinates = 1;
405                 }
406
407         } else if ( dbnum == -1 ) {
408                 if ( nbackends <= 0 ) {
409                         fprintf( stderr, "No available databases\n" );
410                         exit( EXIT_FAILURE );
411                 }
412                 
413                 be = &backends[dbnum=0];
414                 /* If just doing the first by default and it is a
415                  * glue subordinate, find the master.
416                  */
417                 while (SLAP_GLUE_SUBORDINATE(be) || SLAP_MONITOR(be)) {
418                         if (SLAP_GLUE_SUBORDINATE(be)) {
419                                 nosubordinates = 1;
420                         }
421                         be++;
422                         dbnum++;
423                 }
424
425
426                 if ( dbnum >= nbackends ) {
427                         fprintf( stderr, "Available database(s) "
428                                         "do not allow %s\n", progname );
429                         exit( EXIT_FAILURE );
430                 }
431                 
432                 if ( nosubordinates == 0 && dbnum > 0 ) {
433 #ifdef NEW_LOGGING
434                         LDAP_LOG( BACKEND, ERR, 
435 "The first database does not allow %s; using the first available one (%d)\n",
436                                 progname, dbnum + 1, 0 );
437 #else
438                         Debug( LDAP_DEBUG_ANY,
439 "The first database does not allow %s; using the first available one (%d)\n",
440                                 progname, dbnum + 1, 0 );
441 #endif
442                 }
443
444         } else if ( dbnum < 0 || dbnum > (nbackends-1) ) {
445                 fprintf( stderr,
446                         "Database number selected via -n is out of range\n"
447                         "Must be in the range 1 to %d"
448                                 " (number of databases in the config file)\n",
449                         nbackends );
450                 exit( EXIT_FAILURE );
451
452         } else {
453                 be = &backends[dbnum];
454         }
455
456 startup:;
457
458 #ifdef CSRIMALLOC
459         mal_leaktrace(1);
460 #endif
461
462         if ( !dryrun && slap_startup( be ) ) {
463
464                 switch ( tool ) {
465                 case SLAPTEST:
466                         fprintf( stderr, "slap_startup failed "
467                                         "(test would succeed using "
468                                         "the -u switch)\n" );
469                         break;
470
471                 default:
472                         fprintf( stderr, "slap_startup failed\n" );
473                         break;
474                 }
475                 
476                 exit( EXIT_FAILURE );
477         }
478 }
479
480 void slap_tool_destroy( void )
481 {
482         if ( !dryrun && be != NULL ) {
483                 slap_shutdown( be );
484         }
485         slap_destroy();
486 #ifdef SLAPD_MODULES
487         if ( slapMode == SLAP_SERVER_MODE ) {
488         /* always false. just pulls in necessary symbol references. */
489                 lutil_uuidstr(NULL, 0);
490         }
491         module_kill();
492 #endif
493         schema_destroy();
494 #ifdef HAVE_TLS
495         ldap_pvt_tls_destroy();
496 #endif
497         config_destroy();
498
499 #ifdef CSRIMALLOC
500         mal_dumpleaktrace( leakfile );
501 #endif
502 }