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