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