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