]> git.sur5r.net Git - openldap/blob - servers/slurpd/config.c
WinNT path fixes from Howard
[openldap] / servers / slurpd / config.c
1 /* $OpenLDAP$ */
2 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
3  *
4  * Copyright 1998-2004 The OpenLDAP Foundation.
5  * Portions Copyright 2003 Mark Benson.
6  * Portions Copyright 2002 John Morrissey.
7  * All rights reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted only as authorized by the OpenLDAP
11  * Public License.
12  *
13  * A copy of this license is available in file LICENSE in the
14  * top-level directory of the distribution or, alternatively, at
15  * <http://www.OpenLDAP.org/license.html>.
16  */
17 /* Portions Copyright (c) 1996 Regents of the University of Michigan.
18  * All rights reserved.
19  *
20  * Redistribution and use in source and binary forms are permitted
21  * provided that this notice is preserved and that due credit is given
22  * to the University of Michigan at Ann Arbor. The name of the University
23  * may not be used to endorse or promote products derived from this
24  * software without specific prior written permission. This software
25  * is provided ``as is'' without express or implied warranty.
26  */
27 /* ACKNOWLEDGEMENTS:
28  * This work was originally developed by the University of Michigan
29  * (as part of U-MICH LDAP).  Additional signficant contributors
30  * include:
31  *    John Morrissey
32  *    Mark Benson
33  */
34
35
36 /*
37  * config.c - configuration file handling routines
38  */
39
40 #include "portable.h"
41
42 #include <stdio.h>
43
44 #include <ac/stdlib.h>
45 #include <ac/string.h>
46 #include <ac/socket.h>
47 #include <ac/ctype.h>
48
49 #include <ldap.h>
50 #include <lutil.h>
51
52 #include "slurp.h"
53 #include "globals.h"
54
55 #define ARGS_STEP       512
56
57 /* Forward declarations */
58 static void     add_replica LDAP_P(( char **, int ));
59 static int      parse_replica_line LDAP_P(( char **, int, Ri *));
60 static void     parse_line LDAP_P(( char * ));
61 static char     *getline LDAP_P(( FILE * ));
62 static char     *strtok_quote LDAP_P(( char *, char * ));
63
64 int     cargc = 0, cargv_size = 0;
65 char    **cargv;
66 /* current config file line # */
67 static int      lineno;
68
69 char *slurpd_pid_file = NULL;
70 char *slurpd_args_file = NULL;
71
72 /*
73  * Read the slapd config file, looking only for config options we're
74  * interested in.  Since we haven't detached from the controlling
75  * terminal yet, we just perror() and fprintf here.
76  */
77 int
78 slurpd_read_config(
79     char        *fname
80 )
81 {
82     FILE        *fp;
83     char        *line;
84
85         if ( cargv == NULL ) {
86         cargv = ch_calloc( ARGS_STEP + 1, sizeof(*cargv) );
87         cargv_size = ARGS_STEP + 1;
88         }
89
90 #ifdef NEW_LOGGING
91     LDAP_LOG ( CONFIG, ARGS, 
92                 "slurpd_read_config: Config: opening config file \"%s\"\n", 
93                 fname, 0, 0 );
94 #else
95     Debug( LDAP_DEBUG_CONFIG, "Config: opening config file \"%s\"\n",
96             fname, 0, 0 );
97 #endif
98
99     if ( (fp = fopen( fname, "r" )) == NULL ) {
100         perror( fname );
101         exit( EXIT_FAILURE );
102     }
103
104     lineno = 0;
105     while ( (line = getline( fp )) != NULL ) {
106         /* skip comments and blank lines */
107         if ( line[0] == '#' || line[0] == '\0' ) {
108             continue;
109         }
110
111 #ifdef NEW_LOGGING
112     LDAP_LOG ( CONFIG, DETAIL1, 
113                 "slurpd_read_config: Config: (%s)\n", line, 0, 0 );
114 #else
115         Debug( LDAP_DEBUG_CONFIG, "Config: (%s)\n", line, 0, 0 );
116 #endif
117
118         parse_line( line );
119
120         if ( cargc < 1 ) {
121             fprintf( stderr, "line %d: bad config line (ignored)\n", lineno );
122             continue;
123         }
124
125         /* replication log file to which changes are appended */
126         if ( strcasecmp( cargv[0], "replogfile" ) == 0 ) {
127             /* 
128              * if slapd_replogfile has a value, the -r option was given,
129              * so use that value.  If slapd_replogfile has length == 0,
130              * then we should use the value in the config file we're reading.
131              */
132             if ( sglob->slapd_replogfile[ 0 ] == '\0' ) {
133                 if ( cargc < 2 ) {
134                     fprintf( stderr,
135                         "line %d: missing filename in \"replogfile ",
136                         lineno );
137                     fprintf( stderr, "<filename>\" line\n" );
138                     exit( EXIT_FAILURE );
139                 } else if ( cargc > 2 && *cargv[2] != '#' ) {
140                     fprintf( stderr,
141                         "line %d: extra cruft at the end of \"replogfile %s\"",
142                         lineno, cargv[1] );
143                     fprintf( stderr, "line (ignored)\n" );
144                 }
145                 LUTIL_SLASHPATH( cargv[1] );
146                 strcpy( sglob->slapd_replogfile, cargv[1] );
147             }
148         } else if ( strcasecmp( cargv[0], "replica" ) == 0 ) {
149             add_replica( cargv, cargc );
150             
151             /* include another config file */
152         } else if ( strcasecmp( cargv[0], "include" ) == 0 ) {
153             char *savefname;
154             int savelineno;
155
156             if ( cargc < 2 ) {
157 #ifdef NEW_LOGGING
158                 LDAP_LOG( CONFIG, CRIT,
159                         "%s: line %d: missing filename in \"include "
160                         "<filename>\" line.\n", fname, lineno , 0 );
161 #else
162                 Debug( LDAP_DEBUG_ANY,
163         "%s: line %d: missing filename in \"include <filename>\" line\n",
164                         fname, lineno, 0 );
165 #endif
166                 
167                 return( 1 );
168             }
169             LUTIL_SLASHPATH( cargv[1] );
170             savefname = strdup( cargv[1] );
171             savelineno = lineno;
172             
173             if ( slurpd_read_config( savefname ) != 0 ) {
174                 return( 1 );
175             }
176                 
177             free( savefname );
178             lineno = savelineno - 1;
179
180         } else if ( strcasecmp( cargv[0], "replica-pidfile" ) == 0 ) {
181                 if ( cargc < 2 ) {
182 #ifdef NEW_LOGGING
183                         LDAP_LOG( CONFIG, CRIT, 
184                                 "%s: line %d missing file name in \"replica-pidfile <file>\" "
185                                 "line.\n", fname, lineno, 0 );
186 #else
187                         Debug( LDAP_DEBUG_ANY,
188             "%s: line %d: missing file name in \"replica-pidfile <file>\" line\n",
189                                 fname, lineno, 0 );
190 #endif
191
192                         return( 1 );
193                 }
194
195                 LUTIL_SLASHPATH( cargv[1] );
196                 slurpd_pid_file = ch_strdup( cargv[1] );
197
198         } else if ( strcasecmp( cargv[0], "replica-argsfile" ) == 0 ) {
199                 if ( cargc < 2 ) {
200 #ifdef NEW_LOGGING
201                         LDAP_LOG( CONFIG, CRIT, 
202                                    "%s: %d: missing file name in "
203                                    "\"argsfile <file>\" line.\n",
204                                    fname, lineno, 0 );
205 #else
206                         Debug( LDAP_DEBUG_ANY,
207             "%s: line %d: missing file name in \"argsfile <file>\" line\n",
208                             fname, lineno, 0 );
209 #endif
210
211                         return( 1 );
212                 }
213
214                 LUTIL_SLASHPATH( cargv[1] );
215                 slurpd_args_file = ch_strdup( cargv[1] );
216         }
217     }
218     fclose( fp );
219 #ifdef NEW_LOGGING
220     LDAP_LOG ( CONFIG, RESULTS, 
221                 "slurpd_read_config: Config: "
222                 "** configuration file successfully read and parsed\n", 0, 0, 0 );
223 #else
224     Debug( LDAP_DEBUG_CONFIG,
225             "Config: ** configuration file successfully read and parsed\n",
226             0, 0, 0 );
227 #endif
228     return 0;
229 }
230
231
232
233
234 /*
235  * Parse one line of input.
236  */
237 static void
238 parse_line(
239     char        *line
240 )
241 {
242     char *      token;
243
244     cargc = 0;
245     for ( token = strtok_quote( line, " \t" ); token != NULL;
246         token = strtok_quote( NULL, " \t" ) )
247     {
248         if ( cargc == cargv_size - 1 ) {
249             char **tmp;
250             tmp = ch_realloc( cargv, (cargv_size + ARGS_STEP) *
251                                sizeof(*cargv) );
252             if (tmp == NULL) {
253                 cargc = 0;
254                 return;
255             }
256             cargv = tmp;
257             cargv_size += ARGS_STEP;
258         }
259
260         cargv[cargc++] = token;
261     }
262     cargv[cargc] = NULL;
263 }
264
265
266
267
268 static char *
269 strtok_quote(
270     char *line,
271     char *sep
272 )
273 {
274     int         inquote;
275     char        *tmp;
276     static char *next;
277
278     if ( line != NULL ) {
279         next = line;
280     }
281     while ( *next && strchr( sep, *next ) ) {
282         next++;
283     }
284
285     if ( *next == '\0' ) {
286         next = NULL;
287         return( NULL );
288     }
289     tmp = next;
290
291     for ( inquote = 0; *next; ) {
292         switch ( *next ) {
293         case '"':
294             if ( inquote ) {
295                 inquote = 0;
296             } else {
297                 inquote = 1;
298             }
299             AC_MEMCPY( next, next + 1, strlen( next + 1 ) + 1 );
300             break;
301
302         case '\\':
303             if ( next[1] )
304                 AC_MEMCPY( next, next + 1, strlen( next + 1 ) + 1 );
305             next++;             /* dont parse the escaped character */
306             break;
307
308         default:
309             if ( ! inquote ) {
310                 if ( strchr( sep, *next ) != NULL ) {
311                     *next++ = '\0';
312                     return( tmp );
313                 }
314             }
315             next++;
316             break;
317         }
318     }
319
320     return( tmp );
321 }
322
323 #define CATLINE( buf )  { \
324     int len; \
325     len = strlen( buf ); \
326     while ( lcur + len + 1 > lmax ) { \
327         lmax += BUFSIZ; \
328         line = (char *) ch_realloc( line, lmax ); \
329     } \
330     strcpy( line + lcur, buf ); \
331     lcur += len; \
332 }
333
334
335
336 /*
337  * Get a line of input.
338  */
339 static char *
340 getline(
341     FILE *fp
342 )
343 {
344     char        *p;
345     static char buf[BUFSIZ];
346     static char *line;
347     static int  lmax, lcur;
348
349     lcur = 0;
350     CATLINE( buf );
351     while ( fgets( buf, sizeof(buf), fp ) != NULL ) {
352         if ( (p = strchr( buf, '\n' )) != NULL ) {
353                 if( p > buf && p[-1] == '\r' ) --p;       
354                 *p = '\0';
355         }
356         lineno++;
357         if ( ! isspace( (unsigned char) buf[0] ) ) {
358             return( line );
359         }
360
361         /* change leading whitespace to space */
362         buf[0] = ' ';
363
364         CATLINE( buf );
365     }
366     buf[0] = '\0';
367
368     return( line[0] ? line : NULL );
369 }
370
371
372 /*
373  * Add a node to the array of replicas.
374  */
375 static void
376 add_replica(
377     char        **cargv,
378     int         cargc
379 )
380 {
381     int nr;
382
383     nr = ++sglob->num_replicas;
384     sglob->replicas = (Ri **) ch_realloc( sglob->replicas,
385             ( nr + 1 )  * sizeof( Re * ));
386     if ( sglob->replicas == NULL ) {
387         fprintf( stderr, "out of memory, add_replica\n" );
388         exit( EXIT_FAILURE );
389     }
390     sglob->replicas[ nr ] = NULL; 
391
392     if ( Ri_init( &(sglob->replicas[ nr - 1 ])) < 0 ) {
393         fprintf( stderr, "out of memory, Ri_init\n" );
394         exit( EXIT_FAILURE );
395     }
396     if ( parse_replica_line( cargv, cargc,
397             sglob->replicas[ nr - 1] ) < 0 ) {
398         /* Something bad happened - back out */
399         fprintf( stderr,
400             "Warning: failed to add replica \"%s:%d - ignoring replica\n",
401             sglob->replicas[ nr - 1 ]->ri_hostname == NULL ?
402             "(null)" : sglob->replicas[ nr - 1 ]->ri_hostname,
403             sglob->replicas[ nr - 1 ]->ri_port );
404         sglob->replicas[ nr - 1] = NULL;
405         sglob->num_replicas--;
406     } else {
407 #ifdef NEW_LOGGING
408     LDAP_LOG ( CONFIG, RESULTS, 
409                 "add_replica: Config: ** successfully added replica \"%s%d\"\n", 
410                 sglob->replicas[ nr - 1 ]->ri_hostname == NULL ?
411                 "(null)" : sglob->replicas[ nr - 1 ]->ri_hostname,
412                 sglob->replicas[ nr - 1 ]->ri_port, 0 );
413 #else
414         Debug( LDAP_DEBUG_CONFIG,
415                 "Config: ** successfully added replica \"%s:%d\"\n",
416                 sglob->replicas[ nr - 1 ]->ri_hostname == NULL ?
417                 "(null)" : sglob->replicas[ nr - 1 ]->ri_hostname,
418                 sglob->replicas[ nr - 1 ]->ri_port, 0 );
419 #endif
420         sglob->replicas[ nr - 1]->ri_stel =
421                 sglob->st->st_add( sglob->st,
422                 sglob->replicas[ nr - 1 ] );
423         if ( sglob->replicas[ nr - 1]->ri_stel == NULL ) {
424             fprintf( stderr, "Failed to add status element structure\n" );
425             exit( EXIT_FAILURE );
426         }
427     }
428 }
429
430
431
432 /* 
433  * Parse a "replica" line from the config file.  replica lines should be
434  * in the following format:
435  * replica    host=<hostname:portnumber> binddn=<binddn>
436  *            bindmethod="simple" credentials=<creds>
437  *
438  * where:
439  * <hostname:portnumber> describes the host name and port number where the
440  * replica is running,
441  *
442  * <binddn> is the DN to bind to the replica slapd as,
443  *
444  * bindmethod is "simple", and
445  *
446  * <creds> are the credentials (e.g. password) for binddn.  <creds> are
447  * only used for bindmethod=simple.  
448  *
449  * The "replica" config file line may be split across multiple lines.  If
450  * a line begins with whitespace, it is considered a continuation of the
451  * previous line.
452  */
453 #define GOT_HOST        1
454 #define GOT_DN          2
455 #define GOT_METHOD      4
456 #define GOT_ALL         ( GOT_HOST | GOT_DN | GOT_METHOD )
457 #define GOT_MECH        8
458
459 static int
460 parse_replica_line( 
461     char        **cargv,
462     int         cargc,
463     Ri          *ri
464 )
465 {
466     int         gots = 0;
467     int         i;
468     char        *hp, *val;
469     LDAPURLDesc *ludp;
470
471     for ( i = 1; i < cargc; i++ ) {
472         if ( !strncasecmp( cargv[ i ], HOSTSTR, sizeof( HOSTSTR ) - 1 ) ) {
473                 if ( gots & GOT_HOST ) {
474                         fprintf( stderr, "Error: Malformed \"replica\" line in slapd config " );
475                         fprintf( stderr, "file, too many host or uri names specified, line %d\n",
476                                 lineno );
477                         return -1;
478                 }       
479             val = cargv[ i ] + sizeof( HOSTSTR ); /* '\0' string terminator accounts for '=' */
480             if (( hp = strchr( val, ':' )) != NULL ) {
481                 *hp = '\0';
482                 hp++;
483                 ri->ri_port = atoi( hp );
484             }
485             if ( ri->ri_port <= 0 ) {
486                 ri->ri_port = 0;
487             }
488             ri->ri_hostname = strdup( val );
489             gots |= GOT_HOST;
490         } else if ( !strncasecmp( cargv[ i ], URISTR, sizeof( URISTR ) - 1 ) ) {
491                 if ( gots & GOT_HOST ) {
492                         fprintf( stderr, "Error: Malformed \"replica\" line in slapd config " );
493                         fprintf( stderr, "file, too many host or uri names specified, line %d\n",
494                                 lineno );
495                         return -1;
496                 }               
497                 if ( ldap_url_parse( cargv[ i ] + sizeof( URISTR ), &ludp ) != LDAP_SUCCESS ) {
498                         fprintf( stderr, "Error: Malformed \"replica\" line in slapd config " );
499                         fprintf( stderr, "file, bad uri format specified, line %d\n",
500                                 lineno );
501                         return -1;
502                 }
503                 if (ludp->lud_host == NULL) {
504                         fprintf( stderr, "Error: Malformed \"replica\" line in slapd config " );
505                         fprintf( stderr, "file, missing uri hostname, line %d\n",
506                                 lineno );
507                         return -1;
508                 }
509                 ri->ri_hostname = strdup ( ludp->lud_host );
510                 ri->ri_port = ludp->lud_port;
511                 ri->ri_uri = strdup ( cargv[ i ] + sizeof( URISTR ) );          
512                 ldap_free_urldesc( ludp );                              
513             gots |= GOT_HOST;
514         } else if ( !strncasecmp( cargv[ i ], 
515                         ATTRSTR, sizeof( ATTRSTR ) - 1 ) ) {
516             /* ignore it */ ;
517         } else if ( !strncasecmp( cargv[ i ], 
518                         SUFFIXSTR, sizeof( SUFFIXSTR ) - 1 ) ) {
519             /* ignore it */ ;
520         } else if ( !strncasecmp( cargv[i], STARTTLSSTR, sizeof(STARTTLSSTR)-1 )) {
521             val = cargv[ i ] + sizeof( STARTTLSSTR );
522                 if( !strcasecmp( val, CRITICALSTR ) ) {
523                         ri->ri_tls = TLS_CRITICAL;
524                 } else {
525                         ri->ri_tls = TLS_ON;
526                 }
527         } else if ( !strncasecmp( cargv[ i ], TLSSTR, sizeof( TLSSTR ) - 1 ) ) {
528             val = cargv[ i ] + sizeof( TLSSTR );
529                 if( !strcasecmp( val, CRITICALSTR ) ) {
530                         ri->ri_tls = TLS_CRITICAL;
531                 } else {
532                         ri->ri_tls = TLS_ON;
533                 }
534         } else if ( !strncasecmp( cargv[ i ],
535                         BINDDNSTR, sizeof( BINDDNSTR ) - 1 ) ) { 
536             val = cargv[ i ] + sizeof( BINDDNSTR );
537             ri->ri_bind_dn = strdup( val );
538             gots |= GOT_DN;
539         } else if ( !strncasecmp( cargv[ i ], BINDMETHSTR,
540                 sizeof( BINDMETHSTR ) - 1 ) ) {
541             val = cargv[ i ] + sizeof( BINDMETHSTR );
542             if ( !strcasecmp( val, KERBEROSSTR )) {
543             fprintf( stderr, "Error: a bind method of \"kerberos\" was\n" );
544             fprintf( stderr, "specified in the slapd configuration file.\n" );
545             fprintf( stderr, "slurpd no longer supports Kerberos.\n" );
546             exit( EXIT_FAILURE );
547             } else if ( !strcasecmp( val, SIMPLESTR )) {
548                 ri->ri_bind_method = LDAP_AUTH_SIMPLE;
549                 gots |= GOT_METHOD;
550             } else if ( !strcasecmp( val, SASLSTR )) {
551                 ri->ri_bind_method = LDAP_AUTH_SASL;
552                 gots |= GOT_METHOD;
553             } else {
554                 ri->ri_bind_method = -1;
555             }
556         } else if ( !strncasecmp( cargv[ i ], 
557                         SASLMECHSTR, sizeof( SASLMECHSTR ) - 1 ) ) {
558             val = cargv[ i ] + sizeof( SASLMECHSTR );
559             gots |= GOT_MECH;
560             ri->ri_saslmech = strdup( val );
561         } else if ( !strncasecmp( cargv[ i ], 
562                         CREDSTR, sizeof( CREDSTR ) - 1 ) ) {
563             val = cargv[ i ] + sizeof( CREDSTR );
564             ri->ri_password = strdup( val );
565         } else if ( !strncasecmp( cargv[ i ], 
566                         SECPROPSSTR, sizeof( SECPROPSSTR ) - 1 ) ) {
567             val = cargv[ i ] + sizeof( SECPROPSSTR );
568             ri->ri_secprops = strdup( val );
569         } else if ( !strncasecmp( cargv[ i ], 
570                         REALMSTR, sizeof( REALMSTR ) - 1 ) ) {
571             val = cargv[ i ] + sizeof( REALMSTR );
572             ri->ri_realm = strdup( val );
573         } else if ( !strncasecmp( cargv[ i ], 
574                         AUTHCSTR, sizeof( AUTHCSTR ) - 1 ) ) {
575             val = cargv[ i ] + sizeof( AUTHCSTR );
576             ri->ri_authcId = strdup( val );
577         } else if ( !strncasecmp( cargv[ i ], 
578                         OLDAUTHCSTR, sizeof( OLDAUTHCSTR ) - 1 ) ) {
579             /* Old authcID is provided for some backwards compatibility */
580             val = cargv[ i ] + sizeof( OLDAUTHCSTR );
581             ri->ri_authcId = strdup( val );
582         } else if ( !strncasecmp( cargv[ i ], 
583                         AUTHZSTR, sizeof( AUTHZSTR ) - 1 ) ) {
584             val = cargv[ i ] + sizeof( AUTHZSTR );
585             ri->ri_authzId = strdup( val );
586         } else if ( !strncasecmp( cargv[ i ], 
587                         SRVTABSTR, sizeof( SRVTABSTR ) - 1 ) ) {
588             val = cargv[ i ] + sizeof( SRVTABSTR );
589             if ( ri->ri_srvtab != NULL ) {
590                 free( ri->ri_srvtab );
591             }
592             ri->ri_srvtab = strdup( val );
593         } else {
594             fprintf( stderr, 
595                     "Error: parse_replica_line: unknown keyword \"%s\"\n",
596                     cargv[ i ] );
597         }
598     }
599     
600         if ( ri->ri_bind_method == LDAP_AUTH_SASL) {
601                 if ((gots & GOT_MECH) == 0) {
602                         fprintf( stderr, "Error: \"replica\" line needs SASLmech flag in " );
603                         fprintf( stderr, "slapd config file, line %d\n", lineno );
604                         return -1;
605                 }
606         } else if ( gots != GOT_ALL ) {
607                 fprintf( stderr, "Error: Malformed \"replica\" line in slapd " );
608                 fprintf( stderr, "config file, line %d\n", lineno );
609                 return -1;
610         }
611     return 0;
612 }
613