]> git.sur5r.net Git - openldap/blob - servers/slurpd/config.c
Trim both \n and \r\n from config files.
[openldap] / servers / slurpd / config.c
1 /* $OpenLDAP$ */
2 /*
3  * Copyright 1998-2000 The OpenLDAP Foundation, All Rights Reserved.
4  * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
5  */
6 /*
7  * Copyright (c) 1996 Regents of the University of Michigan.
8  * All rights reserved.
9  *
10  * Redistribution and use in source and binary forms are permitted
11  * provided that this notice is preserved and that due credit is given
12  * to the University of Michigan at Ann Arbor. The name of the University
13  * may not be used to endorse or promote products derived from this
14  * software without specific prior written permission. This software
15  * is provided ``as is'' without express or implied warranty.
16  */
17
18
19 /*
20  * config.c - configuration file handling routines
21  */
22
23 #include "portable.h"
24
25 #include <stdio.h>
26
27 #include <ac/stdlib.h>
28 #include <ac/string.h>
29 #include <ac/socket.h>
30 #include <ac/ctype.h>
31
32 #include <ldap.h>
33
34 #include "slurp.h"
35 #include "globals.h"
36
37 #define MAXARGS 500
38
39 /* Forward declarations */
40 static void     add_replica LDAP_P(( char **, int ));
41 static int      parse_replica_line LDAP_P(( char **, int, Ri *));
42 static void     parse_line LDAP_P(( char *, int *, char ** ));
43 static char     *getline LDAP_P(( FILE * ));
44 static char     *strtok_quote LDAP_P(( char *, char * ));
45
46 /* current config file line # */
47 static int      lineno;
48
49
50
51 /*
52  * Read the slapd config file, looking only for config options we're
53  * interested in.  Since we haven't detached from the controlling
54  * terminal yet, we just perror() and fprintf here.
55  */
56 int
57 slurpd_read_config(
58     char        *fname
59 )
60 {
61     FILE        *fp;
62     char        *line;
63     int         cargc;
64     char        *cargv[MAXARGS];
65
66     Debug( LDAP_DEBUG_CONFIG, "Config: opening config file \"%s\"\n",
67             fname, 0, 0 );
68
69     if ( (fp = fopen( fname, "r" )) == NULL ) {
70         perror( fname );
71         exit( EXIT_FAILURE );
72     }
73
74     lineno = 0;
75     while ( (line = getline( fp )) != NULL ) {
76         /* skip comments and blank lines */
77         if ( line[0] == '#' || line[0] == '\0' ) {
78             continue;
79         }
80
81         Debug( LDAP_DEBUG_CONFIG, "Config: (%s)\n", line, 0, 0 );
82
83         parse_line( line, &cargc, cargv );
84
85         if ( cargc < 1 ) {
86             fprintf( stderr, "line %d: bad config line (ignored)\n", lineno );
87             continue;
88         }
89
90         /* replication log file to which changes are appended */
91         if ( strcasecmp( cargv[0], "replogfile" ) == 0 ) {
92             /* 
93              * if slapd_replogfile has a value, the -r option was given,
94              * so use that value.  If slapd_replogfile has length == 0,
95              * then we should use the value in the config file we're reading.
96              */
97             if ( sglob->slapd_replogfile[ 0 ] == '\0' ) {
98                 if ( cargc < 2 ) {
99                     fprintf( stderr,
100                         "line %d: missing filename in \"replogfile ",
101                         lineno );
102                     fprintf( stderr, "<filename>\" line\n" );
103                     exit( EXIT_FAILURE );
104                 } else if ( cargc > 2 && *cargv[2] != '#' ) {
105                     fprintf( stderr,
106                         "line %d: extra cruft at the end of \"replogfile %s\"",
107                         lineno, cargv[1] );
108                     fprintf( stderr, "line (ignored)\n" );
109                 }
110                 strcpy( sglob->slapd_replogfile, cargv[1] );
111             }
112         } else if ( strcasecmp( cargv[0], "replica" ) == 0 ) {
113             add_replica( cargv, cargc );
114             
115             /* include another config file */
116         } else if ( strcasecmp( cargv[0], "include" ) == 0 ) {
117             char *savefname;
118             int savelineno;
119
120             if ( cargc < 2 ) {
121 #ifdef NEW_LOGGING
122                 LDAP_LOG(( "config", LDAP_LEVEL_CRIT,
123                         "%s: line %d: missing filename in \"include "
124                         "<filename>\" line.\n", fname, lineno ));
125 #else
126                 Debug( LDAP_DEBUG_ANY,
127         "%s: line %d: missing filename in \"include <filename>\" line\n",
128                         fname, lineno, 0 );
129 #endif
130                 
131                 return( 1 );
132             }
133             savefname = strdup( cargv[1] );
134             savelineno = lineno;
135             
136             if ( slurpd_read_config( savefname ) != 0 ) {
137                 return( 1 );
138             }
139                 
140             free( savefname );
141             lineno = savelineno - 1;
142         }
143     }
144     fclose( fp );
145     Debug( LDAP_DEBUG_CONFIG,
146             "Config: ** configuration file successfully read and parsed\n",
147             0, 0, 0 );
148     return 0;
149 }
150
151
152
153
154 /*
155  * Parse one line of input.
156  */
157 static void
158 parse_line(
159     char        *line,
160     int         *argcp,
161     char        **argv
162 )
163 {
164     char *      token;
165
166     *argcp = 0;
167     for ( token = strtok_quote( line, " \t" ); token != NULL;
168         token = strtok_quote( NULL, " \t" ) ) {
169         argv[(*argcp)++] = token;
170     }
171     argv[*argcp] = NULL;
172 }
173
174
175
176
177 static char *
178 strtok_quote(
179     char *line,
180     char *sep
181 )
182 {
183     int         inquote;
184     char        *tmp;
185     static char *next;
186
187     if ( line != NULL ) {
188         next = line;
189     }
190     while ( *next && strchr( sep, *next ) ) {
191         next++;
192     }
193
194     if ( *next == '\0' ) {
195         next = NULL;
196         return( NULL );
197     }
198     tmp = next;
199
200     for ( inquote = 0; *next; ) {
201         switch ( *next ) {
202         case '"':
203             if ( inquote ) {
204                 inquote = 0;
205             } else {
206                 inquote = 1;
207             }
208             AC_MEMCPY( next, next + 1, strlen( next + 1 ) + 1 );
209             break;
210
211         case '\\':
212             if ( next[1] )
213                 AC_MEMCPY( next, next + 1, strlen( next + 1 ) + 1 );
214             next++;             /* dont parse the escaped character */
215             break;
216
217         default:
218             if ( ! inquote ) {
219                 if ( strchr( sep, *next ) != NULL ) {
220                     *next++ = '\0';
221                     return( tmp );
222                 }
223             }
224             next++;
225             break;
226         }
227     }
228
229     return( tmp );
230 }
231
232 #define CATLINE( buf )  { \
233     int len; \
234     len = strlen( buf ); \
235     while ( lcur + len + 1 > lmax ) { \
236         lmax += BUFSIZ; \
237         line = (char *) ch_realloc( line, lmax ); \
238     } \
239     strcpy( line + lcur, buf ); \
240     lcur += len; \
241 }
242
243
244
245 /*
246  * Get a line of input.
247  */
248 static char *
249 getline(
250     FILE *fp
251 )
252 {
253     char        *p;
254     static char buf[BUFSIZ];
255     static char *line;
256     static int  lmax, lcur;
257
258     lcur = 0;
259     CATLINE( buf );
260     while ( fgets( buf, sizeof(buf), fp ) != NULL ) {
261         if ( (p = strchr( buf, '\n' )) != NULL ) {
262                 if( p > buf && p[-1] == '\r' ) --p;       
263                 *p = '\0';
264         }
265         lineno++;
266         if ( ! isspace( (unsigned char) buf[0] ) ) {
267             return( line );
268         }
269
270         /* change leading whitespace to space */
271         buf[0] = ' ';
272
273         CATLINE( buf );
274     }
275     buf[0] = '\0';
276
277     return( line[0] ? line : NULL );
278 }
279
280
281 /*
282  * Add a node to the array of replicas.
283  */
284 static void
285 add_replica(
286     char        **cargv,
287     int         cargc
288 )
289 {
290     int nr;
291
292     nr = ++sglob->num_replicas;
293     sglob->replicas = (Ri **) ch_realloc( sglob->replicas,
294             ( nr + 1 )  * sizeof( Re * ));
295     if ( sglob->replicas == NULL ) {
296         fprintf( stderr, "out of memory, add_replica\n" );
297         exit( EXIT_FAILURE );
298     }
299     sglob->replicas[ nr ] = NULL; 
300
301     if ( Ri_init( &(sglob->replicas[ nr - 1 ])) < 0 ) {
302         fprintf( stderr, "out of memory, Ri_init\n" );
303         exit( EXIT_FAILURE );
304     }
305     if ( parse_replica_line( cargv, cargc,
306             sglob->replicas[ nr - 1] ) < 0 ) {
307         /* Something bad happened - back out */
308         fprintf( stderr,
309             "Warning: failed to add replica \"%s:%d - ignoring replica\n",
310             sglob->replicas[ nr - 1 ]->ri_hostname == NULL ?
311             "(null)" : sglob->replicas[ nr - 1 ]->ri_hostname,
312             sglob->replicas[ nr - 1 ]->ri_port );
313         sglob->replicas[ nr - 1] = NULL;
314         sglob->num_replicas--;
315     } else {
316         Debug( LDAP_DEBUG_CONFIG,
317                 "Config: ** successfully added replica \"%s:%d\"\n",
318                 sglob->replicas[ nr - 1 ]->ri_hostname == NULL ?
319                 "(null)" : sglob->replicas[ nr - 1 ]->ri_hostname,
320                 sglob->replicas[ nr - 1 ]->ri_port, 0 );
321         sglob->replicas[ nr - 1]->ri_stel =
322                 sglob->st->st_add( sglob->st,
323                 sglob->replicas[ nr - 1 ] );
324         if ( sglob->replicas[ nr - 1]->ri_stel == NULL ) {
325             fprintf( stderr, "Failed to add status element structure\n" );
326             exit( EXIT_FAILURE );
327         }
328     }
329 }
330
331
332
333 /* 
334  * Parse a "replica" line from the config file.  replica lines should be
335  * in the following format:
336  * replica    host=<hostname:portnumber> binddn=<binddn>
337  *            bindmethod="simple" credentials=<creds>
338  *
339  * where:
340  * <hostname:portnumber> describes the host name and port number where the
341  * replica is running,
342  *
343  * <binddn> is the DN to bind to the replica slapd as,
344  *
345  * bindmethod is "simple", and
346  *
347  * <creds> are the credentials (e.g. password) for binddn.  <creds> are
348  * only used for bindmethod=simple.  
349  *
350  * The "replica" config file line may be split across multiple lines.  If
351  * a line begins with whitespace, it is considered a continuation of the
352  * previous line.
353  */
354 #define GOT_HOST        1
355 #define GOT_DN          2
356 #define GOT_METHOD      4
357 #define GOT_ALL         ( GOT_HOST | GOT_DN | GOT_METHOD )
358 #define GOT_MECH        8
359
360 static int
361 parse_replica_line( 
362     char        **cargv,
363     int         cargc,
364     Ri          *ri
365 )
366 {
367     int         gots = 0;
368     int         i;
369     char        *hp, *val;
370
371     for ( i = 1; i < cargc; i++ ) {
372         if ( !strncasecmp( cargv[ i ], HOSTSTR, strlen( HOSTSTR ))) {
373             val = cargv[ i ] + strlen( HOSTSTR ) + 1;
374             if (( hp = strchr( val, ':' )) != NULL ) {
375                 *hp = '\0';
376                 hp++;
377                 ri->ri_port = atoi( hp );
378             }
379             if ( ri->ri_port <= 0 ) {
380                 ri->ri_port = 0;
381             }
382             ri->ri_hostname = strdup( val );
383             gots |= GOT_HOST;
384         } else if ( !strncasecmp( cargv[ i ], SUFFIXSTR, strlen( HOSTSTR ))) {
385             /* ignore it */ ;
386         } else if ( !strncasecmp( cargv[ i ], TLSSTR, strlen( TLSSTR ))) {
387             val = cargv[ i ] + strlen( TLSSTR ) + 1;
388                 if( !strcasecmp( val, TLSCRITICALSTR ) ) {
389                         ri->ri_tls = TLS_CRITICAL;
390                 } else {
391                         ri->ri_tls = TLS_ON;
392                 }
393         } else if ( !strncasecmp( cargv[ i ],
394                 BINDDNSTR, strlen( BINDDNSTR ))) { 
395             val = cargv[ i ] + strlen( BINDDNSTR ) + 1;
396             ri->ri_bind_dn = strdup( val );
397             gots |= GOT_DN;
398         } else if ( !strncasecmp( cargv[ i ], BINDMETHSTR,
399                 strlen( BINDMETHSTR ))) {
400             val = cargv[ i ] + strlen( BINDMETHSTR ) + 1;
401             if ( !strcasecmp( val, KERBEROSSTR )) {
402             fprintf( stderr, "Error: a bind method of \"kerberos\" was\n" );
403             fprintf( stderr, "specified in the slapd configuration file.\n" );
404             fprintf( stderr, "slurpd no longer supports Kerberos.\n" );
405             exit( EXIT_FAILURE );
406             } else if ( !strcasecmp( val, SIMPLESTR )) {
407                 ri->ri_bind_method = AUTH_SIMPLE;
408                 gots |= GOT_METHOD;
409             } else if ( !strcasecmp( val, SASLSTR )) {
410                 ri->ri_bind_method = AUTH_SASL;
411                 gots |= GOT_METHOD;
412             } else {
413                 ri->ri_bind_method = -1;
414             }
415         } else if ( !strncasecmp( cargv[ i ], SASLMECHSTR, strlen( SASLMECHSTR ))) {
416             val = cargv[ i ] + strlen( SASLMECHSTR ) + 1;
417             gots |= GOT_MECH;
418             ri->ri_saslmech = strdup( val );
419         } else if ( !strncasecmp( cargv[ i ], CREDSTR, strlen( CREDSTR ))) {
420             val = cargv[ i ] + strlen( CREDSTR ) + 1;
421             ri->ri_password = strdup( val );
422         } else if ( !strncasecmp( cargv[ i ], SECPROPSSTR, strlen( SECPROPSSTR ))) {
423             val = cargv[ i ] + strlen( SECPROPSSTR ) + 1;
424             ri->ri_secprops = strdup( val );
425         } else if ( !strncasecmp( cargv[ i ], REALMSTR, strlen( REALMSTR ))) {
426             val = cargv[ i ] + strlen( REALMSTR ) + 1;
427             ri->ri_realm = strdup( val );
428         } else if ( !strncasecmp( cargv[ i ], AUTHCSTR, strlen( AUTHCSTR ))) {
429             val = cargv[ i ] + strlen( AUTHCSTR ) + 1;
430             ri->ri_authcId = strdup( val );
431         } else if ( !strncasecmp( cargv[ i ], OLDAUTHCSTR, strlen( OLDAUTHCSTR ))) {
432             /* Old authcID is provided for some backwards compatibility */
433             val = cargv[ i ] + strlen( OLDAUTHCSTR ) + 1;
434             ri->ri_authcId = strdup( val );
435         } else if ( !strncasecmp( cargv[ i ], AUTHZSTR, strlen( AUTHZSTR ))) {
436             val = cargv[ i ] + strlen( AUTHZSTR ) + 1;
437             ri->ri_authzId = strdup( val );
438         } else if ( !strncasecmp( cargv[ i ], SRVTABSTR, strlen( SRVTABSTR ))) {
439             val = cargv[ i ] + strlen( SRVTABSTR ) + 1;
440             if ( ri->ri_srvtab != NULL ) {
441                 free( ri->ri_srvtab );
442             }
443             ri->ri_srvtab = strdup( val );
444         } else {
445             fprintf( stderr, 
446                     "Error: parse_replica_line: unknown keyword \"%s\"\n",
447                     cargv[ i ] );
448         }
449     }
450     
451         if ( ri->ri_bind_method == AUTH_SASL) {
452                 if ((gots & GOT_MECH) == 0) {
453                         fprintf( stderr, "Error: \"replica\" line needs SASLmech flag in " );
454                         fprintf( stderr, "slapd config file, line %d\n", lineno );
455                         return -1;
456                 }
457         }
458         else if ( gots != GOT_ALL ) {
459                 fprintf( stderr, "Error: Malformed \"replica\" line in slapd " );
460                 fprintf( stderr, "config file, line %d\n", lineno );
461                 return -1;
462         }
463     return 0;
464 }
465