]> git.sur5r.net Git - openldap/blob - servers/slurpd/config.c
some more debug logging
[openldap] / servers / slurpd / config.c
1 /* $OpenLDAP$ */
2 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
3  *
4  * Copyright 1998-2006 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     *slurpd_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 #define GOT_REPLOG_NO           (0)
86 #define GOT_REPLOG_ONE          (1)
87 #define GOT_REPLOG_YES          (2)     
88 #define GOT_REPLOG_DONE         (3)
89 #define GOT_REPLOG_MASK         (0xF)
90 #define GOT_REPLOG(i)           ((i) & GOT_REPLOG_MASK)
91 #define GOT_REPLOG_SET(i,v)     ((i) = ((i) & ~GOT_REPLOG_MASK) | ((v) & GOT_REPLOG_MASK))
92
93 #define GOT_REPLOG_PID          (0x10)
94 #define GOT_REPLOG_ARGS         (0x20)
95 #define GOT_REPLOG_INTERVAL     (0x40)
96         int     got_replog =    GOT_REPLOG_NO;
97
98         /*
99          * replica-pidfile and replica-argsfile can appear before any replog;
100          * in this case they're global (legacy behavior); otherwise, since
101          * each replog needs a slurpd, they can appear after a replogfile line;
102          * in that case, the replog specific values are used.
103          */
104
105         if ( cargv == NULL ) {
106                 cargv = ch_calloc( ARGS_STEP + 1, sizeof(*cargv) );
107                 cargv_size = ARGS_STEP + 1;
108         }
109
110         Debug( LDAP_DEBUG_CONFIG, "Config: opening config file \"%s\"\n",
111                 fname, 0, 0 );
112
113         if ( (fp = fopen( fname, "r" )) == NULL ) {
114                 perror( fname );
115                 exit( EXIT_FAILURE );
116         }
117
118         lineno = 0;
119         while ( (line = slurpd_getline( fp )) != NULL ) {
120                 /* skip comments and blank lines */
121                 if ( line[0] == '#' || line[0] == '\0' ) {
122                         continue;
123                 }
124
125                 Debug( LDAP_DEBUG_CONFIG, "Config: (%s)\n", line, 0, 0 );
126
127                 parse_line( line );
128
129                 if ( cargc < 1 ) {
130                         fprintf( stderr, "line %d: bad config line (ignored)\n", lineno );
131                         continue;
132                 }
133
134                 /* replication log file to which changes are appended */
135                 if ( strcasecmp( cargv[0], "replogfile" ) == 0 ) {
136                         /* 
137                          * if slapd_replogfile has a value, the -r option was given,
138                          * so use that value.  If slapd_replogfile has length == 0,
139                          * then we should use the value in the config file we're reading.
140                          */
141                         if ( cargc < 2 ) {
142                                 fprintf( stderr,
143                                         "line %d: missing filename in \"replogfile ",
144                                         lineno );
145                                 fprintf( stderr, "<filename>\" line\n" );
146                                 exit( EXIT_FAILURE );
147
148                         } else if ( cargc > 2 && *cargv[2] != '#' ) {
149                                 fprintf( stderr,
150                                         "line %d: extra cruft at the end of \"replogfile %s\"",
151                                         lineno, cargv[1] );
152                                 fprintf( stderr, "line (ignored)\n" );
153                         }
154
155                         LUTIL_SLASHPATH( cargv[1] );
156                         if ( sglob->slapd_replogfile[0] == '\0' ) {
157                                 strcpy( sglob->slapd_replogfile, cargv[1] );
158                                 GOT_REPLOG_SET(got_replog, GOT_REPLOG_YES);
159
160                         } else {
161                                 if ( strcmp( sglob->slapd_replogfile, cargv[1] ) == 0 ) {
162                                         GOT_REPLOG_SET(got_replog, GOT_REPLOG_YES);
163
164                                 } else if ( GOT_REPLOG(got_replog) == GOT_REPLOG_YES ) {
165                                         GOT_REPLOG_SET(got_replog, GOT_REPLOG_DONE);
166
167                                 } else {
168                                         GOT_REPLOG_SET(got_replog, GOT_REPLOG_ONE);
169                                 }
170                         }
171
172                 } else if ( strcasecmp( cargv[0], "replica" ) == 0 ) {
173                         add_replica( cargv, cargc );
174             
175                 /* include another config file */
176                 } else if ( strcasecmp( cargv[0], "include" ) == 0 ) {
177                         char *savefname;
178                         int savelineno;
179
180                         if ( cargc < 2 ) {
181                                 Debug( LDAP_DEBUG_ANY,
182                                         "%s: line %d: missing filename in \"include <filename>\" line\n",
183                                         fname, lineno, 0 );
184                 
185                                 return( 1 );
186                         }
187                         LUTIL_SLASHPATH( cargv[1] );
188                         savefname = strdup( cargv[1] );
189                         savelineno = lineno;
190             
191                         if ( slurpd_read_config( savefname ) != 0 ) {
192                                 return( 1 );
193                         }
194                 
195                         free( savefname );
196                         lineno = savelineno - 1;
197
198                 } else if ( strcasecmp( cargv[0], "replica-pidfile" ) == 0 ) {
199                         if ( cargc < 2 ) {
200                                 Debug( LDAP_DEBUG_ANY,
201                                         "%s: line %d: missing file name in \"replica-pidfile <file>\" line\n",
202                                         fname, lineno, 0 );
203
204                                 return( 1 );
205                         }
206
207                         switch ( GOT_REPLOG(got_replog) ) {
208                         case GOT_REPLOG_YES:
209                                 Debug( LDAP_DEBUG_CONFIG, "%s: line %d: "
210                                         "got replog specific replica-pidfile \"%s\".\n",
211                                         fname, lineno, cargv[1] );
212                         case GOT_REPLOG_NO:
213                                 LUTIL_SLASHPATH( cargv[1] );
214                                 if ( slurpd_pid_file != NULL ) {
215                                         ch_free( slurpd_pid_file );
216                                 }
217                                 slurpd_pid_file = ch_strdup( cargv[1] );
218                                 got_replog |= GOT_REPLOG_PID;
219                                 break;
220
221                         default:
222                                 Debug( LDAP_DEBUG_CONFIG, "%s: line %d: "
223                                         "replica-pidfile \"%s\" not mine.\n",
224                                         fname, lineno, cargv[1] );
225                                 break;
226                         }
227
228                 } else if ( strcasecmp( cargv[0], "replica-argsfile" ) == 0 ) {
229                         if ( cargc < 2 ) {
230                                 Debug( LDAP_DEBUG_ANY,
231                                         "%s: line %d: missing file name in \"argsfile <file>\" line\n",
232                                         fname, lineno, 0 );
233
234                                 return( 1 );
235                         }
236
237                         switch ( GOT_REPLOG(got_replog) ) {
238                         case GOT_REPLOG_YES:
239                                 Debug( LDAP_DEBUG_CONFIG, "%s: line %d: "
240                                         "got replog specific replica-argsfile \"%s\".\n",
241                                         fname, lineno, cargv[1] );
242                         case GOT_REPLOG_NO:
243                                 LUTIL_SLASHPATH( cargv[1] );
244                                 if ( slurpd_args_file != NULL ) {
245                                         ch_free( slurpd_args_file );
246                                 }
247                                 slurpd_args_file = ch_strdup( cargv[1] );
248                                 got_replog |= GOT_REPLOG_ARGS;
249                                 break;
250
251                         default:
252                                 Debug( LDAP_DEBUG_CONFIG, "%s: line %d: "
253                                         "replica-argsfile \"%s\" not mine.\n",
254                                         fname, lineno, cargv[1] );
255                                 break;
256                         }
257
258                 } else if ( strcasecmp( cargv[0], "replicationinterval" ) == 0 ) {
259                         int c;
260
261                         if ( cargc < 2 ) {
262                                 Debug( LDAP_DEBUG_ANY, "%s: line %d: missing interval in "
263                                         "\"replicationinterval <seconds>\" line\n",
264                                         fname, lineno, 0 );
265                                 return( 1 );
266                         }
267
268                         if ( lutil_atoi( &c, cargv[1] ) != 0 || c < 1 ) {
269                                 Debug( LDAP_DEBUG_ANY, "%s: line %d: invalid interval "
270                                         "(%d) in \"replicationinterval <seconds>\" line\n",
271                                         fname, lineno, c );
272
273                                 return( 1 );
274                         }
275
276                         switch ( GOT_REPLOG(got_replog) ) {
277                         case GOT_REPLOG_YES:
278                                 Debug( LDAP_DEBUG_CONFIG, "%s: line %d: "
279                                         "got replog specific replicationinterval \"%s\".\n",
280                                         fname, lineno, cargv[1] );
281                         case GOT_REPLOG_NO:
282                                 sglob->no_work_interval = c;
283                                 got_replog |= GOT_REPLOG_INTERVAL;
284                                 break;
285
286                         default:
287                                 Debug( LDAP_DEBUG_CONFIG, "%s: line %d: "
288                                         "replicationinterval \"%s\" not mine.\n",
289                                         fname, lineno, cargv[1] );
290                                 break;
291                         }
292                 }
293         }
294
295         fclose( fp );
296         Debug( LDAP_DEBUG_CONFIG,
297                 "Config: ** configuration file successfully read and parsed\n",
298                 0, 0, 0 );
299         return 0;
300 }
301
302
303
304
305 /*
306  * Parse one line of input.
307  */
308 static void
309 parse_line(
310     char        *line
311 )
312 {
313     char *      token;
314
315     cargc = 0;
316     for ( token = strtok_quote( line, " \t" ); token != NULL;
317         token = strtok_quote( NULL, " \t" ) )
318     {
319         if ( cargc == cargv_size - 1 ) {
320             char **tmp;
321             tmp = ch_realloc( cargv, (cargv_size + ARGS_STEP) *
322                                sizeof(*cargv) );
323             if (tmp == NULL) {
324                 cargc = 0;
325                 return;
326             }
327             cargv = tmp;
328             cargv_size += ARGS_STEP;
329         }
330
331         cargv[cargc++] = token;
332     }
333     cargv[cargc] = NULL;
334 }
335
336
337
338
339 static char *
340 strtok_quote(
341     char *line,
342     char *sep
343 )
344 {
345     int         inquote;
346     char        *tmp;
347     static char *next;
348
349     if ( line != NULL ) {
350         next = line;
351     }
352     while ( *next && strchr( sep, *next ) ) {
353         next++;
354     }
355
356     if ( *next == '\0' ) {
357         next = NULL;
358         return( NULL );
359     }
360     tmp = next;
361
362     for ( inquote = 0; *next; ) {
363         switch ( *next ) {
364         case '"':
365             if ( inquote ) {
366                 inquote = 0;
367             } else {
368                 inquote = 1;
369             }
370             AC_MEMCPY( next, next + 1, strlen( next + 1 ) + 1 );
371             break;
372
373         case '\\':
374             if ( next[1] )
375                 AC_MEMCPY( next, next + 1, strlen( next + 1 ) + 1 );
376             next++;             /* dont parse the escaped character */
377             break;
378
379         default:
380             if ( ! inquote ) {
381                 if ( strchr( sep, *next ) != NULL ) {
382                     *next++ = '\0';
383                     return( tmp );
384                 }
385             }
386             next++;
387             break;
388         }
389     }
390
391     return( tmp );
392 }
393
394 #define CATLINE( buf )  { \
395     int len; \
396     len = strlen( buf ); \
397     while ( lcur + len + 1 > lmax ) { \
398         lmax += BUFSIZ; \
399         line = (char *) ch_realloc( line, lmax ); \
400     } \
401     strcpy( line + lcur, buf ); \
402     lcur += len; \
403 }
404
405
406
407 /*
408  * Get a line of input.
409  */
410 static char *
411 slurpd_getline(
412     FILE *fp
413 )
414 {
415     char        *p;
416     static char buf[BUFSIZ];
417     static char *line;
418     static int  lmax, lcur;
419
420     lcur = 0;
421     CATLINE( buf );
422     while ( fgets( buf, sizeof(buf), fp ) != NULL ) {
423         if ( (p = strchr( buf, '\n' )) != NULL ) {
424                 if( p > buf && p[-1] == '\r' ) --p;       
425                 *p = '\0';
426         }
427         lineno++;
428         if ( ! isspace( (unsigned char) buf[0] ) ) {
429             return( line );
430         }
431
432         /* change leading whitespace to space */
433         buf[0] = ' ';
434
435         CATLINE( buf );
436     }
437     buf[0] = '\0';
438
439     return( line[0] ? line : NULL );
440 }
441
442
443 /*
444  * Add a node to the array of replicas.
445  */
446 static void
447 add_replica(
448     char        **cargv,
449     int         cargc
450 )
451 {
452     int nr;
453
454     nr = ++sglob->num_replicas;
455     sglob->replicas = (Ri **) ch_realloc( sglob->replicas,
456             ( nr + 1 )  * sizeof( Re * ));
457     if ( sglob->replicas == NULL ) {
458         fprintf( stderr, "out of memory, add_replica\n" );
459         exit( EXIT_FAILURE );
460     }
461     sglob->replicas[ nr ] = NULL; 
462
463     if ( Ri_init( &(sglob->replicas[ nr - 1 ])) < 0 ) {
464         fprintf( stderr, "out of memory, Ri_init\n" );
465         exit( EXIT_FAILURE );
466     }
467     if ( parse_replica_line( cargv, cargc,
468             sglob->replicas[ nr - 1] ) < 0 ) {
469         /* Something bad happened - back out */
470         fprintf( stderr,
471             "Warning: failed to add replica \"%s:%d - ignoring replica\n",
472             sglob->replicas[ nr - 1 ]->ri_hostname == NULL ?
473             "(null)" : sglob->replicas[ nr - 1 ]->ri_hostname,
474             sglob->replicas[ nr - 1 ]->ri_port );
475         sglob->replicas[ nr - 1] = NULL;
476         sglob->num_replicas--;
477     } else {
478         Debug( LDAP_DEBUG_CONFIG,
479                 "Config: ** successfully added replica \"%s:%d\"\n",
480                 sglob->replicas[ nr - 1 ]->ri_hostname == NULL ?
481                 "(null)" : sglob->replicas[ nr - 1 ]->ri_hostname,
482                 sglob->replicas[ nr - 1 ]->ri_port, 0 );
483         sglob->replicas[ nr - 1]->ri_stel =
484                 sglob->st->st_add( sglob->st,
485                 sglob->replicas[ nr - 1 ] );
486         if ( sglob->replicas[ nr - 1]->ri_stel == NULL ) {
487             fprintf( stderr, "Failed to add status element structure\n" );
488             exit( EXIT_FAILURE );
489         }
490     }
491 }
492
493
494
495 /* 
496  * Parse a "replica" line from the config file.  replica lines should be
497  * in the following format:
498  * replica    host=<hostname:portnumber> binddn=<binddn>
499  *            bindmethod="simple" credentials=<creds>
500  *
501  * where:
502  * <hostname:portnumber> describes the host name and port number where the
503  * replica is running,
504  *
505  * <binddn> is the DN to bind to the replica slapd as,
506  *
507  * bindmethod is "simple", and
508  *
509  * <creds> are the credentials (e.g. password) for binddn.  <creds> are
510  * only used for bindmethod=simple.  
511  *
512  * The "replica" config file line may be split across multiple lines.  If
513  * a line begins with whitespace, it is considered a continuation of the
514  * previous line.
515  */
516 #define GOT_HOST        1
517 #define GOT_DN          2
518 #define GOT_METHOD      4
519 #define GOT_ALL         ( GOT_HOST | GOT_DN | GOT_METHOD )
520 #define GOT_MECH        8
521
522 static int
523 parse_replica_line( 
524     char        **cargv,
525     int         cargc,
526     Ri          *ri
527 )
528 {
529     int         gots = 0;
530     int         i;
531     char        *hp, *val;
532     LDAPURLDesc *ludp;
533
534     for ( i = 1; i < cargc; i++ ) {
535         if ( !strncasecmp( cargv[ i ], HOSTSTR, sizeof( HOSTSTR ) - 1 ) ) {
536                 if ( gots & GOT_HOST ) {
537                         fprintf( stderr, "Error: Malformed \"replica\" line in slapd config " );
538                         fprintf( stderr, "file, too many host or uri names specified, line %d\n",
539                                 lineno );
540                         return -1;
541                 }       
542             val = cargv[ i ] + sizeof( HOSTSTR ); /* '\0' string terminator accounts for '=' */
543             if (( hp = strchr( val, ':' )) != NULL ) {
544                 *hp = '\0';
545                 hp++;
546                 if ( lutil_atoi( &ri->ri_port, hp ) != 0 ) {
547                     fprintf( stderr, "unable to parse port \"%s\", line %d\n",
548                             hp, lineno );
549                     return -1;
550                 }
551             }
552             if ( ri->ri_port <= 0 ) {
553                 ri->ri_port = LDAP_PORT;
554             }
555             ri->ri_hostname = strdup( val );
556             gots |= GOT_HOST;
557         } else if ( !strncasecmp( cargv[ i ], URISTR, sizeof( URISTR ) - 1 ) ) {
558                 if ( gots & GOT_HOST ) {
559                         fprintf( stderr, "Error: Malformed \"replica\" line in slapd config " );
560                         fprintf( stderr, "file, too many host or uri names specified, line %d\n",
561                                 lineno );
562                         return -1;
563                 }               
564                 if ( ldap_url_parse( cargv[ i ] + sizeof( URISTR ), &ludp ) != LDAP_SUCCESS ) {
565                         fprintf( stderr, "Error: Malformed \"replica\" line in slapd config " );
566                         fprintf( stderr, "file, bad uri format specified, line %d\n",
567                                 lineno );
568                         return -1;
569                 }
570                 if (ludp->lud_host == NULL) {
571                         fprintf( stderr, "Error: Malformed \"replica\" line in slapd config " );
572                         fprintf( stderr, "file, missing uri hostname, line %d\n",
573                                 lineno );
574                         return -1;
575                 }
576                 ri->ri_hostname = strdup ( ludp->lud_host );
577                 ri->ri_port = ludp->lud_port;
578                 ri->ri_uri = strdup ( cargv[ i ] + sizeof( URISTR ) );          
579                 ldap_free_urldesc( ludp );                              
580             gots |= GOT_HOST;
581         } else if ( !strncasecmp( cargv[ i ], 
582                         ATTRSTR, sizeof( ATTRSTR ) - 1 ) ) {
583             /* ignore it */ ;
584         } else if ( !strncasecmp( cargv[ i ], 
585                         SUFFIXSTR, sizeof( SUFFIXSTR ) - 1 ) ) {
586             /* ignore it */ ;
587         } else if ( !strncasecmp( cargv[i], STARTTLSSTR, sizeof(STARTTLSSTR)-1 )) {
588             val = cargv[ i ] + sizeof( STARTTLSSTR );
589                 if( !strcasecmp( val, CRITICALSTR ) ) {
590                         ri->ri_tls = TLS_CRITICAL;
591                 } else {
592                         ri->ri_tls = TLS_ON;
593                 }
594         } else if ( !strncasecmp( cargv[ i ], TLSSTR, sizeof( TLSSTR ) - 1 ) ) {
595             val = cargv[ i ] + sizeof( TLSSTR );
596                 if( !strcasecmp( val, CRITICALSTR ) ) {
597                         ri->ri_tls = TLS_CRITICAL;
598                 } else {
599                         ri->ri_tls = TLS_ON;
600                 }
601         } else if ( !strncasecmp( cargv[ i ],
602                         BINDDNSTR, sizeof( BINDDNSTR ) - 1 ) ) { 
603             val = cargv[ i ] + sizeof( BINDDNSTR );
604             ri->ri_bind_dn = strdup( val );
605             gots |= GOT_DN;
606         } else if ( !strncasecmp( cargv[ i ], BINDMETHSTR,
607                 sizeof( BINDMETHSTR ) - 1 ) ) {
608             val = cargv[ i ] + sizeof( BINDMETHSTR );
609             if ( !strcasecmp( val, KERBEROSSTR )) {
610             fprintf( stderr, "Error: a bind method of \"kerberos\" was\n" );
611             fprintf( stderr, "specified in the slapd configuration file.\n" );
612             fprintf( stderr, "slurpd no longer supports Kerberos.\n" );
613             exit( EXIT_FAILURE );
614             } else if ( !strcasecmp( val, SIMPLESTR )) {
615                 ri->ri_bind_method = LDAP_AUTH_SIMPLE;
616                 gots |= GOT_METHOD;
617             } else if ( !strcasecmp( val, SASLSTR )) {
618                 ri->ri_bind_method = LDAP_AUTH_SASL;
619                 gots |= GOT_METHOD;
620             } else {
621                 ri->ri_bind_method = -1;
622             }
623         } else if ( !strncasecmp( cargv[ i ], 
624                         SASLMECHSTR, sizeof( SASLMECHSTR ) - 1 ) ) {
625             val = cargv[ i ] + sizeof( SASLMECHSTR );
626             gots |= GOT_MECH;
627             ri->ri_saslmech = strdup( val );
628         } else if ( !strncasecmp( cargv[ i ], 
629                         CREDSTR, sizeof( CREDSTR ) - 1 ) ) {
630             val = cargv[ i ] + sizeof( CREDSTR );
631             ri->ri_password = strdup( val );
632         } else if ( !strncasecmp( cargv[ i ], 
633                         SECPROPSSTR, sizeof( SECPROPSSTR ) - 1 ) ) {
634             val = cargv[ i ] + sizeof( SECPROPSSTR );
635             ri->ri_secprops = strdup( val );
636         } else if ( !strncasecmp( cargv[ i ], 
637                         REALMSTR, sizeof( REALMSTR ) - 1 ) ) {
638             val = cargv[ i ] + sizeof( REALMSTR );
639             ri->ri_realm = strdup( val );
640         } else if ( !strncasecmp( cargv[ i ], 
641                         AUTHCSTR, sizeof( AUTHCSTR ) - 1 ) ) {
642             val = cargv[ i ] + sizeof( AUTHCSTR );
643             ri->ri_authcId = strdup( val );
644         } else if ( !strncasecmp( cargv[ i ], 
645                         OLDAUTHCSTR, sizeof( OLDAUTHCSTR ) - 1 ) ) {
646             /* Old authcID is provided for some backwards compatibility */
647             val = cargv[ i ] + sizeof( OLDAUTHCSTR );
648             ri->ri_authcId = strdup( val );
649         } else if ( !strncasecmp( cargv[ i ], 
650                         AUTHZSTR, sizeof( AUTHZSTR ) - 1 ) ) {
651             val = cargv[ i ] + sizeof( AUTHZSTR );
652             ri->ri_authzId = strdup( val );
653         } else if ( !strncasecmp( cargv[ i ], 
654                         SRVTABSTR, sizeof( SRVTABSTR ) - 1 ) ) {
655             val = cargv[ i ] + sizeof( SRVTABSTR );
656             if ( ri->ri_srvtab != NULL ) {
657                 free( ri->ri_srvtab );
658             }
659             ri->ri_srvtab = strdup( val );
660         } else {
661             fprintf( stderr, 
662                     "Error: parse_replica_line: unknown keyword \"%s\"\n",
663                     cargv[ i ] );
664         }
665     }
666     
667         if ( ri->ri_bind_method == LDAP_AUTH_SASL) {
668                 if ((gots & GOT_MECH) == 0) {
669                         fprintf( stderr, "Error: \"replica\" line needs SASLmech flag in " );
670                         fprintf( stderr, "slapd config file, line %d\n", lineno );
671                         return -1;
672                 }
673         } else if ( gots != GOT_ALL ) {
674                 fprintf( stderr, "Error: Malformed \"replica\" line in slapd " );
675                 fprintf( stderr, "config file, line %d\n", lineno );
676                 return -1;
677         }
678     return 0;
679 }
680