]> git.sur5r.net Git - openldap/blob - servers/slurpd/config.c
Add copyright notices
[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     }
116     fclose( fp );
117     Debug( LDAP_DEBUG_CONFIG,
118             "Config: ** configuration file successfully read and parsed\n",
119             0, 0, 0 );
120     return 0;
121 }
122
123
124
125
126 /*
127  * Parse one line of input.
128  */
129 static void
130 parse_line(
131     char        *line,
132     int         *argcp,
133     char        **argv
134 )
135 {
136     char *      token;
137
138     *argcp = 0;
139     for ( token = strtok_quote( line, " \t" ); token != NULL;
140         token = strtok_quote( NULL, " \t" ) ) {
141         argv[(*argcp)++] = token;
142     }
143     argv[*argcp] = NULL;
144 }
145
146
147
148
149 static char *
150 strtok_quote(
151     char *line,
152     char *sep
153 )
154 {
155     int         inquote;
156     char        *tmp;
157     static char *next;
158
159     if ( line != NULL ) {
160         next = line;
161     }
162     while ( *next && strchr( sep, *next ) ) {
163         next++;
164     }
165
166     if ( *next == '\0' ) {
167         next = NULL;
168         return( NULL );
169     }
170     tmp = next;
171
172     for ( inquote = 0; *next; ) {
173         switch ( *next ) {
174         case '"':
175             if ( inquote ) {
176                 inquote = 0;
177             } else {
178                 inquote = 1;
179             }
180             AC_MEMCPY( next, next + 1, strlen( next + 1 ) + 1 );
181             break;
182
183         case '\\':
184             if ( next[1] )
185                 AC_MEMCPY( next, next + 1, strlen( next + 1 ) + 1 );
186             next++;             /* dont parse the escaped character */
187             break;
188
189         default:
190             if ( ! inquote ) {
191                 if ( strchr( sep, *next ) != NULL ) {
192                     *next++ = '\0';
193                     return( tmp );
194                 }
195             }
196             next++;
197             break;
198         }
199     }
200
201     return( tmp );
202 }
203
204 #define CATLINE( buf )  { \
205     int len; \
206     len = strlen( buf ); \
207     while ( lcur + len + 1 > lmax ) { \
208         lmax += BUFSIZ; \
209         line = (char *) ch_realloc( line, lmax ); \
210     } \
211     strcpy( line + lcur, buf ); \
212     lcur += len; \
213 }
214
215
216
217 /*
218  * Get a line of input.
219  */
220 static char *
221 getline(
222     FILE *fp
223 )
224 {
225     char        *p;
226     static char buf[BUFSIZ];
227     static char *line;
228     static int  lmax, lcur;
229
230     lcur = 0;
231     CATLINE( buf );
232     while ( fgets( buf, sizeof(buf), fp ) != NULL ) {
233         if ( (p = strchr( buf, '\n' )) != NULL ) {
234             *p = '\0';
235         }
236         lineno++;
237         if ( ! isspace( (unsigned char) buf[0] ) ) {
238             return( line );
239         }
240
241         CATLINE( buf );
242     }
243     buf[0] = '\0';
244
245     return( line[0] ? line : NULL );
246 }
247
248
249 /*
250  * Add a node to the array of replicas.
251  */
252 static void
253 add_replica(
254     char        **cargv,
255     int         cargc
256 )
257 {
258     int nr;
259
260     nr = ++sglob->num_replicas;
261     sglob->replicas = (Ri **) ch_realloc( sglob->replicas,
262             ( nr + 1 )  * sizeof( Re * ));
263     if ( sglob->replicas == NULL ) {
264         fprintf( stderr, "out of memory, add_replica\n" );
265         exit( EXIT_FAILURE );
266     }
267     sglob->replicas[ nr ] = NULL; 
268
269     if ( Ri_init( &(sglob->replicas[ nr - 1 ])) < 0 ) {
270         fprintf( stderr, "out of memory, Ri_init\n" );
271         exit( EXIT_FAILURE );
272     }
273     if ( parse_replica_line( cargv, cargc,
274             sglob->replicas[ nr - 1] ) < 0 ) {
275         /* Something bad happened - back out */
276         fprintf( stderr,
277             "Warning: failed to add replica \"%s:%d - ignoring replica\n",
278             sglob->replicas[ nr - 1 ]->ri_hostname == NULL ?
279             "(null)" : sglob->replicas[ nr - 1 ]->ri_hostname,
280             sglob->replicas[ nr - 1 ]->ri_port );
281         sglob->replicas[ nr - 1] = NULL;
282         sglob->num_replicas--;
283     } else {
284         Debug( LDAP_DEBUG_CONFIG,
285                 "Config: ** successfully added replica \"%s:%d\"\n",
286                 sglob->replicas[ nr - 1 ]->ri_hostname == NULL ?
287                 "(null)" : sglob->replicas[ nr - 1 ]->ri_hostname,
288                 sglob->replicas[ nr - 1 ]->ri_port, 0 );
289         sglob->replicas[ nr - 1]->ri_stel =
290                 sglob->st->st_add( sglob->st,
291                 sglob->replicas[ nr - 1 ] );
292         if ( sglob->replicas[ nr - 1]->ri_stel == NULL ) {
293             fprintf( stderr, "Failed to add status element structure\n" );
294             exit( EXIT_FAILURE );
295         }
296     }
297 }
298
299
300
301 /* 
302  * Parse a "replica" line from the config file.  replica lines should be
303  * in the following format:
304  * replica    host=<hostname:portnumber> binddn=<binddn>
305  *            bindmethod="simple" credentials=<creds>
306  *
307  * where:
308  * <hostname:portnumber> describes the host name and port number where the
309  * replica is running,
310  *
311  * <binddn> is the DN to bind to the replica slapd as,
312  *
313  * bindmethod is "simple", and
314  *
315  * <creds> are the credentials (e.g. password) for binddn.  <creds> are
316  * only used for bindmethod=simple.  
317  *
318  * The "replica" config file line may be split across multiple lines.  If
319  * a line begins with whitespace, it is considered a continuation of the
320  * previous line.
321  */
322 #define GOT_HOST        1
323 #define GOT_DN          2
324 #define GOT_METHOD      4
325 #define GOT_ALL         ( GOT_HOST | GOT_DN | GOT_METHOD )
326 #define GOT_MECH        8
327
328 static int
329 parse_replica_line( 
330     char        **cargv,
331     int         cargc,
332     Ri          *ri
333 )
334 {
335     int         gots = 0;
336     int         i;
337     char        *hp, *val;
338
339     for ( i = 1; i < cargc; i++ ) {
340         if ( !strncasecmp( cargv[ i ], HOSTSTR, strlen( HOSTSTR ))) {
341             val = cargv[ i ] + strlen( HOSTSTR ) + 1;
342             if (( hp = strchr( val, ':' )) != NULL ) {
343                 *hp = '\0';
344                 hp++;
345                 ri->ri_port = atoi( hp );
346             }
347             if ( ri->ri_port <= 0 ) {
348                 ri->ri_port = 0;
349             }
350             ri->ri_hostname = strdup( val );
351             gots |= GOT_HOST;
352         } else if ( !strncasecmp( cargv[ i ], TLSSTR, strlen( TLSSTR ))) {
353             val = cargv[ i ] + strlen( TLSSTR ) + 1;
354                 if( !strcasecmp( val, TLSCRITICALSTR ) ) {
355                         ri->ri_tls = TLS_CRITICAL;
356                 } else {
357                         ri->ri_tls = TLS_ON;
358                 }
359         } else if ( !strncasecmp( cargv[ i ],
360                 BINDDNSTR, strlen( BINDDNSTR ))) { 
361             val = cargv[ i ] + strlen( BINDDNSTR ) + 1;
362             ri->ri_bind_dn = strdup( val );
363             gots |= GOT_DN;
364         } else if ( !strncasecmp( cargv[ i ], BINDMETHSTR,
365                 strlen( BINDMETHSTR ))) {
366             val = cargv[ i ] + strlen( BINDMETHSTR ) + 1;
367             if ( !strcasecmp( val, KERBEROSSTR )) {
368             fprintf( stderr, "Error: a bind method of \"kerberos\" was\n" );
369             fprintf( stderr, "specified in the slapd configuration file.\n" );
370             fprintf( stderr, "slurpd no longer supports Kerberos.\n" );
371             exit( EXIT_FAILURE );
372             } else if ( !strcasecmp( val, SIMPLESTR )) {
373                 ri->ri_bind_method = AUTH_SIMPLE;
374                 gots |= GOT_METHOD;
375             } else if ( !strcasecmp( val, SASLSTR )) {
376                 ri->ri_bind_method = AUTH_SASL;
377                 gots |= GOT_METHOD;
378             } else {
379                 ri->ri_bind_method = -1;
380             }
381         } else if ( !strncasecmp( cargv[ i ], SASLMECHSTR, strlen( SASLMECHSTR ))) {
382             val = cargv[ i ] + strlen( SASLMECHSTR ) + 1;
383             gots |= GOT_MECH;
384             ri->ri_saslmech = strdup( val );
385         } else if ( !strncasecmp( cargv[ i ], CREDSTR, strlen( CREDSTR ))) {
386             val = cargv[ i ] + strlen( CREDSTR ) + 1;
387             ri->ri_password = strdup( val );
388         } else if ( !strncasecmp( cargv[ i ], SECPROPSSTR, strlen( SECPROPSSTR ))) {
389             val = cargv[ i ] + strlen( SECPROPSSTR ) + 1;
390             ri->ri_secprops = strdup( val );
391         } else if ( !strncasecmp( cargv[ i ], REALMSTR, strlen( REALMSTR ))) {
392             val = cargv[ i ] + strlen( REALMSTR ) + 1;
393             ri->ri_realm = strdup( val );
394         } else if ( !strncasecmp( cargv[ i ], AUTHCSTR, strlen( AUTHCSTR ))) {
395             val = cargv[ i ] + strlen( AUTHCSTR ) + 1;
396             ri->ri_authcId = strdup( val );
397         } else if ( !strncasecmp( cargv[ i ], OLDAUTHCSTR, strlen( OLDAUTHCSTR ))) {
398             /* Old authcID is provided for some backwards compatibility */
399             val = cargv[ i ] + strlen( OLDAUTHCSTR ) + 1;
400             ri->ri_authcId = strdup( val );
401         } else if ( !strncasecmp( cargv[ i ], AUTHZSTR, strlen( AUTHZSTR ))) {
402             val = cargv[ i ] + strlen( AUTHZSTR ) + 1;
403             ri->ri_authzId = strdup( val );
404         } else if ( !strncasecmp( cargv[ i ], SRVTABSTR, strlen( SRVTABSTR ))) {
405             val = cargv[ i ] + strlen( SRVTABSTR ) + 1;
406             if ( ri->ri_srvtab != NULL ) {
407                 free( ri->ri_srvtab );
408             }
409             ri->ri_srvtab = strdup( val );
410         } else {
411             fprintf( stderr, 
412                     "Error: parse_replica_line: unknown keyword \"%s\"\n",
413                     cargv[ i ] );
414         }
415     }
416     
417         if ( ri->ri_bind_method == AUTH_SASL) {
418                 if ((gots & GOT_MECH) == 0) {
419                         fprintf( stderr, "Error: \"replica\" line needs SASLmech flag in " );
420                         fprintf( stderr, "slapd config file, line %d\n", lineno );
421                         return -1;
422                 }
423         }
424         else if ( gots != GOT_ALL ) {
425                 fprintf( stderr, "Error: Malformed \"replica\" line in slapd " );
426                 fprintf( stderr, "config file, line %d\n", lineno );
427                 return -1;
428         }
429     return 0;
430 }
431