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