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