]> git.sur5r.net Git - openldap/blob - servers/slapd/config.c
4ca60728b6dea093d3a4d055f851afa0a33b33e9
[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-2005 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 "slap.h"
38 #ifdef LDAP_SLAPI
39 #include "slapi/slapi.h"
40 #endif
41 #include "lutil.h"
42 #ifdef HAVE_LIMITS_H
43 #include <limits.h>
44 #endif /* HAVE_LIMITS_H */
45 #ifndef PATH_MAX
46 #define PATH_MAX 4096
47 #endif /* ! PATH_MAX */
48 #include "config.h"
49
50 #define ARGS_STEP       512
51
52 /*
53  * defaults for various global variables
54  */
55 slap_mask_t             global_allows = 0;
56 slap_mask_t             global_disallows = 0;
57 int             global_gentlehup = 0;
58 int             global_idletimeout = 0;
59 char    *global_host = NULL;
60 char    *global_realm = NULL;
61 char            *ldap_srvtab = "";
62 char            **default_passwd_hash = NULL;
63 struct berval default_search_base = BER_BVNULL;
64 struct berval default_search_nbase = BER_BVNULL;
65
66 ber_len_t sockbuf_max_incoming = SLAP_SB_MAX_INCOMING_DEFAULT;
67 ber_len_t sockbuf_max_incoming_auth= SLAP_SB_MAX_INCOMING_AUTH;
68
69 int     slap_conn_max_pending = SLAP_CONN_MAX_PENDING_DEFAULT;
70 int     slap_conn_max_pending_auth = SLAP_CONN_MAX_PENDING_AUTH;
71
72 char   *slapd_pid_file  = NULL;
73 char   *slapd_args_file = NULL;
74
75 int use_reverse_lookup = 0;
76
77 #ifdef LDAP_SLAPI
78 int slapi_plugins_used = 0;
79 #endif
80
81 static int fp_getline(FILE *fp, ConfigArgs *c);
82 static void fp_getline_init(ConfigArgs *c);
83 static int fp_parse_line(ConfigArgs *c);
84
85 static char     *strtok_quote(char *line, char *sep, char **quote_ptr);
86
87 int read_config_file(const char *fname, int depth, ConfigArgs *cf);
88
89 ConfigArgs *
90 new_config_args( BackendDB *be, const char *fname, int lineno, int argc, char **argv )
91 {
92         ConfigArgs *c;
93         c = ch_calloc( 1, sizeof( ConfigArgs ) );
94         if ( c == NULL ) return(NULL);
95         c->be     = be; 
96         c->fname  = fname;
97         c->argc   = argc;
98         c->argv   = argv; 
99         c->lineno = lineno;
100         snprintf( c->log, sizeof( c->log ), "%s: line %lu", fname, lineno );
101         return(c);
102 }
103
104 void
105 init_config_argv( ConfigArgs *c )
106 {
107         c->argv = ch_calloc( ARGS_STEP + 1, sizeof( *c->argv ) );
108         c->argv_size = ARGS_STEP + 1;
109 }
110
111 ConfigTable *config_find_keyword(ConfigTable *Conf, ConfigArgs *c) {
112         int i;
113
114         for(i = 0; Conf[i].name; i++)
115                 if( (Conf[i].length && (!strncasecmp(c->argv[0], Conf[i].name, Conf[i].length))) ||
116                         (!strcasecmp(c->argv[0], Conf[i].name)) ) break;
117         if ( !Conf[i].name ) return NULL;
118         return Conf+i;
119 }
120
121 int config_check_vals(ConfigTable *Conf, ConfigArgs *c, int check_only ) {
122         int i, rc, arg_user, arg_type, iarg;
123         long larg;
124         ber_len_t barg;
125         void *ptr;
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                 Debug(LDAP_DEBUG_CONFIG, "%s: keyword <%s> missing <%s> argument\n",
139                         c->log, Conf->name, Conf->what);
140                 return(ARG_BAD_CONF);
141         }
142         if(Conf->max_args && (c->argc > Conf->max_args)) {
143                 Debug(LDAP_DEBUG_CONFIG, "%s: extra cruft after <%s> in <%s> line (ignored)\n",
144                         c->log, Conf->what, Conf->name);
145         }
146         if((arg_type & ARG_DB) && !c->be) {
147                 Debug(LDAP_DEBUG_CONFIG, "%s: keyword <%s> allowed only within database declaration\n",
148                         c->log, Conf->name, 0);
149                 return(ARG_BAD_CONF);
150         }
151         if((arg_type & ARG_PRE_BI) && c->bi) {
152                 Debug(LDAP_DEBUG_CONFIG, "%s: keyword <%s> must appear before any backend %sdeclaration\n",
153                         c->log, Conf->name, ((arg_type & ARG_PRE_DB)
154                         ? "or database " : "") );
155                 return(ARG_BAD_CONF);
156         }
157         if((arg_type & ARG_PRE_DB) && c->be && c->be != frontendDB) {
158                 Debug(LDAP_DEBUG_CONFIG, "%s: keyword <%s> must appear before any database declaration\n",
159                         c->log, Conf->name, 0);
160                 return(ARG_BAD_CONF);
161         }
162         if((arg_type & ARG_PAREN) && *c->argv[1] != '(' /*')'*/) {
163                 Debug(LDAP_DEBUG_CONFIG, "%s: old <%s> format not supported\n",
164                         c->log, Conf->name, 0);
165                 return(ARG_BAD_CONF);
166         }
167         if((arg_type & ARGS_POINTER) && !Conf->arg_item && !(arg_type & ARG_OFFSET)) {
168                 Debug(LDAP_DEBUG_CONFIG, "%s: null arg_item for <%s>\n",
169                         c->log, Conf->name, 0);
170                 return(ARG_BAD_CONF);
171         }
172         c->type = arg_user = (arg_type & ARGS_USERLAND);
173         memset(&c->values, 0, sizeof(c->values));
174         if(arg_type & ARGS_NUMERIC) {
175                 int j;
176                 iarg = 0; larg = 0; barg = 0;
177                 switch(arg_type & ARGS_NUMERIC) {
178                         case ARG_INT:           iarg = atoi(c->argv[1]);                break;
179                         case ARG_LONG:          larg = strtol(c->argv[1], NULL, 0);     break;
180                         case ARG_BER_LEN_T:     barg = (ber_len_t)atol(c->argv[1]);     break;
181                         case ARG_ON_OFF:
182                                 if(c->argc == 1) {
183                                         iarg = 1;
184                                 } else if(!strcasecmp(c->argv[1], "on") ||
185                                         !strcasecmp(c->argv[1], "true")) {
186                                         iarg = 1;
187                                 } else if(!strcasecmp(c->argv[1], "off") ||
188                                         !strcasecmp(c->argv[1], "false")) {
189                                         iarg = 0;
190                                 } else {
191                                         Debug(LDAP_DEBUG_CONFIG, "%s: ignoring ", c->log, 0, 0);
192                                         Debug(LDAP_DEBUG_CONFIG, "invalid %s value (%s) in <%s> line\n",
193                                                 Conf->what, c->argv[1], Conf->name);
194                                         return(0);
195                                 }
196                                 break;
197                 }
198                 j = (arg_type & ARG_NONZERO) ? 1 : 0;
199                 if(iarg < j && larg < j && barg < j ) {
200                         larg = larg ? larg : (barg ? barg : iarg);
201                         Debug(LDAP_DEBUG_CONFIG, "%s: " , c->log, 0, 0);
202                         Debug(LDAP_DEBUG_CONFIG, "invalid %s value (%ld) in <%s> line\n", Conf->what, larg, Conf->name);
203                         return(ARG_BAD_CONF);
204                 }
205                 switch(arg_type & ARGS_NUMERIC) {
206                         case ARG_ON_OFF:
207                         case ARG_INT:           c->value_int = iarg;            break;
208                         case ARG_LONG:          c->value_long = larg;           break;
209                         case ARG_BER_LEN_T:     c->value_ber_t = barg;          break;
210                 }
211         } else if(arg_type & ARG_STRING) {
212                 if ( !check_only )
213                         c->value_string = ch_strdup(c->argv[1]);
214         } else if(arg_type & ARG_BERVAL) {
215                 if ( !check_only )
216                         ber_str2bv( c->argv[1], 0, 1, &c->value_bv );
217         } else if(arg_type & ARG_DN) {
218                 struct berval bv;
219                 ber_str2bv( c->argv[1], 0, 0, &bv );
220                 rc = dnPrettyNormal( NULL, &bv, &c->value_dn, &c->value_ndn, NULL );
221                 if ( rc != LDAP_SUCCESS ) {
222                         Debug(LDAP_DEBUG_CONFIG, "%s: " , c->log, 0, 0);
223                         Debug(LDAP_DEBUG_CONFIG, "%s DN is invalid %d (%s)\n",
224                                 Conf->name, rc, ldap_err2string( rc ));
225                         return(ARG_BAD_CONF);
226                 }
227                 if ( check_only ) {
228                         ch_free( c->value_ndn.bv_val );
229                         ch_free( c->value_dn.bv_val );
230                 }
231         }
232         return 0;
233 }
234
235 int config_set_vals(ConfigTable *Conf, ConfigArgs *c) {
236         int i, rc, arg_type, iarg;
237         long larg;
238         ber_len_t barg;
239         void *ptr;
240
241         arg_type = Conf->arg_type;
242         if(arg_type & ARG_MAGIC) {
243                 if(!c->be) c->be = frontendDB;
244                 rc = (*((ConfigDriver*)Conf->arg_item))(c);
245 #if 0
246                 if(c->be == frontendDB) c->be = NULL;
247 #endif
248                 if(rc) {
249                         Debug(LDAP_DEBUG_CONFIG, "%s: handler for <%s> exited with %d!\n",
250                                 c->log, Conf->name, rc);
251                         return(ARG_BAD_CONF);
252                 }
253                 return(0);
254         }
255         if(arg_type & ARG_OFFSET) {
256                 if (c->be)
257                         ptr = c->be->be_private;
258                 else if (c->bi)
259                         ptr = c->bi->bi_private;
260                 else {
261                         Debug(LDAP_DEBUG_CONFIG, "%s: offset for <%s> missing base pointer!\n",
262                                 c->log, Conf->name, 0);
263                         return(ARG_BAD_CONF);
264                 }
265                 ptr = (void *)((char *)ptr + (int)Conf->arg_item);
266         } else if (arg_type & ARGS_POINTER) {
267                 ptr = Conf->arg_item;
268         }
269         if(arg_type & ARGS_POINTER)
270                 switch(arg_type & ARGS_POINTER) {
271                         case ARG_ON_OFF:
272                         case ARG_INT:           *(int*)ptr = iarg;                      break;
273                         case ARG_LONG:          *(long*)ptr = larg;                     break;
274                         case ARG_BER_LEN_T:     *(ber_len_t*)ptr = barg;                        break;
275                         case ARG_STRING: {
276                                 char *cc = *(char**)ptr;
277                                 if(cc) {
278                                         if (arg_type & ARG_UNIQUE) {
279                                                 Debug(LDAP_DEBUG_CONFIG, "%s: already set %s!\n",
280                                                         c->log, Conf->name, 0 );
281                                                 return(ARG_BAD_CONF);
282                                         }
283                                         ch_free(cc);
284                                 }
285                                 *(char **)ptr = c->value_string;
286                                 break;
287                                 }
288                         case ARG_BERVAL:
289                                 *(struct berval *)ptr = c->value_bv;
290                                 break;
291                 }
292         return(0);
293 }
294
295 int config_add_vals(ConfigTable *Conf, ConfigArgs *c) {
296         int i, rc, arg_type, iarg;
297
298         arg_type = Conf->arg_type;
299         if(arg_type == ARG_IGNORED) {
300                 Debug(LDAP_DEBUG_CONFIG, "%s: keyword <%s> ignored\n",
301                         c->log, Conf->name, 0);
302                 return(0);
303         }
304         rc = config_check_vals( Conf, c, 0 );
305         if ( rc ) return rc;
306         return config_set_vals( Conf, c );
307 }
308
309 int
310 config_del_vals(ConfigTable *cf, ConfigArgs *c)
311 {
312         int rc = 0;
313 }
314
315 int
316 config_get_vals(ConfigTable *cf, ConfigArgs *c)
317 {
318         int rc = 0;
319         struct berval bv;
320         void *ptr;
321
322         if ( cf->arg_type & ARG_IGNORED ) {
323                 return 1;
324         }
325
326         memset(&c->values, 0, sizeof(c->values));
327         c->rvalue_vals = NULL;
328         c->rvalue_nvals = NULL;
329         c->op = SLAP_CONFIG_EMIT;
330         c->type = cf->arg_type & ARGS_USERLAND;
331
332         if ( cf->arg_type & ARG_MAGIC ) {
333                 rc = (*((ConfigDriver*)cf->arg_item))(c);
334                 if ( rc ) return rc;
335         } else {
336                 if ( cf->arg_type & ARG_OFFSET ) {
337                         if ( c->be )
338                                 ptr = c->be->be_private;
339                         else if ( c->bi )
340                                 ptr = c->bi->bi_private;
341                         else
342                                 return 1;
343                         ptr = (void *)((char *)ptr + (int)cf->arg_item);
344                 } else {
345                         ptr = cf->arg_item;
346                 }
347                 
348                 switch(cf->arg_type & ARGS_POINTER) {
349                 case ARG_ON_OFF:
350                 case ARG_INT:   c->value_int = *(int *)ptr; break;
351                 case ARG_LONG:  c->value_long = *(long *)ptr; break;
352                 case ARG_BER_LEN_T:     c->value_ber_t = *(ber_len_t *)ptr; break;
353                 case ARG_STRING:
354                         if ( *(char **)ptr )
355                                 c->value_string = ch_strdup(*(char **)ptr);
356                         break;
357                 case ARG_BERVAL:
358                         ber_dupbv( &c->value_bv, (struct berval *)ptr ); break;
359                 }
360         }
361         if ( cf->arg_type & ARGS_POINTER) {
362                 bv.bv_val = c->log;
363                 switch(cf->arg_type & ARGS_POINTER) {
364                 case ARG_INT: bv.bv_len = sprintf(bv.bv_val, "%d", c->value_int); break;
365                 case ARG_LONG: bv.bv_len = sprintf(bv.bv_val, "%ld", c->value_long); break;
366                 case ARG_BER_LEN_T: bv.bv_len = sprintf(bv.bv_val, "%ld", c->value_ber_t); break;
367                 case ARG_ON_OFF: bv.bv_len = sprintf(bv.bv_val, "%s",
368                         c->value_int ? "TRUE" : "FALSE"); break;
369                 case ARG_STRING:
370                         if ( c->value_string && c->value_string[0]) {
371                                 ber_str2bv( c->value_string, 0, 0, &bv);
372                         } else {
373                                 return 1;
374                         }
375                         break;
376                 case ARG_BERVAL:
377                         if ( !BER_BVISEMPTY( &c->value_bv )) {
378                                 bv = c->value_bv;
379                         } else {
380                                 return 1;
381                         }
382                         break;
383                 }
384                 if (( cf->arg_type & ARGS_POINTER ) == ARG_STRING )
385                         ber_bvarray_add(&c->rvalue_vals, &bv);
386                 else
387                         value_add_one(&c->rvalue_vals, &bv);
388         }
389         return rc;
390 }
391
392 int
393 init_config_attrs(ConfigTable *ct) {
394         LDAPAttributeType *at;
395         int i, code;
396         const char *err;
397
398         for (i=0; ct[i].name; i++ ) {
399                 if ( !ct[i].attribute ) continue;
400                 at = ldap_str2attributetype( ct[i].attribute,
401                         &code, &err, LDAP_SCHEMA_ALLOW_ALL );
402                 if ( !at ) {
403                         fprintf( stderr, "init_config_attrs: AttributeType \"%s\": %s, %s\n",
404                                 ct[i].attribute, ldap_scherr2str(code), err );
405                         return code;
406                 }
407                 code = at_add( at, 0, &err );
408                 if ( code && code != SLAP_SCHERR_ATTR_DUP ) {
409                         fprintf( stderr, "init_config_attrs: AttributeType \"%s\": %s, %s\n",
410                                 ct[i].attribute, scherr2str(code), err );
411                         return code;
412                 }
413                 code = slap_str2ad( at->at_names[0], &ct[i].ad, &err );
414                 if ( code ) {
415                         fprintf( stderr, "init_config_attrs: AttributeType \"%s\": %s\n",
416                                 ct[i].attribute, err );
417                         return code;
418                 }
419                 ldap_memfree( at );
420         }
421
422         return 0;
423 }
424
425 int
426 init_config_ocs( ConfigOCs *ocs ) {
427         int i;
428
429         for (i=0;ocs[i].def;i++) {
430                 LDAPObjectClass *oc;
431                 int code;
432                 const char *err;
433
434                 oc = ldap_str2objectclass( ocs[i].def, &code, &err,
435                         LDAP_SCHEMA_ALLOW_ALL );
436                 if ( !oc ) {
437                         fprintf( stderr, "init_config_ocs: objectclass \"%s\": %s, %s\n",
438                                 ocs[i].def, ldap_scherr2str(code), err );
439                         return code;
440                 }
441                 code = oc_add(oc,0,&err);
442                 if ( code && code != SLAP_SCHERR_CLASS_DUP ) {
443                         fprintf( stderr, "init_config_ocs: objectclass \"%s\": %s, %s\n",
444                                 ocs[i].def, scherr2str(code), err );
445                         return code;
446                 }
447                 if ( ocs[i].oc ) {
448                         *ocs[i].oc = oc_find(oc->oc_names[0]);
449                 }
450                 ldap_memfree(oc);
451         }
452         return 0;
453 }
454
455 int
456 config_parse_vals(ConfigTable *ct, ConfigArgs *c, int valx)
457 {
458         int rc = 0;
459
460         snprintf( c->log, sizeof( c->log ), "%s: value #%d",
461                 ct->ad->ad_cname.bv_val, valx );
462         c->argc = 1;
463         c->argv[0] = ct->ad->ad_cname.bv_val;
464         if ( fp_parse_line( c ) ) {
465                 rc = 1;
466         } else {
467                 rc = config_check_vals( ct, c, 1 );
468         }
469
470         ch_free( c->tline );
471         return rc;
472 }
473
474 int
475 config_parse_add(ConfigTable *ct, ConfigArgs *c, int valx)
476 {
477         int rc = 0;
478
479         snprintf( c->log, sizeof( c->log ), "%s: value #%d",
480                 ct->ad->ad_cname.bv_val, valx );
481         c->argc = 1;
482         c->argv[0] = ct->ad->ad_cname.bv_val;
483         if ( fp_parse_line( c ) ) {
484                 rc = 1;
485         } else {
486                 c->op = LDAP_MOD_ADD;
487                 rc = config_add_vals( ct, c );
488         }
489
490         ch_free( c->tline );
491         return rc;
492 }
493
494 int
495 read_config_file(const char *fname, int depth, ConfigArgs *cf)
496 {
497         FILE *fp;
498         ConfigTable *ct;
499         ConfigArgs *c;
500         int rc;
501
502         c = ch_calloc( 1, sizeof( ConfigArgs ) );
503         if ( c == NULL ) {
504                 return 1;
505         }
506
507         if ( depth ) {
508                 memcpy( c, cf, sizeof( ConfigArgs ) );
509         } else {
510                 c->depth = depth; /* XXX */
511                 c->bi = NULL;
512                 c->be = NULL;
513         }
514
515         c->fname = fname;
516         init_config_argv( c );
517
518         fp = fopen( fname, "r" );
519         if ( fp == NULL ) {
520                 ldap_syslog = 1;
521                 Debug(LDAP_DEBUG_ANY,
522                     "could not open config file \"%s\": %s (%d)\n",
523                     fname, strerror(errno), errno);
524                 return(1);
525         }
526
527         Debug(LDAP_DEBUG_CONFIG, "reading config file %s\n", fname, 0, 0);
528
529         fp_getline_init(c);
530
531         c->tline = NULL;
532
533         while ( fp_getline( fp, c ) ) {
534                 /* skip comments and blank lines */
535                 if ( c->line[0] == '#' || c->line[0] == '\0' ) {
536                         continue;
537                 }
538
539                 snprintf( c->log, sizeof( c->log ), "%s: line %lu",
540                                 c->fname, c->lineno );
541
542                 c->argc = 0;
543                 ch_free( c->tline );
544                 if ( fp_parse_line( c ) ) {
545                         rc = 1;
546                         goto leave;
547                 }
548
549                 if ( c->argc < 1 ) {
550                         Debug(LDAP_DEBUG_CONFIG, "%s: bad config line (ignored)\n", c->log, 0, 0);
551                         continue;
552                 }
553
554                 c->op = LDAP_MOD_ADD;
555
556                 ct = config_find_keyword( config_back_cf_table, c );
557                 if ( ct ) {
558                         rc = config_add_vals( ct, c );
559                         if ( !rc ) continue;
560
561                         if ( rc & ARGS_USERLAND ) {
562                                 /* XXX a usertype would be opaque here */
563                                 Debug(LDAP_DEBUG_CONFIG, "%s: unknown user type <%s>\n",
564                                         c->log, c->argv[0], 0);
565                                 rc = 1;
566                                 goto leave;
567
568                         } else if ( rc == ARG_BAD_CONF ) {
569                                 rc = 1;
570                                 goto leave;
571                         }
572                         
573                 } else if ( c->bi ) {
574                         rc = SLAP_CONF_UNKNOWN;
575                         if ( c->bi->bi_cf_table ) {
576                                 ct = config_find_keyword( c->bi->bi_cf_table, c );
577                                 if ( ct ) {
578                                         rc = config_add_vals( ct, c );
579                                 }
580                         }
581                         if ( c->bi->bi_config && rc == SLAP_CONF_UNKNOWN ) {
582                                 rc = (*c->bi->bi_config)(c->bi, c->fname, c->lineno,
583                                         c->argc, c->argv);
584                         }
585                         if ( rc ) {
586                                 switch(rc) {
587                                 case SLAP_CONF_UNKNOWN:
588                                         Debug(LDAP_DEBUG_CONFIG, "%s: "
589                                                 "unknown directive <%s> inside backend info definition (ignored)\n",
590                                                 c->log, *c->argv, 0);
591                                         continue;
592                                 default:
593                                         rc = 1;
594                                         goto leave;
595                                 }
596                         }
597
598                 } else if ( c->be ) {
599                         rc = SLAP_CONF_UNKNOWN;
600                         if ( c->be->be_cf_table ) {
601                                 ct = config_find_keyword( c->be->be_cf_table, c );
602                                 if ( ct ) {
603                                         rc = config_add_vals( ct, c );
604                                 }
605                         }
606                         if ( c->be->be_config && rc == SLAP_CONF_UNKNOWN ) {
607                                 rc = (*c->be->be_config)(c->be, c->fname, c->lineno,
608                                         c->argc, c->argv);
609                         }
610                         if ( rc ) {
611                                 switch(rc) {
612                                 case SLAP_CONF_UNKNOWN:
613                                         Debug( LDAP_DEBUG_CONFIG, "%s: "
614                                                 "unknown directive <%s> inside backend database "
615                                                 "definition (ignored)\n",
616                                                 c->log, *c->argv, 0);
617                                         continue;
618                                 default:
619                                         rc = 1;
620                                         goto leave;
621                                 }
622                         }
623
624                 } else if ( frontendDB->be_config ) {
625                         rc = (*frontendDB->be_config)(frontendDB, c->fname, (int)c->lineno, c->argc, c->argv);
626                         if ( rc ) {
627                                 switch(rc) {
628                                 case SLAP_CONF_UNKNOWN:
629                                         Debug( LDAP_DEBUG_CONFIG, "%s: "
630                                                 "unknown directive <%s> inside global database definition (ignored)\n",
631                                                 c->log, *c->argv, 0);
632                                         continue;
633                                 default:
634                                         rc = 1;
635                                         goto leave;
636                                 }
637                         }
638                         
639                 } else {
640                         Debug(LDAP_DEBUG_CONFIG, "%s: "
641                                 "unknown directive <%s> outside backend info and database definitions (ignored)\n",
642                                 c->log, *c->argv, 0);
643                         continue;
644
645                 }
646         }
647
648         if ( BER_BVISNULL( &frontendDB->be_schemadn ) ) {
649                 ber_str2bv( SLAPD_SCHEMA_DN, STRLENOF( SLAPD_SCHEMA_DN ), 1,
650                         &frontendDB->be_schemadn );
651                 rc = dnNormalize( 0, NULL, NULL, &frontendDB->be_schemadn, &frontendDB->be_schemandn, NULL );
652                 if ( rc != LDAP_SUCCESS ) {
653                         Debug(LDAP_DEBUG_ANY, "%s: "
654                                 "unable to normalize default schema DN \"%s\"\n",
655                                 c->log, frontendDB->be_schemadn.bv_val, 0 );
656                         /* must not happen */
657                         assert( 0 );
658                 }
659         }
660         rc = 0;
661
662 leave:
663         ch_free(c->tline);
664         fclose(fp);
665         ch_free(c->argv);
666         ch_free(c);
667         return(rc);
668 }
669
670 /* restrictops, allows, disallows, requires, loglevel */
671
672 int
673 verb_to_mask(const char *word, slap_verbmasks *v) {
674         int i;
675         for(i = 0; !BER_BVISNULL(&v[i].word); i++)
676                 if(!strcasecmp(word, v[i].word.bv_val))
677                         break;
678         return(i);
679 }
680
681 int
682 verbs_to_mask(int argc, char *argv[], slap_verbmasks *v, slap_mask_t *m) {
683         int i, j;
684         for(i = 1; i < argc; i++) {
685                 j = verb_to_mask(argv[i], v);
686                 if(BER_BVISNULL(&v[j].word)) return(1);
687                 while (!v[j].mask) j--;
688                 *m |= v[j].mask;
689         }
690         return(0);
691 }
692
693 int
694 mask_to_verbs(slap_verbmasks *v, slap_mask_t m, BerVarray *bva) {
695         int i, j;
696         struct berval bv;
697
698         if (!m) return 1;
699         for (i=0; !BER_BVISNULL(&v[i].word); i++) {
700                 if (!v[i].mask) continue;
701                 if (( m & v[i].mask ) == v[i].mask ) {
702                         value_add_one( bva, &v[i].word );
703                 }
704         }
705         return 0;
706 }
707
708 static slap_verbmasks tlskey[] = {
709         { BER_BVC("no"),                SB_TLS_OFF },
710         { BER_BVC("yes"),               SB_TLS_ON },
711         { BER_BVC("critical"),  SB_TLS_CRITICAL },
712         { BER_BVNULL, 0 }
713 };
714
715 static slap_verbmasks methkey[] = {
716         { BER_BVC("simple"),    LDAP_AUTH_SIMPLE },
717 #ifdef HAVE_CYRUS_SASL
718         { BER_BVC("sasl"),      LDAP_AUTH_SASL },
719 #endif
720         { BER_BVNULL, 0 }
721 };
722
723 typedef struct cf_aux_table {
724         struct berval key;
725         int off;
726         int quote;
727         slap_verbmasks *aux;
728 } cf_aux_table;
729
730 static cf_aux_table bindkey[] = {
731         { BER_BVC("starttls="), offsetof(slap_bindconf, sb_tls), 0, tlskey },
732         { BER_BVC("bindmethod="), offsetof(slap_bindconf, sb_method), 0, methkey },
733         { BER_BVC("binddn="), offsetof(slap_bindconf, sb_binddn), 1, NULL },
734         { BER_BVC("credentials="), offsetof(slap_bindconf, sb_cred), 1, NULL },
735         { BER_BVC("saslmech="), offsetof(slap_bindconf, sb_saslmech), 0, NULL },
736         { BER_BVC("secprops="), offsetof(slap_bindconf, sb_secprops), 0, NULL },
737         { BER_BVC("realm="), offsetof(slap_bindconf, sb_realm), 0, NULL },
738         { BER_BVC("authcID="), offsetof(slap_bindconf, sb_authcId), 0, NULL },
739         { BER_BVC("authzID="), offsetof(slap_bindconf, sb_authzId), 1, NULL },
740         { BER_BVNULL, 0, 0, NULL }
741 };
742
743 int bindconf_parse( const char *word, slap_bindconf *bc ) {
744         int i, rc = 0;
745         char **cptr;
746         cf_aux_table *tab;
747
748         for (tab = bindkey; !BER_BVISNULL(&tab->key); tab++) {
749                 if ( !strncasecmp( word, tab->key.bv_val, tab->key.bv_len )) {
750                         cptr = (char **)((char *)bc + tab->off);
751                         if ( tab->aux ) {
752                                 int j;
753                                 rc = 1;
754                                 for (j=0; !BER_BVISNULL(&tab->aux[j].word); j++) {
755                                         if (!strcasecmp(word+tab->key.bv_len, tab->aux[j].word.bv_val)) {
756                                                 int *ptr = (int *)cptr;
757                                                 *ptr = tab->aux[j].mask;
758                                                 rc = 0;
759                                         }
760                                 }
761                                 if (rc ) {
762                                         Debug(LDAP_DEBUG_ANY, "invalid bind config value %s\n",
763                                                 word, 0, 0 );
764                                 }
765                                 return rc;
766                         }
767                         *cptr = ch_strdup(word+tab->key.bv_len);
768                         return 0;
769                 }
770         }
771         return rc;
772 }
773
774 int bindconf_unparse( slap_bindconf *bc, struct berval *bv ) {
775         char buf[BUFSIZ], *ptr;
776         cf_aux_table *tab;
777         char **cptr;
778         struct berval tmp;
779
780         ptr = buf;
781         for (tab = bindkey; !BER_BVISNULL(&tab->key); tab++) {
782                 cptr = (char **)((char *)bc + tab->off);
783                 if ( tab->aux ) {
784                         int *ip = (int *)cptr, i;
785                         for ( i=0; !BER_BVISNULL(&tab->aux[i].word); i++ ) {
786                                 if ( *ip == tab->aux[i].mask ) {
787                                         *ptr++ = ' ';
788                                         ptr = lutil_strcopy( ptr, tab->key.bv_val );
789                                         ptr = lutil_strcopy( ptr, tab->aux[i].word.bv_val );
790                                         break;
791                                 }
792                         }
793                 } else if ( *cptr ) {
794                         *ptr++ = ' ';
795                         ptr = lutil_strcopy( ptr, tab->key.bv_val );
796                         if ( tab->quote ) *ptr++ = '"';
797                         ptr = lutil_strcopy( ptr, *cptr );
798                         if ( tab->quote ) *ptr++ = '"';
799                 }
800         }
801         tmp.bv_val = buf;
802         tmp.bv_len = ptr - buf;
803         ber_dupbv( bv, &tmp );
804         return 0;
805 }
806
807 void bindconf_free( slap_bindconf *bc ) {
808         if ( bc->sb_binddn ) {
809                 ch_free( bc->sb_binddn );
810         }
811         if ( bc->sb_cred ) {
812                 ch_free( bc->sb_cred );
813         }
814         if ( bc->sb_saslmech ) {
815                 ch_free( bc->sb_saslmech );
816         }
817         if ( bc->sb_secprops ) {
818                 ch_free( bc->sb_secprops );
819         }
820         if ( bc->sb_realm ) {
821                 ch_free( bc->sb_realm );
822         }
823         if ( bc->sb_authcId ) {
824                 ch_free( bc->sb_authcId );
825         }
826         if ( bc->sb_authzId ) {
827                 ch_free( bc->sb_authzId );
828         }
829 }
830
831
832 /* -------------------------------------- */
833
834
835 static char *
836 strtok_quote( char *line, char *sep, char **quote_ptr )
837 {
838         int             inquote;
839         char            *tmp;
840         static char     *next;
841
842         *quote_ptr = NULL;
843         if ( line != NULL ) {
844                 next = line;
845         }
846         while ( *next && strchr( sep, *next ) ) {
847                 next++;
848         }
849
850         if ( *next == '\0' ) {
851                 next = NULL;
852                 return( NULL );
853         }
854         tmp = next;
855
856         for ( inquote = 0; *next; ) {
857                 switch ( *next ) {
858                 case '"':
859                         if ( inquote ) {
860                                 inquote = 0;
861                         } else {
862                                 inquote = 1;
863                         }
864                         AC_MEMCPY( next, next + 1, strlen( next + 1 ) + 1 );
865                         break;
866
867                 case '\\':
868                         if ( next[1] )
869                                 AC_MEMCPY( next,
870                                             next + 1, strlen( next + 1 ) + 1 );
871                         next++;         /* dont parse the escaped character */
872                         break;
873
874                 default:
875                         if ( ! inquote ) {
876                                 if ( strchr( sep, *next ) != NULL ) {
877                                         *quote_ptr = next;
878                                         *next++ = '\0';
879                                         return( tmp );
880                                 }
881                         }
882                         next++;
883                         break;
884                 }
885         }
886
887         return( tmp );
888 }
889
890 static char     buf[BUFSIZ];
891 static char     *line;
892 static size_t lmax, lcur;
893
894 #define CATLINE( buf ) \
895         do { \
896                 size_t len = strlen( buf ); \
897                 while ( lcur + len + 1 > lmax ) { \
898                         lmax += BUFSIZ; \
899                         line = (char *) ch_realloc( line, lmax ); \
900                 } \
901                 strcpy( line + lcur, buf ); \
902                 lcur += len; \
903         } while( 0 )
904
905 static void
906 fp_getline_init(ConfigArgs *c) {
907         c->lineno = -1;
908         buf[0] = '\0';
909 }
910
911 static int
912 fp_getline( FILE *fp, ConfigArgs *c )
913 {
914         char    *p;
915
916         lcur = 0;
917         CATLINE(buf);
918         c->lineno++;
919
920         /* avoid stack of bufs */
921         if ( strncasecmp( line, "include", STRLENOF( "include" ) ) == 0 ) {
922                 buf[0] = '\0';
923                 c->line = line;
924                 return(1);
925         }
926
927         while ( fgets( buf, sizeof( buf ), fp ) ) {
928                 p = strchr( buf, '\n' );
929                 if ( p ) {
930                         if ( p > buf && p[-1] == '\r' ) {
931                                 --p;
932                         }
933                         *p = '\0';
934                 }
935                 /* XXX ugly */
936                 c->line = line;
937                 if ( line[0]
938                                 && ( p = line + strlen( line ) - 1 )[0] == '\\'
939                                 && p[-1] != '\\' )
940                 {
941                         p[0] = '\0';
942                         lcur--;
943                         
944                 } else {
945                         if ( !isspace( (unsigned char)buf[0] ) ) {
946                                 return(1);
947                         }
948                         buf[0] = ' ';
949                 }
950                 CATLINE(buf);
951                 c->lineno++;
952         }
953
954         buf[0] = '\0';
955         c->line = line;
956         return(line[0] ? 1 : 0);
957 }
958
959 static int
960 fp_parse_line(ConfigArgs *c)
961 {
962         char *token;
963         char *hide[] = { "rootpw", "replica", "bindpw", "pseudorootpw", "dbpasswd", '\0' };
964         char *quote_ptr;
965         int i;
966
967         c->tline = ch_strdup(c->line);
968         token = strtok_quote(c->tline, " \t", &quote_ptr);
969
970         if(token) for(i = 0; hide[i]; i++) if(!strcasecmp(token, hide[i])) break;
971         if(quote_ptr) *quote_ptr = ' ';
972         Debug(LDAP_DEBUG_CONFIG, "line %lu (%s%s)\n", c->lineno,
973                 hide[i] ? hide[i] : c->line, hide[i] ? " ***" : "");
974         if(quote_ptr) *quote_ptr = '\0';
975
976         for(; token; token = strtok_quote(NULL, " \t", &quote_ptr)) {
977                 if(c->argc == c->argv_size - 1) {
978                         char **tmp;
979                         tmp = ch_realloc(c->argv, (c->argv_size + ARGS_STEP) * sizeof(*c->argv));
980                         if(!tmp) {
981                                 Debug(LDAP_DEBUG_ANY, "line %lu: out of memory\n", c->lineno, 0, 0);
982                                 return -1;
983                         }
984                         c->argv = tmp;
985                         c->argv_size += ARGS_STEP;
986                 }
987                 c->argv[c->argc++] = token;
988         }
989         c->argv[c->argc] = NULL;
990         return(0);
991 }
992
993 void
994 config_destroy( )
995 {
996         ucdata_unload( UCDATA_ALL );
997         if ( frontendDB ) {
998                 /* NOTE: in case of early exit, frontendDB can be NULL */
999                 if ( frontendDB->be_schemandn.bv_val )
1000                         free( frontendDB->be_schemandn.bv_val );
1001                 if ( frontendDB->be_schemadn.bv_val )
1002                         free( frontendDB->be_schemadn.bv_val );
1003                 if ( frontendDB->be_acl )
1004                         acl_destroy( frontendDB->be_acl, NULL );
1005         }
1006         free( line );
1007         if ( slapd_args_file )
1008                 free ( slapd_args_file );
1009         if ( slapd_pid_file )
1010                 free ( slapd_pid_file );
1011         if ( default_passwd_hash )
1012                 ldap_charray_free( default_passwd_hash );
1013 }
1014
1015 char **
1016 slap_str2clist( char ***out, char *in, const char *brkstr )
1017 {
1018         char    *str;
1019         char    *s;
1020         char    *lasts;
1021         int     i, j;
1022         char    **new;
1023
1024         /* find last element in list */
1025         for (i = 0; *out && (*out)[i]; i++);
1026
1027         /* protect the input string from strtok */
1028         str = ch_strdup( in );
1029
1030         if ( *str == '\0' ) {
1031                 free( str );
1032                 return( *out );
1033         }
1034
1035         /* Count words in string */
1036         j=1;
1037         for ( s = str; *s; s++ ) {
1038                 if ( strchr( brkstr, *s ) != NULL ) {
1039                         j++;
1040                 }
1041         }
1042
1043         *out = ch_realloc( *out, ( i + j + 1 ) * sizeof( char * ) );
1044         new = *out + i;
1045         for ( s = ldap_pvt_strtok( str, brkstr, &lasts );
1046                 s != NULL;
1047                 s = ldap_pvt_strtok( NULL, brkstr, &lasts ) )
1048         {
1049                 *new = ch_strdup( s );
1050                 new++;
1051         }
1052
1053         *new = NULL;
1054         free( str );
1055         return( *out );
1056 }
1057
1058 int config_generic_wrapper( Backend *be, const char *fname, int lineno,
1059         int argc, char **argv )
1060 {
1061         ConfigArgs c = { 0 };
1062         ConfigTable *ct;
1063         int rc;
1064
1065         c.be = be;
1066         c.fname = fname;
1067         c.lineno = lineno;
1068         c.argc = argc;
1069         c.argv = argv;
1070         sprintf( c.log, "%s: line %lu", fname, lineno );
1071
1072         rc = SLAP_CONF_UNKNOWN;
1073         ct = config_find_keyword( be->be_cf_table, &c );
1074         if ( ct )
1075                 rc = config_add_vals( ct, &c );
1076         return rc;
1077 }