]> git.sur5r.net Git - openldap/blob - servers/slapd/config.c
Align with man page
[openldap] / servers / slapd / config.c
1 /* config.c - configuration file handling routines */
2 /* $OpenLDAP$ */
3 /*
4  * Copyright 1998-2000 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
12 #include <ac/string.h>
13 #include <ac/ctype.h>
14 #include <ac/socket.h>
15
16 #include "ldap_pvt.h"
17 #include "slap.h"
18
19 #define MAXARGS 128
20
21 /*
22  * defaults for various global variables
23  */
24 int             defsize = SLAPD_DEFAULT_SIZELIMIT;
25 int             deftime = SLAPD_DEFAULT_TIMELIMIT;
26 AccessControl   *global_acl = NULL;
27 slap_access_t           global_default_access = ACL_READ;
28 slap_mask_t             global_restrictops = 0;
29 slap_mask_t             global_disallows = 0;
30 slap_mask_t             global_requires = 0;
31 slap_ssf_set_t  global_ssf_set;
32 char            *replogfile;
33 int             global_lastmod = ON;
34 int             global_idletimeout = 0;
35 char    *global_realm = NULL;
36 char            *ldap_srvtab = "";
37 char            *default_passwd_hash;
38
39 char   *slapd_pid_file  = NULL;
40 char   *slapd_args_file = NULL;
41
42 static char     *fp_getline(FILE *fp, int *lineno);
43 static void     fp_getline_init(int *lineno);
44 static int      fp_parse_line(char *line, int *argcp, char **argv);
45
46 static char     *strtok_quote(char *line, char *sep);
47
48 int
49 read_config( const char *fname )
50 {
51         FILE    *fp;
52         char    *line, *savefname, *saveline;
53         int     cargc, savelineno;
54         char    *cargv[MAXARGS+1];
55         int     lineno, i;
56 #ifdef HAVE_TLS
57         int rc;
58 #endif
59         struct berval *vals[2];
60         struct berval val;
61
62         static BackendInfo *bi = NULL;
63         static BackendDB        *be = NULL;
64
65         vals[0] = &val;
66         vals[1] = NULL;
67
68         if ( (fp = fopen( fname, "r" )) == NULL ) {
69                 ldap_syslog = 1;
70                 Debug( LDAP_DEBUG_ANY,
71                     "could not open config file \"%s\" - absolute path?\n",
72                     fname, 0, 0 );
73                 perror( fname );
74                 return 1;
75         }
76
77         Debug( LDAP_DEBUG_CONFIG, "reading config file %s\n", fname, 0, 0 );
78
79         fp_getline_init( &lineno );
80
81         while ( (line = fp_getline( fp, &lineno )) != NULL ) {
82                 /* skip comments and blank lines */
83                 if ( line[0] == '#' || line[0] == '\0' ) {
84                         continue;
85                 }
86
87                 Debug( LDAP_DEBUG_CONFIG, "line %d (%s)\n", lineno, line, 0 );
88
89                 /* fp_parse_line is destructive, we save a copy */
90                 saveline = ch_strdup( line );
91
92                 if ( fp_parse_line( line, &cargc, cargv ) != 0 ) {
93                         return( 1 );
94                 }
95
96                 if ( cargc < 1 ) {
97                         Debug( LDAP_DEBUG_ANY,
98                             "%s: line %d: bad config line (ignored)\n",
99                             fname, lineno, 0 );
100                         continue;
101                 }
102
103                 if ( strcasecmp( cargv[0], "backend" ) == 0 ) {
104                         if ( cargc < 2 ) {
105                                 Debug( LDAP_DEBUG_ANY,
106                 "%s: line %d: missing type in \"backend <type>\" line\n",
107                                     fname, lineno, 0 );
108                                 return( 1 );
109                         }
110
111                         if( be != NULL ) {
112                                 Debug( LDAP_DEBUG_ANY,
113 "%s: line %d: backend line must appear before any database definition\n",
114                                     fname, lineno, 0 );
115                                 return( 1 );
116                         }
117
118                         bi = backend_info( cargv[1] );
119
120                         if( bi == NULL ) {
121                                 Debug( LDAP_DEBUG_ANY,
122                                         "backend %s initialization failed.\n",
123                                     cargv[1], 0, 0 );
124                                 return( 1 );
125                         }
126
127                 /* start of a new database definition */
128                 } else if ( strcasecmp( cargv[0], "database" ) == 0 ) {
129                         if ( cargc < 2 ) {
130                                 Debug( LDAP_DEBUG_ANY,
131                 "%s: line %d: missing type in \"database <type>\" line\n",
132                                     fname, lineno, 0 );
133                                 return( 1 );
134                         }
135
136                         bi = NULL;
137                         be = backend_db_init( cargv[1] );
138
139                         if( be == NULL ) {
140                                 Debug( LDAP_DEBUG_ANY,
141                                         "database %s initialization failed.\n",
142                                     cargv[1], 0, 0 );
143                                 return( 1 );
144                         }
145
146                 /* set thread concurrency */
147                 } else if ( strcasecmp( cargv[0], "concurrency" ) == 0 ) {
148                         int c;
149                         if ( cargc < 2 ) {
150                                 Debug( LDAP_DEBUG_ANY,
151             "%s: line %d: missing level in \"concurrency <level>\" line\n",
152                                     fname, lineno, 0 );
153                                 return( 1 );
154                         }
155
156                         c = atoi( cargv[1] );
157
158                         if( c < 1 ) {
159                                 Debug( LDAP_DEBUG_ANY,
160             "%s: line %d: invalid level (%d) in \"concurrency <level>\" line\n",
161                                     fname, lineno, c );
162                                 return( 1 );
163                         }
164
165                         ldap_pvt_thread_set_concurrency( c );
166
167                 /* set maximum threads in thread pool */
168                 } else if ( strcasecmp( cargv[0], "threads" ) == 0 ) {
169                         int c;
170                         if ( cargc < 2 ) {
171                                 Debug( LDAP_DEBUG_ANY,
172             "%s: line %d: missing count in \"threads <count>\" line\n",
173                                     fname, lineno, 0 );
174                                 return( 1 );
175                         }
176
177                         c = atoi( cargv[1] );
178
179                         if( c < 0 ) {
180                                 Debug( LDAP_DEBUG_ANY,
181             "%s: line %d: invalid level (%d) in \"threads <count>\" line\n",
182                                     fname, lineno, c );
183                                 return( 1 );
184                         }
185
186                         ldap_pvt_thread_pool_maxthreads( &connection_pool, c );
187
188                 /* get pid file name */
189                 } else if ( strcasecmp( cargv[0], "pidfile" ) == 0 ) {
190                         if ( cargc < 2 ) {
191                                 Debug( LDAP_DEBUG_ANY,
192             "%s: line %d: missing file name in \"pidfile <file>\" line\n",
193                                     fname, lineno, 0 );
194                                 return( 1 );
195                         }
196
197                         slapd_pid_file = ch_strdup( cargv[1] );
198
199                 /* get args file name */
200                 } else if ( strcasecmp( cargv[0], "argsfile" ) == 0 ) {
201                         if ( cargc < 2 ) {
202                                 Debug( LDAP_DEBUG_ANY,
203             "%s: line %d: missing file name in \"argsfile <file>\" line\n",
204                                     fname, lineno, 0 );
205                                 return( 1 );
206                         }
207
208                         slapd_args_file = ch_strdup( cargv[1] );
209
210                 /* default password hash */
211                 } else if ( strcasecmp( cargv[0], "password-hash" ) == 0 ) {
212                         if ( cargc < 2 ) {
213                                 Debug( LDAP_DEBUG_ANY,
214             "%s: line %d: missing hash in \"password-hash <hash>\" line\n",
215                                     fname, lineno, 0 );
216                                 return( 1 );
217                         }
218                         if ( default_passwd_hash != NULL ) {
219                                 Debug( LDAP_DEBUG_ANY,
220                                         "%s: line %d: already set default password_hash!\n",
221                                         fname, lineno, 0 );
222                                 return 1;
223
224                         } else {
225                                 default_passwd_hash = ch_strdup( cargv[1] );
226                         }
227
228                 /* set SASL realm */
229                 } else if ( strcasecmp( cargv[0], "sasl-realm" ) == 0 ) {
230                         if ( cargc < 2 ) {
231                                 Debug( LDAP_DEBUG_ANY,
232             "%s: line %d: missing realm in \"sasl-realm <realm>\" line\n",
233                                     fname, lineno, 0 );
234                                 return( 1 );
235                         }
236                         if ( be != NULL ) {
237                                 be->be_realm = ch_strdup( cargv[1] );
238
239                         } else if ( global_realm != NULL ) {
240                                 Debug( LDAP_DEBUG_ANY,
241                                         "%s: line %d: already set global realm!\n",
242                                         fname, lineno, 0 );
243                                 return 1;
244
245                         } else {
246                                 global_realm = ch_strdup( cargv[1] );
247                         }
248
249                 /* SASL security properties */
250                 } else if ( strcasecmp( cargv[0], "sasl-secprops" ) == 0 ) {
251                         char *txt;
252
253                         if ( cargc < 2 ) {
254                                 Debug( LDAP_DEBUG_ANY,
255             "%s: line %d: missing flags in \"sasl-secprops <properties>\" line\n",
256                                     fname, lineno, 0 );
257                                 return 1;
258                         }
259
260                         txt = slap_sasl_secprops( cargv[1] );
261                         if ( txt != NULL ) {
262                                 Debug( LDAP_DEBUG_ANY,
263             "%s: line %d: sasl-secprops: %s\n",
264                                     fname, lineno, txt );
265                                 return 1;
266                         }
267
268                 /* set time limit */
269                 } else if ( strcasecmp( cargv[0], "sizelimit" ) == 0 ) {
270                         if ( cargc < 2 ) {
271                                 Debug( LDAP_DEBUG_ANY,
272             "%s: line %d: missing limit in \"sizelimit <limit>\" line\n",
273                                     fname, lineno, 0 );
274                                 return( 1 );
275                         }
276                         if ( be == NULL ) {
277                                 defsize = atoi( cargv[1] );
278                         } else {
279                                 be->be_sizelimit = atoi( cargv[1] );
280                         }
281
282                 /* set time limit */
283                 } else if ( strcasecmp( cargv[0], "timelimit" ) == 0 ) {
284                         if ( cargc < 2 ) {
285                                 Debug( LDAP_DEBUG_ANY,
286             "%s: line %d: missing limit in \"timelimit <limit>\" line\n",
287                                     fname, lineno, 0 );
288                                 return( 1 );
289                         }
290                         if ( be == NULL ) {
291                                 deftime = atoi( cargv[1] );
292                         } else {
293                                 be->be_timelimit = atoi( cargv[1] );
294                         }
295
296                 /* set database suffix */
297                 } else if ( strcasecmp( cargv[0], "suffix" ) == 0 ) {
298                         Backend *tmp_be;
299                         if ( cargc < 2 ) {
300                                 Debug( LDAP_DEBUG_ANY,
301                     "%s: line %d: missing dn in \"suffix <dn>\" line\n",
302                                     fname, lineno, 0 );
303                                 return( 1 );
304                         } else if ( cargc > 2 ) {
305                                 Debug( LDAP_DEBUG_ANY,
306     "%s: line %d: extra cruft after <dn> in \"suffix %s\" line (ignored)\n",
307                                     fname, lineno, cargv[1] );
308                         }
309                         if ( be == NULL ) {
310                                 Debug( LDAP_DEBUG_ANY,
311 "%s: line %d: suffix line must appear inside a database definition (ignored)\n",
312                                     fname, lineno, 0 );
313                         } else if ( ( tmp_be = select_backend( cargv[1] ) ) == be ) {
314                                 Debug( LDAP_DEBUG_ANY,
315 "%s: line %d: suffix already served by this backend (ignored)\n",
316                                     fname, lineno, 0 );
317                         } else if ( tmp_be  != NULL ) {
318                                 Debug( LDAP_DEBUG_ANY,
319 "%s: line %d: suffix already served by a preceeding backend \"%s\" (ignored)\n",
320                                     fname, lineno, tmp_be->be_suffix[0] );
321                         } else {
322                                 char *dn = ch_strdup( cargv[1] );
323                                 (void) dn_validate( dn );
324                                 charray_add( &be->be_suffix, dn );
325                                 (void) ldap_pvt_str2upper( dn );
326                                 charray_add( &be->be_nsuffix, dn );
327                                 free( dn );
328                         }
329
330                 /* set database suffixAlias */
331                 } else if ( strcasecmp( cargv[0], "suffixAlias" ) == 0 ) {
332                         Backend *tmp_be;
333                         if ( cargc < 2 ) {
334                                 Debug( LDAP_DEBUG_ANY,
335 "%s: line %d: missing alias and aliased_dn in \"suffixAlias <alias> <aliased_dn>\" line\n",
336                                         fname, lineno, 0 );
337                                 return( 1 );
338                         } else if ( cargc < 3 ) {
339                                 Debug( LDAP_DEBUG_ANY,
340 "%s: line %d: missing aliased_dn in \"suffixAlias <alias> <aliased_dn>\" line\n",
341                                 fname, lineno, 0 );
342                                 return( 1 );
343                         } else if ( cargc > 3 ) {
344                                 Debug( LDAP_DEBUG_ANY,
345                                         "%s: line %d: extra cruft in suffixAlias line (ignored)\n",
346                                 fname, lineno, 0 );
347                         }
348
349                         if ( be == NULL ) {
350                                 Debug( LDAP_DEBUG_ANY,
351                                         "%s: line %d: suffixAlias line"
352                                         " must appear inside a database definition (ignored)\n",
353                                         fname, lineno, 0 );
354                         } else if ( (tmp_be = select_backend( cargv[1] )) != NULL ) {
355                                 Debug( LDAP_DEBUG_ANY,
356                                         "%s: line %d: suffixAlias served by"
357                                         "  a preceeding backend \"%s\" (ignored)\n",
358                                         fname, lineno, tmp_be->be_suffix[0] );
359
360                         } else if ( (tmp_be = select_backend( cargv[2] )) != NULL ) {
361                                 Debug( LDAP_DEBUG_ANY,
362                                         "%s: line %d: suffixAlias derefs to differnet backend"
363                                         "  a preceeding backend \"%s\" (ignored)\n",
364                                         fname, lineno, tmp_be->be_suffix[0] );
365
366                         } else {
367                                 char *alias, *aliased_dn;
368
369                                 alias = ch_strdup( cargv[1] );
370                                 (void) dn_normalize( alias );
371
372                                 aliased_dn = ch_strdup( cargv[2] );
373                                 (void) dn_normalize( aliased_dn );
374
375                                 charray_add( &be->be_suffixAlias, alias );
376                                 charray_add( &be->be_suffixAlias, aliased_dn );
377
378                                 free(alias);
379                                 free(aliased_dn);
380                         }
381
382                /* set max deref depth */
383                } else if ( strcasecmp( cargv[0], "maxDerefDepth" ) == 0 ) {
384                                         int i;
385                        if ( cargc < 2 ) {
386                                Debug( LDAP_DEBUG_ANY,
387                    "%s: line %d: missing depth in \"maxDerefDepth <depth>\" line\n",
388                                    fname, lineno, 0 );
389                                return( 1 );
390                        }
391                        if ( be == NULL ) {
392                                Debug( LDAP_DEBUG_ANY,
393 "%s: line %d: depth line must appear inside a database definition (ignored)\n",
394                                    fname, lineno, 0 );
395                        } else if ((i = atoi(cargv[1])) < 0) {
396                                Debug( LDAP_DEBUG_ANY,
397 "%s: line %d: depth must be positive (ignored)\n",
398                                    fname, lineno, 0 );
399
400                        } else {
401                            be->be_max_deref_depth = i;
402                                            }
403
404
405                 /* set magic "root" dn for this database */
406                 } else if ( strcasecmp( cargv[0], "rootdn" ) == 0 ) {
407                         if ( cargc < 2 ) {
408                                 Debug( LDAP_DEBUG_ANY,
409                     "%s: line %d: missing dn in \"rootdn <dn>\" line\n",
410                                     fname, lineno, 0 );
411                                 return( 1 );
412                         }
413                         if ( be == NULL ) {
414                                 Debug( LDAP_DEBUG_ANY,
415 "%s: line %d: rootdn line must appear inside a database definition (ignored)\n",
416                                     fname, lineno, 0 );
417                         } else {
418                                 be->be_root_dn = ch_strdup( cargv[1] );
419                                 be->be_root_ndn = ch_strdup( cargv[1] );
420
421                                 if( dn_normalize( be->be_root_ndn ) == NULL ) {
422                                         free( be->be_root_dn );
423                                         free( be->be_root_ndn );
424                                         Debug( LDAP_DEBUG_ANY,
425 "%s: line %d: rootdn DN is invalid\n",
426                                            fname, lineno, 0 );
427                                         return( 1 );
428                                 }
429                         }
430
431                 /* set super-secret magic database password */
432                 } else if ( strcasecmp( cargv[0], "rootpw" ) == 0 ) {
433                         if ( cargc < 2 ) {
434                                 Debug( LDAP_DEBUG_ANY,
435             "%s: line %d: missing passwd in \"rootpw <passwd>\" line\n",
436                                     fname, lineno, 0 );
437                                 return( 1 );
438                         }
439                         if ( be == NULL ) {
440                                 Debug( LDAP_DEBUG_ANY,
441 "%s: line %d: rootpw line must appear inside a database definition (ignored)\n",
442                                     fname, lineno, 0 );
443                         } else {
444                                 be->be_root_pw.bv_val = ch_strdup( cargv[1] );
445                                 be->be_root_pw.bv_len = strlen( be->be_root_pw.bv_val );
446                         }
447
448                 /* make this database read-only */
449                 } else if ( strcasecmp( cargv[0], "readonly" ) == 0 ) {
450                         if ( cargc < 2 ) {
451                                 Debug( LDAP_DEBUG_ANY,
452             "%s: line %d: missing on|off in \"readonly <on|off>\" line\n",
453                                     fname, lineno, 0 );
454                                 return( 1 );
455                         }
456                         if ( be == NULL ) {
457                                 if ( strcasecmp( cargv[1], "on" ) == 0 ) {
458                                         global_restrictops |= SLAP_RESTRICT_OP_WRITES;
459                                 } else {
460                                         global_restrictops &= ~SLAP_RESTRICT_OP_WRITES;
461                                 }
462                         } else {
463                                 if ( strcasecmp( cargv[1], "on" ) == 0 ) {
464                                         be->be_restrictops |= SLAP_RESTRICT_OP_WRITES;
465                                 } else {
466                                         be->be_restrictops &= ~SLAP_RESTRICT_OP_WRITES;
467                                 }
468                         }
469
470
471                 /* disallow these features */
472                 } else if ( strcasecmp( cargv[0], "disallows" ) == 0 ||
473                         strcasecmp( cargv[0], "disallow" ) == 0 )
474                 {
475                         slap_mask_t     disallows;
476
477                         if ( be != NULL ) {
478                                 Debug( LDAP_DEBUG_ANY,
479 "%s: line %d: disallow line must appear prior to database definitions\n",
480                                     fname, lineno, 0 );
481                         }
482
483                         if ( cargc < 2 ) {
484                                 Debug( LDAP_DEBUG_ANY,
485             "%s: line %d: missing feature(s) in \"disallows <features>\" line\n",
486                                     fname, lineno, 0 );
487                                 return( 1 );
488                         }
489
490                         disallows = 0;
491
492                         for( i=1; i < cargc; i++ ) {
493                                 if( strcasecmp( cargv[i], "bind_v2" ) == 0 ) {
494                                         disallows |= SLAP_DISALLOW_BIND_V2;
495
496                                 } else if( strcasecmp( cargv[i], "bind_anon_cred" ) == 0 ) {
497                                         disallows |= SLAP_DISALLOW_BIND_ANON_CRED;
498
499                                 } else if( strcasecmp( cargv[i], "bind_anon_dn" ) == 0 ) {
500                                         disallows |= SLAP_DISALLOW_BIND_ANON_DN;
501
502                                 } else if( strcasecmp( cargv[i], "none" ) != 0 ) {
503                                         Debug( LDAP_DEBUG_ANY,
504                     "%s: line %d: unknown feature %s in \"disallow <features>\" line\n",
505                                             fname, lineno, cargv[i] );
506                                         return( 1 );
507                                 }
508                         }
509
510                         global_disallows = disallows;
511
512                 /* require these features */
513                 } else if ( strcasecmp( cargv[0], "requires" ) == 0 ||
514                         strcasecmp( cargv[0], "require" ) == 0 )
515                 {
516                         slap_mask_t     requires;
517
518                         if ( cargc < 2 ) {
519                                 Debug( LDAP_DEBUG_ANY,
520             "%s: line %d: missing feature(s) in \"require <features>\" line\n",
521                                     fname, lineno, 0 );
522                                 return( 1 );
523                         }
524
525                         requires = 0;
526
527                         for( i=1; i < cargc; i++ ) {
528                                 if( strcasecmp( cargv[i], "bind" ) == 0 ) {
529                                         requires |= SLAP_REQUIRE_BIND;
530
531                                 } else if( strcasecmp( cargv[i], "LDAPv3" ) == 0 ) {
532                                         requires |= SLAP_REQUIRE_LDAP_V3;
533
534                                 } else if( strcasecmp( cargv[i], "authc" ) == 0 ) {
535                                         requires |= SLAP_REQUIRE_AUTHC;
536
537                                 } else if( strcasecmp( cargv[i], "SASL" ) == 0 ) {
538                                         requires |= SLAP_REQUIRE_SASL;
539
540                                 } else if( strcasecmp( cargv[i], "strong" ) == 0 ) {
541                                         requires |= SLAP_REQUIRE_STRONG;
542
543                                 } else if( strcasecmp( cargv[i], "none" ) != 0 ) {
544                                         Debug( LDAP_DEBUG_ANY,
545                     "%s: line %d: unknown feature %s in \"require <features>\" line\n",
546                                             fname, lineno, cargv[i] );
547                                         return( 1 );
548                                 }
549                         }
550
551                         if ( be == NULL ) {
552                                 global_requires = requires;
553                         } else {
554                                 be->be_requires = requires;
555                         }
556
557                 /* required security factors */
558                 } else if ( strcasecmp( cargv[0], "security" ) == 0 ) {
559                         slap_ssf_set_t *set;
560
561                         if ( cargc < 2 ) {
562                                 Debug( LDAP_DEBUG_ANY,
563             "%s: line %d: missing factor(s) in \"security <factors>\" line\n",
564                                     fname, lineno, 0 );
565                                 return( 1 );
566                         }
567
568                         if ( be == NULL ) {
569                                 set = &global_ssf_set;
570                         } else {
571                                 set = &be->be_ssf_set;
572                         }
573
574                         for( i=1; i < cargc; i++ ) {
575                                 if( strncasecmp( cargv[i], "ssf=",
576                                         sizeof("ssf") ) == 0 )
577                                 {
578                                         set->sss_ssf =
579                                                 atoi( &cargv[i][sizeof("ssf")] );
580
581                                 } else if( strncasecmp( cargv[i], "transport=",
582                                         sizeof("transport") ) == 0 )
583                                 {
584                                         set->sss_transport =
585                                                 atoi( &cargv[i][sizeof("transport")] );
586
587                                 } else if( strncasecmp( cargv[i], "tls=",
588                                         sizeof("tls") ) == 0 )
589                                 {
590                                         set->sss_tls =
591                                                 atoi( &cargv[i][sizeof("tls")] );
592
593                                 } else if( strncasecmp( cargv[i], "sasl=",
594                                         sizeof("sasl") ) == 0 )
595                                 {
596                                         set->sss_sasl =
597                                                 atoi( &cargv[i][sizeof("sasl")] );
598
599                                 } else if( strncasecmp( cargv[i], "update_ssf=",
600                                         sizeof("update_ssf") ) == 0 )
601                                 {
602                                         set->sss_update_ssf =
603                                                 atoi( &cargv[i][sizeof("update_ssf")] );
604
605                                 } else if( strncasecmp( cargv[i], "update_transport=",
606                                         sizeof("update_transport") ) == 0 )
607                                 {
608                                         set->sss_update_transport =
609                                                 atoi( &cargv[i][sizeof("update_transport")] );
610
611                                 } else if( strncasecmp( cargv[i], "update_tls=",
612                                         sizeof("update_tls") ) == 0 )
613                                 {
614                                         set->sss_update_tls =
615                                                 atoi( &cargv[i][sizeof("update_tls")] );
616
617                                 } else if( strncasecmp( cargv[i], "update_sasl=",
618                                         sizeof("update_sasl") ) == 0 )
619                                 {
620                                         set->sss_update_sasl =
621                                                 atoi( &cargv[i][sizeof("update_sasl")] );
622
623                                 } else {
624                                         Debug( LDAP_DEBUG_ANY,
625                     "%s: line %d: unknown factor %s in \"security <factors>\" line\n",
626                                             fname, lineno, cargv[i] );
627                                         return( 1 );
628                                 }
629                         }
630
631                 
632                 /* where to send clients when we don't hold it */
633                 } else if ( strcasecmp( cargv[0], "referral" ) == 0 ) {
634                         if ( cargc < 2 ) {
635                                 Debug( LDAP_DEBUG_ANY,
636                     "%s: line %d: missing URL in \"referral <URL>\" line\n",
637                                     fname, lineno, 0 );
638                                 return( 1 );
639                         }
640
641                         vals[0]->bv_val = cargv[1];
642                         vals[0]->bv_len = strlen( vals[0]->bv_val );
643                         value_add( &default_referral, vals );
644
645                 /* specify an Object Identifier macro */
646                 } else if ( strcasecmp( cargv[0], "objectidentifier" ) == 0 ) {
647                         parse_oidm( fname, lineno, cargc, cargv );
648
649                 /* specify an objectclass */
650                 } else if ( strcasecmp( cargv[0], "objectclass" ) == 0 ) {
651                         if ( *cargv[1] == '(' ) {
652                                 char * p;
653                                 p = strchr(saveline,'(');
654                                 parse_oc( fname, lineno, p, cargv );
655                         } else {
656                                 Debug( LDAP_DEBUG_ANY,
657     "%s: line %d: old objectclass format not supported.\n",
658                                     fname, lineno, 0 );
659                         }
660
661                 /* specify an attribute type */
662                 } else if (( strcasecmp( cargv[0], "attributetype" ) == 0 )
663                         || ( strcasecmp( cargv[0], "attribute" ) == 0 ))
664                 {
665                         if ( *cargv[1] == '(' ) {
666                                 char * p;
667                                 p = strchr(saveline,'(');
668                                 parse_at( fname, lineno, p, cargv );
669                         } else {
670                                 Debug( LDAP_DEBUG_ANY,
671     "%s: line %d: old attribute type format not supported.\n",
672                                     fname, lineno, 0 );
673                         }
674
675                 /* turn on/off schema checking */
676                 } else if ( strcasecmp( cargv[0], "schemacheck" ) == 0 ) {
677                         if ( cargc < 2 ) {
678                                 Debug( LDAP_DEBUG_ANY,
679     "%s: line %d: missing on|off in \"schemacheck <on|off>\" line\n",
680                                     fname, lineno, 0 );
681                                 return( 1 );
682                         }
683                         if ( strcasecmp( cargv[1], "off" ) == 0 ) {
684                                 global_schemacheck = 0;
685                         } else {
686                                 global_schemacheck = 1;
687                         }
688
689                 /* specify access control info */
690                 } else if ( strcasecmp( cargv[0], "access" ) == 0 ) {
691                         parse_acl( be, fname, lineno, cargc, cargv );
692
693                 /* specify default access control info */
694                 } else if ( strcasecmp( cargv[0], "defaultaccess" ) == 0 ) {
695                         slap_access_t access;
696
697                         if ( cargc < 2 ) {
698                                 Debug( LDAP_DEBUG_ANY,
699             "%s: line %d: missing limit in \"defaultaccess <access>\" line\n",
700                                     fname, lineno, 0 );
701                                 return( 1 );
702                         }
703
704                         access = str2access( cargv[1] );
705
706                         if ( access == ACL_INVALID_ACCESS ) {
707                                 Debug( LDAP_DEBUG_ANY,
708                                         "%s: line %d: bad access level \"%s\", "
709                                         "expecting none|auth|compare|search|read|write\n",
710                                     fname, lineno, cargv[1] );
711                                 return( 1 );
712                         }
713
714                         if ( be == NULL ) {
715                                 global_default_access = access;
716                         } else {
717                                 be->be_dfltaccess = access;
718                         }
719
720                 /* debug level to log things to syslog */
721                 } else if ( strcasecmp( cargv[0], "loglevel" ) == 0 ) {
722                         if ( cargc < 2 ) {
723                                 Debug( LDAP_DEBUG_ANY,
724                     "%s: line %d: missing level in \"loglevel <level>\" line\n",
725                                     fname, lineno, 0 );
726                                 return( 1 );
727                         }
728
729                         ldap_syslog = 0;
730
731                         for( i=1; i < cargc; i++ ) {
732                                 ldap_syslog += atoi( cargv[1] );
733                         }
734
735                 /* list of replicas of the data in this backend (master only) */
736                 } else if ( strcasecmp( cargv[0], "replica" ) == 0 ) {
737                         if ( cargc < 2 ) {
738                                 Debug( LDAP_DEBUG_ANY,
739             "%s: line %d: missing host in \"replica <host[:port]>\" line\n",
740                                     fname, lineno, 0 );
741                                 return( 1 );
742                         }
743                         if ( be == NULL ) {
744                                 Debug( LDAP_DEBUG_ANY,
745 "%s: line %d: replica line must appear inside a database definition (ignored)\n",
746                                     fname, lineno, 0 );
747                         } else {
748                                 for ( i = 1; i < cargc; i++ ) {
749                                         if ( strncasecmp( cargv[i], "host=", 5 )
750                                             == 0 ) {
751                                                 charray_add( &be->be_replica,
752                                                              cargv[i] + 5 );
753                                                 break;
754                                         }
755                                 }
756                                 if ( i == cargc ) {
757                                         Debug( LDAP_DEBUG_ANY,
758                     "%s: line %d: missing host in \"replica\" line (ignored)\n",
759                                             fname, lineno, 0 );
760                                 }
761                         }
762
763                 /* dn of master entity allowed to write to replica */
764                 } else if ( strcasecmp( cargv[0], "updatedn" ) == 0 ) {
765                         if ( cargc < 2 ) {
766                                 Debug( LDAP_DEBUG_ANY,
767                     "%s: line %d: missing dn in \"updatedn <dn>\" line\n",
768                                     fname, lineno, 0 );
769                                 return( 1 );
770                         }
771                         if ( be == NULL ) {
772                                 Debug( LDAP_DEBUG_ANY,
773 "%s: line %d: updatedn line must appear inside a database definition (ignored)\n",
774                                     fname, lineno, 0 );
775                         } else {
776                                 be->be_update_ndn = ch_strdup( cargv[1] );
777                                 if( dn_normalize( be->be_update_ndn ) == NULL ) {
778                                         Debug( LDAP_DEBUG_ANY,
779 "%s: line %d: updatedn DN is invalid\n",
780                                             fname, lineno, 0 );
781                                         return 1;
782                                 }
783                         }
784
785                 } else if ( strcasecmp( cargv[0], "updateref" ) == 0 ) {
786                         if ( cargc < 2 ) {
787                                 Debug( LDAP_DEBUG_ANY,
788                     "%s: line %d: missing dn in \"updateref <ldapurl>\" line\n",
789                                     fname, lineno, 0 );
790                                 return( 1 );
791                         }
792                         if ( be == NULL ) {
793                                 Debug( LDAP_DEBUG_ANY,
794 "%s: line %d: updateref line must appear inside a database definition (ignored)\n",
795                                     fname, lineno, 0 );
796                         } else if ( be->be_update_ndn == NULL ) {
797                                 Debug( LDAP_DEBUG_ANY,
798 "%s: line %d: updateref line must after updatedn (ignored)\n",
799                                     fname, lineno, 0 );
800                         } else {
801                                 vals[0]->bv_val = cargv[1];
802                                 vals[0]->bv_len = strlen( vals[0]->bv_val );
803                                 value_add( &be->be_update_refs, vals );
804                         }
805
806                 /* replication log file to which changes are appended */
807                 } else if ( strcasecmp( cargv[0], "replogfile" ) == 0 ) {
808                         if ( cargc < 2 ) {
809                                 Debug( LDAP_DEBUG_ANY,
810             "%s: line %d: missing dn in \"replogfile <filename>\" line\n",
811                                     fname, lineno, 0 );
812                                 return( 1 );
813                         }
814                         if ( be ) {
815                                 be->be_replogfile = ch_strdup( cargv[1] );
816                         } else {
817                                 replogfile = ch_strdup( cargv[1] );
818                         }
819
820                 /* maintain lastmodified{by,time} attributes */
821                 } else if ( strcasecmp( cargv[0], "lastmod" ) == 0 ) {
822                         if ( cargc < 2 ) {
823                                 Debug( LDAP_DEBUG_ANY,
824             "%s: line %d: missing on|off in \"lastmod <on|off>\" line\n",
825                                     fname, lineno, 0 );
826                                 return( 1 );
827                         }
828                         if ( strcasecmp( cargv[1], "on" ) == 0 ) {
829                                 if ( be )
830                                         be->be_lastmod = ON;
831                                 else
832                                         global_lastmod = ON;
833                         } else {
834                                 if ( be )
835                                         be->be_lastmod = OFF;
836                                 else
837                                         global_lastmod = OFF;
838                         }
839
840                 /* set idle timeout value */
841                 } else if ( strcasecmp( cargv[0], "idletimeout" ) == 0 ) {
842                         int i;
843                         if ( cargc < 2 ) {
844                                 Debug( LDAP_DEBUG_ANY,
845             "%s: line %d: missing timeout value in \"idletimeout <seconds>\" line\n",
846                                     fname, lineno, 0 );
847                                 return( 1 );
848                         }
849
850                         i = atoi( cargv[1] );
851
852                         if( i < 0 ) {
853                                 Debug( LDAP_DEBUG_ANY,
854             "%s: line %d: timeout value (%d) invalid \"idletimeout <seconds>\" line\n",
855                                     fname, lineno, i );
856                                 return( 1 );
857                         }
858
859                         global_idletimeout = i;
860
861                 /* include another config file */
862                 } else if ( strcasecmp( cargv[0], "include" ) == 0 ) {
863                         if ( cargc < 2 ) {
864                                 Debug( LDAP_DEBUG_ANY,
865     "%s: line %d: missing filename in \"include <filename>\" line\n",
866                                     fname, lineno, 0 );
867                                 return( 1 );
868                         }
869                         savefname = ch_strdup( cargv[1] );
870                         savelineno = lineno;
871
872                         if ( read_config( savefname ) != 0 ) {
873                                 return( 1 );
874                         }
875
876                         free( savefname );
877                         lineno = savelineno - 1;
878
879                 /* location of kerberos srvtab file */
880                 } else if ( strcasecmp( cargv[0], "srvtab" ) == 0 ) {
881                         if ( cargc < 2 ) {
882                                 Debug( LDAP_DEBUG_ANY,
883             "%s: line %d: missing filename in \"srvtab <filename>\" line\n",
884                                     fname, lineno, 0 );
885                                 return( 1 );
886                         }
887                         ldap_srvtab = ch_strdup( cargv[1] );
888
889 #ifdef SLAPD_MODULES
890                 } else if (strcasecmp( cargv[0], "moduleload") == 0 ) {
891                    if ( cargc < 2 ) {
892                       Debug( LDAP_DEBUG_ANY,
893                              "%s: line %d: missing filename in \"moduleload <filename>\" line\n",
894                              fname, lineno, 0 );
895                       exit( EXIT_FAILURE );
896                    }
897                    if (module_load(cargv[1], cargc - 2, (cargc > 2) ? cargv + 2 : NULL)) {
898                       Debug( LDAP_DEBUG_ANY,
899                              "%s: line %d: failed to load or initialize module %s\n",
900                              fname, lineno, cargv[1]);
901                       exit( EXIT_FAILURE );
902                    }
903                 } else if (strcasecmp( cargv[0], "modulepath") == 0 ) {
904                    if ( cargc != 2 ) {
905                       Debug( LDAP_DEBUG_ANY,
906                              "%s: line %d: missing path in \"modulepath <path>\" line\n",
907                              fname, lineno, 0 );
908                       exit( EXIT_FAILURE );
909                    }
910                    if (module_path( cargv[1] )) {
911                       Debug( LDAP_DEBUG_ANY,
912                              "%s: line %d: failed to set module search path to %s\n",
913                              fname, lineno, cargv[1]);
914                       exit( EXIT_FAILURE );
915                    }
916                    
917 #endif /*SLAPD_MODULES*/
918
919 #ifdef HAVE_TLS
920                 } else if ( !strcasecmp( cargv[0], "TLSProtocol" ) ) {
921                         rc = ldap_pvt_tls_set_option( NULL,
922                                                       LDAP_OPT_X_TLS_PROTOCOL,
923                                                       cargv[1] );
924                         if ( rc )
925                                 return rc;
926
927                 } else if ( !strcasecmp( cargv[0], "TLSCipherSuite" ) ) {
928                         rc = ldap_pvt_tls_set_option( NULL,
929                                                       LDAP_OPT_X_TLS_CIPHER_SUITE,
930                                                       cargv[1] );
931                         if ( rc )
932                                 return rc;
933
934                 } else if ( !strcasecmp( cargv[0], "TLSCertificateFile" ) ) {
935                         rc = ldap_pvt_tls_set_option( NULL,
936                                                       LDAP_OPT_X_TLS_CERTFILE,
937                                                       cargv[1] );
938                         if ( rc )
939                                 return rc;
940
941                 } else if ( !strcasecmp( cargv[0], "TLSCertificateKeyFile" ) ) {
942                         rc = ldap_pvt_tls_set_option( NULL,
943                                                       LDAP_OPT_X_TLS_KEYFILE,
944                                                       cargv[1] );
945                         if ( rc )
946                                 return rc;
947
948                 } else if ( !strcasecmp( cargv[0], "TLSCACertificatePath" ) ) {
949                         rc = ldap_pvt_tls_set_option( NULL,
950                                                       LDAP_OPT_X_TLS_CACERTDIR,
951                                                       cargv[1] );
952                         if ( rc )
953                                 return rc;
954
955                 } else if ( !strcasecmp( cargv[0], "TLSCACertificateFile" ) ) {
956                         rc = ldap_pvt_tls_set_option( NULL,
957                                                       LDAP_OPT_X_TLS_CACERTFILE,
958                                                       cargv[1] );
959                         if ( rc )
960                                 return rc;
961                 } else if ( !strcasecmp( cargv[0], "TLSVerifyClient" ) ) {
962                         rc = ldap_pvt_tls_set_option( NULL,
963                                                       LDAP_OPT_X_TLS_REQUIRE_CERT,
964                                                       cargv[1] );
965                         if ( rc )
966                                 return rc;
967
968 #endif
969
970                 /* pass anything else to the current backend info/db config routine */
971                 } else {
972                         if ( bi != NULL ) {
973                                 if ( bi->bi_config == 0 ) {
974                                         Debug( LDAP_DEBUG_ANY,
975 "%s: line %d: unknown directive \"%s\" inside backend info definition (ignored)\n",
976                                                 fname, lineno, cargv[0] );
977                                 } else {
978                                         if ( (*bi->bi_config)( bi, fname, lineno, cargc, cargv )
979                                                 != 0 )
980                                         {
981                                                 return( 1 );
982                                         }
983                                 }
984                         } else if ( be != NULL ) {
985                                 if ( be->be_config == 0 ) {
986                                         Debug( LDAP_DEBUG_ANY,
987 "%s: line %d: unknown directive \"%s\" inside backend database definition (ignored)\n",
988                                         fname, lineno, cargv[0] );
989                                 } else {
990                                         if ( (*be->be_config)( be, fname, lineno, cargc, cargv )
991                                                 != 0 )
992                                         {
993                                                 return( 1 );
994                                         }
995                                 }
996                         } else {
997                                 Debug( LDAP_DEBUG_ANY,
998 "%s: line %d: unknown directive \"%s\" outside backend info and database definitions (ignored)\n",
999                                     fname, lineno, cargv[0] );
1000                         }
1001                 }
1002                 free( saveline );
1003         }
1004         fclose( fp );
1005         return( 0 );
1006 }
1007
1008 static int
1009 fp_parse_line(
1010     char        *line,
1011     int         *argcp,
1012     char        **argv
1013 )
1014 {
1015         char *  token;
1016
1017         *argcp = 0;
1018         for ( token = strtok_quote( line, " \t" ); token != NULL;
1019             token = strtok_quote( NULL, " \t" ) ) {
1020                 if ( *argcp == MAXARGS ) {
1021                         Debug( LDAP_DEBUG_ANY, "Too many tokens (max %d)\n",
1022                             MAXARGS, 0, 0 );
1023                         return( 1 );
1024                 }
1025                 argv[(*argcp)++] = token;
1026         }
1027         argv[*argcp] = NULL;
1028         return 0;
1029 }
1030
1031 static char *
1032 strtok_quote( char *line, char *sep )
1033 {
1034         int             inquote;
1035         char            *tmp;
1036         static char     *next;
1037
1038         if ( line != NULL ) {
1039                 next = line;
1040         }
1041         while ( *next && strchr( sep, *next ) ) {
1042                 next++;
1043         }
1044
1045         if ( *next == '\0' ) {
1046                 next = NULL;
1047                 return( NULL );
1048         }
1049         tmp = next;
1050
1051         for ( inquote = 0; *next; ) {
1052                 switch ( *next ) {
1053                 case '"':
1054                         if ( inquote ) {
1055                                 inquote = 0;
1056                         } else {
1057                                 inquote = 1;
1058                         }
1059                         AC_MEMCPY( next, next + 1, strlen( next + 1 ) + 1 );
1060                         break;
1061
1062                 case '\\':
1063                         if ( next[1] )
1064                                 AC_MEMCPY( next,
1065                                             next + 1, strlen( next + 1 ) + 1 );
1066                         next++;         /* dont parse the escaped character */
1067                         break;
1068
1069                 default:
1070                         if ( ! inquote ) {
1071                                 if ( strchr( sep, *next ) != NULL ) {
1072                                         *next++ = '\0';
1073                                         return( tmp );
1074                                 }
1075                         }
1076                         next++;
1077                         break;
1078                 }
1079         }
1080
1081         return( tmp );
1082 }
1083
1084 static char     buf[BUFSIZ];
1085 static char     *line;
1086 static int      lmax, lcur;
1087
1088 #define CATLINE( buf )  { \
1089         int     len; \
1090         len = strlen( buf ); \
1091         while ( lcur + len + 1 > lmax ) { \
1092                 lmax += BUFSIZ; \
1093                 line = (char *) ch_realloc( line, lmax ); \
1094         } \
1095         strcpy( line + lcur, buf ); \
1096         lcur += len; \
1097 }
1098
1099 static char *
1100 fp_getline( FILE *fp, int *lineno )
1101 {
1102         char            *p;
1103
1104         lcur = 0;
1105         CATLINE( buf );
1106         (*lineno)++;
1107
1108         /* hack attack - keeps us from having to keep a stack of bufs... */
1109         if ( strncasecmp( line, "include", 7 ) == 0 ) {
1110                 buf[0] = '\0';
1111                 return( line );
1112         }
1113
1114         while ( fgets( buf, sizeof(buf), fp ) != NULL ) {
1115                 if ( (p = strchr( buf, '\n' )) != NULL ) {
1116                         *p = '\0';
1117                 }
1118                 if ( ! isspace( (unsigned char) buf[0] ) ) {
1119                         return( line );
1120                 }
1121
1122                 CATLINE( buf );
1123                 (*lineno)++;
1124         }
1125         buf[0] = '\0';
1126
1127         return( line[0] ? line : NULL );
1128 }
1129
1130 static void
1131 fp_getline_init( int *lineno )
1132 {
1133         *lineno = -1;
1134         buf[0] = '\0';
1135 }