~ubuntu-branches/ubuntu/maverick/openldap/maverick-proposed

« back to all changes in this revision

Viewing changes to servers/slapd/bconfig.c

  • Committer: Bazaar Package Importer
  • Author(s): Mathias Gug, Steve Langasek, Mathias Gug
  • Date: 2009-02-18 18:44:00 UTC
  • mfrom: (1.1.2 upstream) (0.1.2 lenny)
  • Revision ID: james.westby@ubuntu.com-20090218184400-zw4mjse9eywt5566
Tags: 2.4.14-0ubuntu1
[ Steve Langasek ]
* New upstream version
  - Fixes a bug with the pcache overlay not returning cached entries
    (closes: #497697)
  - Update evolution-ntlm patch to apply to current Makefiles.
  - (tentatively) drop gnutls-ciphers, since this bug was reported to be
    fixed upstream in 2.4.8.  The fix applied in 2.4.8 didn't match the
    patch from the bug report, so this should be watched for regressions.
* Build against db4.7 instead of db4.2 at last!  Closes: #421946.
* Build with --disable-ndb, to avoid a misbuild when libmysqlclient is
  installed in the build environment.
* New patch, no-crlcheck-for-gnutls, to fix a build failure when using
  --with-tls=gnutls.

[ Mathias Gug ]
* Merge from debian unstable, remaining changes:
  - debian/apparmor-profile: add AppArmor profile
  - debian/slapd.postinst: Reload AA profile on configuration
  - updated debian/slapd.README.Debian for note on AppArmor
  - debian/control: Recommends apparmor >= 2.1+1075-0ubuntu6
  - debian/control: Conflicts with apparmor-profiles << 2.1+1075-0ubuntu4
    to make sure that if earlier version of apparmour-profiles gets
    installed it won't overwrite our profile.
  - Modify Maintainer value to match the DebianMaintainerField
    speficication.
  - follow ApparmorProfileMigration and force apparmor compalin mode on 
    some upgrades (LP: #203529)
  - debian/slapd.dirs: add etc/apparmor.d/force-complain
  - debian/slapd.preinst: create symlink for force-complain on pre-feisty
    upgrades, upgrades where apparmor-profiles profile is unchanged (ie
    non-enforcing) and upgrades where apparmor profile does not exist.
  - debian/slapd.postrm: remove symlink in force-complain/ on purge
  - debian/patches/fix-ucred-libc due to changes how newer glibc handle
    the ucred struct now.
  - debian/control:
    - Build-depend on libltdl7-dev rather then libltdl3-dev.
  - debian/patches/autogen.sh:
    - Call libtoolize with the --install option to install config.{guess,sub}
      files.
  - Don't use local statement in config script as it fails if /bin/sh
    points to bash (LP: #286063).
  - Disable the testsuite on hppa. Allows building of packages on this
    architecture again, once this package is in the archive.
    LP: #288908.
  - debian/slapd.postinst, debian/slapd.script-common: set correct ownership
    and permissions on /var/lib/ldap, /etc/ldap/slapd.d (group readable) and
    /var/run/slapd (world readable). (LP: #257667).
  - debian/patches/nssov-build, debian/rules: 
    Build and package the nss overlay.
    debian/schema/misc.ldif: add ldif file for the misc schema, which defines
    rfc822MailMember (required by the nss overlay).
  - debian/{control,rules}: enable PIE hardening
  - Use cn=config as the default configuration backend instead of 
    slapd.conf. Migrate slapd.conf  file to /etc/ldap/slapd.d/ on upgrade
    asking the end user to enter a new password to control the access to the
    cn=config tree.
* debian/patches/corrupt-contextCSN: The contextCSN can get corrupted at
  times. (ITS: #5947)

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
/* bconfig.c - the config backend */
2
 
/* $OpenLDAP: pkg/ldap/servers/slapd/bconfig.c,v 1.202.2.37 2008/07/09 23:52:27 quanah Exp $ */
 
2
/* $OpenLDAP: pkg/ldap/servers/slapd/bconfig.c,v 1.202.2.59 2009/02/13 03:16:59 quanah Exp $ */
3
3
/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
4
4
 *
5
 
 * Copyright 2005-2008 The OpenLDAP Foundation.
 
5
 * Copyright 2005-2009 The OpenLDAP Foundation.
6
6
 * All rights reserved.
7
7
 *
8
8
 * Redistribution and use in source and binary forms, with or without
63
63
        ContentRule *c_cr_head, *c_cr_tail;
64
64
        ObjectClass *c_oc_head, *c_oc_tail;
65
65
        OidMacro *c_om_head, *c_om_tail;
 
66
        Syntax *c_syn_head, *c_syn_tail;
66
67
        BerVarray c_dseFiles;
67
68
} ConfigFile;
68
69
 
87
88
 
88
89
/* Private state */
89
90
static AttributeDescription *cfAd_backend, *cfAd_database, *cfAd_overlay,
90
 
        *cfAd_include, *cfAd_attr, *cfAd_oc, *cfAd_om;
 
91
        *cfAd_include, *cfAd_attr, *cfAd_oc, *cfAd_om, *cfAd_syntax;
91
92
 
92
93
static ConfigFile *cfn;
93
94
 
97
98
extern AttributeType *at_sys_tail;      /* at.c */
98
99
extern ObjectClass *oc_sys_tail;        /* oc.c */
99
100
extern OidMacro *om_sys_tail;   /* oidm.c */
 
101
extern Syntax *syn_sys_tail;    /* syntax.c */
100
102
static AttributeType *cf_at_tail;
101
103
static ObjectClass *cf_oc_tail;
102
104
static OidMacro *cf_om_tail;
 
105
static Syntax *cf_syn_tail;
103
106
 
104
107
static int config_add_internal( CfBackInfo *cfb, Entry *e, ConfigArgs *ca,
105
108
        SlapReply *rs, int *renumber, Operation *op );
142
145
        CFG_DATABASE,
143
146
        CFG_TLS_RAND,
144
147
        CFG_TLS_CIPHER,
 
148
        CFG_TLS_PROTOCOL_MIN,
145
149
        CFG_TLS_CERT_FILE,
146
150
        CFG_TLS_CERT_KEY,
147
151
        CFG_TLS_CA_PATH,
180
184
        CFG_SERVERID,
181
185
        CFG_SORTVALS,
182
186
        CFG_IX_INTLEN,
 
187
        CFG_SYNTAX,
 
188
        CFG_ACL_ADD,
183
189
 
184
190
        CFG_LAST
185
191
};
254
260
 * OLcfgOv{Oc|At}:17                    -> dyngroup
255
261
 * OLcfgOv{Oc|At}:18                    -> memberof
256
262
 * OLcfgOv{Oc|At}:19                    -> collect
 
263
 * OLcfgOv{Oc|At}:20                    -> retcode
257
264
 */
258
265
 
259
266
/* alphabetical ordering */
275
282
                        "DESC 'Access Control List' "
276
283
                        "EQUALITY caseIgnoreMatch "
277
284
                        "SYNTAX OMsDirectoryString X-ORDERED 'VALUES' )", NULL, NULL },
 
285
        { "add_content_acl",    NULL, 0, 0, 0, ARG_MAY_DB|ARG_ON_OFF|ARG_MAGIC|CFG_ACL_ADD,
 
286
                &config_generic, "( OLcfgGlAt:86 NAME 'olcAddContentAcl' "
 
287
                        "DESC 'Check ACLs against content of Add ops' "
 
288
                        "SYNTAX OMsBoolean SINGLE-VALUE )", NULL, NULL },
278
289
        { "allows",     "features", 2, 0, 5, ARG_PRE_DB|ARG_MAGIC,
279
290
                &config_allows, "( OLcfgGlAt:2 NAME 'olcAllows' "
280
291
                        "DESC 'Allowed set of deprecated features' "
380
391
        { "lastmod", "on|off", 2, 2, 0, ARG_DB|ARG_ON_OFF|ARG_MAGIC|CFG_LASTMOD,
381
392
                &config_generic, "( OLcfgDbAt:0.4 NAME 'olcLastMod' "
382
393
                        "SYNTAX OMsBoolean SINGLE-VALUE )", NULL, NULL },
 
394
        { "ldapsyntax", "syntax", 2, 0, 0,
 
395
                ARG_PAREN|ARG_MAGIC|CFG_SYNTAX,
 
396
                &config_generic, "( OLcfgGlAt:85 NAME 'olcLdapSyntaxes' "
 
397
                        "DESC 'OpenLDAP ldapSyntax' "
 
398
                        "EQUALITY caseIgnoreMatch "
 
399
                        "SYNTAX OMsDirectoryString X-ORDERED 'VALUES' )",
 
400
                                NULL, NULL },
383
401
        { "limits", "limits", 2, 0, 0, ARG_DB|ARG_MAGIC|CFG_LIMITS,
384
402
                &config_generic, "( OLcfgDbAt:0.5 NAME 'olcLimits' "
385
403
                        "EQUALITY caseIgnoreMatch "
668
686
#endif
669
687
                "( OLcfgGlAt:77 NAME 'olcTLSDHParamFile' "
670
688
                        "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL },
 
689
        { "TLSProtocolMin",     NULL, 0, 0, 0,
 
690
#ifdef HAVE_TLS
 
691
                CFG_TLS_PROTOCOL_MIN|ARG_STRING|ARG_MAGIC, &config_tls_config,
 
692
#else
 
693
                ARG_IGNORED, NULL,
 
694
#endif
 
695
                "( OLcfgGlAt:87 NAME 'olcTLSProtocolMin' "
 
696
                        "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL },
671
697
        { "tool-threads", "count", 2, 2, 0, ARG_INT|ARG_MAGIC|CFG_TTHREADS,
672
698
                &config_generic, "( OLcfgGlAt:80 NAME 'olcToolThreads' "
673
699
                        "SYNTAX OMsInteger SINGLE-VALUE )", NULL, NULL },
684
710
                NULL, NULL, NULL, NULL }
685
711
};
686
712
 
 
713
/* Need to no-op this keyword for dynamic config */
 
714
ConfigTable olcDatabaseDummy[] = {
 
715
        { "", "", 0, 0, 0, ARG_IGNORED,
 
716
                NULL, "( OLcfgGlAt:13 NAME 'olcDatabase' "
 
717
                        "DESC 'The backend type for a database instance' "
 
718
                        "SUP olcBackend SINGLE-VALUE X-ORDERED 'SIBLINGS' )", NULL, NULL },
 
719
        { NULL, NULL, 0, 0, 0, ARG_IGNORED }
 
720
};
 
721
 
687
722
/* Routines to check if a child can be added to this type */
688
723
static ConfigLDAPadd cfAddSchema, cfAddInclude, cfAddDatabase,
689
724
        cfAddBackend, cfAddModule, cfAddOverlay;
717
752
                 "olcDisallows $ olcGentleHUP $ olcIdleTimeout $ "
718
753
                 "olcIndexSubstrIfMaxLen $ olcIndexSubstrIfMinLen $ "
719
754
                 "olcIndexSubstrAnyLen $ olcIndexSubstrAnyStep $ olcIndexIntLen $ "
720
 
                 "olcLocalSSF $ olcLogLevel $ "
 
755
                 "olcLocalSSF $ olcLogFile $ olcLogLevel $ "
721
756
                 "olcPasswordCryptSaltFormat $ olcPasswordHash $ olcPidFile $ "
722
757
                 "olcPluginLogFile $ olcReadOnly $ olcReferral $ "
723
758
                 "olcReplogFile $ olcRequires $ olcRestrict $ olcReverseLookup $ "
731
766
                 "olcTLSRandFile $ olcTLSVerifyClient $ olcTLSDHParamFile $ "
732
767
                 "olcTLSCRLFile $ olcToolThreads $ "
733
768
                 "olcObjectIdentifier $ olcAttributeTypes $ olcObjectClasses $ "
734
 
                 "olcDitContentRules ) )", Cft_Global },
 
769
                 "olcDitContentRules $ olcLdapSyntaxes ) )", Cft_Global },
735
770
        { "( OLcfgGlOc:2 "
736
771
                "NAME 'olcSchemaConfig' "
737
772
                "DESC 'OpenLDAP schema object' "
738
773
                "SUP olcConfig STRUCTURAL "
739
774
                "MAY ( cn $ olcObjectIdentifier $ olcAttributeTypes $ "
740
 
                 "olcObjectClasses $ olcDitContentRules ) )",
 
775
                 "olcObjectClasses $ olcDitContentRules $ olcLdapSyntaxes ) )",
741
776
                        Cft_Schema, NULL, cfAddSchema },
742
777
        { "( OLcfgGlOc:3 "
743
778
                "NAME 'olcBackendConfig' "
750
785
                "SUP olcConfig STRUCTURAL "
751
786
                "MUST olcDatabase "
752
787
                "MAY ( olcHidden $ olcSuffix $ olcSubordinate $ olcAccess $ "
753
 
                 "olcLastMod $ olcLimits $ "
 
788
                 "olcAddContentAcl $ olcLastMod $ olcLimits $ "
754
789
                 "olcMaxDerefDepth $ olcPlugin $ olcReadOnly $ olcReplica $ "
755
790
                 "olcReplicaArgsFile $ olcReplicaPidFile $ olcReplicationInterval $ "
756
791
                 "olcReplogFile $ olcRequires $ olcRestrict $ olcRootDN $ olcRootPW $ "
926
961
                                rc = 1;
927
962
                        }
928
963
                        break;
 
964
                case CFG_SYNTAX: {
 
965
                        ConfigFile *cf = c->ca_private;
 
966
                        if ( !cf )
 
967
                                syn_unparse( &c->rvalue_vals, NULL, NULL, 1 );
 
968
                        else if ( cf->c_syn_head )
 
969
                                syn_unparse( &c->rvalue_vals, cf->c_syn_head,
 
970
                                        cf->c_syn_tail, 0 );
 
971
                        if ( !c->rvalue_vals )
 
972
                                rc = 1;
 
973
                        }
 
974
                        break;
929
975
                case CFG_DIT: {
930
976
                        ConfigFile *cf = c->ca_private;
931
977
                        if ( !cf )
942
988
                        AccessControl *a;
943
989
                        char *src, *dst, ibuf[11];
944
990
                        struct berval bv, abv;
945
 
                        AccessControl *end;
946
 
                        if ( c->be == frontendDB )
947
 
                                end = NULL;
948
 
                        else
949
 
                                end = frontendDB->be_acl;
950
 
                        for (i=0, a=c->be->be_acl; a && a != end; i++,a=a->acl_next) {
 
991
                        for (i=0, a=c->be->be_acl; a; i++,a=a->acl_next) {
951
992
                                abv.bv_len = snprintf( ibuf, sizeof( ibuf ), SLAP_X_ORDERED_FMT, i );
952
993
                                if ( abv.bv_len >= sizeof( ibuf ) ) {
953
994
                                        ber_bvarray_free_x( c->rvalue_vals, NULL );
974
1015
                        rc = (!i);
975
1016
                        break;
976
1017
                }
 
1018
                case CFG_ACL_ADD:
 
1019
                        c->value_int = (SLAP_DBACL_ADD(c->be) != 0);
 
1020
                        break;
977
1021
                case CFG_ROOTDSE: {
978
1022
                        ConfigFile *cf = c->ca_private;
979
1023
                        if ( cf->c_dseFiles ) {
993
1037
                                        if ( !BER_BVISEMPTY( &si->si_url )) {
994
1038
                                                bv.bv_len = si->si_url.bv_len + 6;
995
1039
                                                bv.bv_val = ch_malloc( bv.bv_len );
996
 
                                                sprintf( bv.bv_val, "%d %s", si->si_num,
 
1040
                                                bv.bv_len = sprintf( bv.bv_val, "%d %s", si->si_num,
997
1041
                                                        si->si_url.bv_val );
998
1042
                                                ber_bvarray_add( &c->rvalue_vals, &bv );
999
1043
                                        } else {
1127
1171
                case CFG_SASLSECP:
1128
1172
                case CFG_SSTR_IF_MAX:
1129
1173
                case CFG_SSTR_IF_MIN:
 
1174
                case CFG_ACL_ADD:
1130
1175
                        break;
1131
1176
 
1132
1177
                /* no-ops, requires slapd restart */
1179
1224
 
1180
1225
                case CFG_ACL:
1181
1226
                        if ( c->valx < 0 ) {
1182
 
                                AccessControl *end;
1183
 
                                if ( c->be == frontendDB )
1184
 
                                        end = NULL;
1185
 
                                else
1186
 
                                        end = frontendDB->be_acl;
1187
 
                                acl_destroy( c->be->be_acl, end );
1188
 
                                c->be->be_acl = end;
 
1227
                                acl_destroy( c->be->be_acl );
 
1228
                                c->be->be_acl = NULL;
1189
1229
 
1190
1230
                        } else {
1191
1231
                                AccessControl **prev, *a;
1276
1316
                                }
1277
1317
                        }
1278
1318
                        break;
 
1319
 
 
1320
                case CFG_SYNTAX: {
 
1321
                        CfEntryInfo *ce;
 
1322
                        /* Can be NULL when undoing a failed add */
 
1323
                        if ( c->ca_entry ) {
 
1324
                                ce = c->ca_entry->e_private;
 
1325
                                /* can't modify the hardcoded schema */
 
1326
                                if ( ce->ce_parent->ce_type == Cft_Global )
 
1327
                                        return 1;
 
1328
                                }
 
1329
                        }
 
1330
                        cfn = c->ca_private;
 
1331
                        if ( c->valx < 0 ) {
 
1332
                                Syntax *syn;
 
1333
 
 
1334
                                for( syn = cfn->c_syn_head; syn; syn_next( &syn )) {
 
1335
                                        syn_delete( syn );
 
1336
                                        if ( syn == cfn->c_syn_tail )
 
1337
                                                break;
 
1338
                                }
 
1339
                                cfn->c_syn_head = cfn->c_syn_tail = NULL;
 
1340
                        } else {
 
1341
                                Syntax *syn, *prev = NULL;
 
1342
 
 
1343
                                for ( i = 0, syn = cfn->c_syn_head; i < c->valx; i++) {
 
1344
                                        prev = syn;
 
1345
                                        syn_next( &syn );
 
1346
                                }
 
1347
                                syn_delete( syn );
 
1348
                                if ( cfn->c_syn_tail == syn ) {
 
1349
                                        cfn->c_syn_tail = prev;
 
1350
                                }
 
1351
                                if ( cfn->c_syn_head == syn ) {
 
1352
                                        syn_next( &syn );
 
1353
                                        cfn->c_syn_head = syn;
 
1354
                                }
 
1355
                        }
 
1356
                        break;
1279
1357
                case CFG_SORTVALS:
1280
1358
                        if ( c->valx < 0 ) {
1281
1359
                                ADlist *sv;
1502
1580
                        }
1503
1581
                        break;
1504
1582
 
 
1583
                case CFG_SYNTAX: {
 
1584
                        Syntax *syn, *prev;
 
1585
 
 
1586
                        if ( c->op == LDAP_MOD_ADD && c->ca_private && cfn != c->ca_private )
 
1587
                                cfn = c->ca_private;
 
1588
                        if ( c->valx < 0 ) {
 
1589
                                prev = cfn->c_syn_tail;
 
1590
                        } else {
 
1591
                                prev = NULL;
 
1592
                                /* If adding anything after the first, prev is easy */
 
1593
                                if ( c->valx ) {
 
1594
                                        int i;
 
1595
                                        for ( i = 0, syn = cfn->c_syn_head; i < c->valx; i++ ) {
 
1596
                                                prev = syn;
 
1597
                                                syn_next( &syn );
 
1598
                                        }
 
1599
                                } else
 
1600
                                /* If adding the first, and head exists, find its prev */
 
1601
                                        if (cfn->c_syn_head) {
 
1602
                                        for ( syn_start( &syn ); syn != cfn->c_syn_head; ) {
 
1603
                                                prev = syn;
 
1604
                                                syn_next( &syn );
 
1605
                                        }
 
1606
                                }
 
1607
                                /* else prev is NULL, append to end of global list */
 
1608
                        }
 
1609
                        if ( parse_syn( c, &syn, prev ) ) return(1);
 
1610
                        if ( !cfn->c_syn_head ) cfn->c_syn_head = syn;
 
1611
                        if ( cfn->c_syn_tail == prev ) cfn->c_syn_tail = syn;
 
1612
                        }
 
1613
                        break;
 
1614
 
1505
1615
                case CFG_DIT: {
1506
1616
                        ContentRule *cr;
1507
1617
 
1580
1690
                case CFG_ACL:
1581
1691
                        /* Don't append to the global ACL if we're on a specific DB */
1582
1692
                        i = c->valx;
1583
 
                        if ( c->be != frontendDB && frontendDB->be_acl && c->valx == -1 ) {
 
1693
                        if ( c->valx == -1 ) {
1584
1694
                                AccessControl *a;
1585
1695
                                i = 0;
1586
 
                                for ( a=c->be->be_acl; a && a != frontendDB->be_acl;
1587
 
                                        a = a->acl_next )
 
1696
                                for ( a=c->be->be_acl; a; a = a->acl_next )
1588
1697
                                        i++;
1589
1698
                        }
1590
1699
                        if ( parse_acl(c->be, c->fname, c->lineno, c->argc, c->argv, i ) ) {
1592
1701
                        }
1593
1702
                        break;
1594
1703
 
 
1704
                case CFG_ACL_ADD:
 
1705
                        if(c->value_int)
 
1706
                                SLAP_DBFLAGS(c->be) |= SLAP_DBFLAG_ACL_ADD;
 
1707
                        else
 
1708
                                SLAP_DBFLAGS(c->be) &= ~SLAP_DBFLAG_ACL_ADD;
 
1709
                        break;
 
1710
 
1595
1711
                case CFG_ROOTDSE:
1596
1712
                        if(root_dse_read_file(c->argv[1])) {
1597
1713
                                snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> could not read file", c->argv[0] );
1667
1783
                                *sip = si;
1668
1784
 
1669
1785
                                if (( slapMode & SLAP_SERVER_MODE ) && c->argc > 2 ) {
 
1786
                                        Listener **l = slapd_get_listeners();
 
1787
                                        int i, isMe = 0;
 
1788
 
 
1789
                                        /* Try a straight compare with Listener strings */
 
1790
                                        for ( i=0; l && l[i]; i++ ) {
 
1791
                                                if ( !strcasecmp( c->argv[2], l[i]->sl_url.bv_val )) {
 
1792
                                                        isMe = 1;
 
1793
                                                        break;
 
1794
                                                }
 
1795
                                        }
 
1796
 
1670
1797
                                        /* If hostname is empty, or is localhost, or matches
1671
1798
                                         * our hostname, this serverID refers to this host.
1672
1799
                                         * Compare it against listeners and ports.
1673
1800
                                         */
1674
 
                                        if ( !lud->lud_host || !lud->lud_host[0] ||
 
1801
                                        if ( !isMe && ( !lud->lud_host || !lud->lud_host[0] ||
1675
1802
                                                !strncasecmp("localhost", lud->lud_host,
1676
1803
                                                        STRLENOF("localhost")) ||
1677
 
                                                !strcasecmp( global_host, lud->lud_host )) {
1678
 
                                                Listener **l = slapd_get_listeners();
1679
 
                                                int i;
 
1804
                                                !strcasecmp( global_host, lud->lud_host ))) {
1680
1805
 
1681
1806
                                                for ( i=0; l && l[i]; i++ ) {
1682
1807
                                                        LDAPURLDesc *lu2;
1683
 
                                                        int isMe = 0;
1684
1808
                                                        ldap_url_parse( l[i]->sl_url.bv_val, &lu2 );
1685
1809
                                                        do {
1686
1810
                                                                if ( strcasecmp( lud->lud_scheme,
1709
1833
                                                        } while(0);
1710
1834
                                                        ldap_free_urldesc( lu2 );
1711
1835
                                                        if ( isMe ) {
1712
 
                                                                slap_serverID = si->si_num;
1713
 
                                                                Debug( LDAP_DEBUG_CONFIG,
1714
 
                                                                        "%s: SID=%d (listener=%s)\n",
1715
 
                                                                        c->log, slap_serverID,
1716
 
                                                                        l[i]->sl_url.bv_val );
1717
1836
                                                                break;
1718
1837
                                                        }
1719
1838
                                                }
1720
1839
                                        }
 
1840
                                        if ( isMe ) {
 
1841
                                                slap_serverID = si->si_num;
 
1842
                                                Debug( LDAP_DEBUG_CONFIG,
 
1843
                                                        "%s: SID=%d (listener=%s)\n",
 
1844
                                                        c->log, slap_serverID,
 
1845
                                                        l[i]->sl_url.bv_val );
 
1846
                                        }
1721
1847
                                }
1722
1848
                                if ( c->argc > 2 )
1723
1849
                                        ldap_free_urldesc( lud );
2485
2611
                { BER_BVC("bind_simple"),       SLAP_DISALLOW_BIND_SIMPLE },
2486
2612
                { BER_BVC("tls_2_anon"),                SLAP_DISALLOW_TLS_2_ANON },
2487
2613
                { BER_BVC("tls_authc"),         SLAP_DISALLOW_TLS_AUTHC },
 
2614
                { BER_BVC("proxy_authz_non_critical"),  SLAP_DISALLOW_PROXY_AUTHZ_N_CRIT },
 
2615
                { BER_BVC("dontusecopy_non_critical"),  SLAP_DISALLOW_DONTUSECOPY_N_CRIT },
2488
2616
                { BER_BVNULL, 0 }
2489
2617
        };
2490
2618
        if (c->op == SLAP_CONFIG_EMIT) {
2960
3088
                return 1;
2961
3089
        }
2962
3090
 
2963
 
        SLAP_DBFLAGS(c->be) |= (SLAP_DBFLAG_SHADOW | SLAP_DBFLAG_SINGLE_SHADOW | flag);
 
3091
        if ( SLAP_SHADOW(c->be) ) {
 
3092
                /* if already shadow, only check consistency */
 
3093
                if ( ( SLAP_DBFLAGS(c->be) & flag ) != flag ) {
 
3094
                        Debug( LDAP_DEBUG_ANY, "%s: inconsistent shadow flag 0x%x.\n", c->log, flag, 0 );
 
3095
                        return 1;
 
3096
                }
 
3097
 
 
3098
        } else {
 
3099
                SLAP_DBFLAGS(c->be) |= (SLAP_DBFLAG_SHADOW | SLAP_DBFLAG_SINGLE_SHADOW | flag);
 
3100
        }
2964
3101
 
2965
3102
        return 0;
2966
3103
}
3089
3226
        switch(c->type) {
3090
3227
        case CFG_TLS_CRLCHECK:  flag = LDAP_OPT_X_TLS_CRLCHECK; break;
3091
3228
        case CFG_TLS_VERIFY:    flag = LDAP_OPT_X_TLS_REQUIRE_CERT; break;
 
3229
        case CFG_TLS_PROTOCOL_MIN: flag = LDAP_OPT_X_TLS_PROTOCOL_MIN; break;
3092
3230
        default:
3093
3231
                Debug(LDAP_DEBUG_ANY, "%s: "
3094
3232
                                "unknown tls_option <0x%x>\n",
3160
3298
        ConfigArgs *ca;
3161
3299
        Entry *frontend;
3162
3300
        Entry *config;
3163
 
        int     got_frontend;
 
3301
        int got_frontend;
3164
3302
        int got_config;
3165
3303
} setup_cookie;
3166
3304
 
3169
3307
{
3170
3308
        if ( rs->sr_type == REP_SEARCH ) {
3171
3309
                setup_cookie *sc = op->o_callback->sc_private;
 
3310
                struct berval pdn;
3172
3311
 
3173
3312
                sc->cfb->cb_got_ldif = 1;
3174
3313
                /* Does the frontend exist? */
3175
3314
                if ( !sc->got_frontend ) {
3176
3315
                        if ( !strncmp( rs->sr_entry->e_nname.bv_val,
3177
 
                                "olcDatabase", STRLENOF( "olcDatabase" ))) {
 
3316
                                "olcDatabase", STRLENOF( "olcDatabase" )))
 
3317
                        {
3178
3318
                                if ( strncmp( rs->sr_entry->e_nname.bv_val +
3179
3319
                                        STRLENOF( "olcDatabase" ), "={-1}frontend",
3180
 
                                        STRLENOF( "={-1}frontend" ))) {
 
3320
                                        STRLENOF( "={-1}frontend" )))
 
3321
                                {
3181
3322
                                        struct berval rdn;
3182
3323
                                        int i = op->o_noop;
3183
3324
                                        sc->ca->be = frontendDB;
3200
3341
                                }
3201
3342
                        }
3202
3343
                }
 
3344
 
 
3345
                dnParent( &rs->sr_entry->e_nname, &pdn );
 
3346
 
3203
3347
                /* Does the configDB exist? */
3204
3348
                if ( sc->got_frontend && !sc->got_config &&
3205
3349
                        !strncmp( rs->sr_entry->e_nname.bv_val,
3206
 
                        "olcDatabase", STRLENOF( "olcDatabase" ))) {
 
3350
                        "olcDatabase", STRLENOF( "olcDatabase" )) &&
 
3351
                        dn_match( &config_rdn, &pdn ) )
 
3352
                {
3207
3353
                        if ( strncmp( rs->sr_entry->e_nname.bv_val +
3208
3354
                                STRLENOF( "olcDatabase" ), "={0}config",
3209
 
                                STRLENOF( "={0}config" ))) {
 
3355
                                STRLENOF( "={0}config" )))
 
3356
                        {
3210
3357
                                struct berval rdn;
3211
3358
                                int i = op->o_noop;
3212
3359
                                sc->ca->be = LDAP_STAILQ_FIRST( &backendDB );
3507
3654
                rs->sr_entry = ce->ce_entry;
3508
3655
                rs->sr_flags = 0;
3509
3656
                rc = send_search_entry( op, rs );
 
3657
                if ( rc != LDAP_SUCCESS ) {
 
3658
                        return rc;
 
3659
                }
3510
3660
        }
3511
3661
        if ( op->ors_scope == LDAP_SCOPE_SUBTREE ) {
3512
3662
                if ( ce->ce_kids ) {
3669
3819
        struct berval rdn, nrdn;
3670
3820
 
3671
3821
        for (ce2 = ce->ce_kids; ce2; ce2 = ce2->ce_sibs) {
 
3822
                struct berval newdn, newndn;
3672
3823
                dnRdn ( &ce2->ce_entry->e_name, &rdn );
3673
3824
                dnRdn ( &ce2->ce_entry->e_nname, &nrdn );
 
3825
                build_new_dn( &newdn, &ce->ce_entry->e_name, &rdn, NULL );
 
3826
                build_new_dn( &newndn, &ce->ce_entry->e_nname, &nrdn, NULL );
3674
3827
                free( ce2->ce_entry->e_name.bv_val );
3675
3828
                free( ce2->ce_entry->e_nname.bv_val );
3676
 
                build_new_dn( &ce2->ce_entry->e_name, &ce->ce_entry->e_name,
3677
 
                        &rdn, NULL );
3678
 
                build_new_dn( &ce2->ce_entry->e_nname, &ce->ce_entry->e_nname,
3679
 
                        &nrdn, NULL );
 
3829
                ce2->ce_entry->e_name = newdn;
 
3830
                ce2->ce_entry->e_nname = newndn;
3680
3831
                config_rename_kids( ce2 );
3681
3832
        }
3682
3833
}
3837
3988
                        isconfig = 1;
3838
3989
        }
3839
3990
        ptr1 = ber_bvchr( &e->e_name, '{' );
3840
 
        if ( ptr1 && ptr1 - e->e_name.bv_val < rdn.bv_len ) {
 
3991
        if ( ptr1 && ptr1 < &e->e_name.bv_val[ rdn.bv_len ] ) {
3841
3992
                char    *next;
3842
3993
                ptr2 = strchr( ptr1, '}' );
3843
 
                if (!ptr2 || ptr2 - e->e_name.bv_val > rdn.bv_len)
 
3994
                if ( !ptr2 || ptr2 > &e->e_name.bv_val[ rdn.bv_len ] )
3844
3995
                        return LDAP_NAMING_VIOLATION;
3845
3996
                if ( ptr2-ptr1 == 1)
3846
3997
                        return LDAP_NAMING_VIOLATION;
3881
4032
                if ( isconfig && index == -1 ) {
3882
4033
                        index = 0;
3883
4034
                }
3884
 
                if ( !isfrontend && index == -1 ) {
 
4035
                if (( !isfrontend && index == -1 ) || ( index > nsibs ) ){
3885
4036
                        index = nsibs;
3886
4037
                }
3887
4038
 
4061
4212
                ct = config_find_table( colst, nocs, ad, ca );
4062
4213
                config_del_vals( ct, ca );
4063
4214
        }
 
4215
        if ( cfn->c_syn_head ) {
 
4216
                struct berval bv = BER_BVC("olcLdapSyntaxes");
 
4217
                ad = NULL;
 
4218
                slap_bv2ad( &bv, &ad, &text );
 
4219
                ct = config_find_table( colst, nocs, ad, ca );
 
4220
                config_del_vals( ct, ca );
 
4221
        }
4064
4222
        if ( cfn->c_om_head ) {
4065
4223
                struct berval bv = BER_BVC("olcObjectIdentifier");
4066
4224
                ad = NULL;
4330
4488
                if ( !ct ) continue;    /* user data? */
4331
4489
                for (i=0; a->a_vals[i].bv_val; i++) {
4332
4490
                        char *iptr = NULL;
 
4491
                        ca->valx = -1;
4333
4492
                        ca->line = a->a_vals[i].bv_val;
4334
4493
                        if ( a->a_desc->ad_type->sat_flags & SLAP_AT_ORDERED ) {
4335
4494
                                ptr = strchr( ca->line, '}' );
4341
4500
                        if ( a->a_desc->ad_type->sat_flags & SLAP_AT_ORDERED_SIB ) {
4342
4501
                                if ( iptr ) {
4343
4502
                                        ca->valx = strtol( iptr+1, NULL, 0 );
4344
 
                                } else {
4345
 
                                        ca->valx = -1;
4346
4503
                                }
4347
4504
                        } else {
4348
4505
                                ca->valx = i;
4533
4690
                goto out;
4534
4691
        }
4535
4692
 
 
4693
        /*
 
4694
         * Check for attribute ACL
 
4695
         */
 
4696
        if ( !acl_check_modlist( op, op->ora_e, op->orm_modlist )) {
 
4697
                rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
 
4698
                rs->sr_text = "no write access to attribute";
 
4699
                goto out;
 
4700
        }
 
4701
 
4536
4702
        cfb = (CfBackInfo *)op->o_bd->be_private;
4537
4703
 
4538
4704
        /* add opattrs for syncprov */
4539
4705
        {
4540
4706
                char textbuf[SLAP_TEXT_BUFLEN];
4541
4707
                size_t textlen = sizeof textbuf;
4542
 
                rs->sr_err = entry_schema_check(op, op->ora_e, NULL, 0, 1,
 
4708
                rs->sr_err = entry_schema_check(op, op->ora_e, NULL, 0, 1, NULL,
4543
4709
                        &rs->sr_text, textbuf, sizeof( textbuf ) );
4544
4710
                if ( rs->sr_err != LDAP_SUCCESS )
4545
4711
                        goto out;
4622
4788
{
4623
4789
        int rc;
4624
4790
 
 
4791
        ca->valx = -1;
4625
4792
        if (ad->ad_type->sat_flags & SLAP_AT_ORDERED &&
4626
4793
                ca->line[0] == '{' )
4627
4794
        {
4785
4952
        
4786
4953
        if ( rc == LDAP_SUCCESS) {
4787
4954
                /* check that the entry still obeys the schema */
4788
 
                rc = entry_schema_check(op, e, NULL, 0, 0,
 
4955
                rc = entry_schema_check(op, e, NULL, 0, 0, NULL,
4789
4956
                        &rs->sr_text, ca->cr_msg, sizeof(ca->cr_msg) );
4790
4957
        }
4791
4958
        if ( rc ) goto out_noop;
5236
5403
        CfBackInfo *cfb;
5237
5404
        CfEntryInfo *ce, *last, *ce2;
5238
5405
 
5239
 
        slap_mask_t mask;
5240
 
 
5241
5406
        cfb = (CfBackInfo *)op->o_bd->be_private;
5242
5407
 
5243
5408
        ce = config_find_base( cfb->cb_root, &op->o_req_ndn, &last );
5245
5410
                if ( last )
5246
5411
                        rs->sr_matched = last->ce_entry->e_name.bv_val;
5247
5412
                rs->sr_err = LDAP_NO_SUCH_OBJECT;
5248
 
        } if ( ce->ce_kids ) {
 
5413
        } else if ( ce->ce_kids ) {
5249
5414
                rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
5250
5415
        } else if ( ce->ce_type == Cft_Overlay ){
5251
5416
                char *iptr;
5252
 
                int count, ixold, rc;
 
5417
                int count, ixold;
5253
5418
 
5254
5419
                ldap_pvt_thread_pool_pause( &connection_pool );
5255
5420
                
5348
5513
        switch ( op->ors_scope ) {
5349
5514
        case LDAP_SCOPE_BASE:
5350
5515
        case LDAP_SCOPE_SUBTREE:
5351
 
                config_send( op, rs, ce, 0 );
 
5516
                rs->sr_err = config_send( op, rs, ce, 0 );
5352
5517
                break;
5353
5518
                
5354
5519
        case LDAP_SCOPE_ONELEVEL:
5355
5520
                for (ce = ce->ce_kids; ce; ce=ce->ce_sibs) {
5356
 
                        config_send( op, rs, ce, 1 );
 
5521
                        rs->sr_err = config_send( op, rs, ce, 1 );
 
5522
                        if ( rs->sr_err ) {
 
5523
                                break;
 
5524
                        }
5357
5525
                }
5358
5526
                break;
5359
5527
        }
5360
 
                
5361
 
        rs->sr_err = LDAP_SUCCESS;
 
5528
 
5362
5529
out:
5363
5530
        send_ldap_result( op, rs );
5364
 
        return 0;
 
5531
        return rs->sr_err;
5365
5532
}
5366
5533
 
5367
5534
/* no-op, we never free entries */
5407
5574
        return rc;
5408
5575
}
5409
5576
 
5410
 
static void
 
5577
static int
5411
5578
config_build_attrs( Entry *e, AttributeType **at, AttributeDescription *ad,
5412
5579
        ConfigTable *ct, ConfigArgs *c )
5413
5580
{
5424
5591
                                 * returns success with no values */
5425
5592
                                if (rc == LDAP_SUCCESS && c->rvalue_vals != NULL ) {
5426
5593
                                        if ( c->rvalue_nvals )
5427
 
                                                attr_merge(e, ct[i].ad, c->rvalue_vals,
 
5594
                                                rc = attr_merge(e, ct[i].ad, c->rvalue_vals,
5428
5595
                                                        c->rvalue_nvals);
5429
 
                                        else
5430
 
                                                attr_merge_normalize(e, ct[i].ad,
 
5596
                                        else {
 
5597
                                                slap_syntax_validate_func *validate =
 
5598
                                                        ct[i].ad->ad_type->sat_syntax->ssyn_validate;
 
5599
                                                if ( validate ) {
 
5600
                                                        int j;
 
5601
                                                        for ( j=0; c->rvalue_vals[j].bv_val; j++ ) {
 
5602
                                                                rc = ordered_value_validate( ct[i].ad,
 
5603
                                                                        &c->rvalue_vals[j], LDAP_MOD_ADD );
 
5604
                                                                if ( rc ) {
 
5605
                                                                        Debug( LDAP_DEBUG_ANY,
 
5606
                                                                                "config_build_attrs: error %d on %s value #%d\n",
 
5607
                                                                                rc, ct[i].ad->ad_cname.bv_val, j );
 
5608
                                                                        return rc;
 
5609
                                                                }
 
5610
                                                        }
 
5611
                                                }
 
5612
                                                        
 
5613
                                                rc = attr_merge_normalize(e, ct[i].ad,
5431
5614
                                                        c->rvalue_vals, NULL);
 
5615
                                        }
5432
5616
                                        ber_bvarray_free( c->rvalue_nvals );
5433
5617
                                        ber_bvarray_free( c->rvalue_vals );
 
5618
                                        if ( rc ) {
 
5619
                                                Debug( LDAP_DEBUG_ANY,
 
5620
                                                        "config_build_attrs: error %d on %s\n",
 
5621
                                                        rc, ct[i].ad->ad_cname.bv_val, 0 );
 
5622
                                                return rc;
 
5623
                                        }
5434
5624
                                }
5435
5625
                                break;
5436
5626
                        }
5437
5627
                }
5438
5628
        }
 
5629
        return 0;
5439
5630
}
5440
5631
 
5441
5632
Entry *
5449
5640
        AttributeDescription *ad = NULL;
5450
5641
        int rc;
5451
5642
        char *ptr;
5452
 
        const char *text;
 
5643
        const char *text = "";
5453
5644
        Attribute *oc_at;
5454
5645
        struct berval pdn;
5455
5646
        ObjectClass *oc;
5487
5678
        ad_name.bv_len = ptr - rdn->bv_val;
5488
5679
        rc = slap_bv2ad( &ad_name, &ad, &text );
5489
5680
        if ( rc ) {
5490
 
                return NULL;
 
5681
                goto fail;
5491
5682
        }
5492
5683
        val.bv_val = ptr+1;
5493
5684
        val.bv_len = rdn->bv_len - (val.bv_val - rdn->bv_val);
5495
5686
 
5496
5687
        oc = main->co_oc;
5497
5688
        c->table = main->co_type;
5498
 
        if ( oc->soc_required )
5499
 
                config_build_attrs( e, oc->soc_required, ad, main->co_table, c );
 
5689
        if ( oc->soc_required ) {
 
5690
                rc = config_build_attrs( e, oc->soc_required, ad, main->co_table, c );
 
5691
                if ( rc ) goto fail;
 
5692
        }
5500
5693
 
5501
 
        if ( oc->soc_allowed )
5502
 
                config_build_attrs( e, oc->soc_allowed, ad, main->co_table, c );
 
5694
        if ( oc->soc_allowed ) {
 
5695
                rc = config_build_attrs( e, oc->soc_allowed, ad, main->co_table, c );
 
5696
                if ( rc ) goto fail;
 
5697
        }
5503
5698
 
5504
5699
        if ( extra ) {
5505
5700
                oc = extra->co_oc;
5506
5701
                c->table = extra->co_type;
5507
 
                if ( oc->soc_required )
5508
 
                        config_build_attrs( e, oc->soc_required, ad, extra->co_table, c );
 
5702
                if ( oc->soc_required ) {
 
5703
                        rc = config_build_attrs( e, oc->soc_required, ad, extra->co_table, c );
 
5704
                        if ( rc ) goto fail;
 
5705
                }
5509
5706
 
5510
 
                if ( oc->soc_allowed )
5511
 
                        config_build_attrs( e, oc->soc_allowed, ad, extra->co_table, c );
 
5707
                if ( oc->soc_allowed ) {
 
5708
                        rc = config_build_attrs( e, oc->soc_allowed, ad, extra->co_table, c );
 
5709
                        if ( rc ) goto fail;
 
5710
                }
5512
5711
        }
5513
5712
 
5514
5713
        oc_at = attr_find( e->e_attrs, slap_schema.si_ad_objectClass );
5515
5714
        rc = structural_class(oc_at->a_vals, &oc, NULL, &text, c->cr_msg,
5516
5715
                sizeof(c->cr_msg), op ? op->o_tmpmemctx : NULL );
5517
5716
        if ( rc != LDAP_SUCCESS ) {
 
5717
fail:
5518
5718
                Debug( LDAP_DEBUG_ANY,
5519
5719
                        "config_build_entry: build \"%s\" failed: \"%s\"\n",
5520
5720
                        rdn->bv_val, text, 0);
5529
5729
                        op->o_bd->be_add( op, rs );
5530
5730
                        if ( ( rs->sr_err != LDAP_SUCCESS ) 
5531
5731
                                        && (rs->sr_err != LDAP_ALREADY_EXISTS) ) {
5532
 
                                return NULL;
 
5732
                                goto fail;
5533
5733
                        }
5534
5734
                }
5535
5735
        }
5551
5751
        Entry *e;
5552
5752
        ConfigFile *cf = c->ca_private;
5553
5753
        char *ptr;
5554
 
        struct berval bv;
 
5754
        struct berval bv, rdn;
5555
5755
 
5556
5756
        for (; cf; cf=cf->c_sibs, c->depth++) {
5557
5757
                if ( !cf->c_at_head && !cf->c_cr_head && !cf->c_oc_head &&
5558
 
                        !cf->c_om_head ) continue;
 
5758
                        !cf->c_om_head && !cf->c_syn_head ) continue;
5559
5759
                c->value_dn.bv_val = c->log;
5560
5760
                LUTIL_SLASHPATH( cf->c_file.bv_val );
5561
5761
                bv.bv_val = strrchr(cf->c_file.bv_val, LDAP_DIRSEP[0]);
5577
5777
                        bv.bv_len );
5578
5778
                c->value_dn.bv_len += bv.bv_len;
5579
5779
                c->value_dn.bv_val[c->value_dn.bv_len] ='\0';
 
5780
                rdn = c->value_dn;
5580
5781
 
5581
5782
                c->ca_private = cf;
5582
 
                e = config_build_entry( op, rs, ceparent, c, &c->value_dn,
 
5783
                e = config_build_entry( op, rs, ceparent, c, &rdn,
5583
5784
                        &CFOC_SCHEMA, NULL );
5584
5785
                if ( !e ) {
5585
5786
                        return -1;
5684
5885
                        ber_bvarray_free( bv );
5685
5886
                        cf_oc_tail = oc_sys_tail;
5686
5887
                }
 
5888
                if ( cf_syn_tail != syn_sys_tail ) {
 
5889
                        a = attr_find( e->e_attrs, cfAd_syntax );
 
5890
                        if ( a ) {
 
5891
                                if ( a->a_nvals != a->a_vals )
 
5892
                                        ber_bvarray_free( a->a_nvals );
 
5893
                                ber_bvarray_free( a->a_vals );
 
5894
                                a->a_vals = NULL;
 
5895
                                a->a_nvals = NULL;
 
5896
                                a->a_numvals = 0;
 
5897
                        }
 
5898
                        syn_unparse( &bv, NULL, NULL, 1 );
 
5899
                        attr_merge_normalize( e, cfAd_syntax, bv, NULL );
 
5900
                        ber_bvarray_free( bv );
 
5901
                        cf_syn_tail = syn_sys_tail;
 
5902
                }
5687
5903
        } else {
5688
5904
                SlapReply rs = {REP_RESULT};
5689
5905
                c.ca_private = NULL;
5697
5913
                cf_at_tail = at_sys_tail;
5698
5914
                cf_oc_tail = oc_sys_tail;
5699
5915
                cf_om_tail = om_sys_tail;
 
5916
                cf_syn_tail = syn_sys_tail;
5700
5917
        }
5701
5918
        return 0;
5702
5919
}
5727
5944
        /* If we have no explicitly configured ACLs, don't just use
5728
5945
         * the global ACLs. Explicitly deny access to everything.
5729
5946
         */
5730
 
        if ( frontendDB->be_acl && be->be_acl == frontendDB->be_acl ) {
 
5947
        if ( !be->be_acl ) {
5731
5948
                parse_acl(be, "config_back_db_open", 0, 6, (char **)defacl, 0 );
5732
5949
        }
5733
5950
 
5788
6005
        cf_at_tail = at_sys_tail;
5789
6006
        cf_oc_tail = oc_sys_tail;
5790
6007
        cf_om_tail = om_sys_tail;
 
6008
        cf_syn_tail = syn_sys_tail;
5791
6009
 
5792
6010
        /* Create schema nodes for included schema... */
5793
6011
        if ( cfb->cb_config->c_kids ) {
6015
6233
        /* Hide from namingContexts */
6016
6234
        SLAP_BFLAGS(be) |= SLAP_BFLAG_CONFIG;
6017
6235
 
 
6236
        /* Check ACLs on content of Adds by default */
 
6237
        SLAP_DBFLAGS(be) |= SLAP_DBFLAG_ACL_ADD;
 
6238
 
6018
6239
        return 0;
6019
6240
}
6020
6241
 
6221
6442
        { "backend", &cfAd_backend },
6222
6443
        { "database", &cfAd_database },
6223
6444
        { "include", &cfAd_include },
 
6445
        { "ldapsyntax", &cfAd_syntax },
6224
6446
        { "objectclass", &cfAd_oc },
6225
6447
        { "objectidentifier", &cfAd_om },
6226
6448
        { "overlay", &cfAd_overlay },
6327
6549
        i = config_register_schema( ct, cf_ocs );
6328
6550
        if ( i ) return i;
6329
6551
 
 
6552
        i = slap_str2ad( "olcDatabase", &olcDatabaseDummy[0].ad, &text );
 
6553
        if ( i ) return i;
 
6554
 
6330
6555
        /* setup olcRootPW to be base64-encoded when written in LDIF form;
6331
6556
         * basically, we don't care if it fails */
6332
6557
        i = slap_str2ad( "olcRootPW", &ad, &text );