]> git.sur5r.net Git - openldap/blob - servers/slapd/bconfig.c
Added overlay objects
[openldap] / servers / slapd / bconfig.c
1 /* bconfig.c - the config backend */
2 /* $OpenLDAP$ */
3 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
4  *
5  * Copyright 2005 The OpenLDAP Foundation.
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted only as authorized by the OpenLDAP
10  * Public License.
11  *
12  * A copy of this license is available in the file LICENSE in the
13  * top-level directory of the distribution or, alternatively, at
14  * <http://www.OpenLDAP.org/license.html>.
15  */
16 /* ACKNOWLEDGEMENTS:
17  * This work was originally developed by Howard Chu for inclusion
18  * in OpenLDAP Software.
19  */
20
21 #include "portable.h"
22
23 #include <stdio.h>
24 #include <ac/string.h>
25
26 #include "slap.h"
27 #include "config.h"
28
29 #define CONFIG_DN       "cn=config"
30
31 typedef struct CfEntryInfo {
32         struct CfEntryInfo *ce_sibs;
33         struct CfEntryInfo *ce_kids;
34         Entry *ce_entry;
35         BackendInfo *ce_bi;
36         BackendDB *ce_be;
37 } CfEntryInfo;
38
39 typedef struct {
40         ConfigFile *cb_config;
41         CfEntryInfo *cb_root;
42 } CfBackInfo;
43
44 static AttributeDescription *cfAd_backend, *cfAd_database, *cfAd_overlay,
45         *cfAd_include;
46
47 static ObjectClass *cfOc_global, *cfOc_backend, *cfOc_database,
48         *cfOc_include, *cfOc_overlay;
49
50 static struct oc_info {
51         char *def;
52         ObjectClass **oc;
53 } cf_ocs[] = {
54         { "( OLcfgOc:1 "
55                 "NAME 'olcConfig' "
56                 "DESC 'OpenLDAP configuration object' "
57                 "ABSTRACT SUP top "
58                 "MAY ( cn $ olcConfigFile ) )", NULL },
59         { "( OLcfgOc:3 "
60                 "NAME 'olcGlobal' "
61                 "DESC 'OpenLDAP Global configuration options' "
62                 "SUP olcConfig STRUCTURAL "
63                 "MAY ( olcAccess $ olcAllows $ olcArgsFile $ olcAttributeOptions $ "
64                  "olcAuthRewrite $ olcAuthzPolicy $ olcAuthzRegexp $ "
65                  "olcConcurrency $ olcConnMaxPending $ olcConnMaxPendingAuth $ "
66                  "olcDefaultSearchBase $ olcDisallows $ olcGentleHUP $ "
67                  "olcIdleTimeout $ olcIndexSubstrIfMaxLen $ olcIndexSubstrIfMinLen $ "
68                  "olcIndexSubstrAnyLen $ olcIndexSubstrAnyStep $ olcLocalSSF $ "
69                  "olcLogLevel $ olcModuleLoad $ olcModulePath $ olcObjectIdentifier $ "
70                  "olcPasswordCryptSaltFormat $ olcPasswordHash $ olcPidFile $ "
71                  "olcPlugin $ olcPluginLogFile $ olcReadOnly $ olcReferral $ "
72                  "olcReplicaPidFile $ olcReplicaArgsFile $ olcReplicationInterval $ "
73                  "olcReplogFile $ olcRequires $ olcRestrict $ olcReverseLookup $ "
74                  "olcRootDSE $ olcSaslHost $ olcSaslRealm $ olcSaslSecProps $ "
75                  "olcSchemaCheck $ olcSchemaDN $ olcSecurity $ olcSizeLimit $ "
76                  "olcSockbufMaxIncoming $ olcSockbufMaxIncomingAuth $ olcSrvtab $ "
77                  "olcThreads $ olcTimeLimit $ olcTLSCACertificateFile $ "
78                  "olcTLSCACertificatePath $ olcTLSCertificateFile $ "
79                  "olcTLSCertificateKeyFile $ olcTLSCipherSuite $ olcTLSCRLCheck $ "
80                  "olcTLSRandFile $ olcTLSVerifyClient ) )", &cfOc_global },
81         { "( OLcfgOc:4 "
82                 "NAME 'olcBackendConfig' "
83                 "DESC 'OpenLDAP Backend-specific options' "
84                 "SUP olcConfig STRUCTURAL "
85                 "MAY ( olcBackend ) )", &cfOc_backend },
86         { "( OLcfgOc:5 "
87                 "NAME 'olcDatabaseConfig' "
88                 "DESC 'OpenLDAP Database-specific options' "
89                 "SUP olcConfig STRUCTURAL "
90                 "MAY ( olcAccess $ olcDatabase $ olcLastMod $ olcLimits $ "
91                  "olcMaxDerefDepth $ olcReadOnly $ olcReplica $ olcReplogFile $ "
92                  "olcRequires $ olcRestrict $ olcRootDN $ olcRootPW $ olcSchemaDN $ "
93                  "olcSecurity $ olcSizeLimit $ olcSuffix $ olcSyncrepl $ "
94                  "olcTimeLimit $ olcUpdateDN $ olcUpdateRef ) )", &cfOc_database },
95         { "( OLcfgOc:6 "
96                 "NAME 'olcIncludeFile' "
97                 "DESC 'OpenLDAP configuration include file' "
98                 "SUP olcConfig STRUCTURAL "
99                 "MAY ( olcInclude $ olcModuleLoad $ olcModulePath $ olcRootDSE ) )",
100                 &cfOc_include },
101         { "( OLcfgOc:7 "
102                 "NAME 'olcOverlayConfig' "
103                 "DESC 'OpenLDAP Overlay-specific options' "
104                 "SUP olcConfig STRUCTURAL "
105                 "MAY ( olcOverlay ) )", &cfOc_overlay },
106         { NULL, NULL }
107 };
108
109 static int
110 config_back_bind( Operation *op, SlapReply *rs )
111 {
112         if ( op->orb_method == LDAP_AUTH_SIMPLE && be_isroot_pw( op )) {
113                 ber_dupbv( &op->orb_edn, be_root_dn( op->o_bd ));
114                 /* frontend sends result */
115                 return LDAP_SUCCESS;
116         }
117
118         rs->sr_err = LDAP_INVALID_CREDENTIALS;
119         send_ldap_result( op, rs );
120
121         return rs->sr_err;
122 }
123
124 static CfEntryInfo *
125 config_find_base( CfEntryInfo *root, struct berval *dn, CfEntryInfo **last )
126 {
127         struct berval cdn;
128         char *c;
129
130         if ( dn_match( &root->ce_entry->e_nname, dn ))
131                 return root;
132
133         c = dn->bv_val+dn->bv_len;
134         for (;*c != ',';c--);
135
136         while(root) {
137                 *last = root;
138                 for (--c;c>dn->bv_val && *c != ',';c--);
139                 if ( *c == ',' )
140                         c++;
141                 cdn.bv_val = c;
142                 cdn.bv_len = dn->bv_len - (c-dn->bv_val);
143
144                 root = root->ce_kids;
145
146                 for (;root;root=root->ce_sibs) {
147                         if ( dn_match( &root->ce_entry->e_nname, &cdn )) {
148                                 if ( cdn.bv_val == dn->bv_val ) {
149                                         return root;
150                                 }
151                                 break;
152                         }
153                 }
154         }
155         return root;
156 }
157
158 static int
159 config_send( Operation *op, SlapReply *rs, CfEntryInfo *ce, int depth )
160 {
161         int rc = 0;
162
163         if ( test_filter( op, ce->ce_entry, op->ors_filter ) == LDAP_COMPARE_TRUE )
164         {
165                 rs->sr_attrs = op->ors_attrs;
166                 rs->sr_entry = ce->ce_entry;
167                 rc = send_search_entry( op, rs );
168         }
169         if ( op->ors_scope == LDAP_SCOPE_SUBTREE ) {
170                 if ( ce->ce_kids ) {
171                         rc = config_send( op, rs, ce->ce_kids, 1 );
172                         if ( rc ) return rc;
173                 }
174                 if ( depth ) {
175                         for (ce=ce->ce_sibs; ce; ce=ce->ce_sibs) {
176                                 rc = config_send( op, rs, ce, 0 );
177                                 if ( rc ) break;
178                         }
179                 }
180         }
181         return rc;
182 }
183
184 static int
185 config_back_search( Operation *op, SlapReply *rs )
186 {
187         CfBackInfo *cfb;
188         CfEntryInfo *ce, *last;
189         int rc;
190
191         if ( !be_isroot( op ) ) {
192                 rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
193                 send_ldap_result( op, rs );
194         }
195
196         cfb = (CfBackInfo *)op->o_bd->be_private;
197
198         ce = config_find_base( cfb->cb_root, &op->o_req_ndn, &last );
199         if ( !ce ) {
200                 if ( last )
201                         rs->sr_matched = last->ce_entry->e_name.bv_val;
202                 rs->sr_err = LDAP_NO_SUCH_OBJECT;
203                 goto out;
204         }
205         switch ( op->ors_scope ) {
206         case LDAP_SCOPE_BASE:
207         case LDAP_SCOPE_SUBTREE:
208                 config_send( op, rs, ce, 0 );
209                 break;
210                 
211         case LDAP_SCOPE_ONELEVEL:
212                 for (ce = ce->ce_kids; ce; ce=ce->ce_sibs) {
213                         config_send( op, rs, ce, 1 );
214                 }
215                 break;
216         }
217                 
218         rs->sr_err = LDAP_SUCCESS;
219 out:
220         send_ldap_result( op, rs );
221         return 0;
222 }
223
224 static Entry *
225 config_alloc_entry( struct berval *pdn, struct berval *rdn )
226 {
227         Entry *e = ch_calloc( 1, sizeof(Entry) );
228         CfEntryInfo *ce = ch_calloc( 1, sizeof(CfEntryInfo) );
229         e->e_private = ce;
230         ce->ce_entry = e;
231         build_new_dn( &e->e_name, pdn, rdn, NULL );
232         ber_dupbv( &e->e_nname, &e->e_name );
233         return e;
234 }
235
236 #define NO_TABLE        0
237 #define BI_TABLE        1
238 #define BE_TABLE        2
239
240 static int
241 config_build_entry( ConfigArgs *c, Entry *e, ObjectClass *oc,
242          struct berval *rdn, ConfigTable *ct, int table )
243 {
244         struct berval vals[2];
245         struct berval ad_name;
246         AttributeDescription *ad = NULL;
247         int rc, i;
248         char *ptr;
249         const char *text;
250         AttributeType **at;
251
252         BER_BVZERO( &vals[1] );
253
254         vals[0] = oc->soc_cname;
255         attr_merge(e, slap_schema.si_ad_objectClass, vals, NULL );
256         ptr = strchr(rdn->bv_val, '=');
257         ad_name.bv_val = rdn->bv_val;
258         ad_name.bv_len = ptr - rdn->bv_val;
259         rc = slap_bv2ad( &ad_name, &ad, &text );
260         if ( rc ) {
261                 return rc;
262         }
263         vals[0].bv_val = ptr+1;
264         vals[0].bv_len = rdn->bv_len - (vals[0].bv_val - rdn->bv_val);
265         attr_merge(e, ad, vals, NULL );
266
267         for (at=oc->soc_allowed;*at;at++) {
268                 /* Skip the naming attr */
269                 if ((*at)->sat_ad == ad || (*at)->sat_ad == slap_schema.si_ad_cn )
270                         continue;
271                 for (i=0;ct[i].name;i++) {
272                         if (ct[i].ad == (*at)->sat_ad)
273                                 break;
274                 }
275                 rc = config_get_vals(&ct[i], c);
276                 if (rc == LDAP_SUCCESS) {
277                         attr_merge(e, ct[i].ad, c->rvalue_vals, c->rvalue_nvals);
278                 }
279         }
280
281         if ( table ) {
282                 if ( table == BI_TABLE )
283                         ct = c->bi->bi_cf_table;
284                 else
285                         ct = c->be->be_cf_table;
286                 for (;ct && ct->name;ct++) {
287                         if (!ct->ad) continue;
288                         rc = config_get_vals(ct, c);
289                         if (rc == LDAP_SUCCESS) {
290                                 attr_merge(e, ct->ad, c->rvalue_vals, c->rvalue_nvals);
291                         }
292                 }
293         }
294
295         return 0;
296 }
297
298 static CfEntryInfo *
299 config_build_includes( ConfigArgs *c, Entry *parent )
300 {
301         Entry *e;
302         int i;
303         ConfigFile *cf = (ConfigFile *)c->line;
304         CfEntryInfo *ce, *ceparent, *ceprev;
305
306         ceparent = parent->e_private;
307
308         for (i=0; cf; cf=cf->c_sibs, i++) {
309                 c->value_dn.bv_val = c->log;
310                 c->value_dn.bv_len = sprintf(c->value_dn.bv_val, "cn=include{%d}", i);
311                 e = config_alloc_entry( &parent->e_nname, &c->value_dn );
312                 c->line = (char *)cf;
313                 config_build_entry( c, e, cfOc_include, &c->value_dn,
314                         c->bi->bi_cf_table, NO_TABLE );
315                 ce = e->e_private;
316                 if ( !ceparent->ce_kids ) {
317                         ceparent->ce_kids = ce;
318                 } else {
319                         ceprev->ce_sibs = ce;
320                 }
321                 ceprev = ce;
322                 if ( cf->c_kids ) {
323                         c->line = (char *)cf->c_kids;
324                         config_build_includes( c, e );
325                 }
326         }
327         return ce;
328 }
329
330 static int
331 config_back_db_open( BackendDB *be )
332 {
333         CfBackInfo *cfb = be->be_private;
334         struct berval rdn;
335         Entry *e, *parent;
336         CfEntryInfo *ce, *ceparent, *ceprev;
337         int i, rc;
338         BackendInfo *bi;
339         BackendDB *bptr;
340         ConfigArgs c;
341         ConfigTable *ct;
342
343         /* create root of tree */
344         ber_str2bv( CONFIG_DN, STRLENOF( CONFIG_DN ), 0, &rdn );
345         e = config_alloc_entry( NULL, &rdn );
346         ce = e->e_private;
347         cfb->cb_root = ce;
348         c.be = be;
349         c.bi = be->bd_info;
350         c.line = (char *)cfb->cb_config;
351         ct = c.bi->bi_cf_table;
352         config_build_entry( &c, e, cfOc_global, &rdn, ct, NO_TABLE );
353
354         parent = e;
355         ceparent = ce;
356
357         /* Create includeFile nodes... */
358         if ( cfb->cb_config->c_kids ) {
359                 c.line = (char *)cfb->cb_config->c_kids;
360                 ceprev = config_build_includes( &c, parent );
361         }
362
363         /* Create backend nodes. Skip if they don't provide a cf_table.
364          * There usually aren't any of these.
365          */
366         
367         c.line = 0;
368         bi = backendInfo;
369         for (i=0; i<nBackendInfo; i++, bi++) {
370                 if (!bi->bi_cf_table) continue;
371                 if (!bi->bi_private) continue;
372
373                 rdn.bv_val = c.log;
374                 rdn.bv_len = sprintf(rdn.bv_val, "%s=%s", cfAd_backend->ad_cname.bv_val, bi->bi_type);
375                 e = config_alloc_entry( &parent->e_nname, &rdn );
376                 ce = e->e_private;
377                 ce->ce_bi = bi;
378                 c.bi = bi;
379                 config_build_entry( &c, e, cfOc_backend, &rdn, ct, BI_TABLE );
380                 if ( !ceparent->ce_kids ) {
381                         ceparent->ce_kids = ce;
382                 } else {
383                         ceprev->ce_sibs = ce;
384                 }
385                 ceprev = ce;
386         }
387
388         /* Create database nodes... */
389         for (i=0; i<nBackendDB; i++) {
390                 slap_overinfo *oi = NULL;
391                 if ( i == 0 ) {
392                         bptr = frontendDB;
393                 } else {
394                         bptr = &backendDB[i];
395                 }
396                 if ( overlay_is_over( bptr )) {
397                         oi = bptr->bd_info->bi_private;
398                         bi = oi->oi_orig;
399                 } else {
400                         bi = bptr->bd_info;
401                 }
402                 rdn.bv_val = c.log;
403                 rdn.bv_len = sprintf(rdn.bv_val, "%s={%0x}%s", cfAd_database->ad_cname.bv_val,
404                         i, bi->bi_type);
405                 e = config_alloc_entry( &parent->e_nname, &rdn );
406                 ce = e->e_private;
407                 c.be = bptr;
408                 c.bi = bi;
409                 ce->ce_be = c.be;
410                 ce->ce_bi = c.bi;
411                 config_build_entry( &c, e, cfOc_database, &rdn, ct, BE_TABLE );
412                 if ( !ceparent->ce_kids ) {
413                         ceparent->ce_kids = ce;
414                 } else {
415                         ceprev->ce_sibs = ce;
416                 }
417                 ceprev = ce;
418                 /* Iterate through overlays */
419                 if ( oi ) {
420                         slap_overinst *on;
421                         Entry *oe;
422                         CfEntryInfo *opar = ce, *oprev = NULL;
423                         int j;
424
425                         for (j=0,on=oi->oi_list; on; j++,on=on->on_next) {
426                                 rdn.bv_val = c.log;
427                                 rdn.bv_len = sprintf(rdn.bv_val, "%s={%0x}%s",
428                                         cfAd_overlay->ad_cname.bv_val, j, on->on_bi.bi_type );
429                                 oe = config_alloc_entry( &e->e_nname, &rdn );
430                                 ce = oe->e_private;
431                                 c.be = bptr;
432                                 c.bi = &on->on_bi;
433                                 ce->ce_be = c.be;
434                                 ce->ce_bi = c.bi;
435                                 config_build_entry( &c, oe, cfOc_overlay, &rdn, ct, BI_TABLE );
436                                 if ( !opar->ce_kids ) {
437                                         opar->ce_kids = ce;
438                                 } else {
439                                         oprev->ce_sibs = ce;
440                                 }
441                                 oprev = ce;
442                         }
443                 }
444         }
445
446         return 0;
447 }
448
449 static int
450 config_back_db_destroy( Backend *be )
451 {
452         free( be->be_private );
453         return 0;
454 }
455
456 int
457 config_back_initialize( BackendInfo *bi )
458 {
459         bi->bi_open = 0;
460         bi->bi_close = 0;
461         bi->bi_config = 0;
462         bi->bi_destroy = 0;
463
464         bi->bi_db_init = 0;
465         bi->bi_db_config = 0;
466         bi->bi_db_open = config_back_db_open;
467         bi->bi_db_close = 0;
468         bi->bi_db_destroy = config_back_db_destroy;
469
470         bi->bi_op_bind = config_back_bind;
471         bi->bi_op_unbind = 0;
472         bi->bi_op_search = config_back_search;
473         bi->bi_op_compare = 0;
474         bi->bi_op_modify = 0;
475         bi->bi_op_modrdn = 0;
476         bi->bi_op_add = 0;
477         bi->bi_op_delete = 0;
478         bi->bi_op_abandon = 0;
479
480         bi->bi_extended = 0;
481
482         bi->bi_chk_referrals = 0;
483
484         bi->bi_connection_init = 0;
485         bi->bi_connection_destroy = 0;
486
487         return 0;
488 }
489
490 static struct {
491         char *name;
492         AttributeDescription **desc;
493         AttributeDescription *sub;
494 } ads[] = {
495         { "attribute", NULL, NULL },
496         { "backend", &cfAd_backend, NULL },
497         { "database", &cfAd_database, NULL },
498         { "ditcontentrule", NULL, NULL },
499         { "include", &cfAd_include, NULL },
500         { "objectclass", NULL, NULL },
501         { "overlay", &cfAd_overlay, NULL },
502         { NULL, NULL, NULL }
503 };
504
505 int config_back_init( ConfigFile *cfp, ConfigTable *ct )
506 {
507         BackendInfo bi = {0};
508         BackendDB *be;
509         struct berval dn;
510         CfBackInfo *cfb;
511         int i;
512
513         bi.bi_type = "config";
514         bi.bi_init = config_back_initialize;
515         bi.bi_cf_table = ct;
516         backend_add( &bi );
517         be = backend_db_init( bi.bi_type );
518         ber_str2bv( CONFIG_DN, 0, 1, &be->be_rootdn );
519         ber_dupbv( &be->be_rootndn, &be->be_rootdn );
520         ber_dupbv( &dn, &be->be_rootdn );
521         ber_bvarray_add( &be->be_suffix, &dn );
522         ber_dupbv( &dn, &be->be_rootdn );
523         ber_bvarray_add( &be->be_nsuffix, &dn );
524         cfb = ch_calloc( 1, sizeof(CfBackInfo));
525         cfb->cb_config = cfp;
526         be->be_private = cfb;
527
528         /* set up the notable AttributeDescriptions */
529         ads[0].sub = slap_schema.si_ad_attributeTypes;
530         ads[3].sub = slap_schema.si_ad_ditContentRules;
531         ads[5].sub = slap_schema.si_ad_objectClasses;
532
533         i = 0;
534         for (;ct->name;ct++) {
535                 if (strcmp(ct->name, ads[i].name)) continue;
536                 if (ads[i].sub) {
537                         ct->ad = ads[i].sub;
538                 } else {
539                         *ads[i].desc = ct->ad;
540                 }
541                 i++;
542                 if (!ads[i].name) break;
543         }
544
545         /* set up the objectclasses */
546         for (i=0;cf_ocs[i].def;i++) {
547                 LDAPObjectClass *oc;
548                 int code;
549                 const char *err;
550
551                 oc = ldap_str2objectclass( cf_ocs[i].def, &code, &err,
552                         LDAP_SCHEMA_ALLOW_ALL );
553                 if ( !oc ) {
554                         fprintf( stderr, "config_back_init: objectclass \"%s\": %s, %s\n",
555                                 cf_ocs[i].def, ldap_scherr2str(code), err );
556                         return code;
557                 }
558                 code = oc_add(oc,0,&err);
559                 if ( code ) {
560                         fprintf( stderr, "config_back_init: objectclass \"%s\": %s, %s\n",
561                                 cf_ocs[i].def, scherr2str(code), err );
562                         return code;
563                 }
564                 if ( cf_ocs[i].oc ) {
565                         *cf_ocs[i].oc = oc_find(oc->oc_names[0]);
566                 }
567                 ldap_memfree(oc);
568         }
569         return 0;
570 }