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