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 c = atoi( cargv[1] );
198 Debug( LDAP_DEBUG_ANY, "%s: line %d: invalid interval "
199 "(%d) in \"replicationinterval <seconds>\" line\n",
205 sglob->no_work_interval = c;
209 Debug( LDAP_DEBUG_CONFIG,
210 "Config: ** configuration file successfully read and parsed\n",
219 * Parse one line of input.
229 for ( token = strtok_quote( line, " \t" ); token != NULL;
230 token = strtok_quote( NULL, " \t" ) )
232 if ( cargc == cargv_size - 1 ) {
234 tmp = ch_realloc( cargv, (cargv_size + ARGS_STEP) *
241 cargv_size += ARGS_STEP;
244 cargv[cargc++] = token;
262 if ( line != NULL ) {
265 while ( *next && strchr( sep, *next ) ) {
269 if ( *next == '\0' ) {
275 for ( inquote = 0; *next; ) {
283 AC_MEMCPY( next, next + 1, strlen( next + 1 ) + 1 );
288 AC_MEMCPY( next, next + 1, strlen( next + 1 ) + 1 );
289 next++; /* dont parse the escaped character */
294 if ( strchr( sep, *next ) != NULL ) {
307 #define CATLINE( buf ) { \
309 len = strlen( buf ); \
310 while ( lcur + len + 1 > lmax ) { \
312 line = (char *) ch_realloc( line, lmax ); \
314 strcpy( line + lcur, buf ); \
321 * Get a line of input.
329 static char buf[BUFSIZ];
331 static int lmax, lcur;
335 while ( fgets( buf, sizeof(buf), fp ) != NULL ) {
336 if ( (p = strchr( buf, '\n' )) != NULL ) {
337 if( p > buf && p[-1] == '\r' ) --p;
341 if ( ! isspace( (unsigned char) buf[0] ) ) {
345 /* change leading whitespace to space */
352 return( line[0] ? line : NULL );
357 * Add a node to the array of replicas.
367 nr = ++sglob->num_replicas;
368 sglob->replicas = (Ri **) ch_realloc( sglob->replicas,
369 ( nr + 1 ) * sizeof( Re * ));
370 if ( sglob->replicas == NULL ) {
371 fprintf( stderr, "out of memory, add_replica\n" );
372 exit( EXIT_FAILURE );
374 sglob->replicas[ nr ] = NULL;
376 if ( Ri_init( &(sglob->replicas[ nr - 1 ])) < 0 ) {
377 fprintf( stderr, "out of memory, Ri_init\n" );
378 exit( EXIT_FAILURE );
380 if ( parse_replica_line( cargv, cargc,
381 sglob->replicas[ nr - 1] ) < 0 ) {
382 /* Something bad happened - back out */
384 "Warning: failed to add replica \"%s:%d - ignoring replica\n",
385 sglob->replicas[ nr - 1 ]->ri_hostname == NULL ?
386 "(null)" : sglob->replicas[ nr - 1 ]->ri_hostname,
387 sglob->replicas[ nr - 1 ]->ri_port );
388 sglob->replicas[ nr - 1] = NULL;
389 sglob->num_replicas--;
391 Debug( LDAP_DEBUG_CONFIG,
392 "Config: ** successfully added replica \"%s:%d\"\n",
393 sglob->replicas[ nr - 1 ]->ri_hostname == NULL ?
394 "(null)" : sglob->replicas[ nr - 1 ]->ri_hostname,
395 sglob->replicas[ nr - 1 ]->ri_port, 0 );
396 sglob->replicas[ nr - 1]->ri_stel =
397 sglob->st->st_add( sglob->st,
398 sglob->replicas[ nr - 1 ] );
399 if ( sglob->replicas[ nr - 1]->ri_stel == NULL ) {
400 fprintf( stderr, "Failed to add status element structure\n" );
401 exit( EXIT_FAILURE );
409 * Parse a "replica" line from the config file. replica lines should be
410 * in the following format:
411 * replica host=<hostname:portnumber> binddn=<binddn>
412 * bindmethod="simple" credentials=<creds>
415 * <hostname:portnumber> describes the host name and port number where the
416 * replica is running,
418 * <binddn> is the DN to bind to the replica slapd as,
420 * bindmethod is "simple", and
422 * <creds> are the credentials (e.g. password) for binddn. <creds> are
423 * only used for bindmethod=simple.
425 * The "replica" config file line may be split across multiple lines. If
426 * a line begins with whitespace, it is considered a continuation of the
432 #define GOT_ALL ( GOT_HOST | GOT_DN | GOT_METHOD )
447 for ( i = 1; i < cargc; i++ ) {
448 if ( !strncasecmp( cargv[ i ], HOSTSTR, sizeof( HOSTSTR ) - 1 ) ) {
449 if ( gots & GOT_HOST ) {
450 fprintf( stderr, "Error: Malformed \"replica\" line in slapd config " );
451 fprintf( stderr, "file, too many host or uri names specified, line %d\n",
455 val = cargv[ i ] + sizeof( HOSTSTR ); /* '\0' string terminator accounts for '=' */
456 if (( hp = strchr( val, ':' )) != NULL ) {
459 ri->ri_port = atoi( hp );
461 if ( ri->ri_port <= 0 ) {
462 ri->ri_port = LDAP_PORT;
464 ri->ri_hostname = strdup( val );
466 } else if ( !strncasecmp( cargv[ i ], URISTR, sizeof( URISTR ) - 1 ) ) {
467 if ( gots & GOT_HOST ) {
468 fprintf( stderr, "Error: Malformed \"replica\" line in slapd config " );
469 fprintf( stderr, "file, too many host or uri names specified, line %d\n",
473 if ( ldap_url_parse( cargv[ i ] + sizeof( URISTR ), &ludp ) != LDAP_SUCCESS ) {
474 fprintf( stderr, "Error: Malformed \"replica\" line in slapd config " );
475 fprintf( stderr, "file, bad uri format specified, line %d\n",
479 if (ludp->lud_host == NULL) {
480 fprintf( stderr, "Error: Malformed \"replica\" line in slapd config " );
481 fprintf( stderr, "file, missing uri hostname, line %d\n",
485 ri->ri_hostname = strdup ( ludp->lud_host );
486 ri->ri_port = ludp->lud_port;
487 ri->ri_uri = strdup ( cargv[ i ] + sizeof( URISTR ) );
488 ldap_free_urldesc( ludp );
490 } else if ( !strncasecmp( cargv[ i ],
491 ATTRSTR, sizeof( ATTRSTR ) - 1 ) ) {
493 } else if ( !strncasecmp( cargv[ i ],
494 SUFFIXSTR, sizeof( SUFFIXSTR ) - 1 ) ) {
496 } else if ( !strncasecmp( cargv[i], STARTTLSSTR, sizeof(STARTTLSSTR)-1 )) {
497 val = cargv[ i ] + sizeof( STARTTLSSTR );
498 if( !strcasecmp( val, CRITICALSTR ) ) {
499 ri->ri_tls = TLS_CRITICAL;
503 } else if ( !strncasecmp( cargv[ i ], TLSSTR, sizeof( TLSSTR ) - 1 ) ) {
504 val = cargv[ i ] + sizeof( TLSSTR );
505 if( !strcasecmp( val, CRITICALSTR ) ) {
506 ri->ri_tls = TLS_CRITICAL;
510 } else if ( !strncasecmp( cargv[ i ],
511 BINDDNSTR, sizeof( BINDDNSTR ) - 1 ) ) {
512 val = cargv[ i ] + sizeof( BINDDNSTR );
513 ri->ri_bind_dn = strdup( val );
515 } else if ( !strncasecmp( cargv[ i ], BINDMETHSTR,
516 sizeof( BINDMETHSTR ) - 1 ) ) {
517 val = cargv[ i ] + sizeof( BINDMETHSTR );
518 if ( !strcasecmp( val, KERBEROSSTR )) {
519 fprintf( stderr, "Error: a bind method of \"kerberos\" was\n" );
520 fprintf( stderr, "specified in the slapd configuration file.\n" );
521 fprintf( stderr, "slurpd no longer supports Kerberos.\n" );
522 exit( EXIT_FAILURE );
523 } else if ( !strcasecmp( val, SIMPLESTR )) {
524 ri->ri_bind_method = LDAP_AUTH_SIMPLE;
526 } else if ( !strcasecmp( val, SASLSTR )) {
527 ri->ri_bind_method = LDAP_AUTH_SASL;
530 ri->ri_bind_method = -1;
532 } else if ( !strncasecmp( cargv[ i ],
533 SASLMECHSTR, sizeof( SASLMECHSTR ) - 1 ) ) {
534 val = cargv[ i ] + sizeof( SASLMECHSTR );
536 ri->ri_saslmech = strdup( val );
537 } else if ( !strncasecmp( cargv[ i ],
538 CREDSTR, sizeof( CREDSTR ) - 1 ) ) {
539 val = cargv[ i ] + sizeof( CREDSTR );
540 ri->ri_password = strdup( val );
541 } else if ( !strncasecmp( cargv[ i ],
542 SECPROPSSTR, sizeof( SECPROPSSTR ) - 1 ) ) {
543 val = cargv[ i ] + sizeof( SECPROPSSTR );
544 ri->ri_secprops = strdup( val );
545 } else if ( !strncasecmp( cargv[ i ],
546 REALMSTR, sizeof( REALMSTR ) - 1 ) ) {
547 val = cargv[ i ] + sizeof( REALMSTR );
548 ri->ri_realm = strdup( val );
549 } else if ( !strncasecmp( cargv[ i ],
550 AUTHCSTR, sizeof( AUTHCSTR ) - 1 ) ) {
551 val = cargv[ i ] + sizeof( AUTHCSTR );
552 ri->ri_authcId = strdup( val );
553 } else if ( !strncasecmp( cargv[ i ],
554 OLDAUTHCSTR, sizeof( OLDAUTHCSTR ) - 1 ) ) {
555 /* Old authcID is provided for some backwards compatibility */
556 val = cargv[ i ] + sizeof( OLDAUTHCSTR );
557 ri->ri_authcId = strdup( val );
558 } else if ( !strncasecmp( cargv[ i ],
559 AUTHZSTR, sizeof( AUTHZSTR ) - 1 ) ) {
560 val = cargv[ i ] + sizeof( AUTHZSTR );
561 ri->ri_authzId = strdup( val );
562 } else if ( !strncasecmp( cargv[ i ],
563 SRVTABSTR, sizeof( SRVTABSTR ) - 1 ) ) {
564 val = cargv[ i ] + sizeof( SRVTABSTR );
565 if ( ri->ri_srvtab != NULL ) {
566 free( ri->ri_srvtab );
568 ri->ri_srvtab = strdup( val );
571 "Error: parse_replica_line: unknown keyword \"%s\"\n",
576 if ( ri->ri_bind_method == LDAP_AUTH_SASL) {
577 if ((gots & GOT_MECH) == 0) {
578 fprintf( stderr, "Error: \"replica\" line needs SASLmech flag in " );
579 fprintf( stderr, "slapd config file, line %d\n", lineno );
582 } else if ( gots != GOT_ALL ) {
583 fprintf( stderr, "Error: Malformed \"replica\" line in slapd " );
584 fprintf( stderr, "config file, line %d\n", lineno );