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