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