1 /* $NetBSD: bconfig.c,v 1.3 2021/08/14 16:14:58 christos Exp $ */
2
3 /* bconfig.c - the config backend */
4 /* $OpenLDAP$ */
5 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
6 *
7 * Copyright 2005-2021 The OpenLDAP Foundation.
8 * All rights reserved.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted only as authorized by the OpenLDAP
12 * Public License.
13 *
14 * A copy of this license is available in the file LICENSE in the
15 * top-level directory of the distribution or, alternatively, at
16 * <http://www.OpenLDAP.org/license.html>.
17 */
18 /* ACKNOWLEDGEMENTS:
19 * This work was originally developed by Howard Chu for inclusion
20 * in OpenLDAP Software.
21 */
22
23 #include <sys/cdefs.h>
24 __RCSID("$NetBSD: bconfig.c,v 1.3 2021/08/14 16:14:58 christos Exp $");
25
26 #include "portable.h"
27
28 #include <stdio.h>
29 #include <ac/string.h>
30 #include <ac/ctype.h>
31 #include <ac/dirent.h>
32 #include <ac/errno.h>
33 #include <sys/stat.h>
34 #include <ac/unistd.h>
35
36 #include "slap.h"
37
38 #ifdef LDAP_SLAPI
39 #include "slapi/slapi.h"
40 #endif
41
42 #include <ldif.h>
43 #include <lutil.h>
44
45 #include "slap-config.h"
46
47 #define CONFIG_RDN "cn=config"
48 #define SCHEMA_RDN "cn=schema"
49
50 static struct berval config_rdn = BER_BVC(CONFIG_RDN);
51 static struct berval schema_rdn = BER_BVC(SCHEMA_RDN);
52
53 extern int slap_DN_strict; /* dn.c */
54
55 #ifdef SLAPD_MODULES
56 typedef struct modpath_s {
57 struct modpath_s *mp_next;
58 struct berval mp_path;
59 BerVarray mp_loads;
60 } ModPaths;
61
62 static ModPaths modpaths, *modlast = &modpaths, *modcur = &modpaths;
63 #endif
64
65 typedef struct ConfigFile {
66 struct ConfigFile *c_sibs;
67 struct ConfigFile *c_kids;
68 struct berval c_file;
69 AttributeType *c_at_head, *c_at_tail;
70 ContentRule *c_cr_head, *c_cr_tail;
71 ObjectClass *c_oc_head, *c_oc_tail;
72 OidMacro *c_om_head, *c_om_tail;
73 Syntax *c_syn_head, *c_syn_tail;
74 BerVarray c_dseFiles;
75 } ConfigFile;
76
77 typedef struct {
78 ConfigFile *cb_config;
79 CfEntryInfo *cb_root;
80 BackendDB cb_db; /* underlying database */
81 int cb_got_ldif;
82 int cb_use_ldif;
83 } CfBackInfo;
84
85 static CfBackInfo cfBackInfo;
86
87 static char *passwd_salt;
88 static FILE *logfile;
89 static char *logfileName;
90 static AccessControl *defacl_parsed = NULL;
91
92 static struct berval cfdir;
93
94 /* Private state */
95 static AttributeDescription *cfAd_backend, *cfAd_database, *cfAd_overlay,
96 *cfAd_include, *cfAd_attr, *cfAd_oc, *cfAd_om, *cfAd_syntax;
97
98 static ConfigFile *cfn;
99
100 static Avlnode *CfOcTree;
101
102 /* System schema state */
103 extern AttributeType *at_sys_tail; /* at.c */
104 extern ObjectClass *oc_sys_tail; /* oc.c */
105 extern OidMacro *om_sys_tail; /* oidm.c */
106 extern Syntax *syn_sys_tail; /* syntax.c */
107 static AttributeType *cf_at_tail;
108 static ObjectClass *cf_oc_tail;
109 static OidMacro *cf_om_tail;
110 static Syntax *cf_syn_tail;
111
112 static int config_add_internal( CfBackInfo *cfb, Entry *e, ConfigArgs *ca,
113 SlapReply *rs, int *renumber, Operation *op );
114
115 static int config_check_schema( Operation *op, CfBackInfo *cfb );
116
117 static ConfigDriver config_fname;
118 static ConfigDriver config_cfdir;
119 static ConfigDriver config_generic;
120 static ConfigDriver config_search_base;
121 static ConfigDriver config_passwd_hash;
122 static ConfigDriver config_schema_dn;
123 static ConfigDriver config_sizelimit;
124 static ConfigDriver config_timelimit;
125 static ConfigDriver config_overlay;
126 static ConfigDriver config_subordinate;
127 static ConfigDriver config_suffix;
128 #ifdef LDAP_TCP_BUFFER
129 static ConfigDriver config_tcp_buffer;
130 #endif /* LDAP_TCP_BUFFER */
131 static ConfigDriver config_rootdn;
132 static ConfigDriver config_rootpw;
133 static ConfigDriver config_restrict;
134 static ConfigDriver config_allows;
135 static ConfigDriver config_disallows;
136 static ConfigDriver config_requires;
137 static ConfigDriver config_security;
138 static ConfigDriver config_referral;
139 static ConfigDriver config_loglevel;
140 static ConfigDriver config_updatedn;
141 static ConfigDriver config_updateref;
142 static ConfigDriver config_extra_attrs;
143 static ConfigDriver config_include;
144 static ConfigDriver config_obsolete;
145 #ifdef HAVE_TLS
146 static ConfigDriver config_tls_option;
147 static ConfigDriver config_tls_config;
148 #endif
149 extern ConfigDriver syncrepl_config;
150
151 enum {
152 CFG_ACL = 1,
153 CFG_BACKEND,
154 CFG_DATABASE,
155 CFG_TLS_RAND,
156 CFG_TLS_CIPHER,
157 CFG_TLS_PROTOCOL_MIN,
158 CFG_TLS_CERT_FILE,
159 CFG_TLS_CERT_KEY,
160 CFG_TLS_CA_PATH,
161 CFG_TLS_CA_FILE,
162 CFG_TLS_DH_FILE,
163 CFG_TLS_VERIFY,
164 CFG_TLS_CRLCHECK,
165 CFG_TLS_CRL_FILE,
166 CFG_CONCUR,
167 CFG_THREADS,
168 CFG_SALT,
169 CFG_LIMITS,
170 CFG_RO,
171 CFG_REWRITE,
172 CFG_DEPTH,
173 CFG_OID,
174 CFG_OC,
175 CFG_DIT,
176 CFG_ATTR,
177 CFG_ATOPT,
178 CFG_ROOTDSE,
179 CFG_LOGFILE,
180 CFG_PLUGIN,
181 CFG_MODLOAD,
182 CFG_MODPATH,
183 CFG_LASTMOD,
184 CFG_LASTBIND,
185 CFG_AZPOLICY,
186 CFG_AZREGEXP,
187 CFG_AZDUC,
188 CFG_AZDUC_IGNORE,
189 CFG_SASLSECP,
190 CFG_SSTR_IF_MAX,
191 CFG_SSTR_IF_MIN,
192 CFG_TTHREADS,
193 CFG_MULTIPROVIDER,
194 CFG_HIDDEN,
195 CFG_MONITORING,
196 CFG_SERVERID,
197 CFG_SORTVALS,
198 CFG_IX_INTLEN,
199 CFG_SYNTAX,
200 CFG_ACL_ADD,
201 CFG_SYNC_SUBENTRY,
202 CFG_LTHREADS,
203 CFG_IX_HASH64,
204 CFG_DISABLED,
205 CFG_THREADQS,
206 CFG_TLS_ECNAME,
207 CFG_TLS_CACERT,
208 CFG_TLS_CERT,
209 CFG_TLS_KEY,
210
211 CFG_LAST
212 };
213
214 typedef struct {
215 char *name, *oid;
216 } OidRec;
217
218 static OidRec OidMacros[] = {
219 /* OpenLDAProot:1.12.2 */
220 { "OLcfg", "1.3.6.1.4.1.4203.1.12.2" },
221 { "OLcfgAt", "OLcfg:3" },
222 { "OLcfgGlAt", "OLcfgAt:0" },
223 { "OLcfgBkAt", "OLcfgAt:1" },
224 { "OLcfgDbAt", "OLcfgAt:2" },
225 { "OLcfgOvAt", "OLcfgAt:3" },
226 { "OLcfgCtAt", "OLcfgAt:4" }, /* contrib modules */
227 { "OLcfgOc", "OLcfg:4" },
228 { "OLcfgGlOc", "OLcfgOc:0" },
229 { "OLcfgBkOc", "OLcfgOc:1" },
230 { "OLcfgDbOc", "OLcfgOc:2" },
231 { "OLcfgOvOc", "OLcfgOc:3" },
232 { "OLcfgCtOc", "OLcfgOc:4" }, /* contrib modules */
233
234 /* Syntaxes. We should just start using the standard names and
235 * document that they are predefined and available for users
236 * to reference in their own schema. Defining schema without
237 * OID macros is for masochists...
238 */
239 { "OMsyn", "1.3.6.1.4.1.1466.115.121.1" },
240 { "OMsBoolean", "OMsyn:7" },
241 { "OMsDN", "OMsyn:12" },
242 { "OMsDirectoryString", "OMsyn:15" },
243 { "OMsIA5String", "OMsyn:26" },
244 { "OMsInteger", "OMsyn:27" },
245 { "OMsOID", "OMsyn:38" },
246 { "OMsOctetString", "OMsyn:40" },
247 { NULL, NULL }
248 };
249
250 /*
251 * Backend/Database registry
252 *
253 * OLcfg{Bk|Db}{Oc|At}:0 -> common
254 * OLcfg{Bk|Db}{Oc|At}:1 -> back-bdb(/back-hdb) (removed)
255 * OLcfg{Bk|Db}{Oc|At}:2 -> back-ldif
256 * OLcfg{Bk|Db}{Oc|At}:3 -> back-ldap/meta
257 * OLcfg{Bk|Db}{Oc|At}:4 -> back-monitor
258 * OLcfg{Bk|Db}{Oc|At}:5 -> back-relay
259 * OLcfg{Bk|Db}{Oc|At}:6 -> back-sql(/back-ndb)
260 * OLcfg{Bk|Db}{Oc|At}:7 -> back-sock
261 * OLcfg{Bk|Db}{Oc|At}:8 -> back-null
262 * OLcfg{Bk|Db}{Oc|At}:9 -> back-passwd
263 * OLcfg{Bk|Db}{Oc|At}:10 -> back-shell (removed)
264 * OLcfg{Bk|Db}{Oc|At}:11 -> back-perl
265 * OLcfg{Bk|Db}{Oc|At}:12 -> back-mdb
266 * OLcfg{Bk|Db}{Oc|At}:13 -> lloadd
267 */
268
269 /*
270 * Overlay registry
271 *
272 * OLcfgOv{Oc|At}:1 -> syncprov
273 * OLcfgOv{Oc|At}:2 -> pcache
274 * OLcfgOv{Oc|At}:3 -> chain
275 * OLcfgOv{Oc|At}:4 -> accesslog
276 * OLcfgOv{Oc|At}:5 -> valsort
277 * OLcfgOv{Oc|At}:7 -> distproc
278 * OLcfgOv{Oc|At}:8 -> dynlist
279 * OLcfgOv{Oc|At}:9 -> dds
280 * OLcfgOv{Oc|At}:10 -> unique
281 * OLcfgOv{Oc|At}:11 -> refint
282 * OLcfgOv{Oc|At}:12 -> ppolicy
283 * OLcfgOv{Oc|At}:13 -> constraint
284 * OLcfgOv{Oc|At}:14 -> translucent
285 * OLcfgOv{Oc|At}:15 -> auditlog
286 * OLcfgOv{Oc|At}:16 -> rwm
287 * OLcfgOv{Oc|At}:17 -> dyngroup
288 * OLcfgOv{Oc|At}:18 -> memberof
289 * OLcfgOv{Oc|At}:19 -> collect
290 * OLcfgOv{Oc|At}:20 -> retcode
291 * OLcfgOv{Oc|At}:21 -> sssvlv
292 * OLcfgOv{Oc|At}:22 -> autoca
293 * OLcfgOv{Oc|At}:24 -> remoteauth
294 */
295
296 /* alphabetical ordering */
297
298 static ConfigTable config_back_cf_table[] = {
299 /* This attr is read-only */
300 { "", "", 0, 0, 0, ARG_MAGIC,
301 &config_fname, "( OLcfgGlAt:78 NAME 'olcConfigFile' "
302 "DESC 'File for slapd configuration directives' "
303 "EQUALITY caseExactMatch "
304 "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL },
305 { "", "", 0, 0, 0, ARG_MAGIC,
306 &config_cfdir, "( OLcfgGlAt:79 NAME 'olcConfigDir' "
307 "DESC 'Directory for slapd configuration backend' "
308 "EQUALITY caseExactMatch "
309 "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL },
310 { "access", NULL, 0, 0, 0, ARG_MAY_DB|ARG_MAGIC|CFG_ACL,
311 &config_generic, "( OLcfgGlAt:1 NAME 'olcAccess' "
312 "DESC 'Access Control List' "
313 "EQUALITY caseIgnoreMatch "
314 "SYNTAX OMsDirectoryString X-ORDERED 'VALUES' )", NULL, NULL },
315 { "add_content_acl", NULL, 0, 0, 0, ARG_MAY_DB|ARG_ON_OFF|ARG_MAGIC|CFG_ACL_ADD,
316 &config_generic, "( OLcfgGlAt:86 NAME 'olcAddContentAcl' "
317 "DESC 'Check ACLs against content of Add ops' "
318 "EQUALITY booleanMatch "
319 "SYNTAX OMsBoolean SINGLE-VALUE )", NULL, NULL },
320 { "allows", "features", 2, 0, 5, ARG_PRE_DB|ARG_MAGIC,
321 &config_allows, "( OLcfgGlAt:2 NAME 'olcAllows' "
322 "DESC 'Allowed set of deprecated features' "
323 "EQUALITY caseIgnoreMatch "
324 "SYNTAX OMsDirectoryString )", NULL, NULL },
325 { "argsfile", "file", 2, 2, 0, ARG_STRING,
326 &slapd_args_file, "( OLcfgGlAt:3 NAME 'olcArgsFile' "
327 "DESC 'File for slapd command line options' "
328 "EQUALITY caseExactMatch "
329 "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL },
330 { "attributeoptions", NULL, 0, 0, 0, ARG_MAGIC|CFG_ATOPT,
331 &config_generic, "( OLcfgGlAt:5 NAME 'olcAttributeOptions' "
332 "EQUALITY caseIgnoreMatch "
333 "SYNTAX OMsDirectoryString )", NULL, NULL },
334 { "attribute", "attribute", 2, 0, STRLENOF( "attribute" ),
335 ARG_PAREN|ARG_MAGIC|CFG_ATTR,
336 &config_generic, "( OLcfgGlAt:4 NAME 'olcAttributeTypes' "
337 "DESC 'OpenLDAP attributeTypes' "
338 "EQUALITY caseIgnoreMatch "
339 "SUBSTR caseIgnoreSubstringsMatch "
340 "SYNTAX OMsDirectoryString X-ORDERED 'VALUES' )",
341 NULL, NULL },
342 { "authid-rewrite", "rewrite", 2, 0, STRLENOF( "authid-rewrite" ),
343 ARG_MAGIC|CFG_REWRITE, &config_generic,
344 "( OLcfgGlAt:6 NAME 'olcAuthIDRewrite' "
345 "EQUALITY caseIgnoreMatch "
346 "SYNTAX OMsDirectoryString X-ORDERED 'VALUES' )", NULL, NULL },
347 { "authz-policy", "policy", 2, 2, 0, ARG_STRING|ARG_MAGIC|CFG_AZPOLICY,
348 &config_generic, "( OLcfgGlAt:7 NAME 'olcAuthzPolicy' "
349 "EQUALITY caseIgnoreMatch "
350 "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL },
351 { "authz-regexp", "regexp> <DN", 3, 3, 0, ARG_MAGIC|CFG_AZREGEXP,
352 &config_generic, "( OLcfgGlAt:8 NAME 'olcAuthzRegexp' "
353 "EQUALITY caseIgnoreMatch "
354 "SYNTAX OMsDirectoryString X-ORDERED 'VALUES' )", NULL, NULL },
355 { "backend", "type", 2, 2, 0, ARG_PRE_DB|ARG_MAGIC|CFG_BACKEND,
356 &config_generic, "( OLcfgGlAt:9 NAME 'olcBackend' "
357 "DESC 'A type of backend' "
358 "EQUALITY caseIgnoreMatch "
359 "SYNTAX OMsDirectoryString SINGLE-VALUE X-ORDERED 'SIBLINGS' )",
360 NULL, NULL },
361 { "concurrency", "level", 2, 2, 0, ARG_INT|ARG_MAGIC|CFG_CONCUR,
362 &config_generic, "( OLcfgGlAt:10 NAME 'olcConcurrency' "
363 "EQUALITY integerMatch "
364 "SYNTAX OMsInteger SINGLE-VALUE )", NULL, NULL },
365 { "conn_max_pending", "max", 2, 2, 0, ARG_INT,
366 &slap_conn_max_pending, "( OLcfgGlAt:11 NAME 'olcConnMaxPending' "
367 "EQUALITY integerMatch "
368 "SYNTAX OMsInteger SINGLE-VALUE )", NULL, NULL },
369 { "conn_max_pending_auth", "max", 2, 2, 0, ARG_INT,
370 &slap_conn_max_pending_auth, "( OLcfgGlAt:12 NAME 'olcConnMaxPendingAuth' "
371 "EQUALITY integerMatch "
372 "SYNTAX OMsInteger SINGLE-VALUE )", NULL, NULL },
373 { "database", "type", 2, 2, 0, ARG_MAGIC|CFG_DATABASE,
374 &config_generic, "( OLcfgGlAt:13 NAME 'olcDatabase' "
375 "DESC 'The backend type for a database instance' "
376 "SUP olcBackend SINGLE-VALUE X-ORDERED 'SIBLINGS' )", NULL, NULL },
377 { "defaultSearchBase", "dn", 2, 2, 0, ARG_PRE_BI|ARG_PRE_DB|ARG_DN|ARG_QUOTE|ARG_MAGIC,
378 &config_search_base, "( OLcfgGlAt:14 NAME 'olcDefaultSearchBase' "
379 "EQUALITY distinguishedNameMatch "
380 "SYNTAX OMsDN SINGLE-VALUE )", NULL, NULL },
381 { "disabled", "on|off", 2, 2, 0, ARG_DB|ARG_ON_OFF|ARG_MAGIC|CFG_DISABLED,
382 &config_generic, "( OLcfgDbAt:0.21 NAME 'olcDisabled' "
383 "EQUALITY booleanMatch "
384 "SYNTAX OMsBoolean SINGLE-VALUE )", NULL, NULL },
385 { "disallows", "features", 2, 0, 8, ARG_PRE_DB|ARG_MAGIC,
386 &config_disallows, "( OLcfgGlAt:15 NAME 'olcDisallows' "
387 "EQUALITY caseIgnoreMatch "
388 "SYNTAX OMsDirectoryString )", NULL, NULL },
389 { "ditcontentrule", NULL, 0, 0, 0, ARG_MAGIC|CFG_DIT|ARG_NO_DELETE|ARG_NO_INSERT,
390 &config_generic, "( OLcfgGlAt:16 NAME 'olcDitContentRules' "
391 "DESC 'OpenLDAP DIT content rules' "
392 "EQUALITY caseIgnoreMatch "
393 "SUBSTR caseIgnoreSubstringsMatch "
394 "SYNTAX OMsDirectoryString X-ORDERED 'VALUES' )",
395 NULL, NULL },
396 { "extra_attrs", "attrlist", 2, 2, 0, ARG_DB|ARG_MAGIC,
397 &config_extra_attrs, "( OLcfgDbAt:0.20 NAME 'olcExtraAttrs' "
398 "EQUALITY caseIgnoreMatch "
399 "SYNTAX OMsDirectoryString )", NULL, NULL },
400 { "gentlehup", "on|off", 2, 2, 0,
401 #ifdef SIGHUP
402 ARG_ON_OFF, &global_gentlehup,
403 #else
404 ARG_IGNORED, NULL,
405 #endif
406 "( OLcfgGlAt:17 NAME 'olcGentleHUP' "
407 "EQUALITY booleanMatch "
408 "SYNTAX OMsBoolean SINGLE-VALUE )", NULL, NULL },
409 { "hidden", "on|off", 2, 2, 0, ARG_DB|ARG_ON_OFF|ARG_MAGIC|CFG_HIDDEN,
410 &config_generic, "( OLcfgDbAt:0.17 NAME 'olcHidden' "
411 "EQUALITY booleanMatch "
412 "SYNTAX OMsBoolean SINGLE-VALUE )", NULL, NULL },
413 { "idletimeout", "timeout", 2, 2, 0, ARG_INT,
414 &global_idletimeout, "( OLcfgGlAt:18 NAME 'olcIdleTimeout' "
415 "EQUALITY integerMatch "
416 "SYNTAX OMsInteger SINGLE-VALUE )", NULL, NULL },
417 { "include", "file", 2, 2, 0, ARG_MAGIC,
418 &config_include, "( OLcfgGlAt:19 NAME 'olcInclude' "
419 "SUP labeledURI )", NULL, NULL },
420 { "index_hash64", "on|off", 2, 2, 0, ARG_ON_OFF|ARG_MAGIC|CFG_IX_HASH64,
421 &config_generic, "( OLcfgGlAt:94 NAME 'olcIndexHash64' "
422 "EQUALITY booleanMatch "
423 "SYNTAX OMsBoolean SINGLE-VALUE )", NULL, NULL },
424 { "index_substr_if_minlen", "min", 2, 2, 0, ARG_UINT|ARG_NONZERO|ARG_MAGIC|CFG_SSTR_IF_MIN,
425 &config_generic, "( OLcfgGlAt:20 NAME 'olcIndexSubstrIfMinLen' "
426 "EQUALITY integerMatch "
427 "SYNTAX OMsInteger SINGLE-VALUE )", NULL,
428 { .v_uint = SLAP_INDEX_SUBSTR_IF_MINLEN_DEFAULT }
429 },
430 { "index_substr_if_maxlen", "max", 2, 2, 0, ARG_UINT|ARG_NONZERO|ARG_MAGIC|CFG_SSTR_IF_MAX,
431 &config_generic, "( OLcfgGlAt:21 NAME 'olcIndexSubstrIfMaxLen' "
432 "EQUALITY integerMatch "
433 "SYNTAX OMsInteger SINGLE-VALUE )", NULL,
434 { .v_uint = SLAP_INDEX_SUBSTR_IF_MAXLEN_DEFAULT }
435 },
436 { "index_substr_any_len", "len", 2, 2, 0, ARG_UINT|ARG_NONZERO,
437 &index_substr_any_len, "( OLcfgGlAt:22 NAME 'olcIndexSubstrAnyLen' "
438 "EQUALITY integerMatch "
439 "SYNTAX OMsInteger SINGLE-VALUE )", NULL,
440 { .v_uint = SLAP_INDEX_SUBSTR_ANY_LEN_DEFAULT } },
441 { "index_substr_any_step", "step", 2, 2, 0, ARG_UINT|ARG_NONZERO,
442 &index_substr_any_step, "( OLcfgGlAt:23 NAME 'olcIndexSubstrAnyStep' "
443 "EQUALITY integerMatch "
444 "SYNTAX OMsInteger SINGLE-VALUE )", NULL,
445 { .v_uint = SLAP_INDEX_SUBSTR_ANY_STEP_DEFAULT } },
446 { "index_intlen", "len", 2, 2, 0, ARG_UINT|ARG_MAGIC|CFG_IX_INTLEN,
447 &config_generic, "( OLcfgGlAt:84 NAME 'olcIndexIntLen' "
448 "EQUALITY integerMatch "
449 "SYNTAX OMsInteger SINGLE-VALUE )", NULL, NULL },
450 { "lastmod", "on|off", 2, 2, 0, ARG_DB|ARG_ON_OFF|ARG_MAGIC|CFG_LASTMOD,
451 &config_generic, "( OLcfgDbAt:0.4 NAME 'olcLastMod' "
452 "EQUALITY booleanMatch "
453 "SYNTAX OMsBoolean SINGLE-VALUE )", NULL, NULL },
454 { "lastbind", "on|off", 2, 2, 0, ARG_DB|ARG_ON_OFF|ARG_MAGIC|CFG_LASTBIND,
455 &config_generic, "( OLcfgDbAt:0.22 NAME 'olcLastBind' "
456 "EQUALITY booleanMatch "
457 "SYNTAX OMsBoolean SINGLE-VALUE )", NULL, NULL },
458 { "ldapsyntax", "syntax", 2, 0, 0,
459 ARG_PAREN|ARG_MAGIC|CFG_SYNTAX,
460 &config_generic, "( OLcfgGlAt:85 NAME 'olcLdapSyntaxes' "
461 "DESC 'OpenLDAP ldapSyntax' "
462 "EQUALITY caseIgnoreMatch "
463 "SUBSTR caseIgnoreSubstringsMatch "
464 "SYNTAX OMsDirectoryString X-ORDERED 'VALUES' )",
465 NULL, NULL },
466 { "limits", "limits", 2, 0, 0, ARG_DB|ARG_MAGIC|CFG_LIMITS,
467 &config_generic, "( OLcfgDbAt:0.5 NAME 'olcLimits' "
468 "EQUALITY caseIgnoreMatch "
469 "SYNTAX OMsDirectoryString X-ORDERED 'VALUES' )", NULL, NULL },
470 { "listener-threads", "count", 2, 0, 0,
471 ARG_UINT|ARG_MAGIC|CFG_LTHREADS, &config_generic,
472 "( OLcfgGlAt:93 NAME 'olcListenerThreads' "
473 "EQUALITY integerMatch "
474 "SYNTAX OMsInteger SINGLE-VALUE )", NULL,
475 { .v_uint = 1 }
476 },
477 { "localSSF", "ssf", 2, 2, 0, ARG_INT,
478 &local_ssf, "( OLcfgGlAt:26 NAME 'olcLocalSSF' "
479 "EQUALITY integerMatch "
480 "SYNTAX OMsInteger SINGLE-VALUE )", NULL,
481 { .v_int = LDAP_PVT_SASL_LOCAL_SSF } },
482 { "logfile", "file", 2, 2, 0, ARG_STRING|ARG_MAGIC|CFG_LOGFILE,
483 &config_generic, "( OLcfgGlAt:27 NAME 'olcLogFile' "
484 "EQUALITY caseExactMatch "
485 "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL },
486 { "loglevel", "level", 2, 0, 0, ARG_MAGIC,
487 &config_loglevel, "( OLcfgGlAt:28 NAME 'olcLogLevel' "
488 "EQUALITY caseIgnoreMatch "
489 "SYNTAX OMsDirectoryString )", NULL, NULL },
490 { "maxDerefDepth", "depth", 2, 2, 0, ARG_DB|ARG_INT|ARG_MAGIC|CFG_DEPTH,
491 &config_generic, "( OLcfgDbAt:0.6 NAME 'olcMaxDerefDepth' "
492 "EQUALITY integerMatch "
493 "SYNTAX OMsInteger SINGLE-VALUE )", NULL,
494 { .v_int = SLAPD_DEFAULT_MAXDEREFDEPTH }
495 },
496 { "maxFilterDepth", "depth", 2, 2, 0, ARG_INT,
497 &slap_max_filter_depth, "( OLcfgGlAt:101 NAME 'olcMaxFilterDepth' "
498 "EQUALITY integerMatch "
499 "SYNTAX OMsInteger SINGLE-VALUE )", NULL,
500 { .v_int = SLAP_MAX_FILTER_DEPTH_DEFAULT }
501 },
502 { "multiprovider", "on|off", 2, 2, 0, ARG_DB|ARG_ON_OFF|ARG_MAGIC|CFG_MULTIPROVIDER,
503 &config_generic, "( OLcfgDbAt:0.16 NAME ( 'olcMultiProvider' 'olcMirrorMode' ) "
504 "EQUALITY booleanMatch "
505 "SYNTAX OMsBoolean SINGLE-VALUE )", NULL, NULL },
506 { "moduleload", "file", 2, 0, 0,
507 #ifdef SLAPD_MODULES
508 ARG_MAGIC|CFG_MODLOAD|ARG_NO_DELETE, &config_generic,
509 #else
510 ARG_IGNORED, NULL,
511 #endif
512 "( OLcfgGlAt:30 NAME 'olcModuleLoad' "
513 "EQUALITY caseIgnoreMatch "
514 "SYNTAX OMsDirectoryString X-ORDERED 'VALUES' )", NULL, NULL },
515 { "modulepath", "path", 2, 2, 0,
516 #ifdef SLAPD_MODULES
517 ARG_MAGIC|CFG_MODPATH|ARG_NO_DELETE|ARG_NO_INSERT, &config_generic,
518 #else
519 ARG_IGNORED, NULL,
520 #endif
521 "( OLcfgGlAt:31 NAME 'olcModulePath' "
522 "EQUALITY caseExactMatch "
523 "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL },
524 { "monitoring", "TRUE|FALSE", 2, 2, 0,
525 ARG_MAGIC|CFG_MONITORING|ARG_DB|ARG_ON_OFF, &config_generic,
526 "( OLcfgDbAt:0.18 NAME 'olcMonitoring' "
527 "EQUALITY booleanMatch "
528 "SYNTAX OMsBoolean SINGLE-VALUE )", NULL, NULL },
529 { "objectclass", "objectclass", 2, 0, 0, ARG_PAREN|ARG_MAGIC|CFG_OC,
530 &config_generic, "( OLcfgGlAt:32 NAME 'olcObjectClasses' "
531 "DESC 'OpenLDAP object classes' "
532 "EQUALITY caseIgnoreMatch "
533 "SUBSTR caseIgnoreSubstringsMatch "
534 "SYNTAX OMsDirectoryString X-ORDERED 'VALUES' )",
535 NULL, NULL },
536 { "objectidentifier", "name> <oid", 3, 3, 0, ARG_MAGIC|CFG_OID,
537 &config_generic, "( OLcfgGlAt:33 NAME 'olcObjectIdentifier' "
538 "EQUALITY caseIgnoreMatch "
539 "SUBSTR caseIgnoreSubstringsMatch "
540 "SYNTAX OMsDirectoryString X-ORDERED 'VALUES' )", NULL, NULL },
541 { "overlay", "overlay", 2, 2, 0, ARG_MAGIC,
542 &config_overlay, "( OLcfgGlAt:34 NAME 'olcOverlay' "
543 "SUP olcDatabase SINGLE-VALUE X-ORDERED 'SIBLINGS' )", NULL, NULL },
544 { "password-crypt-salt-format", "salt", 2, 2, 0, ARG_STRING|ARG_MAGIC|CFG_SALT,
545 &config_generic, "( OLcfgGlAt:35 NAME 'olcPasswordCryptSaltFormat' "
546 "EQUALITY caseIgnoreMatch "
547 "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL },
548 { "password-hash", "hash", 2, 0, 0, ARG_MAGIC,
549 &config_passwd_hash, "( OLcfgGlAt:36 NAME 'olcPasswordHash' "
550 "EQUALITY caseIgnoreMatch "
551 "SYNTAX OMsDirectoryString )", NULL, NULL },
552 { "pidfile", "file", 2, 2, 0, ARG_STRING,
553 &slapd_pid_file, "( OLcfgGlAt:37 NAME 'olcPidFile' "
554 "EQUALITY caseExactMatch "
555 "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL },
556 { "plugin", NULL, 0, 0, 0,
557 #ifdef LDAP_SLAPI
558 ARG_MAGIC|CFG_PLUGIN, &config_generic,
559 #else
560 ARG_IGNORED, NULL,
561 #endif
562 "( OLcfgGlAt:38 NAME 'olcPlugin' "
563 "EQUALITY caseIgnoreMatch "
564 "SYNTAX OMsDirectoryString X-ORDERED 'VALUES' )", NULL, NULL },
565 { "pluginlog", "filename", 2, 2, 0,
566 #ifdef LDAP_SLAPI
567 ARG_STRING, &slapi_log_file,
568 #else
569 ARG_IGNORED, NULL,
570 #endif
571 "( OLcfgGlAt:39 NAME 'olcPluginLogFile' "
572 "EQUALITY caseExactMatch "
573 "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL },
574 { "readonly", "on|off", 2, 2, 0, ARG_MAY_DB|ARG_ON_OFF|ARG_MAGIC|CFG_RO,
575 &config_generic, "( OLcfgGlAt:40 NAME 'olcReadOnly' "
576 "EQUALITY booleanMatch "
577 "SYNTAX OMsBoolean SINGLE-VALUE )", NULL, NULL },
578 { "referral", "url", 2, 2, 0, ARG_MAGIC,
579 &config_referral, "( OLcfgGlAt:41 NAME 'olcReferral' "
580 "SUP labeledURI SINGLE-VALUE )", NULL, NULL },
581 { "replica", "host or uri", 2, 0, 0, ARG_DB|ARG_MAGIC,
582 &config_obsolete, "( OLcfgDbAt:0.7 NAME 'olcReplica' "
583 "EQUALITY caseIgnoreMatch "
584 "SUP labeledURI X-ORDERED 'VALUES' )", NULL, NULL },
585 { "replica-argsfile", NULL, 0, 0, 0, ARG_MAY_DB|ARG_MAGIC,
586 &config_obsolete, "( OLcfgGlAt:43 NAME 'olcReplicaArgsFile' "
587 "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL },
588 { "replica-pidfile", NULL, 0, 0, 0, ARG_MAY_DB|ARG_MAGIC,
589 &config_obsolete, "( OLcfgGlAt:44 NAME 'olcReplicaPidFile' "
590 "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL },
591 { "replicationInterval", NULL, 0, 0, 0, ARG_MAY_DB|ARG_MAGIC,
592 &config_obsolete, "( OLcfgGlAt:45 NAME 'olcReplicationInterval' "
593 "SYNTAX OMsInteger SINGLE-VALUE )", NULL, NULL },
594 { "replogfile", "filename", 2, 2, 0, ARG_MAY_DB|ARG_MAGIC,
595 &config_obsolete, "( OLcfgGlAt:46 NAME 'olcReplogFile' "
596 "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL },
597 { "require", "features", 2, 0, 7, ARG_MAY_DB|ARG_MAGIC,
598 &config_requires, "( OLcfgGlAt:47 NAME 'olcRequires' "
599 "EQUALITY caseIgnoreMatch "
600 "SYNTAX OMsDirectoryString )", NULL, NULL },
601 { "restrict", "op_list", 2, 0, 0, ARG_MAY_DB|ARG_MAGIC,
602 &config_restrict, "( OLcfgGlAt:48 NAME 'olcRestrict' "
603 "EQUALITY caseIgnoreMatch "
604 "SYNTAX OMsDirectoryString )", NULL, NULL },
605 { "reverse-lookup", "on|off", 2, 2, 0,
606 #ifdef SLAPD_RLOOKUPS
607 ARG_ON_OFF, &use_reverse_lookup,
608 #else
609 ARG_IGNORED, NULL,
610 #endif
611 "( OLcfgGlAt:49 NAME 'olcReverseLookup' "
612 "EQUALITY booleanMatch "
613 "SYNTAX OMsBoolean SINGLE-VALUE )", NULL, NULL },
614 { "rootdn", "dn", 2, 2, 0, ARG_DB|ARG_DN|ARG_QUOTE|ARG_MAGIC,
615 &config_rootdn, "( OLcfgDbAt:0.8 NAME 'olcRootDN' "
616 "EQUALITY distinguishedNameMatch "
617 "SYNTAX OMsDN SINGLE-VALUE )", NULL, NULL },
618 { "rootDSE", "file", 2, 2, 0, ARG_MAGIC|CFG_ROOTDSE,
619 &config_generic, "( OLcfgGlAt:51 NAME 'olcRootDSE' "
620 "EQUALITY caseIgnoreMatch "
621 "SYNTAX OMsDirectoryString )", NULL, NULL },
622 { "rootpw", "password", 2, 2, 0, ARG_BERVAL|ARG_DB|ARG_MAGIC,
623 &config_rootpw, "( OLcfgDbAt:0.9 NAME 'olcRootPW' "
624 "EQUALITY octetStringMatch "
625 "SYNTAX OMsOctetString SINGLE-VALUE )", NULL, NULL },
626 { "sasl-authz-policy", NULL, 2, 2, 0, ARG_MAGIC|CFG_AZPOLICY,
627 &config_generic, NULL, NULL, NULL },
628 { "sasl-auxprops", NULL, 2, 0, 0,
629 #ifdef HAVE_CYRUS_SASL
630 ARG_STRING|ARG_UNIQUE, &slap_sasl_auxprops,
631 #else
632 ARG_IGNORED, NULL,
633 #endif
634 "( OLcfgGlAt:89 NAME 'olcSaslAuxprops' "
635 "EQUALITY caseIgnoreMatch "
636 "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL },
637 { "sasl-auxprops-dontusecopy", NULL, 2, 0, 0,
638 #if defined(HAVE_CYRUS_SASL) && defined(SLAP_AUXPROP_DONTUSECOPY)
639 ARG_MAGIC|CFG_AZDUC, &config_generic,
640 #else
641 ARG_IGNORED, NULL,
642 #endif
643 "( OLcfgGlAt:91 NAME 'olcSaslAuxpropsDontUseCopy' "
644 "EQUALITY caseIgnoreMatch "
645 "SYNTAX OMsDirectoryString )", NULL, NULL },
646 { "sasl-auxprops-dontusecopy-ignore", "true|FALSE", 2, 0, 0,
647 #if defined(HAVE_CYRUS_SASL) && defined(SLAP_AUXPROP_DONTUSECOPY)
648 ARG_ON_OFF|CFG_AZDUC_IGNORE, &slap_dontUseCopy_ignore,
649 #else
650 ARG_IGNORED, NULL,
651 #endif
652 "( OLcfgGlAt:92 NAME 'olcSaslAuxpropsDontUseCopyIgnore' "
653 "EQUALITY booleanMatch "
654 "SYNTAX OMsBoolean SINGLE-VALUE )", NULL, NULL },
655 { "sasl-cbinding", NULL, 2, 2, 0,
656 #ifdef HAVE_CYRUS_SASL
657 ARG_STRING, &sasl_cbinding,
658 #else
659 ARG_IGNORED, NULL,
660 #endif
661 "( OLcfgGlAt:100 NAME 'olcSaslCBinding' "
662 "EQUALITY caseIgnoreMatch "
663 "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL },
664 { "sasl-host", "host", 2, 2, 0,
665 #ifdef HAVE_CYRUS_SASL
666 ARG_STRING|ARG_UNIQUE, &sasl_host,
667 #else
668 ARG_IGNORED, NULL,
669 #endif
670 "( OLcfgGlAt:53 NAME 'olcSaslHost' "
671 "EQUALITY caseIgnoreMatch "
672 "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL },
673 { "sasl-realm", "realm", 2, 2, 0,
674 #ifdef HAVE_CYRUS_SASL
675 ARG_STRING|ARG_UNIQUE, &global_realm,
676 #else
677 ARG_IGNORED, NULL,
678 #endif
679 "( OLcfgGlAt:54 NAME 'olcSaslRealm' "
680 "EQUALITY caseExactMatch "
681 "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL },
682 { "sasl-regexp", NULL, 3, 3, 0, ARG_MAGIC|CFG_AZREGEXP,
683 &config_generic, NULL, NULL, NULL },
684 { "sasl-secprops", "properties", 2, 2, 0,
685 #ifdef HAVE_CYRUS_SASL
686 ARG_MAGIC|CFG_SASLSECP, &config_generic,
687 #else
688 ARG_IGNORED, NULL,
689 #endif
690 "( OLcfgGlAt:56 NAME 'olcSaslSecProps' "
691 "EQUALITY caseExactMatch "
692 "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL },
693 { "saslRegexp", NULL, 3, 3, 0, ARG_MAGIC|CFG_AZREGEXP,
694 &config_generic, NULL, NULL, NULL },
695 { "schemadn", "dn", 2, 2, 0, ARG_MAY_DB|ARG_DN|ARG_QUOTE|ARG_MAGIC,
696 &config_schema_dn, "( OLcfgGlAt:58 NAME 'olcSchemaDN' "
697 "EQUALITY distinguishedNameMatch "
698 "SYNTAX OMsDN SINGLE-VALUE )", NULL, NULL },
699 { "security", "factors", 2, 0, 0, ARG_MAY_DB|ARG_MAGIC,
700 &config_security, "( OLcfgGlAt:59 NAME 'olcSecurity' "
701 "EQUALITY caseIgnoreMatch "
702 "SYNTAX OMsDirectoryString )", NULL, NULL },
703 { "serverID", "number> <[URI]", 2, 3, 0, ARG_MAGIC|CFG_SERVERID,
704 &config_generic, "( OLcfgGlAt:81 NAME 'olcServerID' "
705 "EQUALITY caseIgnoreMatch "
706 "SYNTAX OMsDirectoryString )", NULL, NULL },
707 { "sizelimit", "limit", 2, 0, 0, ARG_MAY_DB|ARG_MAGIC,
708 &config_sizelimit, "( OLcfgGlAt:60 NAME 'olcSizeLimit' "
709 "EQUALITY caseExactMatch "
710 "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL },
711 { "sockbuf_max_incoming", "max", 2, 2, 0, ARG_BER_LEN_T,
712 &sockbuf_max_incoming, "( OLcfgGlAt:61 NAME 'olcSockbufMaxIncoming' "
713 "EQUALITY integerMatch "
714 "SYNTAX OMsInteger SINGLE-VALUE )", NULL,
715 { .v_ber_t = SLAP_SB_MAX_INCOMING_DEFAULT } },
716 { "sockbuf_max_incoming_auth", "max", 2, 2, 0, ARG_BER_LEN_T,
717 &sockbuf_max_incoming_auth, "( OLcfgGlAt:62 NAME 'olcSockbufMaxIncomingAuth' "
718 "EQUALITY integerMatch "
719 "SYNTAX OMsInteger SINGLE-VALUE )", NULL,
720 { .v_ber_t = SLAP_SB_MAX_INCOMING_AUTH } },
721 { "sortvals", "attr", 2, 0, 0, ARG_MAGIC|CFG_SORTVALS,
722 &config_generic, "( OLcfgGlAt:83 NAME 'olcSortVals' "
723 "DESC 'Attributes whose values will always be sorted' "
724 "EQUALITY caseIgnoreMatch "
725 "SYNTAX OMsDirectoryString )", NULL, NULL },
726 { "subordinate", "[advertise]", 1, 2, 0, ARG_DB|ARG_MAGIC,
727 &config_subordinate, "( OLcfgDbAt:0.15 NAME 'olcSubordinate' "
728 "EQUALITY caseExactMatch "
729 "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL },
730 { "suffix", "suffix", 2, 2, 0, ARG_DB|ARG_DN|ARG_QUOTE|ARG_MAGIC,
731 &config_suffix, "( OLcfgDbAt:0.10 NAME 'olcSuffix' "
732 "EQUALITY distinguishedNameMatch "
733 "SYNTAX OMsDN )", NULL, NULL },
734 { "sync_use_subentry", NULL, 0, 0, 0, ARG_ON_OFF|ARG_DB|ARG_MAGIC|CFG_SYNC_SUBENTRY,
735 &config_generic, "( OLcfgDbAt:0.19 NAME 'olcSyncUseSubentry' "
736 "DESC 'Store sync context in a subentry' "
737 "EQUALITY booleanMatch "
738 "SYNTAX OMsBoolean SINGLE-VALUE )", NULL, NULL },
739 { "syncrepl", NULL, 0, 0, 0, ARG_DB|ARG_MAGIC,
740 &syncrepl_config, "( OLcfgDbAt:0.11 NAME 'olcSyncrepl' "
741 "EQUALITY caseIgnoreMatch "
742 "SYNTAX OMsDirectoryString X-ORDERED 'VALUES' )", NULL, NULL },
743 { "tcp-buffer", "[listener=<listener>] [{read|write}=]size", 0, 0, 0,
744 #ifndef LDAP_TCP_BUFFER
745 ARG_IGNORED, NULL,
746 #else /* LDAP_TCP_BUFFER */
747 ARG_MAGIC, &config_tcp_buffer,
748 #endif /* LDAP_TCP_BUFFER */
749 "( OLcfgGlAt:90 NAME 'olcTCPBuffer' "
750 "EQUALITY caseExactMatch "
751 "DESC 'Custom TCP buffer size' "
752 "SYNTAX OMsDirectoryString )", NULL, NULL },
753 { "threads", "count", 2, 2, 0,
754 ARG_INT|ARG_MAGIC|CFG_THREADS, &config_generic,
755 "( OLcfgGlAt:66 NAME 'olcThreads' "
756 "EQUALITY integerMatch "
757 "SYNTAX OMsInteger SINGLE-VALUE )", NULL,
758 { .v_int = SLAP_MAX_WORKER_THREADS }
759 },
760 { "threadqueues", "count", 2, 2, 0,
761 ARG_INT|ARG_MAGIC|CFG_THREADQS, &config_generic,
762 "( OLcfgGlAt:95 NAME 'olcThreadQueues' "
763 "EQUALITY integerMatch "
764 "SYNTAX OMsInteger SINGLE-VALUE )", NULL,
765 { .v_int = 1 }
766 },
767 { "timelimit", "limit", 2, 0, 0, ARG_MAY_DB|ARG_MAGIC,
768 &config_timelimit, "( OLcfgGlAt:67 NAME 'olcTimeLimit' "
769 "EQUALITY caseExactMatch "
770 "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL },
771 { "TLSCACertificate", NULL, 2, 2, 0,
772 #ifdef HAVE_TLS
773 CFG_TLS_CACERT|ARG_BINARY|ARG_MAGIC, &config_tls_option,
774 #else
775 ARG_IGNORED, NULL,
776 #endif
777 "( OLcfgGlAt:97 NAME 'olcTLSCACertificate' "
778 "DESC 'X.509 certificate, must use ;binary' "
779 "EQUALITY certificateExactMatch "
780 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.8 SINGLE-VALUE )", NULL, NULL },
781 { "TLSCACertificateFile", NULL, 2, 2, 0,
782 #ifdef HAVE_TLS
783 CFG_TLS_CA_FILE|ARG_STRING|ARG_MAGIC, &config_tls_option,
784 #else
785 ARG_IGNORED, NULL,
786 #endif
787 "( OLcfgGlAt:68 NAME 'olcTLSCACertificateFile' "
788 "EQUALITY caseExactMatch "
789 "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL },
790 { "TLSCACertificatePath", NULL, 2, 2, 0,
791 #ifdef HAVE_TLS
792 CFG_TLS_CA_PATH|ARG_STRING|ARG_MAGIC, &config_tls_option,
793 #else
794 ARG_IGNORED, NULL,
795 #endif
796 "( OLcfgGlAt:69 NAME 'olcTLSCACertificatePath' "
797 "EQUALITY caseExactMatch "
798 "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL },
799 { "TLSCertificate", NULL, 2, 2, 0,
800 #ifdef HAVE_TLS
801 CFG_TLS_CERT|ARG_BINARY|ARG_MAGIC, &config_tls_option,
802 #else
803 ARG_IGNORED, NULL,
804 #endif
805 "( OLcfgGlAt:98 NAME 'olcTLSCertificate' "
806 "DESC 'X.509 certificate, must use ;binary' "
807 "EQUALITY certificateExactMatch "
808 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.8 SINGLE-VALUE )", NULL, NULL },
809 { "TLSCertificateFile", NULL, 2, 2, 0,
810 #ifdef HAVE_TLS
811 CFG_TLS_CERT_FILE|ARG_STRING|ARG_MAGIC, &config_tls_option,
812 #else
813 ARG_IGNORED, NULL,
814 #endif
815 "( OLcfgGlAt:70 NAME 'olcTLSCertificateFile' "
816 "EQUALITY caseExactMatch "
817 "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL },
818 { "TLSCertificateKey", NULL, 2, 2, 0,
819 #ifdef HAVE_TLS
820 CFG_TLS_KEY|ARG_BINARY|ARG_MAGIC, &config_tls_option,
821 #else
822 ARG_IGNORED, NULL,
823 #endif
824 "( OLcfgGlAt:99 NAME 'olcTLSCertificateKey' "
825 "DESC 'X.509 privateKey, must use ;binary' "
826 "EQUALITY privateKeyMatch "
827 "SYNTAX 1.2.840.113549.1.8.1.1 SINGLE-VALUE )", NULL, NULL },
828 { "TLSCertificateKeyFile", NULL, 2, 2, 0,
829 #ifdef HAVE_TLS
830 CFG_TLS_CERT_KEY|ARG_STRING|ARG_MAGIC, &config_tls_option,
831 #else
832 ARG_IGNORED, NULL,
833 #endif
834 "( OLcfgGlAt:71 NAME 'olcTLSCertificateKeyFile' "
835 "EQUALITY caseExactMatch "
836 "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL },
837 { "TLSCipherSuite", NULL, 2, 2, 0,
838 #ifdef HAVE_TLS
839 CFG_TLS_CIPHER|ARG_STRING|ARG_MAGIC, &config_tls_option,
840 #else
841 ARG_IGNORED, NULL,
842 #endif
843 "( OLcfgGlAt:72 NAME 'olcTLSCipherSuite' "
844 "EQUALITY caseExactMatch "
845 "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL },
846 { "TLSCRLCheck", NULL, 2, 2, 0,
847 #if defined(HAVE_TLS) && defined(HAVE_OPENSSL)
848 CFG_TLS_CRLCHECK|ARG_STRING|ARG_MAGIC, &config_tls_config,
849 #else
850 ARG_IGNORED, NULL,
851 #endif
852 "( OLcfgGlAt:73 NAME 'olcTLSCRLCheck' "
853 "EQUALITY caseExactMatch "
854 "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL },
855 { "TLSCRLFile", NULL, 2, 2, 0,
856 #if defined(HAVE_GNUTLS)
857 CFG_TLS_CRL_FILE|ARG_STRING|ARG_MAGIC, &config_tls_option,
858 #else
859 ARG_IGNORED, NULL,
860 #endif
861 "( OLcfgGlAt:82 NAME 'olcTLSCRLFile' "
862 "EQUALITY caseExactMatch "
863 "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL },
864 { "TLSRandFile", NULL, 2, 2, 0,
865 #ifdef HAVE_TLS
866 CFG_TLS_RAND|ARG_STRING|ARG_MAGIC, &config_tls_option,
867 #else
868 ARG_IGNORED, NULL,
869 #endif
870 "( OLcfgGlAt:74 NAME 'olcTLSRandFile' "
871 "EQUALITY caseExactMatch "
872 "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL },
873 { "TLSVerifyClient", NULL, 2, 2, 0,
874 #ifdef HAVE_TLS
875 CFG_TLS_VERIFY|ARG_STRING|ARG_MAGIC, &config_tls_config,
876 #else
877 ARG_IGNORED, NULL,
878 #endif
879 "( OLcfgGlAt:75 NAME 'olcTLSVerifyClient' "
880 "EQUALITY caseExactMatch "
881 "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL },
882 { "TLSDHParamFile", NULL, 2, 2, 0,
883 #ifdef HAVE_TLS
884 CFG_TLS_DH_FILE|ARG_STRING|ARG_MAGIC, &config_tls_option,
885 #else
886 ARG_IGNORED, NULL,
887 #endif
888 "( OLcfgGlAt:77 NAME 'olcTLSDHParamFile' "
889 "EQUALITY caseExactMatch "
890 "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL },
891 { "TLSECName", NULL, 2, 2, 0,
892 #ifdef HAVE_TLS
893 CFG_TLS_ECNAME|ARG_STRING|ARG_MAGIC, &config_tls_option,
894 #else
895 ARG_IGNORED, NULL,
896 #endif
897 "( OLcfgGlAt:96 NAME 'olcTLSECName' "
898 "EQUALITY caseExactMatch "
899 "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL },
900 { "TLSProtocolMin", NULL, 2, 2, 0,
901 #ifdef HAVE_TLS
902 CFG_TLS_PROTOCOL_MIN|ARG_STRING|ARG_MAGIC, &config_tls_config,
903 #else
904 ARG_IGNORED, NULL,
905 #endif
906 "( OLcfgGlAt:87 NAME 'olcTLSProtocolMin' "
907 "EQUALITY caseExactMatch "
908 "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL },
909 { "tool-threads", "count", 2, 2, 0, ARG_INT|ARG_MAGIC|CFG_TTHREADS,
910 &config_generic, "( OLcfgGlAt:80 NAME 'olcToolThreads' "
911 "EQUALITY integerMatch "
912 "SYNTAX OMsInteger SINGLE-VALUE )", NULL,
913 { .v_int = 1 }
914 },
915 { "ucdata-path", "path", 2, 2, 0, ARG_IGNORED,
916 NULL, NULL, NULL, NULL },
917 { "updatedn", "dn", 2, 2, 0, ARG_DB|ARG_DN|ARG_QUOTE|ARG_MAGIC,
918 &config_updatedn, "( OLcfgDbAt:0.12 NAME 'olcUpdateDN' "
919 "EQUALITY distinguishedNameMatch "
920 "SYNTAX OMsDN SINGLE-VALUE )", NULL, NULL },
921 { "updateref", "url", 2, 2, 0, ARG_DB|ARG_MAGIC,
922 &config_updateref, "( OLcfgDbAt:0.13 NAME 'olcUpdateRef' "
923 "EQUALITY caseIgnoreMatch "
924 "SUP labeledURI )", NULL, NULL },
925 { "writetimeout", "timeout", 2, 2, 0, ARG_INT,
926 &global_writetimeout, "( OLcfgGlAt:88 NAME 'olcWriteTimeout' "
927 "EQUALITY integerMatch "
928 "SYNTAX OMsInteger SINGLE-VALUE )", NULL, NULL },
929 /* Legacy keywords */
930 { "mirrormode", "on|off", 2, 2, 0, ARG_DB|ARG_ON_OFF|ARG_MAGIC|CFG_MULTIPROVIDER,
931 &config_generic, NULL, NULL, NULL },
932 { NULL, NULL, 0, 0, 0, ARG_IGNORED,
933 NULL, NULL, NULL, NULL }
934 };
935
936 /* Need to no-op this keyword for dynamic config */
937 ConfigTable olcDatabaseDummy[] = {
938 { "", "", 0, 0, 0, ARG_IGNORED,
939 NULL, "( OLcfgGlAt:13 NAME 'olcDatabase' "
940 "DESC 'The backend type for a database instance' "
941 "SUP olcBackend SINGLE-VALUE X-ORDERED 'SIBLINGS' )", NULL, NULL },
942 { NULL, NULL, 0, 0, 0, ARG_IGNORED }
943 };
944
945 /* Routines to check if a child can be added to this type */
946 static ConfigLDAPadd cfAddSchema, cfAddInclude, cfAddDatabase,
947 cfAddBackend, cfAddModule, cfAddOverlay;
948
949 /* NOTE: be careful when defining array members
950 * that can be conditionally compiled */
951 #define CFOC_GLOBAL cf_ocs[1]
952 #define CFOC_SCHEMA cf_ocs[2]
953 #define CFOC_BACKEND cf_ocs[3]
954 #define CFOC_DATABASE cf_ocs[4]
955 #define CFOC_OVERLAY cf_ocs[5]
956 #define CFOC_INCLUDE cf_ocs[6]
957 #define CFOC_FRONTEND cf_ocs[7]
958 #ifdef SLAPD_MODULES
959 #define CFOC_MODULE cf_ocs[8]
960 #endif /* SLAPD_MODULES */
961
962 static ConfigOCs cf_ocs[] = {
963 { "( OLcfgGlOc:0 "
964 "NAME 'olcConfig' "
965 "DESC 'OpenLDAP configuration object' "
966 "ABSTRACT SUP top )", Cft_Abstract, NULL },
967 { "( OLcfgGlOc:1 "
968 "NAME 'olcGlobal' "
969 "DESC 'OpenLDAP Global configuration options' "
970 "SUP olcConfig STRUCTURAL "
971 "MAY ( cn $ olcConfigFile $ olcConfigDir $ olcAllows $ olcArgsFile $ "
972 "olcAttributeOptions $ olcAuthIDRewrite $ "
973 "olcAuthzPolicy $ olcAuthzRegexp $ olcConcurrency $ "
974 "olcConnMaxPending $ olcConnMaxPendingAuth $ "
975 "olcDisallows $ olcGentleHUP $ olcIdleTimeout $ "
976 "olcIndexSubstrIfMaxLen $ olcIndexSubstrIfMinLen $ "
977 "olcIndexSubstrAnyLen $ olcIndexSubstrAnyStep $ olcIndexHash64 $ "
978 "olcIndexIntLen $ "
979 "olcListenerThreads $ olcLocalSSF $ olcLogFile $ olcLogLevel $ "
980 "olcMaxFilterDepth $ "
981 "olcPasswordCryptSaltFormat $ olcPasswordHash $ olcPidFile $ "
982 "olcPluginLogFile $ olcReadOnly $ olcReferral $ "
983 "olcReplogFile $ olcRequires $ olcRestrict $ olcReverseLookup $ "
984 "olcRootDSE $ "
985 "olcSaslAuxprops $ olcSaslAuxpropsDontUseCopy $ olcSaslAuxpropsDontUseCopyIgnore $ "
986 "olcSaslCBinding $ olcSaslHost $ olcSaslRealm $ olcSaslSecProps $ "
987 "olcSecurity $ olcServerID $ olcSizeLimit $ "
988 "olcSockbufMaxIncoming $ olcSockbufMaxIncomingAuth $ "
989 "olcTCPBuffer $ "
990 "olcThreads $ olcThreadQueues $ "
991 "olcTimeLimit $ olcTLSCACertificateFile $ "
992 "olcTLSCACertificatePath $ olcTLSCertificateFile $ "
993 "olcTLSCertificateKeyFile $ olcTLSCipherSuite $ olcTLSCRLCheck $ "
994 "olcTLSCACertificate $ olcTLSCertificate $ olcTLSCertificateKey $ "
995 "olcTLSRandFile $ olcTLSVerifyClient $ olcTLSDHParamFile $ olcTLSECName $ "
996 "olcTLSCRLFile $ olcTLSProtocolMin $ olcToolThreads $ olcWriteTimeout $ "
997 "olcObjectIdentifier $ olcAttributeTypes $ olcObjectClasses $ "
998 "olcDitContentRules $ olcLdapSyntaxes ) )", Cft_Global },
999 { "( OLcfgGlOc:2 "
1000 "NAME 'olcSchemaConfig' "
1001 "DESC 'OpenLDAP schema object' "
1002 "SUP olcConfig STRUCTURAL "
1003 "MAY ( cn $ olcObjectIdentifier $ olcLdapSyntaxes $ "
1004 "olcAttributeTypes $ olcObjectClasses $ olcDitContentRules ) )",
1005 Cft_Schema, NULL, cfAddSchema },
1006 { "( OLcfgGlOc:3 "
1007 "NAME 'olcBackendConfig' "
1008 "DESC 'OpenLDAP Backend-specific options' "
1009 "SUP olcConfig STRUCTURAL "
1010 "MUST olcBackend )", Cft_Backend, NULL, cfAddBackend },
1011 { "( OLcfgGlOc:4 "
1012 "NAME 'olcDatabaseConfig' "
1013 "DESC 'OpenLDAP Database-specific options' "
1014 "SUP olcConfig STRUCTURAL "
1015 "MUST olcDatabase "
1016 "MAY ( olcDisabled $ olcHidden $ olcSuffix $ olcSubordinate $ olcAccess $ "
1017 "olcAddContentAcl $ olcLastMod $ olcLastBind $ olcLimits $ "
1018 "olcMaxDerefDepth $ olcPlugin $ olcReadOnly $ olcReplica $ "
1019 "olcReplicaArgsFile $ olcReplicaPidFile $ olcReplicationInterval $ "
1020 "olcReplogFile $ olcRequires $ olcRestrict $ olcRootDN $ olcRootPW $ "
1021 "olcSchemaDN $ olcSecurity $ olcSizeLimit $ olcSyncUseSubentry $ olcSyncrepl $ "
1022 "olcTimeLimit $ olcUpdateDN $ olcUpdateRef $ olcMultiProvider $ "
1023 "olcMonitoring $ olcExtraAttrs ) )",
1024 Cft_Database, NULL, cfAddDatabase },
1025 { "( OLcfgGlOc:5 "
1026 "NAME 'olcOverlayConfig' "
1027 "DESC 'OpenLDAP Overlay-specific options' "
1028 "SUP olcConfig STRUCTURAL "
1029 "MUST olcOverlay "
1030 "MAY olcDisabled )", Cft_Overlay, NULL, cfAddOverlay },
1031 { "( OLcfgGlOc:6 "
1032 "NAME 'olcIncludeFile' "
1033 "DESC 'OpenLDAP configuration include file' "
1034 "SUP olcConfig STRUCTURAL "
1035 "MUST olcInclude "
1036 "MAY ( cn $ olcRootDSE ) )",
1037 /* Used to be Cft_Include, that def has been removed */
1038 Cft_Abstract, NULL, cfAddInclude },
1039 /* This should be STRUCTURAL like all the other database classes, but
1040 * that would mean inheriting all of the olcDatabaseConfig attributes,
1041 * which causes them to be merged twice in config_build_entry.
1042 */
1043 { "( OLcfgGlOc:7 "
1044 "NAME 'olcFrontendConfig' "
1045 "DESC 'OpenLDAP frontend configuration' "
1046 "AUXILIARY "
1047 "MAY ( olcDefaultSearchBase $ olcPasswordHash $ olcSortVals ) )",
1048 Cft_Database, NULL, NULL },
1049 #ifdef SLAPD_MODULES
1050 { "( OLcfgGlOc:8 "
1051 "NAME 'olcModuleList' "
1052 "DESC 'OpenLDAP dynamic module info' "
1053 "SUP olcConfig STRUCTURAL "
1054 "MAY ( cn $ olcModulePath $ olcModuleLoad ) )",
1055 Cft_Module, NULL, cfAddModule },
1056 #endif
1057 { NULL, 0, NULL }
1058 };
1059
1060 typedef struct ServerID {
1061 struct ServerID *si_next;
1062 struct berval si_url;
1063 int si_num;
1064 } ServerID;
1065
1066 static ServerID *sid_list;
1067 static ServerID *sid_set;
1068
1069 typedef struct voidList {
1070 struct voidList *vl_next;
1071 void *vl_ptr;
1072 } voidList;
1073
1074 typedef struct ADlist {
1075 struct ADlist *al_next;
1076 AttributeDescription *al_desc;
1077 } ADlist;
1078
1079 static ADlist *sortVals;
1080
1081 static int new_daemon_threads;
1082
1083 static int
config_resize_lthreads(ConfigArgs * c)1084 config_resize_lthreads(ConfigArgs *c)
1085 {
1086 return slapd_daemon_resize( new_daemon_threads );
1087 }
1088
1089 #define GOT_CONFIG 1
1090 #define GOT_FRONTEND 2
1091 static int
1092 config_unique_db;
1093
1094 static int
config_generic(ConfigArgs * c)1095 config_generic(ConfigArgs *c) {
1096 int i;
1097
1098 if ( c->op == SLAP_CONFIG_EMIT ) {
1099 int rc = 0;
1100 switch(c->type) {
1101 case CFG_CONCUR:
1102 c->value_int = ldap_pvt_thread_get_concurrency();
1103 break;
1104 case CFG_THREADS:
1105 c->value_int = connection_pool_max;
1106 break;
1107 case CFG_THREADQS:
1108 c->value_int = connection_pool_queues;
1109 break;
1110 case CFG_TTHREADS:
1111 c->value_int = slap_tool_thread_max;
1112 break;
1113 case CFG_LTHREADS:
1114 c->value_uint = slapd_daemon_threads;
1115 break;
1116 case CFG_SALT:
1117 if ( passwd_salt )
1118 c->value_string = ch_strdup( passwd_salt );
1119 else
1120 rc = 1;
1121 break;
1122 case CFG_LIMITS:
1123 if ( c->be->be_limits ) {
1124 char buf[4096*3];
1125 struct berval bv;
1126
1127 for ( i=0; c->be->be_limits[i]; i++ ) {
1128 bv.bv_len = snprintf( buf, sizeof( buf ), SLAP_X_ORDERED_FMT, i );
1129 if ( bv.bv_len >= sizeof( buf ) ) {
1130 ber_bvarray_free_x( c->rvalue_vals, NULL );
1131 c->rvalue_vals = NULL;
1132 rc = 1;
1133 break;
1134 }
1135 bv.bv_val = buf + bv.bv_len;
1136 limits_unparse( c->be->be_limits[i], &bv,
1137 sizeof( buf ) - ( bv.bv_val - buf ) );
1138 bv.bv_len += bv.bv_val - buf;
1139 bv.bv_val = buf;
1140 value_add_one( &c->rvalue_vals, &bv );
1141 }
1142 }
1143 if ( !c->rvalue_vals ) rc = 1;
1144 break;
1145 case CFG_RO:
1146 c->value_int = (c->be->be_restrictops & SLAP_RESTRICT_READONLY);
1147 break;
1148 case CFG_AZPOLICY:
1149 c->value_string = ch_strdup( slap_sasl_getpolicy());
1150 break;
1151 case CFG_AZREGEXP:
1152 slap_sasl_regexp_unparse( &c->rvalue_vals );
1153 if ( !c->rvalue_vals ) rc = 1;
1154 break;
1155 #ifdef HAVE_CYRUS_SASL
1156 #ifdef SLAP_AUXPROP_DONTUSECOPY
1157 case CFG_AZDUC: {
1158 static int duc_done = 0;
1159
1160 /* take the opportunity to initialize with known values */
1161 if ( !duc_done ) {
1162 struct berval duc[] = { BER_BVC("cmusaslsecretOTP"), BER_BVNULL };
1163 int i;
1164
1165 for ( i = 0; !BER_BVISNULL( &duc[ i ] ); i++ ) {
1166 const char *text = NULL;
1167 AttributeDescription *ad = NULL;
1168
1169 if ( slap_bv2ad( &duc[ i ], &ad, &text ) == LDAP_SUCCESS ) {
1170 int gotit = 0;
1171 if ( slap_dontUseCopy_propnames ) {
1172 int j;
1173
1174 for ( j = 0; !BER_BVISNULL( &slap_dontUseCopy_propnames[ j ] ); j++ ) {
1175 if ( bvmatch( &slap_dontUseCopy_propnames[ j ], &ad->ad_cname ) ) {
1176 gotit = 1;
1177 }
1178 }
1179 }
1180
1181 if ( !gotit ) {
1182 value_add_one( &slap_dontUseCopy_propnames, &ad->ad_cname );
1183 }
1184 }
1185 }
1186
1187 duc_done = 1;
1188 }
1189
1190 if ( slap_dontUseCopy_propnames != NULL ) {
1191 ber_bvarray_dup_x( &c->rvalue_vals, slap_dontUseCopy_propnames, NULL );
1192 } else {
1193 rc = 1;
1194 }
1195 } break;
1196 #endif /* SLAP_AUXPROP_DONTUSECOPY */
1197 case CFG_SASLSECP: {
1198 struct berval bv = BER_BVNULL;
1199 slap_sasl_secprops_unparse( &bv );
1200 if ( !BER_BVISNULL( &bv )) {
1201 ber_bvarray_add( &c->rvalue_vals, &bv );
1202 } else {
1203 rc = 1;
1204 }
1205 }
1206 break;
1207 #endif
1208 case CFG_DEPTH:
1209 c->value_int = c->be->be_max_deref_depth;
1210 break;
1211 case CFG_DISABLED:
1212 if ( c->bi ) {
1213 /* overlay */
1214 if ( c->bi->bi_flags & SLAPO_BFLAG_DISABLED ) {
1215 c->value_int = 1;
1216 } else {
1217 rc = 1;
1218 }
1219 } else {
1220 /* database */
1221 if ( SLAP_DBDISABLED( c->be )) {
1222 c->value_int = 1;
1223 } else {
1224 rc = 1;
1225 }
1226 }
1227 break;
1228 case CFG_HIDDEN:
1229 if ( SLAP_DBHIDDEN( c->be )) {
1230 c->value_int = 1;
1231 } else {
1232 rc = 1;
1233 }
1234 break;
1235 case CFG_OID: {
1236 ConfigFile *cf = c->ca_private;
1237 if ( !cf )
1238 oidm_unparse( &c->rvalue_vals, NULL, NULL, 1 );
1239 else if ( cf->c_om_head )
1240 oidm_unparse( &c->rvalue_vals, cf->c_om_head,
1241 cf->c_om_tail, 0 );
1242 if ( !c->rvalue_vals )
1243 rc = 1;
1244 }
1245 break;
1246 case CFG_ATOPT:
1247 ad_unparse_options( &c->rvalue_vals );
1248 break;
1249 case CFG_OC: {
1250 ConfigFile *cf = c->ca_private;
1251 if ( !cf )
1252 oc_unparse( &c->rvalue_vals, NULL, NULL, 1 );
1253 else if ( cf->c_oc_head )
1254 oc_unparse( &c->rvalue_vals, cf->c_oc_head,
1255 cf->c_oc_tail, 0 );
1256 if ( !c->rvalue_vals )
1257 rc = 1;
1258 }
1259 break;
1260 case CFG_ATTR: {
1261 ConfigFile *cf = c->ca_private;
1262 if ( !cf )
1263 at_unparse( &c->rvalue_vals, NULL, NULL, 1 );
1264 else if ( cf->c_at_head )
1265 at_unparse( &c->rvalue_vals, cf->c_at_head,
1266 cf->c_at_tail, 0 );
1267 if ( !c->rvalue_vals )
1268 rc = 1;
1269 }
1270 break;
1271 case CFG_SYNTAX: {
1272 ConfigFile *cf = c->ca_private;
1273 if ( !cf )
1274 syn_unparse( &c->rvalue_vals, NULL, NULL, 1 );
1275 else if ( cf->c_syn_head )
1276 syn_unparse( &c->rvalue_vals, cf->c_syn_head,
1277 cf->c_syn_tail, 0 );
1278 if ( !c->rvalue_vals )
1279 rc = 1;
1280 }
1281 break;
1282 case CFG_DIT: {
1283 ConfigFile *cf = c->ca_private;
1284 if ( !cf )
1285 cr_unparse( &c->rvalue_vals, NULL, NULL, 1 );
1286 else if ( cf->c_cr_head )
1287 cr_unparse( &c->rvalue_vals, cf->c_cr_head,
1288 cf->c_cr_tail, 0 );
1289 if ( !c->rvalue_vals )
1290 rc = 1;
1291 }
1292 break;
1293
1294 case CFG_ACL: {
1295 AccessControl *a;
1296 char *src, *dst, ibuf[11];
1297 struct berval bv, abv;
1298 for (i=0, a=c->be->be_acl; a; i++,a=a->acl_next) {
1299 abv.bv_len = snprintf( ibuf, sizeof( ibuf ), SLAP_X_ORDERED_FMT, i );
1300 if ( abv.bv_len >= sizeof( ibuf ) ) {
1301 ber_bvarray_free_x( c->rvalue_vals, NULL );
1302 c->rvalue_vals = NULL;
1303 i = 0;
1304 break;
1305 }
1306 acl_unparse( a, &bv );
1307 abv.bv_val = ch_malloc( abv.bv_len + bv.bv_len + 1 );
1308 AC_MEMCPY( abv.bv_val, ibuf, abv.bv_len );
1309 /* Turn TAB / EOL into plain space */
1310 for (src=bv.bv_val,dst=abv.bv_val+abv.bv_len; *src; src++) {
1311 if (isspace((unsigned char)*src)) *dst++ = ' ';
1312 else *dst++ = *src;
1313 }
1314 *dst = '\0';
1315 if (dst[-1] == ' ') {
1316 dst--;
1317 *dst = '\0';
1318 }
1319 abv.bv_len = dst - abv.bv_val;
1320 ber_bvarray_add( &c->rvalue_vals, &abv );
1321 }
1322 rc = (!i);
1323 break;
1324 }
1325 case CFG_ACL_ADD:
1326 c->value_int = (SLAP_DBACL_ADD(c->be) != 0);
1327 break;
1328 case CFG_ROOTDSE: {
1329 ConfigFile *cf = c->ca_private;
1330 if ( cf->c_dseFiles ) {
1331 value_add( &c->rvalue_vals, cf->c_dseFiles );
1332 } else {
1333 rc = 1;
1334 }
1335 }
1336 break;
1337 case CFG_SERVERID:
1338 if ( sid_list ) {
1339 ServerID *si;
1340 struct berval bv;
1341
1342 for ( si = sid_list; si; si=si->si_next ) {
1343 assert( si->si_num >= 0 && si->si_num <= SLAP_SYNC_SID_MAX );
1344 if ( !BER_BVISEMPTY( &si->si_url )) {
1345 bv.bv_len = si->si_url.bv_len + 6;
1346 bv.bv_val = ch_malloc( bv.bv_len );
1347 bv.bv_len = sprintf( bv.bv_val, "%d %s", si->si_num,
1348 si->si_url.bv_val );
1349 ber_bvarray_add( &c->rvalue_vals, &bv );
1350 } else {
1351 char buf[5];
1352 bv.bv_val = buf;
1353 bv.bv_len = sprintf( buf, "%d", si->si_num );
1354 value_add_one( &c->rvalue_vals, &bv );
1355 }
1356 }
1357 } else {
1358 rc = 1;
1359 }
1360 break;
1361 case CFG_LOGFILE:
1362 if ( logfileName )
1363 c->value_string = ch_strdup( logfileName );
1364 else
1365 rc = 1;
1366 break;
1367 case CFG_LASTMOD:
1368 c->value_int = (SLAP_NOLASTMOD(c->be) == 0);
1369 break;
1370 case CFG_LASTBIND:
1371 c->value_int = (SLAP_NOLASTMOD(c->be) == 0);
1372 break;
1373 case CFG_SYNC_SUBENTRY:
1374 c->value_int = (SLAP_SYNC_SUBENTRY(c->be) != 0);
1375 break;
1376 case CFG_MULTIPROVIDER:
1377 if ( SLAP_SHADOW(c->be))
1378 c->value_int = (SLAP_MULTIPROVIDER(c->be) != 0);
1379 else
1380 rc = 1;
1381 break;
1382 case CFG_MONITORING:
1383 c->value_int = (SLAP_DBMONITORING(c->be) != 0);
1384 break;
1385 case CFG_SSTR_IF_MAX:
1386 c->value_uint = index_substr_if_maxlen;
1387 break;
1388 case CFG_SSTR_IF_MIN:
1389 c->value_uint = index_substr_if_minlen;
1390 break;
1391 case CFG_IX_HASH64:
1392 c->value_int = slap_hash64( -1 );
1393 break;
1394 case CFG_IX_INTLEN:
1395 c->value_int = index_intlen;
1396 break;
1397 case CFG_SORTVALS: {
1398 ADlist *sv;
1399 rc = 1;
1400 for ( sv = sortVals; sv; sv = sv->al_next ) {
1401 value_add_one( &c->rvalue_vals, &sv->al_desc->ad_cname );
1402 rc = 0;
1403 }
1404 } break;
1405 #ifdef SLAPD_MODULES
1406 case CFG_MODLOAD: {
1407 ModPaths *mp = c->ca_private;
1408 if (mp->mp_loads) {
1409 int i;
1410 for (i=0; !BER_BVISNULL(&mp->mp_loads[i]); i++) {
1411 struct berval bv;
1412 bv.bv_val = c->log;
1413 bv.bv_len = snprintf( bv.bv_val, sizeof( c->log ),
1414 SLAP_X_ORDERED_FMT "%s", i,
1415 mp->mp_loads[i].bv_val );
1416 if ( bv.bv_len >= sizeof( c->log ) ) {
1417 ber_bvarray_free_x( c->rvalue_vals, NULL );
1418 c->rvalue_vals = NULL;
1419 break;
1420 }
1421 value_add_one( &c->rvalue_vals, &bv );
1422 }
1423 }
1424
1425 rc = c->rvalue_vals ? 0 : 1;
1426 }
1427 break;
1428 case CFG_MODPATH: {
1429 ModPaths *mp = c->ca_private;
1430 if ( !BER_BVISNULL( &mp->mp_path ))
1431 value_add_one( &c->rvalue_vals, &mp->mp_path );
1432
1433 rc = c->rvalue_vals ? 0 : 1;
1434 }
1435 break;
1436 #endif
1437 #ifdef LDAP_SLAPI
1438 case CFG_PLUGIN:
1439 slapi_int_plugin_unparse( c->be, &c->rvalue_vals );
1440 if ( !c->rvalue_vals ) rc = 1;
1441 break;
1442 #endif
1443 case CFG_REWRITE:
1444 rc = slap_sasl_rewrite_unparse( &c->rvalue_vals );
1445 break;
1446 default:
1447 rc = 1;
1448 }
1449 return rc;
1450 } else if ( c->op == LDAP_MOD_DELETE ) {
1451 int rc = 0;
1452 switch(c->type) {
1453 /* single-valued attrs */
1454 case CFG_CONCUR:
1455 /* FIXME: There is currently no way to retrieve the default? */
1456 break;
1457
1458 case CFG_THREADS:
1459 if ( slapMode & SLAP_SERVER_MODE )
1460 ldap_pvt_thread_pool_maxthreads(&connection_pool,
1461 SLAP_MAX_WORKER_THREADS);
1462 connection_pool_max = SLAP_MAX_WORKER_THREADS; /* save for reference */
1463 break;
1464
1465 case CFG_THREADQS:
1466 if ( slapMode & SLAP_SERVER_MODE )
1467 ldap_pvt_thread_pool_queues(&connection_pool, 1);
1468 connection_pool_queues = 1; /* save for reference */
1469 break;
1470
1471 case CFG_TTHREADS:
1472 slap_tool_thread_max = 1;
1473 break;
1474
1475 case CFG_LTHREADS:
1476 new_daemon_threads = 1;
1477 config_push_cleanup( c, config_resize_lthreads );
1478 break;
1479
1480 case CFG_AZPOLICY:
1481 slap_sasl_setpolicy( "none" );
1482 break;
1483
1484 case CFG_DEPTH:
1485 c->be->be_max_deref_depth = SLAPD_DEFAULT_MAXDEREFDEPTH;
1486 break;
1487
1488 case CFG_LASTMOD:
1489 SLAP_DBFLAGS(c->be) &= ~SLAP_DBFLAG_NOLASTMOD;
1490 break;
1491
1492 case CFG_LASTBIND:
1493 SLAP_DBFLAGS(c->be) &= ~SLAP_DBFLAG_LASTBIND;
1494 break;
1495
1496 case CFG_MONITORING:
1497 SLAP_DBFLAGS(c->be) &= ~SLAP_DBFLAG_MONITORING;
1498 break;
1499
1500 case CFG_SASLSECP:
1501 #ifdef HAVE_CYRUS_SASL
1502 slap_sasl_secprops( "" );
1503 #endif
1504 break;
1505
1506 case CFG_SSTR_IF_MAX:
1507 index_substr_if_maxlen = SLAP_INDEX_SUBSTR_IF_MAXLEN_DEFAULT;
1508 break;
1509
1510 case CFG_SSTR_IF_MIN:
1511 index_substr_if_minlen = SLAP_INDEX_SUBSTR_IF_MINLEN_DEFAULT;
1512 break;
1513
1514 case CFG_ACL_ADD:
1515 SLAP_DBFLAGS(c->be) &= ~SLAP_DBFLAG_ACL_ADD;
1516 break;
1517
1518 case CFG_SYNC_SUBENTRY:
1519 SLAP_DBFLAGS(c->be) &= ~SLAP_DBFLAG_SYNC_SUBENTRY;
1520 break;
1521
1522 case CFG_RO:
1523 c->be->be_restrictops &= ~SLAP_RESTRICT_READONLY;
1524 break;
1525
1526 #ifdef LDAP_SLAPI
1527 case CFG_PLUGIN:
1528 slapi_int_unregister_plugins(c->be, c->valx);
1529 break;
1530 #endif
1531
1532 /* no-op, requires slapd restart */
1533 case CFG_MODLOAD:
1534 snprintf(c->log, sizeof( c->log ), "change requires slapd restart");
1535 break;
1536
1537 case CFG_MULTIPROVIDER:
1538 SLAP_DBFLAGS(c->be) &= ~SLAP_DBFLAG_MULTI_SHADOW;
1539 if(SLAP_SHADOW(c->be))
1540 SLAP_DBFLAGS(c->be) |= SLAP_DBFLAG_SINGLE_SHADOW;
1541 break;
1542
1543 #if defined(HAVE_CYRUS_SASL) && defined(SLAP_AUXPROP_DONTUSECOPY)
1544 case CFG_AZDUC:
1545 if ( c->valx < 0 ) {
1546 if ( slap_dontUseCopy_propnames != NULL ) {
1547 ber_bvarray_free( slap_dontUseCopy_propnames );
1548 slap_dontUseCopy_propnames = NULL;
1549 }
1550
1551 } else {
1552 int i;
1553
1554 if ( slap_dontUseCopy_propnames == NULL ) {
1555 rc = 1;
1556 break;
1557 }
1558
1559 for ( i = 0; !BER_BVISNULL( &slap_dontUseCopy_propnames[ i ] ) && i < c->valx; i++ );
1560 if ( i < c->valx ) {
1561 rc = 1;
1562 break;
1563 }
1564 ber_memfree( slap_dontUseCopy_propnames[ i ].bv_val );
1565 for ( ; !BER_BVISNULL( &slap_dontUseCopy_propnames[ i + 1 ] ); i++ ) {
1566 slap_dontUseCopy_propnames[ i ] = slap_dontUseCopy_propnames[ i + 1 ];
1567 }
1568 BER_BVZERO( &slap_dontUseCopy_propnames[ i ] );
1569 }
1570 break;
1571 #endif /* SLAP_AUXPROP_DONTUSECOPY */
1572
1573 case CFG_AZREGEXP:
1574 rc = slap_sasl_regexp_delete( c->valx );
1575 break;
1576
1577 case CFG_REWRITE:
1578 rc = slap_sasl_rewrite_delete( c->valx );
1579 break;
1580
1581 case CFG_SALT:
1582 ch_free( passwd_salt );
1583 passwd_salt = NULL;
1584 break;
1585
1586 case CFG_LOGFILE:
1587 ch_free( logfileName );
1588 logfileName = NULL;
1589 if ( logfile ) {
1590 fclose( logfile );
1591 logfile = NULL;
1592 }
1593 break;
1594
1595 case CFG_SERVERID: {
1596 ServerID *si, **sip;
1597
1598 for ( i=0, si = sid_list, sip = &sid_list;
1599 si; si = *sip, i++ ) {
1600 if ( c->valx == -1 || i == c->valx ) {
1601 *sip = si->si_next;
1602 if ( sid_set == si )
1603 sid_set = NULL;
1604 ch_free( si );
1605 if ( c->valx >= 0 )
1606 break;
1607 } else {
1608 sip = &si->si_next;
1609 }
1610 }
1611 }
1612 break;
1613 case CFG_HIDDEN:
1614 c->be->be_flags &= ~SLAP_DBFLAG_HIDDEN;
1615 break;
1616
1617 case CFG_DISABLED:
1618 if ( c->bi ) {
1619 c->bi->bi_flags &= ~SLAP_DBFLAG_DISABLED;
1620 if ( c->bi->bi_db_open ) {
1621 BackendInfo *bi_orig = c->be->bd_info;
1622 c->be->bd_info = c->bi;
1623 rc = c->bi->bi_db_open( c->be, &c->reply );
1624 c->be->bd_info = bi_orig;
1625 }
1626 } else {
1627 c->be->be_flags &= ~SLAP_DBFLAG_DISABLED;
1628 rc = backend_startup_one( c->be, &c->reply );
1629 }
1630 break;
1631
1632 case CFG_IX_HASH64:
1633 slap_hash64( 0 );
1634 break;
1635
1636 case CFG_IX_INTLEN:
1637 index_intlen = SLAP_INDEX_INTLEN_DEFAULT;
1638 index_intlen_strlen = SLAP_INDEX_INTLEN_STRLEN(
1639 SLAP_INDEX_INTLEN_DEFAULT );
1640 break;
1641
1642 case CFG_ACL:
1643 if ( c->valx < 0 ) {
1644 acl_destroy( c->be->be_acl );
1645 c->be->be_acl = NULL;
1646
1647 } else {
1648 AccessControl **prev, *a;
1649 int i;
1650 for (i=0, prev = &c->be->be_acl; i < c->valx;
1651 i++ ) {
1652 a = *prev;
1653 prev = &a->acl_next;
1654 }
1655 a = *prev;
1656 *prev = a->acl_next;
1657 acl_free( a );
1658 }
1659 if ( SLAP_CONFIG( c->be ) && !c->be->be_acl ) {
1660 Debug( LDAP_DEBUG_CONFIG, "config_generic (CFG_ACL): "
1661 "Last explicit ACL for back-config removed. "
1662 "Using hardcoded default\n" );
1663 c->be->be_acl = defacl_parsed;
1664 }
1665 break;
1666
1667 case CFG_OC: {
1668 CfEntryInfo *ce;
1669 /* Can be NULL when undoing a failed add */
1670 if ( c->ca_entry ) {
1671 ce = c->ca_entry->e_private;
1672 /* can't modify the hardcoded schema */
1673 if ( ce->ce_parent->ce_type == Cft_Global )
1674 return 1;
1675 }
1676 }
1677 cfn = c->ca_private;
1678 if ( c->valx < 0 ) {
1679 ObjectClass *oc;
1680
1681 for( oc = cfn->c_oc_head; oc; oc_next( &oc )) {
1682 oc_delete( oc );
1683 if ( oc == cfn->c_oc_tail )
1684 break;
1685 }
1686 cfn->c_oc_head = cfn->c_oc_tail = NULL;
1687 } else {
1688 ObjectClass *oc, *prev = NULL;
1689
1690 for ( i=0, oc=cfn->c_oc_head; i<c->valx; i++) {
1691 prev = oc;
1692 oc_next( &oc );
1693 }
1694 oc_delete( oc );
1695 if ( cfn->c_oc_tail == oc ) {
1696 cfn->c_oc_tail = prev;
1697 }
1698 if ( cfn->c_oc_head == oc ) {
1699 oc_next( &oc );
1700 cfn->c_oc_head = oc;
1701 }
1702 }
1703 break;
1704
1705 case CFG_ATTR: {
1706 CfEntryInfo *ce;
1707 /* Can be NULL when undoing a failed add */
1708 if ( c->ca_entry ) {
1709 ce = c->ca_entry->e_private;
1710 /* can't modify the hardcoded schema */
1711 if ( ce->ce_parent->ce_type == Cft_Global )
1712 return 1;
1713 }
1714 }
1715 cfn = c->ca_private;
1716 if ( c->valx < 0 ) {
1717 AttributeType *at;
1718
1719 for( at = cfn->c_at_head; at; at_next( &at )) {
1720 at_delete( at );
1721 if ( at == cfn->c_at_tail )
1722 break;
1723 }
1724 cfn->c_at_head = cfn->c_at_tail = NULL;
1725 } else {
1726 AttributeType *at, *prev = NULL;
1727
1728 for ( i=0, at=cfn->c_at_head; i<c->valx; i++) {
1729 prev = at;
1730 at_next( &at );
1731 }
1732 at_delete( at );
1733 if ( cfn->c_at_tail == at ) {
1734 cfn->c_at_tail = prev;
1735 }
1736 if ( cfn->c_at_head == at ) {
1737 at_next( &at );
1738 cfn->c_at_head = at;
1739 }
1740 }
1741 break;
1742
1743 case CFG_SYNTAX: {
1744 CfEntryInfo *ce;
1745 /* Can be NULL when undoing a failed add */
1746 if ( c->ca_entry ) {
1747 ce = c->ca_entry->e_private;
1748 /* can't modify the hardcoded schema */
1749 if ( ce->ce_parent->ce_type == Cft_Global )
1750 return 1;
1751 }
1752 }
1753 cfn = c->ca_private;
1754 if ( c->valx < 0 ) {
1755 Syntax *syn;
1756
1757 for( syn = cfn->c_syn_head; syn; syn_next( &syn )) {
1758 syn_delete( syn );
1759 if ( syn == cfn->c_syn_tail )
1760 break;
1761 }
1762 cfn->c_syn_head = cfn->c_syn_tail = NULL;
1763 } else {
1764 Syntax *syn, *prev = NULL;
1765
1766 for ( i = 0, syn = cfn->c_syn_head; i < c->valx; i++) {
1767 prev = syn;
1768 syn_next( &syn );
1769 }
1770 syn_delete( syn );
1771 if ( cfn->c_syn_tail == syn ) {
1772 cfn->c_syn_tail = prev;
1773 }
1774 if ( cfn->c_syn_head == syn ) {
1775 syn_next( &syn );
1776 cfn->c_syn_head = syn;
1777 }
1778 }
1779 break;
1780 case CFG_SORTVALS:
1781 if ( c->valx < 0 ) {
1782 ADlist *sv;
1783 for ( sv = sortVals; sv; sv = sortVals ) {
1784 sortVals = sv->al_next;
1785 sv->al_desc->ad_type->sat_flags &= ~SLAP_AT_SORTED_VAL;
1786 ch_free( sv );
1787 }
1788 } else {
1789 ADlist *sv, **prev;
1790 int i = 0;
1791
1792 for ( prev = &sortVals, sv = sortVals; i < c->valx; i++ ) {
1793 prev = &sv->al_next;
1794 sv = sv->al_next;
1795 }
1796 sv->al_desc->ad_type->sat_flags &= ~SLAP_AT_SORTED_VAL;
1797 *prev = sv->al_next;
1798 ch_free( sv );
1799 }
1800 break;
1801
1802 case CFG_LIMITS:
1803 /* FIXME: there is no limits_free function */
1804 if ( c->valx < 0 ) {
1805 limits_destroy( c->be->be_limits );
1806 c->be->be_limits = NULL;
1807
1808 } else {
1809 int cnt, num = -1;
1810
1811 if ( c->be->be_limits ) {
1812 for ( num = 0; c->be->be_limits[ num ]; num++ )
1813 /* just count */ ;
1814 }
1815
1816 if ( c->valx >= num ) {
1817 return 1;
1818 }
1819
1820 if ( num == 1 ) {
1821 limits_destroy( c->be->be_limits );
1822 c->be->be_limits = NULL;
1823
1824 } else {
1825 limits_free_one( c->be->be_limits[ c->valx ] );
1826
1827 for ( cnt = c->valx; cnt < num; cnt++ ) {
1828 c->be->be_limits[ cnt ] = c->be->be_limits[ cnt + 1 ];
1829 }
1830 }
1831 }
1832 break;
1833
1834 case CFG_ATOPT:
1835 /* FIXME: there is no ad_option_free function */
1836 case CFG_ROOTDSE:
1837 /* FIXME: there is no way to remove attributes added by
1838 a DSE file */
1839 case CFG_OID:
1840 case CFG_DIT:
1841 case CFG_MODPATH:
1842 default:
1843 rc = 1;
1844 break;
1845 }
1846 return rc;
1847 }
1848
1849 switch(c->type) {
1850 case CFG_BACKEND:
1851 if(!(c->bi = backend_info(c->argv[1]))) {
1852 snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> failed init", c->argv[0] );
1853 Debug(LDAP_DEBUG_ANY, "%s: %s (%s)!\n",
1854 c->log, c->cr_msg, c->argv[1] );
1855 return(1);
1856 }
1857 if ( c->bi->bi_flags & SLAP_BFLAG_STANDALONE ) {
1858 c->bi->bi_nDB++;
1859 nbackends++;
1860 }
1861 c->be = NULL;
1862 break;
1863
1864 case CFG_DATABASE:
1865 c->bi = NULL;
1866 /* NOTE: config is always the first backend!
1867 */
1868 if ( !strcasecmp( c->argv[1], "config" )) {
1869 if (config_unique_db & GOT_CONFIG) {
1870 sprintf( c->cr_msg, "config DB already defined");
1871 return(1);
1872 }
1873 c->be = LDAP_STAILQ_FIRST(&backendDB);
1874 config_unique_db |= GOT_CONFIG;
1875 } else if ( !strcasecmp( c->argv[1], "frontend" )) {
1876 if (config_unique_db & GOT_FRONTEND) {
1877 sprintf( c->cr_msg, "frontend DB already defined");
1878 return(1);
1879 }
1880 c->be = frontendDB;
1881 config_unique_db |= GOT_FRONTEND;
1882 } else {
1883 c->be = backend_db_init(c->argv[1], NULL, c->valx, &c->reply);
1884 if ( !c->be ) {
1885 if ( c->cr_msg[0] == 0 )
1886 snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> failed init", c->argv[0] );
1887 Debug(LDAP_DEBUG_ANY, "%s: %s (%s)\n", c->log, c->cr_msg, c->argv[1] );
1888 return(1);
1889 }
1890 }
1891 break;
1892
1893 case CFG_CONCUR:
1894 ldap_pvt_thread_set_concurrency(c->value_int);
1895 break;
1896
1897 case CFG_THREADS:
1898 if ( c->value_int < 2 ) {
1899 snprintf( c->cr_msg, sizeof( c->cr_msg ),
1900 "threads=%d smaller than minimum value 2",
1901 c->value_int );
1902 Debug(LDAP_DEBUG_ANY, "%s: %s.\n",
1903 c->log, c->cr_msg );
1904 return 1;
1905
1906 } else if ( c->value_int > 2 * SLAP_MAX_WORKER_THREADS ) {
1907 snprintf( c->cr_msg, sizeof( c->cr_msg ),
1908 "warning, threads=%d larger than twice the default (2*%d=%d); YMMV",
1909 c->value_int, SLAP_MAX_WORKER_THREADS, 2 * SLAP_MAX_WORKER_THREADS );
1910 Debug(LDAP_DEBUG_ANY, "%s: %s.\n",
1911 c->log, c->cr_msg );
1912 }
1913 if ( slapMode & SLAP_SERVER_MODE )
1914 ldap_pvt_thread_pool_maxthreads(&connection_pool, c->value_int);
1915 connection_pool_max = c->value_int; /* save for reference */
1916 break;
1917
1918 case CFG_THREADQS:
1919 if ( c->value_int < 1 ) {
1920 snprintf( c->cr_msg, sizeof( c->cr_msg ),
1921 "threadqueues=%d smaller than minimum value 1",
1922 c->value_int );
1923 Debug(LDAP_DEBUG_ANY, "%s: %s.\n",
1924 c->log, c->cr_msg );
1925 return 1;
1926 }
1927 if ( slapMode & SLAP_SERVER_MODE )
1928 ldap_pvt_thread_pool_queues(&connection_pool, c->value_int);
1929 connection_pool_queues = c->value_int; /* save for reference */
1930 break;
1931
1932 case CFG_TTHREADS:
1933 if ( slapMode & SLAP_TOOL_MODE )
1934 ldap_pvt_thread_pool_maxthreads(&connection_pool, c->value_int);
1935 slap_tool_thread_max = c->value_int; /* save for reference */
1936 break;
1937
1938 case CFG_LTHREADS:
1939 if ( c->value_uint < 1 ) {
1940 snprintf( c->cr_msg, sizeof( c->cr_msg ),
1941 "listenerthreads=%u smaller than minimum value 1",
1942 c->value_uint );
1943 Debug(LDAP_DEBUG_ANY, "%s: %s.\n",
1944 c->log, c->cr_msg );
1945 return 1;
1946 }
1947 { int mask = 0;
1948 /* use a power of two */
1949 while (c->value_uint > 1) {
1950 c->value_uint >>= 1;
1951 mask <<= 1;
1952 mask |= 1;
1953 }
1954 new_daemon_threads = mask+1;
1955 config_push_cleanup( c, config_resize_lthreads );
1956 }
1957 break;
1958
1959 case CFG_SALT:
1960 if ( passwd_salt ) ch_free( passwd_salt );
1961 passwd_salt = c->value_string;
1962 lutil_salt_format(passwd_salt);
1963 break;
1964
1965 case CFG_LIMITS:
1966 if(limits_parse(c->be, c->fname, c->lineno, c->argc, c->argv))
1967 return(1);
1968 break;
1969
1970 case CFG_RO:
1971 if(c->value_int)
1972 c->be->be_restrictops |= SLAP_RESTRICT_READONLY;
1973 else
1974 c->be->be_restrictops &= ~SLAP_RESTRICT_READONLY;
1975 break;
1976
1977 case CFG_AZPOLICY:
1978 ch_free(c->value_string);
1979 if (slap_sasl_setpolicy( c->argv[1] )) {
1980 snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> unable to parse value", c->argv[0] );
1981 Debug(LDAP_DEBUG_ANY, "%s: %s \"%s\"\n",
1982 c->log, c->cr_msg, c->argv[1] );
1983 return(1);
1984 }
1985 break;
1986
1987 case CFG_AZREGEXP:
1988 if (slap_sasl_regexp_config( c->argv[1], c->argv[2], c->valx ))
1989 return(1);
1990 break;
1991
1992 #ifdef HAVE_CYRUS_SASL
1993 #ifdef SLAP_AUXPROP_DONTUSECOPY
1994 case CFG_AZDUC: {
1995 int arg, cnt;
1996
1997 for ( arg = 1; arg < c->argc; arg++ ) {
1998 int duplicate = 0, err;
1999 AttributeDescription *ad = NULL;
2000 const char *text = NULL;
2001
2002 err = slap_str2ad( c->argv[ arg ], &ad, &text );
2003 if ( err != LDAP_SUCCESS ) {
2004 snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s>: attr #%d (\"%s\") unknown (err=%d \"%s\"; ignored)",
2005 c->argv[0], arg, c->argv[ arg ], err, text );
2006 Debug(LDAP_DEBUG_ANY, "%s: %s\n",
2007 c->log, c->cr_msg );
2008
2009 } else {
2010 if ( slap_dontUseCopy_propnames != NULL ) {
2011 for ( cnt = 0; !BER_BVISNULL( &slap_dontUseCopy_propnames[ cnt ] ); cnt++ ) {
2012 if ( bvmatch( &slap_dontUseCopy_propnames[ cnt ], &ad->ad_cname ) ) {
2013 duplicate = 1;
2014 break;
2015 }
2016 }
2017 }
2018
2019 if ( duplicate ) {
2020 snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s>: attr #%d (\"%s\") already defined (ignored)",
2021 c->argv[0], arg, ad->ad_cname.bv_val);
2022 Debug(LDAP_DEBUG_ANY, "%s: %s\n",
2023 c->log, c->cr_msg );
2024 continue;
2025 }
2026
2027 value_add_one( &slap_dontUseCopy_propnames, &ad->ad_cname );
2028 }
2029 }
2030
2031 } break;
2032 #endif /* SLAP_AUXPROP_DONTUSECOPY */
2033
2034 case CFG_SASLSECP:
2035 {
2036 char *txt = slap_sasl_secprops( c->argv[1] );
2037 if ( txt ) {
2038 snprintf( c->cr_msg, sizeof(c->cr_msg), "<%s> %s",
2039 c->argv[0], txt );
2040 Debug(LDAP_DEBUG_ANY, "%s: %s\n", c->log, c->cr_msg );
2041 return(1);
2042 }
2043 break;
2044 }
2045 #endif
2046
2047 case CFG_DEPTH:
2048 c->be->be_max_deref_depth = c->value_int;
2049 break;
2050
2051 case CFG_OID: {
2052 OidMacro *om;
2053
2054 if ( c->op == LDAP_MOD_ADD && c->ca_private && cfn != c->ca_private )
2055 cfn = c->ca_private;
2056 if(parse_oidm(c, 1, &om))
2057 return(1);
2058 if (!cfn->c_om_head) cfn->c_om_head = om;
2059 cfn->c_om_tail = om;
2060 }
2061 break;
2062
2063 case CFG_OC: {
2064 ObjectClass *oc, *prev;
2065
2066 if ( c->op == LDAP_MOD_ADD && c->ca_private && cfn != c->ca_private )
2067 cfn = c->ca_private;
2068 if ( c->valx < 0 ) {
2069 prev = cfn->c_oc_tail;
2070 } else {
2071 prev = NULL;
2072 /* If adding anything after the first, prev is easy */
2073 if ( c->valx ) {
2074 int i;
2075 for (i=0, oc = cfn->c_oc_head; i<c->valx; i++) {
2076 prev = oc;
2077 if ( !oc_next( &oc ))
2078 break;
2079 }
2080 } else
2081 /* If adding the first, and head exists, find its prev */
2082 if (cfn->c_oc_head) {
2083 for ( oc_start( &oc ); oc != cfn->c_oc_head; ) {
2084 prev = oc;
2085 oc_next( &oc );
2086 }
2087 }
2088 /* else prev is NULL, append to end of global list */
2089 }
2090 if(parse_oc(c, &oc, prev)) return(1);
2091 if (!cfn->c_oc_head || !c->valx) cfn->c_oc_head = oc;
2092 if (cfn->c_oc_tail == prev) cfn->c_oc_tail = oc;
2093 }
2094 break;
2095
2096 case CFG_ATTR: {
2097 AttributeType *at, *prev;
2098
2099 if ( c->op == LDAP_MOD_ADD && c->ca_private && cfn != c->ca_private )
2100 cfn = c->ca_private;
2101 if ( c->valx < 0 ) {
2102 prev = cfn->c_at_tail;
2103 } else {
2104 prev = NULL;
2105 /* If adding anything after the first, prev is easy */
2106 if ( c->valx ) {
2107 int i;
2108 for (i=0, at = cfn->c_at_head; i<c->valx; i++) {
2109 prev = at;
2110 if ( !at_next( &at ))
2111 break;
2112 }
2113 } else
2114 /* If adding the first, and head exists, find its prev */
2115 if (cfn->c_at_head) {
2116 for ( at_start( &at ); at != cfn->c_at_head; ) {
2117 prev = at;
2118 at_next( &at );
2119 }
2120 }
2121 /* else prev is NULL, append to end of global list */
2122 }
2123 if(parse_at(c, &at, prev)) return(1);
2124 if (!cfn->c_at_head || !c->valx) cfn->c_at_head = at;
2125 if (cfn->c_at_tail == prev) cfn->c_at_tail = at;
2126 }
2127 break;
2128
2129 case CFG_SYNTAX: {
2130 Syntax *syn, *prev;
2131
2132 if ( c->op == LDAP_MOD_ADD && c->ca_private && cfn != c->ca_private )
2133 cfn = c->ca_private;
2134 if ( c->valx < 0 ) {
2135 prev = cfn->c_syn_tail;
2136 } else {
2137 prev = NULL;
2138 /* If adding anything after the first, prev is easy */
2139 if ( c->valx ) {
2140 int i;
2141 for ( i = 0, syn = cfn->c_syn_head; i < c->valx; i++ ) {
2142 prev = syn;
2143 if ( !syn_next( &syn ))
2144 break;
2145 }
2146 } else
2147 /* If adding the first, and head exists, find its prev */
2148 if (cfn->c_syn_head) {
2149 for ( syn_start( &syn ); syn != cfn->c_syn_head; ) {
2150 prev = syn;
2151 syn_next( &syn );
2152 }
2153 }
2154 /* else prev is NULL, append to end of global list */
2155 }
2156 if ( parse_syn( c, &syn, prev ) ) return(1);
2157 if ( !cfn->c_syn_head || !c->valx ) cfn->c_syn_head = syn;
2158 if ( cfn->c_syn_tail == prev ) cfn->c_syn_tail = syn;
2159 }
2160 break;
2161
2162 case CFG_DIT: {
2163 ContentRule *cr;
2164
2165 if ( c->op == LDAP_MOD_ADD && c->ca_private && cfn != c->ca_private )
2166 cfn = c->ca_private;
2167 if(parse_cr(c, &cr)) return(1);
2168 if (!cfn->c_cr_head) cfn->c_cr_head = cr;
2169 cfn->c_cr_tail = cr;
2170 }
2171 break;
2172
2173 case CFG_ATOPT:
2174 ad_define_option(NULL, NULL, 0);
2175 for(i = 1; i < c->argc; i++)
2176 if(ad_define_option(c->argv[i], c->fname, c->lineno))
2177 return(1);
2178 break;
2179
2180 case CFG_IX_HASH64:
2181 if ( slap_hash64( c->value_int != 0 ))
2182 return 1;
2183 break;
2184
2185 case CFG_IX_INTLEN:
2186 if ( c->value_int < SLAP_INDEX_INTLEN_DEFAULT )
2187 c->value_int = SLAP_INDEX_INTLEN_DEFAULT;
2188 else if ( c->value_int > 255 )
2189 c->value_int = 255;
2190 index_intlen = c->value_int;
2191 index_intlen_strlen = SLAP_INDEX_INTLEN_STRLEN(
2192 index_intlen );
2193 break;
2194
2195 case CFG_SORTVALS: {
2196 ADlist *svnew = NULL, *svtail, *sv;
2197
2198 for ( i = 1; i < c->argc; i++ ) {
2199 AttributeDescription *ad = NULL;
2200 const char *text;
2201 int rc;
2202
2203 rc = slap_str2ad( c->argv[i], &ad, &text );
2204 if ( rc ) {
2205 snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> unknown attribute type #%d",
2206 c->argv[0], i );
2207 sortval_reject:
2208 Debug(LDAP_DEBUG_ANY, "%s: %s %s\n",
2209 c->log, c->cr_msg, c->argv[i] );
2210 for ( sv = svnew; sv; sv = svnew ) {
2211 svnew = sv->al_next;
2212 ch_free( sv );
2213 }
2214 return 1;
2215 }
2216 if (( ad->ad_type->sat_flags & SLAP_AT_ORDERED ) ||
2217 ad->ad_type->sat_single_value ) {
2218 snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> inappropriate attribute type #%d",
2219 c->argv[0], i );
2220 goto sortval_reject;
2221 }
2222 sv = ch_malloc( sizeof( ADlist ));
2223 sv->al_desc = ad;
2224 if ( !svnew ) {
2225 svnew = sv;
2226 } else {
2227 svtail->al_next = sv;
2228 }
2229 svtail = sv;
2230 }
2231 sv->al_next = NULL;
2232 for ( sv = svnew; sv; sv = sv->al_next )
2233 sv->al_desc->ad_type->sat_flags |= SLAP_AT_SORTED_VAL;
2234 for ( sv = sortVals; sv && sv->al_next; sv = sv->al_next );
2235 if ( sv )
2236 sv->al_next = svnew;
2237 else
2238 sortVals = svnew;
2239 }
2240 break;
2241
2242 case CFG_ACL:
2243 if ( SLAP_CONFIG( c->be ) && c->be->be_acl == defacl_parsed) {
2244 c->be->be_acl = NULL;
2245 }
2246 /* Don't append to the global ACL if we're on a specific DB */
2247 i = c->valx;
2248 if ( c->valx == -1 ) {
2249 AccessControl *a;
2250 i = 0;
2251 for ( a=c->be->be_acl; a; a = a->acl_next )
2252 i++;
2253 }
2254 if ( parse_acl(c->be, c->fname, c->lineno, c->argc, c->argv, i ) ) {
2255 if ( SLAP_CONFIG( c->be ) && !c->be->be_acl) {
2256 c->be->be_acl = defacl_parsed;
2257 }
2258 return 1;
2259 }
2260 break;
2261
2262 case CFG_ACL_ADD:
2263 if(c->value_int)
2264 SLAP_DBFLAGS(c->be) |= SLAP_DBFLAG_ACL_ADD;
2265 else
2266 SLAP_DBFLAGS(c->be) &= ~SLAP_DBFLAG_ACL_ADD;
2267 break;
2268
2269 case CFG_ROOTDSE:
2270 if(root_dse_read_file(c->argv[1])) {
2271 snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> could not read file", c->argv[0] );
2272 Debug(LDAP_DEBUG_ANY, "%s: %s %s\n",
2273 c->log, c->cr_msg, c->argv[1] );
2274 return(1);
2275 }
2276 {
2277 struct berval bv;
2278 ber_str2bv( c->argv[1], 0, 1, &bv );
2279 if ( c->op == LDAP_MOD_ADD && c->ca_private && cfn != c->ca_private )
2280 cfn = c->ca_private;
2281 ber_bvarray_add( &cfn->c_dseFiles, &bv );
2282 }
2283 break;
2284
2285 case CFG_SERVERID:
2286 {
2287 ServerID *si, **sip;
2288 LDAPURLDesc *lud;
2289 int num;
2290 if (( lutil_atoi( &num, c->argv[1] ) &&
2291 lutil_atoix( &num, c->argv[1], 16 )) ||
2292 num < 0 || num > SLAP_SYNC_SID_MAX )
2293 {
2294 snprintf( c->cr_msg, sizeof( c->cr_msg ),
2295 "<%s> illegal server ID", c->argv[0] );
2296 Debug(LDAP_DEBUG_ANY, "%s: %s %s\n",
2297 c->log, c->cr_msg, c->argv[1] );
2298 return 1;
2299 }
2300 /* only one value allowed if no URL is given */
2301 if ( c->argc > 2 ) {
2302 int len;
2303
2304 if ( sid_list && BER_BVISEMPTY( &sid_list->si_url )) {
2305 snprintf( c->cr_msg, sizeof( c->cr_msg ),
2306 "<%s> only one server ID allowed now", c->argv[0] );
2307 Debug(LDAP_DEBUG_ANY, "%s: %s %s\n",
2308 c->log, c->cr_msg, c->argv[1] );
2309 return 1;
2310 }
2311
2312 if ( ldap_url_parse( c->argv[2], &lud )) {
2313 snprintf( c->cr_msg, sizeof( c->cr_msg ),
2314 "<%s> invalid URL", c->argv[0] );
2315 Debug(LDAP_DEBUG_ANY, "%s: %s %s\n",
2316 c->log, c->cr_msg, c->argv[2] );
2317 return 1;
2318 }
2319 len = strlen( c->argv[2] );
2320 si = ch_malloc( sizeof(ServerID) + len + 1 );
2321 si->si_url.bv_val = (char *)(si+1);
2322 si->si_url.bv_len = len;
2323 strcpy( si->si_url.bv_val, c->argv[2] );
2324 } else {
2325 if ( sid_list ) {
2326 snprintf( c->cr_msg, sizeof( c->cr_msg ),
2327 "<%s> unqualified server ID not allowed now", c->argv[0] );
2328 Debug(LDAP_DEBUG_ANY, "%s: %s %s\n",
2329 c->log, c->cr_msg, c->argv[1] );
2330 return 1;
2331 }
2332 si = ch_malloc( sizeof(ServerID) );
2333 BER_BVZERO( &si->si_url );
2334 slap_serverID = num;
2335 Debug( LDAP_DEBUG_CONFIG,
2336 "%s: SID=0x%03x\n",
2337 c->log, slap_serverID );
2338 sid_set = si;
2339 }
2340 si->si_next = NULL;
2341 si->si_num = num;
2342 for ( sip = &sid_list; *sip; sip = &(*sip)->si_next );
2343 *sip = si;
2344
2345 if (( slapMode & SLAP_SERVER_MODE ) && c->argc > 2 ) {
2346 Listener *l = config_check_my_url( c->argv[2], lud );
2347 if ( l ) {
2348 if ( sid_set ) {
2349 ldap_free_urldesc( lud );
2350 snprintf( c->cr_msg, sizeof( c->cr_msg ),
2351 "<%s> multiple server ID URLs matched, only one is allowed", c->argv[0] );
2352 Debug(LDAP_DEBUG_ANY, "%s: %s %s\n",
2353 c->log, c->cr_msg, c->argv[1] );
2354 return 1;
2355 }
2356 slap_serverID = si->si_num;
2357 Debug( LDAP_DEBUG_CONFIG,
2358 "%s: SID=0x%03x (listener=%s)\n",
2359 c->log, slap_serverID,
2360 l->sl_url.bv_val );
2361 sid_set = si;
2362 }
2363 }
2364 if ( c->argc > 2 )
2365 ldap_free_urldesc( lud );
2366 }
2367 break;
2368 case CFG_LOGFILE: {
2369 if ( logfileName ) ch_free( logfileName );
2370 logfileName = c->value_string;
2371 logfile = fopen(logfileName, "w");
2372 if(logfile) lutil_debug_file(logfile);
2373 } break;
2374
2375 case CFG_LASTMOD:
2376 if(SLAP_NOLASTMODCMD(c->be)) {
2377 snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> not available for %s database",
2378 c->argv[0], c->be->bd_info->bi_type );
2379 Debug(LDAP_DEBUG_ANY, "%s: %s\n",
2380 c->log, c->cr_msg );
2381 return(1);
2382 }
2383 if(c->value_int)
2384 SLAP_DBFLAGS(c->be) &= ~SLAP_DBFLAG_NOLASTMOD;
2385 else
2386 SLAP_DBFLAGS(c->be) |= SLAP_DBFLAG_NOLASTMOD;
2387 break;
2388
2389 case CFG_LASTBIND:
2390 if (c->value_int)
2391 SLAP_DBFLAGS(c->be) |= SLAP_DBFLAG_LASTBIND;
2392 else
2393 SLAP_DBFLAGS(c->be) &= ~SLAP_DBFLAG_LASTBIND;
2394 break;
2395
2396 case CFG_MULTIPROVIDER:
2397 if(c->value_int && !SLAP_SHADOW(c->be)) {
2398 snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> database is not a shadow",
2399 c->argv[0] );
2400 Debug(LDAP_DEBUG_ANY, "%s: %s\n",
2401 c->log, c->cr_msg );
2402 return(1);
2403 }
2404 if(c->value_int) {
2405 SLAP_DBFLAGS(c->be) &= ~SLAP_DBFLAG_SINGLE_SHADOW;
2406 SLAP_DBFLAGS(c->be) |= SLAP_DBFLAG_MULTI_SHADOW;
2407 } else {
2408 SLAP_DBFLAGS(c->be) |= SLAP_DBFLAG_SINGLE_SHADOW;
2409 SLAP_DBFLAGS(c->be) &= ~SLAP_DBFLAG_MULTI_SHADOW;
2410 }
2411 break;
2412
2413 case CFG_MONITORING:
2414 if(c->value_int)
2415 SLAP_DBFLAGS(c->be) |= SLAP_DBFLAG_MONITORING;
2416 else
2417 SLAP_DBFLAGS(c->be) &= ~SLAP_DBFLAG_MONITORING;
2418 break;
2419
2420 case CFG_DISABLED:
2421 if ( c->bi ) {
2422 if (c->value_int) {
2423 if ( c->bi->bi_db_close ) {
2424 BackendInfo *bi_orig = c->be->bd_info;
2425 c->be->bd_info = c->bi;
2426 c->bi->bi_db_close( c->be, &c->reply );
2427 c->be->bd_info = bi_orig;
2428 }
2429 c->bi->bi_flags |= SLAPO_BFLAG_DISABLED;
2430 } else {
2431 c->bi->bi_flags &= ~SLAPO_BFLAG_DISABLED;
2432 }
2433 } else {
2434 if (c->value_int) {
2435 backend_shutdown( c->be );
2436 SLAP_DBFLAGS(c->be) |= SLAP_DBFLAG_DISABLED;
2437 } else {
2438 SLAP_DBFLAGS(c->be) &= ~SLAP_DBFLAG_DISABLED;
2439 }
2440 }
2441 break;
2442
2443 case CFG_HIDDEN:
2444 if (c->value_int)
2445 SLAP_DBFLAGS(c->be) |= SLAP_DBFLAG_HIDDEN;
2446 else
2447 SLAP_DBFLAGS(c->be) &= ~SLAP_DBFLAG_HIDDEN;
2448 break;
2449
2450 case CFG_SYNC_SUBENTRY:
2451 if (c->value_int)
2452 SLAP_DBFLAGS(c->be) |= SLAP_DBFLAG_SYNC_SUBENTRY;
2453 else
2454 SLAP_DBFLAGS(c->be) &= ~SLAP_DBFLAG_SYNC_SUBENTRY;
2455 break;
2456
2457 case CFG_SSTR_IF_MAX:
2458 if (c->value_uint < index_substr_if_minlen) {
2459 snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> invalid value", c->argv[0] );
2460 Debug(LDAP_DEBUG_ANY, "%s: %s (%d)\n",
2461 c->log, c->cr_msg, c->value_int );
2462 return(1);
2463 }
2464 index_substr_if_maxlen = c->value_uint;
2465 break;
2466
2467 case CFG_SSTR_IF_MIN:
2468 if (c->value_uint > index_substr_if_maxlen) {
2469 snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> invalid value", c->argv[0] );
2470 Debug(LDAP_DEBUG_ANY, "%s: %s (%d)\n",
2471 c->log, c->cr_msg, c->value_int );
2472 return(1);
2473 }
2474 index_substr_if_minlen = c->value_uint;
2475 break;
2476
2477 #ifdef SLAPD_MODULES
2478 case CFG_MODLOAD:
2479 /* If we're just adding a module on an existing modpath,
2480 * make sure we've selected the current path.
2481 */
2482 if ( c->op == LDAP_MOD_ADD && c->ca_private && modcur != c->ca_private ) {
2483 modcur = c->ca_private;
2484 /* This should never fail */
2485 if ( module_path( modcur->mp_path.bv_val )) {
2486 snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> module path no longer valid",
2487 c->argv[0] );
2488 Debug(LDAP_DEBUG_ANY, "%s: %s (%s)\n",
2489 c->log, c->cr_msg, modcur->mp_path.bv_val );
2490 return(1);
2491 }
2492 }
2493 if(module_load(c->argv[1], c->argc - 2, (c->argc > 2) ? c->argv + 2 : NULL))
2494 return(1);
2495 /* Record this load on the current path */
2496 {
2497 struct berval bv;
2498 char *ptr;
2499 if ( c->op == SLAP_CONFIG_ADD ) {
2500 ptr = c->line + STRLENOF("moduleload");
2501 while (!isspace((unsigned char) *ptr)) ptr++;
2502 while (isspace((unsigned char) *ptr)) ptr++;
2503 } else {
2504 ptr = c->line;
2505 }
2506 ber_str2bv(ptr, 0, 1, &bv);
2507 ber_bvarray_add( &modcur->mp_loads, &bv );
2508 }
2509 /* Check for any new hardcoded schema */
2510 if ( c->op == LDAP_MOD_ADD && CONFIG_ONLINE_ADD( c )) {
2511 config_check_schema( NULL, &cfBackInfo );
2512 }
2513 break;
2514
2515 case CFG_MODPATH:
2516 if(module_path(c->argv[1])) return(1);
2517 /* Record which path was used with each module */
2518 {
2519 ModPaths *mp;
2520
2521 if (!modpaths.mp_loads) {
2522 mp = &modpaths;
2523 } else {
2524 mp = ch_malloc( sizeof( ModPaths ));
2525 modlast->mp_next = mp;
2526 }
2527 ber_str2bv(c->argv[1], 0, 1, &mp->mp_path);
2528 mp->mp_next = NULL;
2529 mp->mp_loads = NULL;
2530 modlast = mp;
2531 c->ca_private = mp;
2532 modcur = mp;
2533 }
2534
2535 break;
2536 #endif
2537
2538 #ifdef LDAP_SLAPI
2539 case CFG_PLUGIN:
2540 if(slapi_int_read_config(c->be, c->fname, c->lineno, c->argc, c->argv, c->valx) != LDAP_SUCCESS)
2541 return(1);
2542 slapi_plugins_used++;
2543 break;
2544 #endif
2545
2546 case CFG_REWRITE: {
2547 int rc;
2548
2549 if ( c->op == LDAP_MOD_ADD ) {
2550 c->argv++;
2551 c->argc--;
2552 }
2553 rc = slap_sasl_rewrite_config(c->fname, c->lineno, c->argc, c->argv, c->valx);
2554 if ( c->op == LDAP_MOD_ADD ) {
2555 c->argv--;
2556 c->argc++;
2557 }
2558 return rc;
2559 }
2560
2561
2562 default:
2563 Debug( LDAP_DEBUG_ANY,
2564 "%s: unknown CFG_TYPE %d.\n",
2565 c->log, c->type );
2566 return 1;
2567
2568 }
2569 return(0);
2570 }
2571
2572
2573 static int
config_fname(ConfigArgs * c)2574 config_fname(ConfigArgs *c) {
2575 if(c->op == SLAP_CONFIG_EMIT) {
2576 if (c->ca_private) {
2577 ConfigFile *cf = c->ca_private;
2578 value_add_one( &c->rvalue_vals, &cf->c_file );
2579 return 0;
2580 }
2581 return 1;
2582 }
2583 return(0);
2584 }
2585
2586 static int
config_cfdir(ConfigArgs * c)2587 config_cfdir(ConfigArgs *c) {
2588 if(c->op == SLAP_CONFIG_EMIT) {
2589 if ( !BER_BVISEMPTY( &cfdir )) {
2590 value_add_one( &c->rvalue_vals, &cfdir );
2591 return 0;
2592 }
2593 return 1;
2594 }
2595 return(0);
2596 }
2597
2598 static int
config_search_base(ConfigArgs * c)2599 config_search_base(ConfigArgs *c) {
2600 if(c->op == SLAP_CONFIG_EMIT) {
2601 int rc = 1;
2602 if (!BER_BVISEMPTY(&default_search_base)) {
2603 value_add_one(&c->rvalue_vals, &default_search_base);
2604 value_add_one(&c->rvalue_nvals, &default_search_nbase);
2605 rc = 0;
2606 }
2607 return rc;
2608 } else if( c->op == LDAP_MOD_DELETE ) {
2609 ch_free( default_search_base.bv_val );
2610 ch_free( default_search_nbase.bv_val );
2611 BER_BVZERO( &default_search_base );
2612 BER_BVZERO( &default_search_nbase );
2613 return 0;
2614 }
2615
2616 if(c->bi || c->be != frontendDB) {
2617 Debug(LDAP_DEBUG_ANY, "%s: defaultSearchBase line must appear "
2618 "prior to any backend or database definition\n",
2619 c->log );
2620 return(1);
2621 }
2622
2623 if(default_search_nbase.bv_len) {
2624 free(default_search_base.bv_val);
2625 free(default_search_nbase.bv_val);
2626 }
2627
2628 default_search_base = c->value_dn;
2629 default_search_nbase = c->value_ndn;
2630 return(0);
2631 }
2632
2633 /* For RE23 compatibility we allow this in the global entry
2634 * but we now defer it to the frontend entry to allow modules
2635 * to load new hash types.
2636 */
2637 static int
config_passwd_hash(ConfigArgs * c)2638 config_passwd_hash(ConfigArgs *c) {
2639 int i;
2640 if (c->op == SLAP_CONFIG_EMIT) {
2641 struct berval bv;
2642 /* Don't generate it in the global entry */
2643 if ( c->table == Cft_Global )
2644 return 1;
2645 for (i=0; default_passwd_hash && default_passwd_hash[i]; i++) {
2646 ber_str2bv(default_passwd_hash[i], 0, 0, &bv);
2647 value_add_one(&c->rvalue_vals, &bv);
2648 }
2649 return i ? 0 : 1;
2650 } else if ( c->op == LDAP_MOD_DELETE ) {
2651 /* Deleting from global is a no-op, only the frontendDB entry matters */
2652 if ( c->table == Cft_Global )
2653 return 0;
2654 if ( c->valx < 0 ) {
2655 ldap_charray_free( default_passwd_hash );
2656 default_passwd_hash = NULL;
2657 } else {
2658 i = c->valx;
2659 ch_free( default_passwd_hash[i] );
2660 for (; default_passwd_hash[i]; i++ )
2661 default_passwd_hash[i] = default_passwd_hash[i+1];
2662 }
2663 return 0;
2664 }
2665 for(i = 1; i < c->argc; i++) {
2666 if(!lutil_passwd_scheme(c->argv[i])) {
2667 snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> scheme not available", c->argv[0] );
2668 Debug(LDAP_DEBUG_ANY, "%s: %s (%s)\n",
2669 c->log, c->cr_msg, c->argv[i]);
2670 } else {
2671 ldap_charray_add(&default_passwd_hash, c->argv[i]);
2672 }
2673 }
2674 if(!default_passwd_hash) {
2675 snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> no valid hashes found", c->argv[0] );
2676 Debug(LDAP_DEBUG_ANY, "%s: %s\n",
2677 c->log, c->cr_msg );
2678 return(1);
2679 }
2680 return(0);
2681 }
2682
2683 static int
config_schema_dn(ConfigArgs * c)2684 config_schema_dn(ConfigArgs *c) {
2685 if ( c->op == SLAP_CONFIG_EMIT ) {
2686 int rc = 1;
2687 if ( !BER_BVISEMPTY( &c->be->be_schemadn )) {
2688 value_add_one(&c->rvalue_vals, &c->be->be_schemadn);
2689 value_add_one(&c->rvalue_nvals, &c->be->be_schemandn);
2690 rc = 0;
2691 }
2692 return rc;
2693 } else if ( c->op == LDAP_MOD_DELETE ) {
2694 ch_free( c->be->be_schemadn.bv_val );
2695 ch_free( c->be->be_schemandn.bv_val );
2696 BER_BVZERO( &c->be->be_schemadn );
2697 BER_BVZERO( &c->be->be_schemandn );
2698 return 0;
2699 }
2700 ch_free( c->be->be_schemadn.bv_val );
2701 ch_free( c->be->be_schemandn.bv_val );
2702 c->be->be_schemadn = c->value_dn;
2703 c->be->be_schemandn = c->value_ndn;
2704 return(0);
2705 }
2706
2707 static int
config_sizelimit(ConfigArgs * c)2708 config_sizelimit(ConfigArgs *c) {
2709 int i, rc = 0;
2710 struct slap_limits_set *lim = &c->be->be_def_limit;
2711 if (c->op == SLAP_CONFIG_EMIT) {
2712 char buf[8192];
2713 struct berval bv;
2714 bv.bv_val = buf;
2715 bv.bv_len = 0;
2716 limits_unparse_one( lim, SLAP_LIMIT_SIZE, &bv, sizeof( buf ) );
2717 if ( !BER_BVISEMPTY( &bv ))
2718 value_add_one( &c->rvalue_vals, &bv );
2719 else
2720 rc = 1;
2721 return rc;
2722 } else if ( c->op == LDAP_MOD_DELETE ) {
2723 /* Reset to defaults or values from frontend */
2724 if ( c->be == frontendDB ) {
2725 lim->lms_s_soft = SLAPD_DEFAULT_SIZELIMIT;
2726 lim->lms_s_hard = 0;
2727 lim->lms_s_unchecked = -1;
2728 lim->lms_s_pr = 0;
2729 lim->lms_s_pr_hide = 0;
2730 lim->lms_s_pr_total = 0;
2731 } else {
2732 lim->lms_s_soft = frontendDB->be_def_limit.lms_s_soft;
2733 lim->lms_s_hard = frontendDB->be_def_limit.lms_s_hard;
2734 lim->lms_s_unchecked = frontendDB->be_def_limit.lms_s_unchecked;
2735 lim->lms_s_pr = frontendDB->be_def_limit.lms_s_pr;
2736 lim->lms_s_pr_hide = frontendDB->be_def_limit.lms_s_pr_hide;
2737 lim->lms_s_pr_total = frontendDB->be_def_limit.lms_s_pr_total;
2738 }
2739 goto ok;
2740 }
2741 for(i = 1; i < c->argc; i++) {
2742 if(!strncasecmp(c->argv[i], "size", 4)) {
2743 rc = limits_parse_one(c->argv[i], lim);
2744 if ( rc ) {
2745 snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> unable to parse value", c->argv[0] );
2746 Debug(LDAP_DEBUG_ANY, "%s: %s \"%s\"\n",
2747 c->log, c->cr_msg, c->argv[i]);
2748 return(1);
2749 }
2750 } else {
2751 if(!strcasecmp(c->argv[i], "unlimited")) {
2752 lim->lms_s_soft = -1;
2753 } else {
2754 if ( lutil_atoix( &lim->lms_s_soft, c->argv[i], 0 ) != 0 ) {
2755 snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> unable to parse limit", c->argv[0]);
2756 Debug(LDAP_DEBUG_ANY, "%s: %s \"%s\"\n",
2757 c->log, c->cr_msg, c->argv[i]);
2758 return(1);
2759 }
2760 }
2761 lim->lms_s_hard = 0;
2762 }
2763 }
2764
2765 ok:
2766 if ( ( c->be == frontendDB ) && ( c->ca_entry ) ) {
2767 /* This is a modification to the global limits apply it to
2768 * the other databases as needed */
2769 AttributeDescription *ad=NULL;
2770 const char *text = NULL;
2771 CfEntryInfo *ce = c->ca_entry->e_private;
2772
2773 slap_str2ad(c->argv[0], &ad, &text);
2774 /* if we got here... */
2775 assert( ad != NULL );
2776
2777 if ( ce->ce_type == Cft_Global ){
2778 ce = ce->ce_kids;
2779 }
2780 for (; ce; ce=ce->ce_sibs) {
2781 Entry *dbe = ce->ce_entry;
2782 if ( (ce->ce_type == Cft_Database) && (ce->ce_be != frontendDB)
2783 && (!attr_find(dbe->e_attrs, ad)) ) {
2784 ce->ce_be->be_def_limit.lms_s_soft = lim->lms_s_soft;
2785 ce->ce_be->be_def_limit.lms_s_hard = lim->lms_s_hard;
2786 ce->ce_be->be_def_limit.lms_s_unchecked =lim->lms_s_unchecked;
2787 ce->ce_be->be_def_limit.lms_s_pr =lim->lms_s_pr;
2788 ce->ce_be->be_def_limit.lms_s_pr_hide =lim->lms_s_pr_hide;
2789 ce->ce_be->be_def_limit.lms_s_pr_total =lim->lms_s_pr_total;
2790 }
2791 }
2792 }
2793 return(0);
2794 }
2795
2796 static int
config_timelimit(ConfigArgs * c)2797 config_timelimit(ConfigArgs *c) {
2798 int i, rc = 0;
2799 struct slap_limits_set *lim = &c->be->be_def_limit;
2800 if (c->op == SLAP_CONFIG_EMIT) {
2801 char buf[8192];
2802 struct berval bv;
2803 bv.bv_val = buf;
2804 bv.bv_len = 0;
2805 limits_unparse_one( lim, SLAP_LIMIT_TIME, &bv, sizeof( buf ) );
2806 if ( !BER_BVISEMPTY( &bv ))
2807 value_add_one( &c->rvalue_vals, &bv );
2808 else
2809 rc = 1;
2810 return rc;
2811 } else if ( c->op == LDAP_MOD_DELETE ) {
2812 /* Reset to defaults or values from frontend */
2813 if ( c->be == frontendDB ) {
2814 lim->lms_t_soft = SLAPD_DEFAULT_TIMELIMIT;
2815 lim->lms_t_hard = 0;
2816 } else {
2817 lim->lms_t_soft = frontendDB->be_def_limit.lms_t_soft;
2818 lim->lms_t_hard = frontendDB->be_def_limit.lms_t_hard;
2819 }
2820 goto ok;
2821 }
2822 for(i = 1; i < c->argc; i++) {
2823 if(!strncasecmp(c->argv[i], "time", 4)) {
2824 rc = limits_parse_one(c->argv[i], lim);
2825 if ( rc ) {
2826 snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> unable to parse value", c->argv[0] );
2827 Debug(LDAP_DEBUG_ANY, "%s: %s \"%s\"\n",
2828 c->log, c->cr_msg, c->argv[i]);
2829 return(1);
2830 }
2831 } else {
2832 if(!strcasecmp(c->argv[i], "unlimited")) {
2833 lim->lms_t_soft = -1;
2834 } else {
2835 if ( lutil_atoix( &lim->lms_t_soft, c->argv[i], 0 ) != 0 ) {
2836 snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> unable to parse limit", c->argv[0]);
2837 Debug(LDAP_DEBUG_ANY, "%s: %s \"%s\"\n",
2838 c->log, c->cr_msg, c->argv[i]);
2839 return(1);
2840 }
2841 }
2842 lim->lms_t_hard = 0;
2843 }
2844 }
2845
2846 ok:
2847 if ( ( c->be == frontendDB ) && ( c->ca_entry ) ) {
2848 /* This is a modification to the global limits apply it to
2849 * the other databases as needed */
2850 AttributeDescription *ad=NULL;
2851 const char *text = NULL;
2852 CfEntryInfo *ce = c->ca_entry->e_private;
2853
2854 slap_str2ad(c->argv[0], &ad, &text);
2855 /* if we got here... */
2856 assert( ad != NULL );
2857
2858 if ( ce->ce_type == Cft_Global ){
2859 ce = ce->ce_kids;
2860 }
2861 for (; ce; ce=ce->ce_sibs) {
2862 Entry *dbe = ce->ce_entry;
2863 if ( (ce->ce_type == Cft_Database) && (ce->ce_be != frontendDB)
2864 && (!attr_find(dbe->e_attrs, ad)) ) {
2865 ce->ce_be->be_def_limit.lms_t_soft = lim->lms_t_soft;
2866 ce->ce_be->be_def_limit.lms_t_hard = lim->lms_t_hard;
2867 }
2868 }
2869 }
2870 return(0);
2871 }
2872
2873 static int
config_overlay(ConfigArgs * c)2874 config_overlay(ConfigArgs *c) {
2875 if (c->op == SLAP_CONFIG_EMIT) {
2876 return 1;
2877 } else if ( c->op == LDAP_MOD_DELETE ) {
2878 assert(0);
2879 }
2880 if(c->argv[1][0] == '-' && overlay_config(c->be, &c->argv[1][1],
2881 c->valx, &c->bi, &c->reply)) {
2882 /* log error */
2883 Debug( LDAP_DEBUG_ANY,
2884 "%s: (optional) %s overlay \"%s\" configuration failed.\n",
2885 c->log, c->be == frontendDB ? "global " : "", &c->argv[1][1]);
2886 return 1;
2887 } else if(overlay_config(c->be, c->argv[1], c->valx, &c->bi, &c->reply)) {
2888 return(1);
2889 }
2890 return(0);
2891 }
2892
2893 static int
config_subordinate(ConfigArgs * c)2894 config_subordinate(ConfigArgs *c)
2895 {
2896 int rc = 1;
2897 int advertise = 0;
2898
2899 switch( c->op ) {
2900 case SLAP_CONFIG_EMIT:
2901 if ( SLAP_GLUE_SUBORDINATE( c->be )) {
2902 struct berval bv;
2903
2904 bv.bv_val = SLAP_GLUE_ADVERTISE( c->be ) ? "advertise" : "TRUE";
2905 bv.bv_len = SLAP_GLUE_ADVERTISE( c->be ) ? STRLENOF("advertise") :
2906 STRLENOF("TRUE");
2907
2908 value_add_one( &c->rvalue_vals, &bv );
2909 rc = 0;
2910 }
2911 break;
2912 case LDAP_MOD_DELETE:
2913 if ( !c->line || strcasecmp( c->line, "advertise" )) {
2914 glue_sub_del( c->be );
2915 } else {
2916 SLAP_DBFLAGS( c->be ) &= ~SLAP_DBFLAG_GLUE_ADVERTISE;
2917 }
2918 rc = 0;
2919 break;
2920 case LDAP_MOD_ADD:
2921 case SLAP_CONFIG_ADD:
2922 if ( c->be->be_nsuffix == NULL ) {
2923 /* log error */
2924 snprintf( c->cr_msg, sizeof( c->cr_msg),
2925 "subordinate configuration needs a suffix" );
2926 Debug( LDAP_DEBUG_ANY,
2927 "%s: %s.\n",
2928 c->log, c->cr_msg );
2929 rc = 1;
2930 break;
2931 }
2932
2933 if ( c->argc == 2 ) {
2934 if ( strcasecmp( c->argv[1], "advertise" ) == 0 ) {
2935 advertise = 1;
2936
2937 } else if ( strcasecmp( c->argv[1], "TRUE" ) != 0 ) {
2938 /* log error */
2939 snprintf( c->cr_msg, sizeof( c->cr_msg),
2940 "subordinate must be \"TRUE\" or \"advertise\"" );
2941 Debug( LDAP_DEBUG_ANY,
2942 "%s: suffix \"%s\": %s.\n",
2943 c->log, c->be->be_suffix[0].bv_val, c->cr_msg );
2944 rc = 1;
2945 break;
2946 }
2947 }
2948
2949 rc = glue_sub_add( c->be, advertise, CONFIG_ONLINE_ADD( c ));
2950 break;
2951 }
2952
2953 return rc;
2954 }
2955
2956 /*
2957 * [listener=<listener>] [{read|write}=]<size>
2958 */
2959
2960 #ifdef LDAP_TCP_BUFFER
2961 static BerVarray tcp_buffer;
2962 int tcp_buffer_num;
2963
2964 #define SLAP_TCP_RMEM (0x1U)
2965 #define SLAP_TCP_WMEM (0x2U)
2966
2967 static int
tcp_buffer_parse(struct berval * val,int argc,char ** argv,int * size,int * rw,Listener ** l)2968 tcp_buffer_parse( struct berval *val, int argc, char **argv,
2969 int *size, int *rw, Listener **l )
2970 {
2971 int i, rc = LDAP_SUCCESS;
2972 LDAPURLDesc *lud = NULL;
2973 char *ptr;
2974
2975 if ( val != NULL && argv == NULL ) {
2976 char *s = val->bv_val;
2977
2978 argv = ldap_str2charray( s, " \t" );
2979 if ( argv == NULL ) {
2980 return LDAP_OTHER;
2981 }
2982 }
2983
2984 i = 0;
2985 if ( strncasecmp( argv[ i ], "listener=", STRLENOF( "listener=" ) )
2986 == 0 )
2987 {
2988 char *url = argv[ i ] + STRLENOF( "listener=" );
2989
2990 if ( ldap_url_parse( url, &lud ) ) {
2991 rc = LDAP_INVALID_SYNTAX;
2992 goto done;
2993 }
2994
2995 *l = config_check_my_url( url, lud );
2996 if ( *l == NULL ) {
2997 rc = LDAP_NO_SUCH_ATTRIBUTE;
2998 goto done;
2999 }
3000
3001 i++;
3002 }
3003
3004 ptr = argv[ i ];
3005 if ( strncasecmp( ptr, "read=", STRLENOF( "read=" ) ) == 0 ) {
3006 *rw |= SLAP_TCP_RMEM;
3007 ptr += STRLENOF( "read=" );
3008
3009 } else if ( strncasecmp( ptr, "write=", STRLENOF( "write=" ) ) == 0 ) {
3010 *rw |= SLAP_TCP_WMEM;
3011 ptr += STRLENOF( "write=" );
3012
3013 } else {
3014 *rw |= ( SLAP_TCP_RMEM | SLAP_TCP_WMEM );
3015 }
3016
3017 /* accept any base */
3018 if ( lutil_atoix( size, ptr, 0 ) ) {
3019 rc = LDAP_INVALID_SYNTAX;
3020 goto done;
3021 }
3022
3023 done:;
3024 if ( val != NULL && argv != NULL ) {
3025 ldap_charray_free( argv );
3026 }
3027
3028 if ( lud != NULL ) {
3029 ldap_free_urldesc( lud );
3030 }
3031
3032 return rc;
3033 }
3034
3035 static int
tcp_buffer_delete_one(struct berval * val)3036 tcp_buffer_delete_one( struct berval *val )
3037 {
3038 int rc = 0;
3039 int size = -1, rw = 0;
3040 Listener *l = NULL;
3041
3042 rc = tcp_buffer_parse( val, 0, NULL, &size, &rw, &l );
3043 if ( rc != 0 ) {
3044 return rc;
3045 }
3046
3047 if ( l != NULL ) {
3048 int i;
3049 Listener **ll = slapd_get_listeners();
3050
3051 for ( i = 0; ll[ i ] != NULL; i++ ) {
3052 if ( ll[ i ] == l ) break;
3053 }
3054
3055 if ( ll[ i ] == NULL ) {
3056 return LDAP_NO_SUCH_ATTRIBUTE;
3057 }
3058
3059 if ( rw & SLAP_TCP_RMEM ) l->sl_tcp_rmem = -1;
3060 if ( rw & SLAP_TCP_WMEM ) l->sl_tcp_wmem = -1;
3061
3062 for ( i++ ; ll[ i ] != NULL && bvmatch( &l->sl_url, &ll[ i ]->sl_url ); i++ ) {
3063 if ( rw & SLAP_TCP_RMEM ) ll[ i ]->sl_tcp_rmem = -1;
3064 if ( rw & SLAP_TCP_WMEM ) ll[ i ]->sl_tcp_wmem = -1;
3065 }
3066
3067 } else {
3068 /* NOTE: this affects listeners without a specific setting,
3069 * does not reset all listeners. If a listener without
3070 * specific settings was assigned a buffer because of
3071 * a global setting, it will not be reset. In any case,
3072 * buffer changes will only take place at restart. */
3073 if ( rw & SLAP_TCP_RMEM ) slapd_tcp_rmem = -1;
3074 if ( rw & SLAP_TCP_WMEM ) slapd_tcp_wmem = -1;
3075 }
3076
3077 return rc;
3078 }
3079
3080 static int
tcp_buffer_delete(BerVarray vals)3081 tcp_buffer_delete( BerVarray vals )
3082 {
3083 int i;
3084
3085 for ( i = 0; !BER_BVISNULL( &vals[ i ] ); i++ ) {
3086 tcp_buffer_delete_one( &vals[ i ] );
3087 }
3088
3089 return 0;
3090 }
3091
3092 static int
tcp_buffer_unparse(int size,int rw,Listener * l,struct berval * val)3093 tcp_buffer_unparse( int size, int rw, Listener *l, struct berval *val )
3094 {
3095 char buf[sizeof("2147483648")], *ptr;
3096
3097 /* unparse for later use */
3098 val->bv_len = snprintf( buf, sizeof( buf ), "%d", size );
3099 if ( l != NULL ) {
3100 val->bv_len += STRLENOF( "listener=" " " ) + l->sl_url.bv_len;
3101 }
3102
3103 if ( rw != ( SLAP_TCP_RMEM | SLAP_TCP_WMEM ) ) {
3104 if ( rw & SLAP_TCP_RMEM ) {
3105 val->bv_len += STRLENOF( "read=" );
3106 } else if ( rw & SLAP_TCP_WMEM ) {
3107 val->bv_len += STRLENOF( "write=" );
3108 }
3109 }
3110
3111 val->bv_val = ch_malloc( val->bv_len + 1 );
3112
3113 ptr = val->bv_val;
3114
3115 if ( l != NULL ) {
3116 ptr = lutil_strcopy( ptr, "listener=" );
3117 ptr = lutil_strncopy( ptr, l->sl_url.bv_val, l->sl_url.bv_len );
3118 *ptr++ = ' ';
3119 }
3120
3121 if ( rw != ( SLAP_TCP_RMEM | SLAP_TCP_WMEM ) ) {
3122 if ( rw & SLAP_TCP_RMEM ) {
3123 ptr = lutil_strcopy( ptr, "read=" );
3124 } else if ( rw & SLAP_TCP_WMEM ) {
3125 ptr = lutil_strcopy( ptr, "write=" );
3126 }
3127 }
3128
3129 ptr = lutil_strcopy( ptr, buf );
3130 *ptr = '\0';
3131
3132 assert( val->bv_val + val->bv_len == ptr );
3133
3134 return LDAP_SUCCESS;
3135 }
3136
3137 static int
tcp_buffer_add_one(int argc,char ** argv)3138 tcp_buffer_add_one( int argc, char **argv )
3139 {
3140 int rc = 0;
3141 int size = -1, rw = 0;
3142 Listener *l = NULL;
3143
3144 struct berval val;
3145
3146 /* parse */
3147 rc = tcp_buffer_parse( NULL, argc, argv, &size, &rw, &l );
3148 if ( rc != 0 ) {
3149 return rc;
3150 }
3151
3152 /* unparse for later use */
3153 rc = tcp_buffer_unparse( size, rw, l, &val );
3154 if ( rc != LDAP_SUCCESS ) {
3155 return rc;
3156 }
3157
3158 /* use parsed values */
3159 if ( l != NULL ) {
3160 int i;
3161 Listener **ll = slapd_get_listeners();
3162
3163 for ( i = 0; ll[ i ] != NULL; i++ ) {
3164 if ( ll[ i ] == l ) break;
3165 }
3166
3167 if ( ll[ i ] == NULL ) {
3168 return LDAP_NO_SUCH_ATTRIBUTE;
3169 }
3170
3171 /* buffer only applies to TCP listeners;
3172 * we do not do any check here, and delegate them
3173 * to setsockopt(2) */
3174 if ( rw & SLAP_TCP_RMEM ) l->sl_tcp_rmem = size;
3175 if ( rw & SLAP_TCP_WMEM ) l->sl_tcp_wmem = size;
3176
3177 for ( i++ ; ll[ i ] != NULL && bvmatch( &l->sl_url, &ll[ i ]->sl_url ); i++ ) {
3178 if ( rw & SLAP_TCP_RMEM ) ll[ i ]->sl_tcp_rmem = size;
3179 if ( rw & SLAP_TCP_WMEM ) ll[ i ]->sl_tcp_wmem = size;
3180 }
3181
3182 } else {
3183 /* NOTE: this affects listeners without a specific setting,
3184 * does not set all listeners */
3185 if ( rw & SLAP_TCP_RMEM ) slapd_tcp_rmem = size;
3186 if ( rw & SLAP_TCP_WMEM ) slapd_tcp_wmem = size;
3187 }
3188
3189 tcp_buffer = ch_realloc( tcp_buffer, sizeof( struct berval ) * ( tcp_buffer_num + 2 ) );
3190 /* append */
3191 tcp_buffer[ tcp_buffer_num ] = val;
3192
3193 tcp_buffer_num++;
3194 BER_BVZERO( &tcp_buffer[ tcp_buffer_num ] );
3195
3196 return rc;
3197 }
3198
3199 static int
config_tcp_buffer(ConfigArgs * c)3200 config_tcp_buffer( ConfigArgs *c )
3201 {
3202 if ( c->op == SLAP_CONFIG_EMIT ) {
3203 if ( tcp_buffer == NULL || BER_BVISNULL( &tcp_buffer[ 0 ] ) ) {
3204 return 1;
3205 }
3206 value_add( &c->rvalue_vals, tcp_buffer );
3207 value_add( &c->rvalue_nvals, tcp_buffer );
3208
3209 } else if ( c->op == LDAP_MOD_DELETE ) {
3210 if ( !c->line ) {
3211 tcp_buffer_delete( tcp_buffer );
3212 ber_bvarray_free( tcp_buffer );
3213 tcp_buffer = NULL;
3214 tcp_buffer_num = 0;
3215
3216 } else {
3217 int rc = 0;
3218 int size = -1, rw = 0;
3219 Listener *l = NULL;
3220
3221 struct berval val = BER_BVNULL;
3222
3223 int i;
3224
3225 if ( tcp_buffer_num == 0 ) {
3226 return 1;
3227 }
3228
3229 /* parse */
3230 rc = tcp_buffer_parse( NULL, c->argc - 1, &c->argv[ 1 ], &size, &rw, &l );
3231 if ( rc != 0 ) {
3232 return 1;
3233 }
3234
3235 /* unparse for later use */
3236 rc = tcp_buffer_unparse( size, rw, l, &val );
3237 if ( rc != LDAP_SUCCESS ) {
3238 return 1;
3239 }
3240
3241 for ( i = 0; !BER_BVISNULL( &tcp_buffer[ i ] ); i++ ) {
3242 if ( bvmatch( &tcp_buffer[ i ], &val ) ) {
3243 break;
3244 }
3245 }
3246
3247 if ( BER_BVISNULL( &tcp_buffer[ i ] ) ) {
3248 /* not found */
3249 rc = 1;
3250 goto done;
3251 }
3252
3253 tcp_buffer_delete_one( &tcp_buffer[ i ] );
3254 ber_memfree( tcp_buffer[ i ].bv_val );
3255 for ( ; i < tcp_buffer_num; i++ ) {
3256 tcp_buffer[ i ] = tcp_buffer[ i + 1 ];
3257 }
3258 tcp_buffer_num--;
3259
3260 done:;
3261 if ( !BER_BVISNULL( &val ) ) {
3262 SLAP_FREE( val.bv_val );
3263 }
3264
3265 }
3266
3267 } else {
3268 int rc;
3269
3270 rc = tcp_buffer_add_one( c->argc - 1, &c->argv[ 1 ] );
3271 if ( rc ) {
3272 snprintf( c->cr_msg, sizeof( c->cr_msg ),
3273 "<%s> unable to add value #%d",
3274 c->argv[0], tcp_buffer_num );
3275 Debug( LDAP_DEBUG_ANY, "%s: %s\n",
3276 c->log, c->cr_msg );
3277 return 1;
3278 }
3279 }
3280
3281 return 0;
3282 }
3283 #endif /* LDAP_TCP_BUFFER */
3284
3285 static int
config_suffix(ConfigArgs * c)3286 config_suffix(ConfigArgs *c)
3287 {
3288 Backend *tbe;
3289 struct berval pdn, ndn;
3290 char *notallowed = NULL;
3291
3292 if ( c->be == frontendDB ) {
3293 notallowed = "frontend";
3294
3295 } else if ( SLAP_MONITOR(c->be) ) {
3296 notallowed = "monitor";
3297
3298 } else if ( SLAP_CONFIG(c->be) ) {
3299 notallowed = "config";
3300 }
3301
3302 if ( notallowed != NULL ) {
3303 char buf[ SLAP_TEXT_BUFLEN ] = { '\0' };
3304
3305 switch ( c->op ) {
3306 case LDAP_MOD_ADD:
3307 case LDAP_MOD_DELETE:
3308 case LDAP_MOD_REPLACE:
3309 case LDAP_MOD_INCREMENT:
3310 case SLAP_CONFIG_ADD:
3311 if ( !BER_BVISNULL( &c->value_dn ) ) {
3312 snprintf( buf, sizeof( buf ), "<%s> ",
3313 c->value_dn.bv_val );
3314 }
3315
3316 Debug(LDAP_DEBUG_ANY,
3317 "%s: suffix %snot allowed in %s database.\n",
3318 c->log, buf, notallowed );
3319 break;
3320
3321 case SLAP_CONFIG_EMIT:
3322 /* don't complain when emitting... */
3323 break;
3324
3325 default:
3326 /* FIXME: don't know what values may be valid;
3327 * please remove assertion, or add legal values
3328 * to either block */
3329 assert( 0 );
3330 break;
3331 }
3332
3333 return 1;
3334 }
3335
3336 if (c->op == SLAP_CONFIG_EMIT) {
3337 if ( c->be->be_suffix == NULL
3338 || BER_BVISNULL( &c->be->be_suffix[0] ) )
3339 {
3340 return 1;
3341 } else {
3342 value_add( &c->rvalue_vals, c->be->be_suffix );
3343 value_add( &c->rvalue_nvals, c->be->be_nsuffix );
3344 return 0;
3345 }
3346 } else if ( c->op == LDAP_MOD_DELETE ) {
3347 if ( c->valx < 0 ) {
3348 ber_bvarray_free( c->be->be_suffix );
3349 ber_bvarray_free( c->be->be_nsuffix );
3350 c->be->be_suffix = NULL;
3351 c->be->be_nsuffix = NULL;
3352 } else {
3353 int i = c->valx;
3354 ch_free( c->be->be_suffix[i].bv_val );
3355 ch_free( c->be->be_nsuffix[i].bv_val );
3356 do {
3357 c->be->be_suffix[i] = c->be->be_suffix[i+1];
3358 c->be->be_nsuffix[i] = c->be->be_nsuffix[i+1];
3359 i++;
3360 } while ( !BER_BVISNULL( &c->be->be_suffix[i] ) );
3361 }
3362 return 0;
3363 }
3364
3365 #ifdef SLAPD_MONITOR_DN
3366 if(!strcasecmp(c->argv[1], SLAPD_MONITOR_DN)) {
3367 snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> DN is reserved for monitoring slapd",
3368 c->argv[0] );
3369 Debug(LDAP_DEBUG_ANY, "%s: %s (%s)\n",
3370 c->log, c->cr_msg, SLAPD_MONITOR_DN);
3371 return(1);
3372 }
3373 #endif
3374
3375 if (SLAP_DB_ONE_SUFFIX( c->be ) && c->be->be_suffix &&
3376 !BER_BVISNULL( &c->be->be_suffix[0] )) {
3377 snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> Only one suffix is allowed on this %s backend",
3378 c->argv[0], c->be->bd_info->bi_type );
3379 Debug(LDAP_DEBUG_ANY, "%s: %s\n",
3380 c->log, c->cr_msg );
3381 return(1);
3382 }
3383
3384 pdn = c->value_dn;
3385 ndn = c->value_ndn;
3386
3387 if (SLAP_DBHIDDEN( c->be ))
3388 tbe = NULL;
3389 else
3390 tbe = select_backend(&ndn, 0);
3391 if(tbe == c->be) {
3392 Debug( LDAP_DEBUG_ANY, "%s: suffix already served by this backend!.\n",
3393 c->log );
3394 free(pdn.bv_val);
3395 free(ndn.bv_val);
3396 return 1;
3397 } else if(tbe) {
3398 BackendDB *b2 = tbe;
3399
3400 /* Does tbe precede be? */
3401 while (( b2 = LDAP_STAILQ_NEXT(b2, be_next )) && b2 && b2 != c->be );
3402
3403 if ( b2 ) {
3404 char *type = tbe->bd_info->bi_type;
3405
3406 if ( overlay_is_over( tbe ) ) {
3407 slap_overinfo *oi = (slap_overinfo *)tbe->bd_info->bi_private;
3408 type = oi->oi_orig->bi_type;
3409 }
3410
3411 snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> namingContext \"%s\" "
3412 "already served by a preceding %s database",
3413 c->argv[0], pdn.bv_val, type );
3414 Debug(LDAP_DEBUG_ANY, "%s: %s serving namingContext \"%s\"\n",
3415 c->log, c->cr_msg, tbe->be_suffix[0].bv_val);
3416 free(pdn.bv_val);
3417 free(ndn.bv_val);
3418 return(1);
3419 }
3420 }
3421 if(pdn.bv_len == 0 && default_search_nbase.bv_len) {
3422 Debug(LDAP_DEBUG_ANY, "%s: suffix DN empty and default search "
3423 "base provided \"%s\" (assuming okay)\n",
3424 c->log, default_search_base.bv_val );
3425 }
3426 ber_bvarray_add(&c->be->be_suffix, &pdn);
3427 ber_bvarray_add(&c->be->be_nsuffix, &ndn);
3428 return(0);
3429 }
3430
3431 static int
config_rootdn(ConfigArgs * c)3432 config_rootdn(ConfigArgs *c) {
3433 if (c->op == SLAP_CONFIG_EMIT) {
3434 if ( !BER_BVISNULL( &c->be->be_rootdn )) {
3435 value_add_one(&c->rvalue_vals, &c->be->be_rootdn);
3436 value_add_one(&c->rvalue_nvals, &c->be->be_rootndn);
3437 return 0;
3438 } else {
3439 return 1;
3440 }
3441 } else if ( c->op == LDAP_MOD_DELETE ) {
3442 ch_free( c->be->be_rootdn.bv_val );
3443 ch_free( c->be->be_rootndn.bv_val );
3444 BER_BVZERO( &c->be->be_rootdn );
3445 BER_BVZERO( &c->be->be_rootndn );
3446 return 0;
3447 }
3448 if ( !BER_BVISNULL( &c->be->be_rootdn )) {
3449 ch_free( c->be->be_rootdn.bv_val );
3450 ch_free( c->be->be_rootndn.bv_val );
3451 }
3452 c->be->be_rootdn = c->value_dn;
3453 c->be->be_rootndn = c->value_ndn;
3454 return(0);
3455 }
3456
3457 static int
config_rootpw(ConfigArgs * c)3458 config_rootpw(ConfigArgs *c) {
3459 Backend *tbe;
3460
3461 if (c->op == SLAP_CONFIG_EMIT) {
3462 if (!BER_BVISEMPTY(&c->be->be_rootpw)) {
3463 /* don't copy, because "rootpw" is marked
3464 * as CFG_BERVAL */
3465 c->value_bv = c->be->be_rootpw;
3466 return 0;
3467 }
3468 return 1;
3469 } else if ( c->op == LDAP_MOD_DELETE ) {
3470 ch_free( c->be->be_rootpw.bv_val );
3471 BER_BVZERO( &c->be->be_rootpw );
3472 return 0;
3473 }
3474
3475 tbe = select_backend(&c->be->be_rootndn, 0);
3476 if(tbe != c->be && !SLAP_DBHIDDEN( c->be )) {
3477 snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> can only be set when rootdn is under suffix",
3478 c->argv[0] );
3479 Debug(LDAP_DEBUG_ANY, "%s: %s\n",
3480 c->log, c->cr_msg );
3481 return(1);
3482 }
3483 if ( !BER_BVISNULL( &c->be->be_rootpw ))
3484 ch_free( c->be->be_rootpw.bv_val );
3485 c->be->be_rootpw = c->value_bv;
3486 return(0);
3487 }
3488
3489 static int
config_restrict(ConfigArgs * c)3490 config_restrict(ConfigArgs *c) {
3491 slap_mask_t restrictops = 0;
3492 int i;
3493 slap_verbmasks restrictable_ops[] = {
3494 { BER_BVC("bind"), SLAP_RESTRICT_OP_BIND },
3495 { BER_BVC("add"), SLAP_RESTRICT_OP_ADD },
3496 { BER_BVC("modify"), SLAP_RESTRICT_OP_MODIFY },
3497 { BER_BVC("rename"), SLAP_RESTRICT_OP_RENAME },
3498 { BER_BVC("modrdn"), 0 },
3499 { BER_BVC("delete"), SLAP_RESTRICT_OP_DELETE },
3500 { BER_BVC("search"), SLAP_RESTRICT_OP_SEARCH },
3501 { BER_BVC("compare"), SLAP_RESTRICT_OP_COMPARE },
3502 { BER_BVC("read"), SLAP_RESTRICT_OP_READS },
3503 { BER_BVC("write"), SLAP_RESTRICT_OP_WRITES },
3504 { BER_BVC("extended"), SLAP_RESTRICT_OP_EXTENDED },
3505 { BER_BVC("extended=" LDAP_EXOP_START_TLS ), SLAP_RESTRICT_EXOP_START_TLS },
3506 { BER_BVC("extended=" LDAP_EXOP_MODIFY_PASSWD ), SLAP_RESTRICT_EXOP_MODIFY_PASSWD },
3507 { BER_BVC("extended=" LDAP_EXOP_X_WHO_AM_I ), SLAP_RESTRICT_EXOP_WHOAMI },
3508 { BER_BVC("extended=" LDAP_EXOP_X_CANCEL ), SLAP_RESTRICT_EXOP_CANCEL },
3509 { BER_BVC("all"), SLAP_RESTRICT_OP_ALL },
3510 { BER_BVNULL, 0 }
3511 };
3512
3513 if (c->op == SLAP_CONFIG_EMIT) {
3514 return mask_to_verbs( restrictable_ops, c->be->be_restrictops,
3515 &c->rvalue_vals );
3516 } else if ( c->op == LDAP_MOD_DELETE ) {
3517 if ( !c->line ) {
3518 c->be->be_restrictops = 0;
3519 } else {
3520 i = verb_to_mask( c->line, restrictable_ops );
3521 c->be->be_restrictops &= ~restrictable_ops[i].mask;
3522 }
3523 return 0;
3524 }
3525 i = verbs_to_mask( c->argc, c->argv, restrictable_ops, &restrictops );
3526 if ( i ) {
3527 snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> unknown operation", c->argv[0] );
3528 Debug(LDAP_DEBUG_ANY, "%s: %s %s\n",
3529 c->log, c->cr_msg, c->argv[i]);
3530 return(1);
3531 }
3532 if ( restrictops & SLAP_RESTRICT_OP_EXTENDED )
3533 restrictops &= ~SLAP_RESTRICT_EXOP_MASK;
3534 c->be->be_restrictops |= restrictops;
3535 return(0);
3536 }
3537
3538 static int
config_allows(ConfigArgs * c)3539 config_allows(ConfigArgs *c) {
3540 slap_mask_t allows = 0;
3541 int i;
3542 slap_verbmasks allowable_ops[] = {
3543 { BER_BVC("bind_v2"), SLAP_ALLOW_BIND_V2 },
3544 { BER_BVC("bind_anon_cred"), SLAP_ALLOW_BIND_ANON_CRED },
3545 { BER_BVC("bind_anon_dn"), SLAP_ALLOW_BIND_ANON_DN },
3546 { BER_BVC("update_anon"), SLAP_ALLOW_UPDATE_ANON },
3547 { BER_BVC("proxy_authz_anon"), SLAP_ALLOW_PROXY_AUTHZ_ANON },
3548 { BER_BVNULL, 0 }
3549 };
3550 if (c->op == SLAP_CONFIG_EMIT) {
3551 return mask_to_verbs( allowable_ops, global_allows, &c->rvalue_vals );
3552 } else if ( c->op == LDAP_MOD_DELETE ) {
3553 if ( !c->line ) {
3554 global_allows = 0;
3555 } else {
3556 i = verb_to_mask( c->line, allowable_ops );
3557 global_allows &= ~allowable_ops[i].mask;
3558 }
3559 return 0;
3560 }
3561 i = verbs_to_mask(c->argc, c->argv, allowable_ops, &allows);
3562 if ( i ) {
3563 snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> unknown feature", c->argv[0] );
3564 Debug(LDAP_DEBUG_ANY, "%s: %s %s\n",
3565 c->log, c->cr_msg, c->argv[i]);
3566 return(1);
3567 }
3568 global_allows |= allows;
3569 return(0);
3570 }
3571
3572 static int
config_disallows(ConfigArgs * c)3573 config_disallows(ConfigArgs *c) {
3574 slap_mask_t disallows = 0;
3575 int i;
3576 slap_verbmasks disallowable_ops[] = {
3577 { BER_BVC("bind_anon"), SLAP_DISALLOW_BIND_ANON },
3578 { BER_BVC("bind_simple"), SLAP_DISALLOW_BIND_SIMPLE },
3579 { BER_BVC("tls_2_anon"), SLAP_DISALLOW_TLS_2_ANON },
3580 { BER_BVC("tls_authc"), SLAP_DISALLOW_TLS_AUTHC },
3581 { BER_BVC("proxy_authz_non_critical"), SLAP_DISALLOW_PROXY_AUTHZ_N_CRIT },
3582 { BER_BVC("dontusecopy_non_critical"), SLAP_DISALLOW_DONTUSECOPY_N_CRIT },
3583 { BER_BVNULL, 0 }
3584 };
3585 if (c->op == SLAP_CONFIG_EMIT) {
3586 return mask_to_verbs( disallowable_ops, global_disallows, &c->rvalue_vals );
3587 } else if ( c->op == LDAP_MOD_DELETE ) {
3588 if ( !c->line ) {
3589 global_disallows = 0;
3590 } else {
3591 i = verb_to_mask( c->line, disallowable_ops );
3592 global_disallows &= ~disallowable_ops[i].mask;
3593 }
3594 return 0;
3595 }
3596 i = verbs_to_mask(c->argc, c->argv, disallowable_ops, &disallows);
3597 if ( i ) {
3598 snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> unknown feature", c->argv[0] );
3599 Debug(LDAP_DEBUG_ANY, "%s: %s %s\n",
3600 c->log, c->cr_msg, c->argv[i]);
3601 return(1);
3602 }
3603 global_disallows |= disallows;
3604 return(0);
3605 }
3606
3607 static int
config_requires(ConfigArgs * c)3608 config_requires(ConfigArgs *c) {
3609 slap_mask_t requires = frontendDB->be_requires;
3610 int i, argc = c->argc;
3611 char **argv = c->argv;
3612
3613 slap_verbmasks requires_ops[] = {
3614 { BER_BVC("bind"), SLAP_REQUIRE_BIND },
3615 { BER_BVC("LDAPv3"), SLAP_REQUIRE_LDAP_V3 },
3616 { BER_BVC("authc"), SLAP_REQUIRE_AUTHC },
3617 { BER_BVC("sasl"), SLAP_REQUIRE_SASL },
3618 { BER_BVC("strong"), SLAP_REQUIRE_STRONG },
3619 { BER_BVNULL, 0 }
3620 };
3621 if (c->op == SLAP_CONFIG_EMIT) {
3622 return mask_to_verbs( requires_ops, c->be->be_requires, &c->rvalue_vals );
3623 } else if ( c->op == LDAP_MOD_DELETE ) {
3624 if ( !c->line ) {
3625 c->be->be_requires = 0;
3626 } else {
3627 i = verb_to_mask( c->line, requires_ops );
3628 c->be->be_requires &= ~requires_ops[i].mask;
3629 }
3630 return 0;
3631 }
3632 /* "none" can only be first, to wipe out default/global values */
3633 if ( strcasecmp( c->argv[ 1 ], "none" ) == 0 ) {
3634 argv++;
3635 argc--;
3636 requires = 0;
3637 }
3638 i = verbs_to_mask(argc, argv, requires_ops, &requires);
3639 if ( i ) {
3640 if (strcasecmp( c->argv[ i ], "none" ) == 0 ) {
3641 snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> \"none\" (#%d) must be listed first", c->argv[0], i - 1 );
3642 Debug(LDAP_DEBUG_ANY, "%s: %s\n",
3643 c->log, c->cr_msg );
3644 } else {
3645 snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> unknown feature #%d", c->argv[0], i - 1 );
3646 Debug(LDAP_DEBUG_ANY, "%s: %s \"%s\"\n",
3647 c->log, c->cr_msg, c->argv[i]);
3648 }
3649 return(1);
3650 }
3651 c->be->be_requires = requires;
3652 return(0);
3653 }
3654
3655 static int
config_extra_attrs(ConfigArgs * c)3656 config_extra_attrs(ConfigArgs *c)
3657 {
3658 assert( c->be != NULL );
3659
3660 if ( c->op == SLAP_CONFIG_EMIT ) {
3661 int i;
3662
3663 if ( c->be->be_extra_anlist == NULL ) {
3664 return 1;
3665 }
3666
3667 for ( i = 0; !BER_BVISNULL( &c->be->be_extra_anlist[i].an_name ); i++ ) {
3668 value_add_one( &c->rvalue_vals, &c->be->be_extra_anlist[i].an_name );
3669 }
3670
3671 } else if ( c->op == LDAP_MOD_DELETE ) {
3672 if ( c->be->be_extra_anlist == NULL ) {
3673 return 1;
3674 }
3675
3676 if ( c->valx < 0 ) {
3677 anlist_free( c->be->be_extra_anlist, 1, NULL );
3678 c->be->be_extra_anlist = NULL;
3679
3680 } else {
3681 int i;
3682
3683 for ( i = 0; i < c->valx && !BER_BVISNULL( &c->be->be_extra_anlist[i + 1].an_name ); i++ )
3684 ;
3685
3686 if ( BER_BVISNULL( &c->be->be_extra_anlist[i].an_name ) ) {
3687 return 1;
3688 }
3689
3690 ch_free( c->be->be_extra_anlist[i].an_name.bv_val );
3691
3692 for ( ; !BER_BVISNULL( &c->be->be_extra_anlist[i].an_name ); i++ ) {
3693 c->be->be_extra_anlist[i] = c->be->be_extra_anlist[i + 1];
3694 }
3695 }
3696
3697 } else {
3698 c->be->be_extra_anlist = str2anlist( c->be->be_extra_anlist, c->argv[1], " ,\t" );
3699 if ( c->be->be_extra_anlist == NULL ) {
3700 return 1;
3701 }
3702 }
3703
3704 return 0;
3705 }
3706
3707 static slap_verbmasks *loglevel_ops;
3708
3709 static int
loglevel_init(void)3710 loglevel_init( void )
3711 {
3712 slap_verbmasks lo[] = {
3713 { BER_BVC("Any"), (slap_mask_t) LDAP_DEBUG_ANY },
3714 { BER_BVC("Trace"), LDAP_DEBUG_TRACE },
3715 { BER_BVC("Packets"), LDAP_DEBUG_PACKETS },
3716 { BER_BVC("Args"), LDAP_DEBUG_ARGS },
3717 { BER_BVC("Conns"), LDAP_DEBUG_CONNS },
3718 { BER_BVC("BER"), LDAP_DEBUG_BER },
3719 { BER_BVC("Filter"), LDAP_DEBUG_FILTER },
3720 { BER_BVC("Config"), LDAP_DEBUG_CONFIG },
3721 { BER_BVC("ACL"), LDAP_DEBUG_ACL },
3722 { BER_BVC("Stats"), LDAP_DEBUG_STATS },
3723 { BER_BVC("Stats2"), LDAP_DEBUG_STATS2 },
3724 { BER_BVC("Shell"), LDAP_DEBUG_SHELL },
3725 { BER_BVC("Parse"), LDAP_DEBUG_PARSE },
3726 #if 0 /* no longer used (nor supported) */
3727 { BER_BVC("Cache"), LDAP_DEBUG_CACHE },
3728 { BER_BVC("Index"), LDAP_DEBUG_INDEX },
3729 #endif
3730 { BER_BVC("Sync"), LDAP_DEBUG_SYNC },
3731 { BER_BVC("None"), LDAP_DEBUG_NONE },
3732 { BER_BVNULL, 0 }
3733 };
3734
3735 return slap_verbmasks_init( &loglevel_ops, lo );
3736 }
3737
3738 static void
loglevel_destroy(void)3739 loglevel_destroy( void )
3740 {
3741 if ( loglevel_ops ) {
3742 (void)slap_verbmasks_destroy( loglevel_ops );
3743 }
3744 loglevel_ops = NULL;
3745 }
3746
3747 static slap_mask_t loglevel_ignore[] = { -1, 0 };
3748
3749 int
slap_loglevel_register(slap_mask_t m,struct berval * s)3750 slap_loglevel_register( slap_mask_t m, struct berval *s )
3751 {
3752 int rc;
3753
3754 if ( loglevel_ops == NULL ) {
3755 loglevel_init();
3756 }
3757
3758 rc = slap_verbmasks_append( &loglevel_ops, m, s, loglevel_ignore );
3759
3760 if ( rc != 0 ) {
3761 Debug( LDAP_DEBUG_ANY, "slap_loglevel_register(%lu, \"%s\") failed\n",
3762 m, s->bv_val );
3763 }
3764
3765 return rc;
3766 }
3767
3768 int
slap_loglevel_get(struct berval * s,int * l)3769 slap_loglevel_get( struct berval *s, int *l )
3770 {
3771 int rc;
3772 slap_mask_t m, i;
3773
3774 if ( loglevel_ops == NULL ) {
3775 loglevel_init();
3776 }
3777
3778 for ( m = 0, i = 1; !BER_BVISNULL( &loglevel_ops[ i ].word ); i++ ) {
3779 m |= loglevel_ops[ i ].mask;
3780 }
3781
3782 for ( i = 1; m & i; i <<= 1 )
3783 ;
3784
3785 if ( i == 0 ) {
3786 return -1;
3787 }
3788
3789 rc = slap_verbmasks_append( &loglevel_ops, i, s, loglevel_ignore );
3790
3791 if ( rc != 0 ) {
3792 Debug( LDAP_DEBUG_ANY, "slap_loglevel_get(%lu, \"%s\") failed\n",
3793 i, s->bv_val );
3794
3795 } else {
3796 *l = i;
3797 slap_check_unknown_level( s->bv_val, i );
3798 }
3799
3800 return rc;
3801 }
3802
3803 int
str2loglevel(const char * s,int * l)3804 str2loglevel( const char *s, int *l )
3805 {
3806 int i;
3807
3808 if ( loglevel_ops == NULL ) {
3809 loglevel_init();
3810 }
3811
3812 i = verb_to_mask( s, loglevel_ops );
3813
3814 if ( BER_BVISNULL( &loglevel_ops[ i ].word ) ) {
3815 return -1;
3816 }
3817
3818 *l = loglevel_ops[ i ].mask;
3819
3820 return 0;
3821 }
3822
3823 const char *
loglevel2str(int l)3824 loglevel2str( int l )
3825 {
3826 struct berval bv = BER_BVNULL;
3827
3828 loglevel2bv( l, &bv );
3829
3830 return bv.bv_val;
3831 }
3832
3833 int
loglevel2bv(int l,struct berval * bv)3834 loglevel2bv( int l, struct berval *bv )
3835 {
3836 if ( loglevel_ops == NULL ) {
3837 loglevel_init();
3838 }
3839
3840 BER_BVZERO( bv );
3841
3842 return enum_to_verb( loglevel_ops, l, bv ) == -1;
3843 }
3844
3845 int
loglevel2bvarray(int l,BerVarray * bva)3846 loglevel2bvarray( int l, BerVarray *bva )
3847 {
3848 if ( loglevel_ops == NULL ) {
3849 loglevel_init();
3850 }
3851
3852 if ( l == 0 ) {
3853 struct berval bv = BER_BVC("0");
3854 return value_add_one( bva, &bv );
3855 }
3856
3857 return mask_to_verbs( loglevel_ops, l, bva );
3858 }
3859
3860 int
loglevel_print(FILE * out)3861 loglevel_print( FILE *out )
3862 {
3863 int i;
3864
3865 if ( loglevel_ops == NULL ) {
3866 loglevel_init();
3867 }
3868
3869 fprintf( out, "Installed log subsystems:\n\n" );
3870 for ( i = 0; !BER_BVISNULL( &loglevel_ops[ i ].word ); i++ ) {
3871 unsigned mask = loglevel_ops[ i ].mask & 0xffffffffUL;
3872 fprintf( out,
3873 (mask == ((slap_mask_t) -1 & 0xffffffffUL)
3874 ? "\t%-30s (-1, 0xffffffff)\n" : "\t%-30s (%u, 0x%x)\n"),
3875 loglevel_ops[ i ].word.bv_val, mask, mask );
3876 }
3877
3878 fprintf( out, "\nNOTE: custom log subsystems may be later installed "
3879 "by specific code\n\n" );
3880
3881 return 0;
3882 }
3883
3884 static int config_syslog;
3885
3886 static int
config_loglevel(ConfigArgs * c)3887 config_loglevel(ConfigArgs *c) {
3888 int i;
3889
3890 if ( loglevel_ops == NULL ) {
3891 loglevel_init();
3892 }
3893
3894 if (c->op == SLAP_CONFIG_EMIT) {
3895 /* Get default or commandline slapd setting */
3896 if ( ldap_syslog && !config_syslog )
3897 config_syslog = ldap_syslog;
3898 return loglevel2bvarray( config_syslog, &c->rvalue_vals );
3899
3900 } else if ( c->op == LDAP_MOD_DELETE ) {
3901 if ( !c->line ) {
3902 config_syslog = 0;
3903 } else {
3904 i = verb_to_mask( c->line, loglevel_ops );
3905 config_syslog &= ~loglevel_ops[i].mask;
3906 }
3907 if ( slapMode & SLAP_SERVER_MODE ) {
3908 ldap_syslog = config_syslog;
3909 }
3910 return 0;
3911 }
3912
3913 for( i=1; i < c->argc; i++ ) {
3914 int level;
3915
3916 if ( isdigit((unsigned char)c->argv[i][0]) || c->argv[i][0] == '-' ) {
3917 if( lutil_atoix( &level, c->argv[i], 0 ) != 0 ) {
3918 snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> unable to parse level", c->argv[0] );
3919 Debug( LDAP_DEBUG_ANY, "%s: %s \"%s\"\n",
3920 c->log, c->cr_msg, c->argv[i]);
3921 return( 1 );
3922 }
3923 } else {
3924 if ( str2loglevel( c->argv[i], &level ) ) {
3925 snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> unknown level", c->argv[0] );
3926 Debug( LDAP_DEBUG_ANY, "%s: %s \"%s\"\n",
3927 c->log, c->cr_msg, c->argv[i]);
3928 return( 1 );
3929 }
3930 }
3931 /* Explicitly setting a zero clears all the levels */
3932 if ( level )
3933 config_syslog |= level;
3934 else
3935 config_syslog = 0;
3936 }
3937 if ( slapMode & SLAP_SERVER_MODE ) {
3938 ldap_syslog = config_syslog;
3939 }
3940 return(0);
3941 }
3942
3943 static int
config_referral(ConfigArgs * c)3944 config_referral(ConfigArgs *c) {
3945 struct berval val;
3946 if (c->op == SLAP_CONFIG_EMIT) {
3947 if ( default_referral ) {
3948 value_add( &c->rvalue_vals, default_referral );
3949 return 0;
3950 } else {
3951 return 1;
3952 }
3953 } else if ( c->op == LDAP_MOD_DELETE ) {
3954 if ( c->valx < 0 ) {
3955 ber_bvarray_free( default_referral );
3956 default_referral = NULL;
3957 } else {
3958 int i = c->valx;
3959 ch_free( default_referral[i].bv_val );
3960 for (; default_referral[i].bv_val; i++ )
3961 default_referral[i] = default_referral[i+1];
3962 }
3963 return 0;
3964 }
3965 if(validate_global_referral(c->argv[1])) {
3966 snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> invalid URL", c->argv[0] );
3967 Debug(LDAP_DEBUG_ANY, "%s: %s (%s)\n",
3968 c->log, c->cr_msg, c->argv[1]);
3969 return(1);
3970 }
3971
3972 ber_str2bv(c->argv[1], 0, 0, &val);
3973 if(value_add_one(&default_referral, &val)) return(LDAP_OTHER);
3974 return(0);
3975 }
3976
3977 static struct {
3978 struct berval key;
3979 int off;
3980 } sec_keys[] = {
3981 { BER_BVC("ssf="), offsetof(slap_ssf_set_t, sss_ssf) },
3982 { BER_BVC("transport="), offsetof(slap_ssf_set_t, sss_transport) },
3983 { BER_BVC("tls="), offsetof(slap_ssf_set_t, sss_tls) },
3984 { BER_BVC("sasl="), offsetof(slap_ssf_set_t, sss_sasl) },
3985 { BER_BVC("update_ssf="), offsetof(slap_ssf_set_t, sss_update_ssf) },
3986 { BER_BVC("update_transport="), offsetof(slap_ssf_set_t, sss_update_transport) },
3987 { BER_BVC("update_tls="), offsetof(slap_ssf_set_t, sss_update_tls) },
3988 { BER_BVC("update_sasl="), offsetof(slap_ssf_set_t, sss_update_sasl) },
3989 { BER_BVC("simple_bind="), offsetof(slap_ssf_set_t, sss_simple_bind) },
3990 { BER_BVNULL, 0 }
3991 };
3992
3993 static int
config_security(ConfigArgs * c)3994 config_security(ConfigArgs *c) {
3995 slap_ssf_set_t *set = &c->be->be_ssf_set;
3996 char *next;
3997 int i, j;
3998 if (c->op == SLAP_CONFIG_EMIT) {
3999 char numbuf[32];
4000 struct berval bv;
4001 slap_ssf_t *tgt;
4002 int rc = 1;
4003
4004 for (i=0; !BER_BVISNULL( &sec_keys[i].key ); i++) {
4005 tgt = (slap_ssf_t *)((char *)set + sec_keys[i].off);
4006 if ( *tgt ) {
4007 rc = 0;
4008 bv.bv_len = snprintf( numbuf, sizeof( numbuf ), "%u", *tgt );
4009 if ( bv.bv_len >= sizeof( numbuf ) ) {
4010 ber_bvarray_free_x( c->rvalue_vals, NULL );
4011 c->rvalue_vals = NULL;
4012 rc = 1;
4013 break;
4014 }
4015 bv.bv_len += sec_keys[i].key.bv_len;
4016 bv.bv_val = ch_malloc( bv.bv_len + 1);
4017 next = lutil_strcopy( bv.bv_val, sec_keys[i].key.bv_val );
4018 strcpy( next, numbuf );
4019 ber_bvarray_add( &c->rvalue_vals, &bv );
4020 }
4021 }
4022 return rc;
4023 }
4024 for(i = 1; i < c->argc; i++) {
4025 slap_ssf_t *tgt = NULL;
4026 char *src = NULL;
4027 for ( j=0; !BER_BVISNULL( &sec_keys[j].key ); j++ ) {
4028 if(!strncasecmp(c->argv[i], sec_keys[j].key.bv_val,
4029 sec_keys[j].key.bv_len)) {
4030 src = c->argv[i] + sec_keys[j].key.bv_len;
4031 tgt = (slap_ssf_t *)((char *)set + sec_keys[j].off);
4032 break;
4033 }
4034 }
4035 if ( !tgt ) {
4036 snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> unknown factor", c->argv[0] );
4037 Debug(LDAP_DEBUG_ANY, "%s: %s %s\n",
4038 c->log, c->cr_msg, c->argv[i]);
4039 return(1);
4040 }
4041
4042 if ( lutil_atou( tgt, src ) != 0 ) {
4043 snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> unable to parse factor", c->argv[0] );
4044 Debug(LDAP_DEBUG_ANY, "%s: %s \"%s\"\n",
4045 c->log, c->cr_msg, c->argv[i]);
4046 return(1);
4047 }
4048 }
4049 return(0);
4050 }
4051
4052 char *
anlist_unparse(AttributeName * an,char * ptr,ber_len_t buflen)4053 anlist_unparse( AttributeName *an, char *ptr, ber_len_t buflen ) {
4054 int comma = 0;
4055 char *start = ptr;
4056
4057 for (; !BER_BVISNULL( &an->an_name ); an++) {
4058 /* if buflen == 0, assume the buffer size has been
4059 * already checked otherwise */
4060 if ( buflen > 0 && buflen - ( ptr - start ) < comma + an->an_name.bv_len ) return NULL;
4061 if ( comma ) *ptr++ = ',';
4062 ptr = lutil_strcopy( ptr, an->an_name.bv_val );
4063 comma = 1;
4064 }
4065 return ptr;
4066 }
4067
4068 int
slap_bv_x_ordered_unparse(BerVarray in,BerVarray * out)4069 slap_bv_x_ordered_unparse( BerVarray in, BerVarray *out )
4070 {
4071 int i;
4072 BerVarray bva = NULL;
4073 char ibuf[32], *ptr;
4074 struct berval idx;
4075
4076 assert( in != NULL );
4077
4078 for ( i = 0; !BER_BVISNULL( &in[i] ); i++ )
4079 /* count'em */ ;
4080
4081 if ( i == 0 ) {
4082 return 1;
4083 }
4084
4085 idx.bv_val = ibuf;
4086
4087 bva = ch_malloc( ( i + 1 ) * sizeof(struct berval) );
4088 BER_BVZERO( &bva[ 0 ] );
4089
4090 for ( i = 0; !BER_BVISNULL( &in[i] ); i++ ) {
4091 idx.bv_len = snprintf( idx.bv_val, sizeof( ibuf ), SLAP_X_ORDERED_FMT, i );
4092 if ( idx.bv_len >= sizeof( ibuf ) ) {
4093 ber_bvarray_free( bva );
4094 return 1;
4095 }
4096
4097 bva[i].bv_len = idx.bv_len + in[i].bv_len;
4098 bva[i].bv_val = ch_malloc( bva[i].bv_len + 1 );
4099 ptr = lutil_strcopy( bva[i].bv_val, ibuf );
4100 ptr = lutil_strcopy( ptr, in[i].bv_val );
4101 *ptr = '\0';
4102 BER_BVZERO( &bva[ i + 1 ] );
4103 }
4104
4105 *out = bva;
4106 return 0;
4107 }
4108
4109 static int
config_updatedn(ConfigArgs * c)4110 config_updatedn(ConfigArgs *c) {
4111 if (c->op == SLAP_CONFIG_EMIT) {
4112 if (!BER_BVISEMPTY(&c->be->be_update_ndn)) {
4113 value_add_one(&c->rvalue_vals, &c->be->be_update_ndn);
4114 value_add_one(&c->rvalue_nvals, &c->be->be_update_ndn);
4115 return 0;
4116 }
4117 return 1;
4118 } else if ( c->op == LDAP_MOD_DELETE ) {
4119 ch_free( c->be->be_update_ndn.bv_val );
4120 BER_BVZERO( &c->be->be_update_ndn );
4121 SLAP_DBFLAGS(c->be) ^= (SLAP_DBFLAG_SHADOW | SLAP_DBFLAG_SLURP_SHADOW);
4122 return 0;
4123 }
4124 if(SLAP_SHADOW(c->be)) {
4125 snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> database already shadowed", c->argv[0] );
4126 Debug(LDAP_DEBUG_ANY, "%s: %s\n",
4127 c->log, c->cr_msg );
4128 return(1);
4129 }
4130
4131 ber_memfree_x( c->value_dn.bv_val, NULL );
4132 if ( !BER_BVISNULL( &c->be->be_update_ndn ) ) {
4133 ber_memfree_x( c->be->be_update_ndn.bv_val, NULL );
4134 }
4135 c->be->be_update_ndn = c->value_ndn;
4136 BER_BVZERO( &c->value_dn );
4137 BER_BVZERO( &c->value_ndn );
4138
4139 return config_slurp_shadow( c );
4140 }
4141
4142 int
config_shadow(ConfigArgs * c,slap_mask_t flag)4143 config_shadow( ConfigArgs *c, slap_mask_t flag )
4144 {
4145 char *notallowed = NULL;
4146
4147 if ( c->be == frontendDB ) {
4148 notallowed = "frontend";
4149
4150 } else if ( SLAP_MONITOR(c->be) ) {
4151 notallowed = "monitor";
4152 }
4153
4154 if ( notallowed != NULL ) {
4155 Debug( LDAP_DEBUG_ANY, "%s: %s database cannot be shadow.\n", c->log, notallowed );
4156 return 1;
4157 }
4158
4159 if ( SLAP_SHADOW(c->be) ) {
4160 /* if already shadow, only check consistency */
4161 if ( ( SLAP_DBFLAGS(c->be) & flag ) != flag ) {
4162 Debug( LDAP_DEBUG_ANY, "%s: inconsistent shadow flag 0x%lx.\n",
4163 c->log, flag );
4164 return 1;
4165 }
4166
4167 } else {
4168 SLAP_DBFLAGS(c->be) |= (SLAP_DBFLAG_SHADOW | flag);
4169 if ( !SLAP_MULTIPROVIDER( c->be ))
4170 SLAP_DBFLAGS(c->be) |= SLAP_DBFLAG_SINGLE_SHADOW;
4171 }
4172
4173 return 0;
4174 }
4175
4176 static int
config_updateref(ConfigArgs * c)4177 config_updateref(ConfigArgs *c) {
4178 struct berval val;
4179 if (c->op == SLAP_CONFIG_EMIT) {
4180 if ( c->be->be_update_refs ) {
4181 value_add( &c->rvalue_vals, c->be->be_update_refs );
4182 return 0;
4183 } else {
4184 return 1;
4185 }
4186 } else if ( c->op == LDAP_MOD_DELETE ) {
4187 if ( c->valx < 0 ) {
4188 ber_bvarray_free( c->be->be_update_refs );
4189 c->be->be_update_refs = NULL;
4190 } else {
4191 int i = c->valx;
4192 ch_free( c->be->be_update_refs[i].bv_val );
4193 for (; c->be->be_update_refs[i].bv_val; i++)
4194 c->be->be_update_refs[i] = c->be->be_update_refs[i+1];
4195 }
4196 return 0;
4197 }
4198 if(!SLAP_SHADOW(c->be) && !c->be->be_syncinfo) {
4199 snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> must appear after syncrepl or updatedn",
4200 c->argv[0] );
4201 Debug(LDAP_DEBUG_ANY, "%s: %s\n",
4202 c->log, c->cr_msg );
4203 return(1);
4204 }
4205
4206 if(validate_global_referral(c->argv[1])) {
4207 snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> invalid URL", c->argv[0] );
4208 Debug(LDAP_DEBUG_ANY, "%s: %s (%s)\n",
4209 c->log, c->cr_msg, c->argv[1]);
4210 return(1);
4211 }
4212 ber_str2bv(c->argv[1], 0, 0, &val);
4213 if(value_add_one(&c->be->be_update_refs, &val)) return(LDAP_OTHER);
4214 return(0);
4215 }
4216
4217 static int
config_obsolete(ConfigArgs * c)4218 config_obsolete(ConfigArgs *c) {
4219 if (c->op == SLAP_CONFIG_EMIT)
4220 return 1;
4221
4222 snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> keyword is obsolete (ignored)",
4223 c->argv[0] );
4224 Debug(LDAP_DEBUG_ANY, "%s: %s\n", c->log, c->cr_msg );
4225 return(0);
4226 }
4227
4228 static int
config_include(ConfigArgs * c)4229 config_include(ConfigArgs *c) {
4230 int savelineno = c->lineno;
4231 int rc;
4232 ConfigFile *cf;
4233 ConfigFile *cfsave = cfn;
4234 ConfigFile *cf2 = NULL;
4235
4236 /* Leftover from RE23. No dynamic config for include files */
4237 if ( c->op == SLAP_CONFIG_EMIT || c->op == LDAP_MOD_DELETE )
4238 return 1;
4239
4240 cf = ch_calloc( 1, sizeof(ConfigFile));
4241 if ( cfn->c_kids ) {
4242 for (cf2=cfn->c_kids; cf2 && cf2->c_sibs; cf2=cf2->c_sibs) ;
4243 cf2->c_sibs = cf;
4244 } else {
4245 cfn->c_kids = cf;
4246 }
4247 cfn = cf;
4248 ber_str2bv( c->argv[1], 0, 1, &cf->c_file );
4249 rc = read_config_file(c->argv[1], c->depth + 1, c, config_back_cf_table);
4250 c->lineno = savelineno - 1;
4251 cfn = cfsave;
4252 if ( rc ) {
4253 if ( cf2 ) cf2->c_sibs = NULL;
4254 else cfn->c_kids = NULL;
4255 ch_free( cf->c_file.bv_val );
4256 ch_free( cf );
4257 } else {
4258 c->ca_private = cf;
4259 }
4260 return(rc);
4261 }
4262
4263 #ifdef HAVE_TLS
4264 static int
config_tls_cleanup(ConfigArgs * c)4265 config_tls_cleanup(ConfigArgs *c) {
4266 int rc = 0;
4267
4268 if ( slap_tls_ld ) {
4269 int opt = 1;
4270
4271 ldap_pvt_tls_ctx_free( slap_tls_ctx );
4272 slap_tls_ctx = NULL;
4273
4274 /* Force new ctx to be created */
4275 rc = ldap_pvt_tls_set_option( slap_tls_ld, LDAP_OPT_X_TLS_NEWCTX, &opt );
4276 if( rc == 0 ) {
4277 /* The ctx's refcount is bumped up here */
4278 ldap_pvt_tls_get_option( slap_tls_ld, LDAP_OPT_X_TLS_CTX, &slap_tls_ctx );
4279 /* This is a no-op if it's already loaded */
4280 load_extop( &slap_EXOP_START_TLS, 0, starttls_extop );
4281 } else {
4282 if ( rc == LDAP_NOT_SUPPORTED )
4283 rc = LDAP_UNWILLING_TO_PERFORM;
4284 else
4285 rc = LDAP_OTHER;
4286 }
4287 }
4288 return rc;
4289 }
4290
4291 static int
config_tls_option(ConfigArgs * c)4292 config_tls_option(ConfigArgs *c) {
4293 int flag, rc;
4294 int berval = 0;
4295 LDAP *ld = slap_tls_ld;
4296 switch(c->type) {
4297 case CFG_TLS_RAND: flag = LDAP_OPT_X_TLS_RANDOM_FILE; ld = NULL; break;
4298 case CFG_TLS_CIPHER: flag = LDAP_OPT_X_TLS_CIPHER_SUITE; break;
4299 case CFG_TLS_CERT_FILE: flag = LDAP_OPT_X_TLS_CERTFILE; break;
4300 case CFG_TLS_CERT_KEY: flag = LDAP_OPT_X_TLS_KEYFILE; break;
4301 case CFG_TLS_CA_PATH: flag = LDAP_OPT_X_TLS_CACERTDIR; break;
4302 case CFG_TLS_CA_FILE: flag = LDAP_OPT_X_TLS_CACERTFILE; break;
4303 case CFG_TLS_DH_FILE: flag = LDAP_OPT_X_TLS_DHFILE; break;
4304 case CFG_TLS_ECNAME: flag = LDAP_OPT_X_TLS_ECNAME; break;
4305 #ifdef HAVE_GNUTLS
4306 case CFG_TLS_CRL_FILE: flag = LDAP_OPT_X_TLS_CRLFILE; break;
4307 #endif
4308 case CFG_TLS_CACERT: flag = LDAP_OPT_X_TLS_CACERT; berval = 1; break;
4309 case CFG_TLS_CERT: flag = LDAP_OPT_X_TLS_CERT; berval = 1; break;
4310 case CFG_TLS_KEY: flag = LDAP_OPT_X_TLS_KEY; berval = 1; break;
4311 default: Debug(LDAP_DEBUG_ANY, "%s: "
4312 "unknown tls_option <0x%x>\n",
4313 c->log, c->type );
4314 return 1;
4315 }
4316 if (c->op == SLAP_CONFIG_EMIT) {
4317 return ldap_pvt_tls_get_option( ld, flag, berval ? (void *)&c->value_bv : (void *)&c->value_string );
4318 } else if ( c->op == LDAP_MOD_DELETE ) {
4319 config_push_cleanup( c, config_tls_cleanup );
4320 return ldap_pvt_tls_set_option( ld, flag, NULL );
4321 }
4322 if ( !berval ) ch_free(c->value_string);
4323 config_push_cleanup( c, config_tls_cleanup );
4324 rc = ldap_pvt_tls_set_option(ld, flag, berval ? (void *)&c->value_bv : (void *)c->argv[1]);
4325 if ( berval ) ch_free(c->value_bv.bv_val);
4326 return rc;
4327 }
4328
4329 /* FIXME: this ought to be provided by libldap */
4330 static int
config_tls_config(ConfigArgs * c)4331 config_tls_config(ConfigArgs *c) {
4332 int i, flag;
4333 switch(c->type) {
4334 case CFG_TLS_CRLCHECK: flag = LDAP_OPT_X_TLS_CRLCHECK; break;
4335 case CFG_TLS_VERIFY: flag = LDAP_OPT_X_TLS_REQUIRE_CERT; break;
4336 case CFG_TLS_PROTOCOL_MIN: flag = LDAP_OPT_X_TLS_PROTOCOL_MIN; break;
4337 default:
4338 Debug(LDAP_DEBUG_ANY, "%s: "
4339 "unknown tls_option <0x%x>\n",
4340 c->log, c->type );
4341 return 1;
4342 }
4343 if (c->op == SLAP_CONFIG_EMIT) {
4344 return slap_tls_get_config( slap_tls_ld, flag, &c->value_string );
4345 } else if ( c->op == LDAP_MOD_DELETE ) {
4346 int i = 0;
4347 config_push_cleanup( c, config_tls_cleanup );
4348 return ldap_pvt_tls_set_option( slap_tls_ld, flag, &i );
4349 }
4350 ch_free( c->value_string );
4351 config_push_cleanup( c, config_tls_cleanup );
4352 if ( isdigit( (unsigned char)c->argv[1][0] ) && c->type != CFG_TLS_PROTOCOL_MIN ) {
4353 if ( lutil_atoi( &i, c->argv[1] ) != 0 ) {
4354 Debug(LDAP_DEBUG_ANY, "%s: "
4355 "unable to parse %s \"%s\"\n",
4356 c->log, c->argv[0], c->argv[1] );
4357 return 1;
4358 }
4359 return(ldap_pvt_tls_set_option(slap_tls_ld, flag, &i));
4360 } else {
4361 return(ldap_pvt_tls_config(slap_tls_ld, flag, c->argv[1]));
4362 }
4363 }
4364 #endif
4365
4366 static CfEntryInfo *
config_find_base(CfEntryInfo * root,struct berval * dn,CfEntryInfo ** last)4367 config_find_base( CfEntryInfo *root, struct berval *dn, CfEntryInfo **last )
4368 {
4369 struct berval cdn;
4370 char *c;
4371
4372 if ( !root ) {
4373 *last = NULL;
4374 return NULL;
4375 }
4376
4377 if ( dn_match( &root->ce_entry->e_nname, dn ))
4378 return root;
4379
4380 c = dn->bv_val+dn->bv_len;
4381 for (;*c != ',';c--);
4382
4383 while(root) {
4384 *last = root;
4385 for (--c;c>dn->bv_val && *c != ',';c--);
4386 cdn.bv_val = c;
4387 if ( *c == ',' )
4388 cdn.bv_val++;
4389 cdn.bv_len = dn->bv_len - (cdn.bv_val - dn->bv_val);
4390
4391 root = root->ce_kids;
4392
4393 for (;root;root=root->ce_sibs) {
4394 if ( dn_match( &root->ce_entry->e_nname, &cdn )) {
4395 if ( cdn.bv_val == dn->bv_val ) {
4396 return root;
4397 }
4398 break;
4399 }
4400 }
4401 }
4402 return root;
4403 }
4404
4405 typedef struct setup_cookie {
4406 CfBackInfo *cfb;
4407 ConfigArgs *ca;
4408 Entry *frontend;
4409 Entry *config;
4410 int got_frontend;
4411 int got_config;
4412 } setup_cookie;
4413
4414 static int
config_ldif_resp(Operation * op,SlapReply * rs)4415 config_ldif_resp( Operation *op, SlapReply *rs )
4416 {
4417 if ( rs->sr_type == REP_SEARCH ) {
4418 setup_cookie *sc = op->o_callback->sc_private;
4419 struct berval pdn;
4420
4421 sc->cfb->cb_got_ldif = 1;
4422 /* Does the frontend exist? */
4423 if ( !sc->got_frontend ) {
4424 if ( !strncmp( rs->sr_entry->e_nname.bv_val,
4425 "olcDatabase", STRLENOF( "olcDatabase" )))
4426 {
4427 if ( strncmp( rs->sr_entry->e_nname.bv_val +
4428 STRLENOF( "olcDatabase" ), "={-1}frontend",
4429 STRLENOF( "={-1}frontend" )))
4430 {
4431 struct berval rdn;
4432 int i = op->o_noop;
4433 sc->ca->be = frontendDB;
4434 sc->ca->bi = frontendDB->bd_info;
4435 frontendDB->be_cf_ocs = &CFOC_FRONTEND;
4436 rdn.bv_val = sc->ca->log;
4437 rdn.bv_len = snprintf(rdn.bv_val, sizeof( sc->ca->log ),
4438 "%s=" SLAP_X_ORDERED_FMT "%s",
4439 cfAd_database->ad_cname.bv_val, -1,
4440 sc->ca->bi->bi_type);
4441 op->o_noop = 1;
4442 sc->frontend = config_build_entry( op, rs,
4443 sc->cfb->cb_root, sc->ca, &rdn, &CFOC_DATABASE,
4444 sc->ca->be->be_cf_ocs );
4445 op->o_noop = i;
4446 sc->got_frontend++;
4447 } else {
4448 sc->got_frontend++;
4449 goto ok;
4450 }
4451 }
4452 }
4453
4454 dnParent( &rs->sr_entry->e_nname, &pdn );
4455
4456 /* Does the configDB exist? */
4457 if ( sc->got_frontend && !sc->got_config &&
4458 !strncmp( rs->sr_entry->e_nname.bv_val,
4459 "olcDatabase", STRLENOF( "olcDatabase" )) &&
4460 dn_match( &config_rdn, &pdn ) )
4461 {
4462 if ( strncmp( rs->sr_entry->e_nname.bv_val +
4463 STRLENOF( "olcDatabase" ), "={0}config",
4464 STRLENOF( "={0}config" )))
4465 {
4466 struct berval rdn;
4467 int i = op->o_noop;
4468 sc->ca->be = LDAP_STAILQ_FIRST( &backendDB );
4469 sc->ca->bi = sc->ca->be->bd_info;
4470 rdn.bv_val = sc->ca->log;
4471 rdn.bv_len = snprintf(rdn.bv_val, sizeof( sc->ca->log ),
4472 "%s=" SLAP_X_ORDERED_FMT "%s",
4473 cfAd_database->ad_cname.bv_val, 0,
4474 sc->ca->bi->bi_type);
4475 op->o_noop = 1;
4476 sc->config = config_build_entry( op, rs, sc->cfb->cb_root,
4477 sc->ca, &rdn, &CFOC_DATABASE, sc->ca->be->be_cf_ocs );
4478 op->o_noop = i;
4479 }
4480 sc->got_config++;
4481 }
4482
4483 ok:
4484 rs->sr_err = config_add_internal( sc->cfb, rs->sr_entry, sc->ca, NULL, NULL, NULL );
4485 if ( rs->sr_err != LDAP_SUCCESS ) {
4486 Debug( LDAP_DEBUG_ANY, "config error processing %s: %s\n",
4487 rs->sr_entry->e_name.bv_val, sc->ca->cr_msg );
4488 }
4489 }
4490 return rs->sr_err;
4491 }
4492
4493 /* Configure and read the underlying back-ldif store */
4494 static int
config_setup_ldif(BackendDB * be,const char * dir,int readit)4495 config_setup_ldif( BackendDB *be, const char *dir, int readit ) {
4496 CfBackInfo *cfb = be->be_private;
4497 ConfigArgs c = {0};
4498 ConfigTable *ct;
4499 char *argv[3];
4500 int rc = 0;
4501 setup_cookie sc;
4502 slap_callback cb = { NULL, config_ldif_resp, NULL, NULL };
4503 Connection conn = {0};
4504 OperationBuffer opbuf;
4505 Operation *op;
4506 SlapReply rs = {REP_RESULT};
4507 Filter filter = { LDAP_FILTER_PRESENT };
4508 struct berval filterstr = BER_BVC("(objectclass=*)");
4509 struct stat st;
4510
4511 /* Is the config directory available? */
4512 if ( stat( dir, &st ) < 0 ) {
4513 /* No, so don't bother using the backing store.
4514 * All changes will be in-memory only.
4515 */
4516 return 0;
4517 }
4518
4519 cfb->cb_db.bd_info = backend_info( "ldif" );
4520 if ( !cfb->cb_db.bd_info )
4521 return 0; /* FIXME: eventually this will be a fatal error */
4522
4523 if ( backend_db_init( "ldif", &cfb->cb_db, -1, NULL ) == NULL )
4524 return 1;
4525
4526 cfb->cb_db.be_suffix = be->be_suffix;
4527 cfb->cb_db.be_nsuffix = be->be_nsuffix;
4528
4529 /* The suffix is always "cn=config". The underlying DB's rootdn
4530 * is always the same as the suffix.
4531 */
4532 cfb->cb_db.be_rootdn = be->be_suffix[0];
4533 cfb->cb_db.be_rootndn = be->be_nsuffix[0];
4534
4535 ber_str2bv( dir, 0, 1, &cfdir );
4536
4537 c.be = &cfb->cb_db;
4538 c.fname = "slapd";
4539 c.argc = 2;
4540 argv[0] = "directory";
4541 argv[1] = (char *)dir;
4542 argv[2] = NULL;
4543 c.argv = argv;
4544 c.reply.err = 0;
4545 c.reply.msg[0] = 0;
4546 c.table = Cft_Database;
4547
4548 ct = config_find_keyword( c.be->be_cf_ocs->co_table, &c );
4549 if ( !ct )
4550 return 1;
4551
4552 if ( config_add_vals( ct, &c ))
4553 return 1;
4554
4555 if ( backend_startup_one( &cfb->cb_db, &c.reply ))
4556 return 1;
4557
4558 if ( readit ) {
4559 void *thrctx = ldap_pvt_thread_pool_context();
4560 int prev_DN_strict;
4561
4562 connection_fake_init( &conn, &opbuf, thrctx );
4563 op = &opbuf.ob_op;
4564
4565 filter.f_desc = slap_schema.si_ad_objectClass;
4566
4567 op->o_tag = LDAP_REQ_SEARCH;
4568
4569 op->ors_filter = &filter;
4570 op->ors_filterstr = filterstr;
4571 op->ors_scope = LDAP_SCOPE_SUBTREE;
4572
4573 op->o_dn = c.be->be_rootdn;
4574 op->o_ndn = c.be->be_rootndn;
4575
4576 op->o_req_dn = be->be_suffix[0];
4577 op->o_req_ndn = be->be_nsuffix[0];
4578
4579 op->ors_tlimit = SLAP_NO_LIMIT;
4580 op->ors_slimit = SLAP_NO_LIMIT;
4581
4582 op->ors_attrs = slap_anlist_all_attributes;
4583 op->ors_attrsonly = 0;
4584
4585 op->o_callback = &cb;
4586 sc.cfb = cfb;
4587 sc.ca = &c;
4588 cb.sc_private = ≻
4589 sc.got_frontend = 0;
4590 sc.got_config = 0;
4591 sc.frontend = NULL;
4592 sc.config = NULL;
4593
4594 op->o_bd = &cfb->cb_db;
4595
4596 /* Allow unknown attrs in DNs */
4597 prev_DN_strict = slap_DN_strict;
4598 slap_DN_strict = 0;
4599
4600 rc = op->o_bd->be_search( op, &rs );
4601
4602 /* Restore normal DN validation */
4603 slap_DN_strict = prev_DN_strict;
4604
4605 op->o_tag = LDAP_REQ_ADD;
4606 if ( rc == LDAP_SUCCESS && sc.frontend ) {
4607 rs_reinit( &rs, REP_RESULT );
4608 op->ora_e = sc.frontend;
4609 rc = op->o_bd->be_add( op, &rs );
4610 }
4611 if ( rc == LDAP_SUCCESS && sc.config ) {
4612 rs_reinit( &rs, REP_RESULT );
4613 op->ora_e = sc.config;
4614 rc = op->o_bd->be_add( op, &rs );
4615 }
4616 ldap_pvt_thread_pool_context_reset( thrctx );
4617 } else {
4618 /* ITS#9016 Check directory is empty (except perhaps hidden files) */
4619 DIR *dir_of_path;
4620 struct dirent *entry;
4621
4622 dir_of_path = opendir( dir );
4623 while ( (entry = readdir( dir_of_path )) != NULL ) {
4624 if ( entry->d_name[0] != '.' ) {
4625 Debug( LDAP_DEBUG_ANY, "config_setup_ldif: "
4626 "expected directory %s to be empty!\n",
4627 dir );
4628 rc = LDAP_ALREADY_EXISTS;
4629 break;
4630 }
4631 }
4632 closedir( dir_of_path );
4633 }
4634
4635 /* ITS#4194 - only use if it's present, or we're converting. */
4636 if ( !readit || rc == LDAP_SUCCESS )
4637 cfb->cb_use_ldif = 1;
4638
4639 return rc;
4640 }
4641
4642 static int
CfOc_cmp(const void * c1,const void * c2)4643 CfOc_cmp( const void *c1, const void *c2 ) {
4644 const ConfigOCs *co1 = c1;
4645 const ConfigOCs *co2 = c2;
4646
4647 return ber_bvcmp( co1->co_name, co2->co_name );
4648 }
4649
4650 int
config_register_schema(ConfigTable * ct,ConfigOCs * ocs)4651 config_register_schema(ConfigTable *ct, ConfigOCs *ocs) {
4652 int i;
4653
4654 i = init_config_attrs( ct );
4655 if ( i ) return i;
4656
4657 /* set up the objectclasses */
4658 i = init_config_ocs( ocs );
4659 if ( i ) return i;
4660
4661 for (i=0; ocs[i].co_def; i++) {
4662 if ( ocs[i].co_oc ) {
4663 ocs[i].co_name = &ocs[i].co_oc->soc_cname;
4664 if ( !ocs[i].co_table )
4665 ocs[i].co_table = ct;
4666 ldap_avl_insert( &CfOcTree, &ocs[i], CfOc_cmp, ldap_avl_dup_error );
4667 }
4668 }
4669 return 0;
4670 }
4671
4672 int
read_config(const char * fname,const char * dir)4673 read_config(const char *fname, const char *dir) {
4674 BackendDB *be;
4675 CfBackInfo *cfb;
4676 const char *cfdir, *cfname;
4677 int rc;
4678
4679 /* Setup the config backend */
4680 be = backend_db_init( "config", NULL, 0, NULL );
4681 if ( !be )
4682 return 1;
4683
4684 cfb = be->be_private;
4685 be->be_dfltaccess = ACL_NONE;
4686
4687 /* If no .conf, or a dir was specified, setup the dir */
4688 if ( !fname || dir ) {
4689 if ( dir ) {
4690 /* If explicitly given, check for existence */
4691 struct stat st;
4692
4693 if ( stat( dir, &st ) < 0 ) {
4694 int saved_errno = errno;
4695 Debug( LDAP_DEBUG_ANY,
4696 "invalid config directory %s, error %d\n",
4697 dir, saved_errno );
4698 return 1;
4699 }
4700 cfdir = dir;
4701 } else {
4702 cfdir = SLAPD_DEFAULT_CONFIGDIR;
4703 }
4704 /* if fname is defaulted, try reading .d */
4705 rc = config_setup_ldif( be, cfdir, !fname );
4706
4707 if ( rc ) {
4708 /* It may be OK if the base object doesn't exist yet. */
4709 if ( rc != LDAP_NO_SUCH_OBJECT )
4710 return 1;
4711 /* ITS#4194: But if dir was specified and no fname,
4712 * then we were supposed to read the dir. Unless we're
4713 * trying to slapadd the dir...
4714 */
4715 if ( dir && !fname ) {
4716 if ( slapMode & (SLAP_SERVER_MODE|SLAP_TOOL_READMAIN|SLAP_TOOL_READONLY))
4717 return 1;
4718 /* Assume it's slapadd with a config dir, let it continue */
4719 rc = 0;
4720 cfb->cb_got_ldif = 1;
4721 cfb->cb_use_ldif = 1;
4722 goto done;
4723 }
4724 }
4725
4726 /* If we read the config from back-ldif, nothing to do here */
4727 if ( cfb->cb_got_ldif ) {
4728 rc = 0;
4729 goto done;
4730 }
4731 }
4732
4733 if ( fname )
4734 cfname = fname;
4735 else
4736 cfname = SLAPD_DEFAULT_CONFIGFILE;
4737
4738 rc = read_config_file(cfname, 0, NULL, config_back_cf_table);
4739
4740 if ( rc == 0 )
4741 ber_str2bv( cfname, 0, 1, &cfb->cb_config->c_file );
4742
4743 done:
4744 if ( rc == 0 && BER_BVISNULL( &frontendDB->be_schemadn ) ) {
4745 ber_str2bv( SLAPD_SCHEMA_DN, STRLENOF( SLAPD_SCHEMA_DN ), 1,
4746 &frontendDB->be_schemadn );
4747 rc = dnNormalize( 0, NULL, NULL, &frontendDB->be_schemadn, &frontendDB->be_schemandn, NULL );
4748 if ( rc != LDAP_SUCCESS ) {
4749 Debug(LDAP_DEBUG_ANY, "read_config: "
4750 "unable to normalize default schema DN \"%s\"\n",
4751 frontendDB->be_schemadn.bv_val );
4752 /* must not happen */
4753 assert( 0 );
4754 }
4755 }
4756 if ( rc == 0 && ( slapMode & SLAP_SERVER_MODE ) && sid_list ) {
4757 if ( !BER_BVISEMPTY( &sid_list->si_url ) && !sid_set ) {
4758 Debug(LDAP_DEBUG_ANY, "read_config: no serverID / URL match found. "
4759 "Check slapd -h arguments.\n" );
4760 rc = LDAP_OTHER;
4761 }
4762 }
4763 return rc;
4764 }
4765
4766 static int
config_back_bind(Operation * op,SlapReply * rs)4767 config_back_bind( Operation *op, SlapReply *rs )
4768 {
4769 if ( be_isroot_pw( op ) ) {
4770 ber_dupbv( &op->orb_edn, be_root_dn( op->o_bd ));
4771 /* frontend sends result */
4772 return LDAP_SUCCESS;
4773 }
4774
4775 rs->sr_err = LDAP_INVALID_CREDENTIALS;
4776 send_ldap_result( op, rs );
4777
4778 return rs->sr_err;
4779 }
4780
4781 static int
config_send(Operation * op,SlapReply * rs,CfEntryInfo * ce,int depth)4782 config_send( Operation *op, SlapReply *rs, CfEntryInfo *ce, int depth )
4783 {
4784 int rc = 0;
4785
4786 if ( test_filter( op, ce->ce_entry, op->ors_filter ) == LDAP_COMPARE_TRUE )
4787 {
4788 rs->sr_attrs = op->ors_attrs;
4789 rs->sr_entry = ce->ce_entry;
4790 rs->sr_flags = 0;
4791 rc = send_search_entry( op, rs );
4792 if ( rc != LDAP_SUCCESS ) {
4793 return rc;
4794 }
4795 }
4796 if ( op->ors_scope == LDAP_SCOPE_SUBTREE ) {
4797 if ( ce->ce_kids ) {
4798 rc = config_send( op, rs, ce->ce_kids, 1 );
4799 if ( rc ) return rc;
4800 }
4801 if ( depth ) {
4802 for (ce=ce->ce_sibs; ce; ce=ce->ce_sibs) {
4803 rc = config_send( op, rs, ce, 0 );
4804 if ( rc ) break;
4805 }
4806 }
4807 }
4808 return rc;
4809 }
4810
4811 static ConfigTable *
config_find_table(ConfigOCs ** colst,int nocs,AttributeDescription * ad,ConfigArgs * ca)4812 config_find_table( ConfigOCs **colst, int nocs, AttributeDescription *ad,
4813 ConfigArgs *ca )
4814 {
4815 int i, j;
4816 if (ad->ad_flags & SLAP_DESC_BINARY)
4817 ad = ad->ad_type->sat_ad;
4818
4819 for (j=0; j<nocs; j++) {
4820 for (i=0; colst[j]->co_table[i].name; i++)
4821 if ( colst[j]->co_table[i].ad == ad ) {
4822 ca->table = colst[j]->co_type;
4823 return &colst[j]->co_table[i];
4824 }
4825 }
4826 return NULL;
4827 }
4828
4829 /* Sort the attributes of the entry according to the order defined
4830 * in the objectclass, with required attributes occurring before
4831 * allowed attributes. For any attributes with sequencing dependencies
4832 * (e.g., rootDN must be defined after suffix) the objectclass must
4833 * list the attributes in the desired sequence.
4834 */
4835 static void
sort_attrs(Entry * e,ConfigOCs ** colst,int nocs)4836 sort_attrs( Entry *e, ConfigOCs **colst, int nocs )
4837 {
4838 Attribute *a, *head = NULL, *tail = NULL, **prev;
4839 int i, j;
4840
4841 for (i=0; i<nocs; i++) {
4842 if ( colst[i]->co_oc->soc_required ) {
4843 AttributeType **at = colst[i]->co_oc->soc_required;
4844 for (j=0; at[j]; j++) {
4845 for (a=e->e_attrs, prev=&e->e_attrs; a;
4846 prev = &(*prev)->a_next, a=a->a_next) {
4847 if ( a->a_desc == at[j]->sat_ad ) {
4848 *prev = a->a_next;
4849 if (!head) {
4850 head = a;
4851 tail = a;
4852 } else {
4853 tail->a_next = a;
4854 tail = a;
4855 }
4856 break;
4857 }
4858 }
4859 }
4860 }
4861 if ( colst[i]->co_oc->soc_allowed ) {
4862 AttributeType **at = colst[i]->co_oc->soc_allowed;
4863 for (j=0; at[j]; j++) {
4864 for (a=e->e_attrs, prev=&e->e_attrs; a;
4865 prev = &(*prev)->a_next, a=a->a_next) {
4866 if ( a->a_desc == at[j]->sat_ad ) {
4867 *prev = a->a_next;
4868 if (!head) {
4869 head = a;
4870 tail = a;
4871 } else {
4872 tail->a_next = a;
4873 tail = a;
4874 }
4875 break;
4876 }
4877 }
4878 }
4879 }
4880 }
4881 if ( tail ) {
4882 tail->a_next = e->e_attrs;
4883 e->e_attrs = head;
4884 }
4885 }
4886
4887 static int
check_vals(ConfigTable * ct,ConfigArgs * ca,void * ptr,int isAttr)4888 check_vals( ConfigTable *ct, ConfigArgs *ca, void *ptr, int isAttr )
4889 {
4890 Attribute *a = NULL;
4891 AttributeDescription *ad;
4892 BerVarray vals;
4893
4894 int i, rc = 0;
4895
4896 if ( isAttr ) {
4897 a = ptr;
4898 ad = a->a_desc;
4899 vals = a->a_vals;
4900 } else {
4901 Modifications *ml = ptr;
4902 ad = ml->sml_desc;
4903 vals = ml->sml_values;
4904 }
4905
4906 if ( a && ( ad->ad_type->sat_flags & SLAP_AT_ORDERED_VAL )) {
4907 rc = ordered_value_sort( a, 1 );
4908 if ( rc ) {
4909 snprintf(ca->cr_msg, sizeof( ca->cr_msg ), "ordered_value_sort failed on attr %s\n",
4910 ad->ad_cname.bv_val );
4911 return rc;
4912 }
4913 }
4914 for ( i=0; vals[i].bv_val; i++ ) {
4915 ca->line = vals[i].bv_val;
4916 ca->linelen = vals[i].bv_len;
4917 if (( ad->ad_type->sat_flags & SLAP_AT_ORDERED_VAL ) &&
4918 ca->line[0] == '{' ) {
4919 char *idx = strchr( ca->line, '}' );
4920 if ( idx ) {
4921 ca->linelen -= (idx+1) - ca->line;
4922 ca->line = idx+1;
4923 }
4924 }
4925 rc = config_parse_vals( ct, ca, i );
4926 if ( rc ) {
4927 break;
4928 }
4929 }
4930 return rc;
4931 }
4932
4933 static int
config_rename_attr(SlapReply * rs,Entry * e,struct berval * rdn,Attribute ** at)4934 config_rename_attr( SlapReply *rs, Entry *e, struct berval *rdn,
4935 Attribute **at )
4936 {
4937 struct berval rtype, rval;
4938 Attribute *a;
4939 AttributeDescription *ad = NULL;
4940
4941 dnRdn( &e->e_name, rdn );
4942 rval.bv_val = strchr(rdn->bv_val, '=' ) + 1;
4943 rval.bv_len = rdn->bv_len - (rval.bv_val - rdn->bv_val);
4944 rtype.bv_val = rdn->bv_val;
4945 rtype.bv_len = rval.bv_val - rtype.bv_val - 1;
4946
4947 /* Find attr */
4948 slap_bv2ad( &rtype, &ad, &rs->sr_text );
4949 a = attr_find( e->e_attrs, ad );
4950 if (!a ) return LDAP_NAMING_VIOLATION;
4951 *at = a;
4952
4953 return 0;
4954 }
4955
4956 static void
config_rename_kids(CfEntryInfo * ce)4957 config_rename_kids( CfEntryInfo *ce )
4958 {
4959 CfEntryInfo *ce2;
4960 struct berval rdn, nrdn;
4961
4962 for (ce2 = ce->ce_kids; ce2; ce2 = ce2->ce_sibs) {
4963 struct berval newdn, newndn;
4964 dnRdn ( &ce2->ce_entry->e_name, &rdn );
4965 dnRdn ( &ce2->ce_entry->e_nname, &nrdn );
4966 build_new_dn( &newdn, &ce->ce_entry->e_name, &rdn, NULL );
4967 build_new_dn( &newndn, &ce->ce_entry->e_nname, &nrdn, NULL );
4968 free( ce2->ce_entry->e_name.bv_val );
4969 free( ce2->ce_entry->e_nname.bv_val );
4970 ce2->ce_entry->e_name = newdn;
4971 ce2->ce_entry->e_nname = newndn;
4972 config_rename_kids( ce2 );
4973 }
4974 }
4975
4976 static int
config_rename_one(Operation * op,SlapReply * rs,Entry * e,CfEntryInfo * parent,Attribute * a,struct berval * newrdn,struct berval * nnewrdn,int use_ldif)4977 config_rename_one( Operation *op, SlapReply *rs, Entry *e,
4978 CfEntryInfo *parent, Attribute *a, struct berval *newrdn,
4979 struct berval *nnewrdn, int use_ldif )
4980 {
4981 int cnt, rc = 0;
4982 struct berval odn, ondn;
4983 const char *text = "";
4984 LDAPRDN rDN;
4985
4986 odn = e->e_name;
4987 ondn = e->e_nname;
4988 build_new_dn( &e->e_name, &parent->ce_entry->e_name, newrdn, NULL );
4989 build_new_dn( &e->e_nname, &parent->ce_entry->e_nname, nnewrdn, NULL );
4990
4991 /* Replace attr */
4992 rc = ldap_bv2rdn( &e->e_name, &rDN, (char **)&text, LDAP_DN_FORMAT_LDAP );
4993 if ( rc ) {
4994 return rc;
4995 }
4996 for ( cnt = 0; rDN[cnt]; cnt++ ) {
4997 AttributeDescription *ad = NULL;
4998 LDAPAVA *ava = rDN[cnt];
4999
5000 rc = slap_bv2ad( &ava->la_attr, &ad, &text );
5001 if ( rc ) {
5002 break;
5003 }
5004
5005 if ( ad != a->a_desc ) continue;
5006
5007 free( a->a_vals[0].bv_val );
5008 ber_dupbv( &a->a_vals[0], &ava->la_value );
5009 if ( a->a_nvals != a->a_vals ) {
5010 free( a->a_nvals[0].bv_val );
5011 rc = attr_normalize_one( ad, &ava->la_value, &a->a_nvals[0], NULL );
5012 if ( rc ) {
5013 break;
5014 }
5015 }
5016
5017 /* attributes with X-ORDERED 'SIBLINGS' are single-valued, we're done */
5018 break;
5019 }
5020 /* the attribute must be present in rDN */
5021 assert( rDN[cnt] );
5022 ldap_rdnfree( rDN );
5023 if ( rc ) {
5024 return rc;
5025 }
5026
5027 if ( use_ldif ) {
5028 CfBackInfo *cfb = (CfBackInfo *)op->o_bd->be_private;
5029 BackendDB *be = op->o_bd;
5030 slap_callback sc = { NULL, slap_null_cb, NULL, NULL }, *scp;
5031 struct berval dn, ndn, xdn, xndn;
5032
5033 op->o_bd = &cfb->cb_db;
5034
5035 /* Save current rootdn; use the underlying DB's rootdn */
5036 dn = op->o_dn;
5037 ndn = op->o_ndn;
5038 xdn = op->o_req_dn;
5039 xndn = op->o_req_ndn;
5040 op->o_dn = op->o_bd->be_rootdn;
5041 op->o_ndn = op->o_bd->be_rootndn;
5042 op->o_req_dn = odn;
5043 op->o_req_ndn = ondn;
5044
5045 scp = op->o_callback;
5046 op->o_callback = ≻
5047 op->orr_newrdn = *newrdn;
5048 op->orr_nnewrdn = *nnewrdn;
5049 op->orr_newSup = NULL;
5050 op->orr_nnewSup = NULL;
5051 op->orr_deleteoldrdn = 1;
5052 op->orr_modlist = NULL;
5053 slap_modrdn2mods( op, rs );
5054 slap_mods_opattrs( op, &op->orr_modlist, 1 );
5055 rc = op->o_bd->be_modrdn( op, rs );
5056 slap_mods_free( op->orr_modlist, 1 );
5057
5058 op->o_bd = be;
5059 op->o_callback = scp;
5060 op->o_dn = dn;
5061 op->o_ndn = ndn;
5062 op->o_req_dn = xdn;
5063 op->o_req_ndn = xndn;
5064 }
5065 free( odn.bv_val );
5066 free( ondn.bv_val );
5067 if ( e->e_private )
5068 config_rename_kids( e->e_private );
5069 return rc;
5070 }
5071
5072 static int
config_renumber_one(Operation * op,SlapReply * rs,CfEntryInfo * parent,Entry * e,int idx,int tailindex,int use_ldif)5073 config_renumber_one( Operation *op, SlapReply *rs, CfEntryInfo *parent,
5074 Entry *e, int idx, int tailindex, int use_ldif )
5075 {
5076 struct berval ival, newrdn, nnewrdn;
5077 struct berval rdn;
5078 Attribute *a;
5079 char ibuf[32], *ptr1, *ptr2 = NULL;
5080 int rc = 0;
5081
5082 rc = config_rename_attr( rs, e, &rdn, &a );
5083 if ( rc ) return rc;
5084
5085 ival.bv_val = ibuf;
5086 ival.bv_len = snprintf( ibuf, sizeof( ibuf ), SLAP_X_ORDERED_FMT, idx );
5087 if ( ival.bv_len >= sizeof( ibuf ) ) {
5088 return LDAP_NAMING_VIOLATION;
5089 }
5090
5091 newrdn.bv_len = rdn.bv_len + ival.bv_len;
5092 newrdn.bv_val = ch_malloc( newrdn.bv_len+1 );
5093
5094 if ( tailindex ) {
5095 ptr1 = lutil_strncopy( newrdn.bv_val, rdn.bv_val, rdn.bv_len );
5096 ptr1 = lutil_strcopy( ptr1, ival.bv_val );
5097 } else {
5098 int xlen;
5099 ptr2 = ber_bvchr( &rdn, '}' );
5100 if ( ptr2 ) {
5101 ptr2++;
5102 } else {
5103 ptr2 = rdn.bv_val + a->a_desc->ad_cname.bv_len + 1;
5104 }
5105 xlen = rdn.bv_len - (ptr2 - rdn.bv_val);
5106 ptr1 = lutil_strncopy( newrdn.bv_val, a->a_desc->ad_cname.bv_val,
5107 a->a_desc->ad_cname.bv_len );
5108 *ptr1++ = '=';
5109 ptr1 = lutil_strcopy( ptr1, ival.bv_val );
5110 ptr1 = lutil_strncopy( ptr1, ptr2, xlen );
5111 *ptr1 = '\0';
5112 }
5113
5114 /* Do the equivalent of ModRDN */
5115 /* Replace DN / NDN */
5116 newrdn.bv_len = ptr1 - newrdn.bv_val;
5117 rc = rdnNormalize( 0, NULL, NULL, &newrdn, &nnewrdn, NULL );
5118 if ( rc ) {
5119 free( newrdn.bv_val );
5120 return LDAP_NAMING_VIOLATION;
5121 }
5122 rc = config_rename_one( op, rs, e, parent, a, &newrdn, &nnewrdn, use_ldif );
5123
5124 free( nnewrdn.bv_val );
5125 free( newrdn.bv_val );
5126 return rc;
5127 }
5128
5129 static int
check_name_index(CfEntryInfo * parent,ConfigType ce_type,Entry * e,SlapReply * rs,int * renum,int * ibase)5130 check_name_index( CfEntryInfo *parent, ConfigType ce_type, Entry *e,
5131 SlapReply *rs, int *renum, int *ibase )
5132 {
5133 CfEntryInfo *ce;
5134 int index = -1, gotindex = 0, nsibs, rc = 0;
5135 int renumber = 0, tailindex = 0, isfrontend = 0, isconfig = 0;
5136 char *ptr1, *ptr2 = NULL;
5137 struct berval rdn;
5138
5139 if ( renum ) *renum = 0;
5140
5141 /* These entries don't get indexed/renumbered */
5142 if ( ce_type == Cft_Global ) return 0;
5143 if ( ce_type == Cft_Schema && parent->ce_type == Cft_Global ) return 0;
5144
5145 if ( ce_type == Cft_Module )
5146 tailindex = 1;
5147
5148 /* See if the rdn has an index already */
5149 dnRdn( &e->e_name, &rdn );
5150 if ( ce_type == Cft_Database ) {
5151 if ( !strncmp( rdn.bv_val + rdn.bv_len - STRLENOF("frontend"),
5152 "frontend", STRLENOF("frontend") ))
5153 isfrontend = 1;
5154 else if ( !strncmp( rdn.bv_val + rdn.bv_len - STRLENOF("config"),
5155 "config", STRLENOF("config") ))
5156 isconfig = 1;
5157 }
5158 ptr1 = ber_bvchr( &e->e_name, '{' );
5159 if ( ptr1 && ptr1 < &e->e_name.bv_val[ rdn.bv_len ] ) {
5160 char *next;
5161 ptr2 = strchr( ptr1, '}' );
5162 if ( !ptr2 || ptr2 > &e->e_name.bv_val[ rdn.bv_len ] )
5163 return LDAP_NAMING_VIOLATION;
5164 if ( ptr2-ptr1 == 1)
5165 return LDAP_NAMING_VIOLATION;
5166 gotindex = 1;
5167 index = strtol( ptr1 + 1, &next, 10 );
5168 if ( next == ptr1 + 1 || next[ 0 ] != '}' ) {
5169 return LDAP_NAMING_VIOLATION;
5170 }
5171 if ( index < 0 ) {
5172 /* Special case, we allow -1 for the frontendDB */
5173 if ( index != -1 || !isfrontend )
5174 return LDAP_NAMING_VIOLATION;
5175 }
5176 if ( isconfig && index != 0 ){
5177 return LDAP_NAMING_VIOLATION;
5178 }
5179 }
5180
5181 /* count related kids.
5182 * For entries of type Cft_Misc, only count siblings with same RDN type
5183 */
5184 if ( ce_type == Cft_Misc ) {
5185 rdn.bv_val = e->e_nname.bv_val;
5186 ptr1 = strchr( rdn.bv_val, '=' );
5187 assert( ptr1 != NULL );
5188
5189 rdn.bv_len = ptr1 - rdn.bv_val;
5190
5191 for (nsibs=0, ce=parent->ce_kids; ce; ce=ce->ce_sibs) {
5192 struct berval rdn2;
5193 if ( ce->ce_type != ce_type )
5194 continue;
5195
5196 dnRdn( &ce->ce_entry->e_nname, &rdn2 );
5197
5198 ptr1 = strchr( rdn2.bv_val, '=' );
5199 assert( ptr1 != NULL );
5200
5201 rdn2.bv_len = ptr1 - rdn2.bv_val;
5202 if ( bvmatch( &rdn, &rdn2 ))
5203 nsibs++;
5204 }
5205 } else {
5206 for (nsibs=0, ce=parent->ce_kids; ce; ce=ce->ce_sibs) {
5207 if ( ce->ce_type == ce_type ) nsibs++;
5208 }
5209 }
5210
5211 /* account for -1 frontend */
5212 if ( ce_type == Cft_Database )
5213 nsibs--;
5214
5215 if ( index != nsibs || isfrontend ) {
5216 if ( gotindex ) {
5217 if ( index < nsibs ) {
5218 if ( tailindex ) return LDAP_NAMING_VIOLATION;
5219 /* Siblings need to be renumbered */
5220 if ( index != -1 || !isfrontend )
5221 renumber = 1;
5222 }
5223 }
5224 /* config DB is always "0" */
5225 if ( isconfig && index == -1 ) {
5226 index = 0;
5227 }
5228 if (( !isfrontend && index == -1 ) || ( index > nsibs ) ){
5229 index = nsibs;
5230 }
5231
5232 /* just make index = nsibs */
5233 if ( !renumber ) {
5234 rc = config_renumber_one( NULL, rs, parent, e, index, tailindex, 0 );
5235 }
5236 }
5237 if ( ibase ) *ibase = index;
5238 if ( renum ) *renum = renumber;
5239 return rc;
5240 }
5241
5242 /* Insert all superior classes of the given class */
5243 static int
count_oc(ObjectClass * oc,ConfigOCs *** copp,int * nocs)5244 count_oc( ObjectClass *oc, ConfigOCs ***copp, int *nocs )
5245 {
5246 ConfigOCs co, *cop;
5247 ObjectClass **sups;
5248
5249 for ( sups = oc->soc_sups; sups && *sups; sups++ ) {
5250 if ( count_oc( *sups, copp, nocs ) ) {
5251 return -1;
5252 }
5253 }
5254
5255 co.co_name = &oc->soc_cname;
5256 cop = ldap_avl_find( CfOcTree, &co, CfOc_cmp );
5257 if ( cop ) {
5258 int i;
5259
5260 /* check for duplicates */
5261 for ( i = 0; i < *nocs; i++ ) {
5262 if ( *copp && (*copp)[i] == cop ) {
5263 break;
5264 }
5265 }
5266
5267 if ( i == *nocs ) {
5268 ConfigOCs **tmp = ch_realloc( *copp, (*nocs + 1)*sizeof( ConfigOCs * ) );
5269 if ( tmp == NULL ) {
5270 return -1;
5271 }
5272 *copp = tmp;
5273 (*copp)[*nocs] = cop;
5274 (*nocs)++;
5275 }
5276 }
5277
5278 return 0;
5279 }
5280
5281 /* Find all superior classes of the given objectclasses,
5282 * return list in order of most-subordinate first.
5283 *
5284 * Special / auxiliary / Cft_Misc classes always take precedence.
5285 */
5286 static ConfigOCs **
count_ocs(Attribute * oc_at,int * nocs)5287 count_ocs( Attribute *oc_at, int *nocs )
5288 {
5289 int i, j, misc = -1;
5290 ConfigOCs **colst = NULL;
5291
5292 *nocs = 0;
5293
5294 for ( i = oc_at->a_numvals; i--; ) {
5295 ObjectClass *oc = oc_bvfind( &oc_at->a_nvals[i] );
5296
5297 assert( oc != NULL );
5298 if ( count_oc( oc, &colst, nocs ) ) {
5299 ch_free( colst );
5300 return NULL;
5301 }
5302 }
5303
5304 /* invert order */
5305 i = 0;
5306 j = *nocs - 1;
5307 while ( i < j ) {
5308 ConfigOCs *tmp = colst[i];
5309 colst[i] = colst[j];
5310 colst[j] = tmp;
5311 if (tmp->co_type == Cft_Misc)
5312 misc = j;
5313 i++; j--;
5314 }
5315 /* Move misc class to front of list */
5316 if (misc > 0) {
5317 ConfigOCs *tmp = colst[misc];
5318 for (i=misc; i>0; i--)
5319 colst[i] = colst[i-1];
5320 colst[0] = tmp;
5321 }
5322
5323 return colst;
5324 }
5325
5326 static int
cfAddInclude(CfEntryInfo * p,Entry * e,ConfigArgs * ca)5327 cfAddInclude( CfEntryInfo *p, Entry *e, ConfigArgs *ca )
5328 {
5329 /* Leftover from RE23. Never parse this entry */
5330 return LDAP_COMPARE_TRUE;
5331 }
5332
5333 static int
cfAddSchema(CfEntryInfo * p,Entry * e,ConfigArgs * ca)5334 cfAddSchema( CfEntryInfo *p, Entry *e, ConfigArgs *ca )
5335 {
5336 ConfigFile *cfo;
5337
5338 /* This entry is hardcoded, don't re-parse it */
5339 if ( p->ce_type == Cft_Global ) {
5340 cfn = p->ce_private;
5341 ca->ca_private = cfn;
5342 return LDAP_COMPARE_TRUE;
5343 }
5344 if ( p->ce_type != Cft_Schema )
5345 return LDAP_CONSTRAINT_VIOLATION;
5346
5347 cfn = ch_calloc( 1, sizeof(ConfigFile) );
5348 ca->ca_private = cfn;
5349 cfo = p->ce_private;
5350 cfn->c_sibs = cfo->c_kids;
5351 cfo->c_kids = cfn;
5352 return LDAP_SUCCESS;
5353 }
5354
5355 static int
cfAddDatabase(CfEntryInfo * p,Entry * e,struct config_args_s * ca)5356 cfAddDatabase( CfEntryInfo *p, Entry *e, struct config_args_s *ca )
5357 {
5358 if ( p->ce_type != Cft_Global ) {
5359 return LDAP_CONSTRAINT_VIOLATION;
5360 }
5361 /* config must be {0}, nothing else allowed */
5362 if ( !strncmp( e->e_nname.bv_val, "olcDatabase={0}", STRLENOF("olcDatabase={0}")) &&
5363 strncmp( e->e_nname.bv_val + STRLENOF("olcDatabase={0}"), "config,", STRLENOF("config,") )) {
5364 return LDAP_CONSTRAINT_VIOLATION;
5365 }
5366 ca->be = frontendDB; /* just to get past check_vals */
5367 return LDAP_SUCCESS;
5368 }
5369
5370 static int
cfAddBackend(CfEntryInfo * p,Entry * e,struct config_args_s * ca)5371 cfAddBackend( CfEntryInfo *p, Entry *e, struct config_args_s *ca )
5372 {
5373 if ( p->ce_type != Cft_Global ) {
5374 return LDAP_CONSTRAINT_VIOLATION;
5375 }
5376 return LDAP_SUCCESS;
5377 }
5378
5379 static int
cfAddModule(CfEntryInfo * p,Entry * e,struct config_args_s * ca)5380 cfAddModule( CfEntryInfo *p, Entry *e, struct config_args_s *ca )
5381 {
5382 if ( p->ce_type != Cft_Global ) {
5383 return LDAP_CONSTRAINT_VIOLATION;
5384 }
5385 return LDAP_SUCCESS;
5386 }
5387
5388 static int
cfAddOverlay(CfEntryInfo * p,Entry * e,struct config_args_s * ca)5389 cfAddOverlay( CfEntryInfo *p, Entry *e, struct config_args_s *ca )
5390 {
5391 if ( p->ce_type != Cft_Database ) {
5392 return LDAP_CONSTRAINT_VIOLATION;
5393 }
5394 ca->be = p->ce_be;
5395 return LDAP_SUCCESS;
5396 }
5397
5398 static void
schema_destroy_one(ConfigArgs * ca,ConfigOCs ** colst,int nocs,CfEntryInfo * p)5399 schema_destroy_one( ConfigArgs *ca, ConfigOCs **colst, int nocs,
5400 CfEntryInfo *p )
5401 {
5402 ConfigTable *ct;
5403 ConfigFile *cfo;
5404 AttributeDescription *ad;
5405 const char *text;
5406
5407 ca->valx = -1;
5408 ca->line = NULL;
5409 ca->argc = 1;
5410 if ( cfn->c_cr_head ) {
5411 struct berval bv = BER_BVC("olcDitContentRules");
5412 ad = NULL;
5413 slap_bv2ad( &bv, &ad, &text );
5414 ct = config_find_table( colst, nocs, ad, ca );
5415 config_del_vals( ct, ca );
5416 }
5417 if ( cfn->c_oc_head ) {
5418 struct berval bv = BER_BVC("olcObjectClasses");
5419 ad = NULL;
5420 slap_bv2ad( &bv, &ad, &text );
5421 ct = config_find_table( colst, nocs, ad, ca );
5422 config_del_vals( ct, ca );
5423 }
5424 if ( cfn->c_at_head ) {
5425 struct berval bv = BER_BVC("olcAttributeTypes");
5426 ad = NULL;
5427 slap_bv2ad( &bv, &ad, &text );
5428 ct = config_find_table( colst, nocs, ad, ca );
5429 config_del_vals( ct, ca );
5430 }
5431 if ( cfn->c_syn_head ) {
5432 struct berval bv = BER_BVC("olcLdapSyntaxes");
5433 ad = NULL;
5434 slap_bv2ad( &bv, &ad, &text );
5435 ct = config_find_table( colst, nocs, ad, ca );
5436 config_del_vals( ct, ca );
5437 }
5438 if ( cfn->c_om_head ) {
5439 struct berval bv = BER_BVC("olcObjectIdentifier");
5440 ad = NULL;
5441 slap_bv2ad( &bv, &ad, &text );
5442 ct = config_find_table( colst, nocs, ad, ca );
5443 config_del_vals( ct, ca );
5444 }
5445 cfo = p->ce_private;
5446 cfo->c_kids = cfn->c_sibs;
5447 ch_free( cfn );
5448 }
5449
5450 static int
config_add_oc(ConfigOCs ** cop,CfEntryInfo * last,Entry * e,ConfigArgs * ca)5451 config_add_oc( ConfigOCs **cop, CfEntryInfo *last, Entry *e, ConfigArgs *ca )
5452 {
5453 int rc = LDAP_CONSTRAINT_VIOLATION;
5454 ObjectClass **ocp;
5455
5456 if ( (*cop)->co_ldadd ) {
5457 rc = (*cop)->co_ldadd( last, e, ca );
5458 if ( rc != LDAP_CONSTRAINT_VIOLATION ) {
5459 return rc;
5460 }
5461 }
5462
5463 for ( ocp = (*cop)->co_oc->soc_sups; ocp && *ocp; ocp++ ) {
5464 ConfigOCs co = { 0 };
5465
5466 co.co_name = &(*ocp)->soc_cname;
5467 *cop = ldap_avl_find( CfOcTree, &co, CfOc_cmp );
5468 if ( *cop == NULL ) {
5469 return rc;
5470 }
5471
5472 rc = config_add_oc( cop, last, e, ca );
5473 if ( rc != LDAP_CONSTRAINT_VIOLATION ) {
5474 return rc;
5475 }
5476 }
5477
5478 return rc;
5479 }
5480
5481 /* Parse an LDAP entry into config directives */
5482 static int
config_add_internal(CfBackInfo * cfb,Entry * e,ConfigArgs * ca,SlapReply * rs,int * renum,Operation * op)5483 config_add_internal( CfBackInfo *cfb, Entry *e, ConfigArgs *ca, SlapReply *rs,
5484 int *renum, Operation *op )
5485 {
5486 CfEntryInfo *ce, *last = NULL;
5487 ConfigOCs co, *coptr, **colst;
5488 Attribute *a, *oc_at, *soc_at;
5489 int i, ibase = -1, nocs, rc = 0;
5490 struct berval pdn;
5491 ConfigTable *ct;
5492 char *ptr, *log_prefix = op ? op->o_log_prefix : "";
5493
5494 memset( ca, 0, sizeof(ConfigArgs));
5495
5496 /* Make sure parent exists and entry does not. But allow
5497 * Databases and Overlays to be inserted. Don't do any
5498 * auto-renumbering if manageDSAit control is present.
5499 */
5500 ce = config_find_base( cfb->cb_root, &e->e_nname, &last );
5501 if ( ce ) {
5502 if ( ( op && op->o_managedsait ) ||
5503 ( ce->ce_type != Cft_Database && ce->ce_type != Cft_Overlay &&
5504 ce->ce_type != Cft_Module ) )
5505 {
5506 Debug( LDAP_DEBUG_TRACE, "%s: config_add_internal: "
5507 "DN=\"%s\" already exists\n",
5508 log_prefix, e->e_name.bv_val );
5509 /* global schema ignores all writes */
5510 if ( ce->ce_type == Cft_Schema && ce->ce_parent->ce_type == Cft_Global )
5511 return LDAP_COMPARE_TRUE;
5512 return LDAP_ALREADY_EXISTS;
5513 }
5514 }
5515
5516 dnParent( &e->e_nname, &pdn );
5517
5518 /* If last is NULL, the new entry is the root/suffix entry,
5519 * otherwise last should be the parent.
5520 */
5521 if ( last && !dn_match( &last->ce_entry->e_nname, &pdn ) ) {
5522 if ( rs ) {
5523 rs->sr_matched = last->ce_entry->e_name.bv_val;
5524 }
5525 Debug( LDAP_DEBUG_TRACE, "%s: config_add_internal: "
5526 "DN=\"%s\" not child of DN=\"%s\"\n",
5527 log_prefix, e->e_name.bv_val,
5528 last->ce_entry->e_name.bv_val );
5529 return LDAP_NO_SUCH_OBJECT;
5530 }
5531
5532 if ( op ) {
5533 /* No parent, must be root. This will never happen... */
5534 if ( !last && !be_isroot( op ) && !be_shadow_update( op ) ) {
5535 return LDAP_NO_SUCH_OBJECT;
5536 }
5537
5538 if ( last && !access_allowed( op, last->ce_entry,
5539 slap_schema.si_ad_children, NULL, ACL_WADD, NULL ) )
5540 {
5541 Debug( LDAP_DEBUG_TRACE, "%s: config_add_internal: "
5542 "DN=\"%s\" no write access to \"children\" of parent\n",
5543 log_prefix, e->e_name.bv_val );
5544 return LDAP_INSUFFICIENT_ACCESS;
5545 }
5546 }
5547
5548 oc_at = attr_find( e->e_attrs, slap_schema.si_ad_objectClass );
5549 if ( !oc_at ) {
5550 Debug( LDAP_DEBUG_TRACE, "%s: config_add_internal: "
5551 "DN=\"%s\" no objectClass\n",
5552 log_prefix, e->e_name.bv_val );
5553 return LDAP_OBJECT_CLASS_VIOLATION;
5554 }
5555
5556 soc_at = attr_find( e->e_attrs, slap_schema.si_ad_structuralObjectClass );
5557 if ( !soc_at ) {
5558 ObjectClass *soc = NULL;
5559 char textbuf[ SLAP_TEXT_BUFLEN ];
5560 const char *text = textbuf;
5561
5562 /* FIXME: check result */
5563 rc = structural_class( oc_at->a_nvals, &soc, NULL,
5564 &text, textbuf, sizeof(textbuf), NULL );
5565 if ( rc != LDAP_SUCCESS ) {
5566 Debug( LDAP_DEBUG_TRACE, "%s: config_add_internal: "
5567 "DN=\"%s\" no structural objectClass (%s)\n",
5568 log_prefix, e->e_name.bv_val, text );
5569 return rc;
5570 }
5571 attr_merge_one( e, slap_schema.si_ad_structuralObjectClass, &soc->soc_cname, NULL );
5572 soc_at = attr_find( e->e_attrs, slap_schema.si_ad_structuralObjectClass );
5573 if ( soc_at == NULL ) {
5574 Debug( LDAP_DEBUG_TRACE, "%s: config_add_internal: "
5575 "DN=\"%s\" no structural objectClass; "
5576 "unable to merge computed class %s\n",
5577 log_prefix, e->e_name.bv_val,
5578 soc->soc_cname.bv_val );
5579 return LDAP_OBJECT_CLASS_VIOLATION;
5580 }
5581
5582 Debug( LDAP_DEBUG_TRACE, "%s: config_add_internal: "
5583 "DN=\"%s\" no structural objectClass; "
5584 "computed objectClass %s merged\n",
5585 log_prefix, e->e_name.bv_val,
5586 soc->soc_cname.bv_val );
5587 }
5588
5589 /* Fake the coordinates based on whether we're part of an
5590 * LDAP Add or if reading the config dir
5591 */
5592 if ( rs ) {
5593 ca->fname = "slapd";
5594 ca->lineno = 0;
5595 } else {
5596 ca->fname = cfdir.bv_val;
5597 ca->lineno = 1;
5598 }
5599 ca->ca_op = op;
5600
5601 co.co_name = &soc_at->a_nvals[0];
5602 coptr = ldap_avl_find( CfOcTree, &co, CfOc_cmp );
5603 if ( coptr == NULL ) {
5604 Debug( LDAP_DEBUG_TRACE, "%s: config_add_internal: "
5605 "DN=\"%s\" no structural objectClass in configuration table\n",
5606 log_prefix, e->e_name.bv_val );
5607 return LDAP_OBJECT_CLASS_VIOLATION;
5608 }
5609
5610 /* Only the root can be Cft_Global, everything else must
5611 * have a parent. Only limited nesting arrangements are allowed.
5612 */
5613 rc = LDAP_CONSTRAINT_VIOLATION;
5614 if ( coptr->co_type == Cft_Global && !last ) {
5615 cfn = cfb->cb_config;
5616 ca->ca_private = cfn;
5617 ca->be = frontendDB; /* just to get past check_vals */
5618 rc = LDAP_SUCCESS;
5619 }
5620
5621 colst = count_ocs( oc_at, &nocs );
5622
5623 /* Check whether the Add is allowed by its parent, and do
5624 * any necessary arg setup
5625 */
5626 if ( last ) {
5627 rc = config_add_oc( &coptr, last, e, ca );
5628 if ( rc == LDAP_CONSTRAINT_VIOLATION ) {
5629 for ( i = 0; i<nocs; i++ ) {
5630 /* Already checked these */
5631 if ( colst[i]->co_oc->soc_kind == LDAP_SCHEMA_STRUCTURAL )
5632 continue;
5633 if ( colst[i]->co_ldadd &&
5634 ( rc = colst[i]->co_ldadd( last, e, ca ))
5635 != LDAP_CONSTRAINT_VIOLATION ) {
5636 coptr = colst[i];
5637 break;
5638 }
5639 }
5640 }
5641 if ( rc == LDAP_CONSTRAINT_VIOLATION ) {
5642 Debug( LDAP_DEBUG_TRACE, "%s: config_add_internal: "
5643 "DN=\"%s\" no structural objectClass add function\n",
5644 log_prefix, e->e_name.bv_val );
5645 return LDAP_OBJECT_CLASS_VIOLATION;
5646 }
5647 }
5648
5649 /* Add the entry but don't parse it, we already have its contents */
5650 if ( rc == LDAP_COMPARE_TRUE ) {
5651 rc = LDAP_SUCCESS;
5652 goto ok;
5653 }
5654
5655 if ( rc != LDAP_SUCCESS )
5656 goto done_noop;
5657
5658 /* Parse all the values and check for simple syntax errors before
5659 * performing any set actions.
5660 *
5661 * If doing an LDAPadd, check for indexed names and any necessary
5662 * renaming/renumbering. Entries that don't need indexed names are
5663 * ignored. Entries that need an indexed name and arrive without one
5664 * are assigned to the end. Entries that arrive with an index may
5665 * cause the following entries to be renumbered/bumped down.
5666 *
5667 * Note that "pseudo-indexed" entries (cn=Include{xx}, cn=Module{xx})
5668 * don't allow Adding an entry with an index that's already in use.
5669 * This is flagged as an error (LDAP_ALREADY_EXISTS) up above.
5670 *
5671 * These entries can have auto-assigned indexes (appended to the end)
5672 * but only the other types support auto-renumbering of siblings.
5673 */
5674 {
5675 rc = check_name_index( last, coptr->co_type, e, rs, renum,
5676 &ibase );
5677 if ( rc ) {
5678 goto done_noop;
5679 }
5680 if ( renum && *renum && coptr->co_type != Cft_Database &&
5681 coptr->co_type != Cft_Overlay )
5682 {
5683 snprintf( ca->cr_msg, sizeof( ca->cr_msg ),
5684 "operation requires sibling renumbering" );
5685 rc = LDAP_UNWILLING_TO_PERFORM;
5686 goto done_noop;
5687 }
5688 }
5689
5690 init_config_argv( ca );
5691
5692 /* Make sure we process attrs in the required order */
5693 sort_attrs( e, colst, nocs );
5694
5695 for ( a = e->e_attrs; a; a = a->a_next ) {
5696 if ( a == oc_at ) continue;
5697 ct = config_find_table( colst, nocs, a->a_desc, ca );
5698 if ( !ct ) continue; /* user data? */
5699 rc = check_vals( ct, ca, a, 1 );
5700 if ( rc ) goto done_noop;
5701 }
5702
5703 /* Basic syntax checks are OK. Do the actual settings. */
5704 for ( a=e->e_attrs; a; a=a->a_next ) {
5705 if ( a == oc_at ) continue;
5706 ct = config_find_table( colst, nocs, a->a_desc, ca );
5707 if ( !ct ) continue; /* user data? */
5708 for (i=0; a->a_vals[i].bv_val; i++) {
5709 char *iptr = NULL;
5710 ca->valx = -1;
5711 ca->line = a->a_vals[i].bv_val;
5712 ca->linelen = a->a_vals[i].bv_len;
5713 if ( a->a_desc->ad_type->sat_flags & SLAP_AT_ORDERED ) {
5714 ptr = strchr( ca->line, '}' );
5715 if ( ptr ) {
5716 iptr = strchr( ca->line, '{' );
5717 ca->linelen -= (ptr+1) - ca->line;
5718 ca->line = ptr+1;
5719 }
5720 }
5721 if ( a->a_desc->ad_type->sat_flags & SLAP_AT_ORDERED_SIB ) {
5722 if ( iptr ) {
5723 ca->valx = strtol( iptr+1, NULL, 0 );
5724 }
5725 } else {
5726 ca->valx = i;
5727 }
5728 rc = config_parse_add( ct, ca, i );
5729 if ( rc ) {
5730 rc = LDAP_OTHER;
5731 goto done;
5732 }
5733 }
5734 }
5735 ok:
5736 /* Newly added databases and overlays need to be started up */
5737 if ( CONFIG_ONLINE_ADD( ca )) {
5738 if ( coptr->co_type == Cft_Database ) {
5739 rc = backend_startup_one( ca->be, &ca->reply );
5740
5741 } else if ( coptr->co_type == Cft_Backend ) {
5742 if ( ca->bi->bi_open ) {
5743 rc = ca->bi->bi_open( ca->bi );
5744 }
5745
5746 } else if ( coptr->co_type == Cft_Overlay ) {
5747 if ( ca->bi->bi_db_open ) {
5748 BackendInfo *bi_orig = ca->be->bd_info;
5749 ca->be->bd_info = ca->bi;
5750 rc = ca->bi->bi_db_open( ca->be, &ca->reply );
5751 ca->be->bd_info = bi_orig;
5752 }
5753 } else if ( ca->num_cleanups ) {
5754 rc = config_run_cleanup( ca );
5755 }
5756 if ( rc ) {
5757 if (ca->cr_msg[0] == '\0')
5758 snprintf( ca->cr_msg, sizeof( ca->cr_msg ), "<%s> failed startup", ca->argv[0] );
5759
5760 Debug(LDAP_DEBUG_ANY, "%s: %s (%s)!\n",
5761 ca->log, ca->cr_msg, ca->argv[1] );
5762 rc = LDAP_OTHER;
5763 goto done;
5764 }
5765 }
5766
5767 ca->valx = ibase;
5768 ce = ch_calloc( 1, sizeof(CfEntryInfo) );
5769 ce->ce_parent = last;
5770 ce->ce_entry = entry_dup( e );
5771 ce->ce_entry->e_private = ce;
5772 ce->ce_type = coptr->co_type;
5773 ce->ce_be = ca->be;
5774 ce->ce_bi = ca->bi;
5775 ce->ce_private = ca->ca_private;
5776 ca->ca_entry = ce->ce_entry;
5777 if ( !last ) {
5778 cfb->cb_root = ce;
5779 } else if ( last->ce_kids ) {
5780 CfEntryInfo *c2, **cprev;
5781
5782 /* Advance to first of this type */
5783 cprev = &last->ce_kids;
5784 for ( c2 = *cprev; c2 && c2->ce_type < ce->ce_type; ) {
5785 cprev = &c2->ce_sibs;
5786 c2 = c2->ce_sibs;
5787 }
5788 /* Account for the (-1) frontendDB entry */
5789 if ( ce->ce_type == Cft_Database ) {
5790 if ( ca->be == frontendDB )
5791 ibase = 0;
5792 else if ( ibase != -1 )
5793 ibase++;
5794 }
5795 /* Append */
5796 if ( ibase < 0 ) {
5797 for (c2 = *cprev; c2 && c2->ce_type == ce->ce_type;) {
5798 cprev = &c2->ce_sibs;
5799 c2 = c2->ce_sibs;
5800 }
5801 } else {
5802 /* Insert */
5803 int i;
5804 for ( i=0; i<ibase; i++ ) {
5805 c2 = *cprev;
5806 cprev = &c2->ce_sibs;
5807 }
5808 }
5809 ce->ce_sibs = *cprev;
5810 *cprev = ce;
5811 } else {
5812 last->ce_kids = ce;
5813 }
5814
5815 done:
5816 if ( rc ) {
5817 if ( (coptr->co_type == Cft_Database) && ca->be ) {
5818 if ( ca->be != frontendDB )
5819 backend_destroy_one( ca->be, 1 );
5820 } else if ( (coptr->co_type == Cft_Overlay) && ca->bi ) {
5821 overlay_destroy_one( ca->be, (slap_overinst *)ca->bi );
5822 } else if ( coptr->co_type == Cft_Schema ) {
5823 schema_destroy_one( ca, colst, nocs, last );
5824 } else if ( ca->num_cleanups ) {
5825 config_run_cleanup( ca );
5826 }
5827 }
5828 done_noop:
5829
5830 ch_free( ca->argv );
5831 if ( colst ) ch_free( colst );
5832 return rc;
5833 }
5834
5835 #define BIGTMP 10000
5836 static int
config_rename_add(Operation * op,SlapReply * rs,CfEntryInfo * ce,int base,int rebase,int max,int use_ldif)5837 config_rename_add( Operation *op, SlapReply *rs, CfEntryInfo *ce,
5838 int base, int rebase, int max, int use_ldif )
5839 {
5840 CfEntryInfo *ce2, *ce3, *cetmp = NULL, *cerem = NULL;
5841 ConfigType etype = ce->ce_type;
5842 int count = 0, rc = 0;
5843
5844 /* Reverse ce list */
5845 for (ce2 = ce->ce_sibs;ce2;ce2 = ce3) {
5846 if (ce2->ce_type != etype) {
5847 cerem = ce2;
5848 break;
5849 }
5850 ce3 = ce2->ce_sibs;
5851 ce2->ce_sibs = cetmp;
5852 cetmp = ce2;
5853 count++;
5854 if ( max && count >= max ) {
5855 cerem = ce3;
5856 break;
5857 }
5858 }
5859
5860 /* Move original to a temp name until increments are done */
5861 if ( rebase ) {
5862 ce->ce_entry->e_private = NULL;
5863 rc = config_renumber_one( op, rs, ce->ce_parent, ce->ce_entry,
5864 base+BIGTMP, 0, use_ldif );
5865 ce->ce_entry->e_private = ce;
5866 }
5867 /* start incrementing */
5868 for (ce2=cetmp; ce2; ce2=ce3) {
5869 ce3 = ce2->ce_sibs;
5870 ce2->ce_sibs = cerem;
5871 cerem = ce2;
5872 if ( rc == 0 )
5873 rc = config_renumber_one( op, rs, ce2->ce_parent, ce2->ce_entry,
5874 count+base, 0, use_ldif );
5875 count--;
5876 }
5877 if ( rebase )
5878 rc = config_renumber_one( op, rs, ce->ce_parent, ce->ce_entry,
5879 base, 0, use_ldif );
5880 return rc;
5881 }
5882
5883 static int
config_rename_del(Operation * op,SlapReply * rs,CfEntryInfo * ce,CfEntryInfo * ce2,int old,int use_ldif)5884 config_rename_del( Operation *op, SlapReply *rs, CfEntryInfo *ce,
5885 CfEntryInfo *ce2, int old, int use_ldif )
5886 {
5887 int count = 0;
5888
5889 /* Renumber original to a temp value */
5890 ce->ce_entry->e_private = NULL;
5891 config_renumber_one( op, rs, ce->ce_parent, ce->ce_entry,
5892 old+BIGTMP, 0, use_ldif );
5893 ce->ce_entry->e_private = ce;
5894
5895 /* start decrementing */
5896 for (; ce2 != ce; ce2=ce2->ce_sibs) {
5897 config_renumber_one( op, rs, ce2->ce_parent, ce2->ce_entry,
5898 count+old, 0, use_ldif );
5899 count++;
5900 }
5901 return config_renumber_one( op, rs, ce->ce_parent, ce->ce_entry,
5902 count+old, 0, use_ldif );
5903 }
5904
5905 /* Parse an LDAP entry into config directives, then store in underlying
5906 * database.
5907 */
5908 static int
config_back_add(Operation * op,SlapReply * rs)5909 config_back_add( Operation *op, SlapReply *rs )
5910 {
5911 CfBackInfo *cfb;
5912 int renumber, dopause = 1;
5913 ConfigArgs ca;
5914
5915 if ( !access_allowed( op, op->ora_e, slap_schema.si_ad_entry,
5916 NULL, ACL_WADD, NULL )) {
5917 rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
5918 goto out;
5919 }
5920
5921 /*
5922 * Check for attribute ACL
5923 */
5924 if ( !acl_check_modlist( op, op->ora_e, op->orm_modlist )) {
5925 rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
5926 rs->sr_text = "no write access to attribute";
5927 goto out;
5928 }
5929
5930 cfb = (CfBackInfo *)op->o_bd->be_private;
5931
5932 /* add opattrs for syncprov */
5933 {
5934 char textbuf[SLAP_TEXT_BUFLEN];
5935 size_t textlen = sizeof textbuf;
5936 rs->sr_err = entry_schema_check(op, op->ora_e, NULL, 0, 1, NULL,
5937 &rs->sr_text, textbuf, sizeof( textbuf ) );
5938 if ( rs->sr_err != LDAP_SUCCESS )
5939 goto out;
5940 rs->sr_err = slap_add_opattrs( op, &rs->sr_text, textbuf, textlen, 1 );
5941 if ( rs->sr_err != LDAP_SUCCESS ) {
5942 Debug( LDAP_DEBUG_TRACE,
5943 LDAP_XSTRING(config_back_add) ": entry failed op attrs add: "
5944 "%s (%d)\n", rs->sr_text, rs->sr_err );
5945 goto out;
5946 }
5947 }
5948
5949 if ( op->o_abandon ) {
5950 rs->sr_err = SLAPD_ABANDON;
5951 goto out;
5952 }
5953 if ( slap_pause_server() < 0 )
5954 dopause = 0;
5955
5956 /* Strategy:
5957 * 1) check for existence of entry
5958 * 2) check for sibling renumbering
5959 * 3) perform internal add
5960 * 4) perform any necessary renumbering
5961 * 5) store entry in underlying database
5962 */
5963 rs->sr_err = config_add_internal( cfb, op->ora_e, &ca, rs, &renumber, op );
5964 if ( rs->sr_err != LDAP_SUCCESS ) {
5965 rs->sr_text = ca.cr_msg;
5966 goto out2;
5967 }
5968
5969 if ( renumber ) {
5970 CfEntryInfo *ce = ca.ca_entry->e_private;
5971 req_add_s addr = op->oq_add;
5972 op->o_tag = LDAP_REQ_MODRDN;
5973 rs->sr_err = config_rename_add( op, rs, ce, ca.valx, 0, 0, cfb->cb_use_ldif );
5974 op->o_tag = LDAP_REQ_ADD;
5975 op->oq_add = addr;
5976 if ( rs->sr_err != LDAP_SUCCESS ) {
5977 goto out2;
5978 }
5979 }
5980
5981 if ( cfb->cb_use_ldif ) {
5982 BackendDB *be = op->o_bd;
5983 slap_callback sc = { NULL, slap_null_cb, NULL, NULL }, *scp;
5984 struct berval dn, ndn;
5985
5986 op->o_bd = &cfb->cb_db;
5987
5988 /* Save current rootdn; use the underlying DB's rootdn */
5989 dn = op->o_dn;
5990 ndn = op->o_ndn;
5991 op->o_dn = op->o_bd->be_rootdn;
5992 op->o_ndn = op->o_bd->be_rootndn;
5993
5994 scp = op->o_callback;
5995 op->o_callback = ≻
5996 op->o_bd->be_add( op, rs );
5997 op->o_bd = be;
5998 op->o_callback = scp;
5999 op->o_dn = dn;
6000 op->o_ndn = ndn;
6001 }
6002
6003 out2:;
6004 if ( dopause )
6005 slap_unpause_server();
6006
6007 out:;
6008 { int repl = op->o_dont_replicate;
6009 if ( rs->sr_err == LDAP_COMPARE_TRUE ) {
6010 rs->sr_text = NULL; /* Set after config_add_internal */
6011 rs->sr_err = LDAP_SUCCESS;
6012 op->o_dont_replicate = 1;
6013 }
6014 send_ldap_result( op, rs );
6015 op->o_dont_replicate = repl;
6016 }
6017 slap_graduate_commit_csn( op );
6018 return rs->sr_err;
6019 }
6020
6021 typedef struct delrec {
6022 struct delrec *next;
6023 int nidx;
6024 int idx[1];
6025 } delrec;
6026
6027 static int
config_modify_add(ConfigTable * ct,ConfigArgs * ca,AttributeDescription * ad,int i)6028 config_modify_add( ConfigTable *ct, ConfigArgs *ca, AttributeDescription *ad,
6029 int i )
6030 {
6031 int rc;
6032
6033 ca->valx = -1;
6034 if (ad->ad_type->sat_flags & SLAP_AT_ORDERED &&
6035 ca->line[0] == '{' )
6036 {
6037 char *ptr = strchr( ca->line + 1, '}' );
6038 if ( ptr ) {
6039 char *next;
6040
6041 ca->valx = strtol( ca->line + 1, &next, 0 );
6042 if ( next == ca->line + 1 || next[ 0 ] != '}' ) {
6043 return LDAP_OTHER;
6044 }
6045 ca->linelen -= (ptr+1) - ca->line;
6046 ca->line = ptr+1;
6047 }
6048 }
6049 rc = config_parse_add( ct, ca, i );
6050 if ( rc ) {
6051 rc = LDAP_OTHER;
6052 }
6053 return rc;
6054 }
6055
6056 static int
config_modify_internal(CfEntryInfo * ce,Operation * op,SlapReply * rs,ConfigArgs * ca)6057 config_modify_internal( CfEntryInfo *ce, Operation *op, SlapReply *rs,
6058 ConfigArgs *ca )
6059 {
6060 int rc = LDAP_UNWILLING_TO_PERFORM;
6061 Modifications *ml;
6062 Entry *e = ce->ce_entry;
6063 Attribute *save_attrs = e->e_attrs, *oc_at, *s, *a;
6064 ConfigTable *ct;
6065 ConfigOCs **colst;
6066 int i, nocs;
6067 char *ptr;
6068 delrec *dels = NULL, *deltail = NULL;
6069
6070 oc_at = attr_find( e->e_attrs, slap_schema.si_ad_objectClass );
6071 if ( !oc_at ) return LDAP_OBJECT_CLASS_VIOLATION;
6072
6073 for (ml = op->orm_modlist; ml; ml=ml->sml_next) {
6074 if (ml->sml_desc == slap_schema.si_ad_objectClass)
6075 return rc;
6076 }
6077
6078 colst = count_ocs( oc_at, &nocs );
6079
6080 /* make sure add/del flags are clear; should always be true */
6081 for ( s = save_attrs; s; s = s->a_next ) {
6082 s->a_flags &= ~(SLAP_ATTR_IXADD|SLAP_ATTR_IXDEL);
6083 }
6084
6085 e->e_attrs = attrs_dup( e->e_attrs );
6086
6087 init_config_argv( ca );
6088 ca->be = ce->ce_be;
6089 ca->bi = ce->ce_bi;
6090 ca->ca_private = ce->ce_private;
6091 ca->ca_entry = e;
6092 ca->fname = "slapd";
6093 ca->ca_op = op;
6094 strcpy( ca->log, "back-config" );
6095
6096 for (ml = op->orm_modlist; ml; ml=ml->sml_next) {
6097 ct = config_find_table( colst, nocs, ml->sml_desc, ca );
6098 switch (ml->sml_op) {
6099 case LDAP_MOD_DELETE:
6100 case LDAP_MOD_REPLACE:
6101 case SLAP_MOD_SOFTDEL:
6102 {
6103 BerVarray vals = NULL, nvals = NULL;
6104 int *idx = NULL;
6105 if ( ct && ( ct->arg_type & ARG_NO_DELETE )) {
6106 rc = LDAP_OTHER;
6107 snprintf(ca->cr_msg, sizeof(ca->cr_msg), "cannot delete %s",
6108 ml->sml_desc->ad_cname.bv_val );
6109 goto out_noop;
6110 }
6111 if ( ml->sml_op == LDAP_MOD_REPLACE ) {
6112 vals = ml->sml_values;
6113 nvals = ml->sml_nvalues;
6114 ml->sml_values = NULL;
6115 ml->sml_nvalues = NULL;
6116 }
6117 /* If we're deleting by values, remember the indexes of the
6118 * values we deleted.
6119 */
6120 if ( ct && ml->sml_values ) {
6121 delrec *d;
6122 i = ml->sml_numvals;
6123 d = ch_malloc( sizeof(delrec) + (i - 1)* sizeof(int));
6124 d->nidx = i;
6125 d->next = NULL;
6126 if ( dels ) {
6127 deltail->next = d;
6128 } else {
6129 dels = d;
6130 }
6131 deltail = d;
6132 idx = d->idx;
6133 }
6134 rc = modify_delete_vindex(e, &ml->sml_mod,
6135 get_permissiveModify(op),
6136 &rs->sr_text, ca->cr_msg, sizeof(ca->cr_msg), idx );
6137 if ( ml->sml_op == LDAP_MOD_REPLACE ) {
6138 ml->sml_values = vals;
6139 ml->sml_nvalues = nvals;
6140 }
6141 if ( rc == LDAP_NO_SUCH_ATTRIBUTE && ml->sml_op == SLAP_MOD_SOFTDEL )
6142 {
6143 rc = LDAP_SUCCESS;
6144 }
6145 /* FIXME: check rc before fallthru? */
6146 if ( !vals )
6147 break;
6148 }
6149 /* FALLTHRU: LDAP_MOD_REPLACE && vals */
6150
6151 case SLAP_MOD_ADD_IF_NOT_PRESENT:
6152 if ( ml->sml_op == SLAP_MOD_ADD_IF_NOT_PRESENT
6153 && attr_find( e->e_attrs, ml->sml_desc ) )
6154 {
6155 rc = LDAP_SUCCESS;
6156 break;
6157 }
6158
6159 case LDAP_MOD_ADD:
6160 case SLAP_MOD_SOFTADD: {
6161 int mop = ml->sml_op;
6162 int navals = -1;
6163 ml->sml_op = LDAP_MOD_ADD;
6164 if ( ct ) {
6165 if ( ct->arg_type & ARG_NO_INSERT ) {
6166 Attribute *a = attr_find( e->e_attrs, ml->sml_desc );
6167 if ( a ) {
6168 navals = a->a_numvals;
6169 }
6170 }
6171 for ( i=0; !BER_BVISNULL( &ml->sml_values[i] ); i++ ) {
6172 if ( ml->sml_values[i].bv_val[0] == '{' &&
6173 navals >= 0 )
6174 {
6175 char *next, *val = ml->sml_values[i].bv_val + 1;
6176 int j;
6177
6178 j = strtol( val, &next, 0 );
6179 if ( next == val || next[ 0 ] != '}' || j < navals ) {
6180 rc = LDAP_OTHER;
6181 snprintf(ca->cr_msg, sizeof(ca->cr_msg), "cannot insert %s",
6182 ml->sml_desc->ad_cname.bv_val );
6183 goto out_noop;
6184 }
6185 }
6186 rc = check_vals( ct, ca, ml, 0 );
6187 if ( rc ) goto out_noop;
6188 }
6189 }
6190 rc = modify_add_values(e, &ml->sml_mod,
6191 get_permissiveModify(op),
6192 &rs->sr_text, ca->cr_msg, sizeof(ca->cr_msg) );
6193
6194 /* If value already exists, show success here
6195 * and ignore this operation down below.
6196 */
6197 if ( mop == SLAP_MOD_SOFTADD ) {
6198 if ( rc == LDAP_TYPE_OR_VALUE_EXISTS )
6199 rc = LDAP_SUCCESS;
6200 else
6201 mop = LDAP_MOD_ADD;
6202 }
6203 ml->sml_op = mop;
6204 break;
6205 }
6206
6207 break;
6208 case LDAP_MOD_INCREMENT: /* FIXME */
6209 break;
6210 default:
6211 break;
6212 }
6213 if(rc != LDAP_SUCCESS) break;
6214 }
6215
6216 if ( rc == LDAP_SUCCESS) {
6217 /* check that the entry still obeys the schema */
6218 rc = entry_schema_check(op, e, NULL, 0, 0, NULL,
6219 &rs->sr_text, ca->cr_msg, sizeof(ca->cr_msg) );
6220 }
6221 if ( rc ) goto out_noop;
6222
6223 /* Basic syntax checks are OK. Do the actual settings. */
6224 for ( ml = op->orm_modlist; ml; ml = ml->sml_next ) {
6225 ct = config_find_table( colst, nocs, ml->sml_desc, ca );
6226 if ( !ct ) continue;
6227
6228 s = attr_find( save_attrs, ml->sml_desc );
6229 a = attr_find( e->e_attrs, ml->sml_desc );
6230
6231 switch (ml->sml_op) {
6232 case LDAP_MOD_DELETE:
6233 case LDAP_MOD_REPLACE: {
6234 BerVarray vals = NULL, nvals = NULL;
6235 delrec *d = NULL;
6236
6237 if ( ml->sml_op == LDAP_MOD_REPLACE ) {
6238 vals = ml->sml_values;
6239 nvals = ml->sml_nvalues;
6240 ml->sml_values = NULL;
6241 ml->sml_nvalues = NULL;
6242 }
6243
6244 if ( ml->sml_values )
6245 d = dels;
6246
6247 /* If we didn't delete the whole attribute */
6248 if ( ml->sml_values && a ) {
6249 struct berval *mvals;
6250 int j;
6251
6252 if ( ml->sml_nvalues )
6253 mvals = ml->sml_nvalues;
6254 else
6255 mvals = ml->sml_values;
6256
6257 /* use the indexes we saved up above */
6258 for (i=0; i < d->nidx; i++) {
6259 struct berval bv = *mvals++;
6260 if ( a->a_desc->ad_type->sat_flags & SLAP_AT_ORDERED &&
6261 bv.bv_val[0] == '{' ) {
6262 ptr = strchr( bv.bv_val, '}' ) + 1;
6263 bv.bv_len -= ptr - bv.bv_val;
6264 bv.bv_val = ptr;
6265 }
6266 ca->line = bv.bv_val;
6267 ca->linelen = bv.bv_len;
6268 ca->valx = d->idx[i];
6269 config_parse_vals(ct, ca, d->idx[i] );
6270 rc = config_del_vals( ct, ca );
6271 if ( rc != LDAP_SUCCESS ) break;
6272 if ( s )
6273 s->a_flags |= SLAP_ATTR_IXDEL;
6274 for (j=i+1; j < d->nidx; j++)
6275 if ( d->idx[j] >d->idx[i] )
6276 d->idx[j]--;
6277 }
6278 } else {
6279 ca->valx = -1;
6280 ca->line = NULL;
6281 ca->argc = 1;
6282 rc = config_del_vals( ct, ca );
6283 if ( rc ) rc = LDAP_OTHER;
6284 if ( s )
6285 s->a_flags |= SLAP_ATTR_IXDEL;
6286 }
6287 if ( ml->sml_values ) {
6288 d = d->next;
6289 ch_free( dels );
6290 dels = d;
6291 }
6292 if ( ml->sml_op == LDAP_MOD_REPLACE ) {
6293 ml->sml_values = vals;
6294 ml->sml_nvalues = nvals;
6295 }
6296 if ( !vals || rc != LDAP_SUCCESS )
6297 break;
6298 }
6299 /* FALLTHRU: LDAP_MOD_REPLACE && vals */
6300
6301 case LDAP_MOD_ADD:
6302 if ( !a )
6303 break;
6304 for (i=0; ml->sml_values[i].bv_val; i++) {
6305 ca->line = ml->sml_values[i].bv_val;
6306 ca->linelen = ml->sml_values[i].bv_len;
6307 ca->valx = -1;
6308 rc = config_modify_add( ct, ca, ml->sml_desc, i );
6309 if ( rc )
6310 goto out;
6311 a->a_flags |= SLAP_ATTR_IXADD;
6312 }
6313 break;
6314 }
6315 }
6316
6317 out:
6318 /* Undo for a failed operation */
6319 if ( rc != LDAP_SUCCESS ) {
6320 ConfigReply msg = ca->reply;
6321 for ( s = save_attrs; s; s = s->a_next ) {
6322 if ( s->a_flags & SLAP_ATTR_IXDEL ) {
6323 s->a_flags &= ~(SLAP_ATTR_IXDEL|SLAP_ATTR_IXADD);
6324 ct = config_find_table( colst, nocs, s->a_desc, ca );
6325 a = attr_find( e->e_attrs, s->a_desc );
6326 if ( a ) {
6327 /* clear the flag so the add check below will skip it */
6328 a->a_flags &= ~(SLAP_ATTR_IXDEL|SLAP_ATTR_IXADD);
6329 ca->valx = -1;
6330 ca->line = NULL;
6331 ca->argc = 1;
6332 config_del_vals( ct, ca );
6333 }
6334 for ( i=0; !BER_BVISNULL( &s->a_vals[i] ); i++ ) {
6335 ca->line = s->a_vals[i].bv_val;
6336 ca->linelen = s->a_vals[i].bv_len;
6337 ca->valx = -1;
6338 config_modify_add( ct, ca, s->a_desc, i );
6339 }
6340 }
6341 }
6342 for ( a = e->e_attrs; a; a = a->a_next ) {
6343 if ( a->a_flags & SLAP_ATTR_IXADD ) {
6344 ct = config_find_table( colst, nocs, a->a_desc, ca );
6345 ca->valx = -1;
6346 ca->line = NULL;
6347 ca->argc = 1;
6348 config_del_vals( ct, ca );
6349 s = attr_find( save_attrs, a->a_desc );
6350 if ( s ) {
6351 s->a_flags &= ~(SLAP_ATTR_IXDEL|SLAP_ATTR_IXADD);
6352 for ( i=0; !BER_BVISNULL( &s->a_vals[i] ); i++ ) {
6353 ca->line = s->a_vals[i].bv_val;
6354 ca->linelen = s->a_vals[i].bv_len;
6355 ca->valx = -1;
6356 config_modify_add( ct, ca, s->a_desc, i );
6357 }
6358 }
6359 }
6360 }
6361 ca->reply = msg;
6362 }
6363
6364 if ( ca->num_cleanups ) {
6365 i = config_run_cleanup( ca );
6366 if (rc == LDAP_SUCCESS)
6367 rc = i;
6368 }
6369 out_noop:
6370 if ( rc == LDAP_SUCCESS ) {
6371 attrs_free( save_attrs );
6372 rs->sr_text = NULL;
6373 } else {
6374 attrs_free( e->e_attrs );
6375 e->e_attrs = save_attrs;
6376 }
6377 ch_free( ca->argv );
6378 if ( colst ) ch_free( colst );
6379 while( dels ) {
6380 deltail = dels->next;
6381 ch_free( dels );
6382 dels = deltail;
6383 }
6384
6385 return rc;
6386 }
6387
6388 static int
config_back_modify(Operation * op,SlapReply * rs)6389 config_back_modify( Operation *op, SlapReply *rs )
6390 {
6391 CfBackInfo *cfb;
6392 CfEntryInfo *ce, *last;
6393 Modifications *ml;
6394 ConfigArgs ca = {0};
6395 struct berval rdn;
6396 char *ptr;
6397 AttributeDescription *rad = NULL;
6398 int do_pause = 1;
6399
6400 cfb = (CfBackInfo *)op->o_bd->be_private;
6401
6402 ce = config_find_base( cfb->cb_root, &op->o_req_ndn, &last );
6403 if ( !ce ) {
6404 if ( last )
6405 rs->sr_matched = last->ce_entry->e_name.bv_val;
6406 rs->sr_err = LDAP_NO_SUCH_OBJECT;
6407 goto out;
6408 }
6409
6410 if ( !acl_check_modlist( op, ce->ce_entry, op->orm_modlist )) {
6411 rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
6412 goto out;
6413 }
6414
6415 /* Get type of RDN */
6416 rdn = ce->ce_entry->e_nname;
6417 ptr = strchr( rdn.bv_val, '=' );
6418 rdn.bv_len = ptr - rdn.bv_val;
6419 rs->sr_err = slap_bv2ad( &rdn, &rad, &rs->sr_text );
6420 if ( rs->sr_err != LDAP_SUCCESS ) {
6421 goto out;
6422 }
6423
6424 /* Some basic validation... */
6425 for ( ml = op->orm_modlist; ml; ml = ml->sml_next ) {
6426 /* Don't allow Modify of RDN; must use ModRdn for that. */
6427 if ( ml->sml_desc == rad ) {
6428 rs->sr_err = LDAP_NOT_ALLOWED_ON_RDN;
6429 rs->sr_text = "Use modrdn to change the entry name";
6430 goto out;
6431 }
6432 /* Internal update of contextCSN? */
6433 if ( ml->sml_desc == slap_schema.si_ad_contextCSN && op->o_conn->c_conn_idx == -1 ) {
6434 do_pause = 0;
6435 break;
6436 }
6437 }
6438
6439 slap_mods_opattrs( op, &op->orm_modlist, 1 );
6440
6441 if ( do_pause ) {
6442 if ( op->o_abandon ) {
6443 rs->sr_err = SLAPD_ABANDON;
6444 goto out;
6445 }
6446 if ( slap_pause_server() < 0 )
6447 do_pause = 0;
6448 }
6449
6450 /* Strategy:
6451 * 1) perform the Modify on the cached Entry.
6452 * 2) verify that the Entry still satisfies the schema.
6453 * 3) perform the individual config operations.
6454 * 4) store Modified entry in underlying LDIF backend.
6455 */
6456 rs->sr_err = config_modify_internal( ce, op, rs, &ca );
6457 if ( rs->sr_err ) {
6458 rs->sr_text = ca.cr_msg;
6459 } else if ( cfb->cb_use_ldif ) {
6460 BackendDB *be = op->o_bd;
6461 slap_callback sc = { NULL, slap_null_cb, NULL, NULL }, *scp;
6462 struct berval dn, ndn;
6463
6464 op->o_bd = &cfb->cb_db;
6465
6466 dn = op->o_dn;
6467 ndn = op->o_ndn;
6468 op->o_dn = op->o_bd->be_rootdn;
6469 op->o_ndn = op->o_bd->be_rootndn;
6470
6471 scp = op->o_callback;
6472 op->o_callback = ≻
6473 op->o_bd->be_modify( op, rs );
6474 op->o_bd = be;
6475 op->o_callback = scp;
6476 op->o_dn = dn;
6477 op->o_ndn = ndn;
6478 }
6479
6480 if ( do_pause )
6481 slap_unpause_server();
6482 out:
6483 send_ldap_result( op, rs );
6484 slap_graduate_commit_csn( op );
6485 return rs->sr_err;
6486 }
6487
6488 static int
config_back_modrdn(Operation * op,SlapReply * rs)6489 config_back_modrdn( Operation *op, SlapReply *rs )
6490 {
6491 CfBackInfo *cfb;
6492 CfEntryInfo *ce, *last;
6493 struct berval rdn;
6494 int ixold, ixnew, dopause = 1;
6495
6496 cfb = (CfBackInfo *)op->o_bd->be_private;
6497
6498 ce = config_find_base( cfb->cb_root, &op->o_req_ndn, &last );
6499 if ( !ce ) {
6500 if ( last )
6501 rs->sr_matched = last->ce_entry->e_name.bv_val;
6502 rs->sr_err = LDAP_NO_SUCH_OBJECT;
6503 goto out;
6504 }
6505 if ( !access_allowed( op, ce->ce_entry, slap_schema.si_ad_entry,
6506 NULL, ACL_WRITE, NULL )) {
6507 rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
6508 goto out;
6509 }
6510 { Entry *parent;
6511 if ( ce->ce_parent )
6512 parent = ce->ce_parent->ce_entry;
6513 else
6514 parent = (Entry *)&slap_entry_root;
6515 if ( !access_allowed( op, parent, slap_schema.si_ad_children,
6516 NULL, ACL_WRITE, NULL )) {
6517 rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
6518 goto out;
6519 }
6520 }
6521
6522 /* We don't allow moving objects to new parents.
6523 * Generally we only allow reordering a set of ordered entries.
6524 */
6525 if ( op->orr_newSup ) {
6526 rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
6527 goto out;
6528 }
6529
6530 /* If newRDN == oldRDN, quietly succeed */
6531 dnRdn( &op->o_req_ndn, &rdn );
6532 if ( dn_match( &rdn, &op->orr_nnewrdn )) {
6533 rs->sr_err = LDAP_SUCCESS;
6534 goto out;
6535 }
6536
6537 /* Current behavior, subject to change as needed:
6538 *
6539 * For backends and overlays, we only allow renumbering.
6540 * For schema, we allow renaming with the same number.
6541 * Otherwise, the op is not allowed.
6542 */
6543
6544 if ( ce->ce_type == Cft_Schema ) {
6545 char *ptr1, *ptr2;
6546 int len;
6547
6548 /* Can't alter the main cn=schema entry */
6549 if ( ce->ce_parent->ce_type == Cft_Global ) {
6550 rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
6551 rs->sr_text = "renaming not allowed for this entry";
6552 goto out;
6553 }
6554
6555 /* We could support this later if desired */
6556 ptr1 = ber_bvchr( &rdn, '}' );
6557 ptr2 = ber_bvchr( &op->orr_newrdn, '}' );
6558 len = ptr1 - rdn.bv_val;
6559 if ( len != ptr2 - op->orr_newrdn.bv_val ||
6560 strncmp( rdn.bv_val, op->orr_newrdn.bv_val, len )) {
6561 rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
6562 rs->sr_text = "schema reordering not supported";
6563 goto out;
6564 }
6565 } else if ( ce->ce_type == Cft_Database ||
6566 ce->ce_type == Cft_Overlay ) {
6567 char *ptr1, *ptr2, *iptr1, *iptr2;
6568 int len1, len2;
6569
6570 iptr2 = ber_bvchr( &op->orr_newrdn, '=' ) + 1;
6571 if ( *iptr2 != '{' ) {
6572 rs->sr_err = LDAP_NAMING_VIOLATION;
6573 rs->sr_text = "new ordering index is required";
6574 goto out;
6575 }
6576 iptr2++;
6577 iptr1 = ber_bvchr( &rdn, '{' ) + 1;
6578 ptr1 = ber_bvchr( &rdn, '}' );
6579 ptr2 = ber_bvchr( &op->orr_newrdn, '}' );
6580 if ( !ptr2 ) {
6581 rs->sr_err = LDAP_NAMING_VIOLATION;
6582 rs->sr_text = "new ordering index is required";
6583 goto out;
6584 }
6585
6586 len1 = ptr1 - rdn.bv_val;
6587 len2 = ptr2 - op->orr_newrdn.bv_val;
6588
6589 if ( rdn.bv_len - len1 != op->orr_newrdn.bv_len - len2 ||
6590 strncmp( ptr1, ptr2, rdn.bv_len - len1 )) {
6591 rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
6592 rs->sr_text = "changing database/overlay type not allowed";
6593 goto out;
6594 }
6595 ixold = strtol( iptr1, NULL, 0 );
6596 ixnew = strtol( iptr2, &ptr1, 0 );
6597 if ( ptr1 != ptr2 || ixold < 0 || ixnew < 0 ) {
6598 rs->sr_err = LDAP_NAMING_VIOLATION;
6599 goto out;
6600 }
6601 /* config DB is always 0, cannot be changed */
6602 if ( ce->ce_type == Cft_Database && ( ixold == 0 || ixnew == 0 )) {
6603 rs->sr_err = LDAP_CONSTRAINT_VIOLATION;
6604 goto out;
6605 }
6606 } else {
6607 rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
6608 rs->sr_text = "renaming not supported for this entry";
6609 goto out;
6610 }
6611
6612 if ( op->o_abandon ) {
6613 rs->sr_err = SLAPD_ABANDON;
6614 goto out;
6615 }
6616 if ( slap_pause_server() < 0 )
6617 dopause = 0;
6618
6619 if ( ce->ce_type == Cft_Schema ) {
6620 req_modrdn_s modr = op->oq_modrdn;
6621 struct berval rdn;
6622 Attribute *a;
6623 rs->sr_err = config_rename_attr( rs, ce->ce_entry, &rdn, &a );
6624 if ( rs->sr_err == LDAP_SUCCESS ) {
6625 rs->sr_err = config_rename_one( op, rs, ce->ce_entry,
6626 ce->ce_parent, a, &op->orr_newrdn, &op->orr_nnewrdn,
6627 cfb->cb_use_ldif );
6628 }
6629 op->oq_modrdn = modr;
6630 } else {
6631 CfEntryInfo *ce2, **cprev, **cbprev, *ceold;
6632 req_modrdn_s modr = op->oq_modrdn;
6633 int i;
6634
6635 /* Advance to first of this type */
6636 cprev = &ce->ce_parent->ce_kids;
6637 for ( ce2 = *cprev; ce2 && ce2->ce_type != ce->ce_type; ) {
6638 cprev = &ce2->ce_sibs;
6639 ce2 = ce2->ce_sibs;
6640 }
6641 /* Skip the -1 entry */
6642 if ( ce->ce_type == Cft_Database ) {
6643 cprev = &ce2->ce_sibs;
6644 ce2 = ce2->ce_sibs;
6645 }
6646 cbprev = cprev;
6647
6648 /* Remove from old slot */
6649 for ( ce2 = *cprev; ce2 && ce2 != ce; ce2 = ce2->ce_sibs )
6650 cprev = &ce2->ce_sibs;
6651 *cprev = ce->ce_sibs;
6652 ceold = ce->ce_sibs;
6653
6654 /* Insert into new slot */
6655 cprev = cbprev;
6656 for ( i=0; i<ixnew; i++ ) {
6657 ce2 = *cprev;
6658 if ( !ce2 )
6659 break;
6660 cprev = &ce2->ce_sibs;
6661 }
6662 ce->ce_sibs = *cprev;
6663 *cprev = ce;
6664
6665 ixnew = i;
6666
6667 /* NOTE: These should be encoded in the OC tables, not inline here */
6668 if ( ce->ce_type == Cft_Database )
6669 backend_db_move( ce->ce_be, ixnew );
6670 else if ( ce->ce_type == Cft_Overlay )
6671 overlay_move( ce->ce_be, (slap_overinst *)ce->ce_bi, ixnew );
6672
6673 if ( ixold < ixnew ) {
6674 rs->sr_err = config_rename_del( op, rs, ce, ceold, ixold,
6675 cfb->cb_use_ldif );
6676 } else {
6677 rs->sr_err = config_rename_add( op, rs, ce, ixnew, 1,
6678 ixold - ixnew, cfb->cb_use_ldif );
6679 }
6680 op->oq_modrdn = modr;
6681 }
6682
6683 if ( dopause )
6684 slap_unpause_server();
6685 out:
6686 send_ldap_result( op, rs );
6687 return rs->sr_err;
6688 }
6689
6690 static int
config_back_delete(Operation * op,SlapReply * rs)6691 config_back_delete( Operation *op, SlapReply *rs )
6692 {
6693 #ifdef SLAP_CONFIG_DELETE
6694 CfBackInfo *cfb;
6695 CfEntryInfo *ce, *last, *ce2;
6696 int dopause = 1;
6697
6698 cfb = (CfBackInfo *)op->o_bd->be_private;
6699
6700 ce = config_find_base( cfb->cb_root, &op->o_req_ndn, &last );
6701 if ( !ce ) {
6702 if ( last )
6703 rs->sr_matched = last->ce_entry->e_name.bv_val;
6704 rs->sr_err = LDAP_NO_SUCH_OBJECT;
6705 } else if ( ce->ce_kids ) {
6706 rs->sr_err = LDAP_NOT_ALLOWED_ON_NONLEAF;
6707 } else if ( op->o_abandon ) {
6708 rs->sr_err = SLAPD_ABANDON;
6709 } else if ( ce->ce_type == Cft_Overlay ||
6710 ce->ce_type == Cft_Database ||
6711 ce->ce_type == Cft_Misc ){
6712 char *iptr;
6713 int count, ixold;
6714
6715 if ( slap_pause_server() < 0 )
6716 dopause = 0;
6717
6718 if ( ce->ce_type == Cft_Overlay ){
6719 overlay_remove( ce->ce_be, (slap_overinst *)ce->ce_bi, op );
6720 } else if ( ce->ce_type == Cft_Misc ) {
6721 /*
6722 * only Cft_Misc objects that have a co_lddel handler set in
6723 * the ConfigOCs struct can be deleted. This code also
6724 * assumes that the entry can be only have one objectclass
6725 * with co_type == Cft_Misc
6726 */
6727 ConfigOCs co, *coptr;
6728 Attribute *oc_at;
6729 int i;
6730
6731 oc_at = attr_find( ce->ce_entry->e_attrs,
6732 slap_schema.si_ad_objectClass );
6733 if ( !oc_at ) {
6734 rs->sr_err = LDAP_OTHER;
6735 rs->sr_text = "objectclass not found";
6736 if ( dopause ) slap_unpause_server();
6737 goto out;
6738 }
6739 for ( i=0; !BER_BVISNULL(&oc_at->a_nvals[i]); i++ ) {
6740 co.co_name = &oc_at->a_nvals[i];
6741 coptr = ldap_avl_find( CfOcTree, &co, CfOc_cmp );
6742 if ( coptr == NULL || coptr->co_type != Cft_Misc ) {
6743 continue;
6744 }
6745 if ( ! coptr->co_lddel || coptr->co_lddel( ce, op ) ){
6746 rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
6747 if ( ! coptr->co_lddel ) {
6748 rs->sr_text = "No delete handler found";
6749 } else {
6750 rs->sr_err = LDAP_OTHER;
6751 /* FIXME: We should return a helpful error message
6752 * here */
6753 }
6754 if ( dopause ) slap_unpause_server();
6755 goto out;
6756 }
6757 break;
6758 }
6759 } else if (ce->ce_type == Cft_Database ) {
6760 if ( ce->ce_be == frontendDB || ce->ce_be == op->o_bd ){
6761 rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
6762 rs->sr_text = "Cannot delete config or frontend database";
6763 if ( dopause ) slap_unpause_server();
6764 goto out;
6765 }
6766 if ( ce->ce_be->bd_info->bi_db_close ) {
6767 ce->ce_be->bd_info->bi_db_close( ce->ce_be, NULL );
6768 }
6769 backend_destroy_one( ce->ce_be, 1);
6770 }
6771
6772 /* remove CfEntryInfo from the siblings list */
6773 if ( ce->ce_parent->ce_kids == ce ) {
6774 ce->ce_parent->ce_kids = ce->ce_sibs;
6775 } else {
6776 for ( ce2 = ce->ce_parent->ce_kids ; ce2; ce2 = ce2->ce_sibs ) {
6777 if ( ce2->ce_sibs == ce ) {
6778 ce2->ce_sibs = ce->ce_sibs;
6779 break;
6780 }
6781 }
6782 }
6783
6784 /* remove from underlying database */
6785 if ( cfb->cb_use_ldif ) {
6786 BackendDB *be = op->o_bd;
6787 slap_callback sc = { NULL, slap_null_cb, NULL, NULL }, *scp;
6788 struct berval dn, ndn, req_dn, req_ndn;
6789
6790 op->o_bd = &cfb->cb_db;
6791
6792 dn = op->o_dn;
6793 ndn = op->o_ndn;
6794 req_dn = op->o_req_dn;
6795 req_ndn = op->o_req_ndn;
6796
6797 op->o_dn = op->o_bd->be_rootdn;
6798 op->o_ndn = op->o_bd->be_rootndn;
6799 op->o_req_dn = ce->ce_entry->e_name;
6800 op->o_req_ndn = ce->ce_entry->e_nname;
6801
6802 scp = op->o_callback;
6803 op->o_callback = ≻
6804 op->o_bd->be_delete( op, rs );
6805 op->o_bd = be;
6806 op->o_callback = scp;
6807 op->o_dn = dn;
6808 op->o_ndn = ndn;
6809 op->o_req_dn = req_dn;
6810 op->o_req_ndn = req_ndn;
6811 }
6812
6813 /* renumber siblings */
6814 iptr = ber_bvchr( &op->o_req_ndn, '{' ) + 1;
6815 ixold = strtol( iptr, NULL, 0 );
6816 for (ce2 = ce->ce_sibs, count=0; ce2; ce2=ce2->ce_sibs) {
6817 config_renumber_one( op, rs, ce2->ce_parent, ce2->ce_entry,
6818 count+ixold, 0, cfb->cb_use_ldif );
6819 count++;
6820 }
6821
6822 ce->ce_entry->e_private=NULL;
6823 entry_free(ce->ce_entry);
6824 ch_free(ce);
6825 if ( dopause ) slap_unpause_server();
6826 } else {
6827 rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
6828 }
6829 out:
6830 #else
6831 rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
6832 #endif /* SLAP_CONFIG_DELETE */
6833 send_ldap_result( op, rs );
6834 return rs->sr_err;
6835 }
6836
6837 static int
config_back_search(Operation * op,SlapReply * rs)6838 config_back_search( Operation *op, SlapReply *rs )
6839 {
6840 CfBackInfo *cfb;
6841 CfEntryInfo *ce, *last;
6842 slap_mask_t mask;
6843
6844 cfb = (CfBackInfo *)op->o_bd->be_private;
6845
6846 ce = config_find_base( cfb->cb_root, &op->o_req_ndn, &last );
6847 if ( !ce ) {
6848 if ( last )
6849 rs->sr_matched = last->ce_entry->e_name.bv_val;
6850 rs->sr_err = LDAP_NO_SUCH_OBJECT;
6851 goto out;
6852 }
6853 if ( !access_allowed_mask( op, ce->ce_entry, slap_schema.si_ad_entry, NULL,
6854 ACL_SEARCH, NULL, &mask ))
6855 {
6856 if ( !ACL_GRANT( mask, ACL_DISCLOSE )) {
6857 rs->sr_err = LDAP_NO_SUCH_OBJECT;
6858 } else {
6859 rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
6860 }
6861 goto out;
6862 }
6863 switch ( op->ors_scope ) {
6864 case LDAP_SCOPE_BASE:
6865 case LDAP_SCOPE_SUBTREE:
6866 rs->sr_err = config_send( op, rs, ce, 0 );
6867 break;
6868
6869 case LDAP_SCOPE_ONELEVEL:
6870 for (ce = ce->ce_kids; ce; ce=ce->ce_sibs) {
6871 rs->sr_err = config_send( op, rs, ce, 1 );
6872 if ( rs->sr_err ) {
6873 break;
6874 }
6875 }
6876 break;
6877 }
6878
6879 out:
6880 send_ldap_result( op, rs );
6881 return rs->sr_err;
6882 }
6883
6884 /* no-op, we never free entries */
config_entry_release(Operation * op,Entry * e,int rw)6885 int config_entry_release(
6886 Operation *op,
6887 Entry *e,
6888 int rw )
6889 {
6890 int rc = LDAP_SUCCESS;
6891
6892 if ( !e->e_private ) {
6893 BackendDB *be = op->o_bd;
6894 CfBackInfo *cfb = be->be_private;
6895 BackendInfo *bi = cfb->cb_db.bd_info;
6896
6897 if ( bi && bi->bi_entry_release_rw ) {
6898 op->o_bd = &cfb->cb_db;
6899 rc = bi->bi_entry_release_rw( op, e, rw );
6900 op->o_bd = be;
6901 } else {
6902 entry_free( e );
6903 }
6904 }
6905 return rc;
6906 }
6907
6908 /* return LDAP_SUCCESS IFF we can retrieve the specified entry.
6909 */
config_back_entry_get(Operation * op,struct berval * ndn,ObjectClass * oc,AttributeDescription * at,int rw,Entry ** ent)6910 int config_back_entry_get(
6911 Operation *op,
6912 struct berval *ndn,
6913 ObjectClass *oc,
6914 AttributeDescription *at,
6915 int rw,
6916 Entry **ent )
6917 {
6918 CfBackInfo *cfb;
6919 CfEntryInfo *ce, *last;
6920 int rc = LDAP_NO_SUCH_OBJECT;
6921
6922 cfb = (CfBackInfo *)op->o_bd->be_private;
6923
6924 ce = config_find_base( cfb->cb_root, ndn, &last );
6925 if ( ce ) {
6926 *ent = ce->ce_entry;
6927 if ( *ent ) {
6928 rc = LDAP_SUCCESS;
6929 if ( oc && !is_entry_objectclass_or_sub( *ent, oc ) ) {
6930 rc = LDAP_NO_SUCH_ATTRIBUTE;
6931 *ent = NULL;
6932 }
6933 }
6934 }
6935
6936 return rc;
6937 }
6938
6939 static int
config_build_attrs(Entry * e,AttributeType ** at,AttributeDescription * ad,ConfigTable * ct,ConfigArgs * c)6940 config_build_attrs( Entry *e, AttributeType **at, AttributeDescription *ad,
6941 ConfigTable *ct, ConfigArgs *c )
6942 {
6943 int i, rc;
6944
6945 for (; at && *at; at++) {
6946 /* Skip the naming attr */
6947 if ((*at)->sat_ad == ad || (*at)->sat_ad == slap_schema.si_ad_cn )
6948 continue;
6949 for (i=0;ct[i].name;i++) {
6950 if (ct[i].ad == (*at)->sat_ad) {
6951 rc = config_get_vals(&ct[i], c);
6952 /* NOTE: tolerate that config_get_vals()
6953 * returns success with no values */
6954 if (rc == LDAP_SUCCESS && c->rvalue_vals != NULL ) {
6955 if ( c->rvalue_nvals )
6956 rc = attr_merge(e, ct[i].ad, c->rvalue_vals,
6957 c->rvalue_nvals);
6958 else {
6959 slap_syntax_validate_func *validate =
6960 ct[i].ad->ad_type->sat_syntax->ssyn_validate;
6961 if ( validate ) {
6962 int j;
6963 for ( j=0; c->rvalue_vals[j].bv_val; j++ ) {
6964 rc = ordered_value_validate( ct[i].ad,
6965 &c->rvalue_vals[j], LDAP_MOD_ADD );
6966 if ( rc ) {
6967 Debug( LDAP_DEBUG_ANY,
6968 "config_build_attrs: error %d on %s value #%d\n",
6969 rc, ct[i].ad->ad_cname.bv_val, j );
6970 return rc;
6971 }
6972 }
6973 }
6974
6975 rc = attr_merge_normalize(e, ct[i].ad,
6976 c->rvalue_vals, NULL);
6977 }
6978 ber_bvarray_free( c->rvalue_nvals );
6979 ber_bvarray_free( c->rvalue_vals );
6980 if ( rc ) {
6981 Debug( LDAP_DEBUG_ANY,
6982 "config_build_attrs: error %d on %s\n",
6983 rc, ct[i].ad->ad_cname.bv_val );
6984 return rc;
6985 }
6986 }
6987 break;
6988 }
6989 }
6990 }
6991 return 0;
6992 }
6993
6994 /* currently (2010) does not access rs except possibly writing rs->sr_err */
6995
6996 Entry *
config_build_entry(Operation * op,SlapReply * rs,CfEntryInfo * parent,ConfigArgs * c,struct berval * rdn,ConfigOCs * main,ConfigOCs * extra)6997 config_build_entry( Operation *op, SlapReply *rs, CfEntryInfo *parent,
6998 ConfigArgs *c, struct berval *rdn, ConfigOCs *main, ConfigOCs *extra )
6999 {
7000 Entry *e = entry_alloc();
7001 CfEntryInfo *ce = ch_calloc( 1, sizeof(CfEntryInfo) );
7002 AttributeDescription *ad = NULL;
7003 int cnt, rc;
7004 const char *text = "";
7005 Attribute *oc_at;
7006 struct berval pdn;
7007 ObjectClass *oc;
7008 CfEntryInfo *ceprev = NULL;
7009 LDAPRDN rDN;
7010
7011 Debug( LDAP_DEBUG_TRACE, "config_build_entry: \"%s\"\n", rdn->bv_val );
7012 e->e_private = ce;
7013 ce->ce_entry = e;
7014 ce->ce_type = main->co_type;
7015 ce->ce_parent = parent;
7016 if ( parent ) {
7017 pdn = parent->ce_entry->e_nname;
7018 if ( parent->ce_kids && parent->ce_kids->ce_type <= ce->ce_type )
7019 for ( ceprev = parent->ce_kids; ceprev->ce_sibs &&
7020 ceprev->ce_type <= ce->ce_type;
7021 ceprev = ceprev->ce_sibs );
7022 } else {
7023 BER_BVZERO( &pdn );
7024 }
7025
7026 ce->ce_private = c->ca_private;
7027 ce->ce_be = c->be;
7028 ce->ce_bi = c->bi;
7029
7030 build_new_dn( &e->e_name, &pdn, rdn, NULL );
7031 ber_dupbv( &e->e_nname, &e->e_name );
7032
7033 attr_merge_normalize_one(e, slap_schema.si_ad_objectClass,
7034 main->co_name, NULL );
7035 if ( extra )
7036 attr_merge_normalize_one(e, slap_schema.si_ad_objectClass,
7037 extra->co_name, NULL );
7038
7039 rc = ldap_bv2rdn( rdn, &rDN, (char **)&text, LDAP_DN_FORMAT_LDAP );
7040 if ( rc ) {
7041 goto fail;
7042 }
7043 for ( cnt = 0; rDN[cnt]; cnt++ ) {
7044 LDAPAVA *ava = rDN[cnt];
7045
7046 ad = NULL;
7047 rc = slap_bv2ad( &ava->la_attr, &ad, &text );
7048 if ( rc ) {
7049 break;
7050 }
7051 if ( !ad->ad_type->sat_equality ) {
7052 rc = LDAP_CONSTRAINT_VIOLATION;
7053 text = "attribute has no equality matching rule";
7054 break;
7055 }
7056 if ( !ad->ad_type->sat_equality->smr_match ) {
7057 rc = LDAP_CONSTRAINT_VIOLATION;
7058 text = "attribute has unsupported equality matching rule";
7059 break;
7060 }
7061 attr_merge_normalize_one(e, ad, &ava->la_value, NULL );
7062 }
7063 ldap_rdnfree( rDN );
7064 if ( rc ) {
7065 goto fail;
7066 }
7067
7068 oc = main->co_oc;
7069 c->table = main->co_type;
7070 if ( oc->soc_required ) {
7071 rc = config_build_attrs( e, oc->soc_required, ad, main->co_table, c );
7072 if ( rc ) goto fail;
7073 }
7074
7075 if ( oc->soc_allowed ) {
7076 rc = config_build_attrs( e, oc->soc_allowed, ad, main->co_table, c );
7077 if ( rc ) goto fail;
7078 }
7079
7080 if ( extra ) {
7081 oc = extra->co_oc;
7082 c->table = extra->co_type;
7083 if ( oc->soc_required ) {
7084 rc = config_build_attrs( e, oc->soc_required, ad, extra->co_table, c );
7085 if ( rc ) goto fail;
7086 }
7087
7088 if ( oc->soc_allowed ) {
7089 rc = config_build_attrs( e, oc->soc_allowed, ad, extra->co_table, c );
7090 if ( rc ) goto fail;
7091 }
7092 }
7093
7094 oc_at = attr_find( e->e_attrs, slap_schema.si_ad_objectClass );
7095 rc = structural_class(oc_at->a_vals, &oc, NULL, &text, c->cr_msg,
7096 sizeof(c->cr_msg), op ? op->o_tmpmemctx : NULL );
7097 if ( rc != LDAP_SUCCESS ) {
7098 fail:
7099 Debug( LDAP_DEBUG_ANY,
7100 "config_build_entry: build \"%s\" failed: \"%s\"\n",
7101 rdn->bv_val, text );
7102 return NULL;
7103 }
7104 attr_merge_normalize_one(e, slap_schema.si_ad_structuralObjectClass, &oc->soc_cname, NULL );
7105 if ( op ) {
7106 op->ora_e = e;
7107 op->ora_modlist = NULL;
7108 slap_add_opattrs( op, NULL, NULL, 0, 0 );
7109 if ( !op->o_noop ) {
7110 SlapReply rs2 = {REP_RESULT};
7111 op->o_bd->be_add( op, &rs2 );
7112 rs->sr_err = rs2.sr_err;
7113 rs_assert_done( &rs2 );
7114 if ( ( rs2.sr_err != LDAP_SUCCESS )
7115 && (rs2.sr_err != LDAP_ALREADY_EXISTS) ) {
7116 goto fail;
7117 }
7118 }
7119 }
7120 if ( ceprev ) {
7121 ce->ce_sibs = ceprev->ce_sibs;
7122 ceprev->ce_sibs = ce;
7123 } else if ( parent ) {
7124 ce->ce_sibs = parent->ce_kids;
7125 parent->ce_kids = ce;
7126 }
7127
7128 return e;
7129 }
7130
7131 static int
config_build_schema_inc(ConfigArgs * c,CfEntryInfo * ceparent,Operation * op,SlapReply * rs)7132 config_build_schema_inc( ConfigArgs *c, CfEntryInfo *ceparent,
7133 Operation *op, SlapReply *rs )
7134 {
7135 Entry *e;
7136 ConfigFile *cf = c->ca_private;
7137 char *ptr;
7138 struct berval bv, rdn;
7139
7140 for (; cf; cf=cf->c_sibs, c->depth++) {
7141 if ( !cf->c_at_head && !cf->c_cr_head && !cf->c_oc_head &&
7142 !cf->c_om_head && !cf->c_syn_head && !cf->c_kids ) continue;
7143 c->value_dn.bv_val = c->log;
7144 LUTIL_SLASHPATH( cf->c_file.bv_val );
7145 bv.bv_val = strrchr(cf->c_file.bv_val, LDAP_DIRSEP[0]);
7146 if ( !bv.bv_val ) {
7147 bv = cf->c_file;
7148 } else {
7149 bv.bv_val++;
7150 bv.bv_len = cf->c_file.bv_len - (bv.bv_val - cf->c_file.bv_val);
7151 }
7152 ptr = strchr( bv.bv_val, '.' );
7153 if ( ptr )
7154 bv.bv_len = ptr - bv.bv_val;
7155 c->value_dn.bv_len = snprintf(c->value_dn.bv_val, sizeof( c->log ), "cn=" SLAP_X_ORDERED_FMT, c->depth);
7156 if ( c->value_dn.bv_len >= sizeof( c->log ) ) {
7157 /* FIXME: how can indicate error? */
7158 return -1;
7159 }
7160 strncpy( c->value_dn.bv_val + c->value_dn.bv_len, bv.bv_val,
7161 bv.bv_len );
7162 c->value_dn.bv_len += bv.bv_len;
7163 c->value_dn.bv_val[c->value_dn.bv_len] ='\0';
7164 if ( rdnNormalize( 0, NULL, NULL, &c->value_dn, &rdn, NULL )) {
7165 Debug( LDAP_DEBUG_ANY,
7166 "config_build_schema_inc: invalid schema name \"%s\"\n",
7167 bv.bv_val );
7168 return -1;
7169 }
7170
7171 c->ca_private = cf;
7172 e = config_build_entry( op, rs, ceparent, c, &rdn,
7173 &CFOC_SCHEMA, NULL );
7174 ch_free( rdn.bv_val );
7175 if ( !e ) {
7176 return -1;
7177 } else if ( e && cf->c_kids ) {
7178 c->ca_private = cf->c_kids;
7179 config_build_schema_inc( c, e->e_private, op, rs );
7180 }
7181 }
7182 return 0;
7183 }
7184
7185 #ifdef SLAPD_MODULES
7186
7187 static int
config_build_modules(ConfigArgs * c,CfEntryInfo * ceparent,Operation * op,SlapReply * rs)7188 config_build_modules( ConfigArgs *c, CfEntryInfo *ceparent,
7189 Operation *op, SlapReply *rs )
7190 {
7191 int i;
7192 ModPaths *mp;
7193
7194 for (i=0, mp=&modpaths; mp; mp=mp->mp_next, i++) {
7195 if ( BER_BVISNULL( &mp->mp_path ) && !mp->mp_loads )
7196 continue;
7197 c->value_dn.bv_val = c->log;
7198 c->value_dn.bv_len = snprintf(c->value_dn.bv_val, sizeof( c->log ), "cn=module" SLAP_X_ORDERED_FMT, i);
7199 if ( c->value_dn.bv_len >= sizeof( c->log ) ) {
7200 /* FIXME: how can indicate error? */
7201 return -1;
7202 }
7203 c->ca_private = mp;
7204 if ( ! config_build_entry( op, rs, ceparent, c, &c->value_dn, &CFOC_MODULE, NULL )) {
7205 return -1;
7206 }
7207 }
7208 return 0;
7209 }
7210 #endif
7211
7212 static int
config_check_schema(Operation * op,CfBackInfo * cfb)7213 config_check_schema(Operation *op, CfBackInfo *cfb)
7214 {
7215 struct berval schema_dn = BER_BVC(SCHEMA_RDN "," CONFIG_RDN);
7216 ConfigArgs c = {0};
7217 CfEntryInfo *ce, *last;
7218 Entry *e;
7219
7220 /* If there's no root entry, we must be in the midst of converting */
7221 if ( !cfb->cb_root )
7222 return 0;
7223
7224 /* Make sure the main schema entry exists */
7225 ce = config_find_base( cfb->cb_root, &schema_dn, &last );
7226 if ( ce ) {
7227 Attribute *a;
7228 struct berval *bv;
7229
7230 e = ce->ce_entry;
7231
7232 /* Make sure it's up to date */
7233 if ( cf_om_tail != om_sys_tail ) {
7234 a = attr_find( e->e_attrs, cfAd_om );
7235 if ( a ) {
7236 if ( a->a_nvals != a->a_vals )
7237 ber_bvarray_free( a->a_nvals );
7238 ber_bvarray_free( a->a_vals );
7239 a->a_vals = NULL;
7240 a->a_nvals = NULL;
7241 a->a_numvals = 0;
7242 }
7243 oidm_unparse( &bv, NULL, NULL, 1 );
7244 attr_merge_normalize( e, cfAd_om, bv, NULL );
7245 ber_bvarray_free( bv );
7246 cf_om_tail = om_sys_tail;
7247 }
7248 if ( cf_at_tail != at_sys_tail ) {
7249 a = attr_find( e->e_attrs, cfAd_attr );
7250 if ( a ) {
7251 if ( a->a_nvals != a->a_vals )
7252 ber_bvarray_free( a->a_nvals );
7253 ber_bvarray_free( a->a_vals );
7254 a->a_vals = NULL;
7255 a->a_nvals = NULL;
7256 a->a_numvals = 0;
7257 }
7258 at_unparse( &bv, NULL, NULL, 1 );
7259 attr_merge_normalize( e, cfAd_attr, bv, NULL );
7260 ber_bvarray_free( bv );
7261 cf_at_tail = at_sys_tail;
7262 }
7263 if ( cf_oc_tail != oc_sys_tail ) {
7264 a = attr_find( e->e_attrs, cfAd_oc );
7265 if ( a ) {
7266 if ( a->a_nvals != a->a_vals )
7267 ber_bvarray_free( a->a_nvals );
7268 ber_bvarray_free( a->a_vals );
7269 a->a_vals = NULL;
7270 a->a_nvals = NULL;
7271 a->a_numvals = 0;
7272 }
7273 oc_unparse( &bv, NULL, NULL, 1 );
7274 attr_merge_normalize( e, cfAd_oc, bv, NULL );
7275 ber_bvarray_free( bv );
7276 cf_oc_tail = oc_sys_tail;
7277 }
7278 if ( cf_syn_tail != syn_sys_tail ) {
7279 a = attr_find( e->e_attrs, cfAd_syntax );
7280 if ( a ) {
7281 if ( a->a_nvals != a->a_vals )
7282 ber_bvarray_free( a->a_nvals );
7283 ber_bvarray_free( a->a_vals );
7284 a->a_vals = NULL;
7285 a->a_nvals = NULL;
7286 a->a_numvals = 0;
7287 }
7288 syn_unparse( &bv, NULL, NULL, 1 );
7289 attr_merge_normalize( e, cfAd_syntax, bv, NULL );
7290 ber_bvarray_free( bv );
7291 cf_syn_tail = syn_sys_tail;
7292 }
7293 } else {
7294 SlapReply rs = {REP_RESULT};
7295 c.ca_private = NULL;
7296 e = config_build_entry( op, &rs, cfb->cb_root, &c, &schema_rdn,
7297 &CFOC_SCHEMA, NULL );
7298 if ( !e ) {
7299 return -1;
7300 }
7301 ce = e->e_private;
7302 ce->ce_private = cfb->cb_config;
7303 cf_at_tail = at_sys_tail;
7304 cf_oc_tail = oc_sys_tail;
7305 cf_om_tail = om_sys_tail;
7306 cf_syn_tail = syn_sys_tail;
7307 }
7308 return 0;
7309 }
7310
7311 static const char *defacl[] = {
7312 NULL, "to", "*", "by", "*", "none", NULL
7313 };
7314
7315 static int
config_back_db_open(BackendDB * be,ConfigReply * cr)7316 config_back_db_open( BackendDB *be, ConfigReply *cr )
7317 {
7318 CfBackInfo *cfb = be->be_private;
7319 struct berval rdn;
7320 Entry *e;
7321 CfEntryInfo *ce, *ceparent;
7322 int i, unsupp = 0;
7323 BackendInfo *bi;
7324 ConfigArgs c;
7325 Connection conn = {0};
7326 OperationBuffer opbuf;
7327 Operation *op;
7328 slap_callback cb = { NULL, slap_null_cb, NULL, NULL };
7329 SlapReply rs = {REP_RESULT};
7330 void *thrctx = NULL;
7331 AccessControl *save_access;
7332
7333 Debug( LDAP_DEBUG_TRACE, "config_back_db_open\n" );
7334
7335 /* If we have no explicitly configured ACLs, don't just use
7336 * the global ACLs. Explicitly deny access to everything.
7337 */
7338 save_access = be->bd_self->be_acl;
7339 be->bd_self->be_acl = NULL;
7340 parse_acl(be->bd_self, "config_back_db_open", 0, 6, (char **)defacl, 0 );
7341 defacl_parsed = be->bd_self->be_acl;
7342 if ( save_access ) {
7343 be->bd_self->be_acl = save_access;
7344 } else {
7345 Debug( LDAP_DEBUG_CONFIG, "config_back_db_open: "
7346 "No explicit ACL for back-config configured. "
7347 "Using hardcoded default\n" );
7348 }
7349
7350 thrctx = ldap_pvt_thread_pool_context();
7351 connection_fake_init( &conn, &opbuf, thrctx );
7352 op = &opbuf.ob_op;
7353
7354 op->o_tag = LDAP_REQ_ADD;
7355 op->o_callback = &cb;
7356 op->o_bd = &cfb->cb_db;
7357 op->o_dn = op->o_bd->be_rootdn;
7358 op->o_ndn = op->o_bd->be_rootndn;
7359
7360 if ( !cfb->cb_use_ldif ) {
7361 op->o_noop = 1;
7362 }
7363
7364 /* If we read the config from back-ldif, do some quick sanity checks */
7365 if ( cfb->cb_got_ldif ) {
7366 return config_check_schema( op, cfb );
7367 }
7368
7369 /* create root of tree */
7370 rdn = config_rdn;
7371 c.ca_private = cfb->cb_config;
7372 c.be = frontendDB;
7373 e = config_build_entry( op, &rs, NULL, &c, &rdn, &CFOC_GLOBAL, NULL );
7374 if ( !e ) {
7375 return -1;
7376 }
7377 ce = e->e_private;
7378 cfb->cb_root = ce;
7379
7380 ceparent = ce;
7381
7382 #ifdef SLAPD_MODULES
7383 /* Create Module nodes... */
7384 if ( modpaths.mp_loads ) {
7385 if ( config_build_modules( &c, ceparent, op, &rs ) ){
7386 return -1;
7387 }
7388 }
7389 #endif
7390
7391 /* Create schema nodes... cn=schema will contain the hardcoded core
7392 * schema, read-only. Child objects will contain runtime loaded schema
7393 * files.
7394 */
7395 rdn = schema_rdn;
7396 c.ca_private = NULL;
7397 e = config_build_entry( op, &rs, ceparent, &c, &rdn, &CFOC_SCHEMA, NULL );
7398 if ( !e ) {
7399 return -1;
7400 }
7401 ce = e->e_private;
7402 ce->ce_private = cfb->cb_config;
7403 cf_at_tail = at_sys_tail;
7404 cf_oc_tail = oc_sys_tail;
7405 cf_om_tail = om_sys_tail;
7406 cf_syn_tail = syn_sys_tail;
7407
7408 /* Create schema nodes for included schema... */
7409 if ( cfb->cb_config->c_kids ) {
7410 int rc;
7411 c.depth = 0;
7412 c.ca_private = cfb->cb_config->c_kids;
7413 rc = config_build_schema_inc( &c, ce, op, &rs );
7414 if ( rc ) {
7415 return -1;
7416 }
7417 }
7418
7419 /* Create backend nodes. Skip if they don't provide a cf_table.
7420 * There usually aren't any of these.
7421 */
7422
7423 c.line = 0;
7424 i = 0;
7425 LDAP_STAILQ_FOREACH( bi, &backendInfo, bi_next) {
7426 if (!bi->bi_cf_ocs) {
7427 /* If it only supports the old config mech, complain. */
7428 if ( bi->bi_config ) {
7429 Debug( LDAP_DEBUG_ANY,
7430 "WARNING: No dynamic config support for backend %s.\n",
7431 bi->bi_type );
7432 unsupp++;
7433 }
7434 continue;
7435 }
7436 if ( !bi->bi_private && !(bi->bi_flags & SLAP_BFLAG_STANDALONE) ) continue;
7437
7438 rdn.bv_val = c.log;
7439 rdn.bv_len = snprintf(rdn.bv_val, sizeof( c.log ),
7440 "%s=" SLAP_X_ORDERED_FMT "%s", cfAd_backend->ad_cname.bv_val,
7441 i, bi->bi_type);
7442 if ( rdn.bv_len >= sizeof( c.log ) ) {
7443 /* FIXME: holler ... */ ;
7444 }
7445 c.bi = bi;
7446 e = config_build_entry( op, &rs, ceparent, &c, &rdn, &CFOC_BACKEND,
7447 bi->bi_cf_ocs );
7448 if ( !e ) {
7449 return -1;
7450 }
7451 if ( bi->bi_cf_ocs && bi->bi_cf_ocs->co_cfadd ) {
7452 rs_reinit( &rs, REP_RESULT );
7453 bi->bi_cf_ocs->co_cfadd( op, &rs, e, &c );
7454 }
7455 i++;
7456 }
7457
7458 /* Create database nodes... */
7459 frontendDB->be_cf_ocs = &CFOC_FRONTEND;
7460 LDAP_STAILQ_NEXT(frontendDB, be_next) = LDAP_STAILQ_FIRST(&backendDB);
7461 for ( i = -1, be = frontendDB ; be;
7462 i++, be = LDAP_STAILQ_NEXT( be, be_next )) {
7463 slap_overinfo *oi = NULL;
7464
7465 if ( overlay_is_over( be )) {
7466 oi = be->bd_info->bi_private;
7467 bi = oi->oi_orig;
7468 } else {
7469 bi = be->bd_info;
7470 }
7471
7472 /* If this backend supports the old config mechanism, but not
7473 * the new mech, complain.
7474 */
7475 if ( !be->be_cf_ocs && bi->bi_db_config ) {
7476 Debug( LDAP_DEBUG_ANY,
7477 "WARNING: No dynamic config support for database %s.\n",
7478 bi->bi_type );
7479 unsupp++;
7480 }
7481 rdn.bv_val = c.log;
7482 rdn.bv_len = snprintf(rdn.bv_val, sizeof( c.log ),
7483 "%s=" SLAP_X_ORDERED_FMT "%s", cfAd_database->ad_cname.bv_val,
7484 i, bi->bi_type);
7485 if ( rdn.bv_len >= sizeof( c.log ) ) {
7486 /* FIXME: holler ... */ ;
7487 }
7488 c.be = be;
7489 c.bi = bi;
7490 e = config_build_entry( op, &rs, ceparent, &c, &rdn, &CFOC_DATABASE,
7491 be->be_cf_ocs );
7492 if ( !e ) {
7493 return -1;
7494 }
7495 ce = e->e_private;
7496 if ( be->be_cf_ocs && be->be_cf_ocs->co_cfadd ) {
7497 rs_reinit( &rs, REP_RESULT );
7498 be->be_cf_ocs->co_cfadd( op, &rs, e, &c );
7499 }
7500 /* Iterate through overlays */
7501 if ( oi ) {
7502 slap_overinst *on;
7503 Entry *oe;
7504 int j;
7505 voidList *vl, *v0 = NULL;
7506
7507 /* overlays are in LIFO order, must reverse stack */
7508 for (on=oi->oi_list; on; on=on->on_next) {
7509 vl = ch_malloc( sizeof( voidList ));
7510 vl->vl_next = v0;
7511 v0 = vl;
7512 vl->vl_ptr = on;
7513 }
7514 for (j=0; vl; j++,vl=v0) {
7515 on = vl->vl_ptr;
7516 v0 = vl->vl_next;
7517 ch_free( vl );
7518 if ( on->on_bi.bi_db_config && !on->on_bi.bi_cf_ocs ) {
7519 Debug( LDAP_DEBUG_ANY,
7520 "WARNING: No dynamic config support for overlay %s.\n",
7521 on->on_bi.bi_type );
7522 unsupp++;
7523 }
7524 rdn.bv_val = c.log;
7525 rdn.bv_len = snprintf(rdn.bv_val, sizeof( c.log ),
7526 "%s=" SLAP_X_ORDERED_FMT "%s",
7527 cfAd_overlay->ad_cname.bv_val, j, on->on_bi.bi_type );
7528 if ( rdn.bv_len >= sizeof( c.log ) ) {
7529 /* FIXME: holler ... */ ;
7530 }
7531 c.be = be;
7532 c.bi = &on->on_bi;
7533 oe = config_build_entry( op, &rs, ce, &c, &rdn,
7534 &CFOC_OVERLAY, c.bi->bi_cf_ocs );
7535 if ( !oe ) {
7536 return -1;
7537 }
7538 if ( c.bi->bi_cf_ocs && c.bi->bi_cf_ocs->co_cfadd ) {
7539 rs_reinit( &rs, REP_RESULT );
7540 c.bi->bi_cf_ocs->co_cfadd( op, &rs, oe, &c );
7541 }
7542 }
7543 }
7544 }
7545 if ( thrctx )
7546 ldap_pvt_thread_pool_context_reset( thrctx );
7547
7548 if ( unsupp && cfb->cb_use_ldif ) {
7549 Debug( LDAP_DEBUG_ANY, "\nWARNING: The converted cn=config "
7550 "directory is incomplete and may not work.\n\n" );
7551 }
7552
7553 return 0;
7554 }
7555
7556 static void
cfb_free_cffile(ConfigFile * cf)7557 cfb_free_cffile( ConfigFile *cf )
7558 {
7559 ConfigFile *next;
7560
7561 for (; cf; cf=next) {
7562 next = cf->c_sibs;
7563 if ( cf->c_kids )
7564 cfb_free_cffile( cf->c_kids );
7565 ch_free( cf->c_file.bv_val );
7566 ber_bvarray_free( cf->c_dseFiles );
7567 ch_free( cf );
7568 }
7569 }
7570
7571 static void
cfb_free_entries(CfEntryInfo * ce)7572 cfb_free_entries( CfEntryInfo *ce )
7573 {
7574 CfEntryInfo *next;
7575
7576 for (; ce; ce=next) {
7577 next = ce->ce_sibs;
7578 if ( ce->ce_kids )
7579 cfb_free_entries( ce->ce_kids );
7580 ce->ce_entry->e_private = NULL;
7581 entry_free( ce->ce_entry );
7582 ch_free( ce );
7583 }
7584 }
7585
7586 static int
config_back_db_close(BackendDB * be,ConfigReply * cr)7587 config_back_db_close( BackendDB *be, ConfigReply *cr )
7588 {
7589 CfBackInfo *cfb = be->be_private;
7590
7591 cfb_free_entries( cfb->cb_root );
7592 cfb->cb_root = NULL;
7593
7594 if ( cfb->cb_db.bd_info ) {
7595 backend_shutdown( &cfb->cb_db );
7596 }
7597
7598 if ( defacl_parsed && be->be_acl != defacl_parsed ) {
7599 acl_free( defacl_parsed );
7600 defacl_parsed = NULL;
7601 }
7602
7603 return 0;
7604 }
7605
7606 static int
config_back_db_destroy(BackendDB * be,ConfigReply * cr)7607 config_back_db_destroy( BackendDB *be, ConfigReply *cr )
7608 {
7609 CfBackInfo *cfb = be->be_private;
7610
7611 cfb_free_cffile( cfb->cb_config );
7612
7613 ch_free( cfdir.bv_val );
7614
7615 ldap_avl_free( CfOcTree, NULL );
7616
7617 if ( cfb->cb_db.bd_info ) {
7618 cfb->cb_db.be_suffix = NULL;
7619 cfb->cb_db.be_nsuffix = NULL;
7620 BER_BVZERO( &cfb->cb_db.be_rootdn );
7621 BER_BVZERO( &cfb->cb_db.be_rootndn );
7622
7623 backend_destroy_one( &cfb->cb_db, 0 );
7624 }
7625
7626 loglevel_destroy();
7627
7628 return 0;
7629 }
7630
7631 static int
config_back_db_init(BackendDB * be,ConfigReply * cr)7632 config_back_db_init( BackendDB *be, ConfigReply* cr )
7633 {
7634 struct berval dn;
7635 CfBackInfo *cfb;
7636
7637 cfb = &cfBackInfo;
7638 cfb->cb_config = ch_calloc( 1, sizeof(ConfigFile));
7639 cfn = cfb->cb_config;
7640 be->be_private = cfb;
7641
7642 ber_dupbv( &be->be_rootdn, &config_rdn );
7643 ber_dupbv( &be->be_rootndn, &be->be_rootdn );
7644 ber_dupbv( &dn, &be->be_rootdn );
7645 ber_bvarray_add( &be->be_suffix, &dn );
7646 ber_dupbv( &dn, &be->be_rootdn );
7647 ber_bvarray_add( &be->be_nsuffix, &dn );
7648
7649 /* Hide from namingContexts */
7650 SLAP_BFLAGS(be) |= SLAP_BFLAG_CONFIG;
7651
7652 /* Check ACLs on content of Adds by default */
7653 SLAP_DBFLAGS(be) |= SLAP_DBFLAG_ACL_ADD;
7654
7655 return 0;
7656 }
7657
7658 static int
config_back_destroy(BackendInfo * bi)7659 config_back_destroy( BackendInfo *bi )
7660 {
7661 ldif_must_b64_encode_release();
7662 return 0;
7663 }
7664
7665 static int
config_tool_entry_open(BackendDB * be,int mode)7666 config_tool_entry_open( BackendDB *be, int mode )
7667 {
7668 CfBackInfo *cfb = be->be_private;
7669 BackendInfo *bi = cfb->cb_db.bd_info;
7670
7671 if ( bi && bi->bi_tool_entry_open )
7672 return bi->bi_tool_entry_open( &cfb->cb_db, mode );
7673 else
7674 return -1;
7675
7676 }
7677
7678 static int
config_tool_entry_close(BackendDB * be)7679 config_tool_entry_close( BackendDB *be )
7680 {
7681 CfBackInfo *cfb = be->be_private;
7682 BackendInfo *bi = cfb->cb_db.bd_info;
7683
7684 if ( bi && bi->bi_tool_entry_close )
7685 return bi->bi_tool_entry_close( &cfb->cb_db );
7686 else
7687 return -1;
7688 }
7689
7690 static ID
config_tool_entry_first(BackendDB * be)7691 config_tool_entry_first( BackendDB *be )
7692 {
7693 CfBackInfo *cfb = be->be_private;
7694 BackendInfo *bi = cfb->cb_db.bd_info;
7695
7696 if ( bi && bi->bi_tool_entry_first ) {
7697 return bi->bi_tool_entry_first( &cfb->cb_db );
7698 }
7699 if ( bi && bi->bi_tool_entry_first_x ) {
7700 return bi->bi_tool_entry_first_x( &cfb->cb_db,
7701 NULL, LDAP_SCOPE_DEFAULT, NULL );
7702 }
7703 return NOID;
7704 }
7705
7706 static ID
config_tool_entry_first_x(BackendDB * be,struct berval * base,int scope,Filter * f)7707 config_tool_entry_first_x(
7708 BackendDB *be,
7709 struct berval *base,
7710 int scope,
7711 Filter *f )
7712 {
7713 CfBackInfo *cfb = be->be_private;
7714 BackendInfo *bi = cfb->cb_db.bd_info;
7715
7716 if ( bi && bi->bi_tool_entry_first_x ) {
7717 return bi->bi_tool_entry_first_x( &cfb->cb_db, base, scope, f );
7718 }
7719 return NOID;
7720 }
7721
7722 static ID
config_tool_entry_next(BackendDB * be)7723 config_tool_entry_next( BackendDB *be )
7724 {
7725 CfBackInfo *cfb = be->be_private;
7726 BackendInfo *bi = cfb->cb_db.bd_info;
7727
7728 if ( bi && bi->bi_tool_entry_next )
7729 return bi->bi_tool_entry_next( &cfb->cb_db );
7730 else
7731 return NOID;
7732 }
7733
7734 static ID
config_tool_dn2id_get(Backend * be,struct berval * dn)7735 config_tool_dn2id_get( Backend *be, struct berval *dn )
7736 {
7737 CfBackInfo *cfb = be->be_private;
7738 BackendInfo *bi = cfb->cb_db.bd_info;
7739
7740 if ( bi && bi->bi_tool_dn2id_get )
7741 return bi->bi_tool_dn2id_get( &cfb->cb_db, dn );
7742
7743 return NOID;
7744 }
7745
7746 static Entry *
config_tool_entry_get(BackendDB * be,ID id)7747 config_tool_entry_get( BackendDB *be, ID id )
7748 {
7749 CfBackInfo *cfb = be->be_private;
7750 BackendInfo *bi = cfb->cb_db.bd_info;
7751
7752 if ( bi && bi->bi_tool_entry_get )
7753 return bi->bi_tool_entry_get( &cfb->cb_db, id );
7754 else
7755 return NULL;
7756 }
7757
7758 static int entry_put_got_frontend=0;
7759 static int entry_put_got_config=0;
7760 static ID
config_tool_entry_put(BackendDB * be,Entry * e,struct berval * text)7761 config_tool_entry_put( BackendDB *be, Entry *e, struct berval *text )
7762 {
7763 CfBackInfo *cfb = be->be_private;
7764 BackendInfo *bi = cfb->cb_db.bd_info;
7765 int rc;
7766 struct berval rdn;
7767 ConfigArgs ca;
7768 OperationBuffer opbuf;
7769 Entry *ce;
7770 Connection conn = {0};
7771 Operation *op = NULL;
7772 void *thrctx;
7773 int isFrontend = 0;
7774 int isFrontendChild = 0;
7775
7776 /* Create entry for frontend database if it does not exist already */
7777 if ( !entry_put_got_frontend ) {
7778 if ( !strncmp( e->e_nname.bv_val, "olcDatabase",
7779 STRLENOF( "olcDatabase" ))) {
7780 if ( strncmp( e->e_nname.bv_val +
7781 STRLENOF( "olcDatabase" ), "={-1}frontend",
7782 STRLENOF( "={-1}frontend" )) &&
7783 strncmp( e->e_nname.bv_val +
7784 STRLENOF( "olcDatabase" ), "=frontend",
7785 STRLENOF( "=frontend" ))) {
7786 memset( &ca, 0, sizeof(ConfigArgs));
7787 ca.be = frontendDB;
7788 ca.bi = frontendDB->bd_info;
7789 ca.be->be_cf_ocs = &CFOC_FRONTEND;
7790 rdn.bv_val = ca.log;
7791 rdn.bv_len = snprintf(rdn.bv_val, sizeof( ca.log ),
7792 "%s=" SLAP_X_ORDERED_FMT "%s",
7793 cfAd_database->ad_cname.bv_val, -1,
7794 ca.bi->bi_type);
7795 ce = config_build_entry( NULL, NULL, cfb->cb_root, &ca, &rdn,
7796 &CFOC_DATABASE, ca.be->be_cf_ocs );
7797 thrctx = ldap_pvt_thread_pool_context();
7798 connection_fake_init2( &conn, &opbuf, thrctx,0 );
7799 op = &opbuf.ob_op;
7800 op->o_bd = &cfb->cb_db;
7801 op->o_tag = LDAP_REQ_ADD;
7802 op->ora_e = ce;
7803 op->o_dn = be->be_rootdn;
7804 op->o_ndn = be->be_rootndn;
7805 rc = slap_add_opattrs(op, NULL, NULL, 0, 0);
7806 if ( rc != LDAP_SUCCESS ) {
7807 text->bv_val = "autocreation of \"olcDatabase={-1}frontend\" failed";
7808 text->bv_len = STRLENOF("autocreation of \"olcDatabase={-1}frontend\" failed");
7809 return NOID;
7810 }
7811
7812 if ( ce && bi && bi->bi_tool_entry_put &&
7813 bi->bi_tool_entry_put( &cfb->cb_db, ce, text ) != NOID ) {
7814 entry_put_got_frontend++;
7815 } else {
7816 text->bv_val = "autocreation of \"olcDatabase={-1}frontend\" failed";
7817 text->bv_len = STRLENOF("autocreation of \"olcDatabase={-1}frontend\" failed");
7818 return NOID;
7819 }
7820 } else {
7821 entry_put_got_frontend++;
7822 isFrontend = 1;
7823 }
7824 }
7825 }
7826
7827 /* Child entries of the frontend database, e.g. slapo-chain's back-ldap
7828 * instances, may appear before the config database entry in the ldif, skip
7829 * auto-creation of olcDatabase={0}config in such a case */
7830 if ( !entry_put_got_config &&
7831 !strncmp( e->e_nname.bv_val, "olcDatabase", STRLENOF( "olcDatabase" ))) {
7832 struct berval pdn;
7833 dnParent( &e->e_nname, &pdn );
7834 while ( pdn.bv_len ) {
7835 if ( !strncmp( pdn.bv_val, "olcDatabase",
7836 STRLENOF( "olcDatabase" ))) {
7837 if ( !strncmp( pdn.bv_val +
7838 STRLENOF( "olcDatabase" ), "={-1}frontend",
7839 STRLENOF( "={-1}frontend" )) ||
7840 !strncmp( pdn.bv_val +
7841 STRLENOF( "olcDatabase" ), "=frontend",
7842 STRLENOF( "=frontend" ))) {
7843
7844 isFrontendChild = 1;
7845 break;
7846 }
7847 }
7848 dnParent( &pdn, &pdn );
7849 }
7850 }
7851
7852 /* Create entry for config database if it does not exist already */
7853 if ( !entry_put_got_config && !isFrontend && !isFrontendChild ) {
7854 if ( !strncmp( e->e_nname.bv_val, "olcDatabase",
7855 STRLENOF( "olcDatabase" ))) {
7856 if ( strncmp( e->e_nname.bv_val +
7857 STRLENOF( "olcDatabase" ), "={0}config",
7858 STRLENOF( "={0}config" )) &&
7859 strncmp( e->e_nname.bv_val +
7860 STRLENOF( "olcDatabase" ), "=config",
7861 STRLENOF( "=config" )) ) {
7862 memset( &ca, 0, sizeof(ConfigArgs));
7863 ca.be = LDAP_STAILQ_FIRST( &backendDB );
7864 ca.bi = ca.be->bd_info;
7865 rdn.bv_val = ca.log;
7866 rdn.bv_len = snprintf(rdn.bv_val, sizeof( ca.log ),
7867 "%s=" SLAP_X_ORDERED_FMT "%s",
7868 cfAd_database->ad_cname.bv_val, 0,
7869 ca.bi->bi_type);
7870 ce = config_build_entry( NULL, NULL, cfb->cb_root, &ca, &rdn, &CFOC_DATABASE,
7871 ca.be->be_cf_ocs );
7872 if ( ! op ) {
7873 thrctx = ldap_pvt_thread_pool_context();
7874 connection_fake_init2( &conn, &opbuf, thrctx,0 );
7875 op = &opbuf.ob_op;
7876 op->o_bd = &cfb->cb_db;
7877 op->o_tag = LDAP_REQ_ADD;
7878 op->o_dn = be->be_rootdn;
7879 op->o_ndn = be->be_rootndn;
7880 }
7881 op->ora_e = ce;
7882 rc = slap_add_opattrs(op, NULL, NULL, 0, 0);
7883 if ( rc != LDAP_SUCCESS ) {
7884 text->bv_val = "autocreation of \"olcDatabase={0}config\" failed";
7885 text->bv_len = STRLENOF("autocreation of \"olcDatabase={0}config\" failed");
7886 return NOID;
7887 }
7888 if (ce && bi && bi->bi_tool_entry_put &&
7889 bi->bi_tool_entry_put( &cfb->cb_db, ce, text ) != NOID ) {
7890 entry_put_got_config++;
7891 } else {
7892 text->bv_val = "autocreation of \"olcDatabase={0}config\" failed";
7893 text->bv_len = STRLENOF("autocreation of \"olcDatabase={0}config\" failed");
7894 return NOID;
7895 }
7896 } else {
7897 entry_put_got_config++;
7898 }
7899 }
7900 }
7901 if ( bi && bi->bi_tool_entry_put &&
7902 config_add_internal( cfb, e, &ca, NULL, NULL, NULL ) == 0 )
7903 return bi->bi_tool_entry_put( &cfb->cb_db, e, text );
7904 else {
7905 ber_str2bv( ca.cr_msg, 0, 0, text );
7906 return NOID;
7907 }
7908 }
7909
7910 static ID
config_tool_entry_modify(BackendDB * be,Entry * e,struct berval * text)7911 config_tool_entry_modify( BackendDB *be, Entry *e, struct berval *text )
7912 {
7913 CfBackInfo *cfb = be->be_private;
7914 BackendInfo *bi = cfb->cb_db.bd_info;
7915 CfEntryInfo *ce, *last;
7916
7917 ce = config_find_base( cfb->cb_root, &e->e_nname, &last );
7918
7919 if ( ce && bi && bi->bi_tool_entry_modify )
7920 return bi->bi_tool_entry_modify( &cfb->cb_db, e, text );
7921
7922 return NOID;
7923 }
7924
7925 static int
config_tool_entry_delete(BackendDB * be,struct berval * ndn,struct berval * text)7926 config_tool_entry_delete( BackendDB *be, struct berval *ndn, struct berval *text )
7927 {
7928 CfBackInfo *cfb = be->be_private;
7929 BackendInfo *bi = cfb->cb_db.bd_info;
7930 CfEntryInfo *ce, *last;
7931
7932 ce = config_find_base( cfb->cb_root, ndn, &last );
7933
7934 if ( ce && bi && bi->bi_tool_entry_delete )
7935 return bi->bi_tool_entry_delete( &cfb->cb_db, ndn, text );
7936
7937 return LDAP_OTHER;
7938 }
7939
7940 static struct {
7941 char *name;
7942 AttributeDescription **desc;
7943 } ads[] = {
7944 { "attribute", &cfAd_attr },
7945 { "backend", &cfAd_backend },
7946 { "database", &cfAd_database },
7947 { "include", &cfAd_include },
7948 { "ldapsyntax", &cfAd_syntax },
7949 { "objectclass", &cfAd_oc },
7950 { "objectidentifier", &cfAd_om },
7951 { "overlay", &cfAd_overlay },
7952 { NULL, NULL }
7953 };
7954
7955 /* Notes:
7956 * add / delete: all types that may be added or deleted must use an
7957 * X-ORDERED attributeType for their RDN. Adding and deleting entries
7958 * should automatically renumber the index of any siblings as needed,
7959 * so that no gaps in the numbering sequence exist after the add/delete
7960 * is completed.
7961 * What can be added:
7962 * schema objects
7963 * backend objects for backend-specific config directives
7964 * database objects
7965 * overlay objects
7966 *
7967 * delete: probably no support this time around.
7968 *
7969 * modrdn: generally not done. Will be invoked automatically by add/
7970 * delete to update numbering sequence. Perform as an explicit operation
7971 * so that the renumbering effect may be replicated. Subtree rename must
7972 * be supported, since renumbering a database will affect all its child
7973 * overlays.
7974 *
7975 * modify: must be fully supported.
7976 */
7977
7978 int
config_back_initialize(BackendInfo * bi)7979 config_back_initialize( BackendInfo *bi )
7980 {
7981 ConfigTable *ct = config_back_cf_table;
7982 ConfigArgs ca;
7983 char *argv[4];
7984 int i;
7985 AttributeDescription *ad = NULL;
7986 const char *text;
7987 static char *controls[] = {
7988 LDAP_CONTROL_MANAGEDSAIT,
7989 NULL
7990 };
7991
7992 /* Make sure we don't exceed the bits reserved for userland */
7993 config_check_userland( CFG_LAST );
7994
7995 bi->bi_controls = controls;
7996
7997 bi->bi_open = 0;
7998 bi->bi_close = 0;
7999 bi->bi_config = 0;
8000 bi->bi_destroy = config_back_destroy;
8001
8002 bi->bi_db_init = config_back_db_init;
8003 bi->bi_db_config = 0;
8004 bi->bi_db_open = config_back_db_open;
8005 bi->bi_db_close = config_back_db_close;
8006 bi->bi_db_destroy = config_back_db_destroy;
8007
8008 bi->bi_op_bind = config_back_bind;
8009 bi->bi_op_unbind = 0;
8010 bi->bi_op_search = config_back_search;
8011 bi->bi_op_compare = 0;
8012 bi->bi_op_modify = config_back_modify;
8013 bi->bi_op_modrdn = config_back_modrdn;
8014 bi->bi_op_add = config_back_add;
8015 bi->bi_op_delete = config_back_delete;
8016 bi->bi_op_abandon = 0;
8017
8018 bi->bi_extended = 0;
8019
8020 bi->bi_chk_referrals = 0;
8021
8022 bi->bi_access_allowed = slap_access_allowed;
8023
8024 bi->bi_connection_init = 0;
8025 bi->bi_connection_destroy = 0;
8026
8027 bi->bi_entry_release_rw = config_entry_release;
8028 bi->bi_entry_get_rw = config_back_entry_get;
8029
8030 bi->bi_tool_entry_open = config_tool_entry_open;
8031 bi->bi_tool_entry_close = config_tool_entry_close;
8032 bi->bi_tool_entry_first = config_tool_entry_first;
8033 bi->bi_tool_entry_first_x = config_tool_entry_first_x;
8034 bi->bi_tool_entry_next = config_tool_entry_next;
8035 bi->bi_tool_dn2id_get = config_tool_dn2id_get;
8036 bi->bi_tool_entry_get = config_tool_entry_get;
8037 bi->bi_tool_entry_put = config_tool_entry_put;
8038 bi->bi_tool_entry_modify = config_tool_entry_modify;
8039 bi->bi_tool_entry_delete = config_tool_entry_delete;
8040
8041 ca.argv = argv;
8042 argv[ 0 ] = "slapd";
8043 ca.argv = argv;
8044 ca.argc = 3;
8045 ca.fname = argv[0];
8046
8047 argv[3] = NULL;
8048 for (i=0; OidMacros[i].name; i++ ) {
8049 argv[1] = OidMacros[i].name;
8050 argv[2] = OidMacros[i].oid;
8051 parse_oidm( &ca, 0, NULL );
8052 }
8053
8054 bi->bi_cf_ocs = cf_ocs;
8055
8056 i = config_register_schema( ct, cf_ocs );
8057 if ( i ) return i;
8058
8059 i = slap_str2ad( "olcDatabase", &olcDatabaseDummy[0].ad, &text );
8060 if ( i ) return i;
8061
8062 /* setup olcRootPW to be base64-encoded when written in LDIF form;
8063 * basically, we don't care if it fails */
8064 i = slap_str2ad( "olcRootPW", &ad, &text );
8065 if ( i ) {
8066 Debug( LDAP_DEBUG_ANY, "config_back_initialize: "
8067 "warning, unable to get \"olcRootPW\" "
8068 "attribute description: %d: %s\n",
8069 i, text );
8070 } else {
8071 (void)ldif_must_b64_encode_register( ad->ad_cname.bv_val,
8072 ad->ad_type->sat_oid );
8073 }
8074
8075 /* set up the notable AttributeDescriptions */
8076 i = 0;
8077 for (;ct->name;ct++) {
8078 if (strcmp(ct->name, ads[i].name)) continue;
8079 *ads[i].desc = ct->ad;
8080 i++;
8081 if (!ads[i].name) break;
8082 }
8083
8084 return 0;
8085 }
8086