]> git.sur5r.net Git - openldap/blob - servers/slapd/config.c
2d5a0f9f90048ff2869d13ad0fc54b480aa82c0d
[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                         } else if ( c->bi->bi_config ) {
495                                 rc = (*c->bi->bi_config)(c->bi, c->fname, c->lineno,
496                                         c->argc, c->argv);
497                         }
498                         if ( rc ) {
499                                 switch(rc) {
500                                 case SLAP_CONF_UNKNOWN:
501                                         Debug(LDAP_DEBUG_CONFIG, "%s: "
502                                                 "unknown directive <%s> inside backend info definition (ignored)\n",
503                                                 c->log, *c->argv, 0);
504                                         continue;
505                                 default:
506                                         goto badline;
507                                 }
508                         }
509
510                 } else if ( c->be ) {
511                         rc = SLAP_CONF_UNKNOWN;
512                         if ( c->be->be_cf_table ) {
513                                 ct = config_find_keyword( c->be->be_cf_table, c );
514                                 if ( ct ) {
515                                         rc = config_add_vals( ct, c );
516                                 }
517                         } else if ( c->be->be_config ) {
518                                 rc = (*c->be->be_config)(c->be, c->fname, c->lineno,
519                                         c->argc, c->argv);
520                         }
521                         if ( rc ) {
522                                 switch(rc) {
523                                 case SLAP_CONF_UNKNOWN:
524                                         Debug( LDAP_DEBUG_CONFIG, "%s: "
525                                                 "unknown directive <%s> inside backend database "
526                                                 "definition (ignored)\n",
527                                                 c->log, *c->argv, 0);
528                                         continue;
529                                 default:
530                                         goto badline;
531                                 }
532                         }
533
534                 } else if ( frontendDB->be_config ) {
535                         rc = (*frontendDB->be_config)(frontendDB, c->fname, (int)c->lineno, c->argc, c->argv);
536                         if ( rc ) {
537                                 switch(rc) {
538                                 case SLAP_CONF_UNKNOWN:
539                                         Debug( LDAP_DEBUG_CONFIG, "%s: "
540                                                 "unknown directive <%s> inside global database definition (ignored)\n",
541                                                 c->log, *c->argv, 0);
542                                         continue;
543                                 default:
544                                         goto badline;
545                                 }
546                         }
547                         
548                 } else {
549                         Debug(LDAP_DEBUG_CONFIG, "%s: "
550                                 "unknown directive <%s> outside backend info and database definitions (ignored)\n",
551                                 c->log, *c->argv, 0);
552                         continue;
553
554                 }
555         }
556
557         fclose(fp);
558
559         if ( BER_BVISNULL( &frontendDB->be_schemadn ) ) {
560                 ber_str2bv( SLAPD_SCHEMA_DN, STRLENOF( SLAPD_SCHEMA_DN ), 1,
561                         &frontendDB->be_schemadn );
562                 rc = dnNormalize( 0, NULL, NULL, &frontendDB->be_schemadn, &frontendDB->be_schemandn, NULL );
563                 if ( rc != LDAP_SUCCESS ) {
564                         Debug(LDAP_DEBUG_ANY, "%s: "
565                                 "unable to normalize default schema DN \"%s\"\n",
566                                 c->log, frontendDB->be_schemadn.bv_val, 0 );
567                         /* must not happen */
568                         assert( 0 );
569                 }
570         }
571
572         ch_free(c->argv);
573         ch_free(c);
574         return(0);
575
576 badline:
577         fclose(fp);
578         ch_free(c->argv);
579         ch_free(c);
580         return(1);
581 }
582
583 /* restrictops, allows, disallows, requires, loglevel */
584
585 int
586 verb_to_mask(const char *word, slap_verbmasks *v) {
587         int i;
588         for(i = 0; !BER_BVISNULL(&v[i].word); i++)
589                 if(!strcasecmp(word, v[i].word.bv_val))
590                         break;
591         return(i);
592 }
593
594 int
595 verbs_to_mask(int argc, char *argv[], slap_verbmasks *v, slap_mask_t *m) {
596         int i, j;
597         for(i = 1; i < argc; i++) {
598                 j = verb_to_mask(argv[i], v);
599                 if(BER_BVISNULL(&v[j].word)) return(1);
600                 while (!v[j].mask) j--;
601                 *m |= v[j].mask;
602         }
603         return(0);
604 }
605
606 int
607 mask_to_verbs(slap_verbmasks *v, slap_mask_t m, BerVarray *bva) {
608         int i, j;
609         struct berval bv;
610
611         if (!m) return 1;
612         for (i=0; !BER_BVISNULL(&v[i].word); i++) {
613                 if (!v[i].mask) continue;
614                 if (( m & v[i].mask ) == v[i].mask ) {
615                         value_add_one( bva, &v[i].word );
616                 }
617         }
618         return 0;
619 }
620
621 static slap_verbmasks tlskey[] = {
622         { BER_BVC("no"),                SB_TLS_OFF },
623         { BER_BVC("yes"),               SB_TLS_ON },
624         { BER_BVC("critical"),  SB_TLS_CRITICAL },
625         { BER_BVNULL, 0 }
626 };
627
628 static slap_verbmasks methkey[] = {
629         { BER_BVC("simple"),    LDAP_AUTH_SIMPLE },
630 #ifdef HAVE_CYRUS_SASL
631         { BER_BVC("sasl"),      LDAP_AUTH_SASL },
632 #endif
633         { BER_BVNULL, 0 }
634 };
635
636 typedef struct cf_aux_table {
637         struct berval key;
638         int off;
639         int quote;
640         slap_verbmasks *aux;
641 } cf_aux_table;
642
643 static cf_aux_table bindkey[] = {
644         { BER_BVC("starttls="), offsetof(slap_bindconf, sb_tls), 0, tlskey },
645         { BER_BVC("bindmethod="), offsetof(slap_bindconf, sb_method), 0, methkey },
646         { BER_BVC("binddn="), offsetof(slap_bindconf, sb_binddn), 1, NULL },
647         { BER_BVC("credentials="), offsetof(slap_bindconf, sb_cred), 1, NULL },
648         { BER_BVC("saslmech="), offsetof(slap_bindconf, sb_saslmech), 0, NULL },
649         { BER_BVC("secprops="), offsetof(slap_bindconf, sb_secprops), 0, NULL },
650         { BER_BVC("realm="), offsetof(slap_bindconf, sb_realm), 0, NULL },
651         { BER_BVC("authcID="), offsetof(slap_bindconf, sb_authcId), 0, NULL },
652         { BER_BVC("authzID="), offsetof(slap_bindconf, sb_authzId), 1, NULL },
653         { BER_BVNULL, 0, 0, NULL }
654 };
655
656 int bindconf_parse( const char *word, slap_bindconf *bc ) {
657         int i, rc = 0;
658         char **cptr;
659         cf_aux_table *tab;
660
661         for (tab = bindkey; !BER_BVISNULL(&tab->key); tab++) {
662                 if ( !strncasecmp( word, tab->key.bv_val, tab->key.bv_len )) {
663                         cptr = (char **)((char *)bc + tab->off);
664                         if ( tab->aux ) {
665                                 int j;
666                                 rc = 1;
667                                 for (j=0; !BER_BVISNULL(&tab->aux[j].word); j++) {
668                                         if (!strcasecmp(word+tab->key.bv_len, tab->aux[j].word.bv_val)) {
669                                                 int *ptr = (int *)cptr;
670                                                 *ptr = tab->aux[j].mask;
671                                                 rc = 0;
672                                         }
673                                 }
674                                 if (rc ) {
675                                         Debug(LDAP_DEBUG_ANY, "invalid bind config value %s\n",
676                                                 word, 0, 0 );
677                                 }
678                                 return rc;
679                         }
680                         *cptr = ch_strdup(word+tab->key.bv_len);
681                         return 0;
682                 }
683         }
684         return rc;
685 }
686
687 int bindconf_unparse( slap_bindconf *bc, struct berval *bv ) {
688         char buf[BUFSIZ], *ptr;
689         cf_aux_table *tab;
690         char **cptr;
691         struct berval tmp;
692
693         ptr = buf;
694         for (tab = bindkey; !BER_BVISNULL(&tab->key); tab++) {
695                 cptr = (char **)((char *)bc + tab->off);
696                 if ( tab->aux ) {
697                         int *ip = (int *)cptr, i;
698                         for ( i=0; !BER_BVISNULL(&tab->aux[i].word); i++ ) {
699                                 if ( *ip == tab->aux[i].mask ) {
700                                         *ptr++ = ' ';
701                                         ptr = lutil_strcopy( ptr, tab->key.bv_val );
702                                         ptr = lutil_strcopy( ptr, tab->aux[i].word.bv_val );
703                                         break;
704                                 }
705                         }
706                 } else if ( *cptr ) {
707                         *ptr++ = ' ';
708                         ptr = lutil_strcopy( ptr, tab->key.bv_val );
709                         if ( tab->quote ) *ptr++ = '"';
710                         ptr = lutil_strcopy( ptr, *cptr );
711                         if ( tab->quote ) *ptr++ = '"';
712                 }
713         }
714         tmp.bv_val = buf;
715         tmp.bv_len = ptr - buf;
716         ber_dupbv( bv, &tmp );
717         return 0;
718 }
719
720 void bindconf_free( slap_bindconf *bc ) {
721         if ( bc->sb_binddn ) {
722                 ch_free( bc->sb_binddn );
723         }
724         if ( bc->sb_cred ) {
725                 ch_free( bc->sb_cred );
726         }
727         if ( bc->sb_saslmech ) {
728                 ch_free( bc->sb_saslmech );
729         }
730         if ( bc->sb_secprops ) {
731                 ch_free( bc->sb_secprops );
732         }
733         if ( bc->sb_realm ) {
734                 ch_free( bc->sb_realm );
735         }
736         if ( bc->sb_authcId ) {
737                 ch_free( bc->sb_authcId );
738         }
739         if ( bc->sb_authzId ) {
740                 ch_free( bc->sb_authzId );
741         }
742 }
743
744
745 /* -------------------------------------- */
746
747
748 static char *
749 strtok_quote( char *line, char *sep )
750 {
751         int             inquote;
752         char            *tmp;
753         static char     *next;
754
755         strtok_quote_ptr = NULL;
756         if ( line != NULL ) {
757                 next = line;
758         }
759         while ( *next && strchr( sep, *next ) ) {
760                 next++;
761         }
762
763         if ( *next == '\0' ) {
764                 next = NULL;
765                 return( NULL );
766         }
767         tmp = next;
768
769         for ( inquote = 0; *next; ) {
770                 switch ( *next ) {
771                 case '"':
772                         if ( inquote ) {
773                                 inquote = 0;
774                         } else {
775                                 inquote = 1;
776                         }
777                         AC_MEMCPY( next, next + 1, strlen( next + 1 ) + 1 );
778                         break;
779
780                 case '\\':
781                         if ( next[1] )
782                                 AC_MEMCPY( next,
783                                             next + 1, strlen( next + 1 ) + 1 );
784                         next++;         /* dont parse the escaped character */
785                         break;
786
787                 default:
788                         if ( ! inquote ) {
789                                 if ( strchr( sep, *next ) != NULL ) {
790                                         strtok_quote_ptr = next;
791                                         *next++ = '\0';
792                                         return( tmp );
793                                 }
794                         }
795                         next++;
796                         break;
797                 }
798         }
799
800         return( tmp );
801 }
802
803 static char     buf[BUFSIZ];
804 static char     *line;
805 static size_t lmax, lcur;
806
807 #define CATLINE( buf ) \
808         do { \
809                 size_t len = strlen( buf ); \
810                 while ( lcur + len + 1 > lmax ) { \
811                         lmax += BUFSIZ; \
812                         line = (char *) ch_realloc( line, lmax ); \
813                 } \
814                 strcpy( line + lcur, buf ); \
815                 lcur += len; \
816         } while( 0 )
817
818 static void
819 fp_getline_init(ConfigArgs *c) {
820         c->lineno = -1;
821         buf[0] = '\0';
822 }
823
824 static int
825 fp_getline( FILE *fp, ConfigArgs *c )
826 {
827         char    *p;
828
829         lcur = 0;
830         CATLINE(buf);
831         c->lineno++;
832
833         /* avoid stack of bufs */
834         if ( strncasecmp( line, "include", STRLENOF( "include" ) ) == 0 ) {
835                 buf[0] = '\0';
836                 c->line = line;
837                 return(1);
838         }
839
840         while ( fgets( buf, sizeof( buf ), fp ) ) {
841                 p = strchr( buf, '\n' );
842                 if ( p ) {
843                         if ( p > buf && p[-1] == '\r' ) {
844                                 --p;
845                         }
846                         *p = '\0';
847                 }
848                 /* XXX ugly */
849                 c->line = line;
850                 if ( line[0]
851                                 && ( p = line + strlen( line ) - 1 )[0] == '\\'
852                                 && p[-1] != '\\' )
853                 {
854                         p[0] = '\0';
855                         lcur--;
856                         
857                 } else {
858                         if ( !isspace( (unsigned char)buf[0] ) ) {
859                                 return(1);
860                         }
861                         buf[0] = ' ';
862                 }
863                 CATLINE(buf);
864                 c->lineno++;
865         }
866
867         buf[0] = '\0';
868         c->line = line;
869         return(line[0] ? 1 : 0);
870 }
871
872 static int
873 fp_parse_line(ConfigArgs *c)
874 {
875         char *token;
876         char *tline = ch_strdup(c->line);
877         char *hide[] = { "rootpw", "replica", "bindpw", "pseudorootpw", "dbpasswd", '\0' };
878         int i;
879
880         c->argc = 0;
881         token = strtok_quote(tline, " \t");
882
883         if(token) for(i = 0; hide[i]; i++) if(!strcasecmp(token, hide[i])) break;
884         if(strtok_quote_ptr) *strtok_quote_ptr = ' ';
885         Debug(LDAP_DEBUG_CONFIG, "line %lu (%s%s)\n", c->lineno, hide[i] ? hide[i] : c->line, hide[i] ? " ***" : "");
886         if(strtok_quote_ptr) *strtok_quote_ptr = '\0';
887
888         for(; token; token = strtok_quote(NULL, " \t")) {
889                 if(c->argc == c->argv_size - 1) {
890                         char **tmp;
891                         tmp = ch_realloc(c->argv, (c->argv_size + ARGS_STEP) * sizeof(*c->argv));
892                         if(!tmp) {
893                                 Debug(LDAP_DEBUG_ANY, "line %lu: out of memory\n", c->lineno, 0, 0);
894                                 return -1;
895                         }
896                         c->argv = tmp;
897                         c->argv_size += ARGS_STEP;
898                 }
899                 c->argv[c->argc++] = token;
900         }
901         c->argv[c->argc] = NULL;
902         return(0);
903 }
904
905 void
906 config_destroy( )
907 {
908         ucdata_unload( UCDATA_ALL );
909         if ( frontendDB ) {
910                 /* NOTE: in case of early exit, frontendDB can be NULL */
911                 if ( frontendDB->be_schemandn.bv_val )
912                         free( frontendDB->be_schemandn.bv_val );
913                 if ( frontendDB->be_schemadn.bv_val )
914                         free( frontendDB->be_schemadn.bv_val );
915                 if ( frontendDB->be_acl )
916                         acl_destroy( frontendDB->be_acl, NULL );
917         }
918         free( line );
919         if ( slapd_args_file )
920                 free ( slapd_args_file );
921         if ( slapd_pid_file )
922                 free ( slapd_pid_file );
923         if ( default_passwd_hash )
924                 ldap_charray_free( default_passwd_hash );
925 }
926
927 char **
928 slap_str2clist( char ***out, char *in, const char *brkstr )
929 {
930         char    *str;
931         char    *s;
932         char    *lasts;
933         int     i, j;
934         char    **new;
935
936         /* find last element in list */
937         for (i = 0; *out && (*out)[i]; i++);
938
939         /* protect the input string from strtok */
940         str = ch_strdup( in );
941
942         if ( *str == '\0' ) {
943                 free( str );
944                 return( *out );
945         }
946
947         /* Count words in string */
948         j=1;
949         for ( s = str; *s; s++ ) {
950                 if ( strchr( brkstr, *s ) != NULL ) {
951                         j++;
952                 }
953         }
954
955         *out = ch_realloc( *out, ( i + j + 1 ) * sizeof( char * ) );
956         new = *out + i;
957         for ( s = ldap_pvt_strtok( str, brkstr, &lasts );
958                 s != NULL;
959                 s = ldap_pvt_strtok( NULL, brkstr, &lasts ) )
960         {
961                 *new = ch_strdup( s );
962                 new++;
963         }
964
965         *new = NULL;
966         free( str );
967         return( *out );
968 }
969
970 int config_generic_wrapper( Backend *be, const char *fname, int lineno,
971         int argc, char **argv )
972 {
973         ConfigArgs c = { 0 };
974         ConfigTable *ct;
975         int rc;
976
977         c.be = be;
978         c.fname = fname;
979         c.lineno = lineno;
980         c.argc = argc;
981         c.argv = argv;
982         sprintf( c.log, "%s: line %lu", fname, lineno );
983
984         rc = SLAP_CONF_UNKNOWN;
985         ct = config_find_keyword( be->be_cf_table, &c );
986         if ( ct )
987                 rc = config_add_vals( ct, &c );
988         return rc;
989 }