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