]> git.sur5r.net Git - openldap/blob - servers/slurpd/config.c
Added LDAP_LOG messages
[openldap] / servers / slurpd / config.c
1 /* $OpenLDAP$ */
2 /*
3  * Copyright 1998-2002 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 #ifdef NEW_LOGGING
67     LDAP_LOG (( "config", LDAP_LEVEL_ARGS, 
68         "slurpd_read_config: Config: opening config file \"%s\"\n", fname ));
69 #else
70     Debug( LDAP_DEBUG_CONFIG, "Config: opening config file \"%s\"\n",
71             fname, 0, 0 );
72 #endif
73
74     if ( (fp = fopen( fname, "r" )) == NULL ) {
75         perror( fname );
76         exit( EXIT_FAILURE );
77     }
78
79     lineno = 0;
80     while ( (line = getline( fp )) != NULL ) {
81         /* skip comments and blank lines */
82         if ( line[0] == '#' || line[0] == '\0' ) {
83             continue;
84         }
85
86 #ifdef NEW_LOGGING
87     LDAP_LOG (( "config", LDAP_LEVEL_DETAIL1, 
88                 "slurpd_read_config: Config: (%s)\n", line ));
89 #else
90         Debug( LDAP_DEBUG_CONFIG, "Config: (%s)\n", line, 0, 0 );
91 #endif
92
93         parse_line( line, &cargc, cargv );
94
95         if ( cargc < 1 ) {
96             fprintf( stderr, "line %d: bad config line (ignored)\n", lineno );
97             continue;
98         }
99
100         /* replication log file to which changes are appended */
101         if ( strcasecmp( cargv[0], "replogfile" ) == 0 ) {
102             /* 
103              * if slapd_replogfile has a value, the -r option was given,
104              * so use that value.  If slapd_replogfile has length == 0,
105              * then we should use the value in the config file we're reading.
106              */
107             if ( sglob->slapd_replogfile[ 0 ] == '\0' ) {
108                 if ( cargc < 2 ) {
109                     fprintf( stderr,
110                         "line %d: missing filename in \"replogfile ",
111                         lineno );
112                     fprintf( stderr, "<filename>\" line\n" );
113                     exit( EXIT_FAILURE );
114                 } else if ( cargc > 2 && *cargv[2] != '#' ) {
115                     fprintf( stderr,
116                         "line %d: extra cruft at the end of \"replogfile %s\"",
117                         lineno, cargv[1] );
118                     fprintf( stderr, "line (ignored)\n" );
119                 }
120                 strcpy( sglob->slapd_replogfile, cargv[1] );
121             }
122         } else if ( strcasecmp( cargv[0], "replica" ) == 0 ) {
123             add_replica( cargv, cargc );
124             
125             /* include another config file */
126         } else if ( strcasecmp( cargv[0], "include" ) == 0 ) {
127             char *savefname;
128             int savelineno;
129
130             if ( cargc < 2 ) {
131 #ifdef NEW_LOGGING
132                 LDAP_LOG(( "config", LDAP_LEVEL_CRIT,
133                         "%s: line %d: missing filename in \"include "
134                         "<filename>\" line.\n", fname, lineno ));
135 #else
136                 Debug( LDAP_DEBUG_ANY,
137         "%s: line %d: missing filename in \"include <filename>\" line\n",
138                         fname, lineno, 0 );
139 #endif
140                 
141                 return( 1 );
142             }
143             savefname = strdup( cargv[1] );
144             savelineno = lineno;
145             
146             if ( slurpd_read_config( savefname ) != 0 ) {
147                 return( 1 );
148             }
149                 
150             free( savefname );
151             lineno = savelineno - 1;
152         }
153     }
154     fclose( fp );
155 #ifdef NEW_LOGGING
156     LDAP_LOG (( "config", LDAP_LEVEL_RESULTS, 
157                 "slurpd_read_config: Config: "
158                 "** configuration file successfully read and parsed\n" ));
159 #else
160     Debug( LDAP_DEBUG_CONFIG,
161             "Config: ** configuration file successfully read and parsed\n",
162             0, 0, 0 );
163 #endif
164     return 0;
165 }
166
167
168
169
170 /*
171  * Parse one line of input.
172  */
173 static void
174 parse_line(
175     char        *line,
176     int         *argcp,
177     char        **argv
178 )
179 {
180     char *      token;
181
182     *argcp = 0;
183     for ( token = strtok_quote( line, " \t" ); token != NULL;
184         token = strtok_quote( NULL, " \t" ) ) {
185         argv[(*argcp)++] = token;
186     }
187     argv[*argcp] = NULL;
188 }
189
190
191
192
193 static char *
194 strtok_quote(
195     char *line,
196     char *sep
197 )
198 {
199     int         inquote;
200     char        *tmp;
201     static char *next;
202
203     if ( line != NULL ) {
204         next = line;
205     }
206     while ( *next && strchr( sep, *next ) ) {
207         next++;
208     }
209
210     if ( *next == '\0' ) {
211         next = NULL;
212         return( NULL );
213     }
214     tmp = next;
215
216     for ( inquote = 0; *next; ) {
217         switch ( *next ) {
218         case '"':
219             if ( inquote ) {
220                 inquote = 0;
221             } else {
222                 inquote = 1;
223             }
224             AC_MEMCPY( next, next + 1, strlen( next + 1 ) + 1 );
225             break;
226
227         case '\\':
228             if ( next[1] )
229                 AC_MEMCPY( next, next + 1, strlen( next + 1 ) + 1 );
230             next++;             /* dont parse the escaped character */
231             break;
232
233         default:
234             if ( ! inquote ) {
235                 if ( strchr( sep, *next ) != NULL ) {
236                     *next++ = '\0';
237                     return( tmp );
238                 }
239             }
240             next++;
241             break;
242         }
243     }
244
245     return( tmp );
246 }
247
248 #define CATLINE( buf )  { \
249     int len; \
250     len = strlen( buf ); \
251     while ( lcur + len + 1 > lmax ) { \
252         lmax += BUFSIZ; \
253         line = (char *) ch_realloc( line, lmax ); \
254     } \
255     strcpy( line + lcur, buf ); \
256     lcur += len; \
257 }
258
259
260
261 /*
262  * Get a line of input.
263  */
264 static char *
265 getline(
266     FILE *fp
267 )
268 {
269     char        *p;
270     static char buf[BUFSIZ];
271     static char *line;
272     static int  lmax, lcur;
273
274     lcur = 0;
275     CATLINE( buf );
276     while ( fgets( buf, sizeof(buf), fp ) != NULL ) {
277         if ( (p = strchr( buf, '\n' )) != NULL ) {
278                 if( p > buf && p[-1] == '\r' ) --p;       
279                 *p = '\0';
280         }
281         lineno++;
282         if ( ! isspace( (unsigned char) buf[0] ) ) {
283             return( line );
284         }
285
286         /* change leading whitespace to space */
287         buf[0] = ' ';
288
289         CATLINE( buf );
290     }
291     buf[0] = '\0';
292
293     return( line[0] ? line : NULL );
294 }
295
296
297 /*
298  * Add a node to the array of replicas.
299  */
300 static void
301 add_replica(
302     char        **cargv,
303     int         cargc
304 )
305 {
306     int nr;
307
308     nr = ++sglob->num_replicas;
309     sglob->replicas = (Ri **) ch_realloc( sglob->replicas,
310             ( nr + 1 )  * sizeof( Re * ));
311     if ( sglob->replicas == NULL ) {
312         fprintf( stderr, "out of memory, add_replica\n" );
313         exit( EXIT_FAILURE );
314     }
315     sglob->replicas[ nr ] = NULL; 
316
317     if ( Ri_init( &(sglob->replicas[ nr - 1 ])) < 0 ) {
318         fprintf( stderr, "out of memory, Ri_init\n" );
319         exit( EXIT_FAILURE );
320     }
321     if ( parse_replica_line( cargv, cargc,
322             sglob->replicas[ nr - 1] ) < 0 ) {
323         /* Something bad happened - back out */
324         fprintf( stderr,
325             "Warning: failed to add replica \"%s:%d - ignoring replica\n",
326             sglob->replicas[ nr - 1 ]->ri_hostname == NULL ?
327             "(null)" : sglob->replicas[ nr - 1 ]->ri_hostname,
328             sglob->replicas[ nr - 1 ]->ri_port );
329         sglob->replicas[ nr - 1] = NULL;
330         sglob->num_replicas--;
331     } else {
332 #ifdef NEW_LOGGING
333     LDAP_LOG (( "config", LDAP_LEVEL_RESULTS, 
334                 "add_replica: Config: ** successfully added replica \"%s%d\"\n", 
335                 sglob->replicas[ nr - 1 ]->ri_hostname == NULL ?
336                 "(null)" : sglob->replicas[ nr - 1 ]->ri_hostname,
337                 sglob->replicas[ nr - 1 ]->ri_port, 0 ));
338 #else
339         Debug( LDAP_DEBUG_CONFIG,
340                 "Config: ** successfully added replica \"%s:%d\"\n",
341                 sglob->replicas[ nr - 1 ]->ri_hostname == NULL ?
342                 "(null)" : sglob->replicas[ nr - 1 ]->ri_hostname,
343                 sglob->replicas[ nr - 1 ]->ri_port, 0 );
344 #endif
345         sglob->replicas[ nr - 1]->ri_stel =
346                 sglob->st->st_add( sglob->st,
347                 sglob->replicas[ nr - 1 ] );
348         if ( sglob->replicas[ nr - 1]->ri_stel == NULL ) {
349             fprintf( stderr, "Failed to add status element structure\n" );
350             exit( EXIT_FAILURE );
351         }
352     }
353 }
354
355
356
357 /* 
358  * Parse a "replica" line from the config file.  replica lines should be
359  * in the following format:
360  * replica    host=<hostname:portnumber> binddn=<binddn>
361  *            bindmethod="simple" credentials=<creds>
362  *
363  * where:
364  * <hostname:portnumber> describes the host name and port number where the
365  * replica is running,
366  *
367  * <binddn> is the DN to bind to the replica slapd as,
368  *
369  * bindmethod is "simple", and
370  *
371  * <creds> are the credentials (e.g. password) for binddn.  <creds> are
372  * only used for bindmethod=simple.  
373  *
374  * The "replica" config file line may be split across multiple lines.  If
375  * a line begins with whitespace, it is considered a continuation of the
376  * previous line.
377  */
378 #define GOT_HOST        1
379 #define GOT_DN          2
380 #define GOT_METHOD      4
381 #define GOT_ALL         ( GOT_HOST | GOT_DN | GOT_METHOD )
382 #define GOT_MECH        8
383
384 static int
385 parse_replica_line( 
386     char        **cargv,
387     int         cargc,
388     Ri          *ri
389 )
390 {
391     int         gots = 0;
392     int         i;
393     char        *hp, *val;
394
395     for ( i = 1; i < cargc; i++ ) {
396         if ( !strncasecmp( cargv[ i ], HOSTSTR, sizeof( HOSTSTR ) - 1 ) ) {
397             val = cargv[ i ] + sizeof( HOSTSTR ); /* '\0' string terminator accounts for '=' */
398             if (( hp = strchr( val, ':' )) != NULL ) {
399                 *hp = '\0';
400                 hp++;
401                 ri->ri_port = atoi( hp );
402             }
403             if ( ri->ri_port <= 0 ) {
404                 ri->ri_port = 0;
405             }
406             ri->ri_hostname = strdup( val );
407             gots |= GOT_HOST;
408         } else if ( !strncasecmp( cargv[ i ], 
409                         ATTRSTR, sizeof( ATTRSTR ) - 1 ) ) {
410             /* ignore it */ ;
411         } else if ( !strncasecmp( cargv[ i ], 
412                         SUFFIXSTR, sizeof( SUFFIXSTR ) - 1 ) ) {
413             /* ignore it */ ;
414         } else if ( !strncasecmp( cargv[ i ], TLSSTR, sizeof( TLSSTR ) - 1 ) ) {
415             val = cargv[ i ] + sizeof( TLSSTR );
416                 if( !strcasecmp( val, TLSCRITICALSTR ) ) {
417                         ri->ri_tls = TLS_CRITICAL;
418                 } else {
419                         ri->ri_tls = TLS_ON;
420                 }
421         } else if ( !strncasecmp( cargv[ i ],
422                         BINDDNSTR, sizeof( BINDDNSTR ) - 1 ) ) { 
423             val = cargv[ i ] + sizeof( BINDDNSTR );
424             ri->ri_bind_dn = strdup( val );
425             gots |= GOT_DN;
426         } else if ( !strncasecmp( cargv[ i ], BINDMETHSTR,
427                 sizeof( BINDMETHSTR ) - 1 ) ) {
428             val = cargv[ i ] + sizeof( BINDMETHSTR );
429             if ( !strcasecmp( val, KERBEROSSTR )) {
430             fprintf( stderr, "Error: a bind method of \"kerberos\" was\n" );
431             fprintf( stderr, "specified in the slapd configuration file.\n" );
432             fprintf( stderr, "slurpd no longer supports Kerberos.\n" );
433             exit( EXIT_FAILURE );
434             } else if ( !strcasecmp( val, SIMPLESTR )) {
435                 ri->ri_bind_method = AUTH_SIMPLE;
436                 gots |= GOT_METHOD;
437             } else if ( !strcasecmp( val, SASLSTR )) {
438                 ri->ri_bind_method = AUTH_SASL;
439                 gots |= GOT_METHOD;
440             } else {
441                 ri->ri_bind_method = -1;
442             }
443         } else if ( !strncasecmp( cargv[ i ], 
444                         SASLMECHSTR, sizeof( SASLMECHSTR ) - 1 ) ) {
445             val = cargv[ i ] + sizeof( SASLMECHSTR );
446             gots |= GOT_MECH;
447             ri->ri_saslmech = strdup( val );
448         } else if ( !strncasecmp( cargv[ i ], 
449                         CREDSTR, sizeof( CREDSTR ) - 1 ) ) {
450             val = cargv[ i ] + sizeof( CREDSTR );
451             ri->ri_password = strdup( val );
452         } else if ( !strncasecmp( cargv[ i ], 
453                         SECPROPSSTR, sizeof( SECPROPSSTR ) - 1 ) ) {
454             val = cargv[ i ] + sizeof( SECPROPSSTR );
455             ri->ri_secprops = strdup( val );
456         } else if ( !strncasecmp( cargv[ i ], 
457                         REALMSTR, sizeof( REALMSTR ) - 1 ) ) {
458             val = cargv[ i ] + sizeof( REALMSTR );
459             ri->ri_realm = strdup( val );
460         } else if ( !strncasecmp( cargv[ i ], 
461                         AUTHCSTR, sizeof( AUTHCSTR ) - 1 ) ) {
462             val = cargv[ i ] + sizeof( AUTHCSTR );
463             ri->ri_authcId = strdup( val );
464         } else if ( !strncasecmp( cargv[ i ], 
465                         OLDAUTHCSTR, sizeof( OLDAUTHCSTR ) - 1 ) ) {
466             /* Old authcID is provided for some backwards compatibility */
467             val = cargv[ i ] + sizeof( OLDAUTHCSTR );
468             ri->ri_authcId = strdup( val );
469         } else if ( !strncasecmp( cargv[ i ], 
470                         AUTHZSTR, sizeof( AUTHZSTR ) - 1 ) ) {
471             val = cargv[ i ] + sizeof( AUTHZSTR );
472             ri->ri_authzId = strdup( val );
473         } else if ( !strncasecmp( cargv[ i ], 
474                         SRVTABSTR, sizeof( SRVTABSTR ) - 1 ) ) {
475             val = cargv[ i ] + sizeof( SRVTABSTR );
476             if ( ri->ri_srvtab != NULL ) {
477                 free( ri->ri_srvtab );
478             }
479             ri->ri_srvtab = strdup( val );
480         } else {
481             fprintf( stderr, 
482                     "Error: parse_replica_line: unknown keyword \"%s\"\n",
483                     cargv[ i ] );
484         }
485     }
486     
487         if ( ri->ri_bind_method == AUTH_SASL) {
488                 if ((gots & GOT_MECH) == 0) {
489                         fprintf( stderr, "Error: \"replica\" line needs SASLmech flag in " );
490                         fprintf( stderr, "slapd config file, line %d\n", lineno );
491                         return -1;
492                 }
493         }
494         else if ( gots != GOT_ALL ) {
495                 fprintf( stderr, "Error: Malformed \"replica\" line in slapd " );
496                 fprintf( stderr, "config file, line %d\n", lineno );
497                 return -1;
498         }
499     return 0;
500 }
501