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