]> git.sur5r.net Git - openldap/blob - servers/slapd/config.c
Code clean-up.
[openldap] / servers / slapd / config.c
1 /* config.c - configuration file handling routines */
2
3 #include "portable.h"
4
5 #include <stdio.h>
6
7 #include <ac/string.h>
8 #include <ac/ctype.h>
9 #include <ac/socket.h>
10
11 #include "ldapconfig.h"
12 #include "slap.h"
13
14 #define MAXARGS 100
15
16 /*
17  * defaults for various global variables
18  */
19 int             defsize = SLAPD_DEFAULT_SIZELIMIT;
20 int             deftime = SLAPD_DEFAULT_TIMELIMIT;
21 struct acl      *global_acl = NULL;
22 int             global_default_access = ACL_READ;
23 char            *replogfile;
24 int             global_lastmod;
25 char            *ldap_srvtab = "";
26
27 char   *slapd_pid_file  = NULL;
28 char   *slapd_args_file = NULL;
29
30 static char     *fp_getline(FILE *fp, int *lineno);
31 static void     fp_getline_init(int *lineno);
32 static int      fp_parse_line(char *line, int *argcp, char **argv);
33
34 static char     *strtok_quote(char *line, char *sep);
35
36 int
37 read_config( char *fname )
38 {
39         FILE    *fp;
40         char    *line, *savefname;
41         int     cargc, savelineno;
42         char    *cargv[MAXARGS];
43         int     lineno, i;
44
45         static BackendInfo *bi = NULL;
46         static BackendDB        *be = NULL;
47
48         if ( (fp = fopen( fname, "r" )) == NULL ) {
49                 ldap_syslog = 1;
50                 Debug( LDAP_DEBUG_ANY,
51                     "could not open config file \"%s\" - absolute path?\n",
52                     fname, 0, 0 );
53                 perror( fname );
54                 return 1;
55         }
56
57         Debug( LDAP_DEBUG_CONFIG, "reading config file %s\n", fname, 0, 0 );
58
59         fp_getline_init( &lineno );
60
61         while ( (line = fp_getline( fp, &lineno )) != NULL ) {
62                 /* skip comments and blank lines */
63                 if ( line[0] == '#' || line[0] == '\0' ) {
64                         continue;
65                 }
66
67                 Debug( LDAP_DEBUG_CONFIG, "line %d (%s)\n", lineno, line, 0 );
68
69                 if ( fp_parse_line( line, &cargc, cargv ) != 0 ) {
70                         return( 1 );
71                 }
72
73                 if ( cargc < 1 ) {
74                         Debug( LDAP_DEBUG_ANY,
75                             "%s: line %d: bad config line (ignored)\n",
76                             fname, lineno, 0 );
77                         continue;
78                 }
79
80                 if ( strcasecmp( cargv[0], "backend" ) == 0 ) {
81                         if ( cargc < 2 ) {
82                                 Debug( LDAP_DEBUG_ANY,
83                 "%s: line %d: missing type in \"backend <type>\" line\n",
84                                     fname, lineno, 0 );
85                                 return( 1 );
86                         }
87
88                         if( be != NULL ) {
89                                 Debug( LDAP_DEBUG_ANY,
90 "%s: line %d: backend line must appear before any database definition\n",
91                                     fname, lineno, 0 );
92                                 return( 1 );
93                         }
94
95                         bi = backend_info( cargv[1] );
96
97                 /* start of a new database definition */
98                 } else if ( strcasecmp( cargv[0], "database" ) == 0 ) {
99                         if ( cargc < 2 ) {
100                                 Debug( LDAP_DEBUG_ANY,
101                 "%s: line %d: missing type in \"database <type>\" line\n",
102                                     fname, lineno, 0 );
103                                 return( 1 );
104                         }
105                         bi = NULL;
106                         be = backend_db_init( cargv[1] );
107
108                 /* assign a default depth limit for alias deref */
109                 be->be_maxDerefDepth = SLAPD_DEFAULT_MAXDEREFDEPTH; 
110
111                 /* get pid file name */
112                 } else if ( strcasecmp( cargv[0], "pidfile" ) == 0 ) {
113                         if ( cargc < 2 ) {
114                                 Debug( LDAP_DEBUG_ANY,
115             "%s: line %d: missing file name in \"pidfile <file>\" line\n",
116                                     fname, lineno, 0 );
117                                 return( 1 );
118                         }
119
120                         slapd_pid_file = ch_strdup( cargv[1] );
121
122                 /* get args file name */
123                 } else if ( strcasecmp( cargv[0], "argsfile" ) == 0 ) {
124                         if ( cargc < 2 ) {
125                                 Debug( LDAP_DEBUG_ANY,
126             "%s: line %d: missing file name in \"argsfile <file>\" line\n",
127                                     fname, lineno, 0 );
128                                 return( 1 );
129                         }
130
131                         slapd_args_file = ch_strdup( cargv[1] );
132
133                 /* set size limit */
134                 } else if ( strcasecmp( cargv[0], "sizelimit" ) == 0 ) {
135                         if ( cargc < 2 ) {
136                                 Debug( LDAP_DEBUG_ANY,
137             "%s: line %d: missing limit in \"sizelimit <limit>\" line\n",
138                                     fname, lineno, 0 );
139                                 return( 1 );
140                         }
141                         if ( be == NULL ) {
142                                 defsize = atoi( cargv[1] );
143                         } else {
144                                 be->be_sizelimit = atoi( cargv[1] );
145                         }
146
147                 /* set time limit */
148                 } else if ( strcasecmp( cargv[0], "timelimit" ) == 0 ) {
149                         if ( cargc < 2 ) {
150                                 Debug( LDAP_DEBUG_ANY,
151             "%s: line %d: missing limit in \"timelimit <limit>\" line\n",
152                                     fname, lineno, 0 );
153                                 return( 1 );
154                         }
155                         if ( be == NULL ) {
156                                 deftime = atoi( cargv[1] );
157                         } else {
158                                 be->be_timelimit = atoi( cargv[1] );
159                         }
160
161                 /* set database suffix */
162                 } else if ( strcasecmp( cargv[0], "suffix" ) == 0 ) {
163                         if ( cargc < 2 ) {
164                                 Debug( LDAP_DEBUG_ANY,
165                     "%s: line %d: missing dn in \"suffix <dn>\" line\n",
166                                     fname, lineno, 0 );
167                                 return( 1 );
168                         } else if ( cargc > 2 ) {
169                                 Debug( LDAP_DEBUG_ANY,
170     "%s: line %d: extra cruft after <dn> in \"suffix %s\" line (ignored)\n",
171                                     fname, lineno, cargv[1] );
172                         }
173                         if ( be == NULL ) {
174                                 Debug( LDAP_DEBUG_ANY,
175 "%s: line %d: suffix line must appear inside a database definition (ignored)\n",
176                                     fname, lineno, 0 );
177                         } else {
178                                 char *dn = ch_strdup( cargv[1] );
179                                 (void) dn_normalize_case( dn );
180                                 charray_add( &be->be_suffix, dn );
181                         }
182
183                 /* set database suffixAlias */
184                 } else if ( strcasecmp( cargv[0], "suffixAlias" ) == 0 ) {
185                         if ( cargc < 2 ) {
186                                 Debug( LDAP_DEBUG_ANY,
187                     "%s: line %d: missing alias and aliased_dn in \"suffixAlias <alias> <aliased_dn>\" line\n",
188                                     fname, lineno, 0 );
189                                 return( 1 );
190                         } else if ( cargc < 3 ) {
191                                 Debug( LDAP_DEBUG_ANY,
192                     "%s: line %d: missing aliased_dn in \"suffixAlias <alias> <aliased_dn>\" line\n",
193                                     fname, lineno, 0 );
194                                 return( 1 );
195                         } else if ( cargc > 3 ) {
196                                 Debug( LDAP_DEBUG_ANY,
197     "%s: line %d: extra cruft in suffixAlias line (ignored)\n",
198                                     fname, lineno, 0 );
199                         }
200                         if ( be == NULL ) {
201                                 Debug( LDAP_DEBUG_ANY,
202 "%s: line %d: suffixAlias line must appear inside a database definition (ignored)\n",
203                                     fname, lineno, 0 );
204                         } else {
205                                 char *alias, *aliased_dn;
206
207                                                                 alias = ch_strdup( cargv[1] );
208                                 (void) dn_normalize( alias );
209
210                                 aliased_dn = ch_strdup( cargv[2] );
211                                 (void) dn_normalize( aliased_dn );
212
213
214                                                                 if ( strcasecmp( alias, aliased_dn) == 0 ) {
215                                         Debug( LDAP_DEBUG_ANY,
216 "%s: line %d: suffixAlias %s is not different from aliased dn (ignored)\n",
217                                     fname, lineno, alias );
218                                                                 } else {
219                                         (void) dn_normalize_case( alias );
220                                         (void) dn_normalize_case( aliased_dn );
221                                         charray_add( &be->be_suffixAlias, alias );
222                                         charray_add( &be->be_suffixAlias, aliased_dn );
223                                                                 }
224
225                                                                 free(alias);
226                                                                 free(aliased_dn);
227                         }
228
229                /* set max deref depth */
230                } else if ( strcasecmp( cargv[0], "maxDerefDepth" ) == 0 ) {
231                        if ( cargc < 2 ) {
232                                Debug( LDAP_DEBUG_ANY,
233                    "%s: line %d: missing depth in \"maxDerefDepth <depth>\" line\n",
234                                    fname, lineno, 0 );
235                                return( 1 );
236                        }
237                        if ( be == NULL ) {
238                                Debug( LDAP_DEBUG_ANY,
239 "%s: line %d: depth line must appear inside a database definition (ignored)\n",
240                                    fname, lineno, 0 );
241                        } else {
242                            be->be_maxDerefDepth = atoi (cargv[1]);
243                        }
244
245
246                 /* set magic "root" dn for this database */
247                 } else if ( strcasecmp( cargv[0], "rootdn" ) == 0 ) {
248                         if ( cargc < 2 ) {
249                                 Debug( LDAP_DEBUG_ANY,
250                     "%s: line %d: missing dn in \"rootdn <dn>\" line\n",
251                                     fname, lineno, 0 );
252                                 return( 1 );
253                         }
254                         if ( be == NULL ) {
255                                 Debug( LDAP_DEBUG_ANY,
256 "%s: line %d: rootdn line must appear inside a database definition (ignored)\n",
257                                     fname, lineno, 0 );
258                         } else {
259                                 be->be_root_dn = ch_strdup( cargv[1] );
260                                 be->be_root_ndn = dn_normalize_case( ch_strdup( cargv[1] ) );
261                         }
262
263                 /* set super-secret magic database password */
264                 } else if ( strcasecmp( cargv[0], "rootpw" ) == 0 ) {
265                         if ( cargc < 2 ) {
266                                 Debug( LDAP_DEBUG_ANY,
267             "%s: line %d: missing passwd in \"rootpw <passwd>\" line\n",
268                                     fname, lineno, 0 );
269                                 return( 1 );
270                         }
271                         if ( be == NULL ) {
272                                 Debug( LDAP_DEBUG_ANY,
273 "%s: line %d: rootpw line must appear inside a database definition (ignored)\n",
274                                     fname, lineno, 0 );
275                         } else {
276                                 be->be_root_pw = ch_strdup( cargv[1] );
277                         }
278
279                 /* make this database read-only */
280                 } else if ( strcasecmp( cargv[0], "readonly" ) == 0 ) {
281                         if ( cargc < 2 ) {
282                                 Debug( LDAP_DEBUG_ANY,
283             "%s: line %d: missing on|off in \"readonly <on|off>\" line\n",
284                                     fname, lineno, 0 );
285                                 return( 1 );
286                         }
287                         if ( be == NULL ) {
288                                 Debug( LDAP_DEBUG_ANY,
289 "%s: line %d: readonly line must appear inside a database definition (ignored)\n",
290                                     fname, lineno, 0 );
291                         } else {
292                                 if ( strcasecmp( cargv[1], "on" ) == 0 ) {
293                                         be->be_readonly = 1;
294                                 } else {
295                                         be->be_readonly = 0;
296                                 }
297                         }
298
299                 /* where to send clients when we don't hold it */
300                 } else if ( strcasecmp( cargv[0], "referral" ) == 0 ) {
301                         if ( cargc < 2 ) {
302                                 Debug( LDAP_DEBUG_ANY,
303                     "%s: line %d: missing URL in \"referral <URL>\" line\n",
304                                     fname, lineno, 0 );
305                                 return( 1 );
306                         }
307                         default_referral = (char *) ch_malloc( strlen( cargv[1] )
308                             + sizeof("Referral:\n") + 1 );
309                         strcpy( default_referral, "Referral:\n" );
310                         strcat( default_referral, cargv[1] );
311
312                 /* specify an objectclass */
313                 } else if ( strcasecmp( cargv[0], "objectclass" ) == 0 ) {
314                         parse_oc( be, fname, lineno, cargc, cargv );
315
316                 /* specify an attribute */
317                 } else if ( strcasecmp( cargv[0], "attribute" ) == 0 ) {
318                         attr_syntax_config( fname, lineno, cargc - 1,
319                             &cargv[1] );
320
321                 /* turn on/off schema checking */
322                 } else if ( strcasecmp( cargv[0], "schemacheck" ) == 0 ) {
323                         if ( cargc < 2 ) {
324                                 Debug( LDAP_DEBUG_ANY,
325     "%s: line %d: missing on|off in \"schemacheck <on|off>\" line\n",
326                                     fname, lineno, 0 );
327                                 return( 1 );
328                         }
329                         if ( strcasecmp( cargv[1], "on" ) == 0 ) {
330                                 global_schemacheck = 1;
331                         } else {
332                                 global_schemacheck = 0;
333                         }
334
335                 /* specify access control info */
336                 } else if ( strcasecmp( cargv[0], "access" ) == 0 ) {
337                         parse_acl( be, fname, lineno, cargc, cargv );
338
339                 /* specify default access control info */
340                 } else if ( strcasecmp( cargv[0], "defaultaccess" ) == 0 ) {
341                         if ( cargc < 2 ) {
342                                 Debug( LDAP_DEBUG_ANY,
343             "%s: line %d: missing limit in \"defaultaccess <access>\" line\n",
344                                     fname, lineno, 0 );
345                                 return( 1 );
346                         }
347                         if ( be == NULL ) {
348                                 if ( (global_default_access =
349                                     str2access( cargv[1] )) == -1 ) {
350                                         Debug( LDAP_DEBUG_ANY,
351 "%s: line %d: bad access \"%s\" expecting [self]{none|compare|read|write}\n",
352                                             fname, lineno, cargv[1] );
353                                         return( 1 );
354                                 }
355                         } else {
356                                 if ( (be->be_dfltaccess =
357                                     str2access( cargv[1] )) == -1 ) {
358                                         Debug( LDAP_DEBUG_ANY,
359 "%s: line %d: bad access \"%s\" expecting [self]{none|compare|read|write}\n",
360                                             fname, lineno, cargv[1] );
361                                         return( 1 );
362                                 }
363                         }
364
365                 /* debug level to log things to syslog */
366                 } else if ( strcasecmp( cargv[0], "loglevel" ) == 0 ) {
367                         if ( cargc < 2 ) {
368                                 Debug( LDAP_DEBUG_ANY,
369                     "%s: line %d: missing level in \"loglevel <level>\" line\n",
370                                     fname, lineno, 0 );
371                                 return( 1 );
372                         }
373                         ldap_syslog = atoi( cargv[1] );
374
375                 /* list of replicas of the data in this backend (master only) */
376                 } else if ( strcasecmp( cargv[0], "replica" ) == 0 ) {
377                         if ( cargc < 2 ) {
378                                 Debug( LDAP_DEBUG_ANY,
379             "%s: line %d: missing host in \"replica <host[:port]>\" line\n",
380                                     fname, lineno, 0 );
381                                 return( 1 );
382                         }
383                         if ( be == NULL ) {
384                                 Debug( LDAP_DEBUG_ANY,
385 "%s: line %d: replica line must appear inside a database definition (ignored)\n",
386                                     fname, lineno, 0 );
387                         } else {
388                                 for ( i = 1; i < cargc; i++ ) {
389                                         if ( strncasecmp( cargv[i], "host=", 5 )
390                                             == 0 ) {
391                                                 charray_add( &be->be_replica,
392                                                     ch_strdup( cargv[i] + 5 ) );
393                                                 break;
394                                         }
395                                 }
396                                 if ( i == cargc ) {
397                                         Debug( LDAP_DEBUG_ANY,
398                     "%s: line %d: missing host in \"replica\" line (ignored)\n",
399                                             fname, lineno, 0 );
400                                 }
401                         }
402
403                 /* dn of master entity allowed to write to replica */
404                 } else if ( strcasecmp( cargv[0], "updatedn" ) == 0 ) {
405                         if ( cargc < 2 ) {
406                                 Debug( LDAP_DEBUG_ANY,
407                     "%s: line %d: missing dn in \"updatedn <dn>\" line\n",
408                                     fname, lineno, 0 );
409                                 return( 1 );
410                         }
411                         if ( be == NULL ) {
412                                 Debug( LDAP_DEBUG_ANY,
413 "%s: line %d: updatedn line must appear inside a database definition (ignored)\n",
414                                     fname, lineno, 0 );
415                         } else {
416                                 be->be_update_ndn = ch_strdup( cargv[1] );
417                                 (void) dn_normalize_case( be->be_update_ndn );
418                         }
419
420                 /* replication log file to which changes are appended */
421                 } else if ( strcasecmp( cargv[0], "replogfile" ) == 0 ) {
422                         if ( cargc < 2 ) {
423                                 Debug( LDAP_DEBUG_ANY,
424             "%s: line %d: missing dn in \"replogfile <filename>\" line\n",
425                                     fname, lineno, 0 );
426                                 return( 1 );
427                         }
428                         if ( be ) {
429                                 be->be_replogfile = ch_strdup( cargv[1] );
430                         } else {
431                                 replogfile = ch_strdup( cargv[1] );
432                         }
433
434                 /* maintain lastmodified{by,time} attributes */
435                 } else if ( strcasecmp( cargv[0], "lastmod" ) == 0 ) {
436                         if ( cargc < 2 ) {
437                                 Debug( LDAP_DEBUG_ANY,
438             "%s: line %d: missing on|off in \"lastmod <on|off>\" line\n",
439                                     fname, lineno, 0 );
440                                 return( 1 );
441                         }
442                         if ( strcasecmp( cargv[1], "on" ) == 0 ) {
443                                 if ( be )
444                                         be->be_lastmod = ON;
445                                 else
446                                         global_lastmod = ON;
447                         } else {
448                                 if ( be )
449                                         be->be_lastmod = OFF;
450                                 else
451                                         global_lastmod = OFF;
452                         }
453
454                 /* include another config file */
455                 } else if ( strcasecmp( cargv[0], "include" ) == 0 ) {
456                         if ( cargc < 2 ) {
457                                 Debug( LDAP_DEBUG_ANY,
458     "%s: line %d: missing filename in \"include <filename>\" line\n",
459                                     fname, lineno, 0 );
460                                 return( 1 );
461                         }
462                         savefname = ch_strdup( cargv[1] );
463                         savelineno = lineno;
464
465                         if ( read_config( savefname ) != 0 ) {
466                                 return( 1 );
467                         }
468
469                         free( savefname );
470                         lineno = savelineno - 1;
471
472                 /* location of kerberos srvtab file */
473                 } else if ( strcasecmp( cargv[0], "srvtab" ) == 0 ) {
474                         if ( cargc < 2 ) {
475                                 Debug( LDAP_DEBUG_ANY,
476             "%s: line %d: missing filename in \"srvtab <filename>\" line\n",
477                                     fname, lineno, 0 );
478                                 return( 1 );
479                         }
480                         ldap_srvtab = ch_strdup( cargv[1] );
481
482                 /* pass anything else to the current backend info/db config routine */
483                 } else {
484                         if ( bi != NULL ) {
485                                 if (bi->bi_config == NULL) {
486                                         Debug( LDAP_DEBUG_ANY,
487 "%s: line %d: unknown directive \"%s\" inside backend info definition (ignored)\n",
488                                                 fname, lineno, cargv[0] );
489                                 } else {
490                                         if ( (*bi->bi_config)( bi, fname, lineno, cargc, cargv )
491                                                 != 0 )
492                                         {
493                                                 return( 1 );
494                                         }
495                                 }
496                         } else if ( be != NULL ) {
497                                 if ( be->be_config == NULL ) {
498                                         Debug( LDAP_DEBUG_ANY,
499 "%s: line %d: unknown directive \"%s\" inside backend database definition (ignored)\n",
500                                         fname, lineno, cargv[0] );
501                                 } else {
502                                         if ( (*be->be_config)( be, fname, lineno, cargc, cargv )
503                                                 != 0 )
504                                         {
505                                                 return( 1 );
506                                         }
507                                 }
508                         } else {
509                                 Debug( LDAP_DEBUG_ANY,
510 "%s: line %d: unknown directive \"%s\" outside backend info and database definitions (ignored)\n",
511                                     fname, lineno, cargv[0] );
512                         }
513                 }
514         }
515         fclose( fp );
516 }
517
518 static int
519 fp_parse_line(
520     char        *line,
521     int         *argcp,
522     char        **argv
523 )
524 {
525         char *  token;
526
527         *argcp = 0;
528         for ( token = strtok_quote( line, " \t" ); token != NULL;
529             token = strtok_quote( NULL, " \t" ) ) {
530                 if ( *argcp == MAXARGS ) {
531                         Debug( LDAP_DEBUG_ANY, "Too many tokens (max %d)\n",
532                             MAXARGS, 0, 0 );
533                         return( 1 );
534                 }
535                 argv[(*argcp)++] = token;
536         }
537         argv[*argcp] = NULL;
538         return 0;
539 }
540
541 static char *
542 strtok_quote( char *line, char *sep )
543 {
544         int             inquote;
545         char            *tmp;
546         static char     *next;
547
548         if ( line != NULL ) {
549                 next = line;
550         }
551         while ( *next && strchr( sep, *next ) ) {
552                 next++;
553         }
554
555         if ( *next == '\0' ) {
556                 next = NULL;
557                 return( NULL );
558         }
559         tmp = next;
560
561         for ( inquote = 0; *next; ) {
562                 switch ( *next ) {
563                 case '"':
564                         if ( inquote ) {
565                                 inquote = 0;
566                         } else {
567                                 inquote = 1;
568                         }
569                         SAFEMEMCPY( next, next + 1, strlen( next + 1 ) + 1 );
570                         break;
571
572                 case '\\':
573                         SAFEMEMCPY( next, next + 1, strlen( next + 1 ) + 1 );
574                         break;
575
576                 default:
577                         if ( ! inquote ) {
578                                 if ( strchr( sep, *next ) != NULL ) {
579                                         *next++ = '\0';
580                                         return( tmp );
581                                 }
582                         }
583                         next++;
584                         break;
585                 }
586         }
587
588         return( tmp );
589 }
590
591 static char     buf[BUFSIZ];
592 static char     *line;
593 static int      lmax, lcur;
594
595 #define CATLINE( buf )  { \
596         int     len; \
597         len = strlen( buf ); \
598         while ( lcur + len + 1 > lmax ) { \
599                 lmax += BUFSIZ; \
600                 line = (char *) ch_realloc( line, lmax ); \
601         } \
602         strcpy( line + lcur, buf ); \
603         lcur += len; \
604 }
605
606 static char *
607 fp_getline( FILE *fp, int *lineno )
608 {
609         char            *p;
610
611         lcur = 0;
612         CATLINE( buf );
613         (*lineno)++;
614
615         /* hack attack - keeps us from having to keep a stack of bufs... */
616         if ( strncasecmp( line, "include", 7 ) == 0 ) {
617                 buf[0] = '\0';
618                 return( line );
619         }
620
621         while ( fgets( buf, sizeof(buf), fp ) != NULL ) {
622                 if ( (p = strchr( buf, '\n' )) != NULL ) {
623                         *p = '\0';
624                 }
625                 if ( ! isspace( buf[0] ) ) {
626                         return( line );
627                 }
628
629                 CATLINE( buf );
630                 (*lineno)++;
631         }
632         buf[0] = '\0';
633
634         return( line[0] ? line : NULL );
635 }
636
637 static void
638 fp_getline_init( int *lineno )
639 {
640         *lineno = -1;
641         buf[0] = '\0';
642 }