]> git.sur5r.net Git - openldap/blob - servers/slapd/config.c
misc bug fix for @oc support
[openldap] / servers / slapd / config.c
1 /* config.c - configuration file handling routines */
2 /* $OpenLDAP$ */
3 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
4  *
5  * Copyright 1998-2004 The OpenLDAP Foundation.
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted only as authorized by the OpenLDAP
10  * Public License.
11  *
12  * A copy of this license is available in the file LICENSE in the
13  * top-level directory of the distribution or, alternatively, at
14  * <http://www.OpenLDAP.org/license.html>.
15  */
16 /* Portions Copyright (c) 1995 Regents of the University of Michigan.
17  * All rights reserved.
18  *
19  * Redistribution and use in source and binary forms are permitted
20  * provided that this notice is preserved and that due credit is given
21  * to the University of Michigan at Ann Arbor. The name of the University
22  * may not be used to endorse or promote products derived from this
23  * software without specific prior written permission. This software
24  * is provided ``as is'' without express or implied warranty.
25  */
26
27 #include "portable.h"
28
29 #include <stdio.h>
30
31 #include <ac/string.h>
32 #include <ac/ctype.h>
33 #include <ac/signal.h>
34 #include <ac/socket.h>
35 #include <ac/errno.h>
36
37 #include "ldap_pvt.h"
38 #include "slap.h"
39 #ifdef LDAP_SLAPI
40 #include "slapi/slapi.h"
41 #endif
42 #include "lutil.h"
43
44 #define ARGS_STEP       512
45
46 /*
47  * defaults for various global variables
48  */
49 slap_mask_t             global_allows = 0;
50 slap_mask_t             global_disallows = 0;
51 char            *replogfile;
52 int             global_gentlehup = 0;
53 int             global_idletimeout = 0;
54 char    *global_host = NULL;
55 char    *global_realm = NULL;
56 char            *ldap_srvtab = "";
57 char            **default_passwd_hash = NULL;
58 int             cargc = 0, cargv_size = 0;
59 char    **cargv;
60 struct berval default_search_base = BER_BVNULL;
61 struct berval default_search_nbase = BER_BVNULL;
62 unsigned                num_subordinates = 0;
63
64 ber_len_t sockbuf_max_incoming = SLAP_SB_MAX_INCOMING_DEFAULT;
65 ber_len_t sockbuf_max_incoming_auth= SLAP_SB_MAX_INCOMING_AUTH;
66
67 int     slap_conn_max_pending = SLAP_CONN_MAX_PENDING_DEFAULT;
68 int     slap_conn_max_pending_auth = SLAP_CONN_MAX_PENDING_AUTH;
69
70 char   *slapd_pid_file  = NULL;
71 char   *slapd_args_file = NULL;
72
73 char   *strtok_quote_ptr;
74
75 int use_reverse_lookup = 0;
76
77 #ifdef LDAP_SLAPI
78 int slapi_plugins_used = 0;
79 #endif
80
81 static char *fp_getline(FILE *fp, int *lineno);
82 static void fp_getline_init(int *lineno);
83 static int fp_parse_line(int lineno, char *line);
84
85 static char     *strtok_quote(char *line, char *sep);
86 static int load_ucdata(char *path);
87
88 static int add_syncrepl LDAP_P(( Backend *, char **, int ));
89 static int parse_syncrepl_line LDAP_P(( char **, int, syncinfo_t *));
90
91 static int get_attrs_from_file LDAP_P(( char ***, const char *, const char * ));
92 static int get_ocs_from_file LDAP_P((
93                                         ObjectClass ***, const char *, const char *));
94 static char **str2attrs( char ***, char *, const char * );
95 static ObjectClass **str2ocs( ObjectClass ***, char *, const char * );
96
97 int
98 read_config( const char *fname, int depth )
99 {
100         FILE    *fp;
101         char    *line, *savefname, *saveline;
102         int savelineno;
103         int     lineno, i;
104         int rc;
105         struct berval vals[2];
106         char *replicahost;
107         LDAPURLDesc *ludp;
108         static BackendInfo *bi = NULL;
109         static BackendDB        *be = NULL;
110         char    *next;
111
112         vals[1].bv_val = NULL;
113
114         if ( depth == 0 ) {
115                 cargv = ch_calloc( ARGS_STEP + 1, sizeof(*cargv) );
116                 cargv_size = ARGS_STEP + 1;
117         }
118
119         if ( (fp = fopen( fname, "r" )) == NULL ) {
120                 ldap_syslog = 1;
121                 Debug( LDAP_DEBUG_ANY,
122                     "could not open config file \"%s\": %s (%d)\n",
123                     fname, strerror(errno), errno );
124                 return 1;
125         }
126
127         Debug( LDAP_DEBUG_CONFIG, "reading config file %s\n", fname, 0, 0 );
128
129
130         fp_getline_init( &lineno );
131
132         while ( (line = fp_getline( fp, &lineno )) != NULL ) {
133                 /* skip comments and blank lines */
134                 if ( line[0] == '#' || line[0] == '\0' ) {
135                         continue;
136                 }
137
138                 /* fp_parse_line is destructive, we save a copy */
139                 saveline = ch_strdup( line );
140
141                 if ( fp_parse_line( lineno, line ) != 0 ) {
142                         return( 1 );
143                 }
144
145                 if ( cargc < 1 ) {
146                         Debug( LDAP_DEBUG_ANY,
147                             "%s: line %d: bad config line (ignored)\n",
148                             fname, lineno, 0 );
149
150                         continue;
151                 }
152
153                 if ( strcasecmp( cargv[0], "backend" ) == 0 ) {
154                         if ( cargc < 2 ) {
155                                 Debug( LDAP_DEBUG_ANY,
156                 "%s: line %d: missing type in \"backend <type>\" line\n",
157                                     fname, lineno, 0 );
158
159                                 return( 1 );
160                         }
161
162                         if( be != NULL ) {
163                                 Debug( LDAP_DEBUG_ANY,
164 "%s: line %d: backend line must appear before any database definition\n",
165                                     fname, lineno, 0 );
166
167                                 return( 1 );
168                         }
169
170                         bi = backend_info( cargv[1] );
171
172                         if( bi == NULL ) {
173                                 Debug( LDAP_DEBUG_ANY,
174                                         "backend %s initialization failed.\n",
175                                     cargv[1], 0, 0 );
176
177                                 return( 1 );
178                         }
179                 } else if ( strcasecmp( cargv[0], "database" ) == 0 ) {
180                         if ( cargc < 2 ) {
181                                 Debug( LDAP_DEBUG_ANY,
182                 "%s: line %d: missing type in \"database <type>\" line\n",
183                                     fname, lineno, 0 );
184
185                                 return( 1 );
186                         }
187
188                         bi = NULL;
189                         be = backend_db_init( cargv[1] );
190
191                         if( be == NULL ) {
192                                 Debug( LDAP_DEBUG_ANY,
193                                         "database %s initialization failed.\n",
194                                     cargv[1], 0, 0 );
195
196                                 return( 1 );
197                         }
198
199                 /* set local security factor */
200                 } else if ( strcasecmp( cargv[0], "localSSF" ) == 0 ) {
201                         long ssf;
202                         if ( cargc < 2 ) {
203                                 Debug( LDAP_DEBUG_ANY,
204                                    "%s: line %d: missing ssf in \"localSSF <ssf>\" line\n",
205                                     fname, lineno, 0 );
206                                 return( 1 );
207                         }
208
209                         ssf = atol( cargv[1] );
210
211                         if( ssf < 0 ) {
212                                 Debug( LDAP_DEBUG_ANY,
213                                         "%s: line %d: invalid ssf value (%ld) in "
214                                         "\"localSSF <ssf>\" line.\n",
215                                     fname, lineno, ssf );
216                                 return( 1 );
217                         }
218
219                         local_ssf = ssf;
220
221                 /* set thread concurrency */
222                 } else if ( strcasecmp( cargv[0], "concurrency" ) == 0 ) {
223                         int c;
224                         if ( cargc < 2 ) {
225                                 Debug( LDAP_DEBUG_ANY,
226             "%s: line %d: missing level in \"concurrency <level>\" line\n",
227                                     fname, lineno, 0 );
228
229                                 return( 1 );
230                         }
231
232                         c = strtol( cargv[1], &next, 10 );
233                         if ( next == NULL || next[0] != '\0' ) {
234                                 Debug( LDAP_DEBUG_ANY,
235             "%s: line %d: unable to parse level \"%s\" in \"concurrency <level>\" line\n",
236                                     fname, lineno, cargv[1] );
237                                 return( 1 );
238                         }
239
240                         if( c < 1 ) {
241                                 Debug( LDAP_DEBUG_ANY,
242             "%s: line %d: invalid level (%d) in \"concurrency <level>\" line\n",
243                                     fname, lineno, c );
244
245                                 return( 1 );
246                         }
247
248                         ldap_pvt_thread_set_concurrency( c );
249
250                 /* set sockbuf max */
251                 } else if ( strcasecmp( cargv[0], "sockbuf_max_incoming" ) == 0 ) {
252                         long max;
253                         if ( cargc < 2 ) {
254                                 Debug( LDAP_DEBUG_ANY,
255                                            "%s: line %d: missing max in \"sockbuf_max_incoming <bytes>\" line\n",
256                                     fname, lineno, 0 );
257
258                                 return( 1 );
259                         }
260
261                         max = atol( cargv[1] );
262
263                         if( max < 0 ) {
264                                 Debug( LDAP_DEBUG_ANY,
265                                         "%s: line %d: invalid max value (%ld) in "
266                                         "\"sockbuf_max_incoming <bytes>\" line.\n",
267                                     fname, lineno, max );
268
269                                 return( 1 );
270                         }
271
272                         sockbuf_max_incoming = max;
273
274                 /* set sockbuf max authenticated */
275                 } else if ( strcasecmp( cargv[0], "sockbuf_max_incoming_auth" ) == 0 ) {
276                         long max;
277                         if ( cargc < 2 ) {
278                                 Debug( LDAP_DEBUG_ANY,
279                                            "%s: line %d: missing max in \"sockbuf_max_incoming_auth <bytes>\" line\n",
280                                     fname, lineno, 0 );
281
282                                 return( 1 );
283                         }
284
285                         max = atol( cargv[1] );
286
287                         if( max < 0 ) {
288                                 Debug( LDAP_DEBUG_ANY,
289                                         "%s: line %d: invalid max value (%ld) in "
290                                         "\"sockbuf_max_incoming_auth <bytes>\" line.\n",
291                                     fname, lineno, max );
292
293                                 return( 1 );
294                         }
295
296                         sockbuf_max_incoming_auth = max;
297
298                 /* set conn pending max */
299                 } else if ( strcasecmp( cargv[0], "conn_max_pending" ) == 0 ) {
300                         long max;
301                         if ( cargc < 2 ) {
302                                 Debug( LDAP_DEBUG_ANY,
303                                            "%s: line %d: missing max in \"conn_max_pending <requests>\" line\n",
304                                     fname, lineno, 0 );
305
306                                 return( 1 );
307                         }
308
309                         max = atol( cargv[1] );
310
311                         if( max < 0 ) {
312                                 Debug( LDAP_DEBUG_ANY,
313                                         "%s: line %d: invalid max value (%ld) in "
314                                         "\"conn_max_pending <requests>\" line.\n",
315                                     fname, lineno, max );
316
317                                 return( 1 );
318                         }
319
320                         slap_conn_max_pending = max;
321
322                 /* set conn pending max authenticated */
323                 } else if ( strcasecmp( cargv[0], "conn_max_pending_auth" ) == 0 ) {
324                         long max;
325                         if ( cargc < 2 ) {
326                                 Debug( LDAP_DEBUG_ANY,
327                                            "%s: line %d: missing max in \"conn_max_pending_auth <requests>\" line\n",
328                                     fname, lineno, 0 );
329
330                                 return( 1 );
331                         }
332
333                         max = atol( cargv[1] );
334
335                         if( max < 0 ) {
336                                 Debug( LDAP_DEBUG_ANY,
337                                         "%s: line %d: invalid max value (%ld) in "
338                                         "\"conn_max_pending_auth <requests>\" line.\n",
339                                     fname, lineno, max );
340
341                                 return( 1 );
342                         }
343
344                         slap_conn_max_pending_auth = max;
345
346                 /* default search base */
347                 } else if ( strcasecmp( cargv[0], "defaultSearchBase" ) == 0 ) {
348                         if ( cargc < 2 ) {
349                                 Debug( LDAP_DEBUG_ANY, "%s: line %d: "
350                                         "missing dn in \"defaultSearchBase <dn>\" line\n",
351                                         fname, lineno, 0 );
352
353                                 return 1;
354
355                         } else if ( cargc > 2 ) {
356                                 Debug( LDAP_DEBUG_ANY, "%s: line %d: "
357                                         "extra cruft after <dn> in \"defaultSearchBase %s\", "
358                                         "line (ignored)\n",
359                                         fname, lineno, cargv[1] );
360                         }
361
362                         if ( bi != NULL || be != NULL ) {
363                                 Debug( LDAP_DEBUG_ANY, "%s: line %d: "
364                                         "defaultSearchBaase line must appear prior to "
365                                         "any backend or database definition\n",
366                                     fname, lineno, 0 );
367
368                                 return 1;
369                         }
370
371                         if ( default_search_nbase.bv_len ) {
372                                 Debug( LDAP_DEBUG_ANY, "%s: line %d: "
373                                         "default search base \"%s\" already defined "
374                                         "(discarding old)\n",
375                                         fname, lineno, default_search_base.bv_val );
376
377                                 free( default_search_base.bv_val );
378                                 free( default_search_nbase.bv_val );
379                         }
380
381                         if ( load_ucdata( NULL ) < 0 ) return 1;
382
383                         {
384                                 struct berval dn;
385
386                                 dn.bv_val = cargv[1];
387                                 dn.bv_len = strlen( dn.bv_val );
388
389                                 rc = dnPrettyNormal( NULL, &dn,
390                                         &default_search_base,
391                                         &default_search_nbase, NULL );
392
393                                 if( rc != LDAP_SUCCESS ) {
394                                         Debug( LDAP_DEBUG_ANY,
395                                                 "%s: line %d: defaultSearchBase DN is invalid\n",
396                                            fname, lineno, 0 );
397                                         return( 1 );
398                                 }
399                         }
400
401                 /* set maximum threads in thread pool */
402                 } else if ( strcasecmp( cargv[0], "threads" ) == 0 ) {
403                         int c;
404                         if ( cargc < 2 ) {
405                                 Debug( LDAP_DEBUG_ANY,
406             "%s: line %d: missing count in \"threads <count>\" line\n",
407                                     fname, lineno, 0 );
408
409                                 return( 1 );
410                         }
411
412                         c = strtol( cargv[1], &next, 10 );
413                         if (next == NULL || next[0] != '\0' ) {
414                                 Debug( LDAP_DEBUG_ANY,
415             "%s: line %d: unable to parse count \"%s\" in \"threads <count>\" line\n",
416                                     fname, lineno, cargv[1] );
417                                 return( 1 );
418                         }
419
420                         if( c < 0 ) {
421                                 Debug( LDAP_DEBUG_ANY,
422             "%s: line %d: invalid level (%d) in \"threads <count>\" line\n",
423                                     fname, lineno, c );
424
425                                 return( 1 );
426                         }
427
428                         ldap_pvt_thread_pool_maxthreads( &connection_pool, c );
429
430                         /* save for later use */
431                         connection_pool_max = c;
432
433                 /* get pid file name */
434                 } else if ( strcasecmp( cargv[0], "pidfile" ) == 0 ) {
435                         if ( cargc < 2 ) {
436                                 Debug( LDAP_DEBUG_ANY,
437             "%s: line %d: missing file name in \"pidfile <file>\" line\n",
438                                     fname, lineno, 0 );
439
440                                 return( 1 );
441                         }
442
443                         slapd_pid_file = ch_strdup( cargv[1] );
444
445                 /* get args file name */
446                 } else if ( strcasecmp( cargv[0], "argsfile" ) == 0 ) {
447                         if ( cargc < 2 ) {
448                                 Debug( LDAP_DEBUG_ANY,
449             "%s: line %d: missing file name in \"argsfile <file>\" line\n",
450                                     fname, lineno, 0 );
451
452                                 return( 1 );
453                         }
454
455                         slapd_args_file = ch_strdup( cargv[1] );
456
457                 } else if ( strcasecmp( cargv[0], "replica-pidfile" ) == 0 ) {
458                         /* ignore */ ;
459
460                 } else if ( strcasecmp( cargv[0], "replica-argsfile" ) == 0 ) {
461                         /* ignore */ ;
462
463                 /* default password hash */
464                 } else if ( strcasecmp( cargv[0], "password-hash" ) == 0 ) {
465                         if ( cargc < 2 ) {
466                                 Debug( LDAP_DEBUG_ANY,
467             "%s: line %d: missing hash in \"password-hash <hash>\" line\n",
468                                     fname, lineno, 0 );
469
470                                 return( 1 );
471                         }
472                         if ( default_passwd_hash != NULL ) {
473                                 Debug( LDAP_DEBUG_ANY,
474                                         "%s: line %d: already set default password_hash!\n",
475                                         fname, lineno, 0 );
476
477                                 return 1;
478
479                         }
480                         for(i = 1; i < cargc; i++) {
481                                 if ( lutil_passwd_scheme( cargv[i] ) == 0 ) {
482                                         Debug( LDAP_DEBUG_ANY,
483                                                 "%s: line %d: password scheme \"%s\" not available\n",
484                                                 fname, lineno, cargv[i] );
485                                 } else {
486                                         ldap_charray_add( &default_passwd_hash, cargv[i] );
487                                 }
488                         }
489                         if( !default_passwd_hash ) {
490                                 Debug( LDAP_DEBUG_ANY,
491                                         "%s: line %d: no valid hashes found\n",
492                                         fname, lineno, 0 );
493                                 return 1;
494                         }
495
496                 } else if ( strcasecmp( cargv[0], "password-crypt-salt-format" ) == 0 ) 
497                 {
498                         if ( cargc < 2 ) {
499                                 Debug( LDAP_DEBUG_ANY, "%s: line %d: missing format in "
500                                         "\"password-crypt-salt-format <format>\" line\n",
501                                     fname, lineno, 0 );
502
503                                 return 1;
504                         }
505
506                         lutil_salt_format( cargv[1] );
507
508 #ifdef SLAP_AUTH_REWRITE
509                 /* use authid rewrite instead of sasl regexp */
510                 } else if ( strncasecmp( cargv[0], "auth-rewrite",
511                         STRLENOF("auth-rewrite") ) == 0 )
512                 {
513                         int rc = slap_sasl_rewrite_config( fname, lineno,
514                                         cargc, cargv );
515                         if ( rc ) {
516                                 return rc;
517                         }
518 #endif /* SLAP_AUTH_REWRITE */
519
520                 /* Auth + SASL config options */
521                 } else if ( !strncasecmp( cargv[0], "auth", STRLENOF("auth") ) ||
522                         !strncasecmp( cargv[0], "sasl", STRLENOF("sasl") ))
523                 {
524                         if ( slap_sasl_config( cargc, cargv, line, fname, lineno ) )
525                                 return 1;
526
527
528                 } else if ( strcasecmp( cargv[0], "schemadn" ) == 0 ) {
529                         struct berval dn;
530                         if ( cargc < 2 ) {
531                                 Debug( LDAP_DEBUG_ANY,
532             "%s: line %d: missing dn in \"schemadn <dn>\" line\n",
533                                     fname, lineno, 0 );
534                                 return 1 ;
535                         }
536                         ber_str2bv( cargv[1], 0, 0, &dn );
537                         if ( be ) {
538                                 rc = dnPrettyNormal( NULL, &dn, &be->be_schemadn,
539                                         &be->be_schemandn, NULL );
540                         } else {
541                                 rc = dnPrettyNormal( NULL, &dn, &frontendDB->be_schemadn,
542                                         &frontendDB->be_schemandn, NULL );
543                         }
544                         if ( rc != LDAP_SUCCESS ) {
545                                 Debug( LDAP_DEBUG_ANY,
546                                         "%s: line %d: schemadn DN is invalid\n",
547                                         fname, lineno, 0 );
548                                 return 1;
549                         }
550
551                 /* set UCDATA path */
552                 } else if ( strcasecmp( cargv[0], "ucdata-path" ) == 0 ) {
553                         int err;
554                         if ( cargc < 2 ) {
555                                 Debug( LDAP_DEBUG_ANY,
556             "%s: line %d: missing path in \"ucdata-path <path>\" line\n",
557                                     fname, lineno, 0 );
558
559                                 return( 1 );
560                         }
561
562                         err = load_ucdata( cargv[1] );
563                         if ( err <= 0 ) {
564                                 if ( err == 0 ) {
565                                         Debug( LDAP_DEBUG_ANY,
566                                                "%s: line %d: ucdata already loaded, ucdata-path must be set earlier in the file and/or be specified only once!\n",
567                                                fname, lineno, 0 );
568
569                                 }
570                                 return( 1 );
571                         }
572
573                 /* set size limit */
574                 } else if ( strcasecmp( cargv[0], "sizelimit" ) == 0 ) {
575                         int rc = 0, i;
576                         struct slap_limits_set *lim;
577                         
578                         if ( cargc < 2 ) {
579                                 Debug( LDAP_DEBUG_ANY,
580             "%s: line %d: missing limit in \"sizelimit <limit>\" line\n",
581                                     fname, lineno, 0 );
582
583                                 return( 1 );
584                         }
585
586                         if ( be == NULL ) {
587                                 lim = &frontendDB->be_def_limit;
588                         } else {
589                                 lim = &be->be_def_limit;
590                         }
591
592                         for ( i = 1; i < cargc; i++ ) {
593                                 if ( strncasecmp( cargv[i], "size", 4 ) == 0 ) {
594                                         rc = limits_parse_one( cargv[i], lim );
595                                         if ( rc ) {
596                                                 Debug( LDAP_DEBUG_ANY,
597                                                         "%s: line %d: unable "
598                                                         "to parse value \"%s\" "
599                                                         "in \"sizelimit "
600                                                         "<limit>\" line\n",
601                                                         fname, lineno, cargv[i] );
602                                                 return( 1 );
603                                         }
604
605                                 } else {
606                                         if ( strcasecmp( cargv[i], "unlimited" ) == 0 ) {
607                                                 lim->lms_s_soft = -1;
608                                         } else {
609                                                 lim->lms_s_soft = strtol( cargv[i] , &next, 0 );
610                                                 if ( next == cargv[i] ) {
611                                                         Debug( LDAP_DEBUG_ANY,
612                                                             "%s: line %d: unable to parse limit \"%s\" in \"sizelimit <limit>\" line\n",
613                                                             fname, lineno, cargv[i] );
614                                                         return( 1 );
615
616                                                 } else if ( next[0] != '\0' ) {
617                                                         Debug( LDAP_DEBUG_ANY,
618                                                             "%s: line %d: trailing chars \"%s\" in \"sizelimit <limit>\" line ignored\n",
619                                                             fname, lineno, next );
620                                                 }
621                                         }
622                                         lim->lms_s_hard = 0;
623                                 }
624                         }
625
626                 /* set time limit */
627                 } else if ( strcasecmp( cargv[0], "timelimit" ) == 0 ) {
628                         int rc = 0, i;
629                         struct slap_limits_set *lim;
630                         
631                         if ( cargc < 2 ) {
632                                 Debug( LDAP_DEBUG_ANY,
633             "%s: line %d: missing limit in \"timelimit <limit>\" line\n",
634                                     fname, lineno, 0 );
635
636                                 return( 1 );
637                         }
638                         
639                         if ( be == NULL ) {
640                                 lim = &frontendDB->be_def_limit;
641                         } else {
642                                 lim = &be->be_def_limit;
643                         }
644
645                         for ( i = 1; i < cargc; i++ ) {
646                                 if ( strncasecmp( cargv[i], "time", 4 ) == 0 ) {
647                                         rc = limits_parse_one( cargv[i], lim );
648                                         if ( rc ) {
649                                                 Debug( LDAP_DEBUG_ANY,
650                                                         "%s: line %d: unable "
651                                                         "to parse value \"%s\" "
652                                                         "in \"timelimit "
653                                                         "<limit>\" line\n",
654                                                         fname, lineno, cargv[i] );
655                                                 return( 1 );
656                                         }
657
658                                 } else {
659                                         if ( strcasecmp( cargv[i], "unlimited" ) == 0 ) {
660                                                 lim->lms_t_soft = -1;
661                                         } else {
662                                                 lim->lms_t_soft = strtol( cargv[i] , &next, 0 );
663                                                 if ( next == cargv[i] ) {
664                                                         Debug( LDAP_DEBUG_ANY,
665                                                             "%s: line %d: unable to parse limit \"%s\" in \"timelimit <limit>\" line\n",
666                                                             fname, lineno, cargv[i] );
667                                                         return( 1 );
668
669                                                 } else if ( next[0] != '\0' ) {
670                                                         Debug( LDAP_DEBUG_ANY,
671                                                             "%s: line %d: trailing chars \"%s\" in \"timelimit <limit>\" line ignored\n",
672                                                             fname, lineno, next );
673                                                 }
674                                         }
675                                         lim->lms_t_hard = 0;
676                                 }
677                         }
678
679                 /* set regex-based limits */
680                 } else if ( strcasecmp( cargv[0], "limits" ) == 0 ) {
681                         if ( be == NULL ) {
682                                 Debug( LDAP_DEBUG_ANY,
683         "%s: line %d \"limits\" allowed only in database environment.\n%s",
684                                         fname, lineno, "" );
685                                 return( 1 );
686                         }
687
688                         if ( limits_parse( be, fname, lineno, cargc, cargv ) ) {
689                                 return( 1 );
690                         }
691
692                 /* mark this as a subordinate database */
693                 } else if ( strcasecmp( cargv[0], "subordinate" ) == 0 ) {
694                         if ( be == NULL ) {
695                                 Debug( LDAP_DEBUG_ANY, "%s: line %d: subordinate keyword "
696                                         "must appear inside a database definition.\n",
697                                     fname, lineno, 0 );
698                                 return 1;
699
700                         } else {
701                                 SLAP_DBFLAGS(be) |= SLAP_DBFLAG_GLUE_SUBORDINATE;
702                                 num_subordinates++;
703                         }
704
705                 /* add an overlay to this backend */
706                 } else if ( strcasecmp( cargv[0], "overlay" ) == 0 ) {
707                         if ( be == NULL ) {
708                                 if ( cargv[1][0] == '-' && overlay_config( frontendDB, &cargv[1][1] ) ) {
709                                         /* log error */
710                                         Debug( LDAP_DEBUG_ANY, "%s: line %d: "
711                                                 "(optional) global overlay \"%s\" configuration "
712                                                 "failed (ignored)\n", fname, lineno, &cargv[1][1] );
713                                 } else if ( overlay_config( frontendDB, cargv[1] ) ) {
714                                         return 1;
715                                 }
716
717                         } else {
718                                 if ( cargv[1][0] == '-' && overlay_config( be, &cargv[1][1] ) ) {
719                                         /* log error */
720                                         Debug( LDAP_DEBUG_ANY, "%s: line %d: "
721                                                 "(optional) overlay \"%s\" configuration "
722                                                 "failed (ignored)\n", fname, lineno, &cargv[1][1] );
723                                 } else if ( overlay_config( be, cargv[1] ) ) {
724                                         return 1;
725                                 }
726                         }
727
728                 /* set database suffix */
729                 } else if ( strcasecmp( cargv[0], "suffix" ) == 0 ) {
730                         Backend *tmp_be;
731                         struct berval dn, pdn, ndn;
732
733                         if ( cargc < 2 ) {
734                                 Debug( LDAP_DEBUG_ANY, "%s: line %d: "
735                                         "missing dn in \"suffix <dn>\" line\n",
736                                     fname, lineno, 0 );
737
738                                 return( 1 );
739
740                         } else if ( cargc > 2 ) {
741                                 Debug( LDAP_DEBUG_ANY, "%s: line %d: extra cruft "
742                                         "after <dn> in \"suffix %s\" line (ignored)\n",
743                                     fname, lineno, cargv[1] );
744                         }
745
746                         if ( be == NULL ) {
747                                 Debug( LDAP_DEBUG_ANY, "%s: line %d: suffix line "
748                                         "must appear inside a database definition\n",
749                                     fname, lineno, 0 );
750                                 return( 1 );
751
752 #if defined(SLAPD_MONITOR_DN)
753                         /* "cn=Monitor" is reserved for monitoring slap */
754                         } else if ( strcasecmp( cargv[1], SLAPD_MONITOR_DN ) == 0 ) {
755                                 Debug( LDAP_DEBUG_ANY, "%s: line %d: \""
756                                         "%s\" is reserved for monitoring slapd\n", 
757                                         fname, lineno, SLAPD_MONITOR_DN );
758                                 return( 1 );
759 #endif /* SLAPD_MONITOR_DN */
760                         }
761
762                         if ( load_ucdata( NULL ) < 0 ) return 1;
763
764                         dn.bv_val = cargv[1];
765                         dn.bv_len = strlen( cargv[1] );
766
767                         rc = dnPrettyNormal( NULL, &dn, &pdn, &ndn, NULL );
768                         if( rc != LDAP_SUCCESS ) {
769                                 Debug( LDAP_DEBUG_ANY,
770                                         "%s: line %d: suffix DN is invalid\n",
771                                    fname, lineno, 0 );
772                                 return( 1 );
773                         }
774
775                         tmp_be = select_backend( &ndn, 0, 0 );
776                         if ( tmp_be == be ) {
777                                 Debug( LDAP_DEBUG_ANY, "%s: line %d: suffix "
778                                         "already served by this backend (ignored)\n",
779                                     fname, lineno, 0 );
780                                 free( pdn.bv_val );
781                                 free( ndn.bv_val );
782
783                         } else if ( tmp_be  != NULL ) {
784                                 Debug( LDAP_DEBUG_ANY, "%s: line %d: suffix "
785                                         "already served by a preceeding backend \"%s\"\n",
786                                     fname, lineno, tmp_be->be_suffix[0].bv_val );
787                                 free( pdn.bv_val );
788                                 free( ndn.bv_val );
789                                 return( 1 );
790
791                         } else if( pdn.bv_len == 0 && default_search_nbase.bv_len ) {
792                                         Debug( LDAP_DEBUG_ANY, "%s: line %d: "
793                                                 "suffix DN empty and default "
794                                                 "search base provided \"%s\" (assuming okay)\n",
795                                         fname, lineno, default_search_base.bv_val );
796                         }
797
798                         ber_bvarray_add( &be->be_suffix, &pdn );
799                         ber_bvarray_add( &be->be_nsuffix, &ndn );
800
801                /* set max deref depth */
802                } else if ( strcasecmp( cargv[0], "maxDerefDepth" ) == 0 ) {
803                                         int i;
804                        if ( cargc < 2 ) {
805                                Debug( LDAP_DEBUG_ANY,
806                    "%s: line %d: missing depth in \"maxDerefDepth <depth>\" line\n",
807                                    fname, lineno, 0 );
808
809                                return( 1 );
810                        }
811                        if ( be == NULL ) {
812                                Debug( LDAP_DEBUG_ANY,
813 "%s: line %d: depth line must appear inside a database definition.\n",
814                                    fname, lineno, 0 );
815                                 return 1;
816                        }
817
818                        i = strtol( cargv[1], &next, 10 );
819                        if ( next == NULL || next[0] != '\0' ) {
820                                Debug( LDAP_DEBUG_ANY,
821                                           "%s: line %d: unable to parse depth \"%s\" in \"maxDerefDepth <depth>\" "
822                                           "line.\n", fname, lineno, cargv[1] );
823                                 return 1;
824                        }
825
826                        if (i < 0) {
827                                Debug( LDAP_DEBUG_ANY,
828 "%s: line %d: depth must be positive.\n",
829                                    fname, lineno, 0 );
830                                 return 1;
831
832
833                        }
834                        be->be_max_deref_depth = i;
835
836                 /* set magic "root" dn for this database */
837                 } else if ( strcasecmp( cargv[0], "rootdn" ) == 0 ) {
838                         if ( cargc < 2 ) {
839                                 Debug( LDAP_DEBUG_ANY,
840                     "%s: line %d: missing dn in \"rootdn <dn>\" line\n",
841                                     fname, lineno, 0 );
842
843                                 return( 1 );
844                         }
845
846                         if ( be == NULL ) {
847                                 Debug( LDAP_DEBUG_ANY,
848 "%s: line %d: rootdn line must appear inside a database definition.\n",
849                                     fname, lineno, 0 );
850                                 return 1;
851
852                         } else {
853                                 struct berval dn;
854                                 
855                                 if ( load_ucdata( NULL ) < 0 ) return 1;
856
857                                 dn.bv_val = cargv[1];
858                                 dn.bv_len = strlen( cargv[1] );
859
860                                 rc = dnPrettyNormal( NULL, &dn,
861                                         &be->be_rootdn,
862                                         &be->be_rootndn, NULL );
863
864                                 if( rc != LDAP_SUCCESS ) {
865                                         Debug( LDAP_DEBUG_ANY,
866                                                 "%s: line %d: rootdn DN is invalid\n",
867                                            fname, lineno, 0 );
868                                         return( 1 );
869                                 }
870                         }
871
872                 /* set super-secret magic database password */
873                 } else if ( strcasecmp( cargv[0], "rootpw" ) == 0 ) {
874                         if ( cargc < 2 ) {
875                                 Debug( LDAP_DEBUG_ANY, "%s: line %d: "
876                                         "missing passwd in \"rootpw <passwd>\" line\n",
877                                     fname, lineno, 0 );
878
879                                 return( 1 );
880                         }
881
882                         if ( be == NULL ) {
883                                 Debug( LDAP_DEBUG_ANY, "%s: line %d: "
884                                         "rootpw line must appear inside a database "
885                                         "definition.\n",
886                                     fname, lineno, 0 );
887                                 return 1;
888
889                         } else {
890                                 Backend *tmp_be = select_backend( &be->be_rootndn, 0, 0 );
891
892                                 if( tmp_be != be ) {
893                                         Debug( LDAP_DEBUG_ANY, "%s: line %d: "
894                                                 "rootpw can only be set when rootdn is under suffix\n",
895                                         fname, lineno, 0 );
896                                         return 1;
897                                 }
898
899                                 be->be_rootpw.bv_val = ch_strdup( cargv[1] );
900                                 be->be_rootpw.bv_len = strlen( be->be_rootpw.bv_val );
901                         }
902
903                 /* make this database read-only */
904                 } else if ( strcasecmp( cargv[0], "readonly" ) == 0 ) {
905                         if ( cargc < 2 ) {
906                                 Debug( LDAP_DEBUG_ANY,
907             "%s: line %d: missing on|off in \"readonly <on|off>\" line\n",
908                                     fname, lineno, 0 );
909
910                                 return( 1 );
911                         }
912                         if ( be == NULL ) {
913                                 if ( strcasecmp( cargv[1], "on" ) == 0 ) {
914                                         frontendDB->be_restrictops |= SLAP_RESTRICT_OP_WRITES;
915                                 } else {
916                                         frontendDB->be_restrictops &= ~SLAP_RESTRICT_OP_WRITES;
917                                 }
918
919                         } else {
920                                 if ( strcasecmp( cargv[1], "on" ) == 0 ) {
921                                         be->be_restrictops |= SLAP_RESTRICT_OP_WRITES;
922                                 } else {
923                                         be->be_restrictops &= ~SLAP_RESTRICT_OP_WRITES;
924                                 }
925                         }
926
927                 /* restricts specific operations */
928                 } else if ( strcasecmp( cargv[0], "restrict" ) == 0 ) {
929                         slap_mask_t     restrictops = 0;
930                         struct restrictable_exops_t {
931                                 char    *name;
932                                 int     flag;
933                         } restrictable_exops[] = {
934                                 { LDAP_EXOP_START_TLS,          SLAP_RESTRICT_EXOP_START_TLS },
935                                 { LDAP_EXOP_MODIFY_PASSWD,      SLAP_RESTRICT_EXOP_MODIFY_PASSWD },
936                                 { LDAP_EXOP_X_WHO_AM_I,         SLAP_RESTRICT_EXOP_WHOAMI },
937                                 { LDAP_EXOP_X_CANCEL,           SLAP_RESTRICT_EXOP_CANCEL },
938                                 { NULL,                         0 }
939                         };
940                         int i;
941
942                         if ( cargc < 2 ) {
943                                 Debug( LDAP_DEBUG_ANY,
944                                         "%s: line %d: missing <op_list> in \"restrict <op_list>\" "
945                                         "line.\n", fname, lineno, 0 );
946                                 return 1;
947                         }
948
949                         for ( i = 1; i < cargc; i++ ) {
950                                 if ( strcasecmp( cargv[ i ], "read" ) == 0 ) {
951                                         restrictops |= SLAP_RESTRICT_OP_READS;
952
953                                 } else if ( strcasecmp( cargv[ i ], "write" ) == 0 ) {
954                                         restrictops |= SLAP_RESTRICT_OP_WRITES;
955
956                                 } else if ( strcasecmp( cargv[ i ], "add" ) == 0 ) {
957                                         restrictops |= SLAP_RESTRICT_OP_ADD;
958
959                                 } else if ( strcasecmp( cargv[ i ], "bind" ) == 0 ) {
960                                         restrictops |= SLAP_RESTRICT_OP_BIND;
961
962                                 } else if ( strcasecmp( cargv[ i ], "compare" ) == 0 ) {
963                                         restrictops |= SLAP_RESTRICT_OP_COMPARE;
964
965                                 } else if ( strcasecmp( cargv[ i ], "delete" ) == 0 ) {
966                                         restrictops |= SLAP_RESTRICT_OP_DELETE;
967
968                                 } else if ( strncasecmp( cargv[ i ], "extended",
969                                         STRLENOF( "extended" ) ) == 0 )
970                                 {
971                                         char    *e = cargv[ i ] + STRLENOF( "extended" );
972
973                                         if ( e[0] == '=' ) {
974                                                 int     j;
975
976                                                 e++;
977                                                 for ( j = 0; restrictable_exops[ j ].name; j++ ) {
978                                                         if ( strcmp( e, restrictable_exops[j].name ) == 0 )
979                                                         {
980                                                                 restrictops |= restrictable_exops[ j ].flag;
981                                                                 break;
982                                                         }
983                                                 }
984
985                                                 if ( restrictable_exops[ j ].name == NULL ) {
986                                                         goto restrict_unknown;
987                                                 }
988
989                                                 restrictops &= ~SLAP_RESTRICT_OP_EXTENDED;
990
991                                         } else if ( e[0] == '\0' ) {
992                                                 restrictops &= ~SLAP_RESTRICT_EXOP_MASK;
993                                                 restrictops |= SLAP_RESTRICT_OP_EXTENDED;
994                                                 
995                                         } else {
996                                                 goto restrict_unknown;
997                                         }
998
999                                 } else if ( strcasecmp( cargv[ i ], "modify" ) == 0 ) {
1000                                         restrictops |= SLAP_RESTRICT_OP_MODIFY;
1001
1002                                 } else if ( strcasecmp( cargv[ i ], "rename" ) == 0
1003                                         || strcasecmp( cargv[ i ], "modrdn" ) == 0 )
1004                                 {
1005                                         restrictops |= SLAP_RESTRICT_OP_RENAME;
1006
1007                                 } else if ( strcasecmp( cargv[ i ], "search" ) == 0 ) {
1008                                         restrictops |= SLAP_RESTRICT_OP_SEARCH;
1009
1010                                 } else {
1011 restrict_unknown:;
1012
1013                                         Debug( LDAP_DEBUG_ANY, "%s: line %d: "
1014                                                 "unknown operation %s in \"allow <features>\" line\n",
1015                                                 fname, lineno, cargv[i] );
1016                                         return 1;
1017                                 }
1018                         }
1019
1020                         if ( be == NULL ) {
1021                                 frontendDB->be_restrictops |= restrictops;
1022                         } else {
1023                                 be->be_restrictops |= restrictops;
1024                         }
1025
1026                 /* allow these features */
1027                 } else if ( strcasecmp( cargv[0], "allows" ) == 0 ||
1028                         strcasecmp( cargv[0], "allow" ) == 0 )
1029                 {
1030                         slap_mask_t     allows = 0;
1031
1032                         if ( be != NULL ) {
1033                                 Debug( LDAP_DEBUG_ANY,
1034 "%s: line %d: allow line must appear prior to database definitions\n",
1035                                     fname, lineno, 0 );
1036
1037                         }
1038
1039                         if ( cargc < 2 ) {
1040                                 Debug( LDAP_DEBUG_ANY,
1041             "%s: line %d: missing feature(s) in \"allow <features>\" line\n",
1042                                     fname, lineno, 0 );
1043
1044                                 return( 1 );
1045                         }
1046
1047                         for( i=1; i < cargc; i++ ) {
1048                                 if( strcasecmp( cargv[i], "bind_v2" ) == 0 ) {
1049                                         allows |= SLAP_ALLOW_BIND_V2;
1050
1051                                 } else if( strcasecmp( cargv[i], "bind_anon_cred" ) == 0 ) {
1052                                         allows |= SLAP_ALLOW_BIND_ANON_CRED;
1053
1054                                 } else if( strcasecmp( cargv[i], "bind_anon_dn" ) == 0 ) {
1055                                         allows |= SLAP_ALLOW_BIND_ANON_DN;
1056
1057                                 } else if( strcasecmp( cargv[i], "update_anon" ) == 0 ) {
1058                                         allows |= SLAP_ALLOW_UPDATE_ANON;
1059
1060                                 } else {
1061                                         Debug( LDAP_DEBUG_ANY, "%s: line %d: "
1062                                                 "unknown feature %s in \"allow <features>\" line\n",
1063                                                 fname, lineno, cargv[i] );
1064
1065                                         return 1;
1066                                 }
1067                         }
1068
1069                         global_allows |= allows;
1070
1071                 /* disallow these features */
1072                 } else if ( strcasecmp( cargv[0], "disallows" ) == 0 ||
1073                         strcasecmp( cargv[0], "disallow" ) == 0 )
1074                 {
1075                         slap_mask_t     disallows = 0; 
1076
1077                         if ( be != NULL ) {
1078                                 Debug( LDAP_DEBUG_ANY,
1079 "%s: line %d: disallow line must appear prior to database definitions\n",
1080                                     fname, lineno, 0 );
1081
1082                         }
1083
1084                         if ( cargc < 2 ) {
1085                                 Debug( LDAP_DEBUG_ANY,
1086             "%s: line %d: missing feature(s) in \"disallow <features>\" line\n",
1087                                     fname, lineno, 0 );
1088
1089                                 return( 1 );
1090                         }
1091
1092                         for( i=1; i < cargc; i++ ) {
1093                                 if( strcasecmp( cargv[i], "bind_anon" ) == 0 ) {
1094                                         disallows |= SLAP_DISALLOW_BIND_ANON;
1095
1096                                 } else if( strcasecmp( cargv[i], "bind_simple" ) == 0 ) {
1097                                         disallows |= SLAP_DISALLOW_BIND_SIMPLE;
1098
1099                                 } else if( strcasecmp( cargv[i], "bind_krbv4" ) == 0 ) {
1100                                         disallows |= SLAP_DISALLOW_BIND_KRBV4;
1101
1102                                 } else if( strcasecmp( cargv[i], "tls_2_anon" ) == 0 ) {
1103                                         disallows |= SLAP_DISALLOW_TLS_2_ANON;
1104
1105                                 } else if( strcasecmp( cargv[i], "tls_authc" ) == 0 ) {
1106                                         disallows |= SLAP_DISALLOW_TLS_AUTHC;
1107
1108                                 } else {
1109                                         Debug( LDAP_DEBUG_ANY,
1110                     "%s: line %d: unknown feature %s in \"disallow <features>\" line\n",
1111                                             fname, lineno, cargv[i] );
1112
1113                                         return 1;
1114                                 }
1115                         }
1116
1117                         global_disallows |= disallows;
1118
1119                 /* require these features */
1120                 } else if ( strcasecmp( cargv[0], "requires" ) == 0 ||
1121                         strcasecmp( cargv[0], "require" ) == 0 )
1122                 {
1123                         slap_mask_t     requires = 0; 
1124
1125                         if ( cargc < 2 ) {
1126                                 Debug( LDAP_DEBUG_ANY,
1127             "%s: line %d: missing feature(s) in \"require <features>\" line\n",
1128                                     fname, lineno, 0 );
1129
1130                                 return( 1 );
1131                         }
1132
1133                         for( i=1; i < cargc; i++ ) {
1134                                 if( strcasecmp( cargv[i], "bind" ) == 0 ) {
1135                                         requires |= SLAP_REQUIRE_BIND;
1136
1137                                 } else if( strcasecmp( cargv[i], "LDAPv3" ) == 0 ) {
1138                                         requires |= SLAP_REQUIRE_LDAP_V3;
1139
1140                                 } else if( strcasecmp( cargv[i], "authc" ) == 0 ) {
1141                                         requires |= SLAP_REQUIRE_AUTHC;
1142
1143                                 } else if( strcasecmp( cargv[i], "SASL" ) == 0 ) {
1144                                         requires |= SLAP_REQUIRE_SASL;
1145
1146                                 } else if( strcasecmp( cargv[i], "strong" ) == 0 ) {
1147                                         requires |= SLAP_REQUIRE_STRONG;
1148
1149                                 } else if( strcasecmp( cargv[i], "none" ) != 0 ) {
1150                                         Debug( LDAP_DEBUG_ANY,
1151                     "%s: line %d: unknown feature %s in \"require <features>\" line\n",
1152                                             fname, lineno, cargv[i] );
1153
1154                                         return( 1 );
1155                                 }
1156                         }
1157
1158                         if ( be == NULL ) {
1159                                 frontendDB->be_requires = requires;
1160                         } else {
1161                                 be->be_requires = requires;
1162                         }
1163
1164                 } else if ( strcasecmp( cargv[0], "security" ) == 0 ) {
1165                         slap_ssf_set_t *set;
1166
1167                         if ( cargc < 2 ) {
1168                                 Debug( LDAP_DEBUG_ANY,
1169             "%s: line %d: missing factor(s) in \"security <factors>\" line\n",
1170                                     fname, lineno, 0 );
1171
1172                                 return( 1 );
1173                         }
1174
1175                         if ( be == NULL ) {
1176                                 set = &frontendDB->be_ssf_set;
1177                         } else {
1178                                 set = &be->be_ssf_set;
1179                         }
1180
1181                         for( i=1; i < cargc; i++ ) {
1182                                 slap_ssf_t      *tgt;
1183                                 char            *src;
1184
1185                                 if ( strncasecmp( cargv[i], "ssf=",
1186                                                 STRLENOF("ssf=") ) == 0 )
1187                                 {
1188                                         tgt = &set->sss_ssf;
1189                                         src = &cargv[i][STRLENOF("ssf=")];
1190
1191                                 } else if ( strncasecmp( cargv[i], "transport=",
1192                                                 STRLENOF("transport=") ) == 0 )
1193                                 {
1194                                         tgt = &set->sss_transport;
1195                                         src = &cargv[i][STRLENOF("transport=")];
1196
1197                                 } else if ( strncasecmp( cargv[i], "tls=",
1198                                                 STRLENOF("tls=") ) == 0 )
1199                                 {
1200                                         tgt = &set->sss_tls;
1201                                         src = &cargv[i][STRLENOF("tls=")];
1202
1203                                 } else if ( strncasecmp( cargv[i], "sasl=",
1204                                                 STRLENOF("sasl=") ) == 0 )
1205                                 {
1206                                         tgt = &set->sss_sasl;
1207                                         src = &cargv[i][STRLENOF("sasl=")];
1208
1209                                 } else if ( strncasecmp( cargv[i], "update_ssf=",
1210                                                 STRLENOF("update_ssf=") ) == 0 )
1211                                 {
1212                                         tgt = &set->sss_update_ssf;
1213                                         src = &cargv[i][STRLENOF("update_ssf=")];
1214
1215                                 } else if ( strncasecmp( cargv[i], "update_transport=",
1216                                                 STRLENOF("update_transport=") ) == 0 )
1217                                 {
1218                                         tgt = &set->sss_update_transport;
1219                                         src = &cargv[i][STRLENOF("update_transport=")];
1220
1221                                 } else if ( strncasecmp( cargv[i], "update_tls=",
1222                                                 STRLENOF("update_tls=") ) == 0 )
1223                                 {
1224                                         tgt = &set->sss_update_tls;
1225                                         src = &cargv[i][STRLENOF("update_tls=")];
1226
1227                                 } else if ( strncasecmp( cargv[i], "update_sasl=",
1228                                                 STRLENOF("update_sasl=") ) == 0 )
1229                                 {
1230                                         tgt = &set->sss_update_sasl;
1231                                         src = &cargv[i][STRLENOF("update_sasl=")];
1232
1233                                 } else if ( strncasecmp( cargv[i], "simple_bind=",
1234                                                 STRLENOF("simple_bind=") ) == 0 )
1235                                 {
1236                                         tgt = &set->sss_simple_bind;
1237                                         src = &cargv[i][STRLENOF("simple_bind=")];
1238
1239                                 } else {
1240                                         Debug( LDAP_DEBUG_ANY,
1241                     "%s: line %d: unknown factor %s in \"security <factors>\" line\n",
1242                                             fname, lineno, cargv[i] );
1243
1244                                         return( 1 );
1245                                 }
1246
1247                                 *tgt = strtol( src, &next, 10 );
1248                                 if ( next == NULL || next[0] != '\0' ) {
1249                                         Debug( LDAP_DEBUG_ANY,
1250                     "%s: line %d: unable to parse factor \"%s\" in \"security <factors>\" line\n",
1251                                             fname, lineno, cargv[i] );
1252
1253                                         return( 1 );
1254                                 }
1255                         }
1256
1257                 /* where to send clients when we don't hold it */
1258                 } else if ( strcasecmp( cargv[0], "referral" ) == 0 ) {
1259                         if ( cargc < 2 ) {
1260                                 Debug( LDAP_DEBUG_ANY,
1261                     "%s: line %d: missing URL in \"referral <URL>\" line\n",
1262                                     fname, lineno, 0 );
1263
1264                                 return( 1 );
1265                         }
1266
1267                         if( validate_global_referral( cargv[1] ) ) {
1268                                 Debug( LDAP_DEBUG_ANY, "%s: line %d: "
1269                                         "invalid URL (%s) in \"referral\" line.\n",
1270                                     fname, lineno, cargv[1] );
1271                                 return 1;
1272                         }
1273
1274                         vals[0].bv_val = cargv[1];
1275                         vals[0].bv_len = strlen( vals[0].bv_val );
1276                         if( value_add( &default_referral, vals ) )
1277                                 return LDAP_OTHER;
1278
1279                 /* start of a new database definition */
1280                 } else if ( strcasecmp( cargv[0], "debug" ) == 0 ) {
1281                         int level;
1282                         if ( cargc < 3 ) {
1283                                 Debug( LDAP_DEBUG_ANY,
1284                                         "%s: line %d: Error in debug directive, \"debug subsys level\"\n",
1285                                         fname, lineno, 0 );
1286                                 return( 1 );
1287                         }
1288                         level = strtol( cargv[2], &next, 10 );
1289                         if ( next == NULL || next[0] != '\0' ){
1290                                 Debug( LDAP_DEBUG_ANY,
1291                                            "%s: line %d: unable to parse level \"%s\" in debug directive, "
1292                                            "\"debug <subsys> <level>\"\n", fname, lineno , cargv[2] );
1293                                 return( 1 );
1294                         }
1295
1296                         if ( level <= 0 ) level = lutil_mnem2level( cargv[2] );
1297                         lutil_set_debug_level( cargv[1], level );
1298                 /* specify an Object Identifier macro */
1299                 } else if ( strcasecmp( cargv[0], "objectidentifier" ) == 0 ) {
1300                         rc = parse_oidm( fname, lineno, cargc, cargv );
1301                         if( rc ) return rc;
1302
1303                 /* specify an objectclass */
1304                 } else if ( strcasecmp( cargv[0], "objectclass" ) == 0 ) {
1305                         if ( cargc < 2 ) {
1306                                 Debug( LDAP_DEBUG_ANY,
1307                                        "%s: line %d: illegal objectclass format.\n",
1308                                        fname, lineno, 0 );
1309                                 return( 1 );
1310
1311                         } else if ( *cargv[1] == '('  /*')'*/) {
1312                                 char * p;
1313                                 p = strchr(saveline,'(' /*')'*/);
1314                                 rc = parse_oc( fname, lineno, p, cargv );
1315                                 if( rc ) return rc;
1316
1317                         } else {
1318                                 Debug( LDAP_DEBUG_ANY,
1319                                        "%s: line %d: old objectclass format not supported.\n",
1320                                        fname, lineno, 0 );
1321                         }
1322
1323                 } else if ( strcasecmp( cargv[0], "ditcontentrule" ) == 0 ) {
1324                         char * p;
1325                         p = strchr(saveline,'(' /*')'*/);
1326                         rc = parse_cr( fname, lineno, p, cargv );
1327                         if( rc ) return rc;
1328
1329                 /* specify an attribute type */
1330                 } else if (( strcasecmp( cargv[0], "attributetype" ) == 0 )
1331                         || ( strcasecmp( cargv[0], "attribute" ) == 0 ))
1332                 {
1333                         if ( cargc < 2 ) {
1334                                 Debug( LDAP_DEBUG_ANY, "%s: line %d: "
1335                                         "illegal attribute type format.\n",
1336                                         fname, lineno, 0 );
1337                                 return( 1 );
1338
1339                         } else if ( *cargv[1] == '(' /*')'*/) {
1340                                 char * p;
1341                                 p = strchr(saveline,'(' /*')'*/);
1342                                 rc = parse_at( fname, lineno, p, cargv );
1343                                 if( rc ) return rc;
1344
1345                         } else {
1346                                 Debug( LDAP_DEBUG_ANY,
1347     "%s: line %d: old attribute type format not supported.\n",
1348                                     fname, lineno, 0 );
1349
1350                         }
1351
1352                 /* define attribute option(s) */
1353                 } else if ( strcasecmp( cargv[0], "attributeoptions" ) == 0 ) {
1354                         ad_define_option( NULL, NULL, 0 );
1355                         for ( i = 1; i < cargc; i++ )
1356                                 if ( ad_define_option( cargv[i], fname, lineno ) != 0 )
1357                                         return 1;
1358
1359                 /* turn on/off schema checking */
1360                 } else if ( strcasecmp( cargv[0], "schemacheck" ) == 0 ) {
1361                         if ( cargc < 2 ) {
1362                                 Debug( LDAP_DEBUG_ANY,
1363     "%s: line %d: missing on|off in \"schemacheck <on|off>\" line\n",
1364                                     fname, lineno, 0 );
1365
1366                                 return( 1 );
1367                         }
1368                         if ( strcasecmp( cargv[1], "off" ) == 0 ) {
1369                                 Debug( LDAP_DEBUG_ANY,
1370                                         "%s: line %d: schema checking disabled! your mileage may vary!\n",
1371                                     fname, lineno, 0 );
1372                                 global_schemacheck = 0;
1373                         } else {
1374                                 global_schemacheck = 1;
1375                         }
1376
1377                 /* specify access control info */
1378                 } else if ( strcasecmp( cargv[0], "access" ) == 0 ) {
1379                         parse_acl( be, fname, lineno, cargc, cargv );
1380
1381                 /* debug level to log things to syslog */
1382                 } else if ( strcasecmp( cargv[0], "loglevel" ) == 0 ) {
1383                         if ( cargc < 2 ) {
1384                                 Debug( LDAP_DEBUG_ANY,
1385                     "%s: line %d: missing level(s) in \"loglevel <level> [...]\" line\n",
1386                                     fname, lineno, 0 );
1387
1388                                 return( 1 );
1389                         }
1390
1391                         ldap_syslog = 0;
1392
1393                         for( i=1; i < cargc; i++ ) {
1394                                 int     level;
1395
1396                                 if ( isdigit( cargv[i][0] ) ) {
1397                                         level = strtol( cargv[i], &next, 10 );
1398                                         if ( next == NULL || next[0] != '\0' ) {
1399                                                 Debug( LDAP_DEBUG_ANY,
1400                                                         "%s: line %d: unable to parse level \"%s\" "
1401                                                         "in \"loglevel <level> [...]\" line.\n",
1402                                                         fname, lineno , cargv[i] );
1403                                                 return( 1 );
1404                                         }
1405                                         
1406                                 } else {
1407                                         static struct {
1408                                                 int     i;
1409                                                 char    *s;
1410                                         } int_2_level[] = {
1411                                                 { LDAP_DEBUG_TRACE,     "Trace"         },
1412                                                 { LDAP_DEBUG_PACKETS,   "Packets"       },
1413                                                 { LDAP_DEBUG_ARGS,      "Args"          },
1414                                                 { LDAP_DEBUG_CONNS,     "Conns"         },
1415                                                 { LDAP_DEBUG_BER,       "BER"           },
1416                                                 { LDAP_DEBUG_FILTER,    "Filter"        },
1417                                                 { LDAP_DEBUG_CONFIG,    "Config"        },
1418                                                 { LDAP_DEBUG_ACL,       "ACL"           },
1419                                                 { LDAP_DEBUG_STATS,     "Stats"         },
1420                                                 { LDAP_DEBUG_STATS2,    "Stats2"        },
1421                                                 { LDAP_DEBUG_SHELL,     "Shell"         },
1422                                                 { LDAP_DEBUG_PARSE,     "Parse"         },
1423                                                 { LDAP_DEBUG_CACHE,     "Cache"         },
1424                                                 { LDAP_DEBUG_INDEX,     "Index"         },
1425                                                 { -1,                   "Any"           },
1426                                                 { 0,                    NULL            }
1427                                         };
1428                                         int     j;
1429
1430                                         for ( j = 0; int_2_level[j].s; j++ ) {
1431                                                 if ( strcasecmp( cargv[i], int_2_level[j].s ) == 0 ) {
1432                                                         level = int_2_level[j].i;
1433                                                         break;
1434                                                 }
1435                                         }
1436
1437                                         if ( int_2_level[j].s == NULL ) {
1438                                                 Debug( LDAP_DEBUG_ANY,
1439                                                         "%s: line %d: unknown level \"%s\" "
1440                                                         "in \"loglevel <level> [...]\" line.\n",
1441                                                         fname, lineno , cargv[i] );
1442                                                 return( 1 );
1443                                         }
1444                                 }
1445
1446                                 ldap_syslog |= level;
1447                         }
1448
1449                 /* list of sync replication information in this backend (slave only) */
1450                 } else if ( strcasecmp( cargv[0], "syncrepl" ) == 0 ) {
1451
1452                         if ( be == NULL ) {
1453                                 Debug( LDAP_DEBUG_ANY,
1454                                             "%s: line %d: syncrepl line must appear inside "
1455                                             "a database definition.\n", fname, lineno, 0);
1456                                 return 1;
1457
1458                         } else if ( SLAP_SHADOW( be )) {
1459                                 Debug( LDAP_DEBUG_ANY,
1460                                         "%s: line %d: syncrepl: database already shadowed.\n",
1461                                         fname, lineno, 0);
1462                                 return 1;
1463
1464                         } else if ( add_syncrepl( be, cargv, cargc )) {
1465                                 return 1;
1466                         }
1467
1468                         SLAP_DBFLAGS(be) |= ( SLAP_DBFLAG_SHADOW | SLAP_DBFLAG_SYNC_SHADOW );
1469
1470                 /* list of replicas of the data in this backend (master only) */
1471                 } else if ( strcasecmp( cargv[0], "replica" ) == 0 ) {
1472                         if ( cargc < 2 ) {
1473                                 Debug( LDAP_DEBUG_ANY,
1474             "%s: line %d: missing host or uri in \"replica <host[:port]>\" line\n",
1475                                     fname, lineno, 0 );
1476
1477                                 return( 1 );
1478                         }
1479                         if ( be == NULL ) {
1480                                 Debug( LDAP_DEBUG_ANY,
1481 "%s: line %d: replica line must appear inside a database definition\n",
1482                                     fname, lineno, 0 );
1483                                 return 1;
1484
1485                         } else {
1486                                 int nr = -1;
1487
1488                                 for ( i = 1; i < cargc; i++ ) {
1489                                         if ( strncasecmp( cargv[i], "host=", 5 )
1490                                             == 0 ) {
1491                                                 nr = add_replica_info( be, 
1492                                                         cargv[i] + 5 );
1493                                                 break;
1494                                         } else if (strncasecmp( cargv[i], "uri=", 4 )
1495                                             == 0 ) {
1496                                             if ( ldap_url_parse( cargv[ i ] + 4, &ludp )
1497                                                 != LDAP_SUCCESS ) {
1498                                                         Debug( LDAP_DEBUG_ANY,
1499                                                         "%s: line %d: replica line contains invalid "
1500                                                         "uri definition.\n", fname, lineno, 0);
1501                                                         return 1;
1502                                                 }
1503                                                 if (ludp->lud_host == NULL ) {
1504                                                         Debug( LDAP_DEBUG_ANY,
1505                                                         "%s: line %d: replica line contains invalid "
1506                                                         "uri definition - missing hostname.\n", fname, lineno, 0);
1507                                                         return 1;
1508                                                 }
1509                                         replicahost = ch_malloc( strlen( cargv[ i ] ) );
1510                                                 if ( replicahost == NULL ) {
1511                                                         Debug( LDAP_DEBUG_ANY, 
1512                                                         "out of memory in read_config\n", 0, 0, 0 );
1513                                                         ldap_free_urldesc( ludp );                              
1514                                                         exit( EXIT_FAILURE );
1515                                                 }
1516                                                 sprintf(replicahost, "%s:%d", 
1517                                                         ludp->lud_host, ludp->lud_port);
1518                                                 nr = add_replica_info( be, replicahost );
1519                                                 ldap_free_urldesc( ludp );                              
1520                                                 ch_free(replicahost);
1521                                                 break;
1522                                         }
1523                                 }
1524                                 if ( i == cargc ) {
1525                                         Debug( LDAP_DEBUG_ANY,
1526                     "%s: line %d: missing host or uri in \"replica\" line\n",
1527                                             fname, lineno, 0 );
1528                                         return 1;
1529
1530                                 } else if ( nr == -1 ) {
1531                                         Debug( LDAP_DEBUG_ANY,
1532                 "%s: line %d: unable to add replica \"%s\"\n",
1533                                                 fname, lineno, cargv[i] + 5 );
1534                                         return 1;
1535                                 } else {
1536                                         for ( i = 1; i < cargc; i++ ) {
1537                                                 if ( strncasecmp( cargv[i], "suffix=", 7 ) == 0 ) {
1538
1539                                                         switch ( add_replica_suffix( be, nr, cargv[i] + 7 ) ) {
1540                                                         case 1:
1541                                                                 Debug( LDAP_DEBUG_ANY,
1542                                                                                 "%s: line %d: suffix \"%s\" in \"replica\" line is not valid for backend (ignored)\n",
1543                                                                                 fname, lineno, cargv[i] + 7 );
1544                                                                 break;
1545
1546                                                         case 2:
1547                                                                 Debug( LDAP_DEBUG_ANY,
1548                                                                                  "%s: line %d: unable to normalize suffix in \"replica\" line (ignored)\n",
1549                                                                                  fname, lineno, 0 );
1550                                                                 break;
1551                                                         }
1552
1553                                                 } else if ( strncasecmp( cargv[i], "attr", 4 ) == 0 ) {
1554                                                         int exclude = 0;
1555                                                         char *arg = cargv[i] + 4;
1556
1557                                                         if ( arg[0] == '!' ) {
1558                                                                 arg++;
1559                                                                 exclude = 1;
1560                                                         }
1561
1562                                                         if ( arg[0] != '=' ) {
1563                                                                 continue;
1564                                                         }
1565
1566                                                         if ( add_replica_attrs( be, nr, arg + 1, exclude ) ) {
1567                                                                 Debug( LDAP_DEBUG_ANY,
1568                                                                                 "%s: line %d: attribute \"%s\" in \"replica\" line is unknown\n",
1569                                                                                 fname, lineno, arg + 1 );
1570                                                                 return( 1 );
1571                                                         }
1572                                                 }
1573                                         }
1574                                 }
1575                         }
1576
1577                 } else if ( strcasecmp( cargv[0], "replicationInterval" ) == 0 ) {
1578                         /* ignore */
1579
1580                 /* dn of slave entity allowed to write to replica */
1581                 } else if ( strcasecmp( cargv[0], "updatedn" ) == 0 ) {
1582                         if ( cargc < 2 ) {
1583                                 Debug( LDAP_DEBUG_ANY,
1584                     "%s: line %d: missing dn in \"updatedn <dn>\" line\n",
1585                                     fname, lineno, 0 );
1586
1587                                 return( 1 );
1588                         }
1589                         if ( be == NULL ) {
1590                                 Debug( LDAP_DEBUG_ANY,
1591 "%s: line %d: updatedn line must appear inside a database definition\n",
1592                                     fname, lineno, 0 );
1593                                 return 1;
1594
1595                         } else if ( SLAP_SHADOW(be) ) {
1596                                 Debug( LDAP_DEBUG_ANY,
1597                                         "%s: line %d: updatedn: database already shadowed.\n",
1598                                         fname, lineno, 0);
1599                                 return 1;
1600
1601                         } else {
1602                                 struct berval dn;
1603
1604                                 if ( load_ucdata( NULL ) < 0 ) return 1;
1605
1606                                 dn.bv_val = cargv[1];
1607                                 dn.bv_len = strlen( cargv[1] );
1608
1609                                 rc = dnNormalize( 0, NULL, NULL, &dn, &be->be_update_ndn, NULL );
1610                                 if( rc != LDAP_SUCCESS ) {
1611                                         Debug( LDAP_DEBUG_ANY,
1612                                                 "%s: line %d: updatedn DN is invalid\n",
1613                                             fname, lineno, 0 );
1614                                         return 1;
1615                                 }
1616
1617                         }
1618                         SLAP_DBFLAGS(be) |= ( SLAP_DBFLAG_SHADOW | SLAP_DBFLAG_SLURP_SHADOW );
1619
1620                 } else if ( strcasecmp( cargv[0], "updateref" ) == 0 ) {
1621                         if ( cargc < 2 ) {
1622                                 Debug( LDAP_DEBUG_ANY, "%s: line %d: "
1623                                         "missing url in \"updateref <ldapurl>\" line\n",
1624                                     fname, lineno, 0 );
1625
1626                                 return( 1 );
1627                         }
1628                         if ( be == NULL ) {
1629                                 Debug( LDAP_DEBUG_ANY, "%s: line %d: updateref"
1630                                         " line must appear inside a database definition\n",
1631                                         fname, lineno, 0 );
1632                                 return 1;
1633
1634                         } else if ( !SLAP_SHADOW(be) ) {
1635                                 Debug( LDAP_DEBUG_ANY, "%s: line %d: "
1636                                         "updateref line must after syncrepl or updatedn.\n",
1637                                     fname, lineno, 0 );
1638                                 return 1;
1639                         }
1640
1641                         if( validate_global_referral( cargv[1] ) ) {
1642                                 Debug( LDAP_DEBUG_ANY, "%s: line %d: "
1643                                         "invalid URL (%s) in \"updateref\" line.\n",
1644                                     fname, lineno, cargv[1] );
1645                                 return 1;
1646                         }
1647
1648                         vals[0].bv_val = cargv[1];
1649                         vals[0].bv_len = strlen( vals[0].bv_val );
1650                         if( value_add( &be->be_update_refs, vals ) ) {
1651                                 return LDAP_OTHER;
1652                         }
1653
1654                 /* replication log file to which changes are appended */
1655                 } else if ( strcasecmp( cargv[0], "replogfile" ) == 0 ) {
1656                         if ( cargc < 2 ) {
1657                                 Debug( LDAP_DEBUG_ANY,
1658             "%s: line %d: missing filename in \"replogfile <filename>\" line\n",
1659                                     fname, lineno, 0 );
1660
1661                                 return( 1 );
1662                         }
1663                         if ( be ) {
1664                                 be->be_replogfile = ch_strdup( cargv[1] );
1665                         } else {
1666                                 replogfile = ch_strdup( cargv[1] );
1667                         }
1668
1669                 /* file from which to read additional rootdse attrs */
1670                 } else if ( strcasecmp( cargv[0], "rootDSE" ) == 0) {
1671                         if ( cargc < 2 ) {
1672                                 Debug( LDAP_DEBUG_ANY, "%s: line %d: "
1673                                         "missing filename in \"rootDSE <filename>\" line.\n",
1674                                     fname, lineno, 0 );
1675                                 return 1;
1676                         }
1677
1678                         if( read_root_dse_file( cargv[1] ) ) {
1679                                 Debug( LDAP_DEBUG_ANY, "%s: line %d: "
1680                                         "could not read \"rootDSE <filename>\" line\n",
1681                                     fname, lineno, 0 );
1682                                 return 1;
1683                         }
1684
1685                 /* maintain lastmodified{by,time} attributes */
1686                 } else if ( strcasecmp( cargv[0], "lastmod" ) == 0 ) {
1687                         if ( cargc < 2 ) {
1688                                 Debug( LDAP_DEBUG_ANY,
1689             "%s: line %d: missing on|off in \"lastmod <on|off>\" line\n",
1690                                     fname, lineno, 0 );
1691
1692                                 return( 1 );
1693                         }
1694
1695                         if ( be == NULL ) {
1696                                 Debug( LDAP_DEBUG_ANY, "%s: line %d: lastmod"
1697                                         " line must appear inside a database definition\n",
1698                                         fname, lineno, 0 );
1699                                 return 1;
1700
1701                         } else if ( SLAP_NOLASTMODCMD(be) ) {
1702                                 Debug( LDAP_DEBUG_ANY, "%s: line %d: lastmod"
1703                                         " not available for %s databases\n",
1704                                         fname, lineno, be->bd_info->bi_type );
1705                                 return 1;
1706                         }
1707
1708                         if ( strcasecmp( cargv[1], "on" ) == 0 ) {
1709                                 SLAP_DBFLAGS(be) &= ~SLAP_DBFLAG_NOLASTMOD;
1710                         } else {
1711                                 SLAP_DBFLAGS(be) |= SLAP_DBFLAG_NOLASTMOD;
1712                         }
1713
1714 #ifdef SIGHUP
1715                 /* turn on/off gentle SIGHUP handling */
1716                 } else if ( strcasecmp( cargv[0], "gentlehup" ) == 0 ) {
1717                         if ( cargc < 2 ) {
1718                                 Debug( LDAP_DEBUG_ANY,
1719     "%s: line %d: missing on|off in \"gentlehup <on|off>\" line\n",
1720                                     fname, lineno, 0 );
1721                                 return( 1 );
1722                         }
1723                         if ( strcasecmp( cargv[1], "off" ) == 0 ) {
1724                                 global_gentlehup = 0;
1725                         } else {
1726                                 global_gentlehup = 1;
1727                         }
1728 #endif
1729
1730                 /* set idle timeout value */
1731                 } else if ( strcasecmp( cargv[0], "idletimeout" ) == 0 ) {
1732                         int i;
1733                         if ( cargc < 2 ) {
1734                                 Debug( LDAP_DEBUG_ANY,
1735             "%s: line %d: missing timeout value in \"idletimeout <seconds>\" line\n",
1736                                     fname, lineno, 0 );
1737
1738                                 return( 1 );
1739                         }
1740
1741                         i = atoi( cargv[1] );
1742
1743                         if( i < 0 ) {
1744                                 Debug( LDAP_DEBUG_ANY,
1745             "%s: line %d: timeout value (%d) invalid \"idletimeout <seconds>\" line\n",
1746                                     fname, lineno, i );
1747
1748                                 return( 1 );
1749                         }
1750
1751                         global_idletimeout = i;
1752
1753                 /* include another config file */
1754                 } else if ( strcasecmp( cargv[0], "include" ) == 0 ) {
1755                         if ( cargc < 2 ) {
1756                                 Debug( LDAP_DEBUG_ANY,
1757     "%s: line %d: missing filename in \"include <filename>\" line\n",
1758                                     fname, lineno, 0 );
1759
1760                                 return( 1 );
1761                         }
1762                         savefname = ch_strdup( cargv[1] );
1763                         savelineno = lineno;
1764
1765                         if ( read_config( savefname, depth+1 ) != 0 ) {
1766                                 return( 1 );
1767                         }
1768
1769                         free( savefname );
1770                         lineno = savelineno - 1;
1771
1772                 /* location of kerberos srvtab file */
1773                 } else if ( strcasecmp( cargv[0], "srvtab" ) == 0 ) {
1774                         if ( cargc < 2 ) {
1775                                 Debug( LDAP_DEBUG_ANY,
1776             "%s: line %d: missing filename in \"srvtab <filename>\" line\n",
1777                                     fname, lineno, 0 );
1778
1779                                 return( 1 );
1780                         }
1781                         ldap_srvtab = ch_strdup( cargv[1] );
1782
1783 #ifdef SLAPD_MODULES
1784                 } else if (strcasecmp( cargv[0], "moduleload") == 0 ) {
1785                    if ( cargc < 2 ) {
1786                       Debug( LDAP_DEBUG_ANY,
1787                              "%s: line %d: missing filename in \"moduleload <filename>\" line\n",
1788                              fname, lineno, 0 );
1789
1790                       exit( EXIT_FAILURE );
1791                    }
1792                    if (module_load(cargv[1], cargc - 2, (cargc > 2) ? cargv + 2 : NULL)) {
1793                       Debug( LDAP_DEBUG_ANY,
1794                              "%s: line %d: failed to load or initialize module %s\n",
1795                              fname, lineno, cargv[1]);
1796
1797                       exit( EXIT_FAILURE );
1798                    }
1799                 } else if (strcasecmp( cargv[0], "modulepath") == 0 ) {
1800                    if ( cargc != 2 ) {
1801                       Debug( LDAP_DEBUG_ANY,
1802                              "%s: line %d: missing path in \"modulepath <path>\" line\n",
1803                              fname, lineno, 0 );
1804
1805                       exit( EXIT_FAILURE );
1806                    }
1807                    if (module_path( cargv[1] )) {
1808                            Debug( LDAP_DEBUG_ANY,
1809                                   "%s: line %d: failed to set module search path to %s\n",
1810                                   fname, lineno, cargv[1]);
1811
1812                       exit( EXIT_FAILURE );
1813                    }
1814                    
1815 #endif /*SLAPD_MODULES*/
1816
1817 #ifdef HAVE_TLS
1818                 } else if ( !strcasecmp( cargv[0], "TLSRandFile" ) ) {
1819                         rc = ldap_pvt_tls_set_option( NULL,
1820                                                       LDAP_OPT_X_TLS_RANDOM_FILE,
1821                                                       cargv[1] );
1822                         if ( rc )
1823                                 return rc;
1824
1825                 } else if ( !strcasecmp( cargv[0], "TLSCipherSuite" ) ) {
1826                         rc = ldap_pvt_tls_set_option( NULL,
1827                                                       LDAP_OPT_X_TLS_CIPHER_SUITE,
1828                                                       cargv[1] );
1829                         if ( rc )
1830                                 return rc;
1831
1832                 } else if ( !strcasecmp( cargv[0], "TLSCertificateFile" ) ) {
1833                         rc = ldap_pvt_tls_set_option( NULL,
1834                                                       LDAP_OPT_X_TLS_CERTFILE,
1835                                                       cargv[1] );
1836                         if ( rc )
1837                                 return rc;
1838
1839                 } else if ( !strcasecmp( cargv[0], "TLSCertificateKeyFile" ) ) {
1840                         rc = ldap_pvt_tls_set_option( NULL,
1841                                                       LDAP_OPT_X_TLS_KEYFILE,
1842                                                       cargv[1] );
1843                         if ( rc )
1844                                 return rc;
1845
1846                 } else if ( !strcasecmp( cargv[0], "TLSCACertificatePath" ) ) {
1847                         rc = ldap_pvt_tls_set_option( NULL,
1848                                                       LDAP_OPT_X_TLS_CACERTDIR,
1849                                                       cargv[1] );
1850                         if ( rc )
1851                                 return rc;
1852
1853                 } else if ( !strcasecmp( cargv[0], "TLSCACertificateFile" ) ) {
1854                         rc = ldap_pvt_tls_set_option( NULL,
1855                                                       LDAP_OPT_X_TLS_CACERTFILE,
1856                                                       cargv[1] );
1857                         if ( rc )
1858                                 return rc;
1859                 } else if ( !strcasecmp( cargv[0], "TLSVerifyClient" ) ) {
1860                         if ( isdigit( (unsigned char) cargv[1][0] ) ) {
1861                                 i = atoi(cargv[1]);
1862                                 rc = ldap_pvt_tls_set_option( NULL,
1863                                                       LDAP_OPT_X_TLS_REQUIRE_CERT,
1864                                                       &i );
1865                         } else {
1866                                 rc = ldap_int_tls_config( NULL,
1867                                                       LDAP_OPT_X_TLS_REQUIRE_CERT,
1868                                                       cargv[1] );
1869                         }
1870
1871                         if ( rc )
1872                                 return rc;
1873
1874 #endif
1875
1876                 } else if ( !strcasecmp( cargv[0], "reverse-lookup" ) ) {
1877 #ifdef SLAPD_RLOOKUPS
1878                         if ( cargc < 2 ) {
1879                                 Debug( LDAP_DEBUG_ANY,
1880 "%s: line %d: reverse-lookup: missing \"on\" or \"off\"\n",
1881                                         fname, lineno, 0 );
1882                                 return( 1 );
1883                         }
1884
1885                         if ( !strcasecmp( cargv[1], "on" ) ) {
1886                                 use_reverse_lookup = 1;
1887                         } else if ( !strcasecmp( cargv[1], "off" ) ) {
1888                                 use_reverse_lookup = 0;
1889                         } else {
1890                                 Debug( LDAP_DEBUG_ANY,
1891 "%s: line %d: reverse-lookup: must be \"on\" (default) or \"off\"\n",
1892                                         fname, lineno, 0 );
1893                                 return( 1 );
1894                         }
1895
1896 #else /* !SLAPD_RLOOKUPS */
1897                         Debug( LDAP_DEBUG_ANY,
1898 "%s: line %d: reverse lookups are not configured (ignored).\n",
1899                                 fname, lineno, 0 );
1900 #endif /* !SLAPD_RLOOKUPS */
1901
1902                 /* Netscape plugins */
1903                 } else if ( strcasecmp( cargv[0], "plugin" ) == 0 ) {
1904 #if defined( LDAP_SLAPI )
1905
1906 #ifdef notdef /* allow global plugins, too */
1907                         /*
1908                          * a "plugin" line must be inside a database
1909                          * definition, since we implement pre-,post- 
1910                          * and extended operation plugins
1911                          */
1912                         if ( be == NULL ) {
1913                                 Debug( LDAP_DEBUG_ANY, "%s: line %d: plugin "
1914                                     "line must appear inside a database "
1915                                     "definition\n", fname, lineno, 0 );
1916                                 return( 1 );
1917                         }
1918 #endif /* notdef */
1919
1920                         if ( slapi_int_read_config( be, fname, lineno, cargc, cargv ) 
1921                                         != LDAP_SUCCESS )
1922                         {
1923                                 Debug( LDAP_DEBUG_ANY, "%s: line %d: SLAPI "
1924                                                 "config read failed.\n", fname, lineno, 0 );
1925                                 return( 1 );
1926                         }
1927                         slapi_plugins_used++;
1928
1929 #else /* !defined( LDAP_SLAPI ) */
1930                         Debug( LDAP_DEBUG_ANY, "%s: line %d: SLAPI "
1931                             "not supported.\n", fname, lineno, 0 );
1932                         return( 1 );
1933                         
1934 #endif /* !defined( LDAP_SLAPI ) */
1935
1936                 /* Netscape plugins */
1937                 } else if ( strcasecmp( cargv[0], "pluginlog" ) == 0 ) {
1938 #if defined( LDAP_SLAPI )
1939                         if ( cargc < 2 ) {
1940                                 Debug( LDAP_DEBUG_ANY, 
1941                                         "%s: line %d: missing file name "
1942                                         "in pluginlog <filename> line.\n",
1943                                         fname, lineno, 0 );
1944                                 return( 1 );
1945                         }
1946
1947                         if ( slapi_log_file != NULL ) {
1948                                 ch_free( slapi_log_file );
1949                         }
1950
1951                         slapi_log_file = ch_strdup( cargv[1] );
1952 #endif /* !defined( LDAP_SLAPI ) */
1953
1954                 /* pass anything else to the current backend info/db config routine */
1955                 } else {
1956                         if ( bi != NULL ) {
1957                                 if ( bi->bi_config ) {
1958                                         rc = (*bi->bi_config)( bi, fname, lineno, cargc, cargv );
1959
1960                                         switch ( rc ) {
1961                                         case 0:
1962                                                 break;
1963
1964                                         case SLAP_CONF_UNKNOWN:
1965                                                 Debug( LDAP_DEBUG_ANY,
1966 "%s: line %d: unknown directive \"%s\" inside backend info definition (ignored)\n",
1967                                                         fname, lineno, cargv[0] );
1968                                                 break;
1969
1970                                         default:
1971                                                 return 1;
1972                                         }
1973                                 }
1974
1975                         } else if ( be != NULL ) {
1976                                 if ( be->be_config ) {
1977                                         rc = (*be->be_config)( be, fname, lineno, cargc, cargv );
1978
1979                                         switch ( rc ) {
1980                                         case 0:
1981                                                 break;
1982
1983                                         case SLAP_CONF_UNKNOWN:
1984                                                 Debug( LDAP_DEBUG_ANY,
1985 "%s: line %d: unknown directive \"%s\" inside backend database definition (ignored)\n",
1986                                                         fname, lineno, cargv[0] );
1987                                                 break;
1988
1989                                         default:
1990                                                 return 1;
1991                                         }
1992                                 }
1993
1994                         } else {
1995                                 if ( frontendDB->be_config ) {
1996                                         rc = (*frontendDB->be_config)( frontendDB, fname, lineno, cargc, cargv );
1997
1998                                         switch ( rc ) {
1999                                         case 0:
2000                                                 break;
2001
2002                                         case SLAP_CONF_UNKNOWN:
2003                                                 Debug( LDAP_DEBUG_ANY,
2004 "%s: line %d: unknown directive \"%s\" inside global database definition (ignored)\n",
2005                                                         fname, lineno, cargv[0] );
2006                                                 break;
2007
2008                                         default:
2009                                                 return 1;
2010                                         }
2011                                 }
2012                         }
2013                 }
2014                 free( saveline );
2015         }
2016         fclose( fp );
2017
2018         if ( depth == 0 ) ch_free( cargv );
2019
2020         if ( BER_BVISNULL( &frontendDB->be_schemadn ) ) {
2021                 ber_str2bv( SLAPD_SCHEMA_DN, sizeof(SLAPD_SCHEMA_DN)-1, 1,
2022                         &frontendDB->be_schemadn );
2023                 dnNormalize( 0, NULL, NULL, &frontendDB->be_schemadn, &frontendDB->be_schemandn, NULL );
2024         }
2025
2026         if ( load_ucdata( NULL ) < 0 ) return 1;
2027         return( 0 );
2028 }
2029
2030 static int
2031 fp_parse_line(
2032     int         lineno,
2033     char        *line
2034 )
2035 {
2036         char *  token;
2037         char *  logline;
2038         char    logbuf[sizeof("pseudorootpw ***")];
2039
2040         cargc = 0;
2041         token = strtok_quote( line, " \t" );
2042
2043         logline = line;
2044
2045         if ( token && ( strcasecmp( token, "rootpw" ) == 0 ||
2046                 strcasecmp( token, "replica" ) == 0 ||          /* contains "credentials" */
2047                 strcasecmp( token, "bindpw" ) == 0 ||           /* used in back-ldap */
2048                 strcasecmp( token, "pseudorootpw" ) == 0 ||     /* used in back-meta */
2049                 strcasecmp( token, "dbpasswd" ) == 0 ) )        /* used in back-sql */
2050         {
2051                 snprintf( logline = logbuf, sizeof logbuf, "%s ***", token );
2052         }
2053
2054         if ( strtok_quote_ptr ) {
2055                 *strtok_quote_ptr = ' ';
2056         }
2057
2058         Debug( LDAP_DEBUG_CONFIG, "line %d (%s)\n", lineno, logline, 0 );
2059
2060         if ( strtok_quote_ptr ) {
2061                 *strtok_quote_ptr = '\0';
2062         }
2063
2064         for ( ; token != NULL; token = strtok_quote( NULL, " \t" ) ) {
2065                 if ( cargc == cargv_size - 1 ) {
2066                         char **tmp;
2067                         tmp = ch_realloc( cargv, (cargv_size + ARGS_STEP) *
2068                                             sizeof(*cargv) );
2069                         if ( tmp == NULL ) {
2070                                 Debug( LDAP_DEBUG_ANY, 
2071                                                 "line %d: out of memory\n", 
2072                                                 lineno, 0, 0 );
2073                                 return -1;
2074                         }
2075                         cargv = tmp;
2076                         cargv_size += ARGS_STEP;
2077                 }
2078                 cargv[cargc++] = token;
2079         }
2080         cargv[cargc] = NULL;
2081         return 0;
2082 }
2083
2084 static char *
2085 strtok_quote( char *line, char *sep )
2086 {
2087         int             inquote;
2088         char            *tmp;
2089         static char     *next;
2090
2091         strtok_quote_ptr = NULL;
2092         if ( line != NULL ) {
2093                 next = line;
2094         }
2095         while ( *next && strchr( sep, *next ) ) {
2096                 next++;
2097         }
2098
2099         if ( *next == '\0' ) {
2100                 next = NULL;
2101                 return( NULL );
2102         }
2103         tmp = next;
2104
2105         for ( inquote = 0; *next; ) {
2106                 switch ( *next ) {
2107                 case '"':
2108                         if ( inquote ) {
2109                                 inquote = 0;
2110                         } else {
2111                                 inquote = 1;
2112                         }
2113                         AC_MEMCPY( next, next + 1, strlen( next + 1 ) + 1 );
2114                         break;
2115
2116                 case '\\':
2117                         if ( next[1] )
2118                                 AC_MEMCPY( next,
2119                                             next + 1, strlen( next + 1 ) + 1 );
2120                         next++;         /* dont parse the escaped character */
2121                         break;
2122
2123                 default:
2124                         if ( ! inquote ) {
2125                                 if ( strchr( sep, *next ) != NULL ) {
2126                                         strtok_quote_ptr = next;
2127                                         *next++ = '\0';
2128                                         return( tmp );
2129                                 }
2130                         }
2131                         next++;
2132                         break;
2133                 }
2134         }
2135
2136         return( tmp );
2137 }
2138
2139 static char     buf[BUFSIZ];
2140 static char     *line;
2141 static size_t lmax, lcur;
2142
2143 #define CATLINE( buf ) \
2144         do { \
2145                 size_t len = strlen( buf ); \
2146                 while ( lcur + len + 1 > lmax ) { \
2147                         lmax += BUFSIZ; \
2148                         line = (char *) ch_realloc( line, lmax ); \
2149                 } \
2150                 strcpy( line + lcur, buf ); \
2151                 lcur += len; \
2152         } while( 0 )
2153
2154 static char *
2155 fp_getline( FILE *fp, int *lineno )
2156 {
2157         char            *p;
2158
2159         lcur = 0;
2160         CATLINE( buf );
2161         (*lineno)++;
2162
2163         /* hack attack - keeps us from having to keep a stack of bufs... */
2164         if ( strncasecmp( line, "include", 7 ) == 0 ) {
2165                 buf[0] = '\0';
2166                 return( line );
2167         }
2168
2169         while ( fgets( buf, sizeof(buf), fp ) != NULL ) {
2170                 /* trim off \r\n or \n */
2171                 if ( (p = strchr( buf, '\n' )) != NULL ) {
2172                         if( p > buf && p[-1] == '\r' ) --p;
2173                         *p = '\0';
2174                 }
2175                 
2176                 /* trim off trailing \ and append the next line */
2177                 if ( line[ 0 ] != '\0' 
2178                                 && (p = line + strlen( line ) - 1)[ 0 ] == '\\'
2179                                 && p[ -1 ] != '\\' ) {
2180                         p[ 0 ] = '\0';
2181                         lcur--;
2182
2183                 } else {
2184                         if ( ! isspace( (unsigned char) buf[0] ) ) {
2185                                 return( line );
2186                         }
2187
2188                         /* change leading whitespace to a space */
2189                         buf[0] = ' ';
2190                 }
2191
2192                 CATLINE( buf );
2193                 (*lineno)++;
2194         }
2195         buf[0] = '\0';
2196
2197         return( line[0] ? line : NULL );
2198 }
2199
2200 static void
2201 fp_getline_init( int *lineno )
2202 {
2203         *lineno = -1;
2204         buf[0] = '\0';
2205 }
2206
2207 /* Loads ucdata, returns 1 if loading, 0 if already loaded, -1 on error */
2208 static int
2209 load_ucdata( char *path )
2210 {
2211 #if 0
2212         static int loaded = 0;
2213         int err;
2214         
2215         if ( loaded ) {
2216                 return( 0 );
2217         }
2218         err = ucdata_load( path ? path : SLAPD_DEFAULT_UCDATA, UCDATA_ALL );
2219         if ( err ) {
2220                 Debug( LDAP_DEBUG_ANY, "error loading ucdata (error %d)\n",
2221                        err, 0, 0 );
2222
2223                 return( -1 );
2224         }
2225         loaded = 1;
2226         return( 1 );
2227 #else
2228         /* ucdata is now hardcoded */
2229         return( 0 );
2230 #endif
2231 }
2232
2233 void
2234 config_destroy( )
2235 {
2236         ucdata_unload( UCDATA_ALL );
2237         if ( frontendDB ) {
2238                 /* NOTE: in case of early exit, frontendDB can be NULL */
2239                 if ( frontendDB->be_schemandn.bv_val )
2240                         free( frontendDB->be_schemandn.bv_val );
2241                 if ( frontendDB->be_schemadn.bv_val )
2242                         free( frontendDB->be_schemadn.bv_val );
2243                 if ( frontendDB->be_acl )
2244                         acl_destroy( frontendDB->be_acl, NULL );
2245         }
2246         free( line );
2247         if ( slapd_args_file )
2248                 free ( slapd_args_file );
2249         if ( slapd_pid_file )
2250                 free ( slapd_pid_file );
2251         if ( default_passwd_hash )
2252                 ldap_charray_free( default_passwd_hash );
2253 }
2254
2255 static int
2256 add_syncrepl(
2257         Backend *be,
2258         char    **cargv,
2259         int     cargc
2260 )
2261 {
2262         syncinfo_t *si;
2263         syncinfo_t *si_entry;
2264         int     rc = 0;
2265         int duplicated_replica_id = 0;
2266
2267         si = (syncinfo_t *) ch_calloc( 1, sizeof( syncinfo_t ) );
2268
2269         if ( si == NULL ) {
2270                 Debug( LDAP_DEBUG_ANY, "out of memory in add_syncrepl\n", 0, 0, 0 );
2271                 return 1;
2272         }
2273
2274         si->si_tls = SYNCINFO_TLS_OFF;
2275         if ( be->be_rootndn.bv_val ) {
2276                 ber_dupbv( &si->si_updatedn, &be->be_rootndn );
2277         }
2278         si->si_bindmethod = LDAP_AUTH_SIMPLE;
2279         si->si_schemachecking = 0;
2280         ber_str2bv( "(objectclass=*)", STRLENOF("(objectclass=*)"), 1,
2281                 &si->si_filterstr );
2282         si->si_base.bv_val = NULL;
2283         si->si_scope = LDAP_SCOPE_SUBTREE;
2284         si->si_attrsonly = 0;
2285         si->si_attrs = (char **) ch_calloc( 1, sizeof( char * ));
2286         si->si_attrs[0] = NULL;
2287         si->si_ocs = (ObjectClass **) ch_calloc( 1, sizeof( ObjectClass ));
2288         si->si_ocs[0] = NULL;
2289         si->si_exattrs = (char **) ch_calloc( 1, sizeof( char * ));
2290         si->si_exattrs[0] = NULL;
2291         si->si_type = LDAP_SYNC_REFRESH_ONLY;
2292         si->si_interval = 86400;
2293         si->si_retryinterval = NULL;
2294         si->si_retrynum_init = NULL;
2295         si->si_retrynum = NULL;
2296         si->si_syncCookie.ctxcsn = NULL;
2297         si->si_syncCookie.octet_str = NULL;
2298         si->si_syncCookie.sid = -1;
2299         si->si_manageDSAit = 0;
2300         si->si_tlimit = 0;
2301         si->si_slimit = 0;
2302         si->si_syncUUID_ndn.bv_val = NULL;
2303         si->si_syncUUID_ndn.bv_len = 0;
2304
2305         si->si_presentlist = NULL;
2306         LDAP_LIST_INIT( &si->si_nonpresentlist );
2307
2308         rc = parse_syncrepl_line( cargv, cargc, si );
2309
2310         LDAP_STAILQ_FOREACH( si_entry, &be->be_syncinfo, si_next ) {
2311                 if ( si->si_rid == si_entry->si_rid ) {
2312                         Debug( LDAP_DEBUG_ANY,
2313                                 "add_syncrepl: duplicated replica id\n",0, 0, 0 );
2314                         duplicated_replica_id = 1;
2315                         break;
2316                 }
2317         }
2318
2319         if ( rc < 0 || duplicated_replica_id ) {
2320                 Debug( LDAP_DEBUG_ANY, "failed to add syncinfo\n", 0, 0, 0 );
2321                 return 1;
2322         } else {
2323                 Debug( LDAP_DEBUG_CONFIG,
2324                         "Config: ** successfully added syncrepl \"%s\"\n",
2325                         si->si_provideruri == NULL ? "(null)" : si->si_provideruri, 0, 0 );
2326                 if ( !si->si_schemachecking ) {
2327                         SLAP_DBFLAGS(be) |= SLAP_DBFLAG_NO_SCHEMA_CHECK;
2328                 }
2329                 si->si_be = be;
2330                 LDAP_STAILQ_INSERT_TAIL( &be->be_syncinfo, si, si_next );
2331                 return 0;
2332         }
2333 }
2334
2335 #define IDSTR                   "rid"
2336 #define PROVIDERSTR             "provider"
2337 #define SUFFIXSTR               "suffix"
2338 #define UPDATEDNSTR             "updatedn"
2339 #define BINDMETHSTR             "bindmethod"
2340 #define SIMPLESTR               "simple"
2341 #define SASLSTR                 "sasl"
2342 #define BINDDNSTR               "binddn"
2343 #define CREDSTR                 "credentials"
2344 #define OLDAUTHCSTR             "bindprincipal"
2345 #define AUTHCSTR                "authcID"
2346 #define AUTHZSTR                "authzID"
2347 #define SRVTABSTR               "srvtab"
2348 #define SASLMECHSTR             "saslmech"
2349 #define REALMSTR                "realm"
2350 #define SECPROPSSTR             "secprops"
2351 #define STARTTLSSTR             "starttls"
2352 #define CRITICALSTR             "critical"
2353
2354 #define SCHEMASTR               "schemachecking"
2355 #define FILTERSTR               "filter"
2356 #define SEARCHBASESTR   "searchbase"
2357 #define SCOPESTR                "scope"
2358 #define ATTRSSTR                "attrs"
2359 #define ATTRSONLYSTR    "attrsonly"
2360 #define EXATTRSSTR              "exattrs"
2361 #define TYPESTR                 "type"
2362 #define INTERVALSTR             "interval"
2363 #define LASTMODSTR              "lastmod"
2364 #define LMREQSTR                "req"
2365 #define LMGENSTR                "gen"
2366 #define LMNOSTR                 "no"
2367 #define MANAGEDSAITSTR  "manageDSAit"
2368 #define SLIMITSTR               "sizelimit"
2369 #define TLIMITSTR               "timelimit"
2370
2371 #define RETRYSTR                "retry"
2372
2373 #define GOT_ID                  0x0001
2374 #define GOT_PROVIDER    0x0002
2375 #define GOT_METHOD              0x0004
2376 #define GOT_ALL                 0x0007
2377
2378 static int
2379 parse_syncrepl_line(
2380         char            **cargv,
2381         int             cargc,
2382         syncinfo_t      *si
2383 )
2384 {
2385         int     gots = 0;
2386         int     i, j;
2387         char    *hp, *val;
2388         int     nr_attr = 0;
2389
2390         for ( i = 1; i < cargc; i++ ) {
2391                 if ( !strncasecmp( cargv[ i ], IDSTR, sizeof( IDSTR ) - 1 )) {
2392                         int tmp;
2393                         /* '\0' string terminator accounts for '=' */
2394                         val = cargv[ i ] + sizeof( IDSTR );
2395                         tmp= atoi( val );
2396                         if ( tmp >= 1000 || tmp < 0 ) {
2397                                 fprintf( stderr, "Error: parse_syncrepl_line: "
2398                                          "syncrepl id %d is out of range [0..999]\n", tmp );
2399                                 return -1;
2400                         }
2401                         si->si_rid = tmp;
2402                         gots |= GOT_ID;
2403                 } else if ( !strncasecmp( cargv[ i ], PROVIDERSTR,
2404                                         sizeof( PROVIDERSTR ) - 1 )) {
2405                         val = cargv[ i ] + sizeof( PROVIDERSTR );
2406                         si->si_provideruri = ch_strdup( val );
2407                         si->si_provideruri_bv = (BerVarray)
2408                                 ch_calloc( 2, sizeof( struct berval ));
2409                         ber_str2bv( si->si_provideruri, strlen( si->si_provideruri ),
2410                                 1, &si->si_provideruri_bv[0] );
2411                         si->si_provideruri_bv[1].bv_len = 0;
2412                         si->si_provideruri_bv[1].bv_val = NULL;
2413                         gots |= GOT_PROVIDER;
2414                 } else if ( !strncasecmp( cargv[ i ], STARTTLSSTR,
2415                         sizeof(STARTTLSSTR) - 1 ) )
2416                 {
2417                         val = cargv[ i ] + sizeof( STARTTLSSTR );
2418                         if( !strcasecmp( val, CRITICALSTR ) ) {
2419                                 si->si_tls = SYNCINFO_TLS_CRITICAL;
2420                         } else {
2421                                 si->si_tls = SYNCINFO_TLS_ON;
2422                         }
2423                 } else if ( !strncasecmp( cargv[ i ],
2424                         UPDATEDNSTR, sizeof( UPDATEDNSTR ) - 1 ) )
2425                 {
2426                         struct berval updatedn = {0, NULL};
2427                         val = cargv[ i ] + sizeof( UPDATEDNSTR );
2428                         ber_str2bv( val, 0, 0, &updatedn );
2429                         ch_free( si->si_updatedn.bv_val );
2430                         dnNormalize( 0, NULL, NULL, &updatedn, &si->si_updatedn, NULL );
2431                 } else if ( !strncasecmp( cargv[ i ], BINDMETHSTR,
2432                                 sizeof( BINDMETHSTR ) - 1 ) )
2433                 {
2434                         val = cargv[ i ] + sizeof( BINDMETHSTR );
2435                         if ( !strcasecmp( val, SIMPLESTR )) {
2436                                 si->si_bindmethod = LDAP_AUTH_SIMPLE;
2437                                 gots |= GOT_METHOD;
2438                         } else if ( !strcasecmp( val, SASLSTR )) {
2439 #ifdef HAVE_CYRUS_SASL
2440                                 si->si_bindmethod = LDAP_AUTH_SASL;
2441                                 gots |= GOT_METHOD;
2442 #else /* HAVE_CYRUS_SASL */
2443                                 fprintf( stderr, "Error: parse_syncrepl_line: "
2444                                         "not compiled with SASL support\n" );
2445                                 return 1;
2446 #endif /* HAVE_CYRUS_SASL */
2447                         } else {
2448                                 si->si_bindmethod = -1;
2449                         }
2450                 } else if ( !strncasecmp( cargv[ i ],
2451                                 BINDDNSTR, sizeof( BINDDNSTR ) - 1 ) ) {
2452                         val = cargv[ i ] + sizeof( BINDDNSTR );
2453                         si->si_binddn = ch_strdup( val );
2454                 } else if ( !strncasecmp( cargv[ i ],
2455                                 CREDSTR, sizeof( CREDSTR ) - 1 ) ) {
2456                         val = cargv[ i ] + sizeof( CREDSTR );
2457                         si->si_passwd = ch_strdup( val );
2458                 } else if ( !strncasecmp( cargv[ i ],
2459                                 SASLMECHSTR, sizeof( SASLMECHSTR ) - 1 ) ) {
2460                         val = cargv[ i ] + sizeof( SASLMECHSTR );
2461                         si->si_saslmech = ch_strdup( val );
2462                 } else if ( !strncasecmp( cargv[ i ],
2463                                 SECPROPSSTR, sizeof( SECPROPSSTR ) - 1 ) ) {
2464                         val = cargv[ i ] + sizeof( SECPROPSSTR );
2465                         si->si_secprops = ch_strdup( val );
2466                 } else if ( !strncasecmp( cargv[ i ],
2467                                 REALMSTR, sizeof( REALMSTR ) - 1 ) ) {
2468                         val = cargv[ i ] + sizeof( REALMSTR );
2469                         si->si_realm = ch_strdup( val );
2470                 } else if ( !strncasecmp( cargv[ i ],
2471                                 AUTHCSTR, sizeof( AUTHCSTR ) - 1 ) ) {
2472                         val = cargv[ i ] + sizeof( AUTHCSTR );
2473                         if ( si->si_authcId )
2474                                 ch_free( si->si_authcId );
2475                         si->si_authcId = ch_strdup( val );
2476                 } else if ( !strncasecmp( cargv[ i ],
2477                                 OLDAUTHCSTR, sizeof( OLDAUTHCSTR ) - 1 ) ) {
2478                         /* Old authcID is provided for some backwards compatibility */
2479                         val = cargv[ i ] + sizeof( OLDAUTHCSTR );
2480                         if ( si->si_authcId )
2481                                 ch_free( si->si_authcId );
2482                         si->si_authcId = ch_strdup( val );
2483                 } else if ( !strncasecmp( cargv[ i ],
2484                                 AUTHZSTR, sizeof( AUTHZSTR ) - 1 ) ) {
2485                         val = cargv[ i ] + sizeof( AUTHZSTR );
2486                         si->si_authzId = ch_strdup( val );
2487                 } else if ( !strncasecmp( cargv[ i ],
2488                                 SCHEMASTR, sizeof( SCHEMASTR ) - 1 ) )
2489                 {
2490                         val = cargv[ i ] + sizeof( SCHEMASTR );
2491                         if ( !strncasecmp( val, "on", STRLENOF( "on" ) )) {
2492                                 si->si_schemachecking = 1;
2493                         } else if ( !strncasecmp( val, "off", STRLENOF( "off" ) ) ) {
2494                                 si->si_schemachecking = 0;
2495                         } else {
2496                                 si->si_schemachecking = 1;
2497                         }
2498                 } else if ( !strncasecmp( cargv[ i ],
2499                         FILTERSTR, sizeof( FILTERSTR ) - 1 ) )
2500                 {
2501                         val = cargv[ i ] + sizeof( FILTERSTR );
2502                         ber_str2bv( val, 0, 1, &si->si_filterstr );
2503                 } else if ( !strncasecmp( cargv[ i ],
2504                         SEARCHBASESTR, sizeof( SEARCHBASESTR ) - 1 ) )
2505                 {
2506                         struct berval bv;
2507                         val = cargv[ i ] + sizeof( SEARCHBASESTR );
2508                         if ( si->si_base.bv_val ) {
2509                                 ch_free( si->si_base.bv_val );
2510                         }
2511                         ber_str2bv( val, 0, 0, &bv );
2512                         if ( dnNormalize( 0, NULL, NULL, &bv, &si->si_base, NULL )) {
2513                                 fprintf( stderr, "Invalid base DN \"%s\"\n", val );
2514                                 return 1;
2515                         }
2516                 } else if ( !strncasecmp( cargv[ i ],
2517                         SCOPESTR, sizeof( SCOPESTR ) - 1 ) )
2518                 {
2519                         val = cargv[ i ] + sizeof( SCOPESTR );
2520                         if ( !strncasecmp( val, "base", STRLENOF( "base" ) )) {
2521                                 si->si_scope = LDAP_SCOPE_BASE;
2522                         } else if ( !strncasecmp( val, "one", STRLENOF( "one" ) )) {
2523                                 si->si_scope = LDAP_SCOPE_ONELEVEL;
2524 #ifdef LDAP_SCOPE_SUBORDINATE
2525                         } else if ( !strcasecmp( val, "subordinate" ) ||
2526                                 !strcasecmp( val, "children" ))
2527                         {
2528                                 si->si_scope = LDAP_SCOPE_SUBORDINATE;
2529 #endif
2530                         } else if ( !strncasecmp( val, "sub", STRLENOF( "sub" ) )) {
2531                                 si->si_scope = LDAP_SCOPE_SUBTREE;
2532                         } else {
2533                                 fprintf( stderr, "Error: parse_syncrepl_line: "
2534                                         "unknown scope \"%s\"\n", val);
2535                                 return 1;
2536                         }
2537                 } else if ( !strncasecmp( cargv[ i ],
2538                         ATTRSONLYSTR, sizeof( ATTRSONLYSTR ) - 1 ) )
2539                 {
2540                         si->si_attrsonly = 1;
2541                 } else if ( !strncasecmp( cargv[ i ],
2542                         ATTRSSTR, sizeof( ATTRSSTR ) - 1 ) )
2543                 {
2544                         val = cargv[ i ] + sizeof( ATTRSSTR );
2545                         if ( !strncasecmp( val, ":include:", STRLENOF(":include:") )) {
2546                                 char *attr_fname;
2547                                 attr_fname = ch_strdup( val + STRLENOF(":include:") );
2548                                 if ( get_attrs_from_file( &si->si_attrs, attr_fname, " ,\t" )) {
2549                                         ch_free( attr_fname );
2550                                         return -1;
2551                                 }
2552                                 if ( get_ocs_from_file( &si->si_ocs, attr_fname, " ,\t" )) {
2553                                         ch_free( attr_fname );
2554                                         return -1;
2555                                 }
2556                                 ch_free( attr_fname );
2557                         } else {
2558                                 str2attrs( &si->si_attrs, val, " ,\t" );
2559                                 str2ocs( &si->si_ocs, val, " ,\t" );
2560                         }
2561                 } else if ( !strncasecmp( cargv[ i ],
2562                         EXATTRSSTR, sizeof( EXATTRSSTR ) - 1 ) )
2563                 {
2564                         val = cargv[ i ] + sizeof( EXATTRSSTR );
2565                         if ( !strncasecmp( val, ":include:", STRLENOF(":include:") )) {
2566                                 char *attr_fname;
2567                                 attr_fname = ch_strdup( val + STRLENOF(":include:") );
2568                                 if ( get_attrs_from_file( &si->si_exattrs,
2569                                                         attr_fname, " ,\t" )) {
2570                                         ch_free( attr_fname );
2571                                         return -1;
2572                                 }
2573                                 ch_free( attr_fname );
2574                         } else {
2575                                 str2attrs( &si->si_exattrs, val, " ,\t" );
2576                         }
2577                 } else if ( !strncasecmp( cargv[ i ],
2578                         TYPESTR, sizeof( TYPESTR ) - 1 ) )
2579                 {
2580                         val = cargv[ i ] + sizeof( TYPESTR );
2581                         if ( !strncasecmp( val, "refreshOnly", STRLENOF("refreshOnly") )) {
2582                                 si->si_type = LDAP_SYNC_REFRESH_ONLY;
2583                         } else if ( !strncasecmp( val, "refreshAndPersist",
2584                                 STRLENOF("refreshAndPersist") ))
2585                         {
2586                                 si->si_type = LDAP_SYNC_REFRESH_AND_PERSIST;
2587                                 si->si_interval = 60;
2588                         } else {
2589                                 fprintf( stderr, "Error: parse_syncrepl_line: "
2590                                         "unknown sync type \"%s\"\n", val);
2591                                 return 1;
2592                         }
2593                 } else if ( !strncasecmp( cargv[ i ],
2594                         INTERVALSTR, sizeof( INTERVALSTR ) - 1 ) )
2595                 {
2596                         val = cargv[ i ] + sizeof( INTERVALSTR );
2597                         if ( si->si_type == LDAP_SYNC_REFRESH_AND_PERSIST ) {
2598                                 si->si_interval = 0;
2599                         } else {
2600                                 char *hstr;
2601                                 char *mstr;
2602                                 char *dstr;
2603                                 char *sstr;
2604                                 int dd, hh, mm, ss;
2605                                 dstr = val;
2606                                 hstr = strchr( dstr, ':' );
2607                                 if ( hstr == NULL ) {
2608                                         fprintf( stderr, "Error: parse_syncrepl_line: "
2609                                                 "invalid interval \"%s\"\n", val );
2610                                         return 1;
2611                                 }
2612                                 *hstr++ = '\0';
2613                                 mstr = strchr( hstr, ':' );
2614                                 if ( mstr == NULL ) {
2615                                         fprintf( stderr, "Error: parse_syncrepl_line: "
2616                                                 "invalid interval \"%s\"\n", val );
2617                                         return 1;
2618                                 }
2619                                 *mstr++ = '\0';
2620                                 sstr = strchr( mstr, ':' );
2621                                 if ( sstr == NULL ) {
2622                                         fprintf( stderr, "Error: parse_syncrepl_line: "
2623                                                 "invalid interval \"%s\"\n", val );
2624                                         return 1;
2625                                 }
2626                                 *sstr++ = '\0';
2627
2628                                 dd = atoi( dstr );
2629                                 hh = atoi( hstr );
2630                                 mm = atoi( mstr );
2631                                 ss = atoi( sstr );
2632                                 if (( hh > 24 ) || ( hh < 0 ) ||
2633                                         ( mm > 60 ) || ( mm < 0 ) ||
2634                                         ( ss > 60 ) || ( ss < 0 ) || ( dd < 0 )) {
2635                                         fprintf( stderr, "Error: parse_syncrepl_line: "
2636                                                 "invalid interval \"%s\"\n", val );
2637                                         return 1;
2638                                 }
2639                                 si->si_interval = (( dd * 24 + hh ) * 60 + mm ) * 60 + ss;
2640                         }
2641                         if ( si->si_interval < 0 ) {
2642                                 fprintf( stderr, "Error: parse_syncrepl_line: "
2643                                         "invalid interval \"%ld\"\n",
2644                                         (long) si->si_interval);
2645                                 return 1;
2646                         }
2647                 } else if ( !strncasecmp( cargv[ i ],
2648                         RETRYSTR, sizeof( RETRYSTR ) - 1 ) )
2649                 {
2650                         char *str;
2651                         char **retry_list;
2652                         int j, k, n;
2653
2654                         val = cargv[ i ] + sizeof( RETRYSTR );
2655                         retry_list = (char **) ch_calloc( 1, sizeof( char * ));
2656                         retry_list[0] = NULL;
2657
2658                         slap_str2clist( &retry_list, val, " ,\t" );
2659
2660                         for ( k = 0; retry_list && retry_list[k]; k++ ) ;
2661                         n = k / 2;
2662                         if ( k % 2 ) {
2663                                 fprintf( stderr,
2664                                                 "Error: incomplete syncrepl retry list\n" );
2665                                 for ( k = 0; retry_list && retry_list[k]; k++ ) {
2666                                         ch_free( retry_list[k] );
2667                                 }
2668                                 ch_free( retry_list );
2669                                 exit( EXIT_FAILURE );
2670                         }
2671                         si->si_retryinterval = (time_t *) ch_calloc( n + 1, sizeof( time_t ));
2672                         si->si_retrynum = (int *) ch_calloc( n + 1, sizeof( int ));
2673                         si->si_retrynum_init = (int *) ch_calloc( n + 1, sizeof( int ));
2674                         for ( j = 0; j < n; j++ ) {
2675                                 si->si_retryinterval[j] = atoi( retry_list[j*2] );
2676                                 if ( *retry_list[j*2+1] == '+' ) {
2677                                         si->si_retrynum_init[j] = -1;
2678                                         si->si_retrynum[j] = -1;
2679                                         j++;
2680                                         break;
2681                                 } else {
2682                                         si->si_retrynum_init[j] = atoi( retry_list[j*2+1] );
2683                                         si->si_retrynum[j] = atoi( retry_list[j*2+1] );
2684                                 }
2685                         }
2686                         si->si_retrynum_init[j] = -2;
2687                         si->si_retrynum[j] = -2;
2688                         si->si_retryinterval[j] = 0;
2689                         
2690                         for ( k = 0; retry_list && retry_list[k]; k++ ) {
2691                                 ch_free( retry_list[k] );
2692                         }
2693                         ch_free( retry_list );
2694                 } else if ( !strncasecmp( cargv[ i ],
2695                         MANAGEDSAITSTR, sizeof( MANAGEDSAITSTR ) - 1 ) )
2696                 {
2697                         val = cargv[ i ] + sizeof( MANAGEDSAITSTR );
2698                         si->si_manageDSAit = atoi( val );
2699                 } else if ( !strncasecmp( cargv[ i ],
2700                         SLIMITSTR, sizeof( SLIMITSTR ) - 1 ) )
2701                 {
2702                         val = cargv[ i ] + sizeof( SLIMITSTR );
2703                         si->si_slimit = atoi( val );
2704                 } else if ( !strncasecmp( cargv[ i ],
2705                         TLIMITSTR, sizeof( TLIMITSTR ) - 1 ) )
2706                 {
2707                         val = cargv[ i ] + sizeof( TLIMITSTR );
2708                         si->si_tlimit = atoi( val );
2709                 } else {
2710                         fprintf( stderr, "Error: parse_syncrepl_line: "
2711                                 "unknown keyword \"%s\"\n", cargv[ i ] );
2712                 }
2713         }
2714
2715         if ( gots != GOT_ALL ) {
2716                 fprintf( stderr,
2717                         "Error: Malformed \"syncrepl\" line in slapd config file" );
2718                 return -1;
2719         }
2720
2721         return 0;
2722 }
2723
2724 static ObjectClass **
2725 str2ocs( ObjectClass ***out, char *in, const char *brkstr )
2726 {
2727         char **clist;
2728         int i, k = 0;
2729         ObjectClass *oc;
2730
2731         clist = (char **) ch_calloc( 1, sizeof( char *));
2732         clist[0] = NULL;
2733
2734         slap_str2clist( &clist, in, brkstr );
2735
2736         for ( i = 0; clist && clist[i]; i++ ) {
2737                 if (*clist[i] == '@' ) {
2738                         struct berval ocbv;
2739                         ber_str2bv( clist[i]+1, strlen(clist[i]+1), 1, &ocbv );
2740                         oc = oc_bvfind( &ocbv );
2741                         if ( oc ) {
2742                                 k++;
2743                         }
2744                         ch_free( ocbv.bv_val );
2745                 }
2746         }
2747
2748         *out = ch_realloc( *out, (k + 1) * sizeof( ObjectClass *));
2749
2750         for ( i = 0; clist && clist[i]; i++ ) {
2751                 if (*clist[i] == '@' ) {
2752                         struct berval ocbv;
2753                         ber_str2bv( clist[i]+1, strlen(clist[i]+1), 1, &ocbv );
2754                         (*out)[i] = oc_bvfind( &ocbv );
2755                         ch_free( ocbv.bv_val );
2756                 }
2757         }
2758
2759         (*out)[i] = NULL;
2760
2761         for ( i = 0; clist && clist[i]; i++ ) {
2762                 ch_free( clist[i] );
2763         }
2764         ch_free( clist );
2765
2766         return (*out);
2767 }
2768
2769 static char **
2770 str2attrs( char ***out, char *in, const char *brkstr )
2771 {
2772         int i, j = 0, k = 0, l = 0;
2773         ObjectClass *oc;
2774
2775         slap_str2clist( out, in , brkstr );
2776
2777         for ( i = 0; *out && (*out)[i]; i++ ) {
2778                 if ( *(*out)[i] == '@' ) {
2779                         struct berval ocbv;
2780                         ber_str2bv( (*out)[i]+1, strlen((*out)[i]+1), 1, &ocbv );
2781                         oc = oc_bvfind( &ocbv );
2782                         if ( oc ) {
2783                                 k++;
2784                                 for ( j = 0; oc->soc_required && oc->soc_required[j]; j++ );
2785                                 l += j;
2786                                 for ( j = 0; oc->soc_allowed && oc->soc_allowed[j]; j++ );
2787                                 l += j;
2788                         }
2789                         ch_free( ocbv.bv_val );
2790                 }
2791         }
2792         
2793         *out = ch_realloc( *out, (i - k + l + 1) * sizeof( char * ));
2794
2795         for ( i = 0; *out && (*out)[i]; i++ ) {
2796 retest1:
2797                 if ( *(*out)[i] == '@' ) {
2798                         struct berval ocbv;
2799                         ber_str2bv( (*out)[i]+1, strlen((*out)[i]+1), 1, &ocbv );
2800                         oc = oc_bvfind( &ocbv );
2801                         for ( k = i; (*out)[k]; k++ ) {
2802                                 if ( k == i )
2803                                         ch_free( (*out)[i] );
2804                                 (*out)[k] = (*out)[k+1];
2805                         }                               
2806                         k--;
2807                         if ( oc ) {
2808                                 for ( j = 0; oc->soc_required && oc->soc_required[j]; j++ ) {
2809                                         (*out)[k++] = ch_strdup(
2810                                                         oc->soc_required[j]->sat_cname.bv_val );
2811                                 }
2812                                 for ( j = 0; oc->soc_allowed && oc->soc_allowed[j]; j++ ) {
2813                                         (*out)[k++] = ch_strdup(
2814                                                         oc->soc_allowed[j]->sat_cname.bv_val );
2815                                 }
2816                                 (*out)[k] = NULL;
2817                         }
2818                         ch_free( ocbv.bv_val );
2819                         goto retest1;
2820                 }
2821         }
2822
2823         for ( i = 0; *out && (*out)[i]; i++ ) {
2824                 for ( j = i+1; *out && (*out)[j]; j++ ) {
2825 retest2:
2826                         if ( !strcmp( (*out)[i], (*out)[j] )) {
2827                                 ch_free( (*out)[j] );   
2828                                 for ( k = j; (*out)[k]; k++ ) {
2829                                         (*out)[k] = (*out)[k+1];
2830                                 }
2831                                 if ( (*out)[j] != NULL )
2832                                         goto retest2;
2833                                 else
2834                                         break;
2835                         }
2836                 }
2837         }
2838
2839         for ( i = 0; *out && (*out)[i]; i++ );
2840
2841         *out = ch_realloc( *out, (i + 1) * sizeof( char * ));
2842
2843         return (*out);
2844 }
2845
2846 char **
2847 slap_str2clist( char ***out, char *in, const char *brkstr )
2848 {
2849         char    *str;
2850         char    *s;
2851         char    *lasts;
2852         int     i, j;
2853         const char *text;
2854         char    **new;
2855
2856         /* find last element in list */
2857         for (i = 0; *out && (*out)[i]; i++);
2858
2859         /* protect the input string from strtok */
2860         str = ch_strdup( in );
2861
2862         if ( *str == '\0' ) {
2863                 free( str );
2864                 return( *out );
2865         }
2866
2867         /* Count words in string */
2868         j=1;
2869         for ( s = str; *s; s++ ) {
2870                 if ( strchr( brkstr, *s ) != NULL ) {
2871                         j++;
2872                 }
2873         }
2874
2875         *out = ch_realloc( *out, ( i + j + 1 ) * sizeof( char * ) );
2876         new = *out + i;
2877         for ( s = ldap_pvt_strtok( str, brkstr, &lasts );
2878                 s != NULL;
2879                 s = ldap_pvt_strtok( NULL, brkstr, &lasts ) )
2880         {
2881                 *new = ch_strdup( s );
2882                 new++;
2883         }
2884
2885         *new = NULL;
2886         free( str );
2887         return( *out );
2888 }
2889
2890 #define LBUFSIZ 80
2891 static int
2892 get_attrs_from_file( char ***attrs, const char *fname, const char *brkstr )
2893 {
2894         FILE    *fp;
2895         char    *line = NULL;
2896         char    *lcur = NULL;
2897         char    *c;
2898         size_t  lmax = LBUFSIZ;
2899
2900         fp = fopen( fname, "r" );
2901         if ( fp == NULL ) {
2902                 Debug( LDAP_DEBUG_ANY,
2903                         "get_attrs_from_file: failed to open attribute list file "
2904                         "\"%s\": %s\n", fname, strerror(errno), 0 );
2905                 return 1;
2906         }
2907
2908         lcur = line = (char *) ch_malloc( lmax );
2909         if ( !line ) {
2910                 Debug( LDAP_DEBUG_ANY,
2911                         "get_attrs_from_file: could not allocate memory\n",
2912                         0, 0, 0 );
2913                 fclose(fp);
2914                 return 1;
2915         }
2916
2917         while ( fgets( lcur, LBUFSIZ, fp ) != NULL ) {
2918                 if (c = strchr( lcur, '\n' )) {
2919                         if ( c == line ) {
2920                                 *c = '\0';
2921                         } else if ( *(c-1) == '\r' ) {
2922                                 *(c-1) = '\0';
2923                         } else {
2924                                 *c = '\0';
2925                         }
2926                 } else {
2927                         lmax += LBUFSIZ;
2928                         line = (char *) ch_realloc( line, lmax );
2929                         if ( !line ) {
2930                                 Debug( LDAP_DEBUG_ANY,
2931                                         "get_attrs_from_file: could not allocate memory\n",
2932                                         0, 0, 0 );
2933                                 fclose(fp);
2934                                 return 1;
2935                         }
2936                         lcur = line + strlen( line );
2937                         continue;
2938                 }
2939                 str2attrs( attrs, line, brkstr );
2940                 lcur = line;
2941         }
2942         ch_free( line );
2943         fclose(fp);
2944         return 0;
2945 }
2946 #undef LBUFSIZ
2947
2948 #define LBUFSIZ 80
2949 static int
2950 get_ocs_from_file( ObjectClass ***ocs, const char *fname, const char *brkstr )
2951 {
2952         FILE    *fp;
2953         char    *line = NULL;
2954         char    *lcur = NULL;
2955         char    *c;
2956         size_t  lmax = LBUFSIZ;
2957
2958         fp = fopen( fname, "r" );
2959         if ( fp == NULL ) {
2960                 Debug( LDAP_DEBUG_ANY,
2961                         "get_ocs_from_file: failed to open attribute list file "
2962                         "\"%s\": %s\n", fname, strerror(errno), 0 );
2963                 return 1;
2964         }
2965
2966         lcur = line = (char *) ch_malloc( lmax );
2967         if ( !line ) {
2968                 Debug( LDAP_DEBUG_ANY,
2969                         "get_ocs_from_file: could not allocate memory\n",
2970                         0, 0, 0 );
2971                 fclose(fp);
2972                 return 1;
2973         }
2974
2975         while ( fgets( lcur, LBUFSIZ, fp ) != NULL ) {
2976                 if (c = strchr( lcur, '\n' )) {
2977                         if ( c == line ) {
2978                                 *c = '\0';
2979                         } else if ( *(c-1) == '\r' ) {
2980                                 *(c-1) = '\0';
2981                         } else {
2982                                 *c = '\0';
2983                         }
2984                 } else {
2985                         lmax += LBUFSIZ;
2986                         line = (char *) ch_realloc( line, lmax );
2987                         if ( !line ) {
2988                                 Debug( LDAP_DEBUG_ANY,
2989                                         "get_ocs_from_file: could not allocate memory\n",
2990                                         0, 0, 0 );
2991                                 fclose(fp);
2992                                 return 1;
2993                         }
2994                         lcur = line + strlen( line );
2995                         continue;
2996                 }
2997                 str2ocs( ocs, line, brkstr );
2998                 lcur = line;
2999         }
3000         ch_free( line );
3001         fclose(fp);
3002         return 0;
3003 }
3004 #undef LBUFSIZ