]> git.sur5r.net Git - openldap/blob - servers/slurpd/config.c
308a4edd42104e28eb5cf928f926cf734dec297c
[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 100
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             *p = '\0';
263         }
264         lineno++;
265         if ( ! isspace( (unsigned char) buf[0] ) ) {
266             return( line );
267         }
268
269         CATLINE( buf );
270     }
271     buf[0] = '\0';
272
273     return( line[0] ? line : NULL );
274 }
275
276
277 /*
278  * Add a node to the array of replicas.
279  */
280 static void
281 add_replica(
282     char        **cargv,
283     int         cargc
284 )
285 {
286     int nr;
287
288     nr = ++sglob->num_replicas;
289     sglob->replicas = (Ri **) ch_realloc( sglob->replicas,
290             ( nr + 1 )  * sizeof( Re * ));
291     if ( sglob->replicas == NULL ) {
292         fprintf( stderr, "out of memory, add_replica\n" );
293         exit( EXIT_FAILURE );
294     }
295     sglob->replicas[ nr ] = NULL; 
296
297     if ( Ri_init( &(sglob->replicas[ nr - 1 ])) < 0 ) {
298         fprintf( stderr, "out of memory, Ri_init\n" );
299         exit( EXIT_FAILURE );
300     }
301     if ( parse_replica_line( cargv, cargc,
302             sglob->replicas[ nr - 1] ) < 0 ) {
303         /* Something bad happened - back out */
304         fprintf( stderr,
305             "Warning: failed to add replica \"%s:%d - ignoring replica\n",
306             sglob->replicas[ nr - 1 ]->ri_hostname == NULL ?
307             "(null)" : sglob->replicas[ nr - 1 ]->ri_hostname,
308             sglob->replicas[ nr - 1 ]->ri_port );
309         sglob->replicas[ nr - 1] = NULL;
310         sglob->num_replicas--;
311     } else {
312         Debug( LDAP_DEBUG_CONFIG,
313                 "Config: ** successfully added replica \"%s:%d\"\n",
314                 sglob->replicas[ nr - 1 ]->ri_hostname == NULL ?
315                 "(null)" : sglob->replicas[ nr - 1 ]->ri_hostname,
316                 sglob->replicas[ nr - 1 ]->ri_port, 0 );
317         sglob->replicas[ nr - 1]->ri_stel =
318                 sglob->st->st_add( sglob->st,
319                 sglob->replicas[ nr - 1 ] );
320         if ( sglob->replicas[ nr - 1]->ri_stel == NULL ) {
321             fprintf( stderr, "Failed to add status element structure\n" );
322             exit( EXIT_FAILURE );
323         }
324     }
325 }
326
327
328
329 /* 
330  * Parse a "replica" line from the config file.  replica lines should be
331  * in the following format:
332  * replica    host=<hostname:portnumber> binddn=<binddn>
333  *            bindmethod="simple" credentials=<creds>
334  *
335  * where:
336  * <hostname:portnumber> describes the host name and port number where the
337  * replica is running,
338  *
339  * <binddn> is the DN to bind to the replica slapd as,
340  *
341  * bindmethod is "simple", and
342  *
343  * <creds> are the credentials (e.g. password) for binddn.  <creds> are
344  * only used for bindmethod=simple.  
345  *
346  * The "replica" config file line may be split across multiple lines.  If
347  * a line begins with whitespace, it is considered a continuation of the
348  * previous line.
349  */
350 #define GOT_HOST        1
351 #define GOT_DN          2
352 #define GOT_METHOD      4
353 #define GOT_ALL         ( GOT_HOST | GOT_DN | GOT_METHOD )
354 #define GOT_MECH        8
355
356 static int
357 parse_replica_line( 
358     char        **cargv,
359     int         cargc,
360     Ri          *ri
361 )
362 {
363     int         gots = 0;
364     int         i;
365     char        *hp, *val;
366
367     for ( i = 1; i < cargc; i++ ) {
368         if ( !strncasecmp( cargv[ i ], HOSTSTR, strlen( HOSTSTR ))) {
369             val = cargv[ i ] + strlen( HOSTSTR ) + 1;
370             if (( hp = strchr( val, ':' )) != NULL ) {
371                 *hp = '\0';
372                 hp++;
373                 ri->ri_port = atoi( hp );
374             }
375             if ( ri->ri_port <= 0 ) {
376                 ri->ri_port = 0;
377             }
378             ri->ri_hostname = strdup( val );
379             gots |= GOT_HOST;
380         } else if ( !strncasecmp( cargv[ i ], SUFFIXSTR, strlen( HOSTSTR ))) {
381             /* ignore it */ ;
382         } else if ( !strncasecmp( cargv[ i ], TLSSTR, strlen( TLSSTR ))) {
383             val = cargv[ i ] + strlen( TLSSTR ) + 1;
384                 if( !strcasecmp( val, TLSCRITICALSTR ) ) {
385                         ri->ri_tls = TLS_CRITICAL;
386                 } else {
387                         ri->ri_tls = TLS_ON;
388                 }
389         } else if ( !strncasecmp( cargv[ i ],
390                 BINDDNSTR, strlen( BINDDNSTR ))) { 
391             val = cargv[ i ] + strlen( BINDDNSTR ) + 1;
392             ri->ri_bind_dn = strdup( val );
393             gots |= GOT_DN;
394         } else if ( !strncasecmp( cargv[ i ], BINDMETHSTR,
395                 strlen( BINDMETHSTR ))) {
396             val = cargv[ i ] + strlen( BINDMETHSTR ) + 1;
397             if ( !strcasecmp( val, KERBEROSSTR )) {
398             fprintf( stderr, "Error: a bind method of \"kerberos\" was\n" );
399             fprintf( stderr, "specified in the slapd configuration file.\n" );
400             fprintf( stderr, "slurpd no longer supports Kerberos.\n" );
401             exit( EXIT_FAILURE );
402             } else if ( !strcasecmp( val, SIMPLESTR )) {
403                 ri->ri_bind_method = AUTH_SIMPLE;
404                 gots |= GOT_METHOD;
405             } else if ( !strcasecmp( val, SASLSTR )) {
406                 ri->ri_bind_method = AUTH_SASL;
407                 gots |= GOT_METHOD;
408             } else {
409                 ri->ri_bind_method = -1;
410             }
411         } else if ( !strncasecmp( cargv[ i ], SASLMECHSTR, strlen( SASLMECHSTR ))) {
412             val = cargv[ i ] + strlen( SASLMECHSTR ) + 1;
413             gots |= GOT_MECH;
414             ri->ri_saslmech = strdup( val );
415         } else if ( !strncasecmp( cargv[ i ], CREDSTR, strlen( CREDSTR ))) {
416             val = cargv[ i ] + strlen( CREDSTR ) + 1;
417             ri->ri_password = strdup( val );
418         } else if ( !strncasecmp( cargv[ i ], SECPROPSSTR, strlen( SECPROPSSTR ))) {
419             val = cargv[ i ] + strlen( SECPROPSSTR ) + 1;
420             ri->ri_secprops = strdup( val );
421         } else if ( !strncasecmp( cargv[ i ], REALMSTR, strlen( REALMSTR ))) {
422             val = cargv[ i ] + strlen( REALMSTR ) + 1;
423             ri->ri_realm = strdup( val );
424         } else if ( !strncasecmp( cargv[ i ], AUTHCSTR, strlen( AUTHCSTR ))) {
425             val = cargv[ i ] + strlen( AUTHCSTR ) + 1;
426             ri->ri_authcId = strdup( val );
427         } else if ( !strncasecmp( cargv[ i ], OLDAUTHCSTR, strlen( OLDAUTHCSTR ))) {
428             /* Old authcID is provided for some backwards compatibility */
429             val = cargv[ i ] + strlen( OLDAUTHCSTR ) + 1;
430             ri->ri_authcId = strdup( val );
431         } else if ( !strncasecmp( cargv[ i ], AUTHZSTR, strlen( AUTHZSTR ))) {
432             val = cargv[ i ] + strlen( AUTHZSTR ) + 1;
433             ri->ri_authzId = strdup( val );
434         } else if ( !strncasecmp( cargv[ i ], SRVTABSTR, strlen( SRVTABSTR ))) {
435             val = cargv[ i ] + strlen( SRVTABSTR ) + 1;
436             if ( ri->ri_srvtab != NULL ) {
437                 free( ri->ri_srvtab );
438             }
439             ri->ri_srvtab = strdup( val );
440         } else {
441             fprintf( stderr, 
442                     "Error: parse_replica_line: unknown keyword \"%s\"\n",
443                     cargv[ i ] );
444         }
445     }
446     
447         if ( ri->ri_bind_method == AUTH_SASL) {
448                 if ((gots & GOT_MECH) == 0) {
449                         fprintf( stderr, "Error: \"replica\" line needs SASLmech flag in " );
450                         fprintf( stderr, "slapd config file, line %d\n", lineno );
451                         return -1;
452                 }
453         }
454         else if ( gots != GOT_ALL ) {
455                 fprintf( stderr, "Error: Malformed \"replica\" line in slapd " );
456                 fprintf( stderr, "config file, line %d\n", lineno );
457                 return -1;
458         }
459     return 0;
460 }
461