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