]> git.sur5r.net Git - openldap/blob - servers/slapd/slapcommon.c
Merge from HEAD
[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] [-d debuglevel] [-f configfile] [-F configdir]",
53                 progname );
54
55         switch( tool ) {
56         case SLAPACL:
57                 options = "\n\t[-U authcID | -D authcDN] [-X authzID | -o authzDN=<DN>]"
58                         "\n\t-b DN -o <var>[=<val>] [-u] [attr[/access][:value]] [...]\n";
59                 break;
60
61         case SLAPADD:
62                 options = " [-c]\n\t[-n databasenumber | -b suffix]\n"
63                         "\t[-l ldiffile] [-q] [-u] [-w]\n";
64                 break;
65
66         case SLAPAUTH:
67                 options = "\n\t[-U authcID] [-X authzID] [-R realm] [-M mech] ID [...]\n";
68                 break;
69
70         case SLAPCAT:
71                 options = " [-c]\n\t[-n databasenumber | -b suffix]"
72                         " [-l ldiffile] [-a filter]\n";
73                 break;
74
75         case SLAPDN:
76                 options = "\n\t[-N | -P] DN [...]\n";
77                 break;
78
79         case SLAPINDEX:
80                 options = " [-c]\n\t[-n databasenumber | -b suffix] [-q]\n";
81                 break;
82
83         case SLAPTEST:
84                 options = " [-u]\n";
85                 break;
86         }
87
88         if ( options != NULL ) {
89                 fputs( options, stderr );
90         }
91         exit( EXIT_FAILURE );
92 }
93
94 static int
95 parse_slapacl( void )
96 {
97         size_t  len;
98         char    *p;
99
100         p = strchr( optarg, '=' );
101         if ( p == NULL ) {
102                 return -1;
103         }
104
105         len = p - optarg;
106         p++;
107
108         if ( strncasecmp( optarg, "sockurl", len ) == 0 ) {
109                 if ( !BER_BVISNULL( &listener_url ) ) {
110                         ber_memfree( listener_url.bv_val );
111                 }
112                 ber_str2bv( p, 0, 1, &listener_url );
113
114         } else if ( strncasecmp( optarg, "domain", len ) == 0 ) {
115                 if ( !BER_BVISNULL( &peer_domain ) ) {
116                         ber_memfree( peer_domain.bv_val );
117                 }
118                 ber_str2bv( p, 0, 1, &peer_domain );
119
120         } else if ( strncasecmp( optarg, "peername", len ) == 0 ) {
121                 if ( !BER_BVISNULL( &peer_name ) ) {
122                         ber_memfree( peer_name.bv_val );
123                 }
124                 ber_str2bv( p, 0, 1, &peer_name );
125
126         } else if ( strncasecmp( optarg, "sockname", len ) == 0 ) {
127                 if ( !BER_BVISNULL( &sock_name ) ) {
128                         ber_memfree( sock_name.bv_val );
129                 }
130                 ber_str2bv( p, 0, 1, &sock_name );
131
132         } else if ( strncasecmp( optarg, "ssf", len ) == 0 ) {
133                 ssf = atoi( p );
134
135         } else if ( strncasecmp( optarg, "transport_ssf", len ) == 0 ) {
136                 transport_ssf = atoi( p );
137
138         } else if ( strncasecmp( optarg, "tls_ssf", len ) == 0 ) {
139                 tls_ssf = atoi( p );
140
141         } else if ( strncasecmp( optarg, "sasl_ssf", len ) == 0 ) {
142                 sasl_ssf = atoi( p );
143
144         } else if ( strncasecmp( optarg, "authzDN", len ) == 0 ) {
145                 ber_str2bv( p, 0, 1, &authzDN );
146
147         } else {
148                 return -1;
149         }
150
151         return 0;
152 }
153
154 /*
155  * slap_tool_init - initialize slap utility, handle program options.
156  * arguments:
157  *      name            program name
158  *      tool            tool code
159  *      argc, argv      command line arguments
160  */
161
162 void
163 slap_tool_init(
164         const char* progname,
165         int tool,
166         int argc, char **argv )
167 {
168         char *options;
169         char *conffile = NULL;
170         char *confdir = NULL;
171         struct berval base = BER_BVNULL;
172         char *filterstr = NULL;
173         char *subtree = NULL;
174         char *ldiffile  = NULL;
175         int rc, i, dbnum;
176         int mode = SLAP_TOOL_MODE;
177         int truncatemode = 0;
178
179 #ifdef CSRIMALLOC
180         leakfilename = malloc( strlen( progname ) + STRLENOF( ".leak" ) + 1 );
181         sprintf( leakfilename, "%s.leak", progname );
182         if( ( leakfile = fopen( leakfilename, "w" )) == NULL ) {
183                 leakfile = stderr;
184         }
185         free( leakfilename );
186 #endif
187
188         switch( tool ) {
189         case SLAPADD:
190                 options = "b:cd:f:F:l:n:qtuvw";
191                 break;
192
193         case SLAPCAT:
194                 options = "a:b:cd:f:F:l:n:s:v";
195                 mode |= SLAP_TOOL_READMAIN | SLAP_TOOL_READONLY;
196                 break;
197
198         case SLAPDN:
199                 options = "d:f:F:NPv";
200                 mode |= SLAP_TOOL_READMAIN | SLAP_TOOL_READONLY;
201                 break;
202
203         case SLAPTEST:
204                 options = "d:f:F:uv";
205                 mode |= SLAP_TOOL_READMAIN | SLAP_TOOL_READONLY;
206                 break;
207
208         case SLAPAUTH:
209                 options = "d:f:F:M:R:U:vX:";
210                 mode |= SLAP_TOOL_READMAIN | SLAP_TOOL_READONLY;
211                 break;
212
213         case SLAPINDEX:
214                 options = "b:cd:f:F:n:qv";
215                 mode |= SLAP_TOOL_READMAIN;
216                 break;
217
218         case SLAPACL:
219                 options = "b:D:d:f:F:o:uU:vX:";
220                 mode |= SLAP_TOOL_READMAIN | SLAP_TOOL_READONLY;
221                 break;
222
223         default:
224                 fprintf( stderr, "%s: unknown tool mode (%d)\n", progname, tool );
225                 exit( EXIT_FAILURE );
226         }
227
228         dbnum = -1;
229         while ( (i = getopt( argc, argv, options )) != EOF ) {
230                 switch ( i ) {
231                 case 'a':
232                         filterstr = strdup( optarg );
233                         break;
234
235                 case 'b':
236                         ber_str2bv( optarg, 0, 1, &base );
237                         break;
238
239                 case 'c':       /* enable continue mode */
240                         continuemode++;
241                         break;
242
243                 case 'd':       /* turn on debugging */
244                         ldap_debug += atoi( optarg );
245                         break;
246
247                 case 'D':
248                         ber_str2bv( optarg, 0, 1, &authcDN );
249                         break;
250
251                 case 'f':       /* specify a conf file */
252                         conffile = strdup( optarg );
253                         break;
254
255                 case 'F':       /* specify a conf dir */
256                         confdir = strdup( optarg );
257                         break;
258
259                 case 'l':       /* LDIF file */
260                         ldiffile = strdup( optarg );
261                         break;
262
263                 case 'M':
264                         ber_str2bv( optarg, 0, 0, &mech );
265                         break;
266
267                 case 'N':
268                         if ( dn_mode && dn_mode != SLAP_TOOL_LDAPDN_NORMAL ) {
269                                 usage( tool, progname );
270                         }
271                         dn_mode = SLAP_TOOL_LDAPDN_NORMAL;
272                         break;
273
274                 case 'n':       /* which config file db to index */
275                         dbnum = atoi( optarg );
276                         break;
277
278                 case 'o':
279                         if ( parse_slapacl() ) {
280                                 usage( tool, progname );
281                         }
282                         break;
283
284                 case 'P':
285                         if ( dn_mode && dn_mode != SLAP_TOOL_LDAPDN_PRETTY ) {
286                                 usage( tool, progname );
287                         }
288                         dn_mode = SLAP_TOOL_LDAPDN_PRETTY;
289                         break;
290
291                 case 'q':       /* turn on quick */
292                         mode |= SLAP_TOOL_QUICK;
293                         break;
294
295                 case 'R':
296                         realm = optarg;
297                         break;
298
299                 case 's':       /* dump subtree */
300                         subtree = strdup( optarg );
301                         break;
302
303                 case 't':       /* turn on truncate */
304                         truncatemode++;
305                         mode |= SLAP_TRUNCATE_MODE;
306                         break;
307
308                 case 'U':
309                         ber_str2bv( optarg, 0, 0, &authcID );
310                         break;
311
312                 case 'u':       /* dry run */
313                         dryrun++;
314                         break;
315
316                 case 'v':       /* turn on verbose */
317                         verbose++;
318                         break;
319
320                 case 'w':       /* write context csn at the end */
321                         update_ctxcsn++;
322                         break;
323
324                 case 'X':
325                         ber_str2bv( optarg, 0, 0, &authzID );
326                         break;
327
328                 default:
329                         usage( tool, progname );
330                         break;
331                 }
332         }
333
334         switch ( tool ) {
335         case SLAPADD:
336         case SLAPCAT:
337         case SLAPINDEX:
338                 if ( ( argc != optind ) || (dbnum >= 0 && base.bv_val != NULL ) ) {
339                         usage( tool, progname );
340                 }
341
342                 break;
343
344         case SLAPDN:
345                 if ( argc == optind ) {
346                         usage( tool, progname );
347                 }
348                 break;
349
350         case SLAPAUTH:
351                 if ( argc == optind && BER_BVISNULL( &authcID ) ) {
352                         usage( tool, progname );
353                 }
354                 break;
355
356         case SLAPTEST:
357                 if ( argc != optind ) {
358                         usage( tool, progname );
359                 }
360                 break;
361
362         case SLAPACL:
363                 if ( !BER_BVISNULL( &authcDN ) && !BER_BVISNULL( &authcID ) ) {
364                         usage( tool, progname );
365                 }
366                 if ( BER_BVISNULL( &base ) ) {
367                         usage( tool, progname );
368                 }
369                 ber_dupbv( &baseDN, &base );
370                 break;
371
372         default:
373                 break;
374         }
375
376         ldap_syslog = 0;
377
378         if ( ldiffile == NULL ) {
379                 ldiffp = tool == SLAPCAT ? stdout : stdin;
380
381         } else if ((ldiffp = fopen( ldiffile, tool == SLAPCAT ? "w" : "r" ))
382                 == NULL )
383         {
384                 perror( ldiffile );
385                 exit( EXIT_FAILURE );
386         }
387
388         /*
389          * initialize stuff and figure out which backend we're dealing with
390          */
391
392 #ifdef SLAPD_MODULES
393         if ( module_init() != 0 ) {
394                 fprintf( stderr, "%s: module_init failed!\n", progname );
395                 exit( EXIT_FAILURE );
396         }
397 #endif
398                 
399         rc = slap_schema_init();
400
401         if ( rc != 0 ) {
402                 fprintf( stderr, "%s: slap_schema_init failed!\n", progname );
403                 exit( EXIT_FAILURE );
404         }
405
406         rc = slap_init( mode, progname );
407
408         if ( rc != 0 ) {
409                 fprintf( stderr, "%s: slap_init failed!\n", progname );
410                 exit( EXIT_FAILURE );
411         }
412
413         if ( frontend_init() ) {
414                 fprintf( stderr, "%s: frontend_init failed!\n", progname );
415                 exit( EXIT_FAILURE );
416         }
417
418         if ( overlay_init() ) {
419                 fprintf( stderr, "%s: overlay_init failed!\n", progname );
420                 exit( EXIT_FAILURE );
421         }
422
423         rc = read_config( conffile, confdir );
424
425         if ( rc != 0 ) {
426                 fprintf( stderr, "%s: bad configuration file!\n", progname );
427                 exit( EXIT_FAILURE );
428         }
429
430         at_oc_cache = 1;
431
432         switch ( tool ) {
433         case SLAPADD:
434         case SLAPCAT:
435         case SLAPINDEX:
436                 if ( !nbackends ) {
437                         fprintf( stderr, "No databases found "
438                                         "in config file\n" );
439                         exit( EXIT_FAILURE );
440                 }
441                 break;
442
443         default:
444                 break;
445         }
446
447         rc = slap_schema_check();
448
449         if ( rc != 0 ) {
450                 fprintf( stderr, "%s: slap_schema_prep failed!\n", progname );
451                 exit( EXIT_FAILURE );
452         }
453
454         switch ( tool ) {
455         case SLAPDN:
456         case SLAPTEST:
457         case SLAPAUTH:
458                 be = NULL;
459                 goto startup;
460
461         default:
462                 break;
463         }
464
465         if( filterstr ) {
466                 filter = str2filter( filterstr );
467
468                 if( filter == NULL ) {
469                         fprintf( stderr, "Invalid filter '%s'\n", filterstr );
470                         exit( EXIT_FAILURE );
471                 }
472         }
473
474         if( subtree ) {
475                 struct berval val;
476                 ber_str2bv( subtree, 0, 0, &val );
477                 rc = dnNormalize( 0, NULL, NULL, &val, &sub_ndn, NULL );
478                 if( rc != LDAP_SUCCESS ) {
479                         fprintf( stderr, "Invalid subtree DN '%s'\n", subtree );
480                         exit( EXIT_FAILURE );
481                 }
482
483                 if ( BER_BVISNULL( &base ) && dbnum == -1 ) {
484                         base = val;
485                 } else {
486                         free( subtree );
487                 }
488         }
489
490         if( base.bv_val != NULL ) {
491                 struct berval nbase;
492
493                 rc = dnNormalize( 0, NULL, NULL, &base, &nbase, NULL );
494                 if( rc != LDAP_SUCCESS ) {
495                         fprintf( stderr, "%s: slap_init invalid suffix (\"%s\")\n",
496                                 progname, base.bv_val );
497                         exit( EXIT_FAILURE );
498                 }
499
500                 be = select_backend( &nbase, 0, 0 );
501                 ber_memfree( nbase.bv_val );
502
503                 switch ( tool ) {
504                 case SLAPACL:
505                         goto startup;
506
507                 default:
508                         break;
509                 }
510
511                 if( be == NULL ) {
512                         fprintf( stderr, "%s: slap_init no backend for \"%s\"\n",
513                                 progname, base.bv_val );
514                         exit( EXIT_FAILURE );
515                 }
516                 /* If the named base is a glue master, operate on the
517                  * entire context
518                  */
519                 if ( SLAP_GLUE_INSTANCE( be ) ) {
520                         nosubordinates = 1;
521                 }
522
523         } else if ( dbnum == -1 ) {
524                 if ( nbackends <= 0 ) {
525                         fprintf( stderr, "No available databases\n" );
526                         exit( EXIT_FAILURE );
527                 }
528                 LDAP_STAILQ_FOREACH( be, &backendDB, be_next ) {
529                         dbnum++;
530                         if ( dbnum < 1 ) continue;
531                 
532                         if ( SLAP_MONITOR(be))
533                                 continue;
534
535                 /* If just doing the first by default and it is a
536                  * glue subordinate, find the master.
537                  */
538                         if ( SLAP_GLUE_SUBORDINATE(be) ) {
539                                 nosubordinates = 1;
540                                 continue;
541                         }
542                         break;
543                 }
544
545                 if ( !be ) {
546                         fprintf( stderr, "Available database(s) "
547                                         "do not allow %s\n", progname );
548                         exit( EXIT_FAILURE );
549                 }
550                 
551                 if ( nosubordinates == 0 && dbnum > 0 ) {
552                         Debug( LDAP_DEBUG_ANY,
553                                 "The first database does not allow %s;"
554                                 " using the first available one (%d)\n",
555                                 progname, dbnum + 1, 0 );
556                 }
557
558         } else if ( dbnum < 0 || dbnum > (nbackends-1) ) {
559                 fprintf( stderr,
560                         "Database number selected via -n is out of range\n"
561                         "Must be in the range 1 to %d"
562                         " (number of databases in the config file)\n",
563                         nbackends );
564                 exit( EXIT_FAILURE );
565
566         } else {
567                 LDAP_STAILQ_FOREACH( be, &backendDB, be_next ) {
568                         if ( dbnum == 0 ) break;
569                         dbnum--;
570                 }
571         }
572
573 startup:;
574
575 #ifdef CSRIMALLOC
576         mal_leaktrace(1);
577 #endif
578
579         if ( !dryrun && be && slap_startup( be ) ) {
580                 switch ( tool ) {
581                 case SLAPTEST:
582                         fprintf( stderr, "slap_startup failed "
583                                         "(test would succeed using "
584                                         "the -u switch)\n" );
585                         break;
586
587                 default:
588                         fprintf( stderr, "slap_startup failed\n" );
589                         break;
590                 }
591                 
592                 exit( EXIT_FAILURE );
593         }
594 }
595
596 void slap_tool_destroy( void )
597 {
598         if ( !dryrun ) {
599                 slap_shutdown( be );
600                 slap_destroy();
601         }
602 #ifdef SLAPD_MODULES
603         if ( slapMode == SLAP_SERVER_MODE ) {
604         /* always false. just pulls in necessary symbol references. */
605                 lutil_uuidstr(NULL, 0);
606         }
607         module_kill();
608 #endif
609         schema_destroy();
610 #ifdef HAVE_TLS
611         ldap_pvt_tls_destroy();
612 #endif
613         config_destroy();
614
615 #ifdef CSRIMALLOC
616         mal_dumpleaktrace( leakfile );
617 #endif
618
619         if ( !BER_BVISNULL( &authcDN ) ) {
620                 ch_free( authcDN.bv_val );
621         }
622 }