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