2 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
4 * Copyright 1998-2003 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>
56 /* Forward declarations */
57 static void add_replica LDAP_P(( char **, int ));
58 static int parse_replica_line LDAP_P(( char **, int, Ri *));
59 static void parse_line LDAP_P(( char * ));
60 static char *getline LDAP_P(( FILE * ));
61 static char *strtok_quote LDAP_P(( char *, char * ));
63 int cargc = 0, cargv_size = 0;
65 /* current config file line # */
68 char *slurpd_pid_file = NULL;
69 char *slurpd_args_file = NULL;
72 * Read the slapd config file, looking only for config options we're
73 * interested in. Since we haven't detached from the controlling
74 * terminal yet, we just perror() and fprintf here.
84 if ( cargv == NULL ) {
85 cargv = ch_calloc( ARGS_STEP + 1, sizeof(*cargv) );
86 cargv_size = ARGS_STEP + 1;
90 LDAP_LOG ( CONFIG, ARGS,
91 "slurpd_read_config: Config: opening config file \"%s\"\n",
94 Debug( LDAP_DEBUG_CONFIG, "Config: opening config file \"%s\"\n",
98 if ( (fp = fopen( fname, "r" )) == NULL ) {
100 exit( EXIT_FAILURE );
104 while ( (line = getline( fp )) != NULL ) {
105 /* skip comments and blank lines */
106 if ( line[0] == '#' || line[0] == '\0' ) {
111 LDAP_LOG ( CONFIG, DETAIL1,
112 "slurpd_read_config: Config: (%s)\n", line, 0, 0 );
114 Debug( LDAP_DEBUG_CONFIG, "Config: (%s)\n", line, 0, 0 );
120 fprintf( stderr, "line %d: bad config line (ignored)\n", lineno );
124 /* replication log file to which changes are appended */
125 if ( strcasecmp( cargv[0], "replogfile" ) == 0 ) {
127 * if slapd_replogfile has a value, the -r option was given,
128 * so use that value. If slapd_replogfile has length == 0,
129 * then we should use the value in the config file we're reading.
131 if ( sglob->slapd_replogfile[ 0 ] == '\0' ) {
134 "line %d: missing filename in \"replogfile ",
136 fprintf( stderr, "<filename>\" line\n" );
137 exit( EXIT_FAILURE );
138 } else if ( cargc > 2 && *cargv[2] != '#' ) {
140 "line %d: extra cruft at the end of \"replogfile %s\"",
142 fprintf( stderr, "line (ignored)\n" );
144 strcpy( sglob->slapd_replogfile, cargv[1] );
146 } else if ( strcasecmp( cargv[0], "replica" ) == 0 ) {
147 add_replica( cargv, cargc );
149 /* include another config file */
150 } else if ( strcasecmp( cargv[0], "include" ) == 0 ) {
156 LDAP_LOG( CONFIG, CRIT,
157 "%s: line %d: missing filename in \"include "
158 "<filename>\" line.\n", fname, lineno , 0 );
160 Debug( LDAP_DEBUG_ANY,
161 "%s: line %d: missing filename in \"include <filename>\" line\n",
167 savefname = strdup( cargv[1] );
170 if ( slurpd_read_config( savefname ) != 0 ) {
175 lineno = savelineno - 1;
177 } else if ( strcasecmp( cargv[0], "replica-pidfile" ) == 0 ) {
180 LDAP_LOG( CONFIG, CRIT,
181 "%s: line %d missing file name in \"replica-pidfile <file>\" "
182 "line.\n", fname, lineno, 0 );
184 Debug( LDAP_DEBUG_ANY,
185 "%s: line %d: missing file name in \"replica-pidfile <file>\" line\n",
192 slurpd_pid_file = ch_strdup( cargv[1] );
194 } else if ( strcasecmp( cargv[0], "replica-argsfile" ) == 0 ) {
197 LDAP_LOG( CONFIG, CRIT,
198 "%s: %d: missing file name in "
199 "\"argsfile <file>\" line.\n",
202 Debug( LDAP_DEBUG_ANY,
203 "%s: line %d: missing file name in \"argsfile <file>\" line\n",
210 slurpd_args_file = ch_strdup( cargv[1] );
215 LDAP_LOG ( CONFIG, RESULTS,
216 "slurpd_read_config: Config: "
217 "** configuration file successfully read and parsed\n", 0, 0, 0 );
219 Debug( LDAP_DEBUG_CONFIG,
220 "Config: ** configuration file successfully read and parsed\n",
230 * Parse one line of input.
240 for ( token = strtok_quote( line, " \t" ); token != NULL;
241 token = strtok_quote( NULL, " \t" ) )
243 if ( cargc == cargv_size - 1 ) {
245 tmp = ch_realloc( cargv, (cargv_size + ARGS_STEP) *
252 cargv_size += ARGS_STEP;
255 cargv[cargc++] = token;
273 if ( line != NULL ) {
276 while ( *next && strchr( sep, *next ) ) {
280 if ( *next == '\0' ) {
286 for ( inquote = 0; *next; ) {
294 AC_MEMCPY( next, next + 1, strlen( next + 1 ) + 1 );
299 AC_MEMCPY( next, next + 1, strlen( next + 1 ) + 1 );
300 next++; /* dont parse the escaped character */
305 if ( strchr( sep, *next ) != NULL ) {
318 #define CATLINE( buf ) { \
320 len = strlen( buf ); \
321 while ( lcur + len + 1 > lmax ) { \
323 line = (char *) ch_realloc( line, lmax ); \
325 strcpy( line + lcur, buf ); \
332 * Get a line of input.
340 static char buf[BUFSIZ];
342 static int lmax, lcur;
346 while ( fgets( buf, sizeof(buf), fp ) != NULL ) {
347 if ( (p = strchr( buf, '\n' )) != NULL ) {
348 if( p > buf && p[-1] == '\r' ) --p;
352 if ( ! isspace( (unsigned char) buf[0] ) ) {
356 /* change leading whitespace to space */
363 return( line[0] ? line : NULL );
368 * Add a node to the array of replicas.
378 nr = ++sglob->num_replicas;
379 sglob->replicas = (Ri **) ch_realloc( sglob->replicas,
380 ( nr + 1 ) * sizeof( Re * ));
381 if ( sglob->replicas == NULL ) {
382 fprintf( stderr, "out of memory, add_replica\n" );
383 exit( EXIT_FAILURE );
385 sglob->replicas[ nr ] = NULL;
387 if ( Ri_init( &(sglob->replicas[ nr - 1 ])) < 0 ) {
388 fprintf( stderr, "out of memory, Ri_init\n" );
389 exit( EXIT_FAILURE );
391 if ( parse_replica_line( cargv, cargc,
392 sglob->replicas[ nr - 1] ) < 0 ) {
393 /* Something bad happened - back out */
395 "Warning: failed to add replica \"%s:%d - ignoring replica\n",
396 sglob->replicas[ nr - 1 ]->ri_hostname == NULL ?
397 "(null)" : sglob->replicas[ nr - 1 ]->ri_hostname,
398 sglob->replicas[ nr - 1 ]->ri_port );
399 sglob->replicas[ nr - 1] = NULL;
400 sglob->num_replicas--;
403 LDAP_LOG ( CONFIG, RESULTS,
404 "add_replica: Config: ** successfully added replica \"%s%d\"\n",
405 sglob->replicas[ nr - 1 ]->ri_hostname == NULL ?
406 "(null)" : sglob->replicas[ nr - 1 ]->ri_hostname,
407 sglob->replicas[ nr - 1 ]->ri_port, 0 );
409 Debug( LDAP_DEBUG_CONFIG,
410 "Config: ** successfully added replica \"%s:%d\"\n",
411 sglob->replicas[ nr - 1 ]->ri_hostname == NULL ?
412 "(null)" : sglob->replicas[ nr - 1 ]->ri_hostname,
413 sglob->replicas[ nr - 1 ]->ri_port, 0 );
415 sglob->replicas[ nr - 1]->ri_stel =
416 sglob->st->st_add( sglob->st,
417 sglob->replicas[ nr - 1 ] );
418 if ( sglob->replicas[ nr - 1]->ri_stel == NULL ) {
419 fprintf( stderr, "Failed to add status element structure\n" );
420 exit( EXIT_FAILURE );
428 * Parse a "replica" line from the config file. replica lines should be
429 * in the following format:
430 * replica host=<hostname:portnumber> binddn=<binddn>
431 * bindmethod="simple" credentials=<creds>
434 * <hostname:portnumber> describes the host name and port number where the
435 * replica is running,
437 * <binddn> is the DN to bind to the replica slapd as,
439 * bindmethod is "simple", and
441 * <creds> are the credentials (e.g. password) for binddn. <creds> are
442 * only used for bindmethod=simple.
444 * The "replica" config file line may be split across multiple lines. If
445 * a line begins with whitespace, it is considered a continuation of the
451 #define GOT_ALL ( GOT_HOST | GOT_DN | GOT_METHOD )
466 for ( i = 1; i < cargc; i++ ) {
467 if ( !strncasecmp( cargv[ i ], HOSTSTR, sizeof( HOSTSTR ) - 1 ) ) {
468 if ( gots & GOT_HOST ) {
469 fprintf( stderr, "Error: Malformed \"replica\" line in slapd config " );
470 fprintf( stderr, "file, too many host or uri names specified, line %d\n",
474 val = cargv[ i ] + sizeof( HOSTSTR ); /* '\0' string terminator accounts for '=' */
475 if (( hp = strchr( val, ':' )) != NULL ) {
478 ri->ri_port = atoi( hp );
480 if ( ri->ri_port <= 0 ) {
483 ri->ri_hostname = strdup( val );
485 } else if ( !strncasecmp( cargv[ i ], URISTR, sizeof( URISTR ) - 1 ) ) {
486 if ( gots & GOT_HOST ) {
487 fprintf( stderr, "Error: Malformed \"replica\" line in slapd config " );
488 fprintf( stderr, "file, too many host or uri names specified, line %d\n",
492 if ( ldap_url_parse( cargv[ i ] + sizeof( URISTR ), &ludp ) != LDAP_SUCCESS ) {
493 fprintf( stderr, "Error: Malformed \"replica\" line in slapd config " );
494 fprintf( stderr, "file, bad uri format specified, line %d\n",
498 if (ludp->lud_host == NULL) {
499 fprintf( stderr, "Error: Malformed \"replica\" line in slapd config " );
500 fprintf( stderr, "file, missing uri hostname, line %d\n",
504 ri->ri_hostname = strdup ( ludp->lud_host );
505 ri->ri_port = ludp->lud_port;
506 ri->ri_uri = strdup ( cargv[ i ] + sizeof( URISTR ) );
507 ldap_free_urldesc( ludp );
509 } else if ( !strncasecmp( cargv[ i ],
510 ATTRSTR, sizeof( ATTRSTR ) - 1 ) ) {
512 } else if ( !strncasecmp( cargv[ i ],
513 SUFFIXSTR, sizeof( SUFFIXSTR ) - 1 ) ) {
515 } else if ( !strncasecmp( cargv[i], STARTTLSSTR, sizeof(STARTTLSSTR)-1 )) {
516 val = cargv[ i ] + sizeof( STARTTLSSTR );
517 if( !strcasecmp( val, CRITICALSTR ) ) {
518 ri->ri_tls = TLS_CRITICAL;
522 } else if ( !strncasecmp( cargv[ i ], TLSSTR, sizeof( TLSSTR ) - 1 ) ) {
523 val = cargv[ i ] + sizeof( TLSSTR );
524 if( !strcasecmp( val, CRITICALSTR ) ) {
525 ri->ri_tls = TLS_CRITICAL;
529 } else if ( !strncasecmp( cargv[ i ],
530 BINDDNSTR, sizeof( BINDDNSTR ) - 1 ) ) {
531 val = cargv[ i ] + sizeof( BINDDNSTR );
532 ri->ri_bind_dn = strdup( val );
534 } else if ( !strncasecmp( cargv[ i ], BINDMETHSTR,
535 sizeof( BINDMETHSTR ) - 1 ) ) {
536 val = cargv[ i ] + sizeof( BINDMETHSTR );
537 if ( !strcasecmp( val, KERBEROSSTR )) {
538 fprintf( stderr, "Error: a bind method of \"kerberos\" was\n" );
539 fprintf( stderr, "specified in the slapd configuration file.\n" );
540 fprintf( stderr, "slurpd no longer supports Kerberos.\n" );
541 exit( EXIT_FAILURE );
542 } else if ( !strcasecmp( val, SIMPLESTR )) {
543 ri->ri_bind_method = LDAP_AUTH_SIMPLE;
545 } else if ( !strcasecmp( val, SASLSTR )) {
546 ri->ri_bind_method = LDAP_AUTH_SASL;
549 ri->ri_bind_method = -1;
551 } else if ( !strncasecmp( cargv[ i ],
552 SASLMECHSTR, sizeof( SASLMECHSTR ) - 1 ) ) {
553 val = cargv[ i ] + sizeof( SASLMECHSTR );
555 ri->ri_saslmech = strdup( val );
556 } else if ( !strncasecmp( cargv[ i ],
557 CREDSTR, sizeof( CREDSTR ) - 1 ) ) {
558 val = cargv[ i ] + sizeof( CREDSTR );
559 ri->ri_password = strdup( val );
560 } else if ( !strncasecmp( cargv[ i ],
561 SECPROPSSTR, sizeof( SECPROPSSTR ) - 1 ) ) {
562 val = cargv[ i ] + sizeof( SECPROPSSTR );
563 ri->ri_secprops = strdup( val );
564 } else if ( !strncasecmp( cargv[ i ],
565 REALMSTR, sizeof( REALMSTR ) - 1 ) ) {
566 val = cargv[ i ] + sizeof( REALMSTR );
567 ri->ri_realm = strdup( val );
568 } else if ( !strncasecmp( cargv[ i ],
569 AUTHCSTR, sizeof( AUTHCSTR ) - 1 ) ) {
570 val = cargv[ i ] + sizeof( AUTHCSTR );
571 ri->ri_authcId = strdup( val );
572 } else if ( !strncasecmp( cargv[ i ],
573 OLDAUTHCSTR, sizeof( OLDAUTHCSTR ) - 1 ) ) {
574 /* Old authcID is provided for some backwards compatibility */
575 val = cargv[ i ] + sizeof( OLDAUTHCSTR );
576 ri->ri_authcId = strdup( val );
577 } else if ( !strncasecmp( cargv[ i ],
578 AUTHZSTR, sizeof( AUTHZSTR ) - 1 ) ) {
579 val = cargv[ i ] + sizeof( AUTHZSTR );
580 ri->ri_authzId = strdup( val );
581 } else if ( !strncasecmp( cargv[ i ],
582 SRVTABSTR, sizeof( SRVTABSTR ) - 1 ) ) {
583 val = cargv[ i ] + sizeof( SRVTABSTR );
584 if ( ri->ri_srvtab != NULL ) {
585 free( ri->ri_srvtab );
587 ri->ri_srvtab = strdup( val );
590 "Error: parse_replica_line: unknown keyword \"%s\"\n",
595 if ( ri->ri_bind_method == LDAP_AUTH_SASL) {
596 if ((gots & GOT_MECH) == 0) {
597 fprintf( stderr, "Error: \"replica\" line needs SASLmech flag in " );
598 fprintf( stderr, "slapd config file, line %d\n", lineno );
601 } else if ( gots != GOT_ALL ) {
602 fprintf( stderr, "Error: Malformed \"replica\" line in slapd " );
603 fprintf( stderr, "config file, line %d\n", lineno );