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