]> git.sur5r.net Git - openldap/blob - servers/slapd/config.c
memory leak fixes
[openldap] / servers / slapd / config.c
1 /* config.c - configuration file handling routines */
2 /* $OpenLDAP$ */
3 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
4  *
5  * Copyright 1998-2004 The OpenLDAP Foundation.
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted only as authorized by the OpenLDAP
10  * Public License.
11  *
12  * A copy of this license is available in the file LICENSE in the
13  * top-level directory of the distribution or, alternatively, at
14  * <http://www.OpenLDAP.org/license.html>.
15  */
16 /* Portions Copyright (c) 1995 Regents of the University of Michigan.
17  * All rights reserved.
18  *
19  * Redistribution and use in source and binary forms are permitted
20  * provided that this notice is preserved and that due credit is given
21  * to the University of Michigan at Ann Arbor. The name of the University
22  * may not be used to endorse or promote products derived from this
23  * software without specific prior written permission. This software
24  * is provided ``as is'' without express or implied warranty.
25  */
26
27 #include "portable.h"
28
29 #include <stdio.h>
30
31 #include <ac/string.h>
32 #include <ac/ctype.h>
33 #include <ac/signal.h>
34 #include <ac/socket.h>
35 #include <ac/errno.h>
36
37 #include "ldap_pvt.h"
38 #include "slap.h"
39 #ifdef LDAP_SLAPI
40 #include "slapi/slapi.h"
41 #endif
42 #include "lutil.h"
43
44 #define ARGS_STEP       512
45
46 /*
47  * defaults for various global variables
48  */
49 slap_mask_t             global_allows = 0;
50 slap_mask_t             global_disallows = 0;
51 char            *replogfile;
52 int             global_gentlehup = 0;
53 int             global_idletimeout = 0;
54 char    *global_host = NULL;
55 char    *global_realm = NULL;
56 char            *ldap_srvtab = "";
57 char            **default_passwd_hash = NULL;
58 int             cargc = 0, cargv_size = 0;
59 char    **cargv;
60 struct berval default_search_base = BER_BVNULL;
61 struct berval default_search_nbase = BER_BVNULL;
62 unsigned                num_subordinates = 0;
63
64 ber_len_t sockbuf_max_incoming = SLAP_SB_MAX_INCOMING_DEFAULT;
65 ber_len_t sockbuf_max_incoming_auth= SLAP_SB_MAX_INCOMING_AUTH;
66
67 int     slap_conn_max_pending = SLAP_CONN_MAX_PENDING_DEFAULT;
68 int     slap_conn_max_pending_auth = SLAP_CONN_MAX_PENDING_AUTH;
69
70 char   *slapd_pid_file  = NULL;
71 char   *slapd_args_file = NULL;
72
73 char   *strtok_quote_ptr;
74
75 int use_reverse_lookup = 0;
76
77 #ifdef LDAP_SLAPI
78 int slapi_plugins_used = 0;
79 #endif
80
81 static char *fp_getline(FILE *fp, int *lineno);
82 static void fp_getline_init(int *lineno);
83 static int fp_parse_line(int lineno, char *line);
84
85 static char     *strtok_quote(char *line, char *sep);
86 static int load_ucdata(char *path);
87
88 static int add_syncrepl LDAP_P(( Backend *, char **, int ));
89 static int parse_syncrepl_line LDAP_P(( char **, int, syncinfo_t *));
90
91 int
92 read_config( const char *fname, int depth )
93 {
94         FILE    *fp;
95         char    *line, *savefname, *saveline;
96         int savelineno;
97         int     lineno, i;
98         int rc;
99         struct berval vals[2];
100         char *replicahost;
101         LDAPURLDesc *ludp;
102         static BackendInfo *bi = NULL;
103         static BackendDB        *be = NULL;
104         char    *next;
105
106
107         vals[1].bv_val = NULL;
108
109         if ( depth == 0 ) {
110                 cargv = ch_calloc( ARGS_STEP + 1, sizeof(*cargv) );
111                 cargv_size = ARGS_STEP + 1;
112         }
113
114         if ( (fp = fopen( fname, "r" )) == NULL ) {
115                 ldap_syslog = 1;
116                 Debug( LDAP_DEBUG_ANY,
117                     "could not open config file \"%s\": %s (%d)\n",
118                     fname, strerror(errno), errno );
119                 return 1;
120         }
121
122         Debug( LDAP_DEBUG_CONFIG, "reading config file %s\n", fname, 0, 0 );
123
124
125         fp_getline_init( &lineno );
126
127         while ( (line = fp_getline( fp, &lineno )) != NULL ) {
128                 /* skip comments and blank lines */
129                 if ( line[0] == '#' || line[0] == '\0' ) {
130                         continue;
131                 }
132
133                 /* fp_parse_line is destructive, we save a copy */
134                 saveline = ch_strdup( line );
135
136                 if ( fp_parse_line( lineno, line ) != 0 ) {
137                         return( 1 );
138                 }
139
140                 if ( cargc < 1 ) {
141                         Debug( LDAP_DEBUG_ANY,
142                             "%s: line %d: bad config line (ignored)\n",
143                             fname, lineno, 0 );
144
145                         continue;
146                 }
147
148                 if ( strcasecmp( cargv[0], "backend" ) == 0 ) {
149                         if ( cargc < 2 ) {
150                                 Debug( LDAP_DEBUG_ANY,
151                 "%s: line %d: missing type in \"backend <type>\" line\n",
152                                     fname, lineno, 0 );
153
154                                 return( 1 );
155                         }
156
157                         if( be != NULL ) {
158                                 Debug( LDAP_DEBUG_ANY,
159 "%s: line %d: backend line must appear before any database definition\n",
160                                     fname, lineno, 0 );
161
162                                 return( 1 );
163                         }
164
165                         bi = backend_info( cargv[1] );
166
167                         if( bi == NULL ) {
168                                 Debug( LDAP_DEBUG_ANY,
169                                         "backend %s initialization failed.\n",
170                                     cargv[1], 0, 0 );
171
172                                 return( 1 );
173                         }
174                 } else if ( strcasecmp( cargv[0], "database" ) == 0 ) {
175                         if ( cargc < 2 ) {
176                                 Debug( LDAP_DEBUG_ANY,
177                 "%s: line %d: missing type in \"database <type>\" line\n",
178                                     fname, lineno, 0 );
179
180                                 return( 1 );
181                         }
182
183                         bi = NULL;
184                         be = backend_db_init( cargv[1] );
185
186                         if( be == NULL ) {
187                                 Debug( LDAP_DEBUG_ANY,
188                                         "database %s initialization failed.\n",
189                                     cargv[1], 0, 0 );
190
191                                 return( 1 );
192                         }
193
194                 /* set local security factor */
195                 } else if ( strcasecmp( cargv[0], "localSSF" ) == 0 ) {
196                         long ssf;
197                         if ( cargc < 2 ) {
198                                 Debug( LDAP_DEBUG_ANY,
199                                    "%s: line %d: missing ssf in \"localSSF <ssf>\" line\n",
200                                     fname, lineno, 0 );
201                                 return( 1 );
202                         }
203
204                         ssf = atol( cargv[1] );
205
206                         if( ssf < 0 ) {
207                                 Debug( LDAP_DEBUG_ANY,
208                                         "%s: line %d: invalid ssf value (%ld) in "
209                                         "\"localSSF <ssf>\" line.\n",
210                                     fname, lineno, ssf );
211                                 return( 1 );
212                         }
213
214                         local_ssf = ssf;
215
216                 /* set thread concurrency */
217                 } else if ( strcasecmp( cargv[0], "concurrency" ) == 0 ) {
218                         int c;
219                         if ( cargc < 2 ) {
220                                 Debug( LDAP_DEBUG_ANY,
221             "%s: line %d: missing level in \"concurrency <level>\" line\n",
222                                     fname, lineno, 0 );
223
224                                 return( 1 );
225                         }
226
227                         c = strtol( cargv[1], &next, 10 );
228                         if ( next == NULL || next[0] != '\0' ) {
229                                 Debug( LDAP_DEBUG_ANY,
230             "%s: line %d: unable to parse level \"%s\" in \"concurrency <level>\" line\n",
231                                     fname, lineno, cargv[1] );
232                                 return( 1 );
233                         }
234
235                         if( c < 1 ) {
236                                 Debug( LDAP_DEBUG_ANY,
237             "%s: line %d: invalid level (%d) in \"concurrency <level>\" line\n",
238                                     fname, lineno, c );
239
240                                 return( 1 );
241                         }
242
243                         ldap_pvt_thread_set_concurrency( c );
244
245                 /* set sockbuf max */
246                 } else if ( strcasecmp( cargv[0], "sockbuf_max_incoming" ) == 0 ) {
247                         long max;
248                         if ( cargc < 2 ) {
249                                 Debug( LDAP_DEBUG_ANY,
250                                            "%s: line %d: missing max in \"sockbuf_max_incoming <bytes>\" line\n",
251                                     fname, lineno, 0 );
252
253                                 return( 1 );
254                         }
255
256                         max = atol( cargv[1] );
257
258                         if( max < 0 ) {
259                                 Debug( LDAP_DEBUG_ANY,
260                                         "%s: line %d: invalid max value (%ld) in "
261                                         "\"sockbuf_max_incoming <bytes>\" line.\n",
262                                     fname, lineno, max );
263
264                                 return( 1 );
265                         }
266
267                         sockbuf_max_incoming = max;
268
269                 /* set sockbuf max authenticated */
270                 } else if ( strcasecmp( cargv[0], "sockbuf_max_incoming_auth" ) == 0 ) {
271                         long max;
272                         if ( cargc < 2 ) {
273                                 Debug( LDAP_DEBUG_ANY,
274                                            "%s: line %d: missing max in \"sockbuf_max_incoming_auth <bytes>\" line\n",
275                                     fname, lineno, 0 );
276
277                                 return( 1 );
278                         }
279
280                         max = atol( cargv[1] );
281
282                         if( max < 0 ) {
283                                 Debug( LDAP_DEBUG_ANY,
284                                         "%s: line %d: invalid max value (%ld) in "
285                                         "\"sockbuf_max_incoming_auth <bytes>\" line.\n",
286                                     fname, lineno, max );
287
288                                 return( 1 );
289                         }
290
291                         sockbuf_max_incoming_auth = max;
292
293                 /* set conn pending max */
294                 } else if ( strcasecmp( cargv[0], "conn_max_pending" ) == 0 ) {
295                         long max;
296                         if ( cargc < 2 ) {
297                                 Debug( LDAP_DEBUG_ANY,
298                                            "%s: line %d: missing max in \"conn_max_pending <requests>\" line\n",
299                                     fname, lineno, 0 );
300
301                                 return( 1 );
302                         }
303
304                         max = atol( cargv[1] );
305
306                         if( max < 0 ) {
307                                 Debug( LDAP_DEBUG_ANY,
308                                         "%s: line %d: invalid max value (%ld) in "
309                                         "\"conn_max_pending <requests>\" line.\n",
310                                     fname, lineno, max );
311
312                                 return( 1 );
313                         }
314
315                         slap_conn_max_pending = max;
316
317                 /* set conn pending max authenticated */
318                 } else if ( strcasecmp( cargv[0], "conn_max_pending_auth" ) == 0 ) {
319                         long max;
320                         if ( cargc < 2 ) {
321                                 Debug( LDAP_DEBUG_ANY,
322                                            "%s: line %d: missing max in \"conn_max_pending_auth <requests>\" line\n",
323                                     fname, lineno, 0 );
324
325                                 return( 1 );
326                         }
327
328                         max = atol( cargv[1] );
329
330                         if( max < 0 ) {
331                                 Debug( LDAP_DEBUG_ANY,
332                                         "%s: line %d: invalid max value (%ld) in "
333                                         "\"conn_max_pending_auth <requests>\" line.\n",
334                                     fname, lineno, max );
335
336                                 return( 1 );
337                         }
338
339                         slap_conn_max_pending_auth = max;
340
341                 /* default search base */
342                 } else if ( strcasecmp( cargv[0], "defaultSearchBase" ) == 0 ) {
343                         if ( cargc < 2 ) {
344                                 Debug( LDAP_DEBUG_ANY, "%s: line %d: "
345                                         "missing dn in \"defaultSearchBase <dn>\" line\n",
346                                         fname, lineno, 0 );
347
348                                 return 1;
349
350                         } else if ( cargc > 2 ) {
351                                 Debug( LDAP_DEBUG_ANY, "%s: line %d: "
352                                         "extra cruft after <dn> in \"defaultSearchBase %s\", "
353                                         "line (ignored)\n",
354                                         fname, lineno, cargv[1] );
355                         }
356
357                         if ( bi != NULL || be != NULL ) {
358                                 Debug( LDAP_DEBUG_ANY, "%s: line %d: "
359                                         "defaultSearchBaase line must appear prior to "
360                                         "any backend or database definition\n",
361                                     fname, lineno, 0 );
362
363                                 return 1;
364                         }
365
366                         if ( default_search_nbase.bv_len ) {
367                                 Debug( LDAP_DEBUG_ANY, "%s: line %d: "
368                                         "default search base \"%s\" already defined "
369                                         "(discarding old)\n",
370                                         fname, lineno, default_search_base.bv_val );
371
372                                 free( default_search_base.bv_val );
373                                 free( default_search_nbase.bv_val );
374                         }
375
376                         if ( load_ucdata( NULL ) < 0 ) return 1;
377
378                         {
379                                 struct berval dn;
380
381                                 dn.bv_val = cargv[1];
382                                 dn.bv_len = strlen( dn.bv_val );
383
384                                 rc = dnPrettyNormal( NULL, &dn,
385                                         &default_search_base,
386                                         &default_search_nbase, NULL );
387
388                                 if( rc != LDAP_SUCCESS ) {
389                                         Debug( LDAP_DEBUG_ANY,
390                                                 "%s: line %d: defaultSearchBase DN is invalid\n",
391                                            fname, lineno, 0 );
392                                         return( 1 );
393                                 }
394                         }
395
396                 /* set maximum threads in thread pool */
397                 } else if ( strcasecmp( cargv[0], "threads" ) == 0 ) {
398                         int c;
399                         if ( cargc < 2 ) {
400                                 Debug( LDAP_DEBUG_ANY,
401             "%s: line %d: missing count in \"threads <count>\" line\n",
402                                     fname, lineno, 0 );
403
404                                 return( 1 );
405                         }
406
407                         c = strtol( cargv[1], &next, 10 );
408                         if (next == NULL || next[0] != '\0' ) {
409                                 Debug( LDAP_DEBUG_ANY,
410             "%s: line %d: unable to parse count \"%s\" in \"threads <count>\" line\n",
411                                     fname, lineno, cargv[1] );
412                                 return( 1 );
413                         }
414
415                         if( c < 0 ) {
416                                 Debug( LDAP_DEBUG_ANY,
417             "%s: line %d: invalid level (%d) in \"threads <count>\" line\n",
418                                     fname, lineno, c );
419
420                                 return( 1 );
421                         }
422
423                         ldap_pvt_thread_pool_maxthreads( &connection_pool, c );
424
425                         /* save for later use */
426                         connection_pool_max = c;
427
428                 /* get pid file name */
429                 } else if ( strcasecmp( cargv[0], "pidfile" ) == 0 ) {
430                         if ( cargc < 2 ) {
431                                 Debug( LDAP_DEBUG_ANY,
432             "%s: line %d: missing file name in \"pidfile <file>\" line\n",
433                                     fname, lineno, 0 );
434
435                                 return( 1 );
436                         }
437
438                         slapd_pid_file = ch_strdup( cargv[1] );
439
440                 /* get args file name */
441                 } else if ( strcasecmp( cargv[0], "argsfile" ) == 0 ) {
442                         if ( cargc < 2 ) {
443                                 Debug( LDAP_DEBUG_ANY,
444             "%s: line %d: missing file name in \"argsfile <file>\" line\n",
445                                     fname, lineno, 0 );
446
447                                 return( 1 );
448                         }
449
450                         slapd_args_file = ch_strdup( cargv[1] );
451
452                 } else if ( strcasecmp( cargv[0], "replica-pidfile" ) == 0 ) {
453                         /* ignore */ ;
454
455                 } else if ( strcasecmp( cargv[0], "replica-argsfile" ) == 0 ) {
456                         /* ignore */ ;
457
458                 /* default password hash */
459                 } else if ( strcasecmp( cargv[0], "password-hash" ) == 0 ) {
460                         if ( cargc < 2 ) {
461                                 Debug( LDAP_DEBUG_ANY,
462             "%s: line %d: missing hash in \"password-hash <hash>\" line\n",
463                                     fname, lineno, 0 );
464
465                                 return( 1 );
466                         }
467                         if ( default_passwd_hash != NULL ) {
468                                 Debug( LDAP_DEBUG_ANY,
469                                         "%s: line %d: already set default password_hash!\n",
470                                         fname, lineno, 0 );
471
472                                 return 1;
473
474                         }
475                         for(i = 1; i < cargc; i++) {
476                                 if ( lutil_passwd_scheme( cargv[i] ) == 0 ) {
477                                         Debug( LDAP_DEBUG_ANY,
478                                                 "%s: line %d: password scheme \"%s\" not available\n",
479                                                 fname, lineno, cargv[i] );
480                                 } else {
481                                         ldap_charray_add( &default_passwd_hash, cargv[i] );
482                                 }
483                         }
484                         if( !default_passwd_hash ) {
485                                 Debug( LDAP_DEBUG_ANY,
486                                         "%s: line %d: no valid hashes found\n",
487                                         fname, lineno, 0 );
488                                 return 1;
489                         }
490
491                 } else if ( strcasecmp( cargv[0], "password-crypt-salt-format" ) == 0 ) 
492                 {
493                         if ( cargc < 2 ) {
494                                 Debug( LDAP_DEBUG_ANY, "%s: line %d: missing format in "
495                                         "\"password-crypt-salt-format <format>\" line\n",
496                                     fname, lineno, 0 );
497
498                                 return 1;
499                         }
500
501                         lutil_salt_format( cargv[1] );
502
503 #ifdef SLAP_AUTH_REWRITE
504                 /* use authid rewrite instead of sasl regexp */
505                 } else if ( strncasecmp( cargv[0], "auth-rewrite",
506                         STRLENOF("auth-rewrite") ) == 0 )
507                 {
508                         int rc = slap_sasl_rewrite_config( fname, lineno,
509                                         cargc, cargv );
510                         if ( rc ) {
511                                 return rc;
512                         }
513 #endif /* SLAP_AUTH_REWRITE */
514
515                 /* Auth + SASL config options */
516                 } else if ( !strncasecmp( cargv[0], "auth", STRLENOF("auth") ) ||
517                         !strncasecmp( cargv[0], "sasl", STRLENOF("sasl") ))
518                 {
519                         if ( slap_sasl_config( cargc, cargv, line, fname, lineno ) )
520                                 return 1;
521
522
523                 } else if ( strcasecmp( cargv[0], "schemadn" ) == 0 ) {
524                         struct berval dn;
525                         if ( cargc < 2 ) {
526                                 Debug( LDAP_DEBUG_ANY,
527             "%s: line %d: missing dn in \"schemadn <dn>\" line\n",
528                                     fname, lineno, 0 );
529                                 return 1 ;
530                         }
531                         ber_str2bv( cargv[1], 0, 0, &dn );
532                         if ( be ) {
533                                 rc = dnPrettyNormal( NULL, &dn, &be->be_schemadn,
534                                         &be->be_schemandn, NULL );
535                         } else {
536                                 rc = dnPrettyNormal( NULL, &dn, &frontendDB->be_schemadn,
537                                         &frontendDB->be_schemandn, NULL );
538                         }
539                         if ( rc != LDAP_SUCCESS ) {
540                                 Debug( LDAP_DEBUG_ANY,
541                                         "%s: line %d: schemadn DN is invalid\n",
542                                         fname, lineno, 0 );
543                                 return 1;
544                         }
545
546                 /* set UCDATA path */
547                 } else if ( strcasecmp( cargv[0], "ucdata-path" ) == 0 ) {
548                         int err;
549                         if ( cargc < 2 ) {
550                                 Debug( LDAP_DEBUG_ANY,
551             "%s: line %d: missing path in \"ucdata-path <path>\" line\n",
552                                     fname, lineno, 0 );
553
554                                 return( 1 );
555                         }
556
557                         err = load_ucdata( cargv[1] );
558                         if ( err <= 0 ) {
559                                 if ( err == 0 ) {
560                                         Debug( LDAP_DEBUG_ANY,
561                                                "%s: line %d: ucdata already loaded, ucdata-path must be set earlier in the file and/or be specified only once!\n",
562                                                fname, lineno, 0 );
563
564                                 }
565                                 return( 1 );
566                         }
567
568                 /* set size limit */
569                 } else if ( strcasecmp( cargv[0], "sizelimit" ) == 0 ) {
570                         int rc = 0, i;
571                         struct slap_limits_set *lim;
572                         
573                         if ( cargc < 2 ) {
574                                 Debug( LDAP_DEBUG_ANY,
575             "%s: line %d: missing limit in \"sizelimit <limit>\" line\n",
576                                     fname, lineno, 0 );
577
578                                 return( 1 );
579                         }
580
581                         if ( be == NULL ) {
582                                 lim = &frontendDB->be_def_limit;
583                         } else {
584                                 lim = &be->be_def_limit;
585                         }
586
587                         for ( i = 1; i < cargc; i++ ) {
588                                 if ( strncasecmp( cargv[i], "size", 4 ) == 0 ) {
589                                         rc = limits_parse_one( cargv[i], lim );
590                                         if ( rc ) {
591                                                 Debug( LDAP_DEBUG_ANY,
592                                                         "%s: line %d: unable "
593                                                         "to parse value \"%s\" "
594                                                         "in \"sizelimit "
595                                                         "<limit>\" line\n",
596                                                         fname, lineno, cargv[i] );
597                                                 return( 1 );
598                                         }
599
600                                 } else {
601                                         if ( strcasecmp( cargv[i], "unlimited" ) == 0 ) {
602                                                 lim->lms_s_soft = -1;
603                                         } else {
604                                                 lim->lms_s_soft = strtol( cargv[i] , &next, 0 );
605                                                 if ( next == cargv[i] ) {
606                                                         Debug( LDAP_DEBUG_ANY,
607                                                             "%s: line %d: unable to parse limit \"%s\" in \"sizelimit <limit>\" line\n",
608                                                             fname, lineno, cargv[i] );
609                                                         return( 1 );
610
611                                                 } else if ( next[0] != '\0' ) {
612                                                         Debug( LDAP_DEBUG_ANY,
613                                                             "%s: line %d: trailing chars \"%s\" in \"sizelimit <limit>\" line ignored\n",
614                                                             fname, lineno, next );
615                                                 }
616                                         }
617                                         lim->lms_s_hard = 0;
618                                 }
619                         }
620
621                 /* set time limit */
622                 } else if ( strcasecmp( cargv[0], "timelimit" ) == 0 ) {
623                         int rc = 0, i;
624                         struct slap_limits_set *lim;
625                         
626                         if ( cargc < 2 ) {
627                                 Debug( LDAP_DEBUG_ANY,
628             "%s: line %d: missing limit in \"timelimit <limit>\" line\n",
629                                     fname, lineno, 0 );
630
631                                 return( 1 );
632                         }
633                         
634                         if ( be == NULL ) {
635                                 lim = &frontendDB->be_def_limit;
636                         } else {
637                                 lim = &be->be_def_limit;
638                         }
639
640                         for ( i = 1; i < cargc; i++ ) {
641                                 if ( strncasecmp( cargv[i], "time", 4 ) == 0 ) {
642                                         rc = limits_parse_one( cargv[i], lim );
643                                         if ( rc ) {
644                                                 Debug( LDAP_DEBUG_ANY,
645                                                         "%s: line %d: unable "
646                                                         "to parse value \"%s\" "
647                                                         "in \"timelimit "
648                                                         "<limit>\" line\n",
649                                                         fname, lineno, cargv[i] );
650                                                 return( 1 );
651                                         }
652
653                                 } else {
654                                         if ( strcasecmp( cargv[i], "unlimited" ) == 0 ) {
655                                                 lim->lms_t_soft = -1;
656                                         } else {
657                                                 lim->lms_t_soft = strtol( cargv[i] , &next, 0 );
658                                                 if ( next == cargv[i] ) {
659                                                         Debug( LDAP_DEBUG_ANY,
660                                                             "%s: line %d: unable to parse limit \"%s\" in \"timelimit <limit>\" line\n",
661                                                             fname, lineno, cargv[i] );
662                                                         return( 1 );
663
664                                                 } else if ( next[0] != '\0' ) {
665                                                         Debug( LDAP_DEBUG_ANY,
666                                                             "%s: line %d: trailing chars \"%s\" in \"timelimit <limit>\" line ignored\n",
667                                                             fname, lineno, next );
668                                                 }
669                                         }
670                                         lim->lms_t_hard = 0;
671                                 }
672                         }
673
674                 /* set regex-based limits */
675                 } else if ( strcasecmp( cargv[0], "limits" ) == 0 ) {
676                         if ( be == NULL ) {
677                                 Debug( LDAP_DEBUG_ANY,
678         "%s: line %d \"limits\" allowed only in database environment.\n%s",
679                                         fname, lineno, "" );
680                                 return( 1 );
681                         }
682
683                         if ( limits_parse( be, fname, lineno, cargc, cargv ) ) {
684                                 return( 1 );
685                         }
686
687                 /* mark this as a subordinate database */
688                 } else if ( strcasecmp( cargv[0], "subordinate" ) == 0 ) {
689                         if ( be == NULL ) {
690                                 Debug( LDAP_DEBUG_ANY, "%s: line %d: subordinate keyword "
691                                         "must appear inside a database definition.\n",
692                                     fname, lineno, 0 );
693                                 return 1;
694
695                         } else {
696                                 SLAP_DBFLAGS(be) |= SLAP_DBFLAG_GLUE_SUBORDINATE;
697                                 num_subordinates++;
698                         }
699
700                 /* add an overlay to this backend */
701                 } else if ( strcasecmp( cargv[0], "overlay" ) == 0 ) {
702                         if ( be == NULL ) {
703                                 if ( cargv[1][0] == '-' && overlay_config( frontendDB, &cargv[1][1] ) ) {
704                                         /* log error */
705                                         Debug( LDAP_DEBUG_ANY, "%s: line %d: "
706                                                 "(optional) global overlay \"%s\" configuration "
707                                                 "failed (ignored)\n", fname, lineno, &cargv[1][1] );
708                                 } else if ( overlay_config( frontendDB, cargv[1] ) ) {
709                                         return 1;
710                                 }
711
712                         } else {
713                                 if ( cargv[1][0] == '-' && overlay_config( be, &cargv[1][1] ) ) {
714                                         /* log error */
715                                         Debug( LDAP_DEBUG_ANY, "%s: line %d: "
716                                                 "(optional) overlay \"%s\" configuration "
717                                                 "failed (ignored)\n", fname, lineno, &cargv[1][1] );
718                                 } else if ( overlay_config( be, cargv[1] ) ) {
719                                         return 1;
720                                 }
721                         }
722
723                 /* set database suffix */
724                 } else if ( strcasecmp( cargv[0], "suffix" ) == 0 ) {
725                         Backend *tmp_be;
726                         struct berval dn, pdn, ndn;
727
728                         if ( cargc < 2 ) {
729                                 Debug( LDAP_DEBUG_ANY, "%s: line %d: "
730                                         "missing dn in \"suffix <dn>\" line\n",
731                                     fname, lineno, 0 );
732
733                                 return( 1 );
734
735                         } else if ( cargc > 2 ) {
736                                 Debug( LDAP_DEBUG_ANY, "%s: line %d: extra cruft "
737                                         "after <dn> in \"suffix %s\" line (ignored)\n",
738                                     fname, lineno, cargv[1] );
739                         }
740
741                         if ( be == NULL ) {
742                                 Debug( LDAP_DEBUG_ANY, "%s: line %d: suffix line "
743                                         "must appear inside a database definition\n",
744                                     fname, lineno, 0 );
745                                 return( 1 );
746
747 #if defined(SLAPD_MONITOR_DN)
748                         /* "cn=Monitor" is reserved for monitoring slap */
749                         } else if ( strcasecmp( cargv[1], SLAPD_MONITOR_DN ) == 0 ) {
750                                 Debug( LDAP_DEBUG_ANY, "%s: line %d: \""
751                                         "%s\" is reserved for monitoring slapd\n", 
752                                         fname, lineno, SLAPD_MONITOR_DN );
753                                 return( 1 );
754 #endif /* SLAPD_MONITOR_DN */
755                         }
756
757                         if ( load_ucdata( NULL ) < 0 ) return 1;
758
759                         dn.bv_val = cargv[1];
760                         dn.bv_len = strlen( cargv[1] );
761
762                         rc = dnPrettyNormal( NULL, &dn, &pdn, &ndn, NULL );
763                         if( rc != LDAP_SUCCESS ) {
764                                 Debug( LDAP_DEBUG_ANY,
765                                         "%s: line %d: suffix DN is invalid\n",
766                                    fname, lineno, 0 );
767                                 return( 1 );
768                         }
769
770                         tmp_be = select_backend( &ndn, 0, 0 );
771                         if ( tmp_be == be ) {
772                                 Debug( LDAP_DEBUG_ANY, "%s: line %d: suffix "
773                                         "already served by this backend (ignored)\n",
774                                     fname, lineno, 0 );
775                                 free( pdn.bv_val );
776                                 free( ndn.bv_val );
777
778                         } else if ( tmp_be  != NULL ) {
779                                 Debug( LDAP_DEBUG_ANY, "%s: line %d: suffix "
780                                         "already served by a preceeding backend \"%s\"\n",
781                                     fname, lineno, tmp_be->be_suffix[0].bv_val );
782                                 free( pdn.bv_val );
783                                 free( ndn.bv_val );
784                                 return( 1 );
785
786                         } else if( pdn.bv_len == 0 && default_search_nbase.bv_len ) {
787                                         Debug( LDAP_DEBUG_ANY, "%s: line %d: "
788                                                 "suffix DN empty and default "
789                                                 "search base provided \"%s\" (assuming okay)\n",
790                                         fname, lineno, default_search_base.bv_val );
791                         }
792
793                         ber_bvarray_add( &be->be_suffix, &pdn );
794                         ber_bvarray_add( &be->be_nsuffix, &ndn );
795
796                /* set max deref depth */
797                } else if ( strcasecmp( cargv[0], "maxDerefDepth" ) == 0 ) {
798                                         int i;
799                        if ( cargc < 2 ) {
800                                Debug( LDAP_DEBUG_ANY,
801                    "%s: line %d: missing depth in \"maxDerefDepth <depth>\" line\n",
802                                    fname, lineno, 0 );
803
804                                return( 1 );
805                        }
806                        if ( be == NULL ) {
807                                Debug( LDAP_DEBUG_ANY,
808 "%s: line %d: depth line must appear inside a database definition.\n",
809                                    fname, lineno, 0 );
810                                 return 1;
811                        }
812
813                        i = strtol( cargv[1], &next, 10 );
814                        if ( next == NULL || next[0] != '\0' ) {
815                                Debug( LDAP_DEBUG_ANY,
816                                           "%s: line %d: unable to parse depth \"%s\" in \"maxDerefDepth <depth>\" "
817                                           "line.\n", fname, lineno, cargv[1] );
818                                 return 1;
819                        }
820
821                        if (i < 0) {
822                                Debug( LDAP_DEBUG_ANY,
823 "%s: line %d: depth must be positive.\n",
824                                    fname, lineno, 0 );
825                                 return 1;
826
827
828                        }
829                        be->be_max_deref_depth = i;
830
831                 /* set magic "root" dn for this database */
832                 } else if ( strcasecmp( cargv[0], "rootdn" ) == 0 ) {
833                         if ( cargc < 2 ) {
834                                 Debug( LDAP_DEBUG_ANY,
835                     "%s: line %d: missing dn in \"rootdn <dn>\" line\n",
836                                     fname, lineno, 0 );
837
838                                 return( 1 );
839                         }
840
841                         if ( be == NULL ) {
842                                 Debug( LDAP_DEBUG_ANY,
843 "%s: line %d: rootdn line must appear inside a database definition.\n",
844                                     fname, lineno, 0 );
845                                 return 1;
846
847                         } else {
848                                 struct berval dn;
849                                 
850                                 if ( load_ucdata( NULL ) < 0 ) return 1;
851
852                                 dn.bv_val = cargv[1];
853                                 dn.bv_len = strlen( cargv[1] );
854
855                                 rc = dnPrettyNormal( NULL, &dn,
856                                         &be->be_rootdn,
857                                         &be->be_rootndn, NULL );
858
859                                 if( rc != LDAP_SUCCESS ) {
860                                         Debug( LDAP_DEBUG_ANY,
861                                                 "%s: line %d: rootdn DN is invalid\n",
862                                            fname, lineno, 0 );
863                                         return( 1 );
864                                 }
865                         }
866
867                 /* set super-secret magic database password */
868                 } else if ( strcasecmp( cargv[0], "rootpw" ) == 0 ) {
869                         if ( cargc < 2 ) {
870                                 Debug( LDAP_DEBUG_ANY, "%s: line %d: "
871                                         "missing passwd in \"rootpw <passwd>\" line\n",
872                                     fname, lineno, 0 );
873
874                                 return( 1 );
875                         }
876
877                         if ( be == NULL ) {
878                                 Debug( LDAP_DEBUG_ANY, "%s: line %d: "
879                                         "rootpw line must appear inside a database "
880                                         "definition.\n",
881                                     fname, lineno, 0 );
882                                 return 1;
883
884                         } else {
885                                 Backend *tmp_be = select_backend( &be->be_rootndn, 0, 0 );
886
887                                 if( tmp_be != be ) {
888                                         Debug( LDAP_DEBUG_ANY, "%s: line %d: "
889                                                 "rootpw can only be set when rootdn is under suffix\n",
890                                         fname, lineno, 0 );
891                                         return 1;
892                                 }
893
894                                 be->be_rootpw.bv_val = ch_strdup( cargv[1] );
895                                 be->be_rootpw.bv_len = strlen( be->be_rootpw.bv_val );
896                         }
897
898                 /* make this database read-only */
899                 } else if ( strcasecmp( cargv[0], "readonly" ) == 0 ) {
900                         if ( cargc < 2 ) {
901                                 Debug( LDAP_DEBUG_ANY,
902             "%s: line %d: missing on|off in \"readonly <on|off>\" line\n",
903                                     fname, lineno, 0 );
904
905                                 return( 1 );
906                         }
907                         if ( be == NULL ) {
908                                 if ( strcasecmp( cargv[1], "on" ) == 0 ) {
909                                         frontendDB->be_restrictops |= SLAP_RESTRICT_OP_WRITES;
910                                 } else {
911                                         frontendDB->be_restrictops &= ~SLAP_RESTRICT_OP_WRITES;
912                                 }
913
914                         } else {
915                                 if ( strcasecmp( cargv[1], "on" ) == 0 ) {
916                                         be->be_restrictops |= SLAP_RESTRICT_OP_WRITES;
917                                 } else {
918                                         be->be_restrictops &= ~SLAP_RESTRICT_OP_WRITES;
919                                 }
920                         }
921
922                 /* restricts specific operations */
923                 } else if ( strcasecmp( cargv[0], "restrict" ) == 0 ) {
924                         slap_mask_t     restrictops = 0;
925                         struct restrictable_exops_t {
926                                 char    *name;
927                                 int     flag;
928                         } restrictable_exops[] = {
929                                 { LDAP_EXOP_START_TLS,          SLAP_RESTRICT_EXOP_START_TLS },
930                                 { LDAP_EXOP_MODIFY_PASSWD,      SLAP_RESTRICT_EXOP_MODIFY_PASSWD },
931                                 { LDAP_EXOP_X_WHO_AM_I,         SLAP_RESTRICT_EXOP_WHOAMI },
932                                 { LDAP_EXOP_X_CANCEL,           SLAP_RESTRICT_EXOP_CANCEL },
933                                 { NULL,                         0 }
934                         };
935                         int i;
936
937                         if ( cargc < 2 ) {
938                                 Debug( LDAP_DEBUG_ANY,
939                                         "%s: line %d: missing <op_list> in \"restrict <op_list>\" "
940                                         "line.\n", fname, lineno, 0 );
941                                 return 1;
942                         }
943
944                         for ( i = 1; i < cargc; i++ ) {
945                                 if ( strcasecmp( cargv[ i ], "read" ) == 0 ) {
946                                         restrictops |= SLAP_RESTRICT_OP_READS;
947
948                                 } else if ( strcasecmp( cargv[ i ], "write" ) == 0 ) {
949                                         restrictops |= SLAP_RESTRICT_OP_WRITES;
950
951                                 } else if ( strcasecmp( cargv[ i ], "add" ) == 0 ) {
952                                         restrictops |= SLAP_RESTRICT_OP_ADD;
953
954                                 } else if ( strcasecmp( cargv[ i ], "bind" ) == 0 ) {
955                                         restrictops |= SLAP_RESTRICT_OP_BIND;
956
957                                 } else if ( strcasecmp( cargv[ i ], "compare" ) == 0 ) {
958                                         restrictops |= SLAP_RESTRICT_OP_COMPARE;
959
960                                 } else if ( strcasecmp( cargv[ i ], "delete" ) == 0 ) {
961                                         restrictops |= SLAP_RESTRICT_OP_DELETE;
962
963                                 } else if ( strncasecmp( cargv[ i ], "extended",
964                                         STRLENOF( "extended" ) ) == 0 )
965                                 {
966                                         char    *e = cargv[ i ] + STRLENOF( "extended" );
967
968                                         if ( e[0] == '=' ) {
969                                                 int     j;
970
971                                                 e++;
972                                                 for ( j = 0; restrictable_exops[ j ].name; j++ ) {
973                                                         if ( strcmp( e, restrictable_exops[j].name ) == 0 )
974                                                         {
975                                                                 restrictops |= restrictable_exops[ j ].flag;
976                                                                 break;
977                                                         }
978                                                 }
979
980                                                 if ( restrictable_exops[ j ].name == NULL ) {
981                                                         goto restrict_unknown;
982                                                 }
983
984                                                 restrictops &= ~SLAP_RESTRICT_OP_EXTENDED;
985
986                                         } else if ( e[0] == '\0' ) {
987                                                 restrictops &= ~SLAP_RESTRICT_EXOP_MASK;
988                                                 restrictops |= SLAP_RESTRICT_OP_EXTENDED;
989                                                 
990                                         } else {
991                                                 goto restrict_unknown;
992                                         }
993
994                                 } else if ( strcasecmp( cargv[ i ], "modify" ) == 0 ) {
995                                         restrictops |= SLAP_RESTRICT_OP_MODIFY;
996
997                                 } else if ( strcasecmp( cargv[ i ], "rename" ) == 0
998                                         || strcasecmp( cargv[ i ], "modrdn" ) == 0 )
999                                 {
1000                                         restrictops |= SLAP_RESTRICT_OP_RENAME;
1001
1002                                 } else if ( strcasecmp( cargv[ i ], "search" ) == 0 ) {
1003                                         restrictops |= SLAP_RESTRICT_OP_SEARCH;
1004
1005                                 } else {
1006 restrict_unknown:;
1007
1008                                         Debug( LDAP_DEBUG_ANY, "%s: line %d: "
1009                                                 "unknown operation %s in \"allow <features>\" line\n",
1010                                                 fname, lineno, cargv[i] );
1011                                         return 1;
1012                                 }
1013                         }
1014
1015                         if ( be == NULL ) {
1016                                 frontendDB->be_restrictops |= restrictops;
1017                         } else {
1018                                 be->be_restrictops |= restrictops;
1019                         }
1020
1021                 /* allow these features */
1022                 } else if ( strcasecmp( cargv[0], "allows" ) == 0 ||
1023                         strcasecmp( cargv[0], "allow" ) == 0 )
1024                 {
1025                         slap_mask_t     allows = 0;
1026
1027                         if ( be != NULL ) {
1028                                 Debug( LDAP_DEBUG_ANY,
1029 "%s: line %d: allow line must appear prior to database definitions\n",
1030                                     fname, lineno, 0 );
1031
1032                         }
1033
1034                         if ( cargc < 2 ) {
1035                                 Debug( LDAP_DEBUG_ANY,
1036             "%s: line %d: missing feature(s) in \"allow <features>\" line\n",
1037                                     fname, lineno, 0 );
1038
1039                                 return( 1 );
1040                         }
1041
1042                         for( i=1; i < cargc; i++ ) {
1043                                 if( strcasecmp( cargv[i], "bind_v2" ) == 0 ) {
1044                                         allows |= SLAP_ALLOW_BIND_V2;
1045
1046                                 } else if( strcasecmp( cargv[i], "bind_anon_cred" ) == 0 ) {
1047                                         allows |= SLAP_ALLOW_BIND_ANON_CRED;
1048
1049                                 } else if( strcasecmp( cargv[i], "bind_anon_dn" ) == 0 ) {
1050                                         allows |= SLAP_ALLOW_BIND_ANON_DN;
1051
1052                                 } else if( strcasecmp( cargv[i], "update_anon" ) == 0 ) {
1053                                         allows |= SLAP_ALLOW_UPDATE_ANON;
1054
1055                                 } else {
1056                                         Debug( LDAP_DEBUG_ANY, "%s: line %d: "
1057                                                 "unknown feature %s in \"allow <features>\" line\n",
1058                                                 fname, lineno, cargv[i] );
1059
1060                                         return 1;
1061                                 }
1062                         }
1063
1064                         global_allows |= allows;
1065
1066                 /* disallow these features */
1067                 } else if ( strcasecmp( cargv[0], "disallows" ) == 0 ||
1068                         strcasecmp( cargv[0], "disallow" ) == 0 )
1069                 {
1070                         slap_mask_t     disallows = 0; 
1071
1072                         if ( be != NULL ) {
1073                                 Debug( LDAP_DEBUG_ANY,
1074 "%s: line %d: disallow line must appear prior to database definitions\n",
1075                                     fname, lineno, 0 );
1076
1077                         }
1078
1079                         if ( cargc < 2 ) {
1080                                 Debug( LDAP_DEBUG_ANY,
1081             "%s: line %d: missing feature(s) in \"disallow <features>\" line\n",
1082                                     fname, lineno, 0 );
1083
1084                                 return( 1 );
1085                         }
1086
1087                         for( i=1; i < cargc; i++ ) {
1088                                 if( strcasecmp( cargv[i], "bind_anon" ) == 0 ) {
1089                                         disallows |= SLAP_DISALLOW_BIND_ANON;
1090
1091                                 } else if( strcasecmp( cargv[i], "bind_simple" ) == 0 ) {
1092                                         disallows |= SLAP_DISALLOW_BIND_SIMPLE;
1093
1094                                 } else if( strcasecmp( cargv[i], "bind_krbv4" ) == 0 ) {
1095                                         disallows |= SLAP_DISALLOW_BIND_KRBV4;
1096
1097                                 } else if( strcasecmp( cargv[i], "tls_2_anon" ) == 0 ) {
1098                                         disallows |= SLAP_DISALLOW_TLS_2_ANON;
1099
1100                                 } else if( strcasecmp( cargv[i], "tls_authc" ) == 0 ) {
1101                                         disallows |= SLAP_DISALLOW_TLS_AUTHC;
1102
1103                                 } else {
1104                                         Debug( LDAP_DEBUG_ANY,
1105                     "%s: line %d: unknown feature %s in \"disallow <features>\" line\n",
1106                                             fname, lineno, cargv[i] );
1107
1108                                         return 1;
1109                                 }
1110                         }
1111
1112                         global_disallows |= disallows;
1113
1114                 /* require these features */
1115                 } else if ( strcasecmp( cargv[0], "requires" ) == 0 ||
1116                         strcasecmp( cargv[0], "require" ) == 0 )
1117                 {
1118                         slap_mask_t     requires = 0; 
1119
1120                         if ( cargc < 2 ) {
1121                                 Debug( LDAP_DEBUG_ANY,
1122             "%s: line %d: missing feature(s) in \"require <features>\" line\n",
1123                                     fname, lineno, 0 );
1124
1125                                 return( 1 );
1126                         }
1127
1128                         for( i=1; i < cargc; i++ ) {
1129                                 if( strcasecmp( cargv[i], "bind" ) == 0 ) {
1130                                         requires |= SLAP_REQUIRE_BIND;
1131
1132                                 } else if( strcasecmp( cargv[i], "LDAPv3" ) == 0 ) {
1133                                         requires |= SLAP_REQUIRE_LDAP_V3;
1134
1135                                 } else if( strcasecmp( cargv[i], "authc" ) == 0 ) {
1136                                         requires |= SLAP_REQUIRE_AUTHC;
1137
1138                                 } else if( strcasecmp( cargv[i], "SASL" ) == 0 ) {
1139                                         requires |= SLAP_REQUIRE_SASL;
1140
1141                                 } else if( strcasecmp( cargv[i], "strong" ) == 0 ) {
1142                                         requires |= SLAP_REQUIRE_STRONG;
1143
1144                                 } else if( strcasecmp( cargv[i], "none" ) != 0 ) {
1145                                         Debug( LDAP_DEBUG_ANY,
1146                     "%s: line %d: unknown feature %s in \"require <features>\" line\n",
1147                                             fname, lineno, cargv[i] );
1148
1149                                         return( 1 );
1150                                 }
1151                         }
1152
1153                         if ( be == NULL ) {
1154                                 frontendDB->be_requires = requires;
1155                         } else {
1156                                 be->be_requires = requires;
1157                         }
1158
1159                 } else if ( strcasecmp( cargv[0], "security" ) == 0 ) {
1160                         slap_ssf_set_t *set;
1161
1162                         if ( cargc < 2 ) {
1163                                 Debug( LDAP_DEBUG_ANY,
1164             "%s: line %d: missing factor(s) in \"security <factors>\" line\n",
1165                                     fname, lineno, 0 );
1166
1167                                 return( 1 );
1168                         }
1169
1170                         if ( be == NULL ) {
1171                                 set = &frontendDB->be_ssf_set;
1172                         } else {
1173                                 set = &be->be_ssf_set;
1174                         }
1175
1176                         for( i=1; i < cargc; i++ ) {
1177                                 slap_ssf_t      *tgt;
1178                                 char            *src;
1179
1180                                 if ( strncasecmp( cargv[i], "ssf=",
1181                                                 STRLENOF("ssf=") ) == 0 )
1182                                 {
1183                                         tgt = &set->sss_ssf;
1184                                         src = &cargv[i][STRLENOF("ssf=")];
1185
1186                                 } else if ( strncasecmp( cargv[i], "transport=",
1187                                                 STRLENOF("transport=") ) == 0 )
1188                                 {
1189                                         tgt = &set->sss_transport;
1190                                         src = &cargv[i][STRLENOF("transport=")];
1191
1192                                 } else if ( strncasecmp( cargv[i], "tls=",
1193                                                 STRLENOF("tls=") ) == 0 )
1194                                 {
1195                                         tgt = &set->sss_tls;
1196                                         src = &cargv[i][STRLENOF("tls=")];
1197
1198                                 } else if ( strncasecmp( cargv[i], "sasl=",
1199                                                 STRLENOF("sasl=") ) == 0 )
1200                                 {
1201                                         tgt = &set->sss_sasl;
1202                                         src = &cargv[i][STRLENOF("sasl=")];
1203
1204                                 } else if ( strncasecmp( cargv[i], "update_ssf=",
1205                                                 STRLENOF("update_ssf=") ) == 0 )
1206                                 {
1207                                         tgt = &set->sss_update_ssf;
1208                                         src = &cargv[i][STRLENOF("update_ssf=")];
1209
1210                                 } else if ( strncasecmp( cargv[i], "update_transport=",
1211                                                 STRLENOF("update_transport=") ) == 0 )
1212                                 {
1213                                         tgt = &set->sss_update_transport;
1214                                         src = &cargv[i][STRLENOF("update_transport=")];
1215
1216                                 } else if ( strncasecmp( cargv[i], "update_tls=",
1217                                                 STRLENOF("update_tls=") ) == 0 )
1218                                 {
1219                                         tgt = &set->sss_update_tls;
1220                                         src = &cargv[i][STRLENOF("update_tls=")];
1221
1222                                 } else if ( strncasecmp( cargv[i], "update_sasl=",
1223                                                 STRLENOF("update_sasl=") ) == 0 )
1224                                 {
1225                                         tgt = &set->sss_update_sasl;
1226                                         src = &cargv[i][STRLENOF("update_sasl=")];
1227
1228                                 } else if ( strncasecmp( cargv[i], "simple_bind=",
1229                                                 STRLENOF("simple_bind=") ) == 0 )
1230                                 {
1231                                         tgt = &set->sss_simple_bind;
1232                                         src = &cargv[i][STRLENOF("simple_bind=")];
1233
1234                                 } else {
1235                                         Debug( LDAP_DEBUG_ANY,
1236                     "%s: line %d: unknown factor %s in \"security <factors>\" line\n",
1237                                             fname, lineno, cargv[i] );
1238
1239                                         return( 1 );
1240                                 }
1241
1242                                 *tgt = strtol( src, &next, 10 );
1243                                 if ( next == NULL || next[0] != '\0' ) {
1244                                         Debug( LDAP_DEBUG_ANY,
1245                     "%s: line %d: unable to parse factor \"%s\" in \"security <factors>\" line\n",
1246                                             fname, lineno, cargv[i] );
1247
1248                                         return( 1 );
1249                                 }
1250                         }
1251
1252                 /* where to send clients when we don't hold it */
1253                 } else if ( strcasecmp( cargv[0], "referral" ) == 0 ) {
1254                         if ( cargc < 2 ) {
1255                                 Debug( LDAP_DEBUG_ANY,
1256                     "%s: line %d: missing URL in \"referral <URL>\" line\n",
1257                                     fname, lineno, 0 );
1258
1259                                 return( 1 );
1260                         }
1261
1262                         if( validate_global_referral( cargv[1] ) ) {
1263                                 Debug( LDAP_DEBUG_ANY, "%s: line %d: "
1264                                         "invalid URL (%s) in \"referral\" line.\n",
1265                                     fname, lineno, cargv[1] );
1266                                 return 1;
1267                         }
1268
1269                         vals[0].bv_val = cargv[1];
1270                         vals[0].bv_len = strlen( vals[0].bv_val );
1271                         if( value_add( &default_referral, vals ) )
1272                                 return LDAP_OTHER;
1273
1274                 /* start of a new database definition */
1275                 } else if ( strcasecmp( cargv[0], "debug" ) == 0 ) {
1276                         int level;
1277                         if ( cargc < 3 ) {
1278                                 Debug( LDAP_DEBUG_ANY,
1279                                         "%s: line %d: Error in debug directive, \"debug subsys level\"\n",
1280                                         fname, lineno, 0 );
1281                                 return( 1 );
1282                         }
1283                         level = strtol( cargv[2], &next, 10 );
1284                         if ( next == NULL || next[0] != '\0' ){
1285                                 Debug( LDAP_DEBUG_ANY,
1286                                            "%s: line %d: unable to parse level \"%s\" in debug directive, "
1287                                            "\"debug <subsys> <level>\"\n", fname, lineno , cargv[2] );
1288                                 return( 1 );
1289                         }
1290
1291                         if ( level <= 0 ) level = lutil_mnem2level( cargv[2] );
1292                         lutil_set_debug_level( cargv[1], level );
1293                 /* specify an Object Identifier macro */
1294                 } else if ( strcasecmp( cargv[0], "objectidentifier" ) == 0 ) {
1295                         rc = parse_oidm( fname, lineno, cargc, cargv );
1296                         if( rc ) return rc;
1297
1298                 /* specify an objectclass */
1299                 } else if ( strcasecmp( cargv[0], "objectclass" ) == 0 ) {
1300                         if ( cargc < 2 ) {
1301                                 Debug( LDAP_DEBUG_ANY,
1302                                        "%s: line %d: illegal objectclass format.\n",
1303                                        fname, lineno, 0 );
1304                                 return( 1 );
1305
1306                         } else if ( *cargv[1] == '('  /*')'*/) {
1307                                 char * p;
1308                                 p = strchr(saveline,'(' /*')'*/);
1309                                 rc = parse_oc( fname, lineno, p, cargv );
1310                                 if( rc ) return rc;
1311
1312                         } else {
1313                                 Debug( LDAP_DEBUG_ANY,
1314                                        "%s: line %d: old objectclass format not supported.\n",
1315                                        fname, lineno, 0 );
1316                         }
1317
1318                 } else if ( strcasecmp( cargv[0], "ditcontentrule" ) == 0 ) {
1319                         char * p;
1320                         p = strchr(saveline,'(' /*')'*/);
1321                         rc = parse_cr( fname, lineno, p, cargv );
1322                         if( rc ) return rc;
1323
1324                 /* specify an attribute type */
1325                 } else if (( strcasecmp( cargv[0], "attributetype" ) == 0 )
1326                         || ( strcasecmp( cargv[0], "attribute" ) == 0 ))
1327                 {
1328                         if ( cargc < 2 ) {
1329                                 Debug( LDAP_DEBUG_ANY, "%s: line %d: "
1330                                         "illegal attribute type format.\n",
1331                                         fname, lineno, 0 );
1332                                 return( 1 );
1333
1334                         } else if ( *cargv[1] == '(' /*')'*/) {
1335                                 char * p;
1336                                 p = strchr(saveline,'(' /*')'*/);
1337                                 rc = parse_at( fname, lineno, p, cargv );
1338                                 if( rc ) return rc;
1339
1340                         } else {
1341                                 Debug( LDAP_DEBUG_ANY,
1342     "%s: line %d: old attribute type format not supported.\n",
1343                                     fname, lineno, 0 );
1344
1345                         }
1346
1347                 /* define attribute option(s) */
1348                 } else if ( strcasecmp( cargv[0], "attributeoptions" ) == 0 ) {
1349                         ad_define_option( NULL, NULL, 0 );
1350                         for ( i = 1; i < cargc; i++ )
1351                                 if ( ad_define_option( cargv[i], fname, lineno ) != 0 )
1352                                         return 1;
1353
1354                 /* turn on/off schema checking */
1355                 } else if ( strcasecmp( cargv[0], "schemacheck" ) == 0 ) {
1356                         if ( cargc < 2 ) {
1357                                 Debug( LDAP_DEBUG_ANY,
1358     "%s: line %d: missing on|off in \"schemacheck <on|off>\" line\n",
1359                                     fname, lineno, 0 );
1360
1361                                 return( 1 );
1362                         }
1363                         if ( strcasecmp( cargv[1], "off" ) == 0 ) {
1364                                 Debug( LDAP_DEBUG_ANY,
1365                                         "%s: line %d: schema checking disabled! your mileage may vary!\n",
1366                                     fname, lineno, 0 );
1367                                 global_schemacheck = 0;
1368                         } else {
1369                                 global_schemacheck = 1;
1370                         }
1371
1372                 /* specify access control info */
1373                 } else if ( strcasecmp( cargv[0], "access" ) == 0 ) {
1374                         parse_acl( be, fname, lineno, cargc, cargv );
1375
1376                 /* debug level to log things to syslog */
1377                 } else if ( strcasecmp( cargv[0], "loglevel" ) == 0 ) {
1378                         if ( cargc < 2 ) {
1379                                 Debug( LDAP_DEBUG_ANY,
1380                     "%s: line %d: missing level(s) in \"loglevel <level> [...]\" line\n",
1381                                     fname, lineno, 0 );
1382
1383                                 return( 1 );
1384                         }
1385
1386                         ldap_syslog = 0;
1387
1388                         for( i=1; i < cargc; i++ ) {
1389                                 int     level;
1390
1391                                 if ( isdigit( cargv[i][0] ) ) {
1392                                         level = strtol( cargv[i], &next, 10 );
1393                                         if ( next == NULL || next[0] != '\0' ) {
1394                                                 Debug( LDAP_DEBUG_ANY,
1395                                                         "%s: line %d: unable to parse level \"%s\" "
1396                                                         "in \"loglevel <level> [...]\" line.\n",
1397                                                         fname, lineno , cargv[i] );
1398                                                 return( 1 );
1399                                         }
1400                                         
1401                                 } else {
1402                                         static struct {
1403                                                 int     i;
1404                                                 char    *s;
1405                                         } int_2_level[] = {
1406                                                 { LDAP_DEBUG_TRACE,     "Trace"         },
1407                                                 { LDAP_DEBUG_PACKETS,   "Packets"       },
1408                                                 { LDAP_DEBUG_ARGS,      "Args"          },
1409                                                 { LDAP_DEBUG_CONNS,     "Conns"         },
1410                                                 { LDAP_DEBUG_BER,       "BER"           },
1411                                                 { LDAP_DEBUG_FILTER,    "Filter"        },
1412                                                 { LDAP_DEBUG_CONFIG,    "Config"        },
1413                                                 { LDAP_DEBUG_ACL,       "ACL"           },
1414                                                 { LDAP_DEBUG_STATS,     "Stats"         },
1415                                                 { LDAP_DEBUG_STATS2,    "Stats2"        },
1416                                                 { LDAP_DEBUG_SHELL,     "Shell"         },
1417                                                 { LDAP_DEBUG_PARSE,     "Parse"         },
1418                                                 { LDAP_DEBUG_CACHE,     "Cache"         },
1419                                                 { LDAP_DEBUG_INDEX,     "Index"         },
1420                                                 { -1,                   "Any"           },
1421                                                 { 0,                    NULL            }
1422                                         };
1423                                         int     j;
1424
1425                                         for ( j = 0; int_2_level[j].s; j++ ) {
1426                                                 if ( strcasecmp( cargv[i], int_2_level[j].s ) == 0 ) {
1427                                                         level = int_2_level[j].i;
1428                                                         break;
1429                                                 }
1430                                         }
1431
1432                                         if ( int_2_level[j].s == NULL ) {
1433                                                 Debug( LDAP_DEBUG_ANY,
1434                                                         "%s: line %d: unknown level \"%s\" "
1435                                                         "in \"loglevel <level> [...]\" line.\n",
1436                                                         fname, lineno , cargv[i] );
1437                                                 return( 1 );
1438                                         }
1439                                 }
1440
1441                                 ldap_syslog |= level;
1442                         }
1443
1444                 /* list of sync replication information in this backend (slave only) */
1445                 } else if ( strcasecmp( cargv[0], "syncrepl" ) == 0 ) {
1446
1447                         if ( be == NULL ) {
1448                                 Debug( LDAP_DEBUG_ANY,
1449                                             "%s: line %d: syncrepl line must appear inside "
1450                                             "a database definition.\n", fname, lineno, 0);
1451                                 return 1;
1452
1453                         } else if ( SLAP_SHADOW( be )) {
1454                                 Debug( LDAP_DEBUG_ANY,
1455                                         "%s: line %d: syncrepl: database already shadowed.\n",
1456                                         fname, lineno, 0);
1457                                 return 1;
1458
1459                         } else if ( add_syncrepl( be, cargv, cargc )) {
1460                                 return 1;
1461                         }
1462
1463                         SLAP_DBFLAGS(be) |= ( SLAP_DBFLAG_SHADOW | SLAP_DBFLAG_SYNC_SHADOW );
1464
1465                 /* list of replicas of the data in this backend (master only) */
1466                 } else if ( strcasecmp( cargv[0], "replica" ) == 0 ) {
1467                         if ( cargc < 2 ) {
1468                                 Debug( LDAP_DEBUG_ANY,
1469             "%s: line %d: missing host or uri in \"replica <host[:port]>\" line\n",
1470                                     fname, lineno, 0 );
1471
1472                                 return( 1 );
1473                         }
1474                         if ( be == NULL ) {
1475                                 Debug( LDAP_DEBUG_ANY,
1476 "%s: line %d: replica line must appear inside a database definition\n",
1477                                     fname, lineno, 0 );
1478                                 return 1;
1479
1480                         } else {
1481                                 int nr = -1;
1482
1483                                 for ( i = 1; i < cargc; i++ ) {
1484                                         if ( strncasecmp( cargv[i], "host=", 5 )
1485                                             == 0 ) {
1486                                                 nr = add_replica_info( be, 
1487                                                         cargv[i] + 5 );
1488                                                 break;
1489                                         } else if (strncasecmp( cargv[i], "uri=", 4 )
1490                                             == 0 ) {
1491                                             if ( ldap_url_parse( cargv[ i ] + 4, &ludp )
1492                                                 != LDAP_SUCCESS ) {
1493                                                         Debug( LDAP_DEBUG_ANY,
1494                                                         "%s: line %d: replica line contains invalid "
1495                                                         "uri definition.\n", fname, lineno, 0);
1496                                                         return 1;
1497                                                 }
1498                                                 if (ludp->lud_host == NULL ) {
1499                                                         Debug( LDAP_DEBUG_ANY,
1500                                                         "%s: line %d: replica line contains invalid "
1501                                                         "uri definition - missing hostname.\n", fname, lineno, 0);
1502                                                         return 1;
1503                                                 }
1504                                         replicahost = ch_malloc( strlen( cargv[ i ] ) );
1505                                                 if ( replicahost == NULL ) {
1506                                                         Debug( LDAP_DEBUG_ANY, 
1507                                                         "out of memory in read_config\n", 0, 0, 0 );
1508                                                         ldap_free_urldesc( ludp );                              
1509                                                         exit( EXIT_FAILURE );
1510                                                 }
1511                                                 sprintf(replicahost, "%s:%d", 
1512                                                         ludp->lud_host, ludp->lud_port);
1513                                                 nr = add_replica_info( be, replicahost );
1514                                                 ldap_free_urldesc( ludp );                              
1515                                                 ch_free(replicahost);
1516                                                 break;
1517                                         }
1518                                 }
1519                                 if ( i == cargc ) {
1520                                         Debug( LDAP_DEBUG_ANY,
1521                     "%s: line %d: missing host or uri in \"replica\" line\n",
1522                                             fname, lineno, 0 );
1523                                         return 1;
1524
1525                                 } else if ( nr == -1 ) {
1526                                         Debug( LDAP_DEBUG_ANY,
1527                 "%s: line %d: unable to add replica \"%s\"\n",
1528                                                 fname, lineno, cargv[i] + 5 );
1529                                         return 1;
1530                                 } else {
1531                                         for ( i = 1; i < cargc; i++ ) {
1532                                                 if ( strncasecmp( cargv[i], "suffix=", 7 ) == 0 ) {
1533
1534                                                         switch ( add_replica_suffix( be, nr, cargv[i] + 7 ) ) {
1535                                                         case 1:
1536                                                                 Debug( LDAP_DEBUG_ANY,
1537                                                                                 "%s: line %d: suffix \"%s\" in \"replica\" line is not valid for backend (ignored)\n",
1538                                                                                 fname, lineno, cargv[i] + 7 );
1539                                                                 break;
1540
1541                                                         case 2:
1542                                                                 Debug( LDAP_DEBUG_ANY,
1543                                                                                  "%s: line %d: unable to normalize suffix in \"replica\" line (ignored)\n",
1544                                                                                  fname, lineno, 0 );
1545                                                                 break;
1546                                                         }
1547
1548                                                 } else if ( strncasecmp( cargv[i], "attr", 4 ) == 0 ) {
1549                                                         int exclude = 0;
1550                                                         char *arg = cargv[i] + 4;
1551
1552                                                         if ( arg[0] == '!' ) {
1553                                                                 arg++;
1554                                                                 exclude = 1;
1555                                                         }
1556
1557                                                         if ( arg[0] != '=' ) {
1558                                                                 continue;
1559                                                         }
1560
1561                                                         if ( add_replica_attrs( be, nr, arg + 1, exclude ) ) {
1562                                                                 Debug( LDAP_DEBUG_ANY,
1563                                                                                 "%s: line %d: attribute \"%s\" in \"replica\" line is unknown\n",
1564                                                                                 fname, lineno, arg + 1 );
1565                                                                 return( 1 );
1566                                                         }
1567                                                 }
1568                                         }
1569                                 }
1570                         }
1571
1572                 } else if ( strcasecmp( cargv[0], "replicationInterval" ) == 0 ) {
1573                         /* ignore */
1574
1575                 /* dn of slave entity allowed to write to replica */
1576                 } else if ( strcasecmp( cargv[0], "updatedn" ) == 0 ) {
1577                         if ( cargc < 2 ) {
1578                                 Debug( LDAP_DEBUG_ANY,
1579                     "%s: line %d: missing dn in \"updatedn <dn>\" line\n",
1580                                     fname, lineno, 0 );
1581
1582                                 return( 1 );
1583                         }
1584                         if ( be == NULL ) {
1585                                 Debug( LDAP_DEBUG_ANY,
1586 "%s: line %d: updatedn line must appear inside a database definition\n",
1587                                     fname, lineno, 0 );
1588                                 return 1;
1589
1590                         } else if ( SLAP_SHADOW(be) ) {
1591                                 Debug( LDAP_DEBUG_ANY,
1592                                         "%s: line %d: updatedn: database already shadowed.\n",
1593                                         fname, lineno, 0);
1594                                 return 1;
1595
1596                         } else {
1597                                 struct berval dn;
1598
1599                                 if ( load_ucdata( NULL ) < 0 ) return 1;
1600
1601                                 dn.bv_val = cargv[1];
1602                                 dn.bv_len = strlen( cargv[1] );
1603
1604                                 rc = dnNormalize( 0, NULL, NULL, &dn, &be->be_update_ndn, NULL );
1605                                 if( rc != LDAP_SUCCESS ) {
1606                                         Debug( LDAP_DEBUG_ANY,
1607                                                 "%s: line %d: updatedn DN is invalid\n",
1608                                             fname, lineno, 0 );
1609                                         return 1;
1610                                 }
1611
1612                         }
1613                         SLAP_DBFLAGS(be) |= ( SLAP_DBFLAG_SHADOW | SLAP_DBFLAG_SLURP_SHADOW );
1614
1615                 } else if ( strcasecmp( cargv[0], "updateref" ) == 0 ) {
1616                         if ( cargc < 2 ) {
1617                                 Debug( LDAP_DEBUG_ANY, "%s: line %d: "
1618                                         "missing url in \"updateref <ldapurl>\" line\n",
1619                                     fname, lineno, 0 );
1620
1621                                 return( 1 );
1622                         }
1623                         if ( be == NULL ) {
1624                                 Debug( LDAP_DEBUG_ANY, "%s: line %d: updateref"
1625                                         " line must appear inside a database definition\n",
1626                                         fname, lineno, 0 );
1627                                 return 1;
1628
1629                         } else if ( !SLAP_SHADOW(be) ) {
1630                                 Debug( LDAP_DEBUG_ANY, "%s: line %d: "
1631                                         "updateref line must after syncrepl or updatedn.\n",
1632                                     fname, lineno, 0 );
1633                                 return 1;
1634                         }
1635
1636                         if( validate_global_referral( cargv[1] ) ) {
1637                                 Debug( LDAP_DEBUG_ANY, "%s: line %d: "
1638                                         "invalid URL (%s) in \"updateref\" line.\n",
1639                                     fname, lineno, cargv[1] );
1640                                 return 1;
1641                         }
1642
1643                         vals[0].bv_val = cargv[1];
1644                         vals[0].bv_len = strlen( vals[0].bv_val );
1645                         if( value_add( &be->be_update_refs, vals ) ) {
1646                                 return LDAP_OTHER;
1647                         }
1648
1649                 /* replication log file to which changes are appended */
1650                 } else if ( strcasecmp( cargv[0], "replogfile" ) == 0 ) {
1651                         if ( cargc < 2 ) {
1652                                 Debug( LDAP_DEBUG_ANY,
1653             "%s: line %d: missing filename in \"replogfile <filename>\" line\n",
1654                                     fname, lineno, 0 );
1655
1656                                 return( 1 );
1657                         }
1658                         if ( be ) {
1659                                 be->be_replogfile = ch_strdup( cargv[1] );
1660                         } else {
1661                                 replogfile = ch_strdup( cargv[1] );
1662                         }
1663
1664                 /* file from which to read additional rootdse attrs */
1665                 } else if ( strcasecmp( cargv[0], "rootDSE" ) == 0) {
1666                         if ( cargc < 2 ) {
1667                                 Debug( LDAP_DEBUG_ANY, "%s: line %d: "
1668                                         "missing filename in \"rootDSE <filename>\" line.\n",
1669                                     fname, lineno, 0 );
1670                                 return 1;
1671                         }
1672
1673                         if( read_root_dse_file( cargv[1] ) ) {
1674                                 Debug( LDAP_DEBUG_ANY, "%s: line %d: "
1675                                         "could not read \"rootDSE <filename>\" line\n",
1676                                     fname, lineno, 0 );
1677                                 return 1;
1678                         }
1679
1680                 /* maintain lastmodified{by,time} attributes */
1681                 } else if ( strcasecmp( cargv[0], "lastmod" ) == 0 ) {
1682                         if ( cargc < 2 ) {
1683                                 Debug( LDAP_DEBUG_ANY,
1684             "%s: line %d: missing on|off in \"lastmod <on|off>\" line\n",
1685                                     fname, lineno, 0 );
1686
1687                                 return( 1 );
1688                         }
1689
1690                         if ( be == NULL ) {
1691                                 Debug( LDAP_DEBUG_ANY, "%s: line %d: lastmod"
1692                                         " line must appear inside a database definition\n",
1693                                         fname, lineno, 0 );
1694                                 return 1;
1695
1696                         } else if ( SLAP_NOLASTMODCMD(be) ) {
1697                                 Debug( LDAP_DEBUG_ANY, "%s: line %d: lastmod"
1698                                         " not available for %s databases\n",
1699                                         fname, lineno, be->bd_info->bi_type );
1700                                 return 1;
1701                         }
1702
1703                         if ( strcasecmp( cargv[1], "on" ) == 0 ) {
1704                                 SLAP_DBFLAGS(be) &= ~SLAP_DBFLAG_NOLASTMOD;
1705                         } else {
1706                                 SLAP_DBFLAGS(be) |= SLAP_DBFLAG_NOLASTMOD;
1707                         }
1708
1709 #ifdef SIGHUP
1710                 /* turn on/off gentle SIGHUP handling */
1711                 } else if ( strcasecmp( cargv[0], "gentlehup" ) == 0 ) {
1712                         if ( cargc < 2 ) {
1713                                 Debug( LDAP_DEBUG_ANY,
1714     "%s: line %d: missing on|off in \"gentlehup <on|off>\" line\n",
1715                                     fname, lineno, 0 );
1716                                 return( 1 );
1717                         }
1718                         if ( strcasecmp( cargv[1], "off" ) == 0 ) {
1719                                 global_gentlehup = 0;
1720                         } else {
1721                                 global_gentlehup = 1;
1722                         }
1723 #endif
1724
1725                 /* set idle timeout value */
1726                 } else if ( strcasecmp( cargv[0], "idletimeout" ) == 0 ) {
1727                         int i;
1728                         if ( cargc < 2 ) {
1729                                 Debug( LDAP_DEBUG_ANY,
1730             "%s: line %d: missing timeout value in \"idletimeout <seconds>\" line\n",
1731                                     fname, lineno, 0 );
1732
1733                                 return( 1 );
1734                         }
1735
1736                         i = atoi( cargv[1] );
1737
1738                         if( i < 0 ) {
1739                                 Debug( LDAP_DEBUG_ANY,
1740             "%s: line %d: timeout value (%d) invalid \"idletimeout <seconds>\" line\n",
1741                                     fname, lineno, i );
1742
1743                                 return( 1 );
1744                         }
1745
1746                         global_idletimeout = i;
1747
1748                 /* include another config file */
1749                 } else if ( strcasecmp( cargv[0], "include" ) == 0 ) {
1750                         if ( cargc < 2 ) {
1751                                 Debug( LDAP_DEBUG_ANY,
1752     "%s: line %d: missing filename in \"include <filename>\" line\n",
1753                                     fname, lineno, 0 );
1754
1755                                 return( 1 );
1756                         }
1757                         savefname = ch_strdup( cargv[1] );
1758                         savelineno = lineno;
1759
1760                         if ( read_config( savefname, depth+1 ) != 0 ) {
1761                                 return( 1 );
1762                         }
1763
1764                         free( savefname );
1765                         lineno = savelineno - 1;
1766
1767                 /* location of kerberos srvtab file */
1768                 } else if ( strcasecmp( cargv[0], "srvtab" ) == 0 ) {
1769                         if ( cargc < 2 ) {
1770                                 Debug( LDAP_DEBUG_ANY,
1771             "%s: line %d: missing filename in \"srvtab <filename>\" line\n",
1772                                     fname, lineno, 0 );
1773
1774                                 return( 1 );
1775                         }
1776                         ldap_srvtab = ch_strdup( cargv[1] );
1777
1778 #ifdef SLAPD_MODULES
1779                 } else if (strcasecmp( cargv[0], "moduleload") == 0 ) {
1780                    if ( cargc < 2 ) {
1781                       Debug( LDAP_DEBUG_ANY,
1782                              "%s: line %d: missing filename in \"moduleload <filename>\" line\n",
1783                              fname, lineno, 0 );
1784
1785                       exit( EXIT_FAILURE );
1786                    }
1787                    if (module_load(cargv[1], cargc - 2, (cargc > 2) ? cargv + 2 : NULL)) {
1788                       Debug( LDAP_DEBUG_ANY,
1789                              "%s: line %d: failed to load or initialize module %s\n",
1790                              fname, lineno, cargv[1]);
1791
1792                       exit( EXIT_FAILURE );
1793                    }
1794                 } else if (strcasecmp( cargv[0], "modulepath") == 0 ) {
1795                    if ( cargc != 2 ) {
1796                       Debug( LDAP_DEBUG_ANY,
1797                              "%s: line %d: missing path in \"modulepath <path>\" line\n",
1798                              fname, lineno, 0 );
1799
1800                       exit( EXIT_FAILURE );
1801                    }
1802                    if (module_path( cargv[1] )) {
1803                            Debug( LDAP_DEBUG_ANY,
1804                                   "%s: line %d: failed to set module search path to %s\n",
1805                                   fname, lineno, cargv[1]);
1806
1807                       exit( EXIT_FAILURE );
1808                    }
1809                    
1810 #endif /*SLAPD_MODULES*/
1811
1812 #ifdef HAVE_TLS
1813                 } else if ( !strcasecmp( cargv[0], "TLSRandFile" ) ) {
1814                         rc = ldap_pvt_tls_set_option( NULL,
1815                                                       LDAP_OPT_X_TLS_RANDOM_FILE,
1816                                                       cargv[1] );
1817                         if ( rc )
1818                                 return rc;
1819
1820                 } else if ( !strcasecmp( cargv[0], "TLSCipherSuite" ) ) {
1821                         rc = ldap_pvt_tls_set_option( NULL,
1822                                                       LDAP_OPT_X_TLS_CIPHER_SUITE,
1823                                                       cargv[1] );
1824                         if ( rc )
1825                                 return rc;
1826
1827                 } else if ( !strcasecmp( cargv[0], "TLSCertificateFile" ) ) {
1828                         rc = ldap_pvt_tls_set_option( NULL,
1829                                                       LDAP_OPT_X_TLS_CERTFILE,
1830                                                       cargv[1] );
1831                         if ( rc )
1832                                 return rc;
1833
1834                 } else if ( !strcasecmp( cargv[0], "TLSCertificateKeyFile" ) ) {
1835                         rc = ldap_pvt_tls_set_option( NULL,
1836                                                       LDAP_OPT_X_TLS_KEYFILE,
1837                                                       cargv[1] );
1838                         if ( rc )
1839                                 return rc;
1840
1841                 } else if ( !strcasecmp( cargv[0], "TLSCACertificatePath" ) ) {
1842                         rc = ldap_pvt_tls_set_option( NULL,
1843                                                       LDAP_OPT_X_TLS_CACERTDIR,
1844                                                       cargv[1] );
1845                         if ( rc )
1846                                 return rc;
1847
1848                 } else if ( !strcasecmp( cargv[0], "TLSCACertificateFile" ) ) {
1849                         rc = ldap_pvt_tls_set_option( NULL,
1850                                                       LDAP_OPT_X_TLS_CACERTFILE,
1851                                                       cargv[1] );
1852                         if ( rc )
1853                                 return rc;
1854                 } else if ( !strcasecmp( cargv[0], "TLSVerifyClient" ) ) {
1855                         if ( isdigit( (unsigned char) cargv[1][0] ) ) {
1856                                 i = atoi(cargv[1]);
1857                                 rc = ldap_pvt_tls_set_option( NULL,
1858                                                       LDAP_OPT_X_TLS_REQUIRE_CERT,
1859                                                       &i );
1860                         } else {
1861                                 rc = ldap_int_tls_config( NULL,
1862                                                       LDAP_OPT_X_TLS_REQUIRE_CERT,
1863                                                       cargv[1] );
1864                         }
1865
1866                         if ( rc )
1867                                 return rc;
1868
1869 #endif
1870
1871                 } else if ( !strcasecmp( cargv[0], "reverse-lookup" ) ) {
1872 #ifdef SLAPD_RLOOKUPS
1873                         if ( cargc < 2 ) {
1874                                 Debug( LDAP_DEBUG_ANY,
1875 "%s: line %d: reverse-lookup: missing \"on\" or \"off\"\n",
1876                                         fname, lineno, 0 );
1877                                 return( 1 );
1878                         }
1879
1880                         if ( !strcasecmp( cargv[1], "on" ) ) {
1881                                 use_reverse_lookup = 1;
1882                         } else if ( !strcasecmp( cargv[1], "off" ) ) {
1883                                 use_reverse_lookup = 0;
1884                         } else {
1885                                 Debug( LDAP_DEBUG_ANY,
1886 "%s: line %d: reverse-lookup: must be \"on\" (default) or \"off\"\n",
1887                                         fname, lineno, 0 );
1888                                 return( 1 );
1889                         }
1890
1891 #else /* !SLAPD_RLOOKUPS */
1892                         Debug( LDAP_DEBUG_ANY,
1893 "%s: line %d: reverse lookups are not configured (ignored).\n",
1894                                 fname, lineno, 0 );
1895 #endif /* !SLAPD_RLOOKUPS */
1896
1897                 /* Netscape plugins */
1898                 } else if ( strcasecmp( cargv[0], "plugin" ) == 0 ) {
1899 #if defined( LDAP_SLAPI )
1900
1901 #ifdef notdef /* allow global plugins, too */
1902                         /*
1903                          * a "plugin" line must be inside a database
1904                          * definition, since we implement pre-,post- 
1905                          * and extended operation plugins
1906                          */
1907                         if ( be == NULL ) {
1908                                 Debug( LDAP_DEBUG_ANY, "%s: line %d: plugin "
1909                                     "line must appear inside a database "
1910                                     "definition\n", fname, lineno, 0 );
1911                                 return( 1 );
1912                         }
1913 #endif /* notdef */
1914
1915                         if ( slapi_int_read_config( be, fname, lineno, cargc, cargv ) 
1916                                         != LDAP_SUCCESS )
1917                         {
1918                                 Debug( LDAP_DEBUG_ANY, "%s: line %d: SLAPI "
1919                                                 "config read failed.\n", fname, lineno, 0 );
1920                                 return( 1 );
1921                         }
1922                         slapi_plugins_used++;
1923
1924 #else /* !defined( LDAP_SLAPI ) */
1925                         Debug( LDAP_DEBUG_ANY, "%s: line %d: SLAPI "
1926                             "not supported.\n", fname, lineno, 0 );
1927                         return( 1 );
1928                         
1929 #endif /* !defined( LDAP_SLAPI ) */
1930
1931                 /* Netscape plugins */
1932                 } else if ( strcasecmp( cargv[0], "pluginlog" ) == 0 ) {
1933 #if defined( LDAP_SLAPI )
1934                         if ( cargc < 2 ) {
1935                                 Debug( LDAP_DEBUG_ANY, 
1936                                         "%s: line %d: missing file name "
1937                                         "in pluginlog <filename> line.\n",
1938                                         fname, lineno, 0 );
1939                                 return( 1 );
1940                         }
1941
1942                         if ( slapi_log_file != NULL ) {
1943                                 ch_free( slapi_log_file );
1944                         }
1945
1946                         slapi_log_file = ch_strdup( cargv[1] );
1947 #endif /* !defined( LDAP_SLAPI ) */
1948
1949                 /* pass anything else to the current backend info/db config routine */
1950                 } else {
1951                         if ( bi != NULL ) {
1952                                 if ( bi->bi_config ) {
1953                                         rc = (*bi->bi_config)( bi, fname, lineno, cargc, cargv );
1954
1955                                         switch ( rc ) {
1956                                         case 0:
1957                                                 break;
1958
1959                                         case SLAP_CONF_UNKNOWN:
1960                                                 Debug( LDAP_DEBUG_ANY,
1961 "%s: line %d: unknown directive \"%s\" inside backend info definition (ignored)\n",
1962                                                         fname, lineno, cargv[0] );
1963                                                 break;
1964
1965                                         default:
1966                                                 return 1;
1967                                         }
1968                                 }
1969
1970                         } else if ( be != NULL ) {
1971                                 if ( be->be_config ) {
1972                                         rc = (*be->be_config)( be, fname, lineno, cargc, cargv );
1973
1974                                         switch ( rc ) {
1975                                         case 0:
1976                                                 break;
1977
1978                                         case SLAP_CONF_UNKNOWN:
1979                                                 Debug( LDAP_DEBUG_ANY,
1980 "%s: line %d: unknown directive \"%s\" inside backend database definition (ignored)\n",
1981                                                         fname, lineno, cargv[0] );
1982                                                 break;
1983
1984                                         default:
1985                                                 return 1;
1986                                         }
1987                                 }
1988
1989                         } else {
1990                                 if ( frontendDB->be_config ) {
1991                                         rc = (*frontendDB->be_config)( frontendDB, fname, lineno, cargc, cargv );
1992
1993                                         switch ( rc ) {
1994                                         case 0:
1995                                                 break;
1996
1997                                         case SLAP_CONF_UNKNOWN:
1998                                                 Debug( LDAP_DEBUG_ANY,
1999 "%s: line %d: unknown directive \"%s\" inside global database definition (ignored)\n",
2000                                                         fname, lineno, cargv[0] );
2001                                                 break;
2002
2003                                         default:
2004                                                 return 1;
2005                                         }
2006                                 }
2007                         }
2008                 }
2009                 free( saveline );
2010         }
2011         fclose( fp );
2012
2013         if ( depth == 0 ) ch_free( cargv );
2014
2015         if ( BER_BVISNULL( &frontendDB->be_schemadn ) ) {
2016                 ber_str2bv( SLAPD_SCHEMA_DN, sizeof(SLAPD_SCHEMA_DN)-1, 1,
2017                         &frontendDB->be_schemadn );
2018                 dnNormalize( 0, NULL, NULL, &frontendDB->be_schemadn, &frontendDB->be_schemandn, NULL );
2019         }
2020
2021         if ( load_ucdata( NULL ) < 0 ) return 1;
2022         return( 0 );
2023 }
2024
2025 static int
2026 fp_parse_line(
2027     int         lineno,
2028     char        *line
2029 )
2030 {
2031         char *  token;
2032         char *  logline;
2033         char    logbuf[sizeof("pseudorootpw ***")];
2034
2035         cargc = 0;
2036         token = strtok_quote( line, " \t" );
2037
2038         logline = line;
2039
2040         if ( token && ( strcasecmp( token, "rootpw" ) == 0 ||
2041                 strcasecmp( token, "replica" ) == 0 ||          /* contains "credentials" */
2042                 strcasecmp( token, "bindpw" ) == 0 ||           /* used in back-ldap */
2043                 strcasecmp( token, "pseudorootpw" ) == 0 ||     /* used in back-meta */
2044                 strcasecmp( token, "dbpasswd" ) == 0 ) )        /* used in back-sql */
2045         {
2046                 snprintf( logline = logbuf, sizeof logbuf, "%s ***", token );
2047         }
2048
2049         if ( strtok_quote_ptr ) {
2050                 *strtok_quote_ptr = ' ';
2051         }
2052
2053         Debug( LDAP_DEBUG_CONFIG, "line %d (%s)\n", lineno, logline, 0 );
2054
2055         if ( strtok_quote_ptr ) {
2056                 *strtok_quote_ptr = '\0';
2057         }
2058
2059         for ( ; token != NULL; token = strtok_quote( NULL, " \t" ) ) {
2060                 if ( cargc == cargv_size - 1 ) {
2061                         char **tmp;
2062                         tmp = ch_realloc( cargv, (cargv_size + ARGS_STEP) *
2063                                             sizeof(*cargv) );
2064                         if ( tmp == NULL ) {
2065                                 Debug( LDAP_DEBUG_ANY, 
2066                                                 "line %d: out of memory\n", 
2067                                                 lineno, 0, 0 );
2068                                 return -1;
2069                         }
2070                         cargv = tmp;
2071                         cargv_size += ARGS_STEP;
2072                 }
2073                 cargv[cargc++] = token;
2074         }
2075         cargv[cargc] = NULL;
2076         return 0;
2077 }
2078
2079 static char *
2080 strtok_quote( char *line, char *sep )
2081 {
2082         int             inquote;
2083         char            *tmp;
2084         static char     *next;
2085
2086         strtok_quote_ptr = NULL;
2087         if ( line != NULL ) {
2088                 next = line;
2089         }
2090         while ( *next && strchr( sep, *next ) ) {
2091                 next++;
2092         }
2093
2094         if ( *next == '\0' ) {
2095                 next = NULL;
2096                 return( NULL );
2097         }
2098         tmp = next;
2099
2100         for ( inquote = 0; *next; ) {
2101                 switch ( *next ) {
2102                 case '"':
2103                         if ( inquote ) {
2104                                 inquote = 0;
2105                         } else {
2106                                 inquote = 1;
2107                         }
2108                         AC_MEMCPY( next, next + 1, strlen( next + 1 ) + 1 );
2109                         break;
2110
2111                 case '\\':
2112                         if ( next[1] )
2113                                 AC_MEMCPY( next,
2114                                             next + 1, strlen( next + 1 ) + 1 );
2115                         next++;         /* dont parse the escaped character */
2116                         break;
2117
2118                 default:
2119                         if ( ! inquote ) {
2120                                 if ( strchr( sep, *next ) != NULL ) {
2121                                         strtok_quote_ptr = next;
2122                                         *next++ = '\0';
2123                                         return( tmp );
2124                                 }
2125                         }
2126                         next++;
2127                         break;
2128                 }
2129         }
2130
2131         return( tmp );
2132 }
2133
2134 static char     buf[BUFSIZ];
2135 static char     *line;
2136 static size_t lmax, lcur;
2137
2138 #define CATLINE( buf ) \
2139         do { \
2140                 size_t len = strlen( buf ); \
2141                 while ( lcur + len + 1 > lmax ) { \
2142                         lmax += BUFSIZ; \
2143                         line = (char *) ch_realloc( line, lmax ); \
2144                 } \
2145                 strcpy( line + lcur, buf ); \
2146                 lcur += len; \
2147         } while( 0 )
2148
2149 static char *
2150 fp_getline( FILE *fp, int *lineno )
2151 {
2152         char            *p;
2153
2154         lcur = 0;
2155         CATLINE( buf );
2156         (*lineno)++;
2157
2158         /* hack attack - keeps us from having to keep a stack of bufs... */
2159         if ( strncasecmp( line, "include", 7 ) == 0 ) {
2160                 buf[0] = '\0';
2161                 return( line );
2162         }
2163
2164         while ( fgets( buf, sizeof(buf), fp ) != NULL ) {
2165                 /* trim off \r\n or \n */
2166                 if ( (p = strchr( buf, '\n' )) != NULL ) {
2167                         if( p > buf && p[-1] == '\r' ) --p;
2168                         *p = '\0';
2169                 }
2170                 
2171                 /* trim off trailing \ and append the next line */
2172                 if ( line[ 0 ] != '\0' 
2173                                 && (p = line + strlen( line ) - 1)[ 0 ] == '\\'
2174                                 && p[ -1 ] != '\\' ) {
2175                         p[ 0 ] = '\0';
2176                         lcur--;
2177
2178                 } else {
2179                         if ( ! isspace( (unsigned char) buf[0] ) ) {
2180                                 return( line );
2181                         }
2182
2183                         /* change leading whitespace to a space */
2184                         buf[0] = ' ';
2185                 }
2186
2187                 CATLINE( buf );
2188                 (*lineno)++;
2189         }
2190         buf[0] = '\0';
2191
2192         return( line[0] ? line : NULL );
2193 }
2194
2195 static void
2196 fp_getline_init( int *lineno )
2197 {
2198         *lineno = -1;
2199         buf[0] = '\0';
2200 }
2201
2202 /* Loads ucdata, returns 1 if loading, 0 if already loaded, -1 on error */
2203 static int
2204 load_ucdata( char *path )
2205 {
2206 #if 0
2207         static int loaded = 0;
2208         int err;
2209         
2210         if ( loaded ) {
2211                 return( 0 );
2212         }
2213         err = ucdata_load( path ? path : SLAPD_DEFAULT_UCDATA, UCDATA_ALL );
2214         if ( err ) {
2215                 Debug( LDAP_DEBUG_ANY, "error loading ucdata (error %d)\n",
2216                        err, 0, 0 );
2217
2218                 return( -1 );
2219         }
2220         loaded = 1;
2221         return( 1 );
2222 #else
2223         /* ucdata is now hardcoded */
2224         return( 0 );
2225 #endif
2226 }
2227
2228 void
2229 config_destroy( )
2230 {
2231         ucdata_unload( UCDATA_ALL );
2232         if ( frontendDB ) {
2233                 /* NOTE: in case of early exit, frontendDB can be NULL */
2234                 if ( frontendDB->be_schemandn.bv_val )
2235                         free( frontendDB->be_schemandn.bv_val );
2236                 if ( frontendDB->be_schemadn.bv_val )
2237                         free( frontendDB->be_schemadn.bv_val );
2238                 if ( frontendDB->be_acl )
2239                         acl_destroy( frontendDB->be_acl, NULL );
2240         }
2241         free( line );
2242         if ( slapd_args_file )
2243                 free ( slapd_args_file );
2244         if ( slapd_pid_file )
2245                 free ( slapd_pid_file );
2246         if ( default_passwd_hash )
2247                 ldap_charray_free( default_passwd_hash );
2248 }
2249
2250 static int
2251 add_syncrepl(
2252         Backend *be,
2253         char    **cargv,
2254         int     cargc
2255 )
2256 {
2257         syncinfo_t *si;
2258         syncinfo_t *si_entry;
2259         int     rc = 0;
2260         int duplicated_replica_id = 0;
2261
2262         si = (syncinfo_t *) ch_calloc( 1, sizeof( syncinfo_t ) );
2263
2264         if ( si == NULL ) {
2265                 Debug( LDAP_DEBUG_ANY, "out of memory in add_syncrepl\n", 0, 0, 0 );
2266                 return 1;
2267         }
2268
2269         si->si_tls = SYNCINFO_TLS_OFF;
2270         if ( be->be_rootndn.bv_val ) {
2271                 ber_dupbv( &si->si_updatedn, &be->be_rootndn );
2272         }
2273         si->si_bindmethod = LDAP_AUTH_SIMPLE;
2274         si->si_schemachecking = 0;
2275         ber_str2bv( "(objectclass=*)", STRLENOF("(objectclass=*)"), 1,
2276                 &si->si_filterstr );
2277         si->si_base.bv_val = NULL;
2278         si->si_scope = LDAP_SCOPE_SUBTREE;
2279         si->si_attrsonly = 0;
2280         si->si_attrs = (char **) ch_calloc( 1, sizeof( char * ));
2281         si->si_attrs[0] = NULL;
2282         si->si_exattrs = (char **) ch_calloc( 1, sizeof( char * ));
2283         si->si_exattrs[0] = NULL;
2284         si->si_type = LDAP_SYNC_REFRESH_ONLY;
2285         si->si_interval = 86400;
2286         si->si_retryinterval = NULL;
2287         si->si_retrynum_init = NULL;
2288         si->si_retrynum = NULL;
2289         si->si_syncCookie.ctxcsn = NULL;
2290         si->si_syncCookie.octet_str = NULL;
2291         si->si_syncCookie.sid = -1;
2292         si->si_manageDSAit = 0;
2293         si->si_tlimit = 0;
2294         si->si_slimit = 0;
2295         si->si_syncUUID_ndn.bv_val = NULL;
2296         si->si_syncUUID_ndn.bv_len = 0;
2297
2298         si->si_presentlist = NULL;
2299         LDAP_LIST_INIT( &si->si_nonpresentlist );
2300
2301         rc = parse_syncrepl_line( cargv, cargc, si );
2302
2303         LDAP_STAILQ_FOREACH( si_entry, &be->be_syncinfo, si_next ) {
2304                 if ( si->si_rid == si_entry->si_rid ) {
2305                         Debug( LDAP_DEBUG_ANY,
2306                                 "add_syncrepl: duplicated replica id\n",0, 0, 0 );
2307                         duplicated_replica_id = 1;
2308                         break;
2309                 }
2310         }
2311
2312         if ( rc < 0 || duplicated_replica_id ) {
2313                 Debug( LDAP_DEBUG_ANY, "failed to add syncinfo\n", 0, 0, 0 );
2314                 return 1;
2315         } else {
2316                 Debug( LDAP_DEBUG_CONFIG,
2317                         "Config: ** successfully added syncrepl \"%s\"\n",
2318                         si->si_provideruri == NULL ? "(null)" : si->si_provideruri, 0, 0 );
2319                 if ( !si->si_schemachecking ) {
2320                         SLAP_DBFLAGS(be) |= SLAP_DBFLAG_NO_SCHEMA_CHECK;
2321                 }
2322                 si->si_be = be;
2323                 LDAP_STAILQ_INSERT_TAIL( &be->be_syncinfo, si, si_next );
2324                 return 0;
2325         }
2326 }
2327
2328 #define IDSTR                   "rid"
2329 #define PROVIDERSTR             "provider"
2330 #define SUFFIXSTR               "suffix"
2331 #define UPDATEDNSTR             "updatedn"
2332 #define BINDMETHSTR             "bindmethod"
2333 #define SIMPLESTR               "simple"
2334 #define SASLSTR                 "sasl"
2335 #define BINDDNSTR               "binddn"
2336 #define CREDSTR                 "credentials"
2337 #define OLDAUTHCSTR             "bindprincipal"
2338 #define AUTHCSTR                "authcID"
2339 #define AUTHZSTR                "authzID"
2340 #define SRVTABSTR               "srvtab"
2341 #define SASLMECHSTR             "saslmech"
2342 #define REALMSTR                "realm"
2343 #define SECPROPSSTR             "secprops"
2344 #define STARTTLSSTR             "starttls"
2345 #define CRITICALSTR             "critical"
2346
2347 #define SCHEMASTR               "schemachecking"
2348 #define FILTERSTR               "filter"
2349 #define SEARCHBASESTR   "searchbase"
2350 #define SCOPESTR                "scope"
2351 #define ATTRSSTR                "attrs"
2352 #define ATTRSONLYSTR    "attrsonly"
2353 #define EXATTRSSTR              "exattrs"
2354 #define TYPESTR                 "type"
2355 #define INTERVALSTR             "interval"
2356 #define LASTMODSTR              "lastmod"
2357 #define LMREQSTR                "req"
2358 #define LMGENSTR                "gen"
2359 #define LMNOSTR                 "no"
2360 #define MANAGEDSAITSTR  "manageDSAit"
2361 #define SLIMITSTR               "sizelimit"
2362 #define TLIMITSTR               "timelimit"
2363
2364 #define RETRYSTR                "retry"
2365
2366 #define GOT_ID                  0x0001
2367 #define GOT_PROVIDER    0x0002
2368 #define GOT_METHOD              0x0004
2369 #define GOT_ALL                 0x0007
2370
2371 static int
2372 parse_syncrepl_line(
2373         char            **cargv,
2374         int             cargc,
2375         syncinfo_t      *si
2376 )
2377 {
2378         int     gots = 0;
2379         int     i, j;
2380         char    *hp, *val;
2381         int     nr_attr = 0;
2382
2383         for ( i = 1; i < cargc; i++ ) {
2384                 if ( !strncasecmp( cargv[ i ], IDSTR, sizeof( IDSTR ) - 1 )) {
2385                         int tmp;
2386                         /* '\0' string terminator accounts for '=' */
2387                         val = cargv[ i ] + sizeof( IDSTR );
2388                         tmp= atoi( val );
2389                         if ( tmp >= 1000 || tmp < 0 ) {
2390                                 fprintf( stderr, "Error: parse_syncrepl_line: "
2391                                          "syncrepl id %d is out of range [0..999]\n", tmp );
2392                                 return -1;
2393                         }
2394                         si->si_rid = tmp;
2395                         gots |= GOT_ID;
2396                 } else if ( !strncasecmp( cargv[ i ], PROVIDERSTR,
2397                                         sizeof( PROVIDERSTR ) - 1 )) {
2398                         val = cargv[ i ] + sizeof( PROVIDERSTR );
2399                         si->si_provideruri = ch_strdup( val );
2400                         si->si_provideruri_bv = (BerVarray)
2401                                 ch_calloc( 2, sizeof( struct berval ));
2402                         ber_str2bv( si->si_provideruri, strlen( si->si_provideruri ),
2403                                 1, &si->si_provideruri_bv[0] );
2404                         si->si_provideruri_bv[1].bv_len = 0;
2405                         si->si_provideruri_bv[1].bv_val = NULL;
2406                         gots |= GOT_PROVIDER;
2407                 } else if ( !strncasecmp( cargv[ i ], STARTTLSSTR,
2408                         sizeof(STARTTLSSTR) - 1 ) )
2409                 {
2410                         val = cargv[ i ] + sizeof( STARTTLSSTR );
2411                         if( !strcasecmp( val, CRITICALSTR ) ) {
2412                                 si->si_tls = SYNCINFO_TLS_CRITICAL;
2413                         } else {
2414                                 si->si_tls = SYNCINFO_TLS_ON;
2415                         }
2416                 } else if ( !strncasecmp( cargv[ i ],
2417                         UPDATEDNSTR, sizeof( UPDATEDNSTR ) - 1 ) )
2418                 {
2419                         struct berval updatedn = {0, NULL};
2420                         val = cargv[ i ] + sizeof( UPDATEDNSTR );
2421                         ber_str2bv( val, 0, 0, &updatedn );
2422                         ch_free( si->si_updatedn.bv_val );
2423                         dnNormalize( 0, NULL, NULL, &updatedn, &si->si_updatedn, NULL );
2424                 } else if ( !strncasecmp( cargv[ i ], BINDMETHSTR,
2425                                 sizeof( BINDMETHSTR ) - 1 ) )
2426                 {
2427                         val = cargv[ i ] + sizeof( BINDMETHSTR );
2428                         if ( !strcasecmp( val, SIMPLESTR )) {
2429                                 si->si_bindmethod = LDAP_AUTH_SIMPLE;
2430                                 gots |= GOT_METHOD;
2431                         } else if ( !strcasecmp( val, SASLSTR )) {
2432 #ifdef HAVE_CYRUS_SASL
2433                                 si->si_bindmethod = LDAP_AUTH_SASL;
2434                                 gots |= GOT_METHOD;
2435 #else /* HAVE_CYRUS_SASL */
2436                                 fprintf( stderr, "Error: parse_syncrepl_line: "
2437                                         "not compiled with SASL support\n" );
2438                                 return 1;
2439 #endif /* HAVE_CYRUS_SASL */
2440                         } else {
2441                                 si->si_bindmethod = -1;
2442                         }
2443                 } else if ( !strncasecmp( cargv[ i ],
2444                                 BINDDNSTR, sizeof( BINDDNSTR ) - 1 ) ) {
2445                         val = cargv[ i ] + sizeof( BINDDNSTR );
2446                         si->si_binddn = ch_strdup( val );
2447                 } else if ( !strncasecmp( cargv[ i ],
2448                                 CREDSTR, sizeof( CREDSTR ) - 1 ) ) {
2449                         val = cargv[ i ] + sizeof( CREDSTR );
2450                         si->si_passwd = ch_strdup( val );
2451                 } else if ( !strncasecmp( cargv[ i ],
2452                                 SASLMECHSTR, sizeof( SASLMECHSTR ) - 1 ) ) {
2453                         val = cargv[ i ] + sizeof( SASLMECHSTR );
2454                         si->si_saslmech = ch_strdup( val );
2455                 } else if ( !strncasecmp( cargv[ i ],
2456                                 SECPROPSSTR, sizeof( SECPROPSSTR ) - 1 ) ) {
2457                         val = cargv[ i ] + sizeof( SECPROPSSTR );
2458                         si->si_secprops = ch_strdup( val );
2459                 } else if ( !strncasecmp( cargv[ i ],
2460                                 REALMSTR, sizeof( REALMSTR ) - 1 ) ) {
2461                         val = cargv[ i ] + sizeof( REALMSTR );
2462                         si->si_realm = ch_strdup( val );
2463                 } else if ( !strncasecmp( cargv[ i ],
2464                                 AUTHCSTR, sizeof( AUTHCSTR ) - 1 ) ) {
2465                         val = cargv[ i ] + sizeof( AUTHCSTR );
2466                         if ( si->si_authcId )
2467                                 ch_free( si->si_authcId );
2468                         si->si_authcId = ch_strdup( val );
2469                 } else if ( !strncasecmp( cargv[ i ],
2470                                 OLDAUTHCSTR, sizeof( OLDAUTHCSTR ) - 1 ) ) {
2471                         /* Old authcID is provided for some backwards compatibility */
2472                         val = cargv[ i ] + sizeof( OLDAUTHCSTR );
2473                         if ( si->si_authcId )
2474                                 ch_free( si->si_authcId );
2475                         si->si_authcId = ch_strdup( val );
2476                 } else if ( !strncasecmp( cargv[ i ],
2477                                 AUTHZSTR, sizeof( AUTHZSTR ) - 1 ) ) {
2478                         val = cargv[ i ] + sizeof( AUTHZSTR );
2479                         si->si_authzId = ch_strdup( val );
2480                 } else if ( !strncasecmp( cargv[ i ],
2481                                 SCHEMASTR, sizeof( SCHEMASTR ) - 1 ) )
2482                 {
2483                         val = cargv[ i ] + sizeof( SCHEMASTR );
2484                         if ( !strncasecmp( val, "on", STRLENOF( "on" ) )) {
2485                                 si->si_schemachecking = 1;
2486                         } else if ( !strncasecmp( val, "off", STRLENOF( "off" ) ) ) {
2487                                 si->si_schemachecking = 0;
2488                         } else {
2489                                 si->si_schemachecking = 1;
2490                         }
2491                 } else if ( !strncasecmp( cargv[ i ],
2492                         FILTERSTR, sizeof( FILTERSTR ) - 1 ) )
2493                 {
2494                         val = cargv[ i ] + sizeof( FILTERSTR );
2495                         ber_str2bv( val, 0, 1, &si->si_filterstr );
2496                 } else if ( !strncasecmp( cargv[ i ],
2497                         SEARCHBASESTR, sizeof( SEARCHBASESTR ) - 1 ) )
2498                 {
2499                         struct berval bv;
2500                         val = cargv[ i ] + sizeof( SEARCHBASESTR );
2501                         if ( si->si_base.bv_val ) {
2502                                 ch_free( si->si_base.bv_val );
2503                         }
2504                         ber_str2bv( val, 0, 0, &bv );
2505                         if ( dnNormalize( 0, NULL, NULL, &bv, &si->si_base, NULL )) {
2506                                 fprintf( stderr, "Invalid base DN \"%s\"\n", val );
2507                                 return 1;
2508                         }
2509                 } else if ( !strncasecmp( cargv[ i ],
2510                         SCOPESTR, sizeof( SCOPESTR ) - 1 ) )
2511                 {
2512                         val = cargv[ i ] + sizeof( SCOPESTR );
2513                         if ( !strncasecmp( val, "base", STRLENOF( "base" ) )) {
2514                                 si->si_scope = LDAP_SCOPE_BASE;
2515                         } else if ( !strncasecmp( val, "one", STRLENOF( "one" ) )) {
2516                                 si->si_scope = LDAP_SCOPE_ONELEVEL;
2517 #ifdef LDAP_SCOPE_SUBORDINATE
2518                         } else if ( !strcasecmp( val, "subordinate" ) ||
2519                                 !strcasecmp( val, "children" ))
2520                         {
2521                                 si->si_scope = LDAP_SCOPE_SUBORDINATE;
2522 #endif
2523                         } else if ( !strncasecmp( val, "sub", STRLENOF( "sub" ) )) {
2524                                 si->si_scope = LDAP_SCOPE_SUBTREE;
2525                         } else {
2526                                 fprintf( stderr, "Error: parse_syncrepl_line: "
2527                                         "unknown scope \"%s\"\n", val);
2528                                 return 1;
2529                         }
2530                 } else if ( !strncasecmp( cargv[ i ],
2531                         ATTRSONLYSTR, sizeof( ATTRSONLYSTR ) - 1 ) )
2532                 {
2533                         si->si_attrsonly = 1;
2534                 } else if ( !strncasecmp( cargv[ i ],
2535                         ATTRSSTR, sizeof( ATTRSSTR ) - 1 ) )
2536                 {
2537                         val = cargv[ i ] + sizeof( ATTRSSTR );
2538                         str2clist( &si->si_attrs, val, "," );
2539                 } else if ( !strncasecmp( cargv[ i ],
2540                         EXATTRSSTR, sizeof( EXATTRSSTR ) - 1 ) )
2541                 {
2542                         val = cargv[ i ] + sizeof( EXATTRSSTR );
2543                         str2clist( &si->si_exattrs, val, "," );
2544                 } else if ( !strncasecmp( cargv[ i ],
2545                         TYPESTR, sizeof( TYPESTR ) - 1 ) )
2546                 {
2547                         val = cargv[ i ] + sizeof( TYPESTR );
2548                         if ( !strncasecmp( val, "refreshOnly", STRLENOF("refreshOnly") )) {
2549                                 si->si_type = LDAP_SYNC_REFRESH_ONLY;
2550                         } else if ( !strncasecmp( val, "refreshAndPersist",
2551                                 STRLENOF("refreshAndPersist") ))
2552                         {
2553                                 si->si_type = LDAP_SYNC_REFRESH_AND_PERSIST;
2554                                 si->si_interval = 60;
2555                         } else {
2556                                 fprintf( stderr, "Error: parse_syncrepl_line: "
2557                                         "unknown sync type \"%s\"\n", val);
2558                                 return 1;
2559                         }
2560                 } else if ( !strncasecmp( cargv[ i ],
2561                         INTERVALSTR, sizeof( INTERVALSTR ) - 1 ) )
2562                 {
2563                         val = cargv[ i ] + sizeof( INTERVALSTR );
2564                         if ( si->si_type == LDAP_SYNC_REFRESH_AND_PERSIST ) {
2565                                 si->si_interval = 0;
2566                         } else {
2567                                 char *hstr;
2568                                 char *mstr;
2569                                 char *dstr;
2570                                 char *sstr;
2571                                 int dd, hh, mm, ss;
2572                                 dstr = val;
2573                                 hstr = strchr( dstr, ':' );
2574                                 if ( hstr == NULL ) {
2575                                         fprintf( stderr, "Error: parse_syncrepl_line: "
2576                                                 "invalid interval \"%s\"\n", val );
2577                                         return 1;
2578                                 }
2579                                 *hstr++ = '\0';
2580                                 mstr = strchr( hstr, ':' );
2581                                 if ( mstr == NULL ) {
2582                                         fprintf( stderr, "Error: parse_syncrepl_line: "
2583                                                 "invalid interval \"%s\"\n", val );
2584                                         return 1;
2585                                 }
2586                                 *mstr++ = '\0';
2587                                 sstr = strchr( mstr, ':' );
2588                                 if ( sstr == NULL ) {
2589                                         fprintf( stderr, "Error: parse_syncrepl_line: "
2590                                                 "invalid interval \"%s\"\n", val );
2591                                         return 1;
2592                                 }
2593                                 *sstr++ = '\0';
2594
2595                                 dd = atoi( dstr );
2596                                 hh = atoi( hstr );
2597                                 mm = atoi( mstr );
2598                                 ss = atoi( sstr );
2599                                 if (( hh > 24 ) || ( hh < 0 ) ||
2600                                         ( mm > 60 ) || ( mm < 0 ) ||
2601                                         ( ss > 60 ) || ( ss < 0 ) || ( dd < 0 )) {
2602                                         fprintf( stderr, "Error: parse_syncrepl_line: "
2603                                                 "invalid interval \"%s\"\n", val );
2604                                         return 1;
2605                                 }
2606                                 si->si_interval = (( dd * 24 + hh ) * 60 + mm ) * 60 + ss;
2607                         }
2608                         if ( si->si_interval < 0 ) {
2609                                 fprintf( stderr, "Error: parse_syncrepl_line: "
2610                                         "invalid interval \"%ld\"\n",
2611                                         (long) si->si_interval);
2612                                 return 1;
2613                         }
2614                 } else if ( !strncasecmp( cargv[ i ],
2615                         RETRYSTR, sizeof( RETRYSTR ) - 1 ) )
2616                 {
2617                         char *str;
2618                         char **retry_list;
2619                         int j, k, n;
2620
2621                         val = cargv[ i ] + sizeof( RETRYSTR );
2622                         retry_list = (char **) ch_calloc( 1, sizeof( char * ));
2623                         retry_list[0] = NULL;
2624
2625                         str2clist( &retry_list, val, " ,\t" );
2626
2627                         for ( k = 0; retry_list && retry_list[k]; k++ ) ;
2628                         n = k / 2;
2629                         if ( k % 2 ) {
2630                                 fprintf( stderr,
2631                                                 "Error: incomplete syncrepl retry list\n" );
2632                                 for ( k = 0; retry_list && retry_list[k]; k++ ) {
2633                                         ch_free( retry_list[k] );
2634                                 }
2635                                 ch_free( retry_list );
2636                                 exit( EXIT_FAILURE );
2637                         }
2638                         si->si_retryinterval = (time_t *) ch_calloc( n + 1, sizeof( time_t ));
2639                         si->si_retrynum = (int *) ch_calloc( n + 1, sizeof( int ));
2640                         si->si_retrynum_init = (int *) ch_calloc( n + 1, sizeof( int ));
2641                         for ( j = 0; j < n; j++ ) {
2642                                 si->si_retryinterval[j] = atoi( retry_list[j*2] );
2643                                 if ( *retry_list[j*2+1] == '+' ) {
2644                                         si->si_retrynum_init[j] = -1;
2645                                         si->si_retrynum[j] = -1;
2646                                         j++;
2647                                         break;
2648                                 } else {
2649                                         si->si_retrynum_init[j] = atoi( retry_list[j*2+1] );
2650                                         si->si_retrynum[j] = atoi( retry_list[j*2+1] );
2651                                 }
2652                         }
2653                         si->si_retrynum_init[j] = -2;
2654                         si->si_retrynum[j] = -2;
2655                         si->si_retryinterval[j] = 0;
2656                         
2657                         for ( k = 0; retry_list && retry_list[k]; k++ ) {
2658                                 ch_free( retry_list[k] );
2659                         }
2660                         ch_free( retry_list );
2661                 } else if ( !strncasecmp( cargv[ i ],
2662                         MANAGEDSAITSTR, sizeof( MANAGEDSAITSTR ) - 1 ) )
2663                 {
2664                         val = cargv[ i ] + sizeof( MANAGEDSAITSTR );
2665                         si->si_manageDSAit = atoi( val );
2666                 } else if ( !strncasecmp( cargv[ i ],
2667                         SLIMITSTR, sizeof( SLIMITSTR ) - 1 ) )
2668                 {
2669                         val = cargv[ i ] + sizeof( SLIMITSTR );
2670                         si->si_slimit = atoi( val );
2671                 } else if ( !strncasecmp( cargv[ i ],
2672                         TLIMITSTR, sizeof( TLIMITSTR ) - 1 ) )
2673                 {
2674                         val = cargv[ i ] + sizeof( TLIMITSTR );
2675                         si->si_tlimit = atoi( val );
2676                 } else {
2677                         fprintf( stderr, "Error: parse_syncrepl_line: "
2678                                 "unknown keyword \"%s\"\n", cargv[ i ] );
2679                 }
2680         }
2681
2682         if ( gots != GOT_ALL ) {
2683                 fprintf( stderr,
2684                         "Error: Malformed \"syncrepl\" line in slapd config file" );
2685                 return -1;
2686         }
2687
2688         return 0;
2689 }
2690
2691 char **
2692 str2clist( char ***out, char *in, const char *brkstr )
2693 {
2694         char    *str;
2695         char    *s;
2696         char    *lasts;
2697         int     i, j;
2698         const char *text;
2699         char    **new;
2700
2701         /* find last element in list */
2702         for (i = 0; *out && *out[i]; i++);
2703
2704         /* protect the input string from strtok */
2705         str = ch_strdup( in );
2706
2707         if ( *str == '\0' ) {
2708                 free( str );
2709                 return( *out );
2710         }
2711
2712         /* Count words in string */
2713         j=1;
2714         for ( s = str; *s; s++ ) {
2715                 if ( strchr( brkstr, *s ) != NULL ) {
2716                         j++;
2717                 }
2718         }
2719
2720         *out = ch_realloc( *out, ( i + j + 1 ) * sizeof( char * ) );
2721         new = *out + i;
2722         for ( s = ldap_pvt_strtok( str, brkstr, &lasts );
2723                 s != NULL;
2724                 s = ldap_pvt_strtok( NULL, brkstr, &lasts ) )
2725         {
2726                 *new = ch_strdup( s );
2727                 new++;
2728         }
2729
2730         *new = NULL;
2731         free( str );
2732         return( *out );
2733 }