]> git.sur5r.net Git - openldap/blob - servers/slapd/bconfig.c
Read config tree from back-ldif
[openldap] / servers / slapd / bconfig.c
1 /* bconfig.c - the config backend */
2 /* $OpenLDAP$ */
3 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
4  *
5  * Copyright 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 /* ACKNOWLEDGEMENTS:
17  * This work was originally developed by Howard Chu for inclusion
18  * in OpenLDAP Software.
19  */
20
21 #include "portable.h"
22
23 #include <stdio.h>
24 #include <ac/string.h>
25 #include <ac/ctype.h>
26 #include <ac/errno.h>
27
28 #include "slap.h"
29
30 #ifdef LDAP_SLAPI
31 #include "slapi/slapi.h"
32 #endif
33
34 #include <lutil.h>
35
36 #include "config.h"
37
38 static struct berval config_rdn = BER_BVC("cn=config");
39 static struct berval access_rdn = BER_BVC("cn=access");
40
41 #ifdef SLAPD_MODULES
42 typedef struct modpath_s {
43         struct modpath_s *mp_next;
44         struct berval mp_path;
45         BerVarray mp_loads;
46 } ModPaths;
47 #endif
48
49 typedef struct ConfigFile {
50         struct ConfigFile *c_sibs;
51         struct ConfigFile *c_kids;
52         struct berval c_file;
53 #ifdef SLAPD_MODULES
54         ModPaths c_modpaths;
55         ModPaths *c_modlast;
56 #endif
57         BerVarray c_dseFiles;
58 } ConfigFile;
59
60 typedef struct CfEntryInfo {
61         struct CfEntryInfo *ce_sibs;
62         struct CfEntryInfo *ce_kids;
63         Entry *ce_entry;
64         BackendInfo *ce_bi;
65         BackendDB *ce_be;
66 } CfEntryInfo;
67
68 typedef struct {
69         ConfigFile *cb_config;
70         CfEntryInfo *cb_root;
71         BackendDB       cb_db;  /* underlying database */
72         int             cb_got_ldif;
73 } CfBackInfo;
74
75 /* These do nothing in slapd, they're kept only to make them
76  * editable here.
77  */
78 static char *replica_pidFile, *replica_argsFile;
79 static int replicationInterval;
80
81 static char     *passwd_salt;
82 static char     *logfileName;
83 static BerVarray authz_rewrites;
84
85 static struct berval cfdir;
86
87 static AttributeDescription *cfAd_backend, *cfAd_database, *cfAd_overlay,
88         *cfAd_include;
89
90 static ObjectClass *cfOc_global, *cfOc_backend, *cfOc_database,
91         *cfOc_include, *cfOc_overlay, *cfOc_access;
92
93 static ConfigFile cf_prv, *cfn = &cf_prv;
94
95 static int add_syncrepl LDAP_P(( Backend *, char **, int ));
96 static int parse_syncrepl_line LDAP_P(( char **, int, syncinfo_t *));
97 static void syncrepl_unparse LDAP_P (( syncinfo_t *, struct berval *));
98
99 static ConfigDriver config_fname;
100 static ConfigDriver config_cfdir;
101 static ConfigDriver config_generic;
102 static ConfigDriver config_search_base;
103 static ConfigDriver config_passwd_hash;
104 static ConfigDriver config_schema_dn;
105 static ConfigDriver config_sizelimit;
106 static ConfigDriver config_timelimit;
107 static ConfigDriver config_limits; 
108 static ConfigDriver config_overlay;
109 static ConfigDriver config_suffix; 
110 static ConfigDriver config_deref_depth;
111 static ConfigDriver config_rootdn;
112 static ConfigDriver config_rootpw;
113 static ConfigDriver config_restrict;
114 static ConfigDriver config_allows;
115 static ConfigDriver config_disallows;
116 static ConfigDriver config_requires;
117 static ConfigDriver config_security;
118 static ConfigDriver config_referral;
119 static ConfigDriver config_loglevel;
120 static ConfigDriver config_syncrepl;
121 static ConfigDriver config_replica;
122 static ConfigDriver config_updatedn;
123 static ConfigDriver config_updateref;
124 static ConfigDriver config_include;
125 #ifdef HAVE_TLS
126 static ConfigDriver config_tls_option;
127 static ConfigDriver config_tls_config;
128 #endif
129
130 enum {
131         CFG_ACL = 1,
132         CFG_BACKEND,
133         CFG_DATABASE,
134         CFG_TLS_RAND,
135         CFG_TLS_CIPHER,
136         CFG_TLS_CERT_FILE,
137         CFG_TLS_CERT_KEY,
138         CFG_TLS_CA_PATH,
139         CFG_TLS_CA_FILE,
140         CFG_TLS_VERIFY,
141         CFG_TLS_CRLCHECK,
142         CFG_SIZE,
143         CFG_TIME,
144         CFG_CONCUR,
145         CFG_THREADS,
146         CFG_SALT,
147         CFG_LIMITS,
148         CFG_RO,
149         CFG_REWRITE,
150         CFG_DEPTH,
151         CFG_OID,
152         CFG_OC,
153         CFG_DIT,
154         CFG_ATTR,
155         CFG_ATOPT,
156         CFG_CHECK,
157         CFG_AUDITLOG,
158         CFG_REPLOG,
159         CFG_ROOTDSE,
160         CFG_LOGFILE,
161         CFG_PLUGIN,
162         CFG_MODLOAD,
163         CFG_MODPATH,
164         CFG_LASTMOD,
165         CFG_AZPOLICY,
166         CFG_AZREGEXP,
167         CFG_SASLSECP,
168         CFG_SSTR_IF_MAX,
169         CFG_SSTR_IF_MIN,
170 };
171
172 typedef struct {
173         char *name, *oid;
174 } OidRec;
175
176 static OidRec OidMacros[] = {
177         /* OpenLDAProot:666.11.1 */
178         { "OLcfg", "1.3.6.1.4.1.4203.666.11.1" },
179         { "OLcfgAt", "OLcfg:3" },
180         { "OLcfgOc", "OLcfg:4" },
181         { "OMsyn", "1.3.6.1.4.1.1466.115.121.1" },
182         { "OMsInteger", "OMsyn:2" },
183         { "OMsBoolean", "OMsyn:7" },
184         { "OMsDN", "OMsyn:12" },
185         { "OMsDirectoryString", "OMsyn:15" },
186         { "OMsOctetString", "OMsyn:40" },
187         { NULL, NULL }
188 };
189
190 /* alphabetical ordering */
191
192 ConfigTable config_back_cf_table[] = {
193         /* This attr is read-only */
194         { "", "", 0, 0, 0, ARG_MAGIC,
195                 &config_fname, "( OLcfgAt:78 NAME 'olcConfigFile' "
196                         "DESC 'File for slapd configuration directives' "
197                         "EQUALITY caseIgnoreMatch "
198                         "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL },
199         { "", "", 0, 0, 0, ARG_MAGIC,
200                 &config_cfdir, "( OLcfgAt:79 NAME 'olcConfigDir' "
201                         "DESC 'Directory for slapd configuration backend' "
202                         "EQUALITY caseIgnoreMatch "
203                         "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL },
204         { "access",     NULL, 0, 0, 0, ARG_MAY_DB|ARG_MAGIC|CFG_ACL,
205                 &config_generic, "( OLcfgAt:1 NAME 'olcAccess' "
206                         "DESC 'Access Control List' "
207                         "EQUALITY caseIgnoreMatch "
208                         "SYNTAX OMsDirectoryString X-ORDERED 'VALUES' )", NULL, NULL },
209         { "allows",     "features", 2, 0, 5, ARG_PRE_DB|ARG_MAGIC,
210                 &config_allows, "( OLcfgAt:2 NAME 'olcAllows' "
211                         "DESC 'Allowed set of deprecated features' "
212                         "EQUALITY caseIgnoreMatch "
213                         "SYNTAX OMsDirectoryString )", NULL, NULL },
214         { "argsfile", "file", 2, 2, 0, ARG_STRING,
215                 &slapd_args_file, "( OLcfgAt:3 NAME 'olcArgsFile' "
216                         "DESC 'File for slapd command line options' "
217                         "EQUALITY caseIgnoreMatch "
218                         "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL },
219         /* Use standard 'attributeTypes' attr */
220         { "attribute",  "attribute", 2, 0, 9, ARG_PAREN|ARG_MAGIC|CFG_ATTR,
221                 &config_generic, NULL, NULL, NULL },
222         { "attributeoptions", NULL, 0, 0, 0, ARG_MAGIC|CFG_ATOPT,
223                 &config_generic, "( OLcfgAt:5 NAME 'olcAttributeOptions' "
224                         "EQUALITY caseIgnoreMatch "
225                         "SYNTAX OMsDirectoryString )", NULL, NULL },
226         { "authid-rewrite", NULL, 2, 0, 0,
227 #ifdef SLAP_AUTH_REWRITE
228                 ARG_MAGIC|CFG_REWRITE, &config_generic,
229 #else
230                 ARG_IGNORED, NULL,
231 #endif
232                  "( OLcfgAt:6 NAME 'olcAuthIDRewrite' "
233                         "EQUALITY caseIgnoreMatch "
234                         "SYNTAX OMsDirectoryString X-ORDERED 'VALUES' )", NULL, NULL },
235         { "authz-policy", "policy", 2, 2, 0, ARG_STRING|ARG_MAGIC|CFG_AZPOLICY,
236                 &config_generic, "( OLcfgAt:7 NAME 'olcAuthzPolicy' "
237                         "EQUALITY caseIgnoreMatch "
238                         "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL },
239         { "authz-regexp", NULL, 3, 3, 0, ARG_MAGIC|CFG_AZREGEXP,
240                 &config_generic, "( OLcfgAt:8 NAME 'olcAuthzRegexp' "
241                         "EQUALITY caseIgnoreMatch "
242                         "SYNTAX OMsDirectoryString X-ORDERED 'VALUES' )", NULL, NULL },
243         { "backend", "type", 2, 2, 0, ARG_PRE_DB|ARG_MAGIC|CFG_BACKEND,
244                 &config_generic, "( OLcfgAt:9 NAME 'olcBackend' "
245                         "DESC 'A type of backend' "
246                         "EQUALITY caseIgnoreMatch "
247                         "SYNTAX OMsDirectoryString )", NULL, NULL },
248         { "concurrency", "level", 2, 2, 0, ARG_INT|ARG_NONZERO|ARG_MAGIC|CFG_CONCUR,
249                 &config_generic, "( OLcfgAt:10 NAME 'olcConcurrency' "
250                         "SYNTAX OMsInteger SINGLE-VALUE )", NULL, NULL },
251         { "conn_max_pending", "max", 2, 2, 0, ARG_INT,
252                 &slap_conn_max_pending, "( OLcfgAt:11 NAME 'olcConnMaxPending' "
253                         "SYNTAX OMsInteger SINGLE-VALUE )", NULL, NULL },
254         { "conn_max_pending_auth", "max", 2, 2, 0, ARG_INT,
255                 &slap_conn_max_pending_auth, "( OLcfgAt:12 NAME 'olcConnMaxPendingAuth' "
256                         "SYNTAX OMsInteger SINGLE-VALUE )", NULL, NULL },
257         { "database", "type", 2, 2, 0, ARG_MAGIC|CFG_DATABASE,
258                 &config_generic, "( OLcfgAt:13 NAME 'olcDatabase' "
259                         "DESC 'The backend type for a database instance' "
260                         "SUP olcBackend )", NULL, NULL },
261         { "defaultSearchBase", "dn", 2, 2, 0, ARG_PRE_BI|ARG_PRE_DB|ARG_DN|ARG_MAGIC,
262                 &config_search_base, "( OLcfgAt:14 NAME 'olcDefaultSearchBase' "
263                         "SYNTAX OMsDN SINGLE-VALUE )", NULL, NULL },
264         { "disallows", "features", 2, 0, 8, ARG_PRE_DB|ARG_MAGIC,
265                 &config_disallows, "( OLcfgAt:15 NAME 'olcDisallows' "
266                         "EQUALITY caseIgnoreMatch "
267                         "SYNTAX OMsDirectoryString )", NULL, NULL },
268         /* use standard schema */
269         { "ditcontentrule",     NULL, 0, 0, 0, ARG_MAGIC|CFG_DIT,
270                 &config_generic, NULL, NULL, NULL },
271         { "gentlehup", "on|off", 2, 2, 0,
272 #ifdef SIGHUP
273                 ARG_ON_OFF, &global_gentlehup,
274 #else
275                 ARG_IGNORED, NULL,
276 #endif
277                 "( OLcfgAt:17 NAME 'olcGentleHUP' "
278                         "SYNTAX OMsBoolean SINGLE-VALUE )", NULL, NULL },
279         { "idletimeout", "timeout", 2, 2, 0, ARG_INT,
280                 &global_idletimeout, "( OLcfgAt:18 NAME 'olcIdleTimeout' "
281                         "SYNTAX OMsInteger SINGLE-VALUE )", NULL, NULL },
282 /* XXX -- special case? */
283         { "include", "file", 2, 2, 0, ARG_MAGIC,
284                 &config_include, "( OLcfgAt:19 NAME 'olcInclude' "
285                         "SUP labeledURI )", NULL, NULL },
286         { "index_substr_if_minlen", "min", 2, 2, 0, ARG_INT|ARG_NONZERO|ARG_MAGIC|CFG_SSTR_IF_MIN,
287                 &config_generic, "( OLcfgAt:20 NAME 'olcIndexSubstrIfMinLen' "
288                         "SYNTAX OMsInteger SINGLE-VALUE )", NULL, NULL },
289         { "index_substr_if_maxlen", "max", 2, 2, 0, ARG_INT|ARG_NONZERO|ARG_MAGIC|CFG_SSTR_IF_MAX,
290                 &config_generic, "( OLcfgAt:21 NAME 'olcIndexSubstrIfMaxLen' "
291                         "SYNTAX OMsInteger SINGLE-VALUE )", NULL, NULL },
292         { "index_substr_any_len", "len", 2, 2, 0, ARG_INT|ARG_NONZERO,
293                 &index_substr_any_len, "( OLcfgAt:22 NAME 'olcIndexSubstrAnyLen' "
294                         "SYNTAX OMsInteger SINGLE-VALUE )", NULL, NULL },
295         { "index_substr_step", "step", 2, 2, 0, ARG_INT|ARG_NONZERO,
296                 &index_substr_any_step, "( OLcfgAt:23 NAME 'olcIndexSubstrAnyStep' "
297                         "SYNTAX OMsInteger SINGLE-VALUE )", NULL, NULL },
298         { "lastmod", "on|off", 2, 2, 0, ARG_DB|ARG_ON_OFF|ARG_MAGIC|CFG_LASTMOD,
299                 &config_generic, "( OLcfgAt:24 NAME 'olcLastMod' "
300                         "SYNTAX OMsBoolean SINGLE-VALUE )", NULL, NULL },
301         { "limits", "limits", 2, 0, 0, ARG_DB|ARG_MAGIC|CFG_LIMITS,
302                 &config_generic, "( OLcfgAt:25 NAME 'olcLimits' "
303                         "SYNTAX OMsDirectoryString )", NULL, NULL },
304         { "localSSF", "ssf", 2, 2, 0, ARG_INT,
305                 &local_ssf, "( OLcfgAt:26 NAME 'olcLocalSSF' "
306                         "SYNTAX OMsInteger SINGLE-VALUE )", NULL, NULL },
307         { "logfile", "file", 2, 2, 0, ARG_STRING|ARG_MAGIC|CFG_LOGFILE,
308                 &config_generic, "( OLcfgAt:27 NAME 'olcLogFile' "
309                         "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL },
310         { "loglevel", "level", 2, 0, 0, ARG_MAGIC,
311                 &config_loglevel, "( OLcfgAt:28 NAME 'olcLogLevel' "
312                         "SYNTAX OMsDirectoryString )", NULL, NULL },
313         { "maxDerefDepth", "depth", 2, 2, 0, ARG_DB|ARG_INT|ARG_MAGIC|CFG_DEPTH,
314                 &config_generic, "( OLcfgAt:29 NAME 'olcMaxDerefDepth' "
315                         "SYNTAX OMsInteger SINGLE-VALUE )", NULL, NULL },
316         { "moduleload", "file", 2, 0, 0,
317 #ifdef SLAPD_MODULES
318                 ARG_MAGIC|CFG_MODLOAD, &config_generic,
319 #else
320                 ARG_IGNORED, NULL,
321 #endif
322                 "( OLcfgAt:30 NAME 'olcModuleLoad' "
323                         "SYNTAX OMsDirectoryString X-ORDERED 'VALUES' )", NULL, NULL },
324         { "modulepath", "path", 2, 2, 0,
325 #ifdef SLAPD_MODULES
326                 ARG_MAGIC|CFG_MODPATH, &config_generic,
327 #else
328                 ARG_IGNORED, NULL,
329 #endif
330                 "( OLcfgAt:31 NAME 'olcModulePath' "
331                         "SYNTAX OMsDirectoryString X-ORDERED 'VALUES' )", NULL, NULL },
332         /* use standard schema */
333         { "objectclass", "objectclass", 2, 0, 0, ARG_PAREN|ARG_MAGIC|CFG_OC,
334                 &config_generic, NULL, NULL, NULL },
335         { "objectidentifier", NULL,     0, 0, 0, ARG_MAGIC|CFG_OID,
336                 &config_generic, "( OLcfgAt:33 NAME 'olcObjectIdentifier' "
337                         "SYNTAX OMsDirectoryString X-ORDERED 'VALUES' )", NULL, NULL },
338         { "overlay", "overlay", 2, 2, 0, ARG_MAGIC,
339                 &config_overlay, "( OLcfgAt:34 NAME 'olcOverlay' "
340                         "SUP olcDatabase )", NULL, NULL },
341         { "password-crypt-salt-format", "salt", 2, 2, 0, ARG_STRING|ARG_MAGIC|CFG_SALT,
342                 &config_generic, "( OLcfgAt:35 NAME 'olcPasswordCryptSaltFormat' "
343                         "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL },
344         { "password-hash", "hash", 2, 2, 0, ARG_MAGIC,
345                 &config_passwd_hash, "( OLcfgAt:36 NAME 'olcPasswordHash' "
346                         "SYNTAX OMsDirectoryString )", NULL, NULL },
347         { "pidfile", "file", 2, 2, 0, ARG_STRING,
348                 &slapd_pid_file, "( OLcfgAt:37 NAME 'olcPidFile' "
349                         "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL },
350         { "plugin", NULL, 0, 0, 0,
351 #ifdef LDAP_SLAPI
352                 ARG_MAGIC|CFG_PLUGIN, &config_generic,
353 #else
354                 ARG_IGNORED, NULL,
355 #endif
356                 "( OLcfgAt:38 NAME 'olcPlugin' "
357                         "SYNTAX OMsDirectoryString )", NULL, NULL },
358         { "pluginlog", "filename", 2, 2, 0,
359 #ifdef LDAP_SLAPI
360                 ARG_STRING, &slapi_log_file,
361 #else
362                 ARG_IGNORED, NULL,
363 #endif
364                 "( OLcfgAt:39 NAME 'olcPluginLogFile' "
365                         "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL },
366         { "readonly", "on|off", 2, 2, 0, ARG_MAY_DB|ARG_ON_OFF|ARG_MAGIC|CFG_RO,
367                 &config_generic, "( OLcfgAt:40 NAME 'olcReadOnly' "
368                         "SYNTAX OMsBoolean SINGLE-VALUE )", NULL, NULL },
369         { "referral", "url", 2, 2, 0, ARG_MAGIC,
370                 &config_referral, "( OLcfgAt:41 NAME 'olcReferral' "
371                         "SUP labeledURI SINGLE-VALUE )", NULL, NULL },
372         { "replica", "host or uri", 2, 0, 0, ARG_DB|ARG_MAGIC,
373                 &config_replica, "( OLcfgAt:42 NAME 'olcReplica' "
374                         "SUP labeledURI )", NULL, NULL },
375         { "replica-argsfile", NULL, 0, 0, 0, ARG_STRING,
376                 &replica_argsFile, "( OLcfgAt:43 NAME 'olcReplicaArgsFile' "
377                         "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL },
378         { "replica-pidfile", NULL, 0, 0, 0, ARG_STRING,
379                 &replica_pidFile, "( OLcfgAt:44 NAME 'olcReplicaPidFile' "
380                         "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL },
381         { "replicationInterval", NULL, 0, 0, 0, ARG_INT,
382                 &replicationInterval, "( OLcfgAt:45 NAME 'olcReplicationInterval' "
383                         "SYNTAX OMsInteger SINGLE-VALUE )", NULL, NULL },
384         { "replogfile", "filename", 2, 2, 0, ARG_MAY_DB|ARG_MAGIC|ARG_STRING|CFG_REPLOG,
385                 &config_generic, "( OLcfgAt:46 NAME 'olcReplogFile' "
386                         "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL },
387         { "require", "features", 2, 0, 7, ARG_MAY_DB|ARG_MAGIC,
388                 &config_requires, "( OLcfgAt:47 NAME 'olcRequires' "
389                         "SYNTAX OMsDirectoryString )", NULL, NULL },
390         { "restrict", "op_list", 2, 0, 0, ARG_MAY_DB|ARG_MAGIC,
391                 &config_restrict, "( OLcfgAt:48 NAME 'olcRestrict' "
392                         "SYNTAX OMsDirectoryString )", NULL, NULL },
393         { "reverse-lookup", "on|off", 2, 2, 0,
394 #ifdef SLAPD_RLOOKUPS
395                 ARG_ON_OFF, &use_reverse_lookup,
396 #else
397                 ARG_IGNORED, NULL,
398 #endif
399                 "( OLcfgAt:49 NAME 'olcReverseLookup' "
400                         "SYNTAX OMsBoolean SINGLE-VALUE )", NULL, NULL },
401         { "rootdn", "dn", 2, 2, 0, ARG_DB|ARG_DN|ARG_MAGIC,
402                 &config_rootdn, "( OLcfgAt:50 NAME 'olcRootDN' "
403                         "SYNTAX OMsDN SINGLE-VALUE )", NULL, NULL },
404         { "rootDSE", "file", 2, 2, 0, ARG_MAGIC|CFG_ROOTDSE,
405                 &config_generic, "( OLcfgAt:51 NAME 'olcRootDSE' "
406                         "SYNTAX OMsDirectoryString )", NULL, NULL },
407         { "rootpw", "password", 2, 2, 0, ARG_STRING|ARG_DB|ARG_MAGIC,
408                 &config_rootpw, "( OLcfgAt:52 NAME 'olcRootPW' "
409                         "SYNTAX OMsOctetString SINGLE-VALUE )", NULL, NULL },
410         { "sasl-authz-policy", NULL, 2, 2, 0, ARG_MAGIC|CFG_AZPOLICY,
411                 &config_generic, NULL, NULL, NULL },
412         { "sasl-host", "host", 2, 2, 0,
413 #ifdef HAVE_CYRUS_SASL
414                 ARG_STRING|ARG_UNIQUE, &global_host,
415 #else
416                 ARG_IGNORED, NULL,
417 #endif
418                 "( OLcfgAt:53 NAME 'olcSaslHost' "
419                         "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL },
420         { "sasl-realm", "realm", 2, 2, 0,
421 #ifdef HAVE_CYRUS_SASL
422                 ARG_STRING|ARG_UNIQUE, &global_realm,
423 #else
424                 ARG_IGNORED, NULL,
425 #endif
426                 "( OLcfgAt:54 NAME 'olcSaslRealm' "
427                         "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL },
428         { "sasl-regexp", NULL, 3, 3, 0, ARG_MAGIC|CFG_AZREGEXP,
429                 &config_generic, NULL, NULL, NULL },
430         { "sasl-secprops", "properties", 2, 2, 0,
431 #ifdef HAVE_CYRUS_SASL
432                 ARG_MAGIC|CFG_SASLSECP, &config_generic,
433 #else
434                 ARG_IGNORED, NULL,
435 #endif
436                 "( OLcfgAt:56 NAME 'olcSaslSecProps' "
437                         "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL },
438         { "saslRegexp", NULL, 3, 3, 0, ARG_MAGIC|CFG_AZREGEXP,
439                 &config_generic, NULL, NULL, NULL },
440         { "schemacheck", "on|off", 2, 2, 0, ARG_ON_OFF|ARG_MAGIC|CFG_CHECK,
441                 &config_generic, "( OLcfgAt:57 NAME 'olcSchemaCheck' "
442                         "SYNTAX OMsBoolean SINGLE-VALUE )", NULL, NULL },
443         { "schemadn", "dn", 2, 2, 0, ARG_MAY_DB|ARG_DN|ARG_MAGIC,
444                 &config_schema_dn, "( OLcfgAt:58 NAME 'olcSchemaDN' "
445                         "SYNTAX OMsDN SINGLE-VALUE )", NULL, NULL },
446         { "security", "factors", 2, 0, 0, ARG_MAY_DB|ARG_MAGIC,
447                 &config_security, "( OLcfgAt:59 NAME 'olcSecurity' "
448                         "SYNTAX OMsDirectoryString )", NULL, NULL },
449         { "sizelimit", "limit", 2, 0, 0, ARG_MAY_DB|ARG_MAGIC|CFG_SIZE,
450                 &config_sizelimit, "( OLcfgAt:60 NAME 'olcSizeLimit' "
451                         "SYNTAX OMsInteger )", NULL, NULL },
452         { "sockbuf_max_incoming", "max", 2, 2, 0, ARG_BER_LEN_T,
453                 &sockbuf_max_incoming, "( OLcfgAt:61 NAME 'olcSockbufMaxIncoming' "
454                         "SYNTAX OMsInteger SINGLE-VALUE )", NULL, NULL },
455         { "sockbuf_max_incoming_auth", "max", 2, 2, 0, ARG_BER_LEN_T,
456                 &sockbuf_max_incoming_auth, "( OLcfgAt:62 NAME 'olcSockbufMaxIncomingAuth' "
457                         "SYNTAX OMsInteger SINGLE-VALUE )", NULL, NULL },
458         { "srvtab", "file", 2, 2, 0,
459 #ifdef LDAP_API_FEATURE_X_OPENLDAP_V2_KBIND
460                 ARG_STRING, &ldap_srvtab,
461 #else
462                 ARG_IGNORED, NULL,
463 #endif
464                 "( OLcfgAt:63 NAME 'olcSrvtab' "
465                         "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL },
466         { "suffix",     "suffix", 2, 2, 0, ARG_DB|ARG_DN|ARG_MAGIC,
467                 &config_suffix, "( OLcfgAt:64 NAME 'olcSuffix' "
468                         "SYNTAX OMsDN )", NULL, NULL },
469         { "syncrepl", NULL, 0, 0, 0, ARG_DB|ARG_MAGIC,
470                 &config_syncrepl, "( OLcfgAt:65 NAME 'olcSyncrepl' "
471                         "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL },
472         { "threads", "count", 2, 2, 0, ARG_INT|ARG_MAGIC|CFG_THREADS,
473                 &config_generic, "( OLcfgAt:66 NAME 'olcThreads' "
474                         "SYNTAX OMsInteger SINGLE-VALUE )", NULL, NULL },
475         { "timelimit", "limit", 2, 0, 0, ARG_MAY_DB|ARG_MAGIC|CFG_TIME,
476                 &config_timelimit, "( OLcfgAt:67 NAME 'olcTimeLimit' "
477                         "SYNTAX OMsInteger )", NULL, NULL },
478         { "TLSCACertificateFile", NULL, 0, 0, 0,
479 #ifdef HAVE_TLS
480                 CFG_TLS_CA_FILE|ARG_STRING|ARG_MAGIC, &config_tls_option,
481 #else
482                 ARG_IGNORED, NULL,
483 #endif
484                 "( OLcfgAt:68 NAME 'olcTLSCACertificateFile' "
485                         "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL },
486         { "TLSCACertificatePath", NULL, 0, 0, 0,
487 #ifdef HAVE_TLS
488                 CFG_TLS_CA_PATH|ARG_STRING|ARG_MAGIC, &config_tls_option,
489 #else
490                 ARG_IGNORED, NULL,
491 #endif
492                 "( OLcfgAt:69 NAME 'olcTLSCACertificatePath' "
493                         "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL },
494         { "TLSCertificateFile", NULL, 0, 0, 0,
495 #ifdef HAVE_TLS
496                 CFG_TLS_CERT_FILE|ARG_STRING|ARG_MAGIC, &config_tls_option,
497 #else
498                 ARG_IGNORED, NULL,
499 #endif
500                 "( OLcfgAt:70 NAME 'olcTLSCertificateFile' "
501                         "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL },
502         { "TLSCertificateKeyFile", NULL, 0, 0, 0,
503 #ifdef HAVE_TLS
504                 CFG_TLS_CERT_KEY|ARG_STRING|ARG_MAGIC, &config_tls_option,
505 #else
506                 ARG_IGNORED, NULL,
507 #endif
508                 "( OLcfgAt:71 NAME 'olcTLSCertificateKeyFile' "
509                         "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL },
510         { "TLSCipherSuite",     NULL, 0, 0, 0,
511 #ifdef HAVE_TLS
512                 CFG_TLS_CIPHER|ARG_STRING|ARG_MAGIC, &config_tls_option,
513 #else
514                 ARG_IGNORED, NULL,
515 #endif
516                 "( OLcfgAt:72 NAME 'olcTLSCipherSuite' "
517                         "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL },
518         { "TLSCRLCheck", NULL, 0, 0, 0,
519 #ifdef HAVE_TLS
520                 CFG_TLS_CRLCHECK|ARG_STRING|ARG_MAGIC, &config_tls_config,
521 #else
522                 ARG_IGNORED, NULL,
523 #endif
524                 "( OLcfgAt:73 NAME 'olcTLSCRLCheck' "
525                         "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL },
526         { "TLSRandFile", NULL, 0, 0, 0,
527 #ifdef HAVE_TLS
528                 CFG_TLS_RAND|ARG_STRING|ARG_MAGIC, &config_tls_option,
529 #else
530                 ARG_IGNORED, NULL,
531 #endif
532                 "( OLcfgAt:74 NAME 'olcTLSRandFile' "
533                         "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL },
534         { "TLSVerifyClient", NULL, 0, 0, 0,
535 #ifdef HAVE_TLS
536                 CFG_TLS_VERIFY|ARG_STRING|ARG_MAGIC, &config_tls_config,
537 #else
538                 ARG_IGNORED, NULL,
539 #endif
540                 "( OLcfgAt:75 NAME 'olcTLSVerifyClient' "
541                         "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL },
542         { "ucdata-path", "path", 2, 2, 0, ARG_IGNORED,
543                 NULL, NULL, NULL, NULL },
544         { "updatedn", "dn", 2, 2, 0, ARG_DB|ARG_MAGIC,
545                 &config_updatedn, "( OLcfgAt:76 NAME 'olcUpdateDN' "
546                         "SYNTAX OMsDN SINGLE-VALUE )", NULL, NULL },
547         { "updateref", "url", 2, 2, 0, ARG_DB|ARG_MAGIC,
548                 &config_updateref, "( OLcfgAt:77 NAME 'olcUpdateRef' "
549                         "SUP labeledURI )", NULL, NULL },
550         { NULL, NULL, 0, 0, 0, ARG_IGNORED,
551                 NULL, NULL, NULL, NULL }
552 };
553
554 static ConfigOCs cf_ocs[] = {
555         { "( OLcfgOc:1 "
556                 "NAME 'olcConfig' "
557                 "DESC 'OpenLDAP configuration object' "
558                 "ABSTRACT SUP top "
559                 "MAY ( cn $ olcConfigFile ) )", NULL },
560         { "( OLcfgOc:3 "
561                 "NAME 'olcGlobal' "
562                 "DESC 'OpenLDAP Global configuration options' "
563                 "SUP olcConfig STRUCTURAL "
564                 "MAY ( olcConfigDir $ olcAllows $ olcArgsFile $ olcAttributeOptions $ "
565                  "olcAuthIDRewrite $ olcAuthzPolicy $ olcAuthzRegexp $ "
566                  "olcConcurrency $ olcConnMaxPending $ olcConnMaxPendingAuth $ "
567                  "olcDefaultSearchBase $ olcDisallows $ olcGentleHUP $ "
568                  "olcIdleTimeout $ olcIndexSubstrIfMaxLen $ olcIndexSubstrIfMinLen $ "
569                  "olcIndexSubstrAnyLen $ olcIndexSubstrAnyStep $ olcLocalSSF $ "
570                  "olcLogLevel $ olcModuleLoad $ olcModulePath $ olcObjectIdentifier $ "
571                  "olcPasswordCryptSaltFormat $ olcPasswordHash $ olcPidFile $ "
572                  "olcPlugin $ olcPluginLogFile $ olcReadOnly $ olcReferral $ "
573                  "olcReplicaPidFile $ olcReplicaArgsFile $ olcReplicationInterval $ "
574                  "olcReplogFile $ olcRequires $ olcRestrict $ olcReverseLookup $ "
575                  "olcRootDSE $ olcSaslHost $ olcSaslRealm $ olcSaslSecProps $ "
576                  "olcSchemaCheck $ olcSchemaDN $ olcSecurity $ olcSizeLimit $ "
577                  "olcSockbufMaxIncoming $ olcSockbufMaxIncomingAuth $ olcSrvtab $ "
578                  "olcThreads $ olcTimeLimit $ olcTLSCACertificateFile $ "
579                  "olcTLSCACertificatePath $ olcTLSCertificateFile $ "
580                  "olcTLSCertificateKeyFile $ olcTLSCipherSuite $ olcTLSCRLCheck $ "
581                  "olcTLSRandFile $ olcTLSVerifyClient ) )", &cfOc_global },
582         { "( OLcfgOc:4 "
583                 "NAME 'olcBackendConfig' "
584                 "DESC 'OpenLDAP Backend-specific options' "
585                 "SUP olcConfig STRUCTURAL "
586                 "MAY ( olcBackend ) )", &cfOc_backend },
587         { "( OLcfgOc:5 "
588                 "NAME 'olcDatabaseConfig' "
589                 "DESC 'OpenLDAP Database-specific options' "
590                 "SUP olcConfig STRUCTURAL "
591                 "MAY ( olcDatabase $ olcAccess $ olcLastMod $ olcLimits $ "
592                  "olcMaxDerefDepth $ olcPlugin $ olcReadOnly $ olcReplica $ "
593                  "olcReplogFile $ olcRequires $ olcRestrict $ olcRootDN $ olcRootPW $ "
594                  "olcSchemaDN $ olcSecurity $ olcSizeLimit $ olcSuffix $ olcSyncrepl $ "
595                  "olcTimeLimit $ olcUpdateDN $ olcUpdateRef ) )", &cfOc_database },
596         { "( OLcfgOc:6 "
597                 "NAME 'olcIncludeFile' "
598                 "DESC 'OpenLDAP configuration include file' "
599                 "SUP olcConfig STRUCTURAL "
600                 "MAY ( olcInclude $ olcModuleLoad $ olcModulePath $ olcRootDSE ) )",
601                 &cfOc_include },
602         { "( OLcfgOc:7 "
603                 "NAME 'olcOverlayConfig' "
604                 "DESC 'OpenLDAP Overlay-specific options' "
605                 "SUP olcConfig STRUCTURAL "
606                 "MAY ( olcOverlay ) )", &cfOc_overlay },
607         { "( OLcfgOc:8 "
608                 "NAME 'olcACL' "
609                 "DESC 'OpenLDAP Access Control List' "
610                 "SUP olcConfig STRUCTURAL "
611                 "MUST ( olcAccess ) )", &cfOc_access },
612         { NULL, NULL }
613 };
614
615 static int
616 config_generic(ConfigArgs *c) {
617         char *p;
618         int i;
619
620         if ( c->op == SLAP_CONFIG_EMIT ) {
621                 int rc = 0;
622                 switch(c->type) {
623                 case CFG_CONCUR:
624                         c->value_int = ldap_pvt_thread_get_concurrency();
625                         break;
626                 case CFG_THREADS:
627                         c->value_int = connection_pool_max;
628                         break;
629                 case CFG_SALT:
630                         if ( passwd_salt )
631                                 c->value_string = ch_strdup( passwd_salt );
632                         else
633                                 rc = 1;
634                         break;
635                 case CFG_LIMITS:
636                         if ( c->be->be_limits ) {
637                                 char buf[4096*3];
638                                 struct berval bv;
639                                 int i;
640
641                                 for ( i=0; c->be->be_limits[i]; i++ ) {
642                                         bv.bv_len = sprintf( buf, "{%d}", i );
643                                         bv.bv_val = buf+bv.bv_len;
644                                         limits_unparse( c->be->be_limits[i], &bv );
645                                         bv.bv_len += bv.bv_val - buf;
646                                         bv.bv_val = buf;
647                                         value_add_one( &c->rvalue_vals, &bv );
648                                 }
649                         }
650                         if ( !c->rvalue_vals ) rc = 1;
651                         break;
652                 case CFG_RO:
653                         c->value_int = (c->be->be_restrictops & SLAP_RESTRICT_OP_WRITES) != 0;
654                         break;
655                 case CFG_AZPOLICY:
656                         c->value_string = ch_strdup( slap_sasl_getpolicy());
657                         break;
658                 case CFG_AZREGEXP:
659                         slap_sasl_regexp_unparse( &c->rvalue_vals );
660                         if ( !c->rvalue_vals ) rc = 1;
661                         break;
662 #ifdef HAVE_CYRUS_SASL
663                 case CFG_SASLSECP: {
664                         struct berval bv = BER_BVNULL;
665                         slap_sasl_secprops_unparse( &bv );
666                         if ( !BER_BVISNULL( &bv )) {
667                                 ber_bvarray_add( &c->rvalue_vals, &bv );
668                         } else {
669                                 rc = 1;
670                         }
671                         }
672                         break;
673 #endif
674                 case CFG_DEPTH:
675                         c->value_int = c->be->be_max_deref_depth;
676                         break;
677                 case CFG_OID:
678                         oidm_unparse( &c->rvalue_vals );
679                         if ( !c->rvalue_vals )
680                                 rc = 1;
681                         break;
682                 case CFG_CHECK:
683                         c->value_int = global_schemacheck;
684                         break;
685                 case CFG_ACL: {
686                         AccessControl *a;
687                         char *src, *dst, ibuf[11];
688                         struct berval bv, abv;
689                         for (i=0, a=c->be->be_acl; a; i++,a=a->acl_next) {
690                                 abv.bv_len = sprintf( ibuf, "{%x}", i );
691                                 acl_unparse( a, &bv );
692                                 abv.bv_val = ch_malloc( abv.bv_len + bv.bv_len + 1 );
693                                 AC_MEMCPY( abv.bv_val, ibuf, abv.bv_len );
694                                 /* Turn TAB / EOL into plain space */
695                                 for (src=bv.bv_val,dst=abv.bv_val+abv.bv_len; *src; src++) {
696                                         if (isspace(*src)) *dst++ = ' ';
697                                         else *dst++ = *src;
698                                 }
699                                 *dst = '\0';
700                                 if (dst[-1] == ' ') {
701                                         dst--;
702                                         *dst = '\0';
703                                 }
704                                 abv.bv_len = dst - abv.bv_val;
705                                 ber_bvarray_add( &c->rvalue_vals, &abv );
706                         }
707                         rc = (!i);
708                         break;
709                 }
710                 case CFG_REPLOG:
711                         if ( c->be->be_replogfile )
712                                 c->value_string = ch_strdup( c->be->be_replogfile );
713                         break;
714                 case CFG_ROOTDSE: {
715                         ConfigFile *cf = (ConfigFile *)c->line;
716                         if ( cf->c_dseFiles ) {
717                                 value_add( &c->rvalue_vals, cf->c_dseFiles );
718                         } else {
719                                 rc = 1;
720                         }
721                         }
722                         break;
723                 case CFG_LOGFILE:
724                         if ( logfileName )
725                                 c->value_string = ch_strdup( logfileName );
726                         else
727                                 rc = 1;
728                         break;
729                 case CFG_LASTMOD:
730                         c->value_int = (SLAP_NOLASTMOD(c->be) == 0);
731                         break;
732                 case CFG_SSTR_IF_MAX:
733                         c->value_int = index_substr_if_maxlen;
734                         break;
735                 case CFG_SSTR_IF_MIN:
736                         c->value_int = index_substr_if_minlen;
737                         break;
738 #ifdef SLAPD_MODULES
739                 case CFG_MODLOAD: {
740                         ConfigFile *cf = (ConfigFile *)c->line;
741                         ModPaths *mp;
742                         for (i=0, mp=&cf->c_modpaths; mp; mp=mp->mp_next, i++) {
743                                 int j;
744                                 if (!mp->mp_loads) continue;
745                                 for (j=0; !BER_BVISNULL(&mp->mp_loads[j]); j++) {
746                                         struct berval bv;
747                                         bv.bv_val = c->log;
748                                         bv.bv_len = sprintf( bv.bv_val, "{%d}{%d}%s", i, j,
749                                                 mp->mp_loads[j].bv_val );
750                                         value_add_one( &c->rvalue_vals, &bv );
751                                 }
752                         }
753                         rc = c->rvalue_vals ? 0 : 1;
754                         }
755                         break;
756                 case CFG_MODPATH: {
757                         ConfigFile *cf = (ConfigFile *)c->line;
758                         ModPaths *mp;
759                         for (i=0, mp=&cf->c_modpaths; mp; mp=mp->mp_next, i++) {
760                                 struct berval bv;
761                                 if ( BER_BVISNULL( &mp->mp_path ) && !mp->mp_loads )
762                                         continue;
763                                 bv.bv_val = c->log;
764                                 bv.bv_len = sprintf( bv.bv_val, "{%d}%s", i,
765                                         mp->mp_path.bv_val );
766                                 value_add_one( &c->rvalue_vals, &bv );
767                         }
768                         rc = c->rvalue_vals ? 0 : 1;
769                         }
770                         break;
771 #endif
772 #ifdef LDAP_SLAPI
773                 case CFG_PLUGIN:
774                         slapi_int_plugin_unparse( c->be, &c->rvalue_vals );
775                         if ( !c->rvalue_vals ) rc = 1;
776                         break;
777 #endif
778 #ifdef SLAP_AUTH_REWRITE
779                 case CFG_REWRITE:
780                         if ( authz_rewrites ) {
781                                 struct berval bv, idx;
782                                 char ibuf[32];
783                                 int i;
784
785                                 idx.bv_val = ibuf;
786                                 for ( i=0; !BER_BVISNULL( &authz_rewrites[i] ); i++ ) {
787                                         idx.bv_len = sprintf( idx.bv_val, "{%d}", i );
788                                         bv.bv_len = idx.bv_len + authz_rewrites[i].bv_len;
789                                         bv.bv_val = ch_malloc( bv.bv_len + 1 );
790                                         strcpy( bv.bv_val, idx.bv_val );
791                                         strcpy( bv.bv_val+idx.bv_len, authz_rewrites[i].bv_val );
792                                         ber_bvarray_add( &c->rvalue_vals, &bv );
793                                 }
794                         }
795                         if ( !c->rvalue_vals ) rc = 1;
796                         break;
797 #endif
798                 default:
799                         rc = 1;
800                 }
801                 return rc;
802         }
803
804         p = strchr(c->line,'(' /*')'*/);
805         switch(c->type) {
806                 case CFG_BACKEND:
807                         if(!(c->bi = backend_info(c->argv[1]))) {
808                                 Debug(LDAP_DEBUG_ANY, "%s: "
809                                         "backend %s failed init!\n", c->log, c->argv[1], 0);
810                                 return(1);
811                         }
812                         break;
813
814                 case CFG_DATABASE:
815                         c->bi = NULL;
816                         /* NOTE: config is always the first backend!
817                          */
818                         if ( !strcasecmp( c->argv[1], "config" )) {
819                                 c->be = backendDB;
820                         } else if(!(c->be = backend_db_init(c->argv[1]))) {
821                                 Debug(LDAP_DEBUG_ANY, "%s: "
822                                         "database %s failed init!\n", c->log, c->argv[1], 0);
823                                 return(1);
824                         }
825                         break;
826
827                 case CFG_CONCUR:
828                         ldap_pvt_thread_set_concurrency(c->value_int);
829                         break;
830
831                 case CFG_THREADS:
832                         ldap_pvt_thread_pool_maxthreads(&connection_pool, c->value_int);
833                         connection_pool_max = c->value_int;     /* save for reference */
834                         break;
835
836                 case CFG_SALT:
837                         if ( passwd_salt ) ch_free( passwd_salt );
838                         passwd_salt = c->value_string;
839                         lutil_salt_format(passwd_salt);
840                         break;
841
842                 case CFG_LIMITS:
843                         if(limits_parse(c->be, c->fname, c->lineno, c->argc, c->argv))
844                                 return(1);
845                         break;
846
847                 case CFG_RO:
848                         if(c->value_int)
849                                 c->be->be_restrictops |= SLAP_RESTRICT_OP_WRITES;
850                         else
851                                 c->be->be_restrictops &= ~SLAP_RESTRICT_OP_WRITES;
852                         break;
853
854                 case CFG_AZPOLICY:
855                         ch_free(c->value_string);
856                         if (slap_sasl_setpolicy( c->argv[1] )) {
857                                 Debug(LDAP_DEBUG_ANY, "%s: unable to parse value \"%s\" in"
858                                         " \"authz-policy <policy>\"\n",
859                                         c->log, c->argv[1], 0 );
860                                 return(1);
861                         }
862                         break;
863                 
864                 case CFG_AZREGEXP:
865                         if (slap_sasl_regexp_config( c->argv[1], c->argv[2] ))
866                                 return(1);
867                         break;
868                                 
869 #ifdef HAVE_CYRUS_SASL
870                 case CFG_SASLSECP:
871                         {
872                         char *txt = slap_sasl_secprops( c->argv[1] );
873                         if ( txt ) {
874                                 Debug(LDAP_DEBUG_ANY, "%s: sasl-secprops: %s\n",
875                                         c->log, txt, 0 );
876                                 return(1);
877                         }
878                         break;
879                         }
880 #endif
881
882                 case CFG_DEPTH:
883                         c->be->be_max_deref_depth = c->value_int;
884                         break;
885
886                 case CFG_OID:
887                         if(parse_oidm(c->fname, c->lineno, c->argc, c->argv)) return(1);
888                         break;
889
890                 case CFG_OC:
891                         if(parse_oc(c->fname, c->lineno, p, c->argv)) return(1);
892                         break;
893
894                 case CFG_DIT:
895                         if(parse_cr(c->fname, c->lineno, p, c->argv)) return(1);
896                         break;
897
898                 case CFG_ATTR:
899                         if(parse_at(c->fname, c->lineno, p, c->argv)) return(1);
900                         break;
901
902                 case CFG_ATOPT:
903                         ad_define_option(NULL, NULL, 0);
904                         for(i = 1; i < c->argc; i++)
905                                 if(ad_define_option(c->argv[i], c->fname, c->lineno))
906                                         return(1);
907                         break;
908
909                 case CFG_CHECK:
910                         global_schemacheck = c->value_int;
911                         if(!global_schemacheck) Debug(LDAP_DEBUG_ANY, "%s: "
912                                 "schema checking disabled! your mileage may vary!\n",
913                                 c->log, 0, 0);
914                         break;
915
916                 case CFG_ACL:
917                         parse_acl(c->be, c->fname, c->lineno, c->argc, c->argv);
918                         break;
919
920                 case CFG_REPLOG:
921                         if(SLAP_MONITOR(c->be)) {
922                                 Debug(LDAP_DEBUG_ANY, "%s: "
923                                         "\"replogfile\" should not be used "
924                                         "inside monitor database\n",
925                                         c->log, 0, 0);
926                                 return(0);      /* FIXME: should this be an error? */
927                         }
928
929                         c->be->be_replogfile = c->value_string;
930                         break;
931
932                 case CFG_ROOTDSE:
933                         if(read_root_dse_file(c->argv[1])) {
934                                 Debug(LDAP_DEBUG_ANY, "%s: "
935                                         "could not read \"rootDSE <filename>\" line\n",
936                                         c->log, 0, 0);
937                                 return(1);
938                         }
939                         {
940                                 struct berval bv;
941                                 ber_str2bv( c->argv[1], 0, 1, &bv );
942                                 ber_bvarray_add( &cfn->c_dseFiles, &bv );
943                         }
944                         break;
945
946                 case CFG_LOGFILE: {
947                                 FILE *logfile;
948                                 if ( logfileName ) ch_free( logfileName );
949                                 logfileName = c->value_string;
950                                 logfile = fopen(logfileName, "w");
951                                 if(logfile) lutil_debug_file(logfile);
952                         } break;
953
954                 case CFG_LASTMOD:
955                         if(SLAP_NOLASTMODCMD(c->be)) {
956                                 Debug(LDAP_DEBUG_ANY, "%s: "
957                                         "lastmod not available for %s databases\n",
958                                         c->log, c->be->bd_info->bi_type, 0);
959                                 return(1);
960                         }
961                         if(c->value_int)
962                                 SLAP_DBFLAGS(c->be) &= ~SLAP_DBFLAG_NOLASTMOD;
963                         else
964                                 SLAP_DBFLAGS(c->be) |= SLAP_DBFLAG_NOLASTMOD;
965                         break;
966
967                 case CFG_SSTR_IF_MAX:
968                         if (c->value_int < index_substr_if_minlen) {
969                                 Debug(LDAP_DEBUG_ANY, "%s: "
970                                         "invalid max value (%d)\n",
971                                         c->log, c->value_int, 0 );
972                                 return(1);
973                         }
974                         index_substr_if_maxlen = c->value_int;
975                         break;
976
977                 case CFG_SSTR_IF_MIN:
978                         if (c->value_int > index_substr_if_maxlen) {
979                                 Debug(LDAP_DEBUG_ANY, "%s: "
980                                         "invalid min value (%d)\n",
981                                         c->log, c->value_int, 0 );
982                                 return(1);
983                         }
984                         index_substr_if_minlen = c->value_int;
985                         break;
986
987 #ifdef SLAPD_MODULES
988                 case CFG_MODLOAD:
989                         if(module_load(c->argv[1], c->argc - 2, (c->argc > 2) ? c->argv + 2 : NULL))
990                                 return(1);
991                         /* Record this load on the current path */
992                         {
993                                 struct berval bv;
994                                 ber_str2bv(c->line, 0, 1, &bv);
995                                 ber_bvarray_add( &cfn->c_modlast->mp_loads, &bv );
996                         }
997                         break;
998
999                 case CFG_MODPATH:
1000                         if(module_path(c->argv[1])) return(1);
1001                         /* Record which path was used with each module */
1002                         {
1003                                 ModPaths *mp;
1004
1005                                 if (!cfn->c_modpaths.mp_loads) {
1006                                         mp = &cfn->c_modpaths;
1007                                 } else {
1008                                         mp = ch_malloc( sizeof( ModPaths ));
1009                                         cfn->c_modlast->mp_next = mp;
1010                                 }
1011                                 ber_str2bv(c->argv[1], 0, 1, &mp->mp_path);
1012                                 mp->mp_next = NULL;
1013                                 mp->mp_loads = NULL;
1014                                 cfn->c_modlast = mp;
1015                         }
1016                         
1017                         break;
1018 #endif
1019
1020 #ifdef LDAP_SLAPI
1021                 case CFG_PLUGIN:
1022                         if(slapi_int_read_config(c->be, c->fname, c->lineno, c->argc, c->argv) != LDAP_SUCCESS)
1023                                 return(1);
1024                         slapi_plugins_used++;
1025                         break;
1026 #endif
1027
1028 #ifdef SLAP_AUTH_REWRITE
1029                 case CFG_REWRITE: {
1030                         struct berval bv;
1031                         if(slap_sasl_rewrite_config(c->fname, c->lineno, c->argc, c->argv))
1032                                 return(1);
1033                         ber_str2bv( c->line, 0, 1, &bv );
1034                         ber_bvarray_add( &authz_rewrites, &bv );
1035                         }
1036                         break;
1037 #endif
1038
1039
1040                 default:
1041                         Debug(LDAP_DEBUG_ANY, "%s: unknown CFG_TYPE %d"
1042                                 "(ignored)\n", c->log, c->type, 0);
1043
1044         }
1045         return(0);
1046 }
1047
1048
1049 static int
1050 config_fname(ConfigArgs *c) {
1051         if(c->op == SLAP_CONFIG_EMIT && c->line) {
1052                 ConfigFile *cf = (ConfigFile *)c->line;
1053                 value_add_one( &c->rvalue_vals, &cf->c_file );
1054                 return 0;
1055         }
1056         return(1);
1057 }
1058
1059 static int
1060 config_cfdir(ConfigArgs *c) {
1061         if(c->op == SLAP_CONFIG_EMIT) {
1062                 value_add_one( &c->rvalue_vals, &cfdir );
1063                 return 0;
1064         }
1065         return(1);
1066 }
1067
1068 static int
1069 config_search_base(ConfigArgs *c) {
1070         struct berval dn;
1071
1072         if(c->op == SLAP_CONFIG_EMIT) {
1073                 int rc = 1;
1074                 if (!BER_BVISEMPTY(&default_search_base)) {
1075                         value_add_one(&c->rvalue_vals, &default_search_base);
1076                         value_add_one(&c->rvalue_nvals, &default_search_nbase);
1077                         rc = 0;
1078                 }
1079                 return rc;
1080         }
1081
1082         if(c->bi || c->be != frontendDB) {
1083                 Debug(LDAP_DEBUG_ANY, "%s: defaultSearchBase line must appear "
1084                         "prior to any backend or database definition\n",
1085                         c->log, 0, 0);
1086                 return(1);
1087         }
1088
1089         if(default_search_nbase.bv_len) {
1090                 Debug(LDAP_DEBUG_ANY, "%s: "
1091                         "default search base \"%s\" already defined "
1092                         "(discarding old)\n",
1093                         c->log, default_search_base.bv_val, 0);
1094                 free(default_search_base.bv_val);
1095                 free(default_search_nbase.bv_val);
1096         }
1097
1098         default_search_base = c->value_dn;
1099         default_search_nbase = c->value_ndn;
1100         return(0);
1101 }
1102
1103 static int
1104 config_passwd_hash(ConfigArgs *c) {
1105         int i;
1106         if (c->op == SLAP_CONFIG_EMIT) {
1107                 struct berval bv;
1108                 for (i=0; default_passwd_hash && default_passwd_hash[i]; i++) {
1109                         ber_str2bv(default_passwd_hash[i], 0, 0, &bv);
1110                         value_add_one(&c->rvalue_vals, &bv);
1111                 }
1112                 return i ? 0 : 1;
1113         }
1114         if(default_passwd_hash) {
1115                 Debug(LDAP_DEBUG_ANY, "%s: "
1116                         "already set default password_hash\n",
1117                         c->log, 0, 0);
1118                 return(1);
1119         }
1120         for(i = 1; i < c->argc; i++) {
1121                 if(!lutil_passwd_scheme(c->argv[i])) {
1122                         Debug(LDAP_DEBUG_ANY, "%s: "
1123                                 "password scheme \"%s\" not available\n",
1124                                 c->log, c->argv[i], 0);
1125                 } else {
1126                         ldap_charray_add(&default_passwd_hash, c->argv[i]);
1127                 }
1128                 if(!default_passwd_hash) {
1129                         Debug(LDAP_DEBUG_ANY, "%s: no valid hashes found\n",
1130                                 c->log, 0, 0 );
1131                         return(1);
1132                 }
1133         }
1134         return(0);
1135 }
1136
1137 static int
1138 config_schema_dn(ConfigArgs *c) {
1139         if ( c->op == SLAP_CONFIG_EMIT ) {
1140                 int rc = 1;
1141                 if ( !BER_BVISEMPTY( &c->be->be_schemadn )) {
1142                         value_add_one(&c->rvalue_vals, &c->be->be_schemadn);
1143                         value_add_one(&c->rvalue_nvals, &c->be->be_schemandn);
1144                         rc = 0;
1145                 }
1146                 return rc;
1147         }
1148         c->be->be_schemadn = c->value_dn;
1149         c->be->be_schemandn = c->value_ndn;
1150         return(0);
1151 }
1152
1153 static int
1154 config_sizelimit(ConfigArgs *c) {
1155         int i, rc = 0;
1156         char *next;
1157         struct slap_limits_set *lim = &c->be->be_def_limit;
1158         if (c->op == SLAP_CONFIG_EMIT) {
1159                 char buf[8192];
1160                 struct berval bv;
1161                 bv.bv_val = buf;
1162                 bv.bv_len = 0;
1163                 limits_unparse_one( lim, SLAP_LIMIT_SIZE, &bv );
1164                 if ( !BER_BVISEMPTY( &bv ))
1165                         value_add_one( &c->rvalue_vals, &bv );
1166                 else
1167                         rc = 1;
1168                 return rc;
1169         }
1170         for(i = 1; i < c->argc; i++) {
1171                 if(!strncasecmp(c->argv[i], "size", 4)) {
1172                         rc = limits_parse_one(c->argv[i], lim);
1173                         if ( rc ) {
1174                                 Debug(LDAP_DEBUG_ANY, "%s: "
1175                                         "unable to parse value \"%s\" in \"sizelimit <limit>\" line\n",
1176                                         c->log, c->argv[i], 0);
1177                                 return(1);
1178                         }
1179                 } else {
1180                         if(!strcasecmp(c->argv[i], "unlimited")) {
1181                                 lim->lms_s_soft = -1;
1182                         } else {
1183                                 lim->lms_s_soft = strtol(c->argv[i], &next, 0);
1184                                 if(next == c->argv[i]) {
1185                                         Debug(LDAP_DEBUG_ANY, "%s: "
1186                                                 "unable to parse limit \"%s\" in \"sizelimit <limit>\" line\n",
1187                                                 c->log, c->argv[i], 0);
1188                                         return(1);
1189                                 } else if(next[0] != '\0') {
1190                                         Debug(LDAP_DEBUG_ANY, "%s: "
1191                                                 "trailing chars \"%s\" in \"sizelimit <limit>\" line (ignored)\n",
1192                                                 c->log, next, 0);
1193                                 }
1194                         }
1195                         lim->lms_s_hard = 0;
1196                 }
1197         }
1198         return(0);
1199 }
1200
1201 static int
1202 config_timelimit(ConfigArgs *c) {
1203         int i, rc = 0;
1204         char *next;
1205         struct slap_limits_set *lim = &c->be->be_def_limit;
1206         if (c->op == SLAP_CONFIG_EMIT) {
1207                 char buf[8192];
1208                 struct berval bv;
1209                 bv.bv_val = buf;
1210                 bv.bv_len = 0;
1211                 limits_unparse_one( lim, SLAP_LIMIT_TIME, &bv );
1212                 if ( !BER_BVISEMPTY( &bv ))
1213                         value_add_one( &c->rvalue_vals, &bv );
1214                 else
1215                         rc = 1;
1216                 return rc;
1217         }
1218         for(i = 1; i < c->argc; i++) {
1219                 if(!strncasecmp(c->argv[i], "time", 4)) {
1220                         rc = limits_parse_one(c->argv[i], lim);
1221                         if ( rc ) {
1222                                 Debug(LDAP_DEBUG_ANY, "%s: "
1223                                         "unable to parse value \"%s\" in \"timelimit <limit>\" line\n",
1224                                         c->log, c->argv[i], 0);
1225                                 return(1);
1226                         }
1227                 } else {
1228                         if(!strcasecmp(c->argv[i], "unlimited")) {
1229                                 lim->lms_t_soft = -1;
1230                         } else {
1231                                 lim->lms_t_soft = strtol(c->argv[i], &next, 0);
1232                                 if(next == c->argv[i]) {
1233                                         Debug(LDAP_DEBUG_ANY, "%s: "
1234                                                 "unable to parse limit \"%s\" in \"timelimit <limit>\" line\n",
1235                                                 c->log, c->argv[i], 0);
1236                                         return(1);
1237                                 } else if(next[0] != '\0') {
1238                                         Debug(LDAP_DEBUG_ANY, "%s: "
1239                                                 "trailing chars \"%s\" in \"timelimit <limit>\" line (ignored)\n",
1240                                                 c->log, next, 0);
1241                                 }
1242                         }
1243                         lim->lms_t_hard = 0;
1244                 }
1245         }
1246         return(0);
1247 }
1248
1249 static int
1250 config_overlay(ConfigArgs *c) {
1251         if (c->op == SLAP_CONFIG_EMIT) {
1252                 return 1;
1253         }
1254         if(c->argv[1][0] == '-' && overlay_config(c->be, &c->argv[1][1])) {
1255                 /* log error */
1256                 Debug(LDAP_DEBUG_ANY, "%s: (optional) %s overlay \"%s\" configuration failed (ignored)\n",
1257                         c->log, c->be == frontendDB ? "global " : "", c->argv[1][1]);
1258         } else if(overlay_config(c->be, c->argv[1])) {
1259                 return(1);
1260         }
1261         return(0);
1262 }
1263
1264 static int
1265 config_suffix(ConfigArgs *c) {
1266         Backend *tbe;
1267         struct berval pdn, ndn;
1268         int rc;
1269         if (c->op == SLAP_CONFIG_EMIT) {
1270                 if ( !BER_BVISNULL( &c->be->be_suffix[0] )) {
1271                         value_add( &c->rvalue_vals, c->be->be_suffix );
1272                         value_add( &c->rvalue_nvals, c->be->be_nsuffix );
1273                         return 0;
1274                 } else {
1275                         return 1;
1276                 }
1277         }
1278 #ifdef SLAPD_MONITOR_DN
1279         if(!strcasecmp(c->argv[1], SLAPD_MONITOR_DN)) {
1280                 Debug(LDAP_DEBUG_ANY, "%s: "
1281                         "\"%s\" is reserved for monitoring slapd\n",
1282                         c->log, SLAPD_MONITOR_DN, 0);
1283                 return(1);
1284         }
1285 #endif
1286
1287         pdn = c->value_dn;
1288         ndn = c->value_ndn;
1289         tbe = select_backend(&ndn, 0, 0);
1290         if(tbe == c->be) {
1291                 Debug(LDAP_DEBUG_ANY, "%s: suffix already served by this backend! (ignored)\n",
1292                         c->log, 0, 0);
1293                 free(pdn.bv_val);
1294                 free(ndn.bv_val);
1295         } else if(tbe) {
1296                 Debug(LDAP_DEBUG_ANY, "%s: suffix already served by a preceding backend \"%s\"\n",
1297                         c->log, tbe->be_suffix[0].bv_val, 0);
1298                 free(pdn.bv_val);
1299                 free(ndn.bv_val);
1300                 return(1);
1301         } else if(pdn.bv_len == 0 && default_search_nbase.bv_len) {
1302                 Debug(LDAP_DEBUG_ANY, "%s: suffix DN empty and default search "
1303                         "base provided \"%s\" (assuming okay)\n",
1304                         c->log, default_search_base.bv_val, 0);
1305         }
1306         ber_bvarray_add(&c->be->be_suffix, &pdn);
1307         ber_bvarray_add(&c->be->be_nsuffix, &ndn);
1308         return(0);
1309 }
1310
1311 static int
1312 config_rootdn(ConfigArgs *c) {
1313         if (c->op == SLAP_CONFIG_EMIT) {
1314                 if ( !BER_BVISNULL( &c->be->be_rootdn )) {
1315                         value_add_one(&c->rvalue_vals, &c->be->be_rootdn);
1316                         value_add_one(&c->rvalue_nvals, &c->be->be_rootndn);
1317                         return 0;
1318                 } else {
1319                         return 1;
1320                 }
1321         }
1322         c->be->be_rootdn = c->value_dn;
1323         c->be->be_rootndn = c->value_ndn;
1324         return(0);
1325 }
1326
1327 static int
1328 config_rootpw(ConfigArgs *c) {
1329         Backend *tbe;
1330         if (c->op == SLAP_CONFIG_EMIT) {
1331                 if (!BER_BVISEMPTY(&c->be->be_rootpw)) {
1332                         c->value_string=ch_strdup("*");
1333                         return 0;
1334                 }
1335                 return 1;
1336         }
1337
1338         tbe = select_backend(&c->be->be_rootndn, 0, 0);
1339         if(tbe != c->be) {
1340                 Debug(LDAP_DEBUG_ANY, "%s: "
1341                         "rootpw can only be set when rootdn is under suffix\n",
1342                         c->log, 0, 0);
1343                 return(1);
1344         }
1345         ber_str2bv(c->value_string, 0, 0, &c->be->be_rootpw);
1346         return(0);
1347 }
1348
1349 static int
1350 config_restrict(ConfigArgs *c) {
1351         slap_mask_t restrictops = 0;
1352         int i;
1353         slap_verbmasks restrictable_ops[] = {
1354                 { BER_BVC("bind"),              SLAP_RESTRICT_OP_BIND },
1355                 { BER_BVC("add"),               SLAP_RESTRICT_OP_ADD },
1356                 { BER_BVC("modify"),            SLAP_RESTRICT_OP_MODIFY },
1357                 { BER_BVC("rename"),            SLAP_RESTRICT_OP_RENAME },
1358                 { BER_BVC("modrdn"),            0 },
1359                 { BER_BVC("delete"),            SLAP_RESTRICT_OP_DELETE },
1360                 { BER_BVC("search"),            SLAP_RESTRICT_OP_SEARCH },
1361                 { BER_BVC("compare"),   SLAP_RESTRICT_OP_COMPARE },
1362                 { BER_BVC("read"),              SLAP_RESTRICT_OP_READS },
1363                 { BER_BVC("write"),             SLAP_RESTRICT_OP_WRITES },
1364                 { BER_BVC("extended"),  SLAP_RESTRICT_OP_EXTENDED },
1365                 { BER_BVC("extended=" LDAP_EXOP_START_TLS ),            SLAP_RESTRICT_EXOP_START_TLS },
1366                 { BER_BVC("extended=" LDAP_EXOP_MODIFY_PASSWD ),        SLAP_RESTRICT_EXOP_MODIFY_PASSWD },
1367                 { BER_BVC("extended=" LDAP_EXOP_X_WHO_AM_I ),           SLAP_RESTRICT_EXOP_WHOAMI },
1368                 { BER_BVC("extended=" LDAP_EXOP_X_CANCEL ),             SLAP_RESTRICT_EXOP_CANCEL },
1369                 { BER_BVNULL,   0 }
1370         };
1371
1372         if (c->op == SLAP_CONFIG_EMIT) {
1373                 return mask_to_verbs( restrictable_ops, c->be->be_restrictops,
1374                         &c->rvalue_vals );
1375         }
1376         i = verbs_to_mask( c->argc, c->argv, restrictable_ops, &restrictops );
1377         if ( i ) {
1378                 Debug(LDAP_DEBUG_ANY, "%s: "
1379                         "unknown operation %s in \"restrict <features>\" line\n",
1380                         c->log, c->argv[i], 0);
1381                 return(1);
1382         }
1383         if ( restrictops & SLAP_RESTRICT_OP_EXTENDED )
1384                 restrictops &= ~SLAP_RESTRICT_EXOP_MASK;
1385         c->be->be_restrictops |= restrictops;
1386         return(0);
1387 }
1388
1389 static int
1390 config_allows(ConfigArgs *c) {
1391         slap_mask_t allows = 0;
1392         int i;
1393         slap_verbmasks allowable_ops[] = {
1394                 { BER_BVC("bind_v2"),           SLAP_ALLOW_BIND_V2 },
1395                 { BER_BVC("bind_anon_cred"),    SLAP_ALLOW_BIND_ANON_CRED },
1396                 { BER_BVC("bind_anon_dn"),      SLAP_ALLOW_BIND_ANON_DN },
1397                 { BER_BVC("update_anon"),       SLAP_ALLOW_UPDATE_ANON },
1398                 { BER_BVNULL,   0 }
1399         };
1400         if (c->op == SLAP_CONFIG_EMIT) {
1401                 return mask_to_verbs( allowable_ops, global_allows, &c->rvalue_vals );
1402         }
1403         i = verbs_to_mask(c->argc, c->argv, allowable_ops, &allows);
1404         if ( i ) {
1405                 Debug(LDAP_DEBUG_ANY, "%s: "
1406                         "unknown feature %s in \"allow <features>\" line\n",
1407                         c->log, c->argv[i], 0);
1408                 return(1);
1409         }
1410         global_allows |= allows;
1411         return(0);
1412 }
1413
1414 static int
1415 config_disallows(ConfigArgs *c) {
1416         slap_mask_t disallows = 0;
1417         int i;
1418         slap_verbmasks disallowable_ops[] = {
1419                 { BER_BVC("bind_anon"),         SLAP_DISALLOW_BIND_ANON },
1420                 { BER_BVC("bind_simple"),       SLAP_DISALLOW_BIND_SIMPLE },
1421                 { BER_BVC("bind_krb4"),         SLAP_DISALLOW_BIND_KRBV4 },
1422                 { BER_BVC("tls_2_anon"),                SLAP_DISALLOW_TLS_2_ANON },
1423                 { BER_BVC("tls_authc"),         SLAP_DISALLOW_TLS_AUTHC },
1424                 { BER_BVNULL, 0 }
1425         };
1426         if (c->op == SLAP_CONFIG_EMIT) {
1427                 return mask_to_verbs( disallowable_ops, global_disallows, &c->rvalue_vals );
1428         }
1429         i = verbs_to_mask(c->argc, c->argv, disallowable_ops, &disallows);
1430         if ( i ) {
1431                 Debug(LDAP_DEBUG_ANY, "%s: "
1432                         "unknown feature %s in \"disallow <features>\" line\n",
1433                         c->log, c->argv[i], 0);
1434                 return(1);
1435         }
1436         global_disallows |= disallows;
1437         return(0);
1438 }
1439
1440 static int
1441 config_requires(ConfigArgs *c) {
1442         slap_mask_t requires = 0;
1443         int i;
1444         slap_verbmasks requires_ops[] = {
1445                 { BER_BVC("bind"),              SLAP_REQUIRE_BIND },
1446                 { BER_BVC("LDAPv3"),            SLAP_REQUIRE_LDAP_V3 },
1447                 { BER_BVC("authc"),             SLAP_REQUIRE_AUTHC },
1448                 { BER_BVC("sasl"),              SLAP_REQUIRE_SASL },
1449                 { BER_BVC("strong"),            SLAP_REQUIRE_STRONG },
1450                 { BER_BVNULL, 0 }
1451         };
1452         if (c->op == SLAP_CONFIG_EMIT) {
1453                 return mask_to_verbs( requires_ops, c->be->be_requires, &c->rvalue_vals );
1454         }
1455         i = verbs_to_mask(c->argc, c->argv, requires_ops, &requires);
1456         if ( i ) {
1457                 Debug(LDAP_DEBUG_ANY, "%s: "
1458                         "unknown feature %s in \"require <features>\" line\n",
1459                         c->log, c->argv[i], 0);
1460                 return(1);
1461         }
1462         c->be->be_requires = requires;
1463         return(0);
1464 }
1465
1466 static int
1467 config_loglevel(ConfigArgs *c) {
1468         int i;
1469         char *next;
1470         slap_verbmasks loglevel_ops[] = {
1471                 { BER_BVC("Trace"),     LDAP_DEBUG_TRACE },
1472                 { BER_BVC("Packets"),   LDAP_DEBUG_PACKETS },
1473                 { BER_BVC("Args"),      LDAP_DEBUG_ARGS },
1474                 { BER_BVC("Conns"),     LDAP_DEBUG_CONNS },
1475                 { BER_BVC("BER"),       LDAP_DEBUG_BER },
1476                 { BER_BVC("Filter"),    LDAP_DEBUG_FILTER },
1477                 { BER_BVC("Config"),    LDAP_DEBUG_CONFIG },
1478                 { BER_BVC("ACL"),       LDAP_DEBUG_ACL },
1479                 { BER_BVC("Stats"),     LDAP_DEBUG_STATS },
1480                 { BER_BVC("Stats2"),    LDAP_DEBUG_STATS2 },
1481                 { BER_BVC("Shell"),     LDAP_DEBUG_SHELL },
1482                 { BER_BVC("Parse"),     LDAP_DEBUG_PARSE },
1483                 { BER_BVC("Cache"),     LDAP_DEBUG_CACHE },
1484                 { BER_BVC("Index"),     LDAP_DEBUG_INDEX },
1485                 { BER_BVC("Any"),       -1 },
1486                 { BER_BVNULL,   0 }
1487         };
1488
1489         if (c->op == SLAP_CONFIG_EMIT) {
1490                 return mask_to_verbs( loglevel_ops, ldap_syslog, &c->rvalue_vals );
1491         }
1492
1493         ldap_syslog = 0;
1494
1495         for( i=1; i < c->argc; i++ ) {
1496                 int     level;
1497
1498                 if ( isdigit( c->argv[i][0] ) ) {
1499                         level = strtol( c->argv[i], &next, 10 );
1500                         if ( next == NULL || next[0] != '\0' ) {
1501                                 Debug( LDAP_DEBUG_ANY,
1502                                         "%s: unable to parse level \"%s\" "
1503                                         "in \"loglevel <level> [...]\" line.\n",
1504                                         c->log, c->argv[i], 0);
1505                                 return( 1 );
1506                         }
1507                 } else {
1508                         int j = verb_to_mask(c->argv[i], loglevel_ops);
1509                         if(BER_BVISNULL(&loglevel_ops[j].word)) {
1510                                 Debug( LDAP_DEBUG_ANY,
1511                                         "%s: unknown level \"%s\" "
1512                                         "in \"loglevel <level> [...]\" line.\n",
1513                                         c->log, c->argv[i], 0);
1514                                 return( 1 );
1515                         }
1516                         level = loglevel_ops[j].mask;
1517                 }
1518                 ldap_syslog |= level;
1519         }
1520         return(0);
1521 }
1522
1523 static int
1524 config_syncrepl(ConfigArgs *c) {
1525         if (c->op == SLAP_CONFIG_EMIT) {
1526                 if ( c->be->be_syncinfo ) {
1527                         struct berval bv;
1528                         syncrepl_unparse( c->be->be_syncinfo, &bv ); 
1529                         ber_bvarray_add( &c->rvalue_vals, &bv );
1530                         return 0;
1531                 }
1532                 return 1;
1533         }
1534         if(SLAP_SHADOW(c->be)) {
1535                 Debug(LDAP_DEBUG_ANY, "%s: "
1536                         "syncrepl: database already shadowed.\n",
1537                         c->log, 0, 0);
1538                 return(1);
1539         } else if(add_syncrepl(c->be, c->argv, c->argc)) {
1540                 return(1);
1541         }
1542         SLAP_DBFLAGS(c->be) |= (SLAP_DBFLAG_SHADOW | SLAP_DBFLAG_SYNC_SHADOW);
1543         return(0);
1544 }
1545
1546 static int
1547 config_referral(ConfigArgs *c) {
1548         struct berval vals[2];
1549         if (c->op == SLAP_CONFIG_EMIT) {
1550                 if ( default_referral ) {
1551                         value_add( &c->rvalue_vals, default_referral );
1552                         return 0;
1553                 } else {
1554                         return 1;
1555                 }
1556         }
1557         if(validate_global_referral(c->argv[1])) {
1558                 Debug(LDAP_DEBUG_ANY, "%s: "
1559                         "invalid URL (%s) in \"referral\" line.\n",
1560                         c->log, c->argv[1], 0);
1561                 return(1);
1562         }
1563
1564         ber_str2bv(c->argv[1], 0, 0, &vals[0]);
1565         vals[1].bv_val = NULL; vals[1].bv_len = 0;
1566         if(value_add(&default_referral, vals)) return(LDAP_OTHER);
1567         return(0);
1568 }
1569
1570 static struct {
1571         struct berval key;
1572         int off;
1573 } sec_keys[] = {
1574         { BER_BVC("ssf="), offsetof(slap_ssf_set_t, sss_ssf) },
1575         { BER_BVC("transport="), offsetof(slap_ssf_set_t, sss_transport) },
1576         { BER_BVC("tls="), offsetof(slap_ssf_set_t, sss_tls) },
1577         { BER_BVC("sasl="), offsetof(slap_ssf_set_t, sss_sasl) },
1578         { BER_BVC("update_ssf="), offsetof(slap_ssf_set_t, sss_update_ssf) },
1579         { BER_BVC("update_transport="), offsetof(slap_ssf_set_t, sss_update_transport) },
1580         { BER_BVC("update_tls="), offsetof(slap_ssf_set_t, sss_update_tls) },
1581         { BER_BVC("update_sasl="), offsetof(slap_ssf_set_t, sss_update_sasl) },
1582         { BER_BVC("simple_bind="), offsetof(slap_ssf_set_t, sss_simple_bind) },
1583         { BER_BVNULL, 0 }
1584 };
1585
1586 static int
1587 config_security(ConfigArgs *c) {
1588         slap_ssf_set_t *set = &c->be->be_ssf_set;
1589         char *next;
1590         int i, j;
1591         if (c->op == SLAP_CONFIG_EMIT) {
1592                 char numbuf[32];
1593                 struct berval bv;
1594                 slap_ssf_t *tgt;
1595                 int rc = 1;
1596
1597                 for (i=0; !BER_BVISNULL( &sec_keys[i].key ); i++) {
1598                         tgt = (slap_ssf_t *)((char *)set + sec_keys[i].off);
1599                         if ( *tgt ) {
1600                                 rc = 0;
1601                                 bv.bv_len = sprintf( numbuf, "%u", *tgt );
1602                                 bv.bv_len += sec_keys[i].key.bv_len;
1603                                 bv.bv_val = ch_malloc( bv.bv_len + 1);
1604                                 next = lutil_strcopy( bv.bv_val, sec_keys[i].key.bv_val );
1605                                 strcpy( next, numbuf );
1606                                 ber_bvarray_add( &c->rvalue_vals, &bv );
1607                         }
1608                 }
1609                 return rc;
1610         }
1611         for(i = 1; i < c->argc; i++) {
1612                 slap_ssf_t *tgt = NULL;
1613                 char *src;
1614                 for ( j=0; !BER_BVISNULL( &sec_keys[j].key ); j++ ) {
1615                         if(!strncasecmp(c->argv[i], sec_keys[j].key.bv_val,
1616                                 sec_keys[j].key.bv_len)) {
1617                                 src = c->argv[i] + sec_keys[j].key.bv_len;
1618                                 tgt = (slap_ssf_t *)((char *)set + sec_keys[j].off);
1619                                 break;
1620                         }
1621                 }
1622                 if ( !tgt ) {
1623                         Debug(LDAP_DEBUG_ANY, "%s: "
1624                                 "unknown factor %s in \"security <factors>\" line\n",
1625                                 c->log, c->argv[i], 0);
1626                         return(1);
1627                 }
1628
1629                 *tgt = strtol(src, &next, 10);
1630                 if(next == NULL || next[0] != '\0' ) {
1631                         Debug(LDAP_DEBUG_ANY, "%s: "
1632                                 "unable to parse factor \"%s\" in \"security <factors>\" line\n",
1633                                 c->log, c->argv[i], 0);
1634                         return(1);
1635                 }
1636         }
1637         return(0);
1638 }
1639
1640 static char *
1641 anlist_unparse( AttributeName *an, char *ptr ) {
1642         int comma = 0;
1643
1644         for (; !BER_BVISNULL( &an->an_name ); an++) {
1645                 if ( comma ) *ptr++ = ',';
1646                 ptr = lutil_strcopy( ptr, an->an_name.bv_val );
1647                 comma = 1;
1648         }
1649         return ptr;
1650 }
1651
1652 static void
1653 replica_unparse( struct slap_replica_info *ri, int i, struct berval *bv )
1654 {
1655         int len;
1656         char *ptr;
1657         struct berval bc = {0};
1658         char numbuf[32];
1659
1660         len = sprintf(numbuf, "{%d}", i );
1661
1662         len += strlen( ri->ri_uri ) + STRLENOF("uri=");
1663         if ( ri->ri_nsuffix ) {
1664                 for (i=0; !BER_BVISNULL( &ri->ri_nsuffix[i] ); i++) {
1665                         len += ri->ri_nsuffix[i].bv_len + STRLENOF(" suffix=\"\"");
1666                 }
1667         }
1668         if ( ri->ri_attrs ) {
1669                 len += STRLENOF("attr");
1670                 if ( ri->ri_exclude ) len++;
1671                 for (i=0; !BER_BVISNULL( &ri->ri_attrs[i].an_name ); i++) {
1672                         len += 1 + ri->ri_attrs[i].an_name.bv_len;
1673                 }
1674         }
1675         bindconf_unparse( &ri->ri_bindconf, &bc );
1676         len += bc.bv_len;
1677
1678         bv->bv_val = ch_malloc(len + 1);
1679         bv->bv_len = len;
1680
1681         ptr = lutil_strcopy( bv->bv_val, numbuf );
1682         ptr = lutil_strcopy( ptr, "uri=" );
1683         ptr = lutil_strcopy( ptr, ri->ri_uri );
1684
1685         if ( ri->ri_nsuffix ) {
1686                 for (i=0; !BER_BVISNULL( &ri->ri_nsuffix[i] ); i++) {
1687                         ptr = lutil_strcopy( ptr, " suffix=\"" );
1688                         ptr = lutil_strcopy( ptr, ri->ri_nsuffix[i].bv_val );
1689                         *ptr++ = '"';
1690                 }
1691         }
1692         if ( ri->ri_attrs ) {
1693                 ptr = lutil_strcopy( ptr, "attr" );
1694                 if ( ri->ri_exclude ) *ptr++ = '!';
1695                 *ptr++ = '=';
1696                 ptr = anlist_unparse( ri->ri_attrs, ptr );
1697         }
1698         if ( bc.bv_val ) {
1699                 strcpy( ptr, bc.bv_val );
1700                 ch_free( bc.bv_val );
1701         }
1702 }
1703
1704 static int
1705 config_replica(ConfigArgs *c) {
1706         int i, nr = -1, len;
1707         char *replicahost, *replicauri;
1708         LDAPURLDesc *ludp;
1709
1710         if (c->op == SLAP_CONFIG_EMIT) {
1711                 if (c->be->be_replica) {
1712                         struct berval bv;
1713                         for (i=0;c->be->be_replica[i]; i++) {
1714                                 replica_unparse( c->be->be_replica[i], i, &bv );
1715                                 ber_bvarray_add( &c->rvalue_vals, &bv );
1716                         }
1717                         return 0;
1718                 }
1719                 return 1;
1720         }
1721         if(SLAP_MONITOR(c->be)) {
1722                 Debug(LDAP_DEBUG_ANY, "%s: "
1723                         "\"replica\" should not be used inside monitor database\n",
1724                         c->log, 0, 0);
1725                 return(0);      /* FIXME: should this be an error? */
1726         }
1727
1728         for(i = 1; i < c->argc; i++) {
1729                 if(!strncasecmp(c->argv[i], "host=", STRLENOF("host="))) {
1730                         replicahost = c->argv[i] + STRLENOF("host=");
1731                         len = strlen( replicahost );
1732                         replicauri = ch_malloc( len + STRLENOF("ldap://") + 1 );
1733                         sprintf( replicauri, "ldap://%s", replicahost );
1734                         replicahost = replicauri + STRLENOF( "ldap://");
1735                         nr = add_replica_info(c->be, replicauri, replicahost);
1736                         break;
1737                 } else if(!strncasecmp(c->argv[i], "uri=", STRLENOF("uri="))) {
1738                         if(ldap_url_parse(c->argv[i] + STRLENOF("uri="), &ludp) != LDAP_SUCCESS) {
1739                                 Debug(LDAP_DEBUG_ANY, "%s: "
1740                                         "replica line contains invalid "
1741                                         "uri definition.\n", c->log, 0, 0);
1742                                 return(1);
1743                         }
1744                         if(!ludp->lud_host) {
1745                                 Debug(LDAP_DEBUG_ANY, "%s: "
1746                                         "replica line contains invalid "
1747                                         "uri definition - missing hostname.\n",
1748                                         c->log, 0, 0);
1749                                 return(1);
1750                         }
1751                         ldap_free_urldesc(ludp);
1752                         replicauri = c->argv[i] + STRLENOF("uri=");
1753                         replicauri = ch_strdup( replicauri );
1754                         replicahost = strchr( replicauri, '/' );
1755                         replicahost += 2;
1756                         nr = add_replica_info(c->be, replicauri, replicahost);
1757                         break;
1758                 }
1759         }
1760         if(i == c->argc) {
1761                 Debug(LDAP_DEBUG_ANY, "%s: "
1762                         "missing host or uri in \"replica\" line\n",
1763                         c->log, 0, 0);
1764                 return(1);
1765         } else if(nr == -1) {
1766                 Debug(LDAP_DEBUG_ANY, "%s: "
1767                         "unable to add replica \"%s\"\n",
1768                         c->log, replicauri, 0);
1769                 return(1);
1770         } else {
1771                 for(i = 1; i < c->argc; i++) {
1772                         if(!strncasecmp(c->argv[i], "suffix=", STRLENOF( "suffix="))) {
1773                                 switch(add_replica_suffix(c->be, nr, c->argv[i] + STRLENOF("suffix="))) {
1774                                         case 1:
1775                                                 Debug(LDAP_DEBUG_ANY, "%s: "
1776                                                 "suffix \"%s\" in \"replica\" line is not valid for backend (ignored)\n",
1777                                                 c->log, c->argv[i] + STRLENOF("suffix="), 0);
1778                                                 break;
1779                                         case 2:
1780                                                 Debug(LDAP_DEBUG_ANY, "%s: "
1781                                                 "unable to normalize suffix in \"replica\" line (ignored)\n",
1782                                                 c->log, 0, 0);
1783                                                 break;
1784                                 }
1785
1786                         } else if(!strncasecmp(c->argv[i], "attr", STRLENOF("attr"))) {
1787                                 int exclude = 0;
1788                                 char *arg = c->argv[i] + STRLENOF("attr");
1789                                 if(arg[0] == '!') {
1790                                         arg++;
1791                                         exclude = 1;
1792                                 }
1793                                 if(arg[0] != '=') {
1794                                         continue;
1795                                 }
1796                                 if(add_replica_attrs(c->be, nr, arg + 1, exclude)) {
1797                                         Debug(LDAP_DEBUG_ANY, "%s: "
1798                                                 "attribute \"%s\" in \"replica\" line is unknown\n",
1799                                                 c->log, arg + 1, 0);
1800                                         return(1);
1801                                 }
1802                         } else if ( bindconf_parse( c->argv[i],
1803                                         &c->be->be_replica[nr]->ri_bindconf ) ) {
1804                                 return(1);
1805                         }
1806                 }
1807         }
1808         return(0);
1809 }
1810
1811 static int
1812 config_updatedn(ConfigArgs *c) {
1813         struct berval dn;
1814         int rc;
1815         if (c->op == SLAP_CONFIG_EMIT) {
1816                 if (!BER_BVISEMPTY(&c->be->be_update_ndn)) {
1817                         value_add_one(&c->rvalue_vals, &c->be->be_update_ndn);
1818                         value_add_one(&c->rvalue_nvals, &c->be->be_update_ndn);
1819                         return 0;
1820                 }
1821                 return 1;
1822         }
1823         if(SLAP_SHADOW(c->be)) {
1824                 Debug(LDAP_DEBUG_ANY, "%s: "
1825                         "updatedn: database already shadowed.\n",
1826                         c->log, 0, 0);
1827                 return(1);
1828         }
1829
1830         ber_str2bv(c->argv[1], 0, 0, &dn);
1831
1832         rc = dnNormalize(0, NULL, NULL, &dn, &c->be->be_update_ndn, NULL);
1833
1834         if(rc != LDAP_SUCCESS) {
1835                 Debug(LDAP_DEBUG_ANY, "%s: "
1836                         "updatedn DN is invalid: %d (%s)\n",
1837                         c->log, rc, ldap_err2string( rc ));
1838                 return(1);
1839         }
1840
1841         SLAP_DBFLAGS(c->be) |= (SLAP_DBFLAG_SHADOW | SLAP_DBFLAG_SLURP_SHADOW);
1842         return(0);
1843 }
1844
1845 static int
1846 config_updateref(ConfigArgs *c) {
1847         struct berval vals[2];
1848         if (c->op == SLAP_CONFIG_EMIT) {
1849                 if ( c->be->be_update_refs ) {
1850                         value_add( &c->rvalue_vals, c->be->be_update_refs );
1851                         return 0;
1852                 } else {
1853                         return 1;
1854                 }
1855         }
1856         if(!SLAP_SHADOW(c->be)) {
1857                 Debug(LDAP_DEBUG_ANY, "%s: "
1858                         "updateref line must come after syncrepl or updatedn.\n",
1859                         c->log, 0, 0);
1860                 return(1);
1861         }
1862
1863         if(validate_global_referral(c->argv[1])) {
1864                 Debug(LDAP_DEBUG_ANY, "%s: "
1865                         "invalid URL (%s) in \"updateref\" line.\n",
1866                         c->log, c->argv[1], 0);
1867                 return(1);
1868         }
1869         ber_str2bv(c->argv[1], 0, 0, &vals[0]);
1870         vals[1].bv_val = NULL;
1871         if(value_add(&c->be->be_update_refs, vals)) return(LDAP_OTHER);
1872         return(0);
1873 }
1874
1875 static int
1876 config_include(ConfigArgs *c) {
1877         unsigned long savelineno = c->lineno;
1878         int rc;
1879         ConfigFile *cf;
1880         ConfigFile *cfsave = cfn;
1881         ConfigFile *cf2 = NULL;
1882         if (c->op == SLAP_CONFIG_EMIT) {
1883                 return 1;
1884         }
1885         cf = ch_calloc( 1, sizeof(ConfigFile));
1886 #ifdef SLAPD_MODULES
1887         cf->c_modlast = &cf->c_modpaths;
1888 #endif
1889         if ( cfn->c_kids ) {
1890                 for (cf2=cfn->c_kids; cf2 && cf2->c_sibs; cf2=cf2->c_sibs) ;
1891                 cf2->c_sibs = cf;
1892         } else {
1893                 cfn->c_kids = cf;
1894         }
1895         cfn = cf;
1896         rc = read_config_file(c->argv[1], c->depth + 1, c);
1897         c->lineno = savelineno - 1;
1898         cfn = cfsave;
1899         if ( rc ) {
1900                 if ( cf2 ) cf2->c_sibs = NULL;
1901                 else cfn->c_kids = NULL;
1902                 ch_free( cf );
1903         } else {
1904                 ber_str2bv( c->argv[1], 0, 1, &cf->c_file );
1905         }
1906         return(rc);
1907 }
1908
1909 #ifdef HAVE_TLS
1910 static int
1911 config_tls_option(ConfigArgs *c) {
1912         int flag;
1913         switch(c->type) {
1914         case CFG_TLS_RAND:              flag = LDAP_OPT_X_TLS_RANDOM_FILE;      break;
1915         case CFG_TLS_CIPHER:    flag = LDAP_OPT_X_TLS_CIPHER_SUITE;     break;
1916         case CFG_TLS_CERT_FILE: flag = LDAP_OPT_X_TLS_CERTFILE;         break;  
1917         case CFG_TLS_CERT_KEY:  flag = LDAP_OPT_X_TLS_KEYFILE;          break;
1918         case CFG_TLS_CA_PATH:   flag = LDAP_OPT_X_TLS_CACERTDIR;        break;
1919         case CFG_TLS_CA_FILE:   flag = LDAP_OPT_X_TLS_CACERTFILE;       break;
1920         default:                Debug(LDAP_DEBUG_ANY, "%s: "
1921                                         "unknown tls_option <%x>\n",
1922                                         c->log, c->type, 0);
1923         }
1924         if (c->op == SLAP_CONFIG_EMIT) {
1925                 return ldap_pvt_tls_get_option( NULL, flag, &c->value_string );
1926         }
1927         ch_free(c->value_string);
1928         return(ldap_pvt_tls_set_option(NULL, flag, c->argv[1]));
1929 }
1930
1931 /* FIXME: this ought to be provided by libldap */
1932 static int
1933 config_tls_config(ConfigArgs *c) {
1934         int i, flag;
1935         slap_verbmasks crlkeys[] = {
1936                 { BER_BVC("none"),      LDAP_OPT_X_TLS_CRL_NONE },
1937                 { BER_BVC("peer"),      LDAP_OPT_X_TLS_CRL_PEER },
1938                 { BER_BVC("all"),       LDAP_OPT_X_TLS_CRL_ALL },
1939                 { BER_BVNULL, 0 }
1940         };
1941         slap_verbmasks vfykeys[] = {
1942                 { BER_BVC("never"),     LDAP_OPT_X_TLS_NEVER },
1943                 { BER_BVC("demand"),    LDAP_OPT_X_TLS_DEMAND },
1944                 { BER_BVC("try"),       LDAP_OPT_X_TLS_TRY },
1945                 { BER_BVC("hard"),      LDAP_OPT_X_TLS_HARD },
1946                 { BER_BVNULL, 0 }
1947         }, *keys;
1948         switch(c->type) {
1949 #ifdef HAVE_OPENSSL_CRL
1950         case CFG_TLS_CRLCHECK:  flag = LDAP_OPT_X_TLS_CRLCHECK; keys = crlkeys;
1951                 break;
1952 #endif
1953         case CFG_TLS_VERIFY:    flag = LDAP_OPT_X_TLS_REQUIRE_CERT; keys = vfykeys;
1954                 break;
1955         default:                Debug(LDAP_DEBUG_ANY, "%s: "
1956                                         "unknown tls_option <%x>\n",
1957                                         c->log, c->type, 0);
1958         }
1959         if (c->op == SLAP_CONFIG_EMIT) {
1960                 ldap_pvt_tls_get_option( NULL, flag, &c->value_int );
1961                 for (i=0; !BER_BVISNULL(&keys[i].word); i++) {
1962                         if (keys[i].mask == c->value_int) {
1963                                 c->value_string = ch_strdup( keys[i].word.bv_val );
1964                                 return 0;
1965                         }
1966                 }
1967                 return 1;
1968         }
1969         ch_free( c->value_string );
1970         if(isdigit((unsigned char)c->argv[1][0])) {
1971                 i = atoi(c->argv[1]);
1972                 return(ldap_pvt_tls_set_option(NULL, flag, &i));
1973         } else {
1974                 return(ldap_int_tls_config(NULL, flag, c->argv[1]));
1975         }
1976 }
1977 #endif
1978
1979 static int
1980 add_syncrepl(
1981         Backend *be,
1982         char    **cargv,
1983         int     cargc
1984 )
1985 {
1986         syncinfo_t *si;
1987         int     rc = 0;
1988
1989         si = (syncinfo_t *) ch_calloc( 1, sizeof( syncinfo_t ) );
1990
1991         if ( si == NULL ) {
1992                 Debug( LDAP_DEBUG_ANY, "out of memory in add_syncrepl\n", 0, 0, 0 );
1993                 return 1;
1994         }
1995
1996         si->si_bindconf.sb_tls = SB_TLS_OFF;
1997         si->si_bindconf.sb_method = LDAP_AUTH_SIMPLE;
1998         si->si_schemachecking = 0;
1999         ber_str2bv( "(objectclass=*)", STRLENOF("(objectclass=*)"), 1,
2000                 &si->si_filterstr );
2001         si->si_base.bv_val = NULL;
2002         si->si_scope = LDAP_SCOPE_SUBTREE;
2003         si->si_attrsonly = 0;
2004         si->si_anlist = (AttributeName *) ch_calloc( 1, sizeof( AttributeName ));
2005         si->si_exanlist = (AttributeName *) ch_calloc( 1, sizeof( AttributeName ));
2006         si->si_attrs = NULL;
2007         si->si_allattrs = 0;
2008         si->si_allopattrs = 0;
2009         si->si_exattrs = NULL;
2010         si->si_type = LDAP_SYNC_REFRESH_ONLY;
2011         si->si_interval = 86400;
2012         si->si_retryinterval = NULL;
2013         si->si_retrynum_init = NULL;
2014         si->si_retrynum = NULL;
2015         si->si_manageDSAit = 0;
2016         si->si_tlimit = 0;
2017         si->si_slimit = 0;
2018
2019         si->si_presentlist = NULL;
2020         LDAP_LIST_INIT( &si->si_nonpresentlist );
2021         ldap_pvt_thread_mutex_init( &si->si_mutex );
2022
2023         rc = parse_syncrepl_line( cargv, cargc, si );
2024
2025         if ( rc < 0 ) {
2026                 Debug( LDAP_DEBUG_ANY, "failed to add syncinfo\n", 0, 0, 0 );
2027                 syncinfo_free( si );    
2028                 return 1;
2029         } else {
2030                 Debug( LDAP_DEBUG_CONFIG,
2031                         "Config: ** successfully added syncrepl \"%s\"\n",
2032                         BER_BVISNULL( &si->si_provideruri ) ?
2033                         "(null)" : si->si_provideruri.bv_val, 0, 0 );
2034                 if ( !si->si_schemachecking ) {
2035                         SLAP_DBFLAGS(be) |= SLAP_DBFLAG_NO_SCHEMA_CHECK;
2036                 }
2037                 si->si_be = be;
2038                 be->be_syncinfo = si;
2039                 return 0;
2040         }
2041 }
2042
2043 /* NOTE: used & documented in slapd.conf(5) */
2044 #define IDSTR                   "rid"
2045 #define PROVIDERSTR             "provider"
2046 #define TYPESTR                 "type"
2047 #define INTERVALSTR             "interval"
2048 #define SEARCHBASESTR           "searchbase"
2049 #define FILTERSTR               "filter"
2050 #define SCOPESTR                "scope"
2051 #define ATTRSSTR                "attrs"
2052 #define ATTRSONLYSTR            "attrsonly"
2053 #define SLIMITSTR               "sizelimit"
2054 #define TLIMITSTR               "timelimit"
2055 #define SCHEMASTR               "schemachecking"
2056
2057 /* FIXME: undocumented */
2058 #define OLDAUTHCSTR             "bindprincipal"
2059 #define EXATTRSSTR              "exattrs"
2060 #define RETRYSTR                "retry"
2061
2062 /* FIXME: unused */
2063 #define LASTMODSTR              "lastmod"
2064 #define LMGENSTR                "gen"
2065 #define LMNOSTR                 "no"
2066 #define LMREQSTR                "req"
2067 #define SRVTABSTR               "srvtab"
2068 #define SUFFIXSTR               "suffix"
2069 #define MANAGEDSAITSTR          "manageDSAit"
2070
2071 /* mandatory */
2072 #define GOT_ID                  0x0001
2073 #define GOT_PROVIDER            0x0002
2074
2075 /* check */
2076 #define GOT_ALL                 (GOT_ID|GOT_PROVIDER)
2077
2078 static struct {
2079         struct berval key;
2080         int val;
2081 } scopes[] = {
2082         { BER_BVC("base"), LDAP_SCOPE_BASE },
2083         { BER_BVC("one"), LDAP_SCOPE_ONELEVEL },
2084 #ifdef LDAP_SCOPE_SUBORDINATE
2085         { BER_BVC("children"), LDAP_SCOPE_SUBORDINATE },
2086         { BER_BVC("subordinate"), 0 },
2087 #endif
2088         { BER_BVC("sub"), LDAP_SCOPE_SUBTREE },
2089         { BER_BVNULL, 0 }
2090 };
2091
2092 static int
2093 parse_syncrepl_line(
2094         char            **cargv,
2095         int             cargc,
2096         syncinfo_t      *si
2097 )
2098 {
2099         int     gots = 0;
2100         int     i;
2101         char    *val;
2102
2103         for ( i = 1; i < cargc; i++ ) {
2104                 if ( !strncasecmp( cargv[ i ], IDSTR "=",
2105                                         STRLENOF( IDSTR "=" ) ) )
2106                 {
2107                         int tmp;
2108                         /* '\0' string terminator accounts for '=' */
2109                         val = cargv[ i ] + STRLENOF( IDSTR "=" );
2110                         tmp= atoi( val );
2111                         if ( tmp >= 1000 || tmp < 0 ) {
2112                                 fprintf( stderr, "Error: parse_syncrepl_line: "
2113                                          "syncrepl id %d is out of range [0..999]\n", tmp );
2114                                 return -1;
2115                         }
2116                         si->si_rid = tmp;
2117                         gots |= GOT_ID;
2118                 } else if ( !strncasecmp( cargv[ i ], PROVIDERSTR "=",
2119                                         STRLENOF( PROVIDERSTR "=" ) ) )
2120                 {
2121                         val = cargv[ i ] + STRLENOF( PROVIDERSTR "=" );
2122                         ber_str2bv( val, 0, 1, &si->si_provideruri );
2123                         gots |= GOT_PROVIDER;
2124                 } else if ( !strncasecmp( cargv[ i ], SCHEMASTR "=",
2125                                         STRLENOF( SCHEMASTR "=" ) ) )
2126                 {
2127                         val = cargv[ i ] + STRLENOF( SCHEMASTR "=" );
2128                         if ( !strncasecmp( val, "on", STRLENOF( "on" ) )) {
2129                                 si->si_schemachecking = 1;
2130                         } else if ( !strncasecmp( val, "off", STRLENOF( "off" ) ) ) {
2131                                 si->si_schemachecking = 0;
2132                         } else {
2133                                 si->si_schemachecking = 1;
2134                         }
2135                 } else if ( !strncasecmp( cargv[ i ], FILTERSTR "=",
2136                                         STRLENOF( FILTERSTR "=" ) ) )
2137                 {
2138                         val = cargv[ i ] + STRLENOF( FILTERSTR "=" );
2139                         ber_str2bv( val, 0, 1, &si->si_filterstr );
2140                 } else if ( !strncasecmp( cargv[ i ], SEARCHBASESTR "=",
2141                                         STRLENOF( SEARCHBASESTR "=" ) ) )
2142                 {
2143                         struct berval   bv;
2144                         int             rc;
2145
2146                         val = cargv[ i ] + STRLENOF( SEARCHBASESTR "=" );
2147                         if ( si->si_base.bv_val ) {
2148                                 ch_free( si->si_base.bv_val );
2149                         }
2150                         ber_str2bv( val, 0, 0, &bv );
2151                         rc = dnNormalize( 0, NULL, NULL, &bv, &si->si_base, NULL );
2152                         if ( rc != LDAP_SUCCESS ) {
2153                                 fprintf( stderr, "Invalid base DN \"%s\": %d (%s)\n",
2154                                         val, rc, ldap_err2string( rc ) );
2155                                 return -1;
2156                         }
2157                 } else if ( !strncasecmp( cargv[ i ], SCOPESTR "=",
2158                                         STRLENOF( SCOPESTR "=" ) ) )
2159                 {
2160                         int j;
2161                         val = cargv[ i ] + STRLENOF( SCOPESTR "=" );
2162                         for ( j=0; !BER_BVISNULL(&scopes[j].key); j++ ) {
2163                                 if (!strncasecmp( val, scopes[j].key.bv_val,
2164                                         scopes[j].key.bv_len )) {
2165                                         while (!scopes[j].val) j--;
2166                                         si->si_scope = scopes[j].val;
2167                                         break;
2168                                 }
2169                         }
2170                         if ( BER_BVISNULL(&scopes[j].key) ) {
2171                                 fprintf( stderr, "Error: parse_syncrepl_line: "
2172                                         "unknown scope \"%s\"\n", val);
2173                                 return -1;
2174                         }
2175                 } else if ( !strncasecmp( cargv[ i ], ATTRSONLYSTR "=",
2176                                         STRLENOF( ATTRSONLYSTR "=" ) ) )
2177                 {
2178                         si->si_attrsonly = 1;
2179                 } else if ( !strncasecmp( cargv[ i ], ATTRSSTR "=",
2180                                         STRLENOF( ATTRSSTR "=" ) ) )
2181                 {
2182                         val = cargv[ i ] + STRLENOF( ATTRSSTR "=" );
2183                         if ( !strncasecmp( val, ":include:", STRLENOF(":include:") ) ) {
2184                                 char *attr_fname;
2185                                 attr_fname = ch_strdup( val + STRLENOF(":include:") );
2186                                 si->si_anlist = file2anlist( si->si_anlist, attr_fname, " ,\t" );
2187                                 if ( si->si_anlist == NULL ) {
2188                                         ch_free( attr_fname );
2189                                         return -1;
2190                                 }
2191                                 si->si_anfile = attr_fname;
2192                         } else {
2193                                 char *str, *s, *next;
2194                                 char delimstr[] = " ,\t";
2195                                 str = ch_strdup( val );
2196                                 for ( s = ldap_pvt_strtok( str, delimstr, &next );
2197                                                 s != NULL;
2198                                                 s = ldap_pvt_strtok( NULL, delimstr, &next ) )
2199                                 {
2200                                         if ( strlen(s) == 1 && *s == '*' ) {
2201                                                 si->si_allattrs = 1;
2202                                                 *(val + ( s - str )) = delimstr[0];
2203                                         }
2204                                         if ( strlen(s) == 1 && *s == '+' ) {
2205                                                 si->si_allopattrs = 1;
2206                                                 *(val + ( s - str )) = delimstr[0];
2207                                         }
2208                                 }
2209                                 ch_free( str );
2210                                 si->si_anlist = str2anlist( si->si_anlist, val, " ,\t" );
2211                                 if ( si->si_anlist == NULL ) {
2212                                         return -1;
2213                                 }
2214                         }
2215                 } else if ( !strncasecmp( cargv[ i ], EXATTRSSTR "=",
2216                                         STRLENOF( EXATTRSSTR "=" ) ) )
2217                 {
2218                         val = cargv[ i ] + STRLENOF( EXATTRSSTR "=" );
2219                         if ( !strncasecmp( val, ":include:", STRLENOF(":include:") )) {
2220                                 char *attr_fname;
2221                                 attr_fname = ch_strdup( val + STRLENOF(":include:") );
2222                                 si->si_exanlist = file2anlist(
2223                                                                         si->si_exanlist, attr_fname, " ,\t" );
2224                                 if ( si->si_exanlist == NULL ) {
2225                                         ch_free( attr_fname );
2226                                         return -1;
2227                                 }
2228                                 ch_free( attr_fname );
2229                         } else {
2230                                 si->si_exanlist = str2anlist( si->si_exanlist, val, " ,\t" );
2231                                 if ( si->si_exanlist == NULL ) {
2232                                         return -1;
2233                                 }
2234                         }
2235                 } else if ( !strncasecmp( cargv[ i ], TYPESTR "=",
2236                                         STRLENOF( TYPESTR "=" ) ) )
2237                 {
2238                         val = cargv[ i ] + STRLENOF( TYPESTR "=" );
2239                         if ( !strncasecmp( val, "refreshOnly",
2240                                                 STRLENOF("refreshOnly") ))
2241                         {
2242                                 si->si_type = LDAP_SYNC_REFRESH_ONLY;
2243                         } else if ( !strncasecmp( val, "refreshAndPersist",
2244                                                 STRLENOF("refreshAndPersist") ))
2245                         {
2246                                 si->si_type = LDAP_SYNC_REFRESH_AND_PERSIST;
2247                                 si->si_interval = 60;
2248                         } else {
2249                                 fprintf( stderr, "Error: parse_syncrepl_line: "
2250                                         "unknown sync type \"%s\"\n", val);
2251                                 return -1;
2252                         }
2253                 } else if ( !strncasecmp( cargv[ i ], INTERVALSTR "=",
2254                                         STRLENOF( INTERVALSTR "=" ) ) )
2255                 {
2256                         val = cargv[ i ] + STRLENOF( INTERVALSTR "=" );
2257                         if ( si->si_type == LDAP_SYNC_REFRESH_AND_PERSIST ) {
2258                                 si->si_interval = 0;
2259                         } else {
2260                                 char *hstr;
2261                                 char *mstr;
2262                                 char *dstr;
2263                                 char *sstr;
2264                                 int dd, hh, mm, ss;
2265                                 dstr = val;
2266                                 hstr = strchr( dstr, ':' );
2267                                 if ( hstr == NULL ) {
2268                                         fprintf( stderr, "Error: parse_syncrepl_line: "
2269                                                 "invalid interval \"%s\"\n", val );
2270                                         return -1;
2271                                 }
2272                                 *hstr++ = '\0';
2273                                 mstr = strchr( hstr, ':' );
2274                                 if ( mstr == NULL ) {
2275                                         fprintf( stderr, "Error: parse_syncrepl_line: "
2276                                                 "invalid interval \"%s\"\n", val );
2277                                         return -1;
2278                                 }
2279                                 *mstr++ = '\0';
2280                                 sstr = strchr( mstr, ':' );
2281                                 if ( sstr == NULL ) {
2282                                         fprintf( stderr, "Error: parse_syncrepl_line: "
2283                                                 "invalid interval \"%s\"\n", val );
2284                                         return -1;
2285                                 }
2286                                 *sstr++ = '\0';
2287
2288                                 dd = atoi( dstr );
2289                                 hh = atoi( hstr );
2290                                 mm = atoi( mstr );
2291                                 ss = atoi( sstr );
2292                                 if (( hh > 24 ) || ( hh < 0 ) ||
2293                                         ( mm > 60 ) || ( mm < 0 ) ||
2294                                         ( ss > 60 ) || ( ss < 0 ) || ( dd < 0 )) {
2295                                         fprintf( stderr, "Error: parse_syncrepl_line: "
2296                                                 "invalid interval \"%s\"\n", val );
2297                                         return -1;
2298                                 }
2299                                 si->si_interval = (( dd * 24 + hh ) * 60 + mm ) * 60 + ss;
2300                         }
2301                         if ( si->si_interval < 0 ) {
2302                                 fprintf( stderr, "Error: parse_syncrepl_line: "
2303                                         "invalid interval \"%ld\"\n",
2304                                         (long) si->si_interval);
2305                                 return -1;
2306                         }
2307                 } else if ( !strncasecmp( cargv[ i ], RETRYSTR "=",
2308                                         STRLENOF( RETRYSTR "=" ) ) )
2309                 {
2310                         char **retry_list;
2311                         int j, k, n;
2312
2313                         val = cargv[ i ] + STRLENOF( RETRYSTR "=" );
2314                         retry_list = (char **) ch_calloc( 1, sizeof( char * ));
2315                         retry_list[0] = NULL;
2316
2317                         slap_str2clist( &retry_list, val, " ,\t" );
2318
2319                         for ( k = 0; retry_list && retry_list[k]; k++ ) ;
2320                         n = k / 2;
2321                         if ( k % 2 ) {
2322                                 fprintf( stderr,
2323                                                 "Error: incomplete syncrepl retry list\n" );
2324                                 for ( k = 0; retry_list && retry_list[k]; k++ ) {
2325                                         ch_free( retry_list[k] );
2326                                 }
2327                                 ch_free( retry_list );
2328                                 exit( EXIT_FAILURE );
2329                         }
2330                         si->si_retryinterval = (time_t *) ch_calloc( n + 1, sizeof( time_t ));
2331                         si->si_retrynum = (int *) ch_calloc( n + 1, sizeof( int ));
2332                         si->si_retrynum_init = (int *) ch_calloc( n + 1, sizeof( int ));
2333                         for ( j = 0; j < n; j++ ) {
2334                                 si->si_retryinterval[j] = atoi( retry_list[j*2] );
2335                                 if ( *retry_list[j*2+1] == '+' ) {
2336                                         si->si_retrynum_init[j] = -1;
2337                                         si->si_retrynum[j] = -1;
2338                                         j++;
2339                                         break;
2340                                 } else {
2341                                         si->si_retrynum_init[j] = atoi( retry_list[j*2+1] );
2342                                         si->si_retrynum[j] = atoi( retry_list[j*2+1] );
2343                                 }
2344                         }
2345                         si->si_retrynum_init[j] = -2;
2346                         si->si_retrynum[j] = -2;
2347                         si->si_retryinterval[j] = 0;
2348                         
2349                         for ( k = 0; retry_list && retry_list[k]; k++ ) {
2350                                 ch_free( retry_list[k] );
2351                         }
2352                         ch_free( retry_list );
2353                 } else if ( !strncasecmp( cargv[ i ], MANAGEDSAITSTR "=",
2354                                         STRLENOF( MANAGEDSAITSTR "=" ) ) )
2355                 {
2356                         val = cargv[ i ] + STRLENOF( MANAGEDSAITSTR "=" );
2357                         si->si_manageDSAit = atoi( val );
2358                 } else if ( !strncasecmp( cargv[ i ], SLIMITSTR "=",
2359                                         STRLENOF( SLIMITSTR "=") ) )
2360                 {
2361                         val = cargv[ i ] + STRLENOF( SLIMITSTR "=" );
2362                         si->si_slimit = atoi( val );
2363                 } else if ( !strncasecmp( cargv[ i ], TLIMITSTR "=",
2364                                         STRLENOF( TLIMITSTR "=" ) ) )
2365                 {
2366                         val = cargv[ i ] + STRLENOF( TLIMITSTR "=" );
2367                         si->si_tlimit = atoi( val );
2368                 } else if ( bindconf_parse( cargv[i], &si->si_bindconf )) {
2369                         fprintf( stderr, "Error: parse_syncrepl_line: "
2370                                 "unknown keyword \"%s\"\n", cargv[ i ] );
2371                         return -1;
2372                 }
2373         }
2374
2375         if ( gots != GOT_ALL ) {
2376                 fprintf( stderr,
2377                         "Error: Malformed \"syncrepl\" line in slapd config file" );
2378                 return -1;
2379         }
2380
2381         return 0;
2382 }
2383
2384 static void
2385 syncrepl_unparse( syncinfo_t *si, struct berval *bv )
2386 {
2387         struct berval bc;
2388         char buf[BUFSIZ*2], *ptr;
2389         int i, len;
2390
2391         bindconf_unparse( &si->si_bindconf, &bc );
2392         ptr = buf;
2393         ptr += sprintf( ptr, IDSTR "=%03d " PROVIDERSTR "=%s",
2394                 si->si_rid, si->si_provideruri.bv_val );
2395         if ( !BER_BVISNULL( &bc )) {
2396                 ptr = lutil_strcopy( ptr, bc.bv_val );
2397                 free( bc.bv_val );
2398         }
2399         if ( !BER_BVISEMPTY( &si->si_filterstr )) {
2400                 ptr = lutil_strcopy( ptr, " " FILTERSTR "=\"" );
2401                 ptr = lutil_strcopy( ptr, si->si_filterstr.bv_val );
2402                 *ptr++ = '"';
2403         }
2404         if ( !BER_BVISNULL( &si->si_base )) {
2405                 ptr = lutil_strcopy( ptr, " " SEARCHBASESTR "=\"" );
2406                 ptr = lutil_strcopy( ptr, si->si_base.bv_val );
2407                 *ptr++ = '"';
2408         }
2409         for (i=0; !BER_BVISNULL(&scopes[i].key);i++) {
2410                 if ( si->si_scope == scopes[i].val ) {
2411                         ptr = lutil_strcopy( ptr, " " SCOPESTR "=" );
2412                         ptr = lutil_strcopy( ptr, scopes[i].key.bv_val );
2413                         break;
2414                 }
2415         }
2416         if ( si->si_attrsonly ) {
2417                 ptr = lutil_strcopy( ptr, " " ATTRSONLYSTR "=yes" );
2418         }
2419         if ( si->si_anfile ) {
2420                 ptr = lutil_strcopy( ptr, " " ATTRSSTR "=:include:" );
2421                 ptr = lutil_strcopy( ptr, si->si_anfile );
2422         } else if ( si->si_allattrs || si->si_allopattrs ||
2423                 ( si->si_anlist && !BER_BVISNULL(&si->si_anlist[0].an_name) )) {
2424                 char *old;
2425                 ptr = lutil_strcopy( ptr, " " ATTRSSTR "=\"" );
2426                 old = ptr;
2427                 ptr = anlist_unparse( si->si_anlist, ptr );
2428                 if ( si->si_allattrs ) {
2429                         if ( old != ptr ) *ptr++ = ',';
2430                         *ptr++ = '*';
2431                 }
2432                 if ( si->si_allopattrs ) {
2433                         if ( old != ptr ) *ptr++ = ',';
2434                         *ptr++ = '+';
2435                 }
2436                 *ptr++ = '"';
2437         }
2438         if ( si->si_exanlist && !BER_BVISNULL(&si->si_exanlist[0].an_name) ) {
2439                 ptr = lutil_strcopy( ptr, " " EXATTRSSTR "=" );
2440                 ptr = anlist_unparse( si->si_exanlist, ptr );
2441         }
2442         ptr = lutil_strcopy( ptr, " " SCHEMASTR "=" );
2443         ptr = lutil_strcopy( ptr, si->si_schemachecking ? "on" : "off" );
2444         
2445         ptr = lutil_strcopy( ptr, " " TYPESTR "=" );
2446         ptr = lutil_strcopy( ptr, si->si_type == LDAP_SYNC_REFRESH_AND_PERSIST ?
2447                 "refreshAndPersist" : "refreshOnly" );
2448
2449         if ( si->si_type == LDAP_SYNC_REFRESH_ONLY ) {
2450                 int dd, hh, mm, ss;
2451
2452                 dd = si->si_interval;
2453                 ss = dd % 60;
2454                 dd /= 60;
2455                 mm = dd % 60;
2456                 dd /= 60;
2457                 hh = dd % 24;
2458                 dd /= 24;
2459                 ptr = lutil_strcopy( ptr, " " INTERVALSTR "=" );
2460                 ptr += sprintf( ptr, "%02d:%02d:%02d:%02d", dd, hh, mm, ss );
2461         } else if ( si->si_retryinterval ) {
2462                 int space=0;
2463                 ptr = lutil_strcopy( ptr, " " RETRYSTR "=\"" );
2464                 for (i=0; si->si_retryinterval[i]; i++) {
2465                         if ( space ) *ptr++ = ' ';
2466                         space = 1;
2467                         ptr += sprintf( ptr, "%d", si->si_retryinterval[i] );
2468                         if ( si->si_retrynum_init[i] == -1 )
2469                                 *ptr++ = '+';
2470                         else
2471                                 ptr += sprintf( ptr, "%d", si->si_retrynum_init );
2472                 }
2473                 *ptr++ = '"';
2474         }
2475
2476 #if 0 /* FIXME: unused in syncrepl.c, should remove it */
2477         ptr = lutil_strcopy( ptr, " " MANAGEDSAITSTR "=" );
2478         ptr += sprintf( ptr, "%d", si->si_manageDSAit );
2479 #endif
2480
2481         if ( si->si_slimit ) {
2482                 ptr = lutil_strcopy( ptr, " " SLIMITSTR "=" );
2483                 ptr += sprintf( ptr, "%d", si->si_slimit );
2484         }
2485
2486         if ( si->si_tlimit ) {
2487                 ptr = lutil_strcopy( ptr, " " TLIMITSTR "=" );
2488                 ptr += sprintf( ptr, "%d", si->si_tlimit );
2489         }
2490         bc.bv_len = ptr - buf;
2491         bc.bv_val = buf;
2492         ber_dupbv( bv, &bc );
2493 }
2494
2495 static CfEntryInfo *
2496 config_find_base( CfEntryInfo *root, struct berval *dn, CfEntryInfo **last )
2497 {
2498         struct berval cdn;
2499         char *c;
2500
2501         if ( !root ) {
2502                 *last = NULL;
2503                 return NULL;
2504         }
2505
2506         if ( dn_match( &root->ce_entry->e_nname, dn ))
2507                 return root;
2508
2509         c = dn->bv_val+dn->bv_len;
2510         for (;*c != ',';c--);
2511
2512         while(root) {
2513                 *last = root;
2514                 for (--c;c>dn->bv_val && *c != ',';c--);
2515                 if ( *c == ',' )
2516                         c++;
2517                 cdn.bv_val = c;
2518                 cdn.bv_len = dn->bv_len - (c-dn->bv_val);
2519
2520                 root = root->ce_kids;
2521
2522                 for (;root;root=root->ce_sibs) {
2523                         if ( dn_match( &root->ce_entry->e_nname, &cdn )) {
2524                                 if ( cdn.bv_val == dn->bv_val ) {
2525                                         return root;
2526                                 }
2527                                 break;
2528                         }
2529                 }
2530         }
2531         return root;
2532 }
2533
2534 static int
2535 config_ldif_resp( Operation *op, SlapReply *rs )
2536 {
2537         if ( rs->sr_type == REP_SEARCH ) {
2538                 CfBackInfo *cfb = op->o_callback->sc_private;
2539                 CfEntryInfo *ce, *last;
2540
2541                 cfb->cb_got_ldif = 1;
2542                 config_find_base( cfb->cb_root, &rs->sr_entry->e_nname, &last );
2543                 ce = ch_calloc( 1, sizeof(CfEntryInfo) );
2544                 ce->ce_entry = entry_dup( rs->sr_entry );
2545                 ce->ce_entry->e_private = ce;
2546                 if ( !last ) {
2547                         cfb->cb_root = ce;
2548                 } else if ( last->ce_kids ) {
2549                         CfEntryInfo *c2;
2550
2551                         for (c2=last->ce_kids; c2 && c2->ce_sibs; c2 = c2->ce_sibs);
2552                         c2->ce_sibs = ce;
2553                 } else {
2554                         last->ce_kids = ce;
2555                 }
2556         }
2557         return 0;
2558 }
2559
2560 /* Configure and read the underlying back-ldif store */
2561 static int
2562 config_setup_ldif( BackendDB *be, const char *dir ) {
2563         CfBackInfo *cfb = be->be_private;
2564         ConfigArgs c = {0};
2565         ConfigTable *ct;
2566         char *argv[3];
2567         int rc;
2568         slap_callback cb = { NULL, config_ldif_resp, NULL, NULL };
2569         Connection conn = {0};
2570         char opbuf[OPERATION_BUFFER_SIZE];
2571         Operation *op;
2572         SlapReply rs = {REP_RESULT};
2573         Filter filter = { LDAP_FILTER_PRESENT };
2574         struct berval filterstr = BER_BVC("(objectclass=*)");
2575
2576         cfb->cb_db.bd_info = backend_info( "ldif" );
2577         if ( !cfb->cb_db.bd_info )
2578                 return 1;
2579
2580         if ( cfb->cb_db.bd_info->bi_db_init( &cfb->cb_db )) return 1;
2581
2582         /* Mark that back-ldif type is in use */
2583         cfb->cb_db.bd_info->bi_nDB++;
2584
2585         cfb->cb_db.be_suffix = be->be_suffix;
2586         cfb->cb_db.be_nsuffix = be->be_nsuffix;
2587         cfb->cb_db.be_rootdn = be->be_rootdn;
2588         cfb->cb_db.be_rootndn = be->be_rootndn;
2589
2590         ber_str2bv( dir, 0, 1, &cfdir );
2591
2592         c.be = &cfb->cb_db;
2593         c.fname = "slapd";
2594         c.argc = 2;
2595         argv[0] = "directory";
2596         argv[1] = (char *)dir;
2597         argv[2] = NULL;
2598         c.argv = argv;
2599
2600         ct = config_find_keyword( c.be->be_cf_table, &c );
2601         if ( !ct )
2602                 return 1;
2603
2604         if ( config_add_vals( ct, &c ))
2605                 return 1;
2606
2607         if ( backend_startup_one( &cfb->cb_db ))
2608                 return 1;
2609
2610         op = (Operation *)opbuf;
2611         connection_fake_init( &conn, op, cfb );
2612
2613         filter.f_desc = slap_schema.si_ad_objectClass;
2614         
2615         op->o_tag = LDAP_REQ_SEARCH;
2616
2617         op->ors_filter = &filter;
2618         op->ors_filterstr = filterstr;
2619         op->ors_scope = LDAP_SCOPE_SUBTREE;
2620
2621         op->o_dn = be->be_rootdn;
2622         op->o_ndn = be->be_rootndn;
2623
2624         op->o_req_dn = be->be_suffix[0];
2625         op->o_req_ndn = be->be_nsuffix[0];
2626
2627         op->ors_tlimit = SLAP_NO_LIMIT;
2628         op->ors_slimit = SLAP_NO_LIMIT;
2629
2630         op->ors_attrs = slap_anlist_all_attributes;
2631         op->ors_attrsonly = 0;
2632
2633         op->o_callback = &cb;
2634         cb.sc_private = cfb;
2635
2636         op->o_bd = &cfb->cb_db;
2637         op->o_bd->be_search( op, &rs );
2638         
2639         return 0;
2640 }
2641
2642 int
2643 read_config(const char *fname, const char *dir) {
2644         BackendDB *be;
2645
2646         /* Setup the config backend */
2647         be = backend_db_init( "config" );
2648         if ( !be )
2649                 return 1;
2650
2651         /* Setup the underlying back-ldif backend */
2652         if ( config_setup_ldif( be, dir ))
2653                 return 1;
2654
2655 #if 0   /* not yet
2656         /* If we read the config from back-ldif, nothing to do here */
2657         if ( cfb->cb_got_ldif )
2658                 return 0;
2659 #endif
2660         ber_str2bv( fname, 0, 1, &cf_prv.c_file );
2661
2662         return read_config_file(fname, 0, NULL);
2663 }
2664
2665 static int
2666 config_back_bind( Operation *op, SlapReply *rs )
2667 {
2668         if ( op->orb_method == LDAP_AUTH_SIMPLE && be_isroot_pw( op )) {
2669                 ber_dupbv( &op->orb_edn, be_root_dn( op->o_bd ));
2670                 /* frontend sends result */
2671                 return LDAP_SUCCESS;
2672         }
2673
2674         rs->sr_err = LDAP_INVALID_CREDENTIALS;
2675         send_ldap_result( op, rs );
2676
2677         return rs->sr_err;
2678 }
2679
2680 static int
2681 config_send( Operation *op, SlapReply *rs, CfEntryInfo *ce, int depth )
2682 {
2683         int rc = 0;
2684
2685         if ( test_filter( op, ce->ce_entry, op->ors_filter ) == LDAP_COMPARE_TRUE )
2686         {
2687                 rs->sr_attrs = op->ors_attrs;
2688                 rs->sr_entry = ce->ce_entry;
2689                 rc = send_search_entry( op, rs );
2690         }
2691         if ( op->ors_scope == LDAP_SCOPE_SUBTREE ) {
2692                 if ( ce->ce_kids ) {
2693                         rc = config_send( op, rs, ce->ce_kids, 1 );
2694                         if ( rc ) return rc;
2695                 }
2696                 if ( depth ) {
2697                         for (ce=ce->ce_sibs; ce; ce=ce->ce_sibs) {
2698                                 rc = config_send( op, rs, ce, 0 );
2699                                 if ( rc ) break;
2700                         }
2701                 }
2702         }
2703         return rc;
2704 }
2705
2706 static int
2707 config_back_modify( Operation *op, SlapReply *rs )
2708 {
2709         CfBackInfo *cfb;
2710         CfEntryInfo *ce, *last;
2711
2712         if ( !be_isroot( op ) ) {
2713                 rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
2714                 send_ldap_result( op, rs );
2715         }
2716
2717         cfb = (CfBackInfo *)op->o_bd->be_private;
2718
2719         ce = config_find_base( cfb->cb_root, &op->o_req_ndn, &last );
2720         if ( !ce ) {
2721                 if ( last )
2722                         rs->sr_matched = last->ce_entry->e_name.bv_val;
2723                 rs->sr_err = LDAP_NO_SUCH_OBJECT;
2724                 goto out;
2725         }
2726         ldap_pvt_thread_pool_pause( &connection_pool );
2727
2728         /* Strategy:
2729          * 1) perform the Modify on the cached Entry.
2730          * 2) verify that the Entry still satisfies the schema.
2731          * 3) perform the individual config operations.
2732          * 4) store Modified entry in underlying LDIF backend.
2733          */
2734         ldap_pvt_thread_pool_resume( &connection_pool );
2735 out:
2736         send_ldap_result( op, rs );
2737         return rs->sr_err;
2738 }
2739
2740 static int
2741 config_back_search( Operation *op, SlapReply *rs )
2742 {
2743         CfBackInfo *cfb;
2744         CfEntryInfo *ce, *last;
2745         int rc;
2746
2747         if ( !be_isroot( op ) ) {
2748                 rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
2749                 send_ldap_result( op, rs );
2750         }
2751
2752         cfb = (CfBackInfo *)op->o_bd->be_private;
2753
2754         ce = config_find_base( cfb->cb_root, &op->o_req_ndn, &last );
2755         if ( !ce ) {
2756                 if ( last )
2757                         rs->sr_matched = last->ce_entry->e_name.bv_val;
2758                 rs->sr_err = LDAP_NO_SUCH_OBJECT;
2759                 goto out;
2760         }
2761         switch ( op->ors_scope ) {
2762         case LDAP_SCOPE_BASE:
2763         case LDAP_SCOPE_SUBTREE:
2764                 config_send( op, rs, ce, 0 );
2765                 break;
2766                 
2767         case LDAP_SCOPE_ONELEVEL:
2768                 for (ce = ce->ce_kids; ce; ce=ce->ce_sibs) {
2769                         config_send( op, rs, ce, 1 );
2770                 }
2771                 break;
2772         }
2773                 
2774         rs->sr_err = LDAP_SUCCESS;
2775 out:
2776         send_ldap_result( op, rs );
2777         return 0;
2778 }
2779
2780 static Entry *
2781 config_alloc_entry( struct berval *pdn, struct berval *rdn )
2782 {
2783         Entry *e = ch_calloc( 1, sizeof(Entry) );
2784         CfEntryInfo *ce = ch_calloc( 1, sizeof(CfEntryInfo) );
2785         e->e_private = ce;
2786         ce->ce_entry = e;
2787         build_new_dn( &e->e_name, pdn, rdn, NULL );
2788         ber_dupbv( &e->e_nname, &e->e_name );
2789         return e;
2790 }
2791
2792 #define NO_TABLE        0
2793 #define BI_TABLE        1
2794 #define BE_TABLE        2
2795
2796 static int
2797 config_build_entry( ConfigArgs *c, Entry *e, ObjectClass *oc,
2798          struct berval *rdn, ConfigTable *ct, int table )
2799 {
2800         struct berval vals[2];
2801         struct berval ad_name;
2802         AttributeDescription *ad = NULL;
2803         int rc, i;
2804         char *ptr;
2805         const char *text;
2806         AttributeType **at;
2807
2808         BER_BVZERO( &vals[1] );
2809
2810         vals[0] = oc->soc_cname;
2811         attr_merge(e, slap_schema.si_ad_objectClass, vals, NULL );
2812         attr_merge(e, slap_schema.si_ad_structuralObjectClass, vals, NULL );
2813         ptr = strchr(rdn->bv_val, '=');
2814         ad_name.bv_val = rdn->bv_val;
2815         ad_name.bv_len = ptr - rdn->bv_val;
2816         rc = slap_bv2ad( &ad_name, &ad, &text );
2817         if ( rc ) {
2818                 return rc;
2819         }
2820         vals[0].bv_val = ptr+1;
2821         vals[0].bv_len = rdn->bv_len - (vals[0].bv_val - rdn->bv_val);
2822         attr_merge(e, ad, vals, NULL );
2823
2824         for (at=oc->soc_required; at && *at; at++) {
2825                 /* Skip the naming attr */
2826                 if ((*at)->sat_ad == ad || (*at)->sat_ad == slap_schema.si_ad_cn )
2827                         continue;
2828                 for (i=0;ct[i].name;i++) {
2829                         if (ct[i].ad == (*at)->sat_ad) {
2830                                 rc = config_get_vals(&ct[i], c);
2831                                 if (rc == LDAP_SUCCESS) {
2832                                         attr_merge(e, ct[i].ad, c->rvalue_vals, c->rvalue_nvals);
2833                                         ber_bvarray_free( c->rvalue_nvals );
2834                                         ber_bvarray_free( c->rvalue_vals );
2835                                 }
2836                                 break;
2837                         }
2838                 }
2839         }
2840
2841         for (at=oc->soc_allowed; at && *at; at++) {
2842                 /* Skip the naming attr */
2843                 if ((*at)->sat_ad == ad || (*at)->sat_ad == slap_schema.si_ad_cn )
2844                         continue;
2845                 for (i=0;ct[i].name;i++) {
2846                         if (ct[i].ad == (*at)->sat_ad) {
2847                                 rc = config_get_vals(&ct[i], c);
2848                                 if (rc == LDAP_SUCCESS) {
2849                                         attr_merge(e, ct[i].ad, c->rvalue_vals, c->rvalue_nvals);
2850                                         ber_bvarray_free( c->rvalue_nvals );
2851                                         ber_bvarray_free( c->rvalue_vals );
2852                                 }
2853                                 break;
2854                         }
2855                 }
2856         }
2857
2858         if ( table ) {
2859                 if ( table == BI_TABLE )
2860                         ct = c->bi->bi_cf_table;
2861                 else
2862                         ct = c->be->be_cf_table;
2863                 for (;ct && ct->name;ct++) {
2864                         if (!ct->ad) continue;
2865                         rc = config_get_vals(ct, c);
2866                         if (rc == LDAP_SUCCESS) {
2867                                 attr_merge(e, ct->ad, c->rvalue_vals, c->rvalue_nvals);
2868                         }
2869                 }
2870         }
2871
2872         return 0;
2873 }
2874
2875 static CfEntryInfo *
2876 config_build_includes( ConfigArgs *c, Entry *parent,
2877         Operation *op, SlapReply *rs )
2878 {
2879         Entry *e;
2880         int i;
2881         ConfigFile *cf = (ConfigFile *)c->line;
2882         CfEntryInfo *ce, *ceparent, *ceprev;
2883
2884         ceparent = parent->e_private;
2885
2886         for (i=0; cf; cf=cf->c_sibs, i++) {
2887                 c->value_dn.bv_val = c->log;
2888                 c->value_dn.bv_len = sprintf(c->value_dn.bv_val, "cn=include{%d}", i);
2889                 e = config_alloc_entry( &parent->e_nname, &c->value_dn );
2890                 c->line = (char *)cf;
2891                 config_build_entry( c, e, cfOc_include, &c->value_dn,
2892                         c->bi->bi_cf_table, NO_TABLE );
2893                 op->ora_e = e;
2894                 op->o_bd->be_add( op, rs );
2895                 ce = e->e_private;
2896                 if ( !ceparent->ce_kids ) {
2897                         ceparent->ce_kids = ce;
2898                 } else {
2899                         ceprev->ce_sibs = ce;
2900                 }
2901                 ceprev = ce;
2902                 if ( cf->c_kids ) {
2903                         c->line = (char *)cf->c_kids;
2904                         config_build_includes( c, e, op, rs );
2905                 }
2906         }
2907         return ce;
2908 }
2909
2910 static int
2911 config_back_db_open( BackendDB *be )
2912 {
2913         CfBackInfo *cfb = be->be_private;
2914         struct berval rdn;
2915         Entry *e, *parent;
2916         CfEntryInfo *ce, *ceparent, *ceprev;
2917         int i, rc;
2918         BackendInfo *bi;
2919         BackendDB *bptr;
2920         ConfigArgs c;
2921         ConfigTable *ct;
2922         Connection conn = {0};
2923         char opbuf[OPERATION_BUFFER_SIZE];
2924         Operation *op;
2925         slap_callback cb = { NULL, slap_null_cb, NULL, NULL };
2926         SlapReply rs = {REP_RESULT};
2927
2928         /* If we read the config from back-ldif, nothing to do here */
2929         if ( cfb->cb_got_ldif )
2930                 return 0;
2931
2932         op = (Operation *)opbuf;
2933         connection_fake_init( &conn, op, cfb );
2934
2935         op->o_dn = be->be_rootdn;
2936         op->o_ndn = be->be_rootndn;
2937
2938         op->o_tag = LDAP_REQ_ADD;
2939         op->o_callback = &cb;
2940         op->o_bd = &cfb->cb_db;
2941
2942         /* create root of tree */
2943         rdn = config_rdn;
2944         e = config_alloc_entry( NULL, &rdn );
2945         ce = e->e_private;
2946         cfb->cb_root = ce;
2947         c.be = be;
2948         c.bi = be->bd_info;
2949         c.line = (char *)cfb->cb_config;
2950         ct = c.bi->bi_cf_table;
2951         config_build_entry( &c, e, cfOc_global, &rdn, ct, NO_TABLE );
2952         op->ora_e = e;
2953         op->o_bd->be_add( op, &rs );
2954
2955         parent = e;
2956         ceparent = ce;
2957
2958         /* Create includeFile nodes... */
2959         if ( cfb->cb_config->c_kids ) {
2960                 c.line = (char *)cfb->cb_config->c_kids;
2961                 ceprev = config_build_includes( &c, parent, op, &rs );
2962         }
2963
2964         /* Create backend nodes. Skip if they don't provide a cf_table.
2965          * There usually aren't any of these.
2966          */
2967         
2968         c.line = 0;
2969         bi = backendInfo;
2970         for (i=0; i<nBackendInfo; i++, bi++) {
2971                 if (!bi->bi_cf_table) continue;
2972                 if (!bi->bi_private) continue;
2973
2974                 rdn.bv_val = c.log;
2975                 rdn.bv_len = sprintf(rdn.bv_val, "%s=%s", cfAd_backend->ad_cname.bv_val, bi->bi_type);
2976                 e = config_alloc_entry( &parent->e_nname, &rdn );
2977                 ce = e->e_private;
2978                 ce->ce_bi = bi;
2979                 c.bi = bi;
2980                 config_build_entry( &c, e, cfOc_backend, &rdn, ct, BI_TABLE );
2981                 op->ora_e = e;
2982                 op->o_bd->be_add( op, &rs );
2983                 if ( !ceparent->ce_kids ) {
2984                         ceparent->ce_kids = ce;
2985                 } else {
2986                         ceprev->ce_sibs = ce;
2987                 }
2988                 ceprev = ce;
2989         }
2990
2991         /* Create database nodes... */
2992         for (i=0; i<nBackendDB; i++) {
2993                 slap_overinfo *oi = NULL;
2994                 if ( i == 0 ) {
2995                         bptr = frontendDB;
2996                 } else {
2997                         bptr = &backendDB[i];
2998                 }
2999                 if ( overlay_is_over( bptr )) {
3000                         oi = bptr->bd_info->bi_private;
3001                         bi = oi->oi_orig;
3002                 } else {
3003                         bi = bptr->bd_info;
3004                 }
3005                 rdn.bv_val = c.log;
3006                 rdn.bv_len = sprintf(rdn.bv_val, "%s={%0x}%s", cfAd_database->ad_cname.bv_val,
3007                         i, bi->bi_type);
3008                 e = config_alloc_entry( &parent->e_nname, &rdn );
3009                 ce = e->e_private;
3010                 c.be = bptr;
3011                 c.bi = bi;
3012                 ce->ce_be = c.be;
3013                 ce->ce_bi = c.bi;
3014                 config_build_entry( &c, e, cfOc_database, &rdn, ct, BE_TABLE );
3015                 op->ora_e = e;
3016                 op->o_bd->be_add( op, &rs );
3017                 if ( !ceparent->ce_kids ) {
3018                         ceparent->ce_kids = ce;
3019                 } else {
3020                         ceprev->ce_sibs = ce;
3021                 }
3022                 ceprev = ce;
3023                 /* Iterate through overlays */
3024                 if ( oi ) {
3025                         slap_overinst *on;
3026                         Entry *oe;
3027                         CfEntryInfo *opar = ce, *oprev = NULL;
3028                         int j;
3029
3030                         for (j=0,on=oi->oi_list; on; j++,on=on->on_next) {
3031                                 rdn.bv_val = c.log;
3032                                 rdn.bv_len = sprintf(rdn.bv_val, "%s={%0x}%s",
3033                                         cfAd_overlay->ad_cname.bv_val, j, on->on_bi.bi_type );
3034                                 oe = config_alloc_entry( &e->e_nname, &rdn );
3035                                 ce = oe->e_private;
3036                                 c.be = bptr;
3037                                 c.bi = &on->on_bi;
3038                                 ce->ce_be = c.be;
3039                                 ce->ce_bi = c.bi;
3040                                 config_build_entry( &c, oe, cfOc_overlay, &rdn, ct, BI_TABLE );
3041                                 op->ora_e = oe;
3042                                 op->o_bd->be_add( op, &rs );
3043                                 if ( !opar->ce_kids ) {
3044                                         opar->ce_kids = ce;
3045                                 } else {
3046                                         oprev->ce_sibs = ce;
3047                                 }
3048                                 oprev = ce;
3049                         }
3050                 }
3051         }
3052
3053         return 0;
3054 }
3055
3056 static int
3057 config_back_db_destroy( Backend *be )
3058 {
3059         free( be->be_private );
3060         return 0;
3061 }
3062
3063 static int
3064 config_back_db_init( Backend *be )
3065 {
3066         struct berval dn;
3067         CfBackInfo *cfb;
3068
3069         cfb = ch_calloc( 1, sizeof(CfBackInfo));
3070         cfb->cb_config = &cf_prv;
3071         be->be_private = cfb;
3072
3073         ber_dupbv( &be->be_rootdn, &config_rdn );
3074         ber_dupbv( &be->be_rootndn, &be->be_rootdn );
3075         ber_dupbv( &dn, &be->be_rootdn );
3076         ber_bvarray_add( &be->be_suffix, &dn );
3077         ber_dupbv( &dn, &be->be_rootdn );
3078         ber_bvarray_add( &be->be_nsuffix, &dn );
3079
3080         /* Hide from namingContexts */
3081         SLAP_BFLAGS(be) |= SLAP_BFLAG_CONFIG;
3082
3083         return 0;
3084 }
3085
3086 static struct {
3087         char *name;
3088         AttributeDescription **desc;
3089         AttributeDescription *sub;
3090 } ads[] = {
3091         { "attribute", NULL, NULL },
3092         { "backend", &cfAd_backend, NULL },
3093         { "database", &cfAd_database, NULL },
3094         { "ditcontentrule", NULL, NULL },
3095         { "include", &cfAd_include, NULL },
3096         { "objectclass", NULL, NULL },
3097         { "overlay", &cfAd_overlay, NULL },
3098         { NULL, NULL, NULL }
3099 };
3100
3101 int
3102 config_back_initialize( BackendInfo *bi )
3103 {
3104         ConfigTable *ct = config_back_cf_table;
3105         char *argv[4];
3106         int i;
3107
3108         bi->bi_open = 0;
3109         bi->bi_close = 0;
3110         bi->bi_config = 0;
3111         bi->bi_destroy = 0;
3112
3113         bi->bi_db_init = config_back_db_init;
3114         bi->bi_db_config = 0;
3115         bi->bi_db_open = config_back_db_open;
3116         bi->bi_db_close = 0;
3117         bi->bi_db_destroy = config_back_db_destroy;
3118
3119         bi->bi_op_bind = config_back_bind;
3120         bi->bi_op_unbind = 0;
3121         bi->bi_op_search = config_back_search;
3122         bi->bi_op_compare = 0;
3123         bi->bi_op_modify = config_back_modify;
3124         bi->bi_op_modrdn = 0;
3125         bi->bi_op_add = 0;
3126         bi->bi_op_delete = 0;
3127         bi->bi_op_abandon = 0;
3128
3129         bi->bi_extended = 0;
3130
3131         bi->bi_chk_referrals = 0;
3132
3133         bi->bi_connection_init = 0;
3134         bi->bi_connection_destroy = 0;
3135
3136         argv[3] = NULL;
3137         for (i=0; OidMacros[i].name; i++ ) {
3138                 argv[1] = OidMacros[i].name;
3139                 argv[2] = OidMacros[i].oid;
3140                 parse_oidm( "slapd", i, 3, argv );
3141         }
3142
3143         i = init_config_attrs( ct );
3144         if ( i ) return i;
3145
3146         /* set up the notable AttributeDescriptions */
3147         ads[0].sub = slap_schema.si_ad_attributeTypes;
3148         ads[3].sub = slap_schema.si_ad_ditContentRules;
3149         ads[5].sub = slap_schema.si_ad_objectClasses;
3150
3151         bi->bi_cf_table = ct;
3152
3153         i = 0;
3154         for (;ct->name;ct++) {
3155                 if (strcmp(ct->name, ads[i].name)) continue;
3156                 if (ads[i].sub) {
3157                         ct->ad = ads[i].sub;
3158                 } else {
3159                         *ads[i].desc = ct->ad;
3160                 }
3161                 i++;
3162                 if (!ads[i].name) break;
3163         }
3164
3165         /* set up the objectclasses */
3166         i = init_config_ocs( cf_ocs );
3167
3168         return i;
3169 }
3170