]> git.sur5r.net Git - openldap/blob - servers/slapd/config.c
2322f3a3413ac6b630e57cefcbc6bf65b89ae88b
[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-2006 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 <sys/types.h>
38 #include <sys/stat.h>
39 #include <unistd.h>
40
41 #include "slap.h"
42 #ifdef LDAP_SLAPI
43 #include "slapi/slapi.h"
44 #endif
45 #include "lutil.h"
46 #include "config.h"
47
48 #ifdef HAVE_TLS
49 #include <openssl/ssl.h>
50 #endif
51
52 #define ARGS_STEP       512
53
54 /*
55  * defaults for various global variables
56  */
57 slap_mask_t             global_allows = 0;
58 slap_mask_t             global_disallows = 0;
59 int             global_gentlehup = 0;
60 int             global_idletimeout = 0;
61 char    *global_host = NULL;
62 char    *global_realm = NULL;
63 char            *ldap_srvtab = "";
64 char            **default_passwd_hash = NULL;
65 struct berval default_search_base = BER_BVNULL;
66 struct berval default_search_nbase = BER_BVNULL;
67
68 ber_len_t sockbuf_max_incoming = SLAP_SB_MAX_INCOMING_DEFAULT;
69 ber_len_t sockbuf_max_incoming_auth= SLAP_SB_MAX_INCOMING_AUTH;
70
71 int     slap_conn_max_pending = SLAP_CONN_MAX_PENDING_DEFAULT;
72 int     slap_conn_max_pending_auth = SLAP_CONN_MAX_PENDING_AUTH;
73
74 char   *slapd_pid_file  = NULL;
75 char   *slapd_args_file = NULL;
76
77 int use_reverse_lookup = 0;
78
79 #ifdef LDAP_SLAPI
80 int slapi_plugins_used = 0;
81 #endif
82
83 static int fp_getline(FILE *fp, ConfigArgs *c);
84 static void fp_getline_init(ConfigArgs *c);
85 static int fp_parse_line(ConfigArgs *c);
86
87 static char     *strtok_quote(char *line, char *sep, char **quote_ptr);
88 static char *strtok_quote_ldif(char **line);
89
90 ConfigArgs *
91 new_config_args( BackendDB *be, const char *fname, int lineno, int argc, char **argv )
92 {
93         ConfigArgs *c;
94         c = ch_calloc( 1, sizeof( ConfigArgs ) );
95         if ( c == NULL ) return(NULL);
96         c->be     = be; 
97         c->fname  = fname;
98         c->argc   = argc;
99         c->argv   = argv; 
100         c->lineno = lineno;
101         snprintf( c->log, sizeof( c->log ), "%s: line %d", fname, lineno );
102         return(c);
103 }
104
105 void
106 init_config_argv( ConfigArgs *c )
107 {
108         c->argv = ch_calloc( ARGS_STEP + 1, sizeof( *c->argv ) );
109         c->argv_size = ARGS_STEP + 1;
110 }
111
112 ConfigTable *config_find_keyword(ConfigTable *Conf, ConfigArgs *c) {
113         int i;
114
115         for(i = 0; Conf[i].name; i++)
116                 if( (Conf[i].length && (!strncasecmp(c->argv[0], Conf[i].name, Conf[i].length))) ||
117                         (!strcasecmp(c->argv[0], Conf[i].name)) ) break;
118         if ( !Conf[i].name ) return NULL;
119         return Conf+i;
120 }
121
122 int config_check_vals(ConfigTable *Conf, ConfigArgs *c, int check_only ) {
123         int rc, arg_user, arg_type, iarg;
124         long larg;
125         ber_len_t barg;
126         
127         arg_type = Conf->arg_type;
128         if(arg_type == ARG_IGNORED) {
129                 Debug(LDAP_DEBUG_CONFIG, "%s: keyword <%s> ignored\n",
130                         c->log, Conf->name, 0);
131                 return(0);
132         }
133         if((arg_type & ARG_DN) && c->argc == 1) {
134                 c->argc = 2;
135                 c->argv[1] = "";
136         }
137         if(Conf->min_args && (c->argc < Conf->min_args)) {
138                 snprintf( c->msg, sizeof( c->msg ), "<%s> missing <%s> argument",
139                         c->argv[0], Conf->what );
140                 Debug(LDAP_DEBUG_CONFIG, "%s: keyword %s\n", c->log, c->msg, 0 );
141                 return(ARG_BAD_CONF);
142         }
143         if(Conf->max_args && (c->argc > Conf->max_args)) {
144                 char    *ignored = " ignored";
145
146                 snprintf( c->msg, sizeof( c->msg ), "<%s> extra cruft after <%s>",
147                         c->argv[0], Conf->what );
148
149 #ifdef LDAP_DEVEL
150                 ignored = "";
151 #endif /* LDAP_DEVEL */
152                 Debug(LDAP_DEBUG_CONFIG, "%s: %s%s.\n",
153                                 c->log, c->msg, ignored );
154 #ifdef LDAP_DEVEL
155                 return(ARG_BAD_CONF);
156 #endif /* LDAP_DEVEL */
157         }
158         if((arg_type & ARG_DB) && !c->be) {
159                 snprintf( c->msg, sizeof( c->msg ), "<%s> only allowed within database declaration",
160                         c->argv[0] );
161                 Debug(LDAP_DEBUG_CONFIG, "%s: keyword %s\n",
162                         c->log, c->msg, 0);
163                 return(ARG_BAD_CONF);
164         }
165         if((arg_type & ARG_PRE_BI) && c->bi) {
166                 snprintf( c->msg, sizeof( c->msg ), "<%s> must occur before any backend %sdeclaration",
167                         c->argv[0], (arg_type & ARG_PRE_DB) ? "or database " : "" );
168                 Debug(LDAP_DEBUG_CONFIG, "%s: keyword %s\n",
169                         c->log, c->msg, 0 );
170                 return(ARG_BAD_CONF);
171         }
172         if((arg_type & ARG_PRE_DB) && c->be && c->be != frontendDB) {
173                 snprintf( c->msg, sizeof( c->msg ), "<%s> must occur before any database declaration",
174                         c->argv[0] );
175                 Debug(LDAP_DEBUG_CONFIG, "%s: keyword %s\n",
176                         c->log, c->msg, 0);
177                 return(ARG_BAD_CONF);
178         }
179         if((arg_type & ARG_PAREN) && *c->argv[1] != '(' /*')'*/) {
180                 snprintf( c->msg, sizeof( c->msg ), "<%s> old format not supported", c->argv[0] );
181                 Debug(LDAP_DEBUG_CONFIG, "%s: %s\n",
182                         c->log, c->msg, 0);
183                 return(ARG_BAD_CONF);
184         }
185         if((arg_type & ARGS_POINTER) && !Conf->arg_item && !(arg_type & ARG_OFFSET)) {
186                 snprintf( c->msg, sizeof( c->msg ), "<%s> invalid config_table, arg_item is NULL",
187                         c->argv[0] );
188                 Debug(LDAP_DEBUG_CONFIG, "%s: %s\n",
189                         c->log, c->msg, 0);
190                 return(ARG_BAD_CONF);
191         }
192         c->type = arg_user = (arg_type & ARGS_USERLAND);
193         memset(&c->values, 0, sizeof(c->values));
194         if(arg_type & ARGS_NUMERIC) {
195                 int j;
196                 iarg = 0; larg = 0; barg = 0;
197                 switch(arg_type & ARGS_NUMERIC) {
198                         case ARG_INT:
199                                 if ( lutil_atoix( &iarg, c->argv[1], 0 ) != 0 ) {
200                                         snprintf( c->msg, sizeof( c->msg ),
201                                                 "<%s> unable to parse \"%s\" as int",
202                                                 c->argv[0], c->argv[1] );
203                                         Debug(LDAP_DEBUG_CONFIG, "%s: %s\n",
204                                                 c->log, c->msg, 0);
205                                         return(ARG_BAD_CONF);
206                                 }
207                                 break;
208                         case ARG_LONG:
209                                 if ( lutil_atolx( &larg, c->argv[1], 0 ) != 0 ) {
210                                         snprintf( c->msg, sizeof( c->msg ),
211                                                 "<%s> unable to parse \"%s\" as long",
212                                                 c->argv[0], c->argv[1] );
213                                         Debug(LDAP_DEBUG_CONFIG, "%s: %s\n",
214                                                 c->log, c->msg, 0);
215                                         return(ARG_BAD_CONF);
216                                 }
217                                 break;
218                         case ARG_BER_LEN_T: {
219                                 unsigned long   l;
220                                 if ( lutil_atoulx( &l, c->argv[1], 0 ) != 0 ) {
221                                         snprintf( c->msg, sizeof( c->msg ),
222                                                 "<%s> unable to parse \"%s\" as ber_len_t",
223                                                 c->argv[0], c->argv[1] );
224                                         Debug(LDAP_DEBUG_CONFIG, "%s: %s\n",
225                                                 c->log, c->msg, 0);
226                                         return(ARG_BAD_CONF);
227                                 }
228                                 barg = (ber_len_t)l;
229                                 } break;
230                         case ARG_ON_OFF:
231                                 if (c->argc == 1) {
232                                         iarg = 1;
233                                 } else if ( !strcasecmp(c->argv[1], "on") ||
234                                         !strcasecmp(c->argv[1], "true") ||
235                                         !strcasecmp(c->argv[1], "yes") )
236                                 {
237                                         iarg = 1;
238                                 } else if ( !strcasecmp(c->argv[1], "off") ||
239                                         !strcasecmp(c->argv[1], "false") ||
240                                         !strcasecmp(c->argv[1], "no") )
241                                 {
242                                         iarg = 0;
243                                 } else {
244                                         snprintf( c->msg, sizeof( c->msg ), "<%s> invalid value",
245                                                 c->argv[0] );
246                                         Debug(LDAP_DEBUG_ANY, "%s: %s\n",
247                                                 c->log, c->msg, 0 );
248                                         return(ARG_BAD_CONF);
249                                 }
250                                 break;
251                 }
252                 j = (arg_type & ARG_NONZERO) ? 1 : 0;
253                 if(iarg < j && larg < j && barg < j ) {
254                         larg = larg ? larg : (barg ? barg : iarg);
255                         snprintf( c->msg, sizeof( c->msg ), "<%s> invalid value",
256                                 c->argv[0] );
257                         Debug(LDAP_DEBUG_ANY, "%s: %s\n",
258                                 c->log, c->msg, 0 );
259                         return(ARG_BAD_CONF);
260                 }
261                 switch(arg_type & ARGS_NUMERIC) {
262                         case ARG_ON_OFF:
263                         case ARG_INT:           c->value_int = iarg;            break;
264                         case ARG_LONG:          c->value_long = larg;           break;
265                         case ARG_BER_LEN_T:     c->value_ber_t = barg;          break;
266                 }
267         } else if(arg_type & ARG_STRING) {
268                 if ( !check_only )
269                         c->value_string = ch_strdup(c->argv[1]);
270         } else if(arg_type & ARG_BERVAL) {
271                 if ( !check_only )
272                         ber_str2bv( c->argv[1], 0, 1, &c->value_bv );
273         } else if(arg_type & ARG_DN) {
274                 struct berval bv;
275                 ber_str2bv( c->argv[1], 0, 0, &bv );
276                 rc = dnPrettyNormal( NULL, &bv, &c->value_dn, &c->value_ndn, NULL );
277                 if ( rc != LDAP_SUCCESS ) {
278                         snprintf( c->msg, sizeof( c->msg ), "<%s> invalid DN %d (%s)",
279                                 c->argv[0], rc, ldap_err2string( rc ));
280                         Debug(LDAP_DEBUG_CONFIG, "%s: %s\n" , c->log, c->msg, 0);
281                         return(ARG_BAD_CONF);
282                 }
283                 if ( check_only ) {
284                         ch_free( c->value_ndn.bv_val );
285                         ch_free( c->value_dn.bv_val );
286                 }
287         }
288         return 0;
289 }
290
291 int config_set_vals(ConfigTable *Conf, ConfigArgs *c) {
292         int rc, arg_type;
293         void *ptr = NULL;
294
295         arg_type = Conf->arg_type;
296         if(arg_type & ARG_MAGIC) {
297                 if(!c->be) c->be = frontendDB;
298                 c->msg[0] = '\0';
299                 rc = (*((ConfigDriver*)Conf->arg_item))(c);
300 #if 0
301                 if(c->be == frontendDB) c->be = NULL;
302 #endif
303                 if(rc) {
304                         if ( !c->msg[0] ) {
305                                 snprintf( c->msg, sizeof( c->msg ), "<%s> handler exited with %d",
306                                         c->argv[0], rc );
307                                 Debug(LDAP_DEBUG_CONFIG, "%s: %s!\n",
308                                         c->log, c->msg, 0 );
309                         }
310                         return(ARG_BAD_CONF);
311                 }
312                 return(0);
313         }
314         if(arg_type & ARG_OFFSET) {
315                 if (c->be)
316                         ptr = c->be->be_private;
317                 else if (c->bi)
318                         ptr = c->bi->bi_private;
319                 else {
320                         snprintf( c->msg, sizeof( c->msg ), "<%s> offset is missing base pointer",
321                                 c->argv[0] );
322                         Debug(LDAP_DEBUG_CONFIG, "%s: %s!\n",
323                                 c->log, c->msg, 0);
324                         return(ARG_BAD_CONF);
325                 }
326                 ptr = (void *)((char *)ptr + (long)Conf->arg_item);
327         } else if (arg_type & ARGS_POINTER) {
328                 ptr = Conf->arg_item;
329         }
330         if(arg_type & ARGS_POINTER)
331                 switch(arg_type & ARGS_POINTER) {
332                         case ARG_ON_OFF:
333                         case ARG_INT:           *(int*)ptr = c->value_int;                      break;
334                         case ARG_LONG:          *(long*)ptr = c->value_long;                    break;
335                         case ARG_BER_LEN_T:     *(ber_len_t*)ptr = c->value_ber_t;                      break;
336                         case ARG_STRING: {
337                                 char *cc = *(char**)ptr;
338                                 if(cc) {
339                                         if ((arg_type & ARG_UNIQUE) && c->op == SLAP_CONFIG_ADD ) {
340                                                 Debug(LDAP_DEBUG_CONFIG, "%s: already set %s!\n",
341                                                         c->log, Conf->name, 0 );
342                                                 return(ARG_BAD_CONF);
343                                         }
344                                         ch_free(cc);
345                                 }
346                                 *(char **)ptr = c->value_string;
347                                 break;
348                                 }
349                         case ARG_BERVAL:
350                                 *(struct berval *)ptr = c->value_bv;
351                                 break;
352                 }
353         return(0);
354 }
355
356 int config_add_vals(ConfigTable *Conf, ConfigArgs *c) {
357         int rc, arg_type;
358
359         arg_type = Conf->arg_type;
360         if(arg_type == ARG_IGNORED) {
361                 Debug(LDAP_DEBUG_CONFIG, "%s: keyword <%s> ignored\n",
362                         c->log, Conf->name, 0);
363                 return(0);
364         }
365         rc = config_check_vals( Conf, c, 0 );
366         if ( rc ) return rc;
367         return config_set_vals( Conf, c );
368 }
369
370 int
371 config_del_vals(ConfigTable *cf, ConfigArgs *c)
372 {
373         int rc = 0;
374
375         /* If there is no handler, just ignore it */
376         if ( cf->arg_type & ARG_MAGIC ) {
377                 c->op = LDAP_MOD_DELETE;
378                 c->type = cf->arg_type & ARGS_USERLAND;
379                 rc = (*((ConfigDriver*)cf->arg_item))(c);
380         }
381         return rc;
382 }
383
384 int
385 config_get_vals(ConfigTable *cf, ConfigArgs *c)
386 {
387         int rc = 0;
388         struct berval bv;
389         void *ptr;
390
391         if ( cf->arg_type & ARG_IGNORED ) {
392                 return 1;
393         }
394
395         memset(&c->values, 0, sizeof(c->values));
396         c->rvalue_vals = NULL;
397         c->rvalue_nvals = NULL;
398         c->op = SLAP_CONFIG_EMIT;
399         c->type = cf->arg_type & ARGS_USERLAND;
400
401         if ( cf->arg_type & ARG_MAGIC ) {
402                 rc = (*((ConfigDriver*)cf->arg_item))(c);
403                 if ( rc ) return rc;
404         } else {
405                 if ( cf->arg_type & ARG_OFFSET ) {
406                         if ( c->be )
407                                 ptr = c->be->be_private;
408                         else if ( c->bi )
409                                 ptr = c->bi->bi_private;
410                         else
411                                 return 1;
412                         ptr = (void *)((char *)ptr + (long)cf->arg_item);
413                 } else {
414                         ptr = cf->arg_item;
415                 }
416                 
417                 switch(cf->arg_type & ARGS_POINTER) {
418                 case ARG_ON_OFF:
419                 case ARG_INT:   c->value_int = *(int *)ptr; break;
420                 case ARG_LONG:  c->value_long = *(long *)ptr; break;
421                 case ARG_BER_LEN_T:     c->value_ber_t = *(ber_len_t *)ptr; break;
422                 case ARG_STRING:
423                         if ( *(char **)ptr )
424                                 c->value_string = ch_strdup(*(char **)ptr);
425                         break;
426                 case ARG_BERVAL:
427                         ber_dupbv( &c->value_bv, (struct berval *)ptr ); break;
428                 }
429         }
430         if ( cf->arg_type & ARGS_POINTER) {
431                 bv.bv_val = c->log;
432                 switch(cf->arg_type & ARGS_POINTER) {
433                 case ARG_INT: bv.bv_len = snprintf(bv.bv_val, sizeof( c->log ), "%d", c->value_int); break;
434                 case ARG_LONG: bv.bv_len = snprintf(bv.bv_val, sizeof( c->log ), "%ld", c->value_long); break;
435                 case ARG_BER_LEN_T: bv.bv_len = snprintf(bv.bv_val, sizeof( c->log ), "%ld", c->value_ber_t); break;
436                 case ARG_ON_OFF: bv.bv_len = snprintf(bv.bv_val, sizeof( c->log ), "%s",
437                         c->value_int ? "TRUE" : "FALSE"); break;
438                 case ARG_STRING:
439                         if ( c->value_string && c->value_string[0]) {
440                                 ber_str2bv( c->value_string, 0, 0, &bv);
441                         } else {
442                                 return 1;
443                         }
444                         break;
445                 case ARG_BERVAL:
446                         if ( !BER_BVISEMPTY( &c->value_bv )) {
447                                 bv = c->value_bv;
448                         } else {
449                                 return 1;
450                         }
451                         break;
452                 }
453                 if (bv.bv_val == c->log && bv.bv_len >= sizeof( c->log ) ) {
454                         return 1;
455                 }
456                 if (( cf->arg_type & ARGS_POINTER ) == ARG_STRING )
457                         ber_bvarray_add(&c->rvalue_vals, &bv);
458                 else
459                         value_add_one(&c->rvalue_vals, &bv);
460         }
461         return rc;
462 }
463
464 int
465 init_config_attrs(ConfigTable *ct) {
466         LDAPAttributeType *at;
467         int i, code;
468         const char *err;
469
470         for (i=0; ct[i].name; i++ ) {
471                 int             freeit = 0;
472
473                 if ( !ct[i].attribute ) continue;
474                 at = ldap_str2attributetype( ct[i].attribute,
475                         &code, &err, LDAP_SCHEMA_ALLOW_ALL );
476                 if ( !at ) {
477                         fprintf( stderr, "init_config_attrs: AttributeType \"%s\": %s, %s\n",
478                                 ct[i].attribute, ldap_scherr2str(code), err );
479                         return code;
480                 }
481
482                 code = at_add( at, 0, NULL, &err );
483                 if ( code ) {
484                         if ( code == SLAP_SCHERR_ATTR_DUP ) {
485                                 freeit = 1;
486
487                         } else {
488                                 ldap_attributetype_free( at );
489                                 fprintf( stderr, "init_config_attrs: AttributeType \"%s\": %s, %s\n",
490                                         ct[i].attribute, scherr2str(code), err );
491                                 return code;
492                         }
493                 }
494                 code = slap_str2ad( at->at_names[0], &ct[i].ad, &err );
495                 if ( freeit || code ) {
496                         ldap_attributetype_free( at );
497                 } else {
498                         ldap_memfree( at );
499                 }
500                 if ( code ) {
501                         fprintf( stderr, "init_config_attrs: AttributeType \"%s\": %s\n",
502                                 ct[i].attribute, err );
503                         return code;
504                 }
505         }
506
507         return 0;
508 }
509
510 int
511 init_config_ocs( ConfigOCs *ocs ) {
512         int i;
513
514         for (i=0;ocs[i].co_def;i++) {
515                 LDAPObjectClass *oc;
516                 int code;
517                 const char *err;
518
519                 oc = ldap_str2objectclass( ocs[i].co_def, &code, &err,
520                         LDAP_SCHEMA_ALLOW_ALL );
521                 if ( !oc ) {
522                         fprintf( stderr, "init_config_ocs: objectclass \"%s\": %s, %s\n",
523                                 ocs[i].co_def, ldap_scherr2str(code), err );
524                         return code;
525                 }
526                 code = oc_add(oc,0,NULL,&err);
527                 if ( code && code != SLAP_SCHERR_CLASS_DUP ) {
528                         fprintf( stderr, "init_config_ocs: objectclass \"%s\": %s, %s\n",
529                                 ocs[i].co_def, scherr2str(code), err );
530                         ldap_objectclass_free(oc);
531                         return code;
532                 }
533                 ocs[i].co_oc = oc_find(oc->oc_names[0]);
534                 if ( code )
535                         ldap_objectclass_free(oc);
536                 else
537                         ldap_memfree(oc);
538         }
539         return 0;
540 }
541
542 /* Split an LDIF line into space-separated tokens. Words may be grouped
543  * by quotes. A quoted string may begin in the middle of a word, but must
544  * end at the end of the word (be followed by whitespace or EOS). Any other
545  * quotes are passed through unchanged. All other characters are passed
546  * through unchanged.
547  */
548 static char *
549 strtok_quote_ldif( char **line )
550 {
551         char *beg, *ptr, *quote=NULL;
552         int inquote=0;
553
554         ptr = *line;
555
556         if ( !ptr || !*ptr )
557                 return NULL;
558
559         while( isspace( (unsigned char) *ptr )) ptr++;
560
561         if ( *ptr == '"' ) {
562                 inquote = 1;
563                 ptr++;
564         }
565
566         beg = ptr;
567
568         for (;*ptr;ptr++) {
569                 if ( *ptr == '"' ) {
570                         if ( inquote && ( !ptr[1] || isspace((unsigned char) ptr[1]))) {
571                                 *ptr++ = '\0';
572                                 break;
573                         }
574                         inquote = 1;
575                         quote = ptr;
576                         continue;
577                 }
578                 if ( inquote )
579                         continue;
580                 if ( isspace( (unsigned char) *ptr )) {
581                         *ptr++ = '\0';
582                         break;
583                 }
584         }
585         if ( quote ) {
586                 while ( quote < ptr ) {
587                         *quote = quote[1];
588                         quote++;
589                 }
590         }
591         if ( !*ptr ) {
592                 *line = NULL;
593         } else {
594                 while ( isspace( (unsigned char) *ptr )) ptr++;
595                 *line = ptr;
596         }
597         return beg;
598 }
599
600 static void
601 config_parse_ldif( ConfigArgs *c )
602 {
603         char *next;
604         c->tline = ch_strdup(c->line);
605         next = c->tline;
606
607         while ((c->argv[c->argc] = strtok_quote_ldif( &next )) != NULL) {
608                 c->argc++;
609                 if ( c->argc >= c->argv_size ) {
610                         char **tmp = ch_realloc( c->argv, (c->argv_size + ARGS_STEP) *
611                                 sizeof( *c->argv ));
612                         c->argv = tmp;
613                         c->argv_size += ARGS_STEP;
614                 }
615         }
616         c->argv[c->argc] = NULL;
617 }
618
619 int
620 config_parse_vals(ConfigTable *ct, ConfigArgs *c, int valx)
621 {
622         int     rc = 0;
623
624         snprintf( c->log, sizeof( c->log ), "%s: value #%d",
625                 ct->ad->ad_cname.bv_val, valx );
626         c->argc = 1;
627         c->argv[0] = ct->ad->ad_cname.bv_val;
628
629         if ( ( ct->arg_type & ARG_QUOTE ) && c->line[ 0 ] != '"' ) {
630                 c->argv[c->argc] = c->line;
631                 c->argc++;
632                 c->argv[c->argc] = NULL;
633                 c->tline = NULL;
634         } else {
635                 config_parse_ldif( c );
636         }
637         rc = config_check_vals( ct, c, 1 );
638         ch_free( c->tline );
639         c->tline = NULL;
640
641         if ( rc )
642                 rc = LDAP_CONSTRAINT_VIOLATION;
643
644         return rc;
645 }
646
647 int
648 config_parse_add(ConfigTable *ct, ConfigArgs *c)
649 {
650         int     rc = 0;
651
652         snprintf( c->log, sizeof( c->log ), "%s: value #%d",
653                 ct->ad->ad_cname.bv_val, c->valx );
654         c->argc = 1;
655         c->argv[0] = ct->ad->ad_cname.bv_val;
656
657         if ( ( ct->arg_type & ARG_QUOTE ) && c->line[ 0 ] != '"' ) {
658                 c->argv[c->argc] = c->line;
659                 c->argc++;
660                 c->argv[c->argc] = NULL;
661                 c->tline = NULL;
662         } else {
663                 config_parse_ldif( c );
664         }
665         c->op = LDAP_MOD_ADD;
666         rc = config_add_vals( ct, c );
667         ch_free( c->tline );
668
669         return rc;
670 }
671
672 int
673 read_config_file(const char *fname, int depth, ConfigArgs *cf, ConfigTable *cft)
674 {
675         FILE *fp;
676         ConfigTable *ct;
677         ConfigArgs *c;
678         int rc;
679         struct stat s;
680
681         c = ch_calloc( 1, sizeof( ConfigArgs ) );
682         if ( c == NULL ) {
683                 return 1;
684         }
685
686         if ( depth ) {
687                 memcpy( c, cf, sizeof( ConfigArgs ) );
688         } else {
689                 c->depth = depth; /* XXX */
690                 c->bi = NULL;
691                 c->be = NULL;
692         }
693
694         c->valx = -1;
695         c->fname = fname;
696         init_config_argv( c );
697
698         if ( stat( fname, &s ) != 0 ) {
699                 ldap_syslog = 1;
700                 Debug(LDAP_DEBUG_ANY,
701                     "could not stat config file \"%s\": %s (%d)\n",
702                     fname, strerror(errno), errno);
703                 ch_free( c );
704                 return(1);
705         }
706
707         if ( !S_ISREG( s.st_mode ) ) {
708                 ldap_syslog = 1;
709                 Debug(LDAP_DEBUG_ANY,
710                     "regular file expected, got \"%s\"\n",
711                     fname, 0, 0 );
712                 ch_free( c );
713                 return(1);
714         }
715
716         fp = fopen( fname, "r" );
717         if ( fp == NULL ) {
718                 ldap_syslog = 1;
719                 Debug(LDAP_DEBUG_ANY,
720                     "could not open config file \"%s\": %s (%d)\n",
721                     fname, strerror(errno), errno);
722                 ch_free( c );
723                 return(1);
724         }
725
726         Debug(LDAP_DEBUG_CONFIG, "reading config file %s\n", fname, 0, 0);
727
728         fp_getline_init(c);
729
730         c->tline = NULL;
731
732         while ( fp_getline( fp, c ) ) {
733                 /* skip comments and blank lines */
734                 if ( c->line[0] == '#' || c->line[0] == '\0' ) {
735                         continue;
736                 }
737
738                 snprintf( c->log, sizeof( c->log ), "%s: line %d",
739                                 c->fname, c->lineno );
740
741                 c->argc = 0;
742                 ch_free( c->tline );
743                 if ( fp_parse_line( c ) ) {
744                         rc = 1;
745                         goto done;
746                 }
747
748                 if ( c->argc < 1 ) {
749                         Debug( LDAP_DEBUG_ANY, "%s: bad config line.\n",
750                                 c->log, 0, 0);
751                         rc = 1;
752                         goto done;
753                 }
754
755                 c->op = SLAP_CONFIG_ADD;
756
757                 ct = config_find_keyword( cft, c );
758                 if ( ct ) {
759                         rc = config_add_vals( ct, c );
760                         if ( !rc ) continue;
761
762                         if ( rc & ARGS_USERLAND ) {
763                                 /* XXX a usertype would be opaque here */
764                                 Debug(LDAP_DEBUG_CONFIG, "%s: unknown user type <%s>\n",
765                                         c->log, c->argv[0], 0);
766                                 rc = 1;
767                                 goto done;
768
769                         } else if ( rc == ARG_BAD_CONF ) {
770                                 rc = 1;
771                                 goto done;
772                         }
773                         
774                 } else if ( c->bi && !c->be ) {
775                         rc = SLAP_CONF_UNKNOWN;
776                         if ( c->bi->bi_cf_ocs ) {
777                                 ct = config_find_keyword( c->bi->bi_cf_ocs->co_table, c );
778                                 if ( ct ) {
779                                         rc = config_add_vals( ct, c );
780                                 }
781                         }
782                         if ( c->bi->bi_config && rc == SLAP_CONF_UNKNOWN ) {
783                                 rc = (*c->bi->bi_config)(c->bi, c->fname, c->lineno,
784                                         c->argc, c->argv);
785                         }
786                         if ( rc ) {
787                                 switch(rc) {
788                                 case SLAP_CONF_UNKNOWN:
789                                         Debug( LDAP_DEBUG_ANY, "%s: unknown directive "
790                                                 "<%s> inside backend info definition.\n",
791                                                 c->log, *c->argv, 0);
792                                 default:
793                                         rc = 1;
794                                         goto done;
795                                 }
796                         }
797
798                 } else if ( c->be && c->be != frontendDB ) {
799                         rc = SLAP_CONF_UNKNOWN;
800                         if ( c->be->be_cf_ocs ) {
801                                 ct = config_find_keyword( c->be->be_cf_ocs->co_table, c );
802                                 if ( ct ) {
803                                         rc = config_add_vals( ct, c );
804                                 }
805                         }
806                         if ( c->be->be_config && rc == SLAP_CONF_UNKNOWN ) {
807                                 rc = (*c->be->be_config)(c->be, c->fname, c->lineno,
808                                         c->argc, c->argv);
809                         }
810                         if ( rc == SLAP_CONF_UNKNOWN && SLAP_ISGLOBALOVERLAY( frontendDB ) )
811                         {
812                                 /* global overlays may need 
813                                  * definitions inside other databases...
814                                  */
815                                 rc = (*frontendDB->be_config)( frontendDB,
816                                         c->fname, (int)c->lineno, c->argc, c->argv );
817                         }
818
819                         switch ( rc ) {
820                         case 0:
821                                 break;
822
823                         case SLAP_CONF_UNKNOWN:
824                                 Debug( LDAP_DEBUG_ANY, "%s: unknown directive "
825                                         "<%s> inside backend database definition.\n",
826                                         c->log, *c->argv, 0);
827                                 
828                         default:
829                                 rc = 1;
830                                 goto done;
831                         }
832
833                 } else if ( frontendDB->be_config ) {
834                         rc = (*frontendDB->be_config)( frontendDB,
835                                 c->fname, (int)c->lineno, c->argc, c->argv);
836                         if ( rc ) {
837                                 switch(rc) {
838                                 case SLAP_CONF_UNKNOWN:
839                                         Debug( LDAP_DEBUG_ANY, "%s: unknown directive "
840                                                 "<%s> inside global database definition.\n",
841                                                 c->log, *c->argv, 0);
842
843                                 default:
844                                         rc = 1;
845                                         goto done;
846                                 }
847                         }
848                         
849                 } else {
850                         Debug( LDAP_DEBUG_ANY, "%s: unknown directive "
851                                 "<%s> outside backend info and database definitions.\n",
852                                 c->log, *c->argv, 0);
853                         rc = 1;
854                         goto done;
855                 }
856         }
857
858         rc = 0;
859
860 done:
861         ch_free(c->tline);
862         fclose(fp);
863         ch_free(c->argv);
864         ch_free(c);
865         return(rc);
866 }
867
868 /* restrictops, allows, disallows, requires, loglevel */
869
870 int
871 verb_to_mask(const char *word, slap_verbmasks *v) {
872         int i;
873         for(i = 0; !BER_BVISNULL(&v[i].word); i++) {
874                 if(!strcasecmp(word, v[i].word.bv_val)) break;
875         }
876         return(i);
877 }
878
879 int
880 verbs_to_mask(int argc, char *argv[], slap_verbmasks *v, slap_mask_t *m) {
881         int i, j;
882         for(i = 1; i < argc; i++) {
883                 j = verb_to_mask(argv[i], v);
884                 if(BER_BVISNULL(&v[j].word)) return i;
885                 while (!v[j].mask) j--;
886                 *m |= v[j].mask;
887         }
888         return(0);
889 }
890
891 /* Mask keywords that represent multiple bits should occur before single
892  * bit keywords in the verbmasks array.
893  */
894 int
895 mask_to_verbs(slap_verbmasks *v, slap_mask_t m, BerVarray *bva) {
896         int i, rc = 1;
897
898         if (m) {
899                 for (i=0; !BER_BVISNULL(&v[i].word); i++) {
900                         if (!v[i].mask) continue;
901                         if (( m & v[i].mask ) == v[i].mask ) {
902                                 value_add_one( bva, &v[i].word );
903                                 rc = 0;
904                                 m ^= v[i].mask;
905                                 if ( !m ) break;
906                         }
907                 }
908         }
909         return rc;
910 }
911
912 int
913 slap_verbmasks_init( slap_verbmasks **vp, slap_verbmasks *v )
914 {
915         int             i;
916
917         assert( *vp == NULL );
918
919         for ( i = 0; !BER_BVISNULL( &v[ i ].word ); i++ ) /* EMPTY */;
920
921         *vp = ch_calloc( i + 1, sizeof( slap_verbmasks ) );
922
923         for ( i = 0; !BER_BVISNULL( &v[ i ].word ); i++ ) {
924                 ber_dupbv( &(*vp)[ i ].word, &v[ i ].word );
925                 *((slap_mask_t *)&(*vp)[ i ].mask) = v[ i ].mask;
926         }
927
928         BER_BVZERO( &(*vp)[ i ].word );
929
930         return 0;               
931 }
932
933 int
934 slap_verbmasks_destroy( slap_verbmasks *v )
935 {
936         int             i;
937
938         assert( v != NULL );
939
940         for ( i = 0; !BER_BVISNULL( &v[ i ].word ); i++ ) {
941                 ch_free( v[ i ].word.bv_val );
942         }
943
944         ch_free( v );
945
946         return 0;
947 }
948
949 int
950 slap_verbmasks_append(
951         slap_verbmasks  **vp,
952         slap_mask_t     m,
953         struct berval   *v,
954         slap_mask_t     *ignore )
955 {
956         int     i;
957
958         if ( !m ) {
959                 return LDAP_OPERATIONS_ERROR;
960         }
961
962         for ( i = 0; !BER_BVISNULL( &(*vp)[ i ].word ); i++ ) {
963                 if ( !(*vp)[ i ].mask ) continue;
964
965                 if ( ignore != NULL ) {
966                         int     j;
967
968                         for ( j = 0; ignore[ j ] != 0; j++ ) {
969                                 if ( (*vp)[ i ].mask == ignore[ j ] ) {
970                                         goto check_next;
971                                 }
972                         }
973                 }
974
975                 if ( ( m & (*vp)[ i ].mask ) == (*vp)[ i ].mask ) {
976                         if ( ber_bvstrcasecmp( v, &(*vp)[ i ].word ) == 0 ) {
977                                 /* already set; ignore */
978                                 return LDAP_SUCCESS;
979                         }
980                         /* conflicts */
981                         return LDAP_TYPE_OR_VALUE_EXISTS;
982                 }
983
984                 if ( m & (*vp)[ i ].mask ) {
985                         /* conflicts */
986                         return LDAP_CONSTRAINT_VIOLATION;
987                 }
988 check_next:;
989         }
990
991         *vp = ch_realloc( *vp, sizeof( slap_verbmasks ) * ( i + 2 ) );
992         ber_dupbv( &(*vp)[ i ].word, v );
993         *((slap_mask_t *)&(*vp)[ i ].mask) = m;
994         BER_BVZERO( &(*vp)[ i + 1 ].word );
995
996         return LDAP_SUCCESS;
997 }
998
999 int
1000 enum_to_verb(slap_verbmasks *v, slap_mask_t m, struct berval *bv) {
1001         int i;
1002
1003         for (i=0; !BER_BVISNULL(&v[i].word); i++) {
1004                 if ( m == v[i].mask ) {
1005                         if ( bv != NULL ) {
1006                                 *bv = v[i].word;
1007                         }
1008                         return i;
1009                 }
1010         }
1011         return -1;
1012 }
1013
1014 static slap_verbmasks tlskey[] = {
1015         { BER_BVC("no"),        SB_TLS_OFF },
1016         { BER_BVC("yes"),       SB_TLS_ON },
1017         { BER_BVC("critical"),  SB_TLS_CRITICAL },
1018         { BER_BVNULL, 0 }
1019 };
1020
1021 static slap_verbmasks methkey[] = {
1022         { BER_BVC("none"),      LDAP_AUTH_NONE },
1023         { BER_BVC("simple"),    LDAP_AUTH_SIMPLE },
1024 #ifdef HAVE_CYRUS_SASL
1025         { BER_BVC("sasl"),      LDAP_AUTH_SASL },
1026 #endif
1027         { BER_BVNULL, 0 }
1028 };
1029
1030 static slap_cf_aux_table bindkey[] = {
1031         { BER_BVC("uri="), offsetof(slap_bindconf, sb_uri), 'b', 1, NULL },
1032         { BER_BVC("starttls="), offsetof(slap_bindconf, sb_tls), 'd', 0, tlskey },
1033         { BER_BVC("bindmethod="), offsetof(slap_bindconf, sb_method), 'd', 0, methkey },
1034         { BER_BVC("binddn="), offsetof(slap_bindconf, sb_binddn), 'b', 1, NULL },
1035         { BER_BVC("credentials="), offsetof(slap_bindconf, sb_cred), 'b', 1, NULL },
1036         { BER_BVC("saslmech="), offsetof(slap_bindconf, sb_saslmech), 'b', 0, NULL },
1037         { BER_BVC("secprops="), offsetof(slap_bindconf, sb_secprops), 's', 0, NULL },
1038         { BER_BVC("realm="), offsetof(slap_bindconf, sb_realm), 'b', 0, NULL },
1039         { BER_BVC("authcID="), offsetof(slap_bindconf, sb_authcId), 'b', 0, NULL },
1040         { BER_BVC("authzID="), offsetof(slap_bindconf, sb_authzId), 'b', 1, NULL },
1041 #ifdef HAVE_TLS
1042         { BER_BVC("tls_cert="), offsetof(slap_bindconf, sb_tls_cert), 's', 1, NULL },
1043         { BER_BVC("tls_key="), offsetof(slap_bindconf, sb_tls_key), 's', 1, NULL },
1044         { BER_BVC("tls_cacert="), offsetof(slap_bindconf, sb_tls_cacert), 's', 1, NULL },
1045         { BER_BVC("tls_cacertdir="), offsetof(slap_bindconf, sb_tls_cacertdir), 's', 1, NULL },
1046         { BER_BVC("tls_reqcert="), offsetof(slap_bindconf, sb_tls_reqcert), 's', 1, NULL },
1047         { BER_BVC("tls_cipher_suite="), offsetof(slap_bindconf, sb_tls_cipher_suite), 's', 1, NULL },
1048 #ifdef HAVE_OPENSSL_CRL
1049         { BER_BVC("tls_crlcheck="), offsetof(slap_bindconf, sb_tls_crlcheck), 's', 1, NULL },
1050 #endif
1051 #endif
1052         { BER_BVNULL, 0, 0, 0, NULL }
1053 };
1054
1055 int
1056 slap_cf_aux_table_parse( const char *word, void *dst, slap_cf_aux_table *tab0, LDAP_CONST char *tabmsg )
1057 {
1058         int rc = 0;
1059         slap_cf_aux_table *tab;
1060
1061         for (tab = tab0; !BER_BVISNULL(&tab->key); tab++ ) {
1062                 if ( !strncasecmp( word, tab->key.bv_val, tab->key.bv_len )) {
1063                         char **cptr;
1064                         int *iptr, j;
1065                         unsigned *uptr;
1066                         long *lptr;
1067                         unsigned long *ulptr;
1068                         struct berval *bptr;
1069                         const char *val = word + tab->key.bv_len;
1070
1071                         switch ( tab->type ) {
1072                         case 's':
1073                                 cptr = (char **)((char *)dst + tab->off);
1074                                 *cptr = ch_strdup( val );
1075                                 break;
1076
1077                         case 'b':
1078                                 bptr = (struct berval *)((char *)dst + tab->off);
1079                                 ber_str2bv( val, 0, 1, bptr );
1080                                 break;
1081
1082                         case 'd':
1083                                 assert( tab->aux != NULL );
1084                                 iptr = (int *)((char *)dst + tab->off);
1085
1086                                 rc = 1;
1087                                 for ( j = 0; !BER_BVISNULL( &tab->aux[j].word ); j++ ) {
1088                                         if ( !strcasecmp( val, tab->aux[j].word.bv_val ) ) {
1089                                                 *iptr = tab->aux[j].mask;
1090                                                 rc = 0;
1091                                         }
1092                                 }
1093                                 break;
1094
1095                         case 'i':
1096                                 iptr = (int *)((char *)dst + tab->off);
1097
1098                                 rc = lutil_atoix( iptr, val, 0 );
1099                                 break;
1100
1101                         case 'u':
1102                                 uptr = (unsigned *)((char *)dst + tab->off);
1103
1104                                 rc = lutil_atoux( uptr, val, 0 );
1105                                 break;
1106
1107                         case 'I':
1108                                 lptr = (long *)((char *)dst + tab->off);
1109
1110                                 rc = lutil_atolx( lptr, val, 0 );
1111                                 break;
1112
1113                         case 'U':
1114                                 ulptr = (unsigned long *)((char *)dst + tab->off);
1115
1116                                 rc = lutil_atoulx( ulptr, val, 0 );
1117                                 break;
1118                         }
1119
1120                         if ( rc ) {
1121                                 Debug( LDAP_DEBUG_ANY, "invalid %s value %s\n",
1122                                         tabmsg, word, 0 );
1123                         }
1124                         
1125                         return rc;
1126                 }
1127         }
1128
1129         return rc;
1130 }
1131
1132 int
1133 slap_cf_aux_table_unparse( void *src, struct berval *bv, slap_cf_aux_table *tab0 )
1134 {
1135         char buf[BUFSIZ], *ptr;
1136         slap_cf_aux_table *tab;
1137         struct berval tmp;
1138
1139         ptr = buf;
1140         for (tab = tab0; !BER_BVISNULL(&tab->key); tab++ ) {
1141                 char **cptr;
1142                 int *iptr, i;
1143                 unsigned *uptr;
1144                 long *lptr;
1145                 unsigned long *ulptr;
1146                 struct berval *bptr;
1147
1148                 cptr = (char **)((char *)src + tab->off);
1149
1150                 switch ( tab->type ) {
1151                 case 'b':
1152                         bptr = (struct berval *)((char *)src + tab->off);
1153                         cptr = &bptr->bv_val;
1154                 case 's':
1155                         if ( *cptr ) {
1156                                 *ptr++ = ' ';
1157                                 ptr = lutil_strcopy( ptr, tab->key.bv_val );
1158                                 if ( tab->quote ) *ptr++ = '"';
1159                                 ptr = lutil_strcopy( ptr, *cptr );
1160                                 if ( tab->quote ) *ptr++ = '"';
1161                         }
1162                         break;
1163
1164                 case 'd':
1165                         assert( tab->aux != NULL );
1166                         iptr = (int *)((char *)src + tab->off);
1167                 
1168                         for ( i = 0; !BER_BVISNULL( &tab->aux[i].word ); i++ ) {
1169                                 if ( *iptr == tab->aux[i].mask ) {
1170                                         *ptr++ = ' ';
1171                                         ptr = lutil_strcopy( ptr, tab->key.bv_val );
1172                                         ptr = lutil_strcopy( ptr, tab->aux[i].word.bv_val );
1173                                         break;
1174                                 }
1175                         }
1176                         break;
1177
1178                 case 'i':
1179                         iptr = (int *)((char *)src + tab->off);
1180                         *ptr++ = ' ';
1181                         ptr = lutil_strcopy( ptr, tab->key.bv_val );
1182                         ptr += snprintf( ptr, sizeof( buf ) - ( ptr - buf ), "%d", *iptr );
1183                         break;
1184
1185                 case 'u':
1186                         uptr = (unsigned *)((char *)src + tab->off);
1187                         *ptr++ = ' ';
1188                         ptr = lutil_strcopy( ptr, tab->key.bv_val );
1189                         ptr += snprintf( ptr, sizeof( buf ) - ( ptr - buf ), "%u", *uptr );
1190                         break;
1191
1192                 case 'I':
1193                         lptr = (long *)((char *)src + tab->off);
1194                         *ptr++ = ' ';
1195                         ptr = lutil_strcopy( ptr, tab->key.bv_val );
1196                         ptr += snprintf( ptr, sizeof( buf ) - ( ptr - buf ), "%ld", *lptr );
1197                         break;
1198
1199                 case 'U':
1200                         ulptr = (unsigned long *)((char *)src + tab->off);
1201                         *ptr++ = ' ';
1202                         ptr = lutil_strcopy( ptr, tab->key.bv_val );
1203                         ptr += snprintf( ptr, sizeof( buf ) - ( ptr - buf ), "%lu", *ulptr );
1204                         break;
1205
1206                 default:
1207                         assert( 0 );
1208                 }
1209         }
1210         tmp.bv_val = buf;
1211         tmp.bv_len = ptr - buf;
1212         ber_dupbv( bv, &tmp );
1213         return 0;
1214 }
1215
1216 int
1217 bindconf_parse( const char *word, slap_bindconf *bc )
1218 {
1219         return slap_cf_aux_table_parse( word, bc, bindkey, "bind config" );
1220 }
1221
1222 int
1223 bindconf_unparse( slap_bindconf *bc, struct berval *bv )
1224 {
1225         return slap_cf_aux_table_unparse( bc, bv, bindkey );
1226 }
1227
1228 void bindconf_free( slap_bindconf *bc ) {
1229         if ( !BER_BVISNULL( &bc->sb_uri ) ) {
1230                 ch_free( bc->sb_uri.bv_val );
1231                 BER_BVZERO( &bc->sb_uri );
1232         }
1233         if ( !BER_BVISNULL( &bc->sb_binddn ) ) {
1234                 ch_free( bc->sb_binddn.bv_val );
1235                 BER_BVZERO( &bc->sb_binddn );
1236         }
1237         if ( !BER_BVISNULL( &bc->sb_cred ) ) {
1238                 ch_free( bc->sb_cred.bv_val );
1239                 BER_BVZERO( &bc->sb_cred );
1240         }
1241         if ( !BER_BVISNULL( &bc->sb_saslmech ) ) {
1242                 ch_free( bc->sb_saslmech.bv_val );
1243                 BER_BVZERO( &bc->sb_saslmech );
1244         }
1245         if ( bc->sb_secprops ) {
1246                 ch_free( bc->sb_secprops );
1247                 bc->sb_secprops = NULL;
1248         }
1249         if ( !BER_BVISNULL( &bc->sb_realm ) ) {
1250                 ch_free( bc->sb_realm.bv_val );
1251                 BER_BVZERO( &bc->sb_realm );
1252         }
1253         if ( !BER_BVISNULL( &bc->sb_authcId ) ) {
1254                 ch_free( bc->sb_authcId.bv_val );
1255                 BER_BVZERO( &bc->sb_authcId );
1256         }
1257         if ( !BER_BVISNULL( &bc->sb_authzId ) ) {
1258                 ch_free( bc->sb_authzId.bv_val );
1259                 BER_BVZERO( &bc->sb_authzId );
1260         }
1261 #ifdef HAVE_TLS
1262         if ( bc->sb_tls_ctx ) {
1263                 SSL_CTX_free( bc->sb_tls_ctx );
1264                 bc->sb_tls_ctx = NULL;
1265         }
1266         if ( bc->sb_tls_cert ) {
1267                 ch_free( bc->sb_tls_cert );
1268                 bc->sb_tls_cert = NULL;
1269         }
1270         if ( bc->sb_tls_key ) {
1271                 ch_free( bc->sb_tls_key );
1272                 bc->sb_tls_key = NULL;
1273         }
1274         if ( bc->sb_tls_cacert ) {
1275                 ch_free( bc->sb_tls_cacert );
1276                 bc->sb_tls_cacert = NULL;
1277         }
1278         if ( bc->sb_tls_cacertdir ) {
1279                 ch_free( bc->sb_tls_cacertdir );
1280                 bc->sb_tls_cacertdir = NULL;
1281         }
1282         if ( bc->sb_tls_reqcert ) {
1283                 ch_free( bc->sb_tls_reqcert );
1284                 bc->sb_tls_reqcert = NULL;
1285         }
1286         if ( bc->sb_tls_cipher_suite ) {
1287                 ch_free( bc->sb_tls_cipher_suite );
1288                 bc->sb_tls_cipher_suite = NULL;
1289         }
1290 #ifdef HAVE_OPENSSL_CRL
1291         if ( bc->sb_tls_crlcheck ) {
1292                 ch_free( bc->sb_tls_crlcheck );
1293                 bc->sb_tls_crlcheck = NULL;
1294         }
1295 #endif
1296 #endif
1297 }
1298
1299 static struct {
1300         const char *key;
1301         size_t offset;
1302         int opt;
1303 } bindtlsopts[] = {
1304         { "tls_cert", offsetof(slap_bindconf, sb_tls_cert), LDAP_OPT_X_TLS_CERTFILE },
1305         { "tls_key", offsetof(slap_bindconf, sb_tls_key), LDAP_OPT_X_TLS_KEYFILE },
1306         { "tls_cacert", offsetof(slap_bindconf, sb_tls_cacert), LDAP_OPT_X_TLS_CACERTFILE },
1307         { "tls_cacertdir", offsetof(slap_bindconf, sb_tls_cacertdir), LDAP_OPT_X_TLS_CACERTDIR },
1308         { "tls_cipher_suite", offsetof(slap_bindconf, sb_tls_cipher_suite), LDAP_OPT_X_TLS_CIPHER_SUITE },
1309         {0, 0}
1310 };
1311
1312 int bindconf_tls_set( slap_bindconf *bc, LDAP *ld )
1313 {
1314         int i, rc, newctx = 0, res = 0;
1315         char *ptr = (char *)bc, **word;
1316
1317         for (i=0; bindtlsopts[i].opt; i++) {
1318                 word = (char **)(ptr + bindtlsopts[i].offset);
1319                 if ( *word ) {
1320                         rc = ldap_set_option( ld, bindtlsopts[i].opt, *word );
1321                         if ( rc ) {
1322                                 Debug( LDAP_DEBUG_ANY,
1323                                         "bindconf_tls_set: failed to set %s to %s\n",
1324                                                 bindtlsopts[i].key, *word, 0 );
1325                                 res = -1;
1326                         } else
1327                                 newctx = 1;
1328                 }
1329         }
1330         if ( bc->sb_tls_reqcert ) {
1331                 rc = ldap_int_tls_config( ld, LDAP_OPT_X_TLS_REQUIRE_CERT,
1332                         bc->sb_tls_reqcert );
1333                 if ( rc ) {
1334                         Debug( LDAP_DEBUG_ANY,
1335                                 "bindconf_tls_set: failed to set tls_reqcert to %s\n",
1336                                         bc->sb_tls_reqcert, 0, 0 );
1337                         res = -1;
1338                 } else
1339                         newctx = 1;
1340         }
1341 #ifdef HAVE_OPENSSL_CRL
1342         if ( bc->sb_tls_crlcheck ) {
1343                 rc = ldap_int_tls_config( ld, LDAP_OPT_X_TLS_CRLCHECK,
1344                         bc->sb_tls_crlcheck );
1345                 if ( rc ) {
1346                         Debug( LDAP_DEBUG_ANY,
1347                                 "bindconf_tls_set: failed to set tls_crlcheck to %s\n",
1348                                         bc->sb_tls_crlcheck, 0, 0 );
1349                         res = -1;
1350                 } else
1351                         newctx = 1;
1352         }
1353 #endif
1354         if ( newctx ) {
1355                 int opt = 0;
1356                 rc = ldap_set_option( ld, LDAP_OPT_X_TLS_NEWCTX, &opt );
1357                 if ( rc )
1358                         res = rc;
1359                 else
1360                         ldap_get_option( ld, LDAP_OPT_X_TLS_CTX, &bc->sb_tls_ctx );
1361         }
1362         
1363         return res;
1364 }
1365
1366 /* -------------------------------------- */
1367
1368
1369 static char *
1370 strtok_quote( char *line, char *sep, char **quote_ptr )
1371 {
1372         int             inquote;
1373         char            *tmp;
1374         static char     *next;
1375
1376         *quote_ptr = NULL;
1377         if ( line != NULL ) {
1378                 next = line;
1379         }
1380         while ( *next && strchr( sep, *next ) ) {
1381                 next++;
1382         }
1383
1384         if ( *next == '\0' ) {
1385                 next = NULL;
1386                 return( NULL );
1387         }
1388         tmp = next;
1389
1390         for ( inquote = 0; *next; ) {
1391                 switch ( *next ) {
1392                 case '"':
1393                         if ( inquote ) {
1394                                 inquote = 0;
1395                         } else {
1396                                 inquote = 1;
1397                         }
1398                         AC_MEMCPY( next, next + 1, strlen( next + 1 ) + 1 );
1399                         break;
1400
1401                 case '\\':
1402                         if ( next[1] )
1403                                 AC_MEMCPY( next,
1404                                             next + 1, strlen( next + 1 ) + 1 );
1405                         next++;         /* dont parse the escaped character */
1406                         break;
1407
1408                 default:
1409                         if ( ! inquote ) {
1410                                 if ( strchr( sep, *next ) != NULL ) {
1411                                         *quote_ptr = next;
1412                                         *next++ = '\0';
1413                                         return( tmp );
1414                                 }
1415                         }
1416                         next++;
1417                         break;
1418                 }
1419         }
1420
1421         return( tmp );
1422 }
1423
1424 static char     buf[BUFSIZ];
1425 static char     *line;
1426 static size_t lmax, lcur;
1427
1428 #define CATLINE( buf ) \
1429         do { \
1430                 size_t len = strlen( buf ); \
1431                 while ( lcur + len + 1 > lmax ) { \
1432                         lmax += BUFSIZ; \
1433                         line = (char *) ch_realloc( line, lmax ); \
1434                 } \
1435                 strcpy( line + lcur, buf ); \
1436                 lcur += len; \
1437         } while( 0 )
1438
1439 static void
1440 fp_getline_init(ConfigArgs *c) {
1441         c->lineno = -1;
1442         buf[0] = '\0';
1443 }
1444
1445 static int
1446 fp_getline( FILE *fp, ConfigArgs *c )
1447 {
1448         char    *p;
1449
1450         lcur = 0;
1451         CATLINE(buf);
1452         c->lineno++;
1453
1454         /* avoid stack of bufs */
1455         if ( strncasecmp( line, "include", STRLENOF( "include" ) ) == 0 ) {
1456                 buf[0] = '\0';
1457                 c->line = line;
1458                 return(1);
1459         }
1460
1461         while ( fgets( buf, sizeof( buf ), fp ) ) {
1462                 p = strchr( buf, '\n' );
1463                 if ( p ) {
1464                         if ( p > buf && p[-1] == '\r' ) {
1465                                 --p;
1466                         }
1467                         *p = '\0';
1468                 }
1469                 /* XXX ugly */
1470                 c->line = line;
1471                 if ( line[0]
1472                                 && ( p = line + strlen( line ) - 1 )[0] == '\\'
1473                                 && p[-1] != '\\' )
1474                 {
1475                         p[0] = '\0';
1476                         lcur--;
1477                         
1478                 } else {
1479                         if ( !isspace( (unsigned char)buf[0] ) ) {
1480                                 return(1);
1481                         }
1482                         buf[0] = ' ';
1483                 }
1484                 CATLINE(buf);
1485                 c->lineno++;
1486         }
1487
1488         buf[0] = '\0';
1489         c->line = line;
1490         return(line[0] ? 1 : 0);
1491 }
1492
1493 static int
1494 fp_parse_line(ConfigArgs *c)
1495 {
1496         char *token;
1497         static char *const hide[] = {
1498                 "rootpw", "replica", "syncrepl",  /* in slapd */
1499                 "acl-bind", "acl-method", "idassert-bind",  /* in back-ldap */
1500                 "acl-passwd", "bindpw",  /* in back-<ldap/meta> */
1501                 "pseudorootpw",  /* in back-meta */
1502                 "dbpasswd",  /* in back-sql */
1503                 NULL
1504         };
1505         char *quote_ptr;
1506         int i = (int)(sizeof(hide)/sizeof(hide[0])) - 1;
1507
1508         c->tline = ch_strdup(c->line);
1509         token = strtok_quote(c->tline, " \t", &quote_ptr);
1510
1511         if(token) for(i = 0; hide[i]; i++) if(!strcasecmp(token, hide[i])) break;
1512         if(quote_ptr) *quote_ptr = ' ';
1513         Debug(LDAP_DEBUG_CONFIG, "line %d (%s%s)\n", c->lineno,
1514                 hide[i] ? hide[i] : c->line, hide[i] ? " ***" : "");
1515         if(quote_ptr) *quote_ptr = '\0';
1516
1517         for(;; token = strtok_quote(NULL, " \t", &quote_ptr)) {
1518                 if(c->argc >= c->argv_size) {
1519                         char **tmp;
1520                         tmp = ch_realloc(c->argv, (c->argv_size + ARGS_STEP) * sizeof(*c->argv));
1521                         if(!tmp) {
1522                                 Debug(LDAP_DEBUG_ANY, "line %d: out of memory\n", c->lineno, 0, 0);
1523                                 return -1;
1524                         }
1525                         c->argv = tmp;
1526                         c->argv_size += ARGS_STEP;
1527                 }
1528                 if(token == NULL)
1529                         break;
1530                 c->argv[c->argc++] = token;
1531         }
1532         c->argv[c->argc] = NULL;
1533         return(0);
1534 }
1535
1536 void
1537 config_destroy( )
1538 {
1539         ucdata_unload( UCDATA_ALL );
1540         if ( frontendDB ) {
1541                 /* NOTE: in case of early exit, frontendDB can be NULL */
1542                 if ( frontendDB->be_schemandn.bv_val )
1543                         free( frontendDB->be_schemandn.bv_val );
1544                 if ( frontendDB->be_schemadn.bv_val )
1545                         free( frontendDB->be_schemadn.bv_val );
1546                 if ( frontendDB->be_acl )
1547                         acl_destroy( frontendDB->be_acl, NULL );
1548         }
1549         free( line );
1550         if ( slapd_args_file )
1551                 free ( slapd_args_file );
1552         if ( slapd_pid_file )
1553                 free ( slapd_pid_file );
1554         if ( default_passwd_hash )
1555                 ldap_charray_free( default_passwd_hash );
1556 }
1557
1558 char **
1559 slap_str2clist( char ***out, char *in, const char *brkstr )
1560 {
1561         char    *str;
1562         char    *s;
1563         char    *lasts;
1564         int     i, j;
1565         char    **new;
1566
1567         /* find last element in list */
1568         for (i = 0; *out && (*out)[i]; i++);
1569
1570         /* protect the input string from strtok */
1571         str = ch_strdup( in );
1572
1573         if ( *str == '\0' ) {
1574                 free( str );
1575                 return( *out );
1576         }
1577
1578         /* Count words in string */
1579         j=1;
1580         for ( s = str; *s; s++ ) {
1581                 if ( strchr( brkstr, *s ) != NULL ) {
1582                         j++;
1583                 }
1584         }
1585
1586         *out = ch_realloc( *out, ( i + j + 1 ) * sizeof( char * ) );
1587         new = *out + i;
1588         for ( s = ldap_pvt_strtok( str, brkstr, &lasts );
1589                 s != NULL;
1590                 s = ldap_pvt_strtok( NULL, brkstr, &lasts ) )
1591         {
1592                 *new = ch_strdup( s );
1593                 new++;
1594         }
1595
1596         *new = NULL;
1597         free( str );
1598         return( *out );
1599 }
1600
1601 int config_generic_wrapper( Backend *be, const char *fname, int lineno,
1602         int argc, char **argv )
1603 {
1604         ConfigArgs c = { 0 };
1605         ConfigTable *ct;
1606         int rc;
1607
1608         c.be = be;
1609         c.fname = fname;
1610         c.lineno = lineno;
1611         c.argc = argc;
1612         c.argv = argv;
1613         c.valx = -1;
1614         c.line = line;
1615         c.op = SLAP_CONFIG_ADD;
1616         snprintf( c.log, sizeof( c.log ), "%s: line %d", fname, lineno );
1617
1618         rc = SLAP_CONF_UNKNOWN;
1619         ct = config_find_keyword( be->be_cf_ocs->co_table, &c );
1620         if ( ct )
1621                 rc = config_add_vals( ct, &c );
1622         return rc;
1623 }