]> git.sur5r.net Git - openldap/blob - servers/slapd/config.c
Misc. cleanup
[openldap] / servers / slapd / config.c
1 /* config.c - configuration file handling routines */
2 /* $OpenLDAP$ */
3 /*
4  * Copyright 1998-1999 The OpenLDAP Foundation, All Rights Reserved.
5  * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
6  */
7
8 #include "portable.h"
9
10 #include <stdio.h>
11 #ifdef HAVE_LOCALE_H
12 #include <locale.h>
13 #endif
14
15 #include <ac/string.h>
16 #include <ac/ctype.h>
17 #include <ac/socket.h>
18
19 #include "ldap_pvt.h"
20 #include "slap.h"
21
22 #define MAXARGS 100
23
24 /*
25  * defaults for various global variables
26  */
27 int             defsize = SLAPD_DEFAULT_SIZELIMIT;
28 int             deftime = SLAPD_DEFAULT_TIMELIMIT;
29 AccessControl   *global_acl = NULL;
30 int             global_default_access = ACL_READ;
31 int             global_readonly = 0;
32 char            *replogfile;
33 int             global_lastmod = ON;
34 int             global_idletimeout = 0;
35 char    *global_realm = NULL;
36 char            *ldap_srvtab = "";
37
38 char   *slapd_pid_file  = NULL;
39 char   *slapd_args_file = NULL;
40
41 static char     *fp_getline(FILE *fp, int *lineno);
42 static void     fp_getline_init(int *lineno);
43 static int      fp_parse_line(char *line, int *argcp, char **argv);
44
45 static char     *strtok_quote(char *line, char *sep);
46
47 int
48 read_config( const char *fname )
49 {
50         FILE    *fp;
51         char    *line, *savefname, *saveline;
52         int     cargc, savelineno;
53         char    *cargv[MAXARGS];
54         int     lineno, i;
55 #ifdef HAVE_TLS
56         int rc;
57 #endif
58         struct berval *vals[2];
59         struct berval val;
60
61         static BackendInfo *bi = NULL;
62         static BackendDB        *be = NULL;
63
64         vals[0] = &val;
65         vals[1] = NULL;
66
67         if ( (fp = fopen( fname, "r" )) == NULL ) {
68                 ldap_syslog = 1;
69                 Debug( LDAP_DEBUG_ANY,
70                     "could not open config file \"%s\" - absolute path?\n",
71                     fname, 0, 0 );
72                 perror( fname );
73                 return 1;
74         }
75
76         Debug( LDAP_DEBUG_CONFIG, "reading config file %s\n", fname, 0, 0 );
77
78         if ( schema_init( ) != 0 ) {
79                 Debug( LDAP_DEBUG_ANY,
80                     "error initializing the schema\n",
81                     0, 0, 0 );
82                 return( 1 );
83         }
84
85         fp_getline_init( &lineno );
86
87         while ( (line = fp_getline( fp, &lineno )) != NULL ) {
88                 /* skip comments and blank lines */
89                 if ( line[0] == '#' || line[0] == '\0' ) {
90                         continue;
91                 }
92
93                 Debug( LDAP_DEBUG_CONFIG, "line %d (%s)\n", lineno, line, 0 );
94
95                 /* fp_parse_line is destructive, we save a copy */
96                 saveline = ch_strdup( line );
97
98                 if ( fp_parse_line( line, &cargc, cargv ) != 0 ) {
99                         return( 1 );
100                 }
101
102                 if ( cargc < 1 ) {
103                         Debug( LDAP_DEBUG_ANY,
104                             "%s: line %d: bad config line (ignored)\n",
105                             fname, lineno, 0 );
106                         continue;
107                 }
108
109                 if ( strcasecmp( cargv[0], "backend" ) == 0 ) {
110                         if ( cargc < 2 ) {
111                                 Debug( LDAP_DEBUG_ANY,
112                 "%s: line %d: missing type in \"backend <type>\" line\n",
113                                     fname, lineno, 0 );
114                                 return( 1 );
115                         }
116
117                         if( be != NULL ) {
118                                 Debug( LDAP_DEBUG_ANY,
119 "%s: line %d: backend line must appear before any database definition\n",
120                                     fname, lineno, 0 );
121                                 return( 1 );
122                         }
123
124                         bi = backend_info( cargv[1] );
125
126                         if( bi == NULL ) {
127                                 Debug( LDAP_DEBUG_ANY,
128                                         "backend %s initialization failed.n",
129                                     cargv[1], 0, 0 );
130                                 return( 1 );
131                         }
132
133                 /* start of a new database definition */
134                 } else if ( strcasecmp( cargv[0], "database" ) == 0 ) {
135                         if ( cargc < 2 ) {
136                                 Debug( LDAP_DEBUG_ANY,
137                 "%s: line %d: missing type in \"database <type>\" line\n",
138                                     fname, lineno, 0 );
139                                 return( 1 );
140                         }
141
142                         bi = NULL;
143                         be = backend_db_init( cargv[1] );
144
145                         if( be == NULL ) {
146                                 Debug( LDAP_DEBUG_ANY,
147                                         "database %s initialization failed.n",
148                                     cargv[1], 0, 0 );
149                                 return( 1 );
150                         }
151
152                 /* get pid file name */
153                 } else if ( strcasecmp( cargv[0], "pidfile" ) == 0 ) {
154                         if ( cargc < 2 ) {
155                                 Debug( LDAP_DEBUG_ANY,
156             "%s: line %d: missing file name in \"pidfile <file>\" line\n",
157                                     fname, lineno, 0 );
158                                 return( 1 );
159                         }
160
161                         slapd_pid_file = ch_strdup( cargv[1] );
162
163                 /* get args file name */
164                 } else if ( strcasecmp( cargv[0], "argsfile" ) == 0 ) {
165                         if ( cargc < 2 ) {
166                                 Debug( LDAP_DEBUG_ANY,
167             "%s: line %d: missing file name in \"argsfile <file>\" line\n",
168                                     fname, lineno, 0 );
169                                 return( 1 );
170                         }
171
172                         slapd_args_file = ch_strdup( cargv[1] );
173
174                 /* set DIGEST realm */
175                 } else if ( strcasecmp( cargv[0], "digest-realm" ) == 0 ) {
176                         if ( cargc < 2 ) {
177                                 Debug( LDAP_DEBUG_ANY,
178             "%s: line %d: missing realm in \"digest-realm <realm>\" line\n",
179                                     fname, lineno, 0 );
180                                 return( 1 );
181                         }
182                         if ( be != NULL ) {
183                                 be->be_realm = ch_strdup( cargv[1] );
184
185                         } else if ( global_realm != NULL ) {
186                                 Debug( LDAP_DEBUG_ANY,
187                                         "%s: line %d: already set global realm!\n",
188                                         fname, lineno, 0 );
189                                 return 1;
190
191                         } else {
192                                 global_realm = ch_strdup( cargv[1] );
193                         }
194
195                 /* set time limit */
196                 } else if ( strcasecmp( cargv[0], "sizelimit" ) == 0 ) {
197                         if ( cargc < 2 ) {
198                                 Debug( LDAP_DEBUG_ANY,
199             "%s: line %d: missing limit in \"sizelimit <limit>\" line\n",
200                                     fname, lineno, 0 );
201                                 return( 1 );
202                         }
203                         if ( be == NULL ) {
204                                 defsize = atoi( cargv[1] );
205                         } else {
206                                 be->be_sizelimit = atoi( cargv[1] );
207                         }
208
209                 /* set time limit */
210                 } else if ( strcasecmp( cargv[0], "timelimit" ) == 0 ) {
211                         if ( cargc < 2 ) {
212                                 Debug( LDAP_DEBUG_ANY,
213             "%s: line %d: missing limit in \"timelimit <limit>\" line\n",
214                                     fname, lineno, 0 );
215                                 return( 1 );
216                         }
217                         if ( be == NULL ) {
218                                 deftime = atoi( cargv[1] );
219                         } else {
220                                 be->be_timelimit = atoi( cargv[1] );
221                         }
222
223                 /* set database suffix */
224                 } else if ( strcasecmp( cargv[0], "suffix" ) == 0 ) {
225                         Backend *tmp_be;
226                         if ( cargc < 2 ) {
227                                 Debug( LDAP_DEBUG_ANY,
228                     "%s: line %d: missing dn in \"suffix <dn>\" line\n",
229                                     fname, lineno, 0 );
230                                 return( 1 );
231                         } else if ( cargc > 2 ) {
232                                 Debug( LDAP_DEBUG_ANY,
233     "%s: line %d: extra cruft after <dn> in \"suffix %s\" line (ignored)\n",
234                                     fname, lineno, cargv[1] );
235                         }
236                         if ( be == NULL ) {
237                                 Debug( LDAP_DEBUG_ANY,
238 "%s: line %d: suffix line must appear inside a database definition (ignored)\n",
239                                     fname, lineno, 0 );
240                         } else if ( ( tmp_be = select_backend( cargv[1] ) ) == be ) {
241                                 Debug( LDAP_DEBUG_ANY,
242 "%s: line %d: suffix already served by this backend (ignored)\n",
243                                     fname, lineno, 0 );
244                         } else if ( tmp_be  != NULL ) {
245                                 Debug( LDAP_DEBUG_ANY,
246 "%s: line %d: suffix already served by a preceeding backend \"%s\" (ignored)\n",
247                                     fname, lineno, tmp_be->be_suffix[0] );
248                         } else {
249                                 char *dn = ch_strdup( cargv[1] );
250                                 (void) dn_normalize( dn );
251                                 charray_add( &be->be_suffix, dn );
252                                 (void) ldap_pvt_str2upper( dn );
253                                 charray_add( &be->be_nsuffix, dn );
254                                 free( dn );
255                         }
256
257                 /* set database suffixAlias */
258                 } else if ( strcasecmp( cargv[0], "suffixAlias" ) == 0 ) {
259                         Backend *tmp_be;
260                         if ( cargc < 2 ) {
261                                 Debug( LDAP_DEBUG_ANY,
262 "%s: line %d: missing alias and aliased_dn in \"suffixAlias <alias> <aliased_dn>\" line\n",
263                                         fname, lineno, 0 );
264                                 return( 1 );
265                         } else if ( cargc < 3 ) {
266                                 Debug( LDAP_DEBUG_ANY,
267 "%s: line %d: missing aliased_dn in \"suffixAlias <alias> <aliased_dn>\" line\n",
268                                 fname, lineno, 0 );
269                                 return( 1 );
270                         } else if ( cargc > 3 ) {
271                                 Debug( LDAP_DEBUG_ANY,
272                                         "%s: line %d: extra cruft in suffixAlias line (ignored)\n",
273                                 fname, lineno, 0 );
274                         }
275
276                         if ( be == NULL ) {
277                                 Debug( LDAP_DEBUG_ANY,
278                                         "%s: line %d: suffixAlias line"
279                                         " must appear inside a database definition (ignored)\n",
280                                         fname, lineno, 0 );
281                         } else if ( (tmp_be = select_backend( cargv[1] )) != NULL ) {
282                                 Debug( LDAP_DEBUG_ANY,
283                                         "%s: line %d: suffixAlias served by"
284                                         "  a preceeding backend \"%s\" (ignored)\n",
285                                         fname, lineno, tmp_be->be_suffix[0] );
286
287                         } else if ( (tmp_be = select_backend( cargv[2] )) != NULL ) {
288                                 Debug( LDAP_DEBUG_ANY,
289                                         "%s: line %d: suffixAlias derefs to differnet backend"
290                                         "  a preceeding backend \"%s\" (ignored)\n",
291                                         fname, lineno, tmp_be->be_suffix[0] );
292
293                         } else {
294                                 char *alias, *aliased_dn;
295
296                                 alias = ch_strdup( cargv[1] );
297                                 (void) dn_normalize( alias );
298
299                                 aliased_dn = ch_strdup( cargv[2] );
300                                 (void) dn_normalize( aliased_dn );
301
302                                 (void) dn_normalize_case( alias );
303                                 (void) dn_normalize_case( aliased_dn );
304                                 charray_add( &be->be_suffixAlias, alias );
305                                 charray_add( &be->be_suffixAlias, aliased_dn );
306
307                                 free(alias);
308                                 free(aliased_dn);
309                         }
310
311                /* set max deref depth */
312                } else if ( strcasecmp( cargv[0], "maxDerefDepth" ) == 0 ) {
313                                         int i;
314                        if ( cargc < 2 ) {
315                                Debug( LDAP_DEBUG_ANY,
316                    "%s: line %d: missing depth in \"maxDerefDepth <depth>\" line\n",
317                                    fname, lineno, 0 );
318                                return( 1 );
319                        }
320                        if ( be == NULL ) {
321                                Debug( LDAP_DEBUG_ANY,
322 "%s: line %d: depth line must appear inside a database definition (ignored)\n",
323                                    fname, lineno, 0 );
324                        } else if ((i = atoi(cargv[1])) < 0) {
325                                Debug( LDAP_DEBUG_ANY,
326 "%s: line %d: depth must be positive (ignored)\n",
327                                    fname, lineno, 0 );
328
329                        } else {
330                            be->be_max_deref_depth = i;
331                                            }
332
333
334                 /* set magic "root" dn for this database */
335                 } else if ( strcasecmp( cargv[0], "rootdn" ) == 0 ) {
336                         if ( cargc < 2 ) {
337                                 Debug( LDAP_DEBUG_ANY,
338                     "%s: line %d: missing dn in \"rootdn <dn>\" line\n",
339                                     fname, lineno, 0 );
340                                 return( 1 );
341                         }
342                         if ( be == NULL ) {
343                                 Debug( LDAP_DEBUG_ANY,
344 "%s: line %d: rootdn line must appear inside a database definition (ignored)\n",
345                                     fname, lineno, 0 );
346                         } else {
347                                 be->be_root_dn = ch_strdup( cargv[1] );
348                                 be->be_root_ndn = ch_strdup( cargv[1] );
349
350                                 if( dn_normalize_case( be->be_root_ndn ) == NULL ) {
351                                         free( be->be_root_dn );
352                                         free( be->be_root_ndn );
353                                         Debug( LDAP_DEBUG_ANY,
354 "%s: line %d: rootdn DN is invalid\n",
355                                            fname, lineno, 0 );
356                                         return( 1 );
357                                 }
358                         }
359
360                 /* set super-secret magic database password */
361                 } else if ( strcasecmp( cargv[0], "rootpw" ) == 0 ) {
362                         if ( cargc < 2 ) {
363                                 Debug( LDAP_DEBUG_ANY,
364             "%s: line %d: missing passwd in \"rootpw <passwd>\" line\n",
365                                     fname, lineno, 0 );
366                                 return( 1 );
367                         }
368                         if ( be == NULL ) {
369                                 Debug( LDAP_DEBUG_ANY,
370 "%s: line %d: rootpw line must appear inside a database definition (ignored)\n",
371                                     fname, lineno, 0 );
372                         } else {
373                                 be->be_root_pw = ch_strdup( cargv[1] );
374                         }
375
376                 /* make this database read-only */
377                 } else if ( strcasecmp( cargv[0], "readonly" ) == 0 ) {
378                         if ( cargc < 2 ) {
379                                 Debug( LDAP_DEBUG_ANY,
380             "%s: line %d: missing on|off in \"readonly <on|off>\" line\n",
381                                     fname, lineno, 0 );
382                                 return( 1 );
383                         }
384                         if ( be == NULL ) {
385                                 global_readonly = (strcasecmp( cargv[1], "on" ) == 0);
386                         } else {
387                                 if ( strcasecmp( cargv[1], "on" ) == 0 ) {
388                                         be->be_readonly = 1;
389                                 } else {
390                                         be->be_readonly = 0;
391                                 }
392                         }
393
394                 /* where to send clients when we don't hold it */
395                 } else if ( strcasecmp( cargv[0], "referral" ) == 0 ) {
396                         if ( cargc < 2 ) {
397                                 Debug( LDAP_DEBUG_ANY,
398                     "%s: line %d: missing URL in \"referral <URL>\" line\n",
399                                     fname, lineno, 0 );
400                                 return( 1 );
401                         }
402
403                         vals[0]->bv_val = cargv[1];
404                         vals[0]->bv_len = strlen( vals[0]->bv_val );
405                         value_add( &default_referral, vals );
406
407                 /* specify locale */
408                 } else if ( strcasecmp( cargv[0], "locale" ) == 0 ) {
409 #ifdef HAVE_LOCALE_H
410                         char *locale;
411                         if ( cargc < 2 ) {
412                                 Debug( LDAP_DEBUG_ANY,
413         "%s: line %d: missing locale in \"locale <name | on | off>\" line\n",
414                                        fname, lineno, 0 );
415                                 return( 1 );
416                         }
417
418                         locale = (strcasecmp(   cargv[1], "on"  ) == 0 ? ""
419                                   : strcasecmp( cargv[1], "off" ) == 0 ? "C"
420                                   : ch_strdup( cargv[1] )                    );
421
422                         if ( setlocale( LC_CTYPE, locale ) == 0 ) {
423                                 Debug( LDAP_DEBUG_ANY,
424                                        (*locale
425                                         ? "%s: line %d: bad locale \"%s\"\n"
426                                         : "%s: line %d: bad locale\n"),
427                                        fname, lineno, locale );
428                                 return( 1 );
429                         }
430 #else
431                         Debug( LDAP_DEBUG_ANY,
432                                "%s: line %d: \"locale\" unsupported\n",
433                                fname, lineno, 0 );
434                         return( 1 );
435 #endif
436                 /* specify an Object Identifier macro */
437                 } else if ( strcasecmp( cargv[0], "objectidentifier" ) == 0 ) {
438                         parse_oidm( fname, lineno, cargc, cargv );
439                 /* specify an objectclass */
440                 } else if ( strcasecmp( cargv[0], "objectclass" ) == 0 ) {
441                         if ( *cargv[1] == '(' ) {
442                                 char * p;
443                                 p = strchr(saveline,'(');
444                                 parse_oc( fname, lineno, p, cargv );
445                         } else {
446                                 parse_oc_old( be, fname, lineno, cargc, cargv );
447                         }
448
449                 /* specify an attribute */
450                 } else if ( strcasecmp( cargv[0], "attribute" ) == 0 ) {
451                         if ( *cargv[1] == '(' ) {
452                                 char * p;
453                                 p = strchr(saveline,'(');
454                                 parse_at( fname, lineno, p, cargv );
455                         } else {
456                                 attr_syntax_config( fname, lineno, cargc - 1,
457                                     &cargv[1] );
458                         }
459
460                 /* turn on/off schema checking */
461                 } else if ( strcasecmp( cargv[0], "schemacheck" ) == 0 ) {
462                         if ( cargc < 2 ) {
463                                 Debug( LDAP_DEBUG_ANY,
464     "%s: line %d: missing on|off in \"schemacheck <on|off>\" line\n",
465                                     fname, lineno, 0 );
466                                 return( 1 );
467                         }
468                         if ( strcasecmp( cargv[1], "off" ) == 0 ) {
469                                 global_schemacheck = 0;
470                         } else {
471                                 global_schemacheck = 1;
472                         }
473
474                 /* specify access control info */
475                 } else if ( strcasecmp( cargv[0], "access" ) == 0 ) {
476                         parse_acl( be, fname, lineno, cargc, cargv );
477
478                 /* specify default access control info */
479                 } else if ( strcasecmp( cargv[0], "defaultaccess" ) == 0 ) {
480                         if ( cargc < 2 ) {
481                                 Debug( LDAP_DEBUG_ANY,
482             "%s: line %d: missing limit in \"defaultaccess <access>\" line\n",
483                                     fname, lineno, 0 );
484                                 return( 1 );
485                         }
486                         if ( be == NULL ) {
487                                 if ( ACL_IS_INVALID(ACL_SET(global_default_access,
488                                                 str2access(cargv[1]))) )
489                                 {
490                                         Debug( LDAP_DEBUG_ANY,
491 "%s: line %d: bad access \"%s\" expecting [self]{none|auth|compare|search|read|write}\n",
492                                             fname, lineno, cargv[1] );
493                                         return( 1 );
494                                 }
495                         } else {
496                                 if ( ACL_IS_INVALID(ACL_SET(be->be_dfltaccess,
497                                                 str2access(cargv[1]))) )
498                                 {
499                                         Debug( LDAP_DEBUG_ANY,
500                                                 "%s: line %d: bad access \"%s\", "
501                                                 "expecting [self]{none|auth|compare|search|read|write}\n",
502                                             fname, lineno, cargv[1] );
503                                         return( 1 );
504                                 }
505                         }
506
507                 /* debug level to log things to syslog */
508                 } else if ( strcasecmp( cargv[0], "loglevel" ) == 0 ) {
509                         if ( cargc < 2 ) {
510                                 Debug( LDAP_DEBUG_ANY,
511                     "%s: line %d: missing level in \"loglevel <level>\" line\n",
512                                     fname, lineno, 0 );
513                                 return( 1 );
514                         }
515                         ldap_syslog = atoi( cargv[1] );
516
517                 /* list of replicas of the data in this backend (master only) */
518                 } else if ( strcasecmp( cargv[0], "replica" ) == 0 ) {
519                         if ( cargc < 2 ) {
520                                 Debug( LDAP_DEBUG_ANY,
521             "%s: line %d: missing host in \"replica <host[:port]>\" line\n",
522                                     fname, lineno, 0 );
523                                 return( 1 );
524                         }
525                         if ( be == NULL ) {
526                                 Debug( LDAP_DEBUG_ANY,
527 "%s: line %d: replica line must appear inside a database definition (ignored)\n",
528                                     fname, lineno, 0 );
529                         } else {
530                                 for ( i = 1; i < cargc; i++ ) {
531                                         if ( strncasecmp( cargv[i], "host=", 5 )
532                                             == 0 ) {
533                                                 charray_add( &be->be_replica,
534                                                              cargv[i] + 5 );
535                                                 break;
536                                         }
537                                 }
538                                 if ( i == cargc ) {
539                                         Debug( LDAP_DEBUG_ANY,
540                     "%s: line %d: missing host in \"replica\" line (ignored)\n",
541                                             fname, lineno, 0 );
542                                 }
543                         }
544
545                 /* dn of master entity allowed to write to replica */
546                 } else if ( strcasecmp( cargv[0], "updatedn" ) == 0 ) {
547                         if ( cargc < 2 ) {
548                                 Debug( LDAP_DEBUG_ANY,
549                     "%s: line %d: missing dn in \"updatedn <dn>\" line\n",
550                                     fname, lineno, 0 );
551                                 return( 1 );
552                         }
553                         if ( be == NULL ) {
554                                 Debug( LDAP_DEBUG_ANY,
555 "%s: line %d: updatedn line must appear inside a database definition (ignored)\n",
556                                     fname, lineno, 0 );
557                         } else {
558                                 be->be_update_ndn = ch_strdup( cargv[1] );
559                                 if( dn_normalize_case( be->be_update_ndn ) == NULL ) {
560                                         Debug( LDAP_DEBUG_ANY,
561 "%s: line %d: updatedn DN is invalid\n",
562                                             fname, lineno, 0 );
563                                         return 1;
564                                 }
565                         }
566
567                 } else if ( strcasecmp( cargv[0], "updateref" ) == 0 ) {
568                         if ( cargc < 2 ) {
569                                 Debug( LDAP_DEBUG_ANY,
570                     "%s: line %d: missing dn in \"updateref <ldapurl>\" line\n",
571                                     fname, lineno, 0 );
572                                 return( 1 );
573                         }
574                         if ( be == NULL ) {
575                                 Debug( LDAP_DEBUG_ANY,
576 "%s: line %d: updateref line must appear inside a database definition (ignored)\n",
577                                     fname, lineno, 0 );
578                         } else if ( be->be_update_ndn == NULL ) {
579                                 Debug( LDAP_DEBUG_ANY,
580 "%s: line %d: updateref line must after updatedn (ignored)\n",
581                                     fname, lineno, 0 );
582                         } else {
583                                 vals[0]->bv_val = cargv[1];
584                                 vals[0]->bv_len = strlen( vals[0]->bv_val );
585                                 value_add( &be->be_update_refs, vals );
586                         }
587
588                 /* replication log file to which changes are appended */
589                 } else if ( strcasecmp( cargv[0], "replogfile" ) == 0 ) {
590                         if ( cargc < 2 ) {
591                                 Debug( LDAP_DEBUG_ANY,
592             "%s: line %d: missing dn in \"replogfile <filename>\" line\n",
593                                     fname, lineno, 0 );
594                                 return( 1 );
595                         }
596                         if ( be ) {
597                                 be->be_replogfile = ch_strdup( cargv[1] );
598                         } else {
599                                 replogfile = ch_strdup( cargv[1] );
600                         }
601
602                 /* maintain lastmodified{by,time} attributes */
603                 } else if ( strcasecmp( cargv[0], "lastmod" ) == 0 ) {
604                         if ( cargc < 2 ) {
605                                 Debug( LDAP_DEBUG_ANY,
606             "%s: line %d: missing on|off in \"lastmod <on|off>\" line\n",
607                                     fname, lineno, 0 );
608                                 return( 1 );
609                         }
610                         if ( strcasecmp( cargv[1], "on" ) == 0 ) {
611                                 if ( be )
612                                         be->be_lastmod = ON;
613                                 else
614                                         global_lastmod = ON;
615                         } else {
616                                 if ( be )
617                                         be->be_lastmod = OFF;
618                                 else
619                                         global_lastmod = OFF;
620                         }
621
622                 /* set idle timeout value */
623                 } else if ( strcasecmp( cargv[0], "idletimeout" ) == 0 ) {
624                         int i;
625                         if ( cargc < 2 ) {
626                                 Debug( LDAP_DEBUG_ANY,
627             "%s: line %d: missing timeout value in \"idletimeout <seconds>\" line\n",
628                                     fname, lineno, 0 );
629                                 return( 1 );
630                         }
631
632                         i = atoi( cargv[1] );
633
634                         if( i < 0 ) {
635                                 Debug( LDAP_DEBUG_ANY,
636             "%s: line %d: timeout value (%d) invalid \"idletimeout <seconds>\" line\n",
637                                     fname, lineno, i );
638                                 return( 1 );
639                         }
640
641                         global_idletimeout = i;
642
643                 /* include another config file */
644                 } else if ( strcasecmp( cargv[0], "include" ) == 0 ) {
645                         if ( cargc < 2 ) {
646                                 Debug( LDAP_DEBUG_ANY,
647     "%s: line %d: missing filename in \"include <filename>\" line\n",
648                                     fname, lineno, 0 );
649                                 return( 1 );
650                         }
651                         savefname = ch_strdup( cargv[1] );
652                         savelineno = lineno;
653
654                         if ( read_config( savefname ) != 0 ) {
655                                 return( 1 );
656                         }
657
658                         free( savefname );
659                         lineno = savelineno - 1;
660
661                 /* location of kerberos srvtab file */
662                 } else if ( strcasecmp( cargv[0], "srvtab" ) == 0 ) {
663                         if ( cargc < 2 ) {
664                                 Debug( LDAP_DEBUG_ANY,
665             "%s: line %d: missing filename in \"srvtab <filename>\" line\n",
666                                     fname, lineno, 0 );
667                                 return( 1 );
668                         }
669                         ldap_srvtab = ch_strdup( cargv[1] );
670
671 #ifdef SLAPD_MODULES
672                 } else if (strcasecmp( cargv[0], "moduleload") == 0 ) {
673                    if ( cargc < 2 ) {
674                       Debug( LDAP_DEBUG_ANY,
675                              "%s: line %d: missing filename in \"moduleload <filename>\" line\n",
676                              fname, lineno, 0 );
677                       exit( EXIT_FAILURE );
678                    }
679                    if (module_load(cargv[1], cargc - 2, (cargc > 2) ? cargv + 2 : NULL)) {
680                       Debug( LDAP_DEBUG_ANY,
681                              "%s: line %d: failed to load or initialize module %s\n",
682                              fname, lineno, cargv[1]);
683                       exit( EXIT_FAILURE );
684                    }
685                 } else if (strcasecmp( cargv[0], "modulepath") == 0 ) {
686                    if ( cargc != 2 ) {
687                       Debug( LDAP_DEBUG_ANY,
688                              "%s: line %d: missing path in \"modulepath <path>\" line\n",
689                              fname, lineno, 0 );
690                       exit( EXIT_FAILURE );
691                    }
692                    if (module_path( cargv[1] )) {
693                       Debug( LDAP_DEBUG_ANY,
694                              "%s: line %d: failed to set module search path to %s\n",
695                              fname, lineno, cargv[1]);
696                       exit( EXIT_FAILURE );
697                    }
698                    
699 #endif /*SLAPD_MODULES*/
700
701 #ifdef HAVE_TLS
702                 } else if ( !strcasecmp( cargv[0], "TLSProtocol" ) ) {
703                         rc = ldap_pvt_tls_set_option( NULL,
704                                                       LDAP_OPT_X_TLS_PROTOCOL,
705                                                       cargv[1] );
706                         if ( rc )
707                                 return rc;
708
709                 } else if ( !strcasecmp( cargv[0], "TLSCipherSuite" ) ) {
710                         rc = ldap_pvt_tls_set_option( NULL,
711                                                       LDAP_OPT_X_TLS_CIPHER_SUITE,
712                                                       cargv[1] );
713                         if ( rc )
714                                 return rc;
715
716                 } else if ( !strcasecmp( cargv[0], "TLSCertificateFile" ) ) {
717                         rc = ldap_pvt_tls_set_option( NULL,
718                                                       LDAP_OPT_X_TLS_CERTFILE,
719                                                       cargv[1] );
720                         if ( rc )
721                                 return rc;
722
723                 } else if ( !strcasecmp( cargv[0], "TLSCertificateKeyFile" ) ) {
724                         rc = ldap_pvt_tls_set_option( NULL,
725                                                       LDAP_OPT_X_TLS_KEYFILE,
726                                                       cargv[1] );
727                         if ( rc )
728                                 return rc;
729
730                 } else if ( !strcasecmp( cargv[0], "TLSCACertificatePath" ) ) {
731                         rc = ldap_pvt_tls_set_option( NULL,
732                                                       LDAP_OPT_X_TLS_CACERTDIR,
733                                                       cargv[1] );
734                         if ( rc )
735                                 return rc;
736
737                 } else if ( !strcasecmp( cargv[0], "TLSCACertificateFile" ) ) {
738                         rc = ldap_pvt_tls_set_option( NULL,
739                                                       LDAP_OPT_X_TLS_CACERTFILE,
740                                                       cargv[1] );
741                         if ( rc )
742                                 return rc;
743                 } else if ( !strcasecmp( cargv[0], "TLSVerifyClient" ) ) {
744                         rc = ldap_pvt_tls_set_option( NULL,
745                                                       LDAP_OPT_X_TLS_REQUIRE_CERT,
746                                                       cargv[1] );
747                         if ( rc )
748                                 return rc;
749
750 #endif
751
752                 /* pass anything else to the current backend info/db config routine */
753                 } else {
754                         if ( bi != NULL ) {
755                                 if ( bi->bi_config == 0 ) {
756                                         Debug( LDAP_DEBUG_ANY,
757 "%s: line %d: unknown directive \"%s\" inside backend info definition (ignored)\n",
758                                                 fname, lineno, cargv[0] );
759                                 } else {
760                                         if ( (*bi->bi_config)( bi, fname, lineno, cargc, cargv )
761                                                 != 0 )
762                                         {
763                                                 return( 1 );
764                                         }
765                                 }
766                         } else if ( be != NULL ) {
767                                 if ( be->be_config == 0 ) {
768                                         Debug( LDAP_DEBUG_ANY,
769 "%s: line %d: unknown directive \"%s\" inside backend database definition (ignored)\n",
770                                         fname, lineno, cargv[0] );
771                                 } else {
772                                         if ( (*be->be_config)( be, fname, lineno, cargc, cargv )
773                                                 != 0 )
774                                         {
775                                                 return( 1 );
776                                         }
777                                 }
778                         } else {
779                                 Debug( LDAP_DEBUG_ANY,
780 "%s: line %d: unknown directive \"%s\" outside backend info and database definitions (ignored)\n",
781                                     fname, lineno, cargv[0] );
782                         }
783                 }
784                 free( saveline );
785         }
786         fclose( fp );
787         return( 0 );
788 }
789
790 static int
791 fp_parse_line(
792     char        *line,
793     int         *argcp,
794     char        **argv
795 )
796 {
797         char *  token;
798
799         *argcp = 0;
800         for ( token = strtok_quote( line, " \t" ); token != NULL;
801             token = strtok_quote( NULL, " \t" ) ) {
802                 if ( *argcp == MAXARGS ) {
803                         Debug( LDAP_DEBUG_ANY, "Too many tokens (max %d)\n",
804                             MAXARGS, 0, 0 );
805                         return( 1 );
806                 }
807                 argv[(*argcp)++] = token;
808         }
809         argv[*argcp] = NULL;
810         return 0;
811 }
812
813 static char *
814 strtok_quote( char *line, char *sep )
815 {
816         int             inquote;
817         char            *tmp;
818         static char     *next;
819
820         if ( line != NULL ) {
821                 next = line;
822         }
823         while ( *next && strchr( sep, *next ) ) {
824                 next++;
825         }
826
827         if ( *next == '\0' ) {
828                 next = NULL;
829                 return( NULL );
830         }
831         tmp = next;
832
833         for ( inquote = 0; *next; ) {
834                 switch ( *next ) {
835                 case '"':
836                         if ( inquote ) {
837                                 inquote = 0;
838                         } else {
839                                 inquote = 1;
840                         }
841                         SAFEMEMCPY( next, next + 1, strlen( next + 1 ) + 1 );
842                         break;
843
844                 case '\\':
845                         if ( next[1] )
846                                 SAFEMEMCPY( next,
847                                             next + 1, strlen( next + 1 ) + 1 );
848                         next++;         /* dont parse the escaped character */
849                         break;
850
851                 default:
852                         if ( ! inquote ) {
853                                 if ( strchr( sep, *next ) != NULL ) {
854                                         *next++ = '\0';
855                                         return( tmp );
856                                 }
857                         }
858                         next++;
859                         break;
860                 }
861         }
862
863         return( tmp );
864 }
865
866 static char     buf[BUFSIZ];
867 static char     *line;
868 static int      lmax, lcur;
869
870 #define CATLINE( buf )  { \
871         int     len; \
872         len = strlen( buf ); \
873         while ( lcur + len + 1 > lmax ) { \
874                 lmax += BUFSIZ; \
875                 line = (char *) ch_realloc( line, lmax ); \
876         } \
877         strcpy( line + lcur, buf ); \
878         lcur += len; \
879 }
880
881 static char *
882 fp_getline( FILE *fp, int *lineno )
883 {
884         char            *p;
885
886         lcur = 0;
887         CATLINE( buf );
888         (*lineno)++;
889
890         /* hack attack - keeps us from having to keep a stack of bufs... */
891         if ( strncasecmp( line, "include", 7 ) == 0 ) {
892                 buf[0] = '\0';
893                 return( line );
894         }
895
896         while ( fgets( buf, sizeof(buf), fp ) != NULL ) {
897                 if ( (p = strchr( buf, '\n' )) != NULL ) {
898                         *p = '\0';
899                 }
900                 if ( ! isspace( (unsigned char) buf[0] ) ) {
901                         return( line );
902                 }
903
904                 CATLINE( buf );
905                 (*lineno)++;
906         }
907         buf[0] = '\0';
908
909         return( line[0] ? line : NULL );
910 }
911
912 static void
913 fp_getline_init( int *lineno )
914 {
915         *lineno = -1;
916         buf[0] = '\0';
917 }