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