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