2 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
4 * Copyright 1998-2005 The OpenLDAP Foundation.
5 * Portions Copyright 2003 Mark Benson.
6 * Portions Copyright 2002 John Morrissey.
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted only as authorized by the OpenLDAP
13 * A copy of this license is available in file LICENSE in the
14 * top-level directory of the distribution or, alternatively, at
15 * <http://www.OpenLDAP.org/license.html>.
17 /* Portions Copyright (c) 1996 Regents of the University of Michigan.
18 * All rights reserved.
20 * Redistribution and use in source and binary forms are permitted
21 * provided that this notice is preserved and that due credit is given
22 * to the University of Michigan at Ann Arbor. The name of the University
23 * may not be used to endorse or promote products derived from this
24 * software without specific prior written permission. This software
25 * is provided ``as is'' without express or implied warranty.
28 * This work was originally developed by the University of Michigan
29 * (as part of U-MICH LDAP). Additional signficant contributors
37 * config.c - configuration file handling routines
44 #include <ac/stdlib.h>
45 #include <ac/string.h>
46 #include <ac/socket.h>
57 /* Forward declarations */
58 static void add_replica LDAP_P(( char **, int ));
59 static int parse_replica_line LDAP_P(( char **, int, Ri *));
60 static void parse_line LDAP_P(( char * ));
61 static char *slurpd_getline LDAP_P(( FILE * ));
62 static char *strtok_quote LDAP_P(( char *, char * ));
64 int cargc = 0, cargv_size = 0;
66 /* current config file line # */
69 char *slurpd_pid_file = NULL;
70 char *slurpd_args_file = NULL;
73 * Read the slapd config file, looking only for config options we're
74 * interested in. Since we haven't detached from the controlling
75 * terminal yet, we just perror() and fprintf here.
85 if ( cargv == NULL ) {
86 cargv = ch_calloc( ARGS_STEP + 1, sizeof(*cargv) );
87 cargv_size = ARGS_STEP + 1;
90 Debug( LDAP_DEBUG_CONFIG, "Config: opening config file \"%s\"\n",
93 if ( (fp = fopen( fname, "r" )) == NULL ) {
99 while ( (line = slurpd_getline( fp )) != NULL ) {
100 /* skip comments and blank lines */
101 if ( line[0] == '#' || line[0] == '\0' ) {
105 Debug( LDAP_DEBUG_CONFIG, "Config: (%s)\n", line, 0, 0 );
110 fprintf( stderr, "line %d: bad config line (ignored)\n", lineno );
114 /* replication log file to which changes are appended */
115 if ( strcasecmp( cargv[0], "replogfile" ) == 0 ) {
117 * if slapd_replogfile has a value, the -r option was given,
118 * so use that value. If slapd_replogfile has length == 0,
119 * then we should use the value in the config file we're reading.
121 if ( sglob->slapd_replogfile[ 0 ] == '\0' ) {
124 "line %d: missing filename in \"replogfile ",
126 fprintf( stderr, "<filename>\" line\n" );
127 exit( EXIT_FAILURE );
128 } else if ( cargc > 2 && *cargv[2] != '#' ) {
130 "line %d: extra cruft at the end of \"replogfile %s\"",
132 fprintf( stderr, "line (ignored)\n" );
134 LUTIL_SLASHPATH( cargv[1] );
135 strcpy( sglob->slapd_replogfile, cargv[1] );
137 } else if ( strcasecmp( cargv[0], "replica" ) == 0 ) {
138 add_replica( cargv, cargc );
140 /* include another config file */
141 } else if ( strcasecmp( cargv[0], "include" ) == 0 ) {
146 Debug( LDAP_DEBUG_ANY,
147 "%s: line %d: missing filename in \"include <filename>\" line\n",
152 LUTIL_SLASHPATH( cargv[1] );
153 savefname = strdup( cargv[1] );
156 if ( slurpd_read_config( savefname ) != 0 ) {
161 lineno = savelineno - 1;
163 } else if ( strcasecmp( cargv[0], "replica-pidfile" ) == 0 ) {
165 Debug( LDAP_DEBUG_ANY,
166 "%s: line %d: missing file name in \"replica-pidfile <file>\" line\n",
172 LUTIL_SLASHPATH( cargv[1] );
173 slurpd_pid_file = ch_strdup( cargv[1] );
175 } else if ( strcasecmp( cargv[0], "replica-argsfile" ) == 0 ) {
177 Debug( LDAP_DEBUG_ANY,
178 "%s: line %d: missing file name in \"argsfile <file>\" line\n",
184 LUTIL_SLASHPATH( cargv[1] );
185 slurpd_args_file = ch_strdup( cargv[1] );
187 } else if ( strcasecmp( cargv[0], "replicationinterval" ) == 0 ) {
190 Debug( LDAP_DEBUG_ANY, "%s: line %d: missing interval in "
191 "\"replicationinterval <seconds>\" line\n",
196 if ( lutil_atoi( &c, cargv[1] ) != 0 || c < 1 ) {
197 Debug( LDAP_DEBUG_ANY, "%s: line %d: invalid interval "
198 "(%d) in \"replicationinterval <seconds>\" line\n",
204 sglob->no_work_interval = c;
208 Debug( LDAP_DEBUG_CONFIG,
209 "Config: ** configuration file successfully read and parsed\n",
218 * Parse one line of input.
228 for ( token = strtok_quote( line, " \t" ); token != NULL;
229 token = strtok_quote( NULL, " \t" ) )
231 if ( cargc == cargv_size - 1 ) {
233 tmp = ch_realloc( cargv, (cargv_size + ARGS_STEP) *
240 cargv_size += ARGS_STEP;
243 cargv[cargc++] = token;
261 if ( line != NULL ) {
264 while ( *next && strchr( sep, *next ) ) {
268 if ( *next == '\0' ) {
274 for ( inquote = 0; *next; ) {
282 AC_MEMCPY( next, next + 1, strlen( next + 1 ) + 1 );
287 AC_MEMCPY( next, next + 1, strlen( next + 1 ) + 1 );
288 next++; /* dont parse the escaped character */
293 if ( strchr( sep, *next ) != NULL ) {
306 #define CATLINE( buf ) { \
308 len = strlen( buf ); \
309 while ( lcur + len + 1 > lmax ) { \
311 line = (char *) ch_realloc( line, lmax ); \
313 strcpy( line + lcur, buf ); \
320 * Get a line of input.
328 static char buf[BUFSIZ];
330 static int lmax, lcur;
334 while ( fgets( buf, sizeof(buf), fp ) != NULL ) {
335 if ( (p = strchr( buf, '\n' )) != NULL ) {
336 if( p > buf && p[-1] == '\r' ) --p;
340 if ( ! isspace( (unsigned char) buf[0] ) ) {
344 /* change leading whitespace to space */
351 return( line[0] ? line : NULL );
356 * Add a node to the array of replicas.
366 nr = ++sglob->num_replicas;
367 sglob->replicas = (Ri **) ch_realloc( sglob->replicas,
368 ( nr + 1 ) * sizeof( Re * ));
369 if ( sglob->replicas == NULL ) {
370 fprintf( stderr, "out of memory, add_replica\n" );
371 exit( EXIT_FAILURE );
373 sglob->replicas[ nr ] = NULL;
375 if ( Ri_init( &(sglob->replicas[ nr - 1 ])) < 0 ) {
376 fprintf( stderr, "out of memory, Ri_init\n" );
377 exit( EXIT_FAILURE );
379 if ( parse_replica_line( cargv, cargc,
380 sglob->replicas[ nr - 1] ) < 0 ) {
381 /* Something bad happened - back out */
383 "Warning: failed to add replica \"%s:%d - ignoring replica\n",
384 sglob->replicas[ nr - 1 ]->ri_hostname == NULL ?
385 "(null)" : sglob->replicas[ nr - 1 ]->ri_hostname,
386 sglob->replicas[ nr - 1 ]->ri_port );
387 sglob->replicas[ nr - 1] = NULL;
388 sglob->num_replicas--;
390 Debug( LDAP_DEBUG_CONFIG,
391 "Config: ** successfully added replica \"%s:%d\"\n",
392 sglob->replicas[ nr - 1 ]->ri_hostname == NULL ?
393 "(null)" : sglob->replicas[ nr - 1 ]->ri_hostname,
394 sglob->replicas[ nr - 1 ]->ri_port, 0 );
395 sglob->replicas[ nr - 1]->ri_stel =
396 sglob->st->st_add( sglob->st,
397 sglob->replicas[ nr - 1 ] );
398 if ( sglob->replicas[ nr - 1]->ri_stel == NULL ) {
399 fprintf( stderr, "Failed to add status element structure\n" );
400 exit( EXIT_FAILURE );
408 * Parse a "replica" line from the config file. replica lines should be
409 * in the following format:
410 * replica host=<hostname:portnumber> binddn=<binddn>
411 * bindmethod="simple" credentials=<creds>
414 * <hostname:portnumber> describes the host name and port number where the
415 * replica is running,
417 * <binddn> is the DN to bind to the replica slapd as,
419 * bindmethod is "simple", and
421 * <creds> are the credentials (e.g. password) for binddn. <creds> are
422 * only used for bindmethod=simple.
424 * The "replica" config file line may be split across multiple lines. If
425 * a line begins with whitespace, it is considered a continuation of the
431 #define GOT_ALL ( GOT_HOST | GOT_DN | GOT_METHOD )
446 for ( i = 1; i < cargc; i++ ) {
447 if ( !strncasecmp( cargv[ i ], HOSTSTR, sizeof( HOSTSTR ) - 1 ) ) {
448 if ( gots & GOT_HOST ) {
449 fprintf( stderr, "Error: Malformed \"replica\" line in slapd config " );
450 fprintf( stderr, "file, too many host or uri names specified, line %d\n",
454 val = cargv[ i ] + sizeof( HOSTSTR ); /* '\0' string terminator accounts for '=' */
455 if (( hp = strchr( val, ':' )) != NULL ) {
458 if ( lutil_atoi( &ri->ri_port, hp ) != 0 ) {
459 fprintf( stderr, "unable to parse port \"%s\", line %d\n",
464 if ( ri->ri_port <= 0 ) {
465 ri->ri_port = LDAP_PORT;
467 ri->ri_hostname = strdup( val );
469 } else if ( !strncasecmp( cargv[ i ], URISTR, sizeof( URISTR ) - 1 ) ) {
470 if ( gots & GOT_HOST ) {
471 fprintf( stderr, "Error: Malformed \"replica\" line in slapd config " );
472 fprintf( stderr, "file, too many host or uri names specified, line %d\n",
476 if ( ldap_url_parse( cargv[ i ] + sizeof( URISTR ), &ludp ) != LDAP_SUCCESS ) {
477 fprintf( stderr, "Error: Malformed \"replica\" line in slapd config " );
478 fprintf( stderr, "file, bad uri format specified, line %d\n",
482 if (ludp->lud_host == NULL) {
483 fprintf( stderr, "Error: Malformed \"replica\" line in slapd config " );
484 fprintf( stderr, "file, missing uri hostname, line %d\n",
488 ri->ri_hostname = strdup ( ludp->lud_host );
489 ri->ri_port = ludp->lud_port;
490 ri->ri_uri = strdup ( cargv[ i ] + sizeof( URISTR ) );
491 ldap_free_urldesc( ludp );
493 } else if ( !strncasecmp( cargv[ i ],
494 ATTRSTR, sizeof( ATTRSTR ) - 1 ) ) {
496 } else if ( !strncasecmp( cargv[ i ],
497 SUFFIXSTR, sizeof( SUFFIXSTR ) - 1 ) ) {
499 } else if ( !strncasecmp( cargv[i], STARTTLSSTR, sizeof(STARTTLSSTR)-1 )) {
500 val = cargv[ i ] + sizeof( STARTTLSSTR );
501 if( !strcasecmp( val, CRITICALSTR ) ) {
502 ri->ri_tls = TLS_CRITICAL;
506 } else if ( !strncasecmp( cargv[ i ], TLSSTR, sizeof( TLSSTR ) - 1 ) ) {
507 val = cargv[ i ] + sizeof( TLSSTR );
508 if( !strcasecmp( val, CRITICALSTR ) ) {
509 ri->ri_tls = TLS_CRITICAL;
513 } else if ( !strncasecmp( cargv[ i ],
514 BINDDNSTR, sizeof( BINDDNSTR ) - 1 ) ) {
515 val = cargv[ i ] + sizeof( BINDDNSTR );
516 ri->ri_bind_dn = strdup( val );
518 } else if ( !strncasecmp( cargv[ i ], BINDMETHSTR,
519 sizeof( BINDMETHSTR ) - 1 ) ) {
520 val = cargv[ i ] + sizeof( BINDMETHSTR );
521 if ( !strcasecmp( val, KERBEROSSTR )) {
522 fprintf( stderr, "Error: a bind method of \"kerberos\" was\n" );
523 fprintf( stderr, "specified in the slapd configuration file.\n" );
524 fprintf( stderr, "slurpd no longer supports Kerberos.\n" );
525 exit( EXIT_FAILURE );
526 } else if ( !strcasecmp( val, SIMPLESTR )) {
527 ri->ri_bind_method = LDAP_AUTH_SIMPLE;
529 } else if ( !strcasecmp( val, SASLSTR )) {
530 ri->ri_bind_method = LDAP_AUTH_SASL;
533 ri->ri_bind_method = -1;
535 } else if ( !strncasecmp( cargv[ i ],
536 SASLMECHSTR, sizeof( SASLMECHSTR ) - 1 ) ) {
537 val = cargv[ i ] + sizeof( SASLMECHSTR );
539 ri->ri_saslmech = strdup( val );
540 } else if ( !strncasecmp( cargv[ i ],
541 CREDSTR, sizeof( CREDSTR ) - 1 ) ) {
542 val = cargv[ i ] + sizeof( CREDSTR );
543 ri->ri_password = strdup( val );
544 } else if ( !strncasecmp( cargv[ i ],
545 SECPROPSSTR, sizeof( SECPROPSSTR ) - 1 ) ) {
546 val = cargv[ i ] + sizeof( SECPROPSSTR );
547 ri->ri_secprops = strdup( val );
548 } else if ( !strncasecmp( cargv[ i ],
549 REALMSTR, sizeof( REALMSTR ) - 1 ) ) {
550 val = cargv[ i ] + sizeof( REALMSTR );
551 ri->ri_realm = strdup( val );
552 } else if ( !strncasecmp( cargv[ i ],
553 AUTHCSTR, sizeof( AUTHCSTR ) - 1 ) ) {
554 val = cargv[ i ] + sizeof( AUTHCSTR );
555 ri->ri_authcId = strdup( val );
556 } else if ( !strncasecmp( cargv[ i ],
557 OLDAUTHCSTR, sizeof( OLDAUTHCSTR ) - 1 ) ) {
558 /* Old authcID is provided for some backwards compatibility */
559 val = cargv[ i ] + sizeof( OLDAUTHCSTR );
560 ri->ri_authcId = strdup( val );
561 } else if ( !strncasecmp( cargv[ i ],
562 AUTHZSTR, sizeof( AUTHZSTR ) - 1 ) ) {
563 val = cargv[ i ] + sizeof( AUTHZSTR );
564 ri->ri_authzId = strdup( val );
565 } else if ( !strncasecmp( cargv[ i ],
566 SRVTABSTR, sizeof( SRVTABSTR ) - 1 ) ) {
567 val = cargv[ i ] + sizeof( SRVTABSTR );
568 if ( ri->ri_srvtab != NULL ) {
569 free( ri->ri_srvtab );
571 ri->ri_srvtab = strdup( val );
574 "Error: parse_replica_line: unknown keyword \"%s\"\n",
579 if ( ri->ri_bind_method == LDAP_AUTH_SASL) {
580 if ((gots & GOT_MECH) == 0) {
581 fprintf( stderr, "Error: \"replica\" line needs SASLmech flag in " );
582 fprintf( stderr, "slapd config file, line %d\n", lineno );
585 } else if ( gots != GOT_ALL ) {
586 fprintf( stderr, "Error: Malformed \"replica\" line in slapd " );
587 fprintf( stderr, "config file, line %d\n", lineno );