]> git.sur5r.net Git - openldap/blob - servers/slapd/config.c
66e856796274133c3c80dd96caccd55838ae7dd7
[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                 /* 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 magic "root" dn for this database */
138                 } else if ( strcasecmp( cargv[0], "rootdn" ) == 0 ) {
139                         if ( cargc < 2 ) {
140                                 Debug( LDAP_DEBUG_ANY,
141                     "%s: line %d: missing dn in \"rootdn <dn>\" line\n",
142                                     fname, lineno, 0 );
143                                 exit( 1 );
144                         }
145                         if ( be == NULL ) {
146                                 Debug( LDAP_DEBUG_ANY,
147 "%s: line %d: rootdn line must appear inside a database definition (ignored)\n",
148                                     fname, lineno, 0 );
149                         } else {
150                                 dn = strdup( cargv[1] );
151                                 (void) dn_normalize( dn );
152                                 be->be_rootdn = dn;
153                         }
154
155                 /* set super-secret magic database password */
156                 } else if ( strcasecmp( cargv[0], "rootpw" ) == 0 ) {
157                         if ( cargc < 2 ) {
158                                 Debug( LDAP_DEBUG_ANY,
159             "%s: line %d: missing passwd in \"rootpw <passwd>\" line\n",
160                                     fname, lineno, 0 );
161                                 exit( 1 );
162                         }
163                         if ( be == NULL ) {
164                                 Debug( LDAP_DEBUG_ANY,
165 "%s: line %d: rootpw line must appear inside a database definition (ignored)\n",
166                                     fname, lineno, 0 );
167                         } else {
168                                 be->be_rootpw = strdup( cargv[1] );
169                         }
170
171                 /* make this database read-only */
172                 } else if ( strcasecmp( cargv[0], "readonly" ) == 0 ) {
173                         if ( cargc < 2 ) {
174                                 Debug( LDAP_DEBUG_ANY,
175             "%s: line %d: missing on|off in \"readonly <on|off>\" line\n",
176                                     fname, lineno, 0 );
177                                 exit( 1 );
178                         }
179                         if ( be == NULL ) {
180                                 Debug( LDAP_DEBUG_ANY,
181 "%s: line %d: readonly line must appear inside a database definition (ignored)\n",
182                                     fname, lineno, 0 );
183                         } else {
184                                 if ( strcasecmp( cargv[1], "on" ) == 0 ) {
185                                         be->be_readonly = 1;
186                                 } else {
187                                         be->be_readonly = 0;
188                                 }
189                         }
190
191                 /* where to send clients when we don't hold it */
192                 } else if ( strcasecmp( cargv[0], "referral" ) == 0 ) {
193                         if ( cargc < 2 ) {
194                                 Debug( LDAP_DEBUG_ANY,
195                     "%s: line %d: missing URL in \"referral <URL>\" line\n",
196                                     fname, lineno, 0 );
197                                 exit( 1 );
198                         }
199                         default_referral = (char *) malloc( strlen( cargv[1] )
200                             + sizeof("Referral:\n") + 1 );
201                         strcpy( default_referral, "Referral:\n" );
202                         strcat( default_referral, cargv[1] );
203
204                 /* specify an objectclass */
205                 } else if ( strcasecmp( cargv[0], "objectclass" ) == 0 ) {
206                         parse_oc( be, fname, lineno, cargc, cargv );
207
208                 /* specify an attribute */
209                 } else if ( strcasecmp( cargv[0], "attribute" ) == 0 ) {
210                         attr_syntax_config( fname, lineno, cargc - 1,
211                             &cargv[1] );
212
213                 /* turn on/off schema checking */
214                 } else if ( strcasecmp( cargv[0], "schemacheck" ) == 0 ) {
215                         if ( cargc < 2 ) {
216                                 Debug( LDAP_DEBUG_ANY,
217     "%s: line %d: missing on|off in \"schemacheck <on|off>\" line\n",
218                                     fname, lineno, 0 );
219                                 exit( 1 );
220                         }
221                         if ( strcasecmp( cargv[1], "on" ) == 0 ) {
222                                 global_schemacheck = 1;
223                         } else {
224                                 global_schemacheck = 0;
225                         }
226
227                 /* specify access control info */
228                 } else if ( strcasecmp( cargv[0], "access" ) == 0 ) {
229                         parse_acl( be, fname, lineno, cargc, cargv );
230
231                 /* specify default access control info */
232                 } else if ( strcasecmp( cargv[0], "defaultaccess" ) == 0 ) {
233                         if ( cargc < 2 ) {
234                                 Debug( LDAP_DEBUG_ANY,
235             "%s: line %d: missing limit in \"defaultaccess <access>\" line\n",
236                                     fname, lineno, 0 );
237                                 exit( 1 );
238                         }
239                         if ( be == NULL ) {
240                                 if ( (global_default_access =
241                                     str2access( cargv[1] )) == -1 ) {
242                                         Debug( LDAP_DEBUG_ANY,
243 "%s: line %d: bad access \"%s\" expecting [self]{none|compare|read|write}\n",
244                                             fname, lineno, cargv[1] );
245                                         exit( 1 );
246                                 }
247                         } else {
248                                 if ( (be->be_dfltaccess =
249                                     str2access( cargv[1] )) == -1 ) {
250                                         Debug( LDAP_DEBUG_ANY,
251 "%s: line %d: bad access \"%s\" expecting [self]{none|compare|read|write}\n",
252                                             fname, lineno, cargv[1] );
253                                         exit( 1 );
254                                 }
255                         }
256
257                 /* debug level to log things to syslog */
258                 } else if ( strcasecmp( cargv[0], "loglevel" ) == 0 ) {
259                         if ( cargc < 2 ) {
260                                 Debug( LDAP_DEBUG_ANY,
261                     "%s: line %d: missing level in \"loglevel <level>\" line\n",
262                                     fname, lineno, 0 );
263                                 exit( 1 );
264                         }
265                         ldap_syslog = atoi( cargv[1] );
266
267                 /* list of replicas of the data in this backend (master only) */
268                 } else if ( strcasecmp( cargv[0], "replica" ) == 0 ) {
269                         if ( cargc < 2 ) {
270                                 Debug( LDAP_DEBUG_ANY,
271             "%s: line %d: missing host in \"replica <host[:port]>\" line\n",
272                                     fname, lineno, 0 );
273                                 exit( 1 );
274                         }
275                         if ( be == NULL ) {
276                                 Debug( LDAP_DEBUG_ANY,
277 "%s: line %d: replica line must appear inside a database definition (ignored)\n",
278                                     fname, lineno, 0 );
279                         } else {
280                                 for ( i = 1; i < cargc; i++ ) {
281                                         if ( strncasecmp( cargv[i], "host=", 5 )
282                                             == 0 ) {
283                                                 charray_add( &be->be_replica,
284                                                     strdup( cargv[i] + 5 ) );
285                                                 break;
286                                         }
287                                 }
288                                 if ( i == cargc ) {
289                                         Debug( LDAP_DEBUG_ANY,
290                     "%s: line %d: missing host in \"replica\" line (ignored)\n",
291                                             fname, lineno, 0 );
292                                 }
293                         }
294
295                 /* dn of master entity allowed to write to replica */
296                 } else if ( strcasecmp( cargv[0], "updatedn" ) == 0 ) {
297                         if ( cargc < 2 ) {
298                                 Debug( LDAP_DEBUG_ANY,
299                     "%s: line %d: missing dn in \"updatedn <dn>\" line\n",
300                                     fname, lineno, 0 );
301                                 exit( 1 );
302                         }
303                         if ( be == NULL ) {
304                                 Debug( LDAP_DEBUG_ANY,
305 "%s: line %d: updatedn line must appear inside a database definition (ignored)\n",
306                                     fname, lineno, 0 );
307                         } else {
308                                 be->be_updatedn = strdup( cargv[1] );
309                                 (void) dn_normalize( be->be_updatedn );
310                         }
311
312                 /* replication log file to which changes are appended */
313                 } else if ( strcasecmp( cargv[0], "replogfile" ) == 0 ) {
314                         if ( cargc < 2 ) {
315                                 Debug( LDAP_DEBUG_ANY,
316             "%s: line %d: missing dn in \"replogfile <filename>\" line\n",
317                                     fname, lineno, 0 );
318                                 exit( 1 );
319                         }
320                         if ( be ) {
321                                 be->be_replogfile = strdup( cargv[1] );
322                         } else {
323                                 replogfile = strdup( cargv[1] );
324                         }
325
326                 /* maintain lastmodified{by,time} attributes */
327                 } else if ( strcasecmp( cargv[0], "lastmod" ) == 0 ) {
328                         if ( cargc < 2 ) {
329                                 Debug( LDAP_DEBUG_ANY,
330             "%s: line %d: missing on|off in \"lastmod <on|off>\" line\n",
331                                     fname, lineno, 0 );
332                                 exit( 1 );
333                         }
334                         if ( strcasecmp( cargv[1], "on" ) == 0 ) {
335                                 if ( be )
336                                         be->be_lastmod = ON;
337                                 else
338                                         global_lastmod = ON;
339                         } else {
340                                 if ( be )
341                                         be->be_lastmod = OFF;
342                                 else
343                                         global_lastmod = OFF;
344                         }
345
346                 /* include another config file */
347                 } else if ( strcasecmp( cargv[0], "include" ) == 0 ) {
348                         if ( cargc < 2 ) {
349                                 Debug( LDAP_DEBUG_ANY,
350     "%s: line %d: missing filename in \"include <filename>\" line\n",
351                                     fname, lineno, 0 );
352                                 exit( 1 );
353                         }
354                         savefname = strdup( cargv[1] );
355                         savelineno = lineno;
356                         read_config( savefname, bep, NULL );
357                         be = *bep;
358                         free( savefname );
359                         lineno = savelineno - 1;
360
361                 /* location of kerberos srvtab file */
362                 } else if ( strcasecmp( cargv[0], "srvtab" ) == 0 ) {
363                         if ( cargc < 2 ) {
364                                 Debug( LDAP_DEBUG_ANY,
365             "%s: line %d: missing filename in \"srvtab <filename>\" line\n",
366                                     fname, lineno, 0 );
367                                 exit( 1 );
368                         }
369                         ldap_srvtab = strdup( cargv[1] );
370
371                 /* pass anything else to the current backend config routine */
372                 } else {
373                         if ( be == NULL ) {
374                                 Debug( LDAP_DEBUG_ANY,
375 "%s: line %d: unknown directive \"%s\" outside database definition (ignored)\n",
376                                     fname, lineno, cargv[0] );
377                         } else if ( be->be_config == NULL ) {
378                                 Debug( LDAP_DEBUG_ANY,
379 "%s: line %d: unknown directive \"%s\" inside database definition (ignored)\n",
380                                     fname, lineno, cargv[0] );
381                         } else {
382                                 (*be->be_config)( be, fname, lineno, cargc,
383                                     cargv );
384                         }
385                 }
386         }
387         fclose( fp );
388 }
389
390 static void
391 fp_parse_line(
392     char        *line,
393     int         *argcp,
394     char        **argv
395 )
396 {
397         char *  token;
398
399         *argcp = 0;
400         for ( token = strtok_quote( line, " \t" ); token != NULL;
401             token = strtok_quote( NULL, " \t" ) ) {
402                 if ( *argcp == MAXARGS ) {
403                         Debug( LDAP_DEBUG_ANY, "Too many tokens (max %d)\n",
404                             MAXARGS, 0, 0 );
405                         exit( 1 );
406                 }
407                 argv[(*argcp)++] = token;
408         }
409         argv[*argcp] = NULL;
410 }
411
412 static char *
413 strtok_quote( char *line, char *sep )
414 {
415         int             inquote;
416         char            *tmp;
417         static char     *next;
418
419         if ( line != NULL ) {
420                 next = line;
421         }
422         while ( *next && strchr( sep, *next ) ) {
423                 next++;
424         }
425
426         if ( *next == '\0' ) {
427                 next = NULL;
428                 return( NULL );
429         }
430         tmp = next;
431
432         for ( inquote = 0; *next; ) {
433                 switch ( *next ) {
434                 case '"':
435                         if ( inquote ) {
436                                 inquote = 0;
437                         } else {
438                                 inquote = 1;
439                         }
440                         strcpy( next, next + 1 );
441                         break;
442
443                 case '\\':
444                         strcpy( next, next + 1 );
445                         break;
446
447                 default:
448                         if ( ! inquote ) {
449                                 if ( strchr( sep, *next ) != NULL ) {
450                                         *next++ = '\0';
451                                         return( tmp );
452                                 }
453                         }
454                         next++;
455                         break;
456                 }
457         }
458
459         return( tmp );
460 }
461
462 static char     buf[BUFSIZ];
463 static char     *line;
464 static int      lmax, lcur;
465
466 #define CATLINE( buf )  { \
467         int     len; \
468         len = strlen( buf ); \
469         while ( lcur + len + 1 > lmax ) { \
470                 lmax += BUFSIZ; \
471                 line = (char *) ch_realloc( line, lmax ); \
472         } \
473         strcpy( line + lcur, buf ); \
474         lcur += len; \
475 }
476
477 static char *
478 fp_getline( FILE *fp, int *lineno )
479 {
480         char            *p;
481
482         lcur = 0;
483         CATLINE( buf );
484         (*lineno)++;
485
486         /* hack attack - keeps us from having to keep a stack of bufs... */
487         if ( strncasecmp( line, "include", 7 ) == 0 ) {
488                 buf[0] = '\0';
489                 return( line );
490         }
491
492         while ( fgets( buf, sizeof(buf), fp ) != NULL ) {
493                 if ( (p = strchr( buf, '\n' )) != NULL ) {
494                         *p = '\0';
495                 }
496                 if ( ! isspace( buf[0] ) ) {
497                         return( line );
498                 }
499
500                 CATLINE( buf );
501                 (*lineno)++;
502         }
503         buf[0] = '\0';
504
505         return( line[0] ? line : NULL );
506 }
507
508 static void
509 fp_getline_init( int *lineno )
510 {
511         *lineno = -1;
512         buf[0] = '\0';
513 }